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

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package util
    18  
    19  import (
    20  	"crypto"
    21  	"crypto/ecdsa"
    22  	"crypto/rsa"
    23  	"crypto/tls"
    24  	"crypto/x509"
    25  	"encoding/hex"
    26  	"encoding/pem"
    27  	"fmt"
    28  	"github.com/Hyperledger-TWGC/tjfoc-gm/sm2"
    29  	"io/ioutil"
    30  	"os"
    31  	"strings"
    32  	_ "time" // for ocspSignerFromConfig
    33  
    34  	gtls "github.com/Hyperledger-TWGC/tjfoc-gm/gmtls"
    35  	x509GM "github.com/Hyperledger-TWGC/tjfoc-gm/x509"
    36  	_ "github.com/cloudflare/cfssl/cli" // for ocspSignerFromConfig
    37  	"github.com/cloudflare/cfssl/config"
    38  	"github.com/cloudflare/cfssl/csr"
    39  	"github.com/cloudflare/cfssl/helpers"
    40  	"github.com/cloudflare/cfssl/log"
    41  	_ "github.com/cloudflare/cfssl/ocsp" // for ocspSignerFromConfig
    42  	"github.com/cloudflare/cfssl/signer"
    43  	"github.com/cloudflare/cfssl/signer/local"
    44  	"github.com/pkg/errors"
    45  	"github.com/tw-bc-group/fabric-gm/bccsp"
    46  	"github.com/tw-bc-group/fabric-gm/bccsp/factory"
    47  	"github.com/tw-bc-group/fabric-gm/bccsp/gm"
    48  	cspsigner "github.com/tw-bc-group/fabric-gm/bccsp/signer"
    49  	"github.com/tw-bc-group/fabric-gm/bccsp/utils"
    50  )
    51  
    52  // GetDefaultBCCSP returns the default BCCSP
    53  func GetDefaultBCCSP() bccsp.BCCSP {
    54  	return factory.GetDefault()
    55  }
    56  
    57  // InitBCCSP initializes BCCSP
    58  func InitBCCSP(optsPtr **factory.FactoryOpts, mspDir, homeDir string) (bccsp.BCCSP, error) {
    59  	err := ConfigureBCCSP(optsPtr, mspDir, homeDir)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	csp, err := GetBCCSP(*optsPtr, homeDir)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	return csp, nil
    68  }
    69  
    70  // GetBCCSP returns BCCSP
    71  func GetBCCSP(opts *factory.FactoryOpts, homeDir string) (bccsp.BCCSP, error) {
    72  
    73  	// Get BCCSP from the opts
    74  	csp, err := factory.GetBCCSPFromOpts(opts)
    75  	if err != nil {
    76  		return nil, errors.WithMessage(err, "Failed to get BCCSP with opts")
    77  	}
    78  	return csp, nil
    79  }
    80  
    81  // makeFileNamesAbsolute makes all relative file names associated with CSP absolute,
    82  // relative to 'homeDir'.
    83  func makeFileNamesAbsolute(opts *factory.FactoryOpts, homeDir string) error {
    84  	var err error
    85  	if opts != nil && opts.SwOpts != nil && opts.SwOpts.FileKeystore != nil {
    86  		fks := opts.SwOpts.FileKeystore
    87  		fks.KeyStorePath, err = MakeFileAbs(fks.KeyStorePath, homeDir)
    88  	}
    89  	return err
    90  }
    91  
    92  // BccspBackedSigner attempts to create a signer using csp bccsp.BCCSP. This csp could be SW (golang crypto)
    93  // PKCS11 or whatever BCCSP-conformant library is configured
    94  func BccspBackedSigner(caFile, keyFile string, policy *config.Signing, csp bccsp.BCCSP) (signer.Signer, error) {
    95  	_, cspSigner, parsedCa, err := GetSignerFromCertFile(caFile, csp)
    96  	if err != nil {
    97  		// Fallback: attempt to read out of keyFile and import
    98  		log.Debugf("No key found in BCCSP keystore, attempting fallback")
    99  		var key bccsp.Key
   100  		var signer crypto.Signer
   101  
   102  		key, err = ImportBCCSPKeyFromPEM(keyFile, csp, false)
   103  		if err != nil {
   104  			return nil, errors.WithMessage(err, fmt.Sprintf("Could not find the private key in BCCSP keystore nor in keyfile '%s'", keyFile))
   105  		}
   106  
   107  		signer, err = cspsigner.New(csp, key)
   108  		if err != nil {
   109  			return nil, errors.WithMessage(err, "Failed initializing CryptoSigner")
   110  		}
   111  		cspSigner = signer
   112  	}
   113  
   114  	signer, err := local.NewSigner(cspSigner, parsedCa, signer.DefaultSigAlgo(cspSigner), policy)
   115  	if err != nil {
   116  		return nil, errors.Wrap(err, "Failed to create new signer")
   117  	}
   118  	return signer, nil
   119  }
   120  
   121  // getBCCSPKeyOpts generates a key as specified in the request.
   122  // This supports ECDSA and RSA.
   123  func getBCCSPKeyOpts(kr csr.KeyRequest, ephemeral bool) (opts bccsp.KeyGenOpts, err error) {
   124  	if kr == nil {
   125  		return &bccsp.ECDSAKeyGenOpts{Temporary: ephemeral}, nil
   126  	}
   127  	log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
   128  	switch kr.Algo() {
   129  	case "rsa":
   130  		switch kr.Size() {
   131  		case 2048:
   132  			return &bccsp.RSA2048KeyGenOpts{Temporary: ephemeral}, nil
   133  		case 3072:
   134  			return &bccsp.RSA3072KeyGenOpts{Temporary: ephemeral}, nil
   135  		case 4096:
   136  			return &bccsp.RSA4096KeyGenOpts{Temporary: ephemeral}, nil
   137  		default:
   138  			// Need to add a way to specify arbitrary RSA key size to bccsp
   139  			return nil, errors.Errorf("Invalid RSA key size: %d", kr.Size())
   140  		}
   141  	case "ecdsa":
   142  		switch kr.Size() {
   143  		case 256:
   144  			return &bccsp.ECDSAP256KeyGenOpts{Temporary: ephemeral}, nil
   145  		case 384:
   146  			return &bccsp.ECDSAP384KeyGenOpts{Temporary: ephemeral}, nil
   147  		case 521:
   148  			// Need to add curve P521 to bccsp
   149  			// return &bccsp.ECDSAP512KeyGenOpts{Temporary: false}, nil
   150  			return nil, errors.New("Unsupported ECDSA key size: 521")
   151  		default:
   152  			return nil, errors.Errorf("Invalid ECDSA key size: %d", kr.Size())
   153  		}
   154  	case "gmsm2":
   155  		return &bccsp.GMSM2KeyGenOpts{Temporary: ephemeral}, nil
   156  	case "gmsm2_kms":
   157  		return &bccsp.KMSGMSM2KeyGenOpts{Temporary: ephemeral}, nil
   158  	case "gmsm2_ce":
   159  		return &bccsp.ZHGMSM2KeyGenOpts{Temporary: ephemeral}, nil
   160  	default:
   161  		return nil, errors.Errorf("Invalid algorithm: %s", kr.Algo())
   162  	}
   163  }
   164  
   165  // GetSignerFromCert load private key represented by ski and return bccsp signer that conforms to crypto.Signer
   166  func GetSignerFromCert(cert *x509.Certificate, csp bccsp.BCCSP) (bccsp.Key, crypto.Signer, error) {
   167  	if csp == nil {
   168  		return nil, nil, errors.New("CSP was not initialized")
   169  	}
   170  	log.Infof("xxxx begin csp.KeyImport,cert.PublicKey is %T   csp:%T", cert.PublicKey, csp)
   171  	switch cert.PublicKey.(type) {
   172  	case *ecdsa.PublicKey:
   173  		log.Infof("xxxxx cert is ecdsa puk")
   174  	case *sm2.PublicKey:
   175  		log.Infof("xxxxx cert is sm2 puk")
   176  	default:
   177  		log.Infof("xxxxx cert is default puk")
   178  	}
   179  
   180  	sm2cert := gm.ParseX509Certificate2Sm2(cert)
   181  	// get the public key in the right format
   182  	certPubK, err := csp.KeyImport(sm2cert, &bccsp.X509PublicKeyImportOpts{Temporary: true})
   183  	if err != nil {
   184  		return nil, nil, errors.WithMessage(err, "Failed to import certificate's public key")
   185  	}
   186  	kname := hex.EncodeToString(certPubK.SKI())
   187  	log.Infof("xxxx begin csp.GetKey kname:%s", kname)
   188  	// Get the key given the SKI value
   189  	privateKey, err := csp.GetKey(certPubK.SKI())
   190  	if err != nil {
   191  		return nil, nil, fmt.Errorf("Could not find matching private key for SKI: %s", err.Error())
   192  	}
   193  	log.Info("xxxx begin cspsigner.New()")
   194  	// Construct and initialize the signer
   195  	signer, err := cspsigner.New(csp, privateKey)
   196  	if err != nil {
   197  		return nil, nil, fmt.Errorf("Failed to load ski from bccsp: %s", err.Error())
   198  	}
   199  	log.Info("xxxx end GetSignerFromCert successfuul")
   200  	return privateKey, signer, nil
   201  }
   202  
   203  // GetSignerFromSM2Cert load private key represented by ski and return bccsp signer that conforms to crypto.Signer
   204  func GetSignerFromSM2Cert(cert *x509GM.Certificate, csp bccsp.BCCSP) (bccsp.Key, crypto.Signer, error) {
   205  	if csp == nil {
   206  		return nil, nil, fmt.Errorf("CSP was not initialized")
   207  	}
   208  
   209  	log.Infof("xxxx begin csp.KeyImport,cert.PublicKey is %T   csp:%T", cert.PublicKey, csp)
   210  	switch cert.PublicKey.(type) {
   211  	case sm2.PublicKey:
   212  		log.Infof("xxxxx cert is sm2 puk")
   213  	default:
   214  		log.Infof("xxxxx cert is default puk")
   215  	}
   216  
   217  	// sm2cert := gm.ParseX509Certificate2Sm2(cert)
   218  	// pk := cert.PublicKey
   219  	// sm2PublickKey := pk.(sm2.PublicKey)
   220  	// // if !ok {
   221  	// // 	return nil, nil, errors.New("Parse interface []  to sm2 pk error")
   222  	// // }
   223  	// der, err := sm2.MarshalSm2PublicKey(&sm2PublickKey)
   224  	// if err != nil {
   225  	// 	return nil, nil, errors.New("MarshalSm2PublicKey error")
   226  	// }
   227  
   228  	// get the public key in the right format
   229  	certPubK, err := csp.KeyImport(cert, &bccsp.GMSM2PublicKeyImportOpts{Temporary: true})
   230  	if err != nil {
   231  		return nil, nil, fmt.Errorf("Failed to import certificate's public key: %s", err.Error())
   232  	}
   233  
   234  	kname := hex.EncodeToString(certPubK.SKI())
   235  	log.Infof("xxxx begin csp.GetKey kname:%s", kname)
   236  
   237  	// Get the key given the SKI value
   238  	privateKey, err := csp.GetKey(certPubK.SKI())
   239  	if err != nil {
   240  		return nil, nil, errors.Errorf("The private key associated with the certificate with SKI '%s' was not found", hex.EncodeToString(certPubK.SKI()))
   241  	}
   242  
   243  	log.Info("xxxx begin cspsigner.New()")
   244  	// Construct and initialize the signer
   245  	signer, err := cspsigner.New(csp, privateKey)
   246  	if err != nil {
   247  		return nil, nil, errors.WithMessage(err, "Failed to load ski from bccsp")
   248  	}
   249  	log.Info("xxxx end GetSignerFromCert successfuul")
   250  	return privateKey, signer, nil
   251  }
   252  
   253  // GetSignerFromCertFile load skiFile and load private key represented by ski and return bccsp signer that conforms to crypto.Signer
   254  func GetSignerFromCertFile(certFile string, csp bccsp.BCCSP) (bccsp.Key, crypto.Signer, *x509.Certificate, error) {
   255  	var cert *x509.Certificate
   256  	log.Debugf("GetSignerFromCertFile, certFile: %s", certFile)
   257  	// Load cert file
   258  	certBytes, err := ioutil.ReadFile(certFile)
   259  	if err != nil {
   260  		return nil, nil, nil, errors.Wrapf(err, "Could not read certFile '%s'", certFile)
   261  	}
   262  	if IsGMConfig() {
   263  		sm2Cert, err := x509GM.ReadCertificateFromPem(certBytes)
   264  		if err != nil {
   265  			return nil, nil, nil, err
   266  		}
   267  		cert = gm.ParseSm2Certificate2X509(sm2Cert)
   268  	} else {
   269  		cert, err = helpers.ParseCertificatePEM(certBytes)
   270  	}
   271  	key, cspSigner, err := GetSignerFromCert(cert, csp)
   272  	log.Infof("+++++++++++++KEY = %T error = %v", key, err)
   273  	return key, cspSigner, cert, err
   274  }
   275  
   276  //TODO: remove first param
   277  // BCCSPKeyRequestGenerate generates keys through BCCSP
   278  // somewhat mirroring to cfssl/req.KeyRequest.Generate()
   279  func BCCSPKeyRequestGenerate(req *csr.CertificateRequest, myCSP bccsp.BCCSP) (bccsp.Key, crypto.Signer, error) {
   280  	log.Infof("generating key: %+v", req.KeyRequest)
   281  	keyOpts, err := getBCCSPKeyOpts(req.KeyRequest, false)
   282  	if err != nil {
   283  		return nil, nil, err
   284  	}
   285  	key, err := myCSP.KeyGen(keyOpts)
   286  	if err != nil {
   287  		return nil, nil, err
   288  	}
   289  	cspSigner, err := cspsigner.New(myCSP, key)
   290  	if err != nil {
   291  		return nil, nil, errors.WithMessage(err, "Failed initializing CryptoSigner")
   292  	}
   293  	return key, cspSigner, nil
   294  }
   295  
   296  // ImportBCCSPKeyFromPEM attempts to create a private BCCSP key from a pem file keyFile
   297  func ImportBCCSPKeyFromPEM(keyFile string, myCSP bccsp.BCCSP, temporary bool) (bccsp.Key, error) {
   298  	keyBuff, err := ioutil.ReadFile(keyFile)
   299  	if err != nil {
   300  		return nil, err
   301  	}
   302  	var key interface{}
   303  	if os.Getenv("CA_GM_PROVIDER") == "ALIYUN_KMS" {
   304  		priv, err := myCSP.KeyImport(strings.Trim(string(keyBuff), "\n"), &bccsp.KMSGMSM2KeyImportOpts{Temporary: temporary})
   305  		if err != nil {
   306  			return nil, fmt.Errorf("failed to convert kms SM2 private key from %s: %s", keyFile, err.Error())
   307  		}
   308  		return priv, nil
   309  	} else {
   310  		key, err = utils.PEMtoPrivateKey(keyBuff, nil)
   311  		if err != nil {
   312  			return nil, errors.WithMessage(err, fmt.Sprintf("Failed parsing private key from %s", keyFile))
   313  		}
   314  
   315  		switch key.(type) {
   316  		case *sm2.PrivateKey:
   317  			log.Info("xxxx sm2.PrivateKey!!!!!!!!!!!")
   318  			block, _ := pem.Decode(keyBuff)
   319  			priv, err := myCSP.KeyImport(block.Bytes, &bccsp.GMSM2PrivateKeyImportOpts{Temporary: temporary})
   320  			if err != nil {
   321  				return nil, fmt.Errorf("failed to convert SM2 private key from %s: %s", keyFile, err.Error())
   322  			}
   323  			return priv, nil
   324  		case *ecdsa.PrivateKey:
   325  			priv, err := utils.PrivateKeyToDER(key.(*ecdsa.PrivateKey))
   326  			if err != nil {
   327  				return nil, errors.WithMessage(err, fmt.Sprintf("Failed to convert ECDSA private key for '%s'", keyFile))
   328  			}
   329  			sk, err := myCSP.KeyImport(priv, &bccsp.ECDSAPrivateKeyImportOpts{Temporary: temporary})
   330  			if err != nil {
   331  				return nil, errors.WithMessage(err, fmt.Sprintf("Failed to import ECDSA private key for '%s'", keyFile))
   332  			}
   333  			return sk, nil
   334  		case *rsa.PrivateKey:
   335  			return nil, errors.Errorf("Failed to import RSA key from %s; RSA private key import is not supported", keyFile)
   336  		default:
   337  			return nil, errors.Errorf("Failed to import key from %s: invalid secret key type", keyFile)
   338  		}
   339  	}
   340  }
   341  
   342  // LoadX509KeyPair reads and parses a public/private key pair from a pair
   343  // of files. The files must contain PEM encoded data. The certificate file
   344  // may contain intermediate certificates following the leaf certificate to
   345  // form a certificate chain. On successful return, Certificate.Leaf will
   346  // be nil because the parsed form of the certificate is not retained.
   347  //
   348  // This function originated from crypto/tls/tls.go and was adapted to use a
   349  // BCCSP Signer
   350  func LoadX509KeyPair(certFile, keyFile string, csp bccsp.BCCSP) (*tls.Certificate, error) {
   351  
   352  	certPEMBlock, err := ioutil.ReadFile(certFile)
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  
   357  	cert := &tls.Certificate{}
   358  	var skippedBlockTypes []string
   359  	for {
   360  		var certDERBlock *pem.Block
   361  		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
   362  		if certDERBlock == nil {
   363  			break
   364  		}
   365  		if certDERBlock.Type == "CERTIFICATE" {
   366  			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
   367  		} else {
   368  			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
   369  		}
   370  	}
   371  
   372  	if len(cert.Certificate) == 0 {
   373  		if len(skippedBlockTypes) == 0 {
   374  			return nil, errors.Errorf("Failed to find PEM block in file %s", certFile)
   375  		}
   376  		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
   377  			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)
   378  		}
   379  		return nil, errors.Errorf("Failed to find \"CERTIFICATE\" PEM block in file %s after skipping PEM blocks of the following types: %v", certFile, skippedBlockTypes)
   380  	}
   381  
   382  	sm2Cert, err := x509GM.ParseCertificate(cert.Certificate[0])
   383  	if err != nil {
   384  		return nil, err
   385  	}
   386  
   387  	x509Cert := gm.ParseSm2Certificate2X509(sm2Cert)
   388  
   389  	_, cert.PrivateKey, err = GetSignerFromCert(x509Cert, csp)
   390  	if err != nil {
   391  		if keyFile != "" {
   392  			log.Debugf("Could not load TLS certificate with BCCSP: %s", err)
   393  			log.Debugf("Attempting fallback with certfile %s and keyfile %s", certFile, keyFile)
   394  			fallbackCerts, err := tls.LoadX509KeyPair(certFile, keyFile)
   395  			if err != nil {
   396  				return nil, errors.Wrapf(err, "Could not get the private key %s that matches %s", keyFile, certFile)
   397  			}
   398  			cert = &fallbackCerts
   399  		} else {
   400  			return nil, errors.WithMessage(err, "Could not load TLS certificate with BCCSP")
   401  		}
   402  
   403  	}
   404  
   405  	return cert, nil
   406  }
   407  
   408  func LoadX509KeyPairSM2(certFile, keyFile string, csp bccsp.BCCSP) (bccsp.Key, *gtls.Certificate, error) {
   409  
   410  	certPEMBlock, err := ioutil.ReadFile(certFile)
   411  	if err != nil {
   412  		return nil, nil, err
   413  	}
   414  
   415  	cert := &gtls.Certificate{}
   416  	var skippedBlockTypes []string
   417  	for {
   418  		var certDERBlock *pem.Block
   419  		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
   420  		if certDERBlock == nil {
   421  			break
   422  		}
   423  		if certDERBlock.Type == "CERTIFICATE" {
   424  			cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
   425  		} else {
   426  			skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
   427  		}
   428  	}
   429  
   430  	if len(cert.Certificate) == 0 {
   431  		if len(skippedBlockTypes) == 0 {
   432  			return nil, nil, errors.Errorf("Failed to find PEM block in file %s", certFile)
   433  		}
   434  		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
   435  			return nil, 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)
   436  		}
   437  		return nil, nil, errors.Errorf("Failed to find \"CERTIFICATE\" PEM block in file %s after skipping PEM blocks of the following types: %v", certFile, skippedBlockTypes)
   438  	}
   439  
   440  	sm2Cert, err := x509GM.ParseCertificate(cert.Certificate[0])
   441  	if err != nil {
   442  		return nil, nil, err
   443  	}
   444  
   445  	x509Cert := gm.ParseSm2Certificate2X509(sm2Cert)
   446  	var privateKey bccsp.Key
   447  	privateKey, cert.PrivateKey, err = GetSignerFromCert(x509Cert, csp)
   448  	if err != nil {
   449  		if keyFile != "" {
   450  			log.Debugf("Could not load TLS certificate with BCCSP: %s", err)
   451  			log.Debugf("Attempting fallback with certfile %s and keyfile %s", certFile, keyFile)
   452  			fallbackCerts, err := gtls.LoadX509KeyPair(certFile, keyFile)
   453  			if err != nil {
   454  				return nil, nil, errors.Wrapf(err, "Could not get the private key %s that matches %s", keyFile, certFile)
   455  			}
   456  			keyPEMBLock, err := ioutil.ReadFile(keyFile)
   457  			if err != nil {
   458  				return nil, nil, err
   459  			}
   460  			keyDERBlock, _ := pem.Decode(keyPEMBLock)
   461  			privateKey, err = csp.KeyImport(keyDERBlock.Bytes, &bccsp.GMSM2PrivateKeyImportOpts{Temporary: true})
   462  			if err != nil {
   463  				return nil, nil, errors.Wrapf(err, "Could not import the private key to bccsp key")
   464  			}
   465  			log.Infof("[matrix] import %v to bccsp key success", keyFile)
   466  			cert = &fallbackCerts
   467  		} else {
   468  			return nil, nil, errors.WithMessage(err, "Could not load TLS certificate with BCCSP")
   469  		}
   470  
   471  	}
   472  
   473  	return privateKey, cert, nil
   474  }