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 := >ls.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 }