github.com/tw-bc-group/fabric-ca-gm@v0.0.0-20201218004200-3b690512bd5a/lib/util.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib
     8  
     9  import (
    10  	"crypto/x509"
    11  	"encoding/hex"
    12  	"encoding/json"
    13  	"encoding/pem"
    14  	"fmt"
    15  	"io/ioutil"
    16  	"os"
    17  	"path/filepath"
    18  	"strings"
    19  
    20  	tls "github.com/Hyperledger-TWGC/tjfoc-gm/gmtls"
    21  	sm2 "github.com/Hyperledger-TWGC/tjfoc-gm/x509"
    22  	"github.com/cloudflare/cfssl/log"
    23  	"github.com/grantae/certinfo"
    24  	"github.com/pkg/errors"
    25  	"github.com/spf13/viper"
    26  	"github.com/tw-bc-group/fabric-ca-gm/api"
    27  	"github.com/tw-bc-group/fabric-ca-gm/util"
    28  	"github.com/tw-bc-group/net-go-gm/http"
    29  )
    30  
    31  var clientAuthTypes = map[string]tls.ClientAuthType{
    32  	"noclientcert":               tls.NoClientCert,
    33  	"requestclientcert":          tls.RequestClientCert,
    34  	"requireanyclientcert":       tls.RequireAnyClientCert,
    35  	"verifyclientcertifgiven":    tls.VerifyClientCertIfGiven,
    36  	"requireandverifyclientcert": tls.RequireAndVerifyClientCert,
    37  }
    38  
    39  // GetCertID returns both the serial number and AKI (Authority Key ID) for the certificate
    40  func GetCertID(bytes []byte) (string, string, error) {
    41  	cert, err := BytesToX509Cert(bytes)
    42  	if err != nil {
    43  		return "", "", err
    44  	}
    45  	serial := util.GetSerialAsHex(cert.SerialNumber)
    46  	aki := hex.EncodeToString(cert.AuthorityKeyId)
    47  	return serial, aki, nil
    48  }
    49  
    50  // BytesToX509Cert converts bytes (PEM or DER) to an X509 certificate
    51  func BytesToX509Cert(bytes []byte) (*x509.Certificate, error) {
    52  	dcert, _ := pem.Decode(bytes)
    53  	if dcert != nil {
    54  		bytes = dcert.Bytes
    55  	}
    56  	cert, err := x509.ParseCertificate(bytes)
    57  	if err != nil {
    58  		return nil, errors.Wrap(err, "Buffer was neither PEM nor DER encoding")
    59  	}
    60  	return cert, err
    61  }
    62  
    63  // LoadPEMCertPool loads a pool of PEM certificates from list of files
    64  func LoadPEMCertPool(certFiles []string) (*sm2.CertPool, error) {
    65  	certPool := sm2.NewCertPool()
    66  
    67  	if len(certFiles) > 0 {
    68  		for _, cert := range certFiles {
    69  			log.Debugf("Reading cert file: %s", cert)
    70  			pemCerts, err := ioutil.ReadFile(cert)
    71  			if err != nil {
    72  				return nil, err
    73  			}
    74  
    75  			log.Debugf("Appending cert %s to pool", cert)
    76  			if !certPool.AppendCertsFromPEM(pemCerts) {
    77  				return nil, errors.New("Failed to load cert pool")
    78  			}
    79  		}
    80  	}
    81  
    82  	return certPool, nil
    83  }
    84  
    85  // UnmarshalConfig unmarshals a configuration file
    86  func UnmarshalConfig(config interface{}, vp *viper.Viper, configFile string,
    87  	server bool) error {
    88  
    89  	vp.SetConfigFile(configFile)
    90  	err := vp.ReadInConfig()
    91  	if err != nil {
    92  		return errors.Wrapf(err, "Failed to read config file '%s'", configFile)
    93  	}
    94  
    95  	err = vp.Unmarshal(config)
    96  	if err != nil {
    97  		return errors.Wrapf(err, "Incorrect format in file '%s'", configFile)
    98  	}
    99  	if server {
   100  		serverCfg := config.(*ServerConfig)
   101  		err = vp.Unmarshal(&serverCfg.CAcfg)
   102  		if err != nil {
   103  			return errors.Wrapf(err, "Incorrect format in file '%s'", configFile)
   104  		}
   105  	}
   106  	return nil
   107  }
   108  
   109  func getMaxEnrollments(userMaxEnrollments int, caMaxEnrollments int) (int, error) {
   110  	log.Debugf("Max enrollment value verification - User specified max enrollment: %d, CA max enrollment: %d", userMaxEnrollments, caMaxEnrollments)
   111  	if userMaxEnrollments < -1 {
   112  		return 0, errors.Errorf("Max enrollment in registration request may not be less than -1, but was %d", userMaxEnrollments)
   113  	}
   114  	switch caMaxEnrollments {
   115  	case -1:
   116  		if userMaxEnrollments == 0 {
   117  			// The user is requesting the matching limit of the CA, so gets infinite
   118  			return caMaxEnrollments, nil
   119  		}
   120  		// There is no CA max enrollment limit, so simply use the user requested value
   121  		return userMaxEnrollments, nil
   122  	case 0:
   123  		// The CA max enrollment is 0, so registration is disabled.
   124  		return 0, errors.New("Registration is disabled")
   125  	default:
   126  		switch userMaxEnrollments {
   127  		case -1:
   128  			// User requested infinite enrollments is not allowed
   129  			return 0, errors.New("Registration for infinite enrollments is not allowed")
   130  		case 0:
   131  			// User is requesting the current CA maximum
   132  			return caMaxEnrollments, nil
   133  		default:
   134  			// User is requesting a specific positive value; make sure it doesn't exceed the CA maximum.
   135  			if userMaxEnrollments > caMaxEnrollments {
   136  				return 0, errors.Errorf("Requested enrollments (%d) exceeds maximum allowable enrollments (%d)",
   137  					userMaxEnrollments, caMaxEnrollments)
   138  			}
   139  			// otherwise, use the requested maximum
   140  			return userMaxEnrollments, nil
   141  		}
   142  	}
   143  }
   144  
   145  func addQueryParm(req *http.Request, name, value string) {
   146  	url := req.URL.Query()
   147  	url.Add(name, value)
   148  	req.URL.RawQuery = url.Encode()
   149  }
   150  
   151  // IdentityDecoder decodes streams of data coming from the server into an Identity object
   152  func IdentityDecoder(decoder *json.Decoder) error {
   153  	var id api.IdentityInfo
   154  	err := decoder.Decode(&id)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	fmt.Printf("Name: %s, Type: %s, Affiliation: %s, Max Enrollments: %d, Attributes: %+v\n", id.ID, id.Type, id.Affiliation, id.MaxEnrollments, id.Attributes)
   159  	return nil
   160  }
   161  
   162  // AffiliationDecoder decodes streams of data coming from the server into an Affiliation object
   163  func AffiliationDecoder(decoder *json.Decoder) error {
   164  	var aff api.AffiliationInfo
   165  	err := decoder.Decode(&aff)
   166  	if err != nil {
   167  		return err
   168  	}
   169  	fmt.Printf("%s\n", aff.Name)
   170  	return nil
   171  }
   172  
   173  // CertificateDecoder is needed to keep track of state, to see how many certificates
   174  // have been returned for each enrollment ID.
   175  type CertificateDecoder struct {
   176  	certIDCount map[string]int
   177  	storePath   string
   178  }
   179  
   180  // NewCertificateDecoder returns decoder for certificates
   181  func NewCertificateDecoder(storePath string) *CertificateDecoder {
   182  	cd := &CertificateDecoder{}
   183  	cd.certIDCount = make(map[string]int)
   184  	cd.storePath = storePath
   185  	return cd
   186  }
   187  
   188  // CertificateDecoder decodes streams of data coming from the server
   189  func (cd *CertificateDecoder) CertificateDecoder(decoder *json.Decoder) error {
   190  	var cert certPEM
   191  	err := decoder.Decode(&cert)
   192  	if err != nil {
   193  		return err
   194  	}
   195  	block, rest := pem.Decode([]byte(cert.PEM))
   196  	if block == nil || len(rest) > 0 {
   197  		return errors.New("Certificate decoding error")
   198  	}
   199  	certificate, err := x509.ParseCertificate(block.Bytes)
   200  	if err != nil {
   201  		return err
   202  	}
   203  	enrollmentID := certificate.Subject.CommonName
   204  	if cd.storePath != "" {
   205  		err = cd.StoreCert(enrollmentID, cd.storePath, []byte(cert.PEM))
   206  		if err != nil {
   207  			return err
   208  		}
   209  	}
   210  
   211  	result, err := certinfo.CertificateText(certificate)
   212  	if err != nil {
   213  		return err
   214  	}
   215  	fmt.Printf(result)
   216  	return nil
   217  }
   218  
   219  // StoreCert stores the certificate on the file system
   220  func (cd *CertificateDecoder) StoreCert(enrollmentID, storePath string, cert []byte) error {
   221  	cd.certIDCount[enrollmentID] = cd.certIDCount[enrollmentID] + 1
   222  
   223  	err := os.MkdirAll(storePath, os.ModePerm)
   224  	if err != nil {
   225  		return err
   226  	}
   227  
   228  	var filePath string
   229  	singleCertName := fmt.Sprintf("%s.pem", enrollmentID)
   230  	switch cd.certIDCount[enrollmentID] {
   231  	case 1: // Only one certificate returned, don't need to append number to certificate file name
   232  		filePath = filepath.Join(storePath, singleCertName)
   233  	case 2: // Two certificates returned, rename the old certificate to have number at the end
   234  		err := os.Rename(filepath.Join(storePath, singleCertName), filepath.Join(storePath, fmt.Sprintf("%s-1.pem", enrollmentID)))
   235  		if err != nil {
   236  			return errors.WithMessage(err, fmt.Sprintf("Failed to rename certificate: %s", singleCertName))
   237  		}
   238  		filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID]))
   239  	default:
   240  		filePath = filepath.Join(storePath, fmt.Sprintf("%s-%d.pem", enrollmentID, cd.certIDCount[enrollmentID]))
   241  	}
   242  
   243  	err = ioutil.WriteFile(filePath, cert, 0644)
   244  	if err != nil {
   245  		return errors.WithMessage(err, fmt.Sprintf("Failed to store certificate at: %s", storePath))
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  // SM2证书请求 转换 X509 证书请求
   252  func ParseSm2CertificateRequest2X509(sm2req *sm2.CertificateRequest) *x509.CertificateRequest {
   253  	x509req := &x509.CertificateRequest{
   254  		Raw:                      sm2req.Raw,                      // Complete ASN.1 DER content (CSR, signature algorithm and signature).
   255  		RawTBSCertificateRequest: sm2req.RawTBSCertificateRequest, // Certificate request info part of raw ASN.1 DER content.
   256  		RawSubjectPublicKeyInfo:  sm2req.RawSubjectPublicKeyInfo,  // DER encoded SubjectPublicKeyInfo.
   257  		RawSubject:               sm2req.RawSubject,               // DER encoded Subject.
   258  
   259  		Version:            sm2req.Version,
   260  		Signature:          sm2req.Signature,
   261  		SignatureAlgorithm: x509.SignatureAlgorithm(sm2req.SignatureAlgorithm),
   262  
   263  		PublicKeyAlgorithm: x509.PublicKeyAlgorithm(sm2req.PublicKeyAlgorithm),
   264  		PublicKey:          sm2req.PublicKey,
   265  
   266  		Subject: sm2req.Subject,
   267  
   268  		// Attributes is the dried husk of a bug and shouldn't be used.
   269  		Attributes: sm2req.Attributes,
   270  
   271  		// Extensions contains raw X.509 extensions. When parsing CSRs, this
   272  		// can be used to extract extensions that are not parsed by this
   273  		// package.
   274  		Extensions: sm2req.Extensions,
   275  
   276  		// ExtraExtensions contains extensions to be copied, raw, into any
   277  		// marshaled CSR. Values override any extensions that would otherwise
   278  		// be produced based on the other fields but are overridden by any
   279  		// extensions specified in Attributes.
   280  		//
   281  		// The ExtraExtensions field is not populated when parsing CSRs, see
   282  		// Extensions.
   283  		ExtraExtensions: sm2req.ExtraExtensions,
   284  
   285  		// Subject Alternate Name values.
   286  		DNSNames:       sm2req.DNSNames,
   287  		EmailAddresses: sm2req.EmailAddresses,
   288  		IPAddresses:    sm2req.IPAddresses,
   289  	}
   290  	return x509req
   291  }
   292  
   293  var providerName string
   294  
   295  func IsGMConfig() bool {
   296  	if providerName == "" {
   297  		return false
   298  	}
   299  	if strings.ToUpper(providerName) == "GM" {
   300  		return true
   301  	}
   302  	return false
   303  }
   304  
   305  func SetProviderName(name string) {
   306  	providerName = name
   307  }