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