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