github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/bccsp/pkcs11/impl.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package pkcs11 8 9 import ( 10 "crypto/rsa" 11 "github.com/hellobchain/newcryptosm/ecdsa" 12 "github.com/hellobchain/newcryptosm/x509" 13 "github.com/hellobchain/wswlog/wlogging" 14 "os" 15 16 "github.com/miekg/pkcs11" 17 "github.com/pkg/errors" 18 "github.com/hellobchain/third_party/hyperledger/fabric/bccsp" 19 "github.com/hellobchain/third_party/hyperledger/fabric/bccsp/sw" 20 ) 21 22 var ( 23 logger = wlogging.MustGetLoggerWithoutName() 24 sessionCacheSize = 10 25 ) 26 27 // New WithParams returns a new instance of the software-based BCCSP 28 // set at the passed security level, hash family and KeyStore. 29 func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { 30 // Init config 31 conf := &config{} 32 err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily) 33 if err != nil { 34 return nil, errors.Wrapf(err, "Failed initializing configuration") 35 } 36 37 swCSP, err := sw.NewWithParams(opts.SecLevel, opts.HashFamily, keyStore) 38 if err != nil { 39 return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP") 40 } 41 42 // Check KeyStore 43 if keyStore == nil { 44 return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil") 45 } 46 47 lib := opts.Library 48 pin := opts.Pin 49 label := opts.Label 50 ctx, slot, session, err := loadLib(lib, pin, label) 51 if err != nil { 52 return nil, errors.Wrapf(err, "Failed initializing PKCS11 library %s %s", 53 lib, label) 54 } 55 56 sessions := make(chan pkcs11.SessionHandle, sessionCacheSize) 57 csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, pin, lib, opts.SoftVerify, opts.Immutable, opts.AltId} 58 csp.returnSession(*session) 59 return csp, nil 60 } 61 62 type impl struct { 63 bccsp.BCCSP 64 65 conf *config 66 ks bccsp.KeyStore 67 68 ctx *pkcs11.Ctx 69 sessions chan pkcs11.SessionHandle 70 slot uint 71 pin string 72 73 lib string 74 softVerify bool 75 //Immutable flag makes object immutable 76 immutable bool 77 // Alternate identifier of the private key 78 altId string 79 } 80 81 // KeyGen generates a key using opts. 82 func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { 83 // Validate arguments 84 if opts == nil { 85 return nil, errors.New("Invalid Opts parameter. It must not be nil") 86 } 87 88 // Parse algorithm 89 switch opts.(type) { 90 case *bccsp.ECDSAKeyGenOpts: 91 ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) 92 if err != nil { 93 return nil, errors.Wrapf(err, "Failed generating ECDSA key") 94 } 95 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 96 97 case *bccsp.ECDSAP256KeyGenOpts: 98 ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) 99 if err != nil { 100 return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key") 101 } 102 103 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 104 105 case *bccsp.ECDSAP384KeyGenOpts: 106 ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) 107 if err != nil { 108 return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key") 109 } 110 111 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 112 113 default: 114 return csp.BCCSP.KeyGen(opts) 115 } 116 117 return k, nil 118 } 119 120 // KeyImport imports a key from its raw representation using opts. 121 // The opts argument should be appropriate for the primitive used. 122 func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { 123 // Validate arguments 124 if raw == nil { 125 return nil, errors.New("Invalid raw. Cannot be nil") 126 } 127 128 if opts == nil { 129 return nil, errors.New("Invalid Opts parameter. It must not be nil") 130 } 131 132 switch opts.(type) { 133 134 case *bccsp.X509PublicKeyImportOpts: 135 x509Cert, ok := raw.(*x509.Certificate) 136 if !ok { 137 return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate") 138 } 139 140 pk := x509Cert.PublicKey 141 142 switch pk.(type) { 143 case *ecdsa.PublicKey: 144 return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 145 case *rsa.PublicKey: 146 return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 147 default: 148 return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") 149 } 150 151 default: 152 return csp.BCCSP.KeyImport(raw, opts) 153 154 } 155 } 156 157 // GetKey returns the key this CSP associates to 158 // the Subject Key Identifier ski. 159 func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) { 160 pubKey, isPriv, err := csp.getECKey(ski) 161 if err == nil { 162 if isPriv { 163 return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil 164 } 165 return &ecdsaPublicKey{ski, pubKey}, nil 166 } 167 return csp.BCCSP.GetKey(ski) 168 } 169 170 // Sign signs digest using key k. 171 // The opts argument should be appropriate for the primitive used. 172 // 173 // Note that when a signature of a hash of a larger message is needed, 174 // the caller is responsible for hashing the larger message and passing 175 // the hash (as digest). 176 func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { 177 // Validate arguments 178 if k == nil { 179 return nil, errors.New("Invalid Key. It must not be nil") 180 } 181 if len(digest) == 0 { 182 return nil, errors.New("Invalid digest. Cannot be empty") 183 } 184 185 // Check key type 186 switch k.(type) { 187 case *ecdsaPrivateKey: 188 return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts) 189 default: 190 return csp.BCCSP.Sign(k, digest, opts) 191 } 192 } 193 194 // Verify verifies signature against key k and digest 195 func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { 196 // Validate arguments 197 if k == nil { 198 return false, errors.New("Invalid Key. It must not be nil") 199 } 200 if len(signature) == 0 { 201 return false, errors.New("Invalid signature. Cannot be empty") 202 } 203 if len(digest) == 0 { 204 return false, errors.New("Invalid digest. Cannot be empty") 205 } 206 207 // Check key type 208 switch k.(type) { 209 case *ecdsaPrivateKey: 210 return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts) 211 case *ecdsaPublicKey: 212 return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts) 213 default: 214 return csp.BCCSP.Verify(k, signature, digest, opts) 215 } 216 } 217 218 // Encrypt encrypts plaintext using key k. 219 // The opts argument should be appropriate for the primitive used. 220 func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) { 221 // TODO: Add PKCS11 support for encryption, when fabric starts requiring it 222 return csp.BCCSP.Encrypt(k, plaintext, opts) 223 } 224 225 // Decrypt decrypts ciphertext using key k. 226 // The opts argument should be appropriate for the primitive used. 227 func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) { 228 return csp.BCCSP.Decrypt(k, ciphertext, opts) 229 } 230 231 // FindPKCS11Lib IS ONLY USED FOR TESTING 232 // This is a convenience function. Useful to self-configure, for tests where usual configuration is not 233 // available 234 func FindPKCS11Lib() (lib, pin, label string) { 235 //FIXME: Till we workout the configuration piece, look for the libraries in the familiar places 236 lib = os.Getenv("PKCS11_LIB") 237 if lib == "" { 238 pin = "98765432" 239 label = "ForFabric" 240 possibilities := []string{ 241 "/usr/lib/softhsm/libsofthsm2.so", //Debian 242 "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 243 "/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 244 "/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so", //Power 245 "/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS 246 } 247 for _, path := range possibilities { 248 if _, err := os.Stat(path); !os.IsNotExist(err) { 249 lib = path 250 break 251 } 252 } 253 } else { 254 pin = os.Getenv("PKCS11_PIN") 255 label = os.Getenv("PKCS11_LABEL") 256 } 257 return lib, pin, label 258 }