github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/internal/pkg/util/csp.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package util
     8  
     9  import (
    10  	"crypto"
    11  	"encoding/hex"
    12  	"encoding/pem"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"strings"
    16  	_ "time" // for ocspSignerFromConfig
    17  
    18  	"gitee.com/zhaochuninhefei/zcgolog/zclog"
    19  	gtls "github.com/hxx258456/ccgo/gmtls"
    20  	"github.com/hxx258456/ccgo/sm2"
    21  	gx509 "github.com/hxx258456/ccgo/x509"
    22  	_ "github.com/hxx258456/cfssl-gm/cli" // for ocspSignerFromConfig
    23  	"github.com/hxx258456/cfssl-gm/config"
    24  	"github.com/hxx258456/cfssl-gm/csr"
    25  	_ "github.com/hxx258456/cfssl-gm/ocsp" // for ocspSignerFromConfig
    26  	"github.com/hxx258456/cfssl-gm/signer"
    27  	"github.com/hxx258456/cfssl-gm/signer/local"
    28  	"github.com/hxx258456/fabric-gm/bccsp"
    29  	"github.com/hxx258456/fabric-gm/bccsp/factory"
    30  	cspsigner "github.com/hxx258456/fabric-gm/bccsp/signer"
    31  	"github.com/hxx258456/fabric-gm/bccsp/utils"
    32  	"github.com/pkg/errors"
    33  )
    34  
    35  // GetDefaultBCCSP returns the default BCCSP
    36  func GetDefaultBCCSP() bccsp.BCCSP {
    37  	return factory.GetDefault()
    38  }
    39  
    40  // InitBCCSP initializes BCCSP
    41  func InitBCCSP(optsPtr **factory.FactoryOpts, mspDir, homeDir string) (bccsp.BCCSP, error) {
    42  	err := ConfigureBCCSP(optsPtr, mspDir, homeDir)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	csp, err := GetBCCSP(*optsPtr, homeDir)
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	return csp, nil
    51  }
    52  
    53  // GetBCCSP returns BCCSP
    54  func GetBCCSP(opts *factory.FactoryOpts, homeDir string) (bccsp.BCCSP, error) {
    55  
    56  	// Get BCCSP from the opts
    57  	csp, err := factory.GetBCCSPFromOpts(opts)
    58  	if err != nil {
    59  		return nil, errors.WithMessage(err, "Failed to get BCCSP with opts")
    60  	}
    61  	return csp, nil
    62  }
    63  
    64  // makeFileNamesAbsolute makes all relative file names associated with CSP absolute,
    65  // relative to 'homeDir'.
    66  func makeFileNamesAbsolute(opts *factory.FactoryOpts, homeDir string) error {
    67  	var err error
    68  	if opts != nil && opts.SwOpts != nil && opts.SwOpts.FileKeystore != nil {
    69  		fks := opts.SwOpts.FileKeystore
    70  		fks.KeyStorePath, err = MakeFileAbs(fks.KeyStorePath, homeDir)
    71  	}
    72  	return err
    73  }
    74  
    75  // BccspBackedSigner attempts to create a signer using csp bccsp.BCCSP. This csp could be SW (golang crypto)
    76  // PKCS11 or whatever BCCSP-conformant library is configured
    77  func BccspBackedSigner(caFile, keyFile string, policy *config.Signing, csp bccsp.BCCSP) (signer.Signer, error) {
    78  	_, cspSigner, parsedCa, err := GetSignerFromCertFile(caFile, csp)
    79  	if err != nil {
    80  		// Fallback: attempt to read out of keyFile and import
    81  		zclog.Debugf("===== No key found in BCCSP keystore, attempting fallback")
    82  		var key bccsp.Key
    83  		var signer crypto.Signer
    84  
    85  		key, err = ImportBCCSPKeyFromPEM(keyFile, csp, false)
    86  		if err != nil {
    87  			return nil, errors.WithMessage(err, fmt.Sprintf("Could not find the private key in BCCSP keystore nor in keyfile '%s'", keyFile))
    88  		}
    89  
    90  		signer, err = cspsigner.New(csp, key)
    91  		if err != nil {
    92  			return nil, errors.WithMessage(err, "Failed initializing CryptoSigner")
    93  		}
    94  		cspSigner = signer
    95  	}
    96  	signer, err := local.NewSigner(cspSigner, parsedCa, signer.DefaultSigAlgo(cspSigner), policy)
    97  	if err != nil {
    98  		return nil, errors.Wrap(err, "Failed to create new signer")
    99  	}
   100  	return signer, nil
   101  }
   102  
   103  // getBCCSPKeyOpts generates a key as specified in the request.
   104  // This supports ECDSA and RSA.
   105  // 国密改造后只支持sm2
   106  func getBCCSPKeyOpts(kr *csr.KeyRequest, ephemeral bool) (opts bccsp.KeyGenOpts, err error) {
   107  	if kr == nil {
   108  		return &bccsp.SM2KeyGenOpts{Temporary: ephemeral}, nil
   109  	}
   110  	zclog.Debugf("===== generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
   111  	switch kr.Algo() {
   112  	// case "rsa":
   113  	// 	switch kr.Size() {
   114  	// 	case 2048:
   115  	// 		return &bccsp.RSA2048KeyGenOpts{Temporary: ephemeral}, nil
   116  	// 	case 3072:
   117  	// 		return &bccsp.RSA3072KeyGenOpts{Temporary: ephemeral}, nil
   118  	// 	case 4096:
   119  	// 		return &bccsp.RSA4096KeyGenOpts{Temporary: ephemeral}, nil
   120  	// 	default:
   121  	// 		// Need to add a way to specify arbitrary RSA key size to bccsp
   122  	// 		return nil, errors.Errorf("Invalid RSA key size: %d", kr.Size())
   123  	// 	}
   124  	// case "ecdsa":
   125  	// 	switch kr.Size() {
   126  	// 	case 256:
   127  	// 		return &bccsp.ECDSAP256KeyGenOpts{Temporary: ephemeral}, nil
   128  	// 	case 384:
   129  	// 		return &bccsp.ECDSAP384KeyGenOpts{Temporary: ephemeral}, nil
   130  	// 	case 521:
   131  	// 		// Need to add curve P521 to bccsp
   132  	// 		// return &bccsp.ECDSAP512KeyGenOpts{Temporary: false}, nil
   133  	// 		return nil, errors.New("Unsupported ECDSA key size: 521")
   134  	// 	default:
   135  	// 		return nil, errors.Errorf("Invalid ECDSA key size: %d", kr.Size())
   136  	// 	}
   137  	case bccsp.SM2:
   138  		return &bccsp.SM2KeyGenOpts{Temporary: ephemeral}, nil
   139  	default:
   140  		return nil, errors.Errorf("Invalid algorithm: %s", kr.Algo())
   141  	}
   142  }
   143  
   144  // 根据国密x509证书中获取私钥与Signer。
   145  // GetSignerFromCert load private key represented by ski and return bccsp signer that conforms to crypto.Signer
   146  func GetSignerFromCert(cert *gx509.Certificate, csp bccsp.BCCSP) (bccsp.Key, crypto.Signer, error) {
   147  	if csp == nil {
   148  		return nil, nil, errors.New("CSP was not initialized")
   149  	}
   150  	// zclog.Infof("===== internal/pkg/util/csp.go GetSignerFromCert: begin csp.KeyImport,cert.PublicKey is %T   csp:%T", cert.PublicKey, csp)
   151  	// switch cert.PublicKey.(type) {
   152  	// case sm2.PublicKey:
   153  	// 	zclog.Infof("===== internal/pkg/util/csp.go GetSignerFromCert: cert is sm2 puk")
   154  	// default:
   155  	// 	zclog.Infof("===== internal/pkg/util/csp.go GetSignerFromCert: cert is default puk")
   156  	// }
   157  
   158  	// sm2cert := sw.ParseX509Certificate2Sm2(cert)
   159  	// get the public key in the right format
   160  	// 从国密x509证书中获取证书公钥
   161  	certPubK, err := csp.KeyImport(cert, &bccsp.GMX509PublicKeyImportOpts{Temporary: true})
   162  	if err != nil {
   163  		return nil, nil, errors.WithMessage(err, "Failed to import certificate's public key")
   164  	}
   165  	ski := certPubK.SKI()
   166  	kname := hex.EncodeToString(ski)
   167  	// zclog.Infof("===== internal/pkg/util/csp.go GetSignerFromCert: begin csp.GetKey kname:%s", kname)
   168  	// Get the key given the SKI value
   169  	privateKey, err := csp.GetKey(ski)
   170  	if err != nil {
   171  		return nil, nil, errors.WithMessage(err, "Could not find matching private key for SKI")
   172  	}
   173  	// BCCSP returns a public key if the private key for the SKI wasn't found, so
   174  	// we need to return an error in that case.
   175  	if !privateKey.Private() {
   176  		return nil, nil, errors.Errorf("The private key associated with the certificate with SKI '%s' was not found", kname)
   177  	}
   178  	// Construct and initialize the signer
   179  	signer, err := cspsigner.New(csp, privateKey)
   180  	if err != nil {
   181  		return nil, nil, errors.WithMessage(err, "Failed to load ski from bccsp")
   182  	}
   183  	// zclog.Info("===== internal/pkg/util/csp.go GetSignerFromCert successfuul")
   184  	return privateKey, signer, nil
   185  }
   186  
   187  // 根据x509证书文件获取对应的私钥、Signer以及x509证书。
   188  // GetSignerFromCertFile load skiFile and load private key represented by ski and return bccsp signer that conforms to crypto.Signer
   189  func GetSignerFromCertFile(certFile string, csp bccsp.BCCSP) (bccsp.Key, crypto.Signer, *gx509.Certificate, error) {
   190  	// zclog.Infof("===== internal/pkg/util/csp.go GetSignerFromCertFile:certFile:,%s", certFile)
   191  	// Load cert file
   192  	certBytes, err := ioutil.ReadFile(certFile)
   193  	if err != nil {
   194  		return nil, nil, nil, errors.Wrapf(err, "Could not read certFile '%s'", certFile)
   195  	}
   196  	// TODO 修改为国密
   197  	// // Parse certificate
   198  	// parsedCa, err := helpers.ParseCertificatePEM(certBytes)
   199  	// if err != nil {
   200  	// 	return nil, nil, nil, err
   201  	// }
   202  	// // Get the signer from the cert
   203  	// key, cspSigner, err := GetSignerFromCert(parsedCa, csp)
   204  	// return key, cspSigner, parsedCa, err
   205  
   206  	// cert, err := helpers.ParseCertificatePEM(certBytes)
   207  	cert, _ := gx509.ReadCertificateFromPem(certBytes)
   208  	// if err != nil || cert == nil {
   209  	// 	zclog.Infof("===== error = %s,尝试作为 gm cert 读入!", err.Error())
   210  	// 	sm2Cert, err := gx509.ReadCertificateFromPem(certBytes)
   211  	// 	if err != nil {
   212  	// 		return nil, nil, nil, err
   213  	// 	}
   214  	// 	cert = sw.ParseSm2Certificate2X509(sm2Cert)
   215  	// }
   216  	key, cspSigner, err := GetSignerFromCert(cert, csp)
   217  	// zclog.Infof("===== KEY = %T error = %v", key, err)
   218  	return key, cspSigner, cert, err
   219  }
   220  
   221  // BCCSPKeyRequestGenerate generates keys through BCCSP
   222  // somewhat mirroring to cfssl/req.KeyRequest.Generate()
   223  func BCCSPKeyRequestGenerate(req *csr.CertificateRequest, myCSP bccsp.BCCSP) (bccsp.Key, crypto.Signer, error) {
   224  	zclog.Infof("===== generating key: %+v", req.KeyRequest)
   225  	keyOpts, err := getBCCSPKeyOpts(req.KeyRequest, false)
   226  	if err != nil {
   227  		return nil, nil, err
   228  	}
   229  	key, err := myCSP.KeyGen(keyOpts)
   230  	if err != nil {
   231  		return nil, nil, err
   232  	}
   233  	cspSigner, err := cspsigner.New(myCSP, key)
   234  	if err != nil {
   235  		return nil, nil, errors.WithMessage(err, "Failed initializing CryptoSigner")
   236  	}
   237  	return key, cspSigner, nil
   238  }
   239  
   240  // ImportBCCSPKeyFromPEM attempts to create a private BCCSP key from a pem file keyFile
   241  func ImportBCCSPKeyFromPEM(keyFile string, myCSP bccsp.BCCSP, temporary bool) (bccsp.Key, error) {
   242  	keyBuff, err := ioutil.ReadFile(keyFile)
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	key, err := utils.PEMtoPrivateKey(keyBuff, nil)
   247  	if err != nil {
   248  		return nil, errors.WithMessage(err, fmt.Sprintf("Failed parsing private key from %s", keyFile))
   249  	}
   250  	// TODO 国密对应
   251  	// switch key := key.(type) {
   252  	switch key.(type) {
   253  	case *sm2.PrivateKey:
   254  		opts := &factory.FactoryOpts{
   255  			ProviderName: "SW",
   256  			SwOpts: &factory.SwOpts{
   257  				HashFamily: bccsp.SM3,
   258  				SecLevel:   256,
   259  				FileKeystore: &factory.FileKeystoreOpts{
   260  					KeyStorePath: keyFile,
   261  				},
   262  			},
   263  			UsingGM: "Y",
   264  		}
   265  		csp, err := factory.GetBCCSPFromOpts(opts)
   266  		if err != nil {
   267  			return nil, errors.Errorf("Failed to convert SM2 private key from %s: %s", keyFile, err.Error())
   268  		}
   269  		block, _ := pem.Decode(keyBuff)
   270  		priv, err := csp.KeyImport(block.Bytes, &bccsp.SM2PrivateKeyImportOpts{Temporary: true})
   271  		if err != nil {
   272  			return nil, errors.Errorf("Failed to convert SM2 private key from %s: %s", keyFile, err.Error())
   273  		}
   274  		return priv, nil
   275  	// case *ecdsa.PrivateKey:
   276  	// TODO 国密对应,去除对ECDSA的支持
   277  	// priv, err := utils.PrivateKeyToDER(key)
   278  	// if err != nil {
   279  	// 	return nil, errors.WithMessage(err, fmt.Sprintf("Failed to convert ECDSA private key for '%s'", keyFile))
   280  	// }
   281  	// sk, err := myCSP.KeyImport(priv, &bccsp.ECDSAPrivateKeyImportOpts{Temporary: temporary})
   282  	// if err != nil {
   283  	// 	return nil, errors.WithMessage(err, fmt.Sprintf("Failed to import ECDSA private key for '%s'", keyFile))
   284  	// }
   285  	// return sk, nil
   286  	// return nil, errors.Errorf("Failed to import ECDSA key from %s; ECDSA private key import is not supported", keyFile)
   287  	// case *rsa.PrivateKey:
   288  	// 	return nil, errors.Errorf("Failed to import RSA key from %s; RSA private key import is not supported", keyFile)
   289  	default:
   290  		return nil, errors.Errorf("Failed to import key from %s: invalid secret key type", keyFile)
   291  	}
   292  }
   293  
   294  // LoadX509KeyPair reads and parses a public/private key pair from a pair
   295  // of files. The files must contain PEM encoded data. The certificate file
   296  // may contain intermediate certificates following the leaf certificate to
   297  // form a certificate chain. On successful return, Certificate.Leaf will
   298  // be nil because the parsed form of the certificate is not retained.
   299  //
   300  // This function originated from crypto/tls/tls.go and was adapted to use a
   301  // BCCSP Signer
   302  func LoadX509KeyPair(certFile, keyFile string, csp bccsp.BCCSP) (*gtls.Certificate, error) {
   303  
   304  	certPEMBlock, err := ioutil.ReadFile(certFile)
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  
   309  	cert := &gtls.Certificate{}
   310  	var skippedBlockTypes []string
   311  	for {
   312  		var certDERBlock *pem.Block
   313  		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
   314  		if certDERBlock == nil {
   315  			break
   316  		}
   317  		if certDERBlock.Type == "CERTIFICATE" {
   318  			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
   319  		} else {
   320  			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
   321  		}
   322  	}
   323  
   324  	if len(cert.Certificate) == 0 {
   325  		if len(skippedBlockTypes) == 0 {
   326  			return nil, errors.Errorf("Failed to find PEM block in file %s", certFile)
   327  		}
   328  		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
   329  			return nil, errors.Errorf("Failed to find certificate PEM data in file %s, but did find a private key; PEM inputs may have been switched", certFile)
   330  		}
   331  		return nil, errors.Errorf("Failed to find \"CERTIFICATE\" PEM block in file %s after skipping PEM blocks of the following types: %v", certFile, skippedBlockTypes)
   332  	}
   333  
   334  	sm2Cert, err := gx509.ParseCertificate(cert.Certificate[0])
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  
   339  	// x509Cert := sw.ParseSm2Certificate2X509(sm2Cert)
   340  	_, cert.PrivateKey, err = GetSignerFromCert(sm2Cert, csp)
   341  	if err != nil {
   342  		if keyFile != "" {
   343  			zclog.Debugf("===== Could not load TLS certificate with BCCSP: %s", err)
   344  			zclog.Debugf("===== Attempting fallback with certfile %s and keyfile %s", certFile, keyFile)
   345  			fallbackCerts, err := gtls.LoadX509KeyPair(certFile, keyFile)
   346  			if err != nil {
   347  				return nil, errors.Wrapf(err, "Could not get the private key %s that matches %s", keyFile, certFile)
   348  			}
   349  			cert = &fallbackCerts
   350  		} else {
   351  			return nil, errors.WithMessage(err, "Could not load TLS certificate with BCCSP")
   352  		}
   353  
   354  	}
   355  
   356  	return cert, nil
   357  }
   358  
   359  func LoadX509KeyPairSM2(certFile, keyFile string, csp bccsp.BCCSP) (*gtls.Certificate, error) {
   360  
   361  	certPEMBlock, err := ioutil.ReadFile(certFile)
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	cert := &gtls.Certificate{}
   367  	var skippedBlockTypes []string
   368  	for {
   369  		var certDERBlock *pem.Block
   370  		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
   371  		if certDERBlock == nil {
   372  			break
   373  		}
   374  		if certDERBlock.Type == "CERTIFICATE" {
   375  			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
   376  		} else {
   377  			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
   378  		}
   379  	}
   380  
   381  	if len(cert.Certificate) == 0 {
   382  		if len(skippedBlockTypes) == 0 {
   383  			return nil, errors.Errorf("Failed to find PEM block in file %s", certFile)
   384  		}
   385  		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
   386  			return nil, errors.Errorf("Failed to find certificate PEM data in file %s, but did find a private key; PEM inputs may have been switched", certFile)
   387  		}
   388  		return nil, errors.Errorf("Failed to find \"CERTIFICATE\" PEM block in file %s after skipping PEM blocks of the following types: %v", certFile, skippedBlockTypes)
   389  	}
   390  
   391  	sm2Cert, err := gx509.ParseCertificate(cert.Certificate[0])
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  
   396  	// x509Cert := sw.ParseSm2Certificate2X509(sm2Cert)
   397  	_, cert.PrivateKey, err = GetSignerFromCert(sm2Cert, csp)
   398  	if err != nil {
   399  		if keyFile != "" {
   400  			zclog.Debugf("===== Could not load TLS certificate with BCCSP: %s", err)
   401  			zclog.Debugf("===== Attempting fallback with certfile %s and keyfile %s", certFile, keyFile)
   402  			fallbackCerts, err := gtls.LoadX509KeyPair(certFile, keyFile)
   403  			if err != nil {
   404  				return nil, errors.Wrapf(err, "Could not get the private key %s that matches %s", keyFile, certFile)
   405  			}
   406  			cert = &fallbackCerts
   407  		} else {
   408  			return nil, errors.WithMessage(err, "Could not load TLS certificate with BCCSP")
   409  		}
   410  
   411  	}
   412  
   413  	return cert, nil
   414  }