github.com/true-sqn/fabric@v2.1.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, pin, 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 pin string 70 71 lib string 72 softVerify bool 73 //Immutable flag makes object immutable 74 immutable bool 75 } 76 77 // KeyGen generates a key using opts. 78 func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { 79 // Validate arguments 80 if opts == nil { 81 return nil, errors.New("Invalid Opts parameter. It must not be nil") 82 } 83 84 // Parse algorithm 85 switch opts.(type) { 86 case *bccsp.ECDSAKeyGenOpts: 87 ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) 88 if err != nil { 89 return nil, errors.Wrapf(err, "Failed generating ECDSA key") 90 } 91 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 92 93 case *bccsp.ECDSAP256KeyGenOpts: 94 ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) 95 if err != nil { 96 return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key") 97 } 98 99 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 100 101 case *bccsp.ECDSAP384KeyGenOpts: 102 ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) 103 if err != nil { 104 return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key") 105 } 106 107 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 108 109 default: 110 return csp.BCCSP.KeyGen(opts) 111 } 112 113 return k, nil 114 } 115 116 // KeyImport imports a key from its raw representation using opts. 117 // The opts argument should be appropriate for the primitive used. 118 func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { 119 // Validate arguments 120 if raw == nil { 121 return nil, errors.New("Invalid raw. Cannot be nil") 122 } 123 124 if opts == nil { 125 return nil, errors.New("Invalid Opts parameter. It must not be nil") 126 } 127 128 switch opts.(type) { 129 130 case *bccsp.X509PublicKeyImportOpts: 131 x509Cert, ok := raw.(*x509.Certificate) 132 if !ok { 133 return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate") 134 } 135 136 pk := x509Cert.PublicKey 137 138 switch pk.(type) { 139 case *ecdsa.PublicKey: 140 return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 141 default: 142 return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA]") 143 } 144 145 default: 146 return csp.BCCSP.KeyImport(raw, opts) 147 148 } 149 } 150 151 // GetKey returns the key this CSP associates to 152 // the Subject Key Identifier ski. 153 func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) { 154 pubKey, isPriv, err := csp.getECKey(ski) 155 if err == nil { 156 if isPriv { 157 return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil 158 } 159 return &ecdsaPublicKey{ski, pubKey}, nil 160 } 161 return csp.BCCSP.GetKey(ski) 162 } 163 164 // Sign signs digest using key k. 165 // The opts argument should be appropriate for the primitive used. 166 // 167 // Note that when a signature of a hash of a larger message is needed, 168 // the caller is responsible for hashing the larger message and passing 169 // the hash (as digest). 170 func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { 171 // Validate arguments 172 if k == nil { 173 return nil, errors.New("Invalid Key. It must not be nil") 174 } 175 if len(digest) == 0 { 176 return nil, errors.New("Invalid digest. Cannot be empty") 177 } 178 179 // Check key type 180 switch key := k.(type) { 181 case *ecdsaPrivateKey: 182 return csp.signECDSA(*key, digest, opts) 183 default: 184 return csp.BCCSP.Sign(key, digest, opts) 185 } 186 } 187 188 // Verify verifies signature against key k and digest 189 func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { 190 // Validate arguments 191 if k == nil { 192 return false, errors.New("Invalid Key. It must not be nil") 193 } 194 if len(signature) == 0 { 195 return false, errors.New("Invalid signature. Cannot be empty") 196 } 197 if len(digest) == 0 { 198 return false, errors.New("Invalid digest. Cannot be empty") 199 } 200 201 // Check key type 202 switch key := k.(type) { 203 case *ecdsaPrivateKey: 204 return csp.verifyECDSA(key.pub, signature, digest, opts) 205 case *ecdsaPublicKey: 206 return csp.verifyECDSA(*key, signature, digest, opts) 207 default: 208 return csp.BCCSP.Verify(k, signature, digest, opts) 209 } 210 } 211 212 // Encrypt encrypts plaintext using key k. 213 // The opts argument should be appropriate for the primitive used. 214 func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) { 215 // TODO: Add PKCS11 support for encryption, when fabric starts requiring it 216 return csp.BCCSP.Encrypt(k, plaintext, opts) 217 } 218 219 // Decrypt decrypts ciphertext using key k. 220 // The opts argument should be appropriate for the primitive used. 221 func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) { 222 return csp.BCCSP.Decrypt(k, ciphertext, opts) 223 } 224 225 // FindPKCS11Lib IS ONLY USED FOR TESTING 226 // This is a convenience function. Useful to self-configure, for tests where usual configuration is not 227 // available 228 func FindPKCS11Lib() (lib, pin, label string) { 229 //FIXME: Till we workout the configuration piece, look for the libraries in the familiar places 230 lib = os.Getenv("PKCS11_LIB") 231 if lib == "" { 232 pin = "98765432" 233 label = "ForFabric" 234 possibilities := []string{ 235 "/usr/lib/softhsm/libsofthsm2.so", //Debian 236 "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 237 "/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 238 "/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so", //Power 239 "/usr/local/Cellar/softhsm/2.5.0/lib/softhsm/libsofthsm2.so", //MacOS 240 } 241 for _, path := range possibilities { 242 if _, err := os.Stat(path); !os.IsNotExist(err) { 243 lib = path 244 break 245 } 246 } 247 } else { 248 pin = os.Getenv("PKCS11_PIN") 249 label = os.Getenv("PKCS11_LABEL") 250 } 251 return lib, pin, label 252 }