github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/bccsp/pkcs11/impl.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 package pkcs11 17 18 import ( 19 "crypto/ecdsa" 20 "crypto/elliptic" 21 "crypto/rsa" 22 "crypto/sha256" 23 "crypto/x509" 24 "errors" 25 "fmt" 26 "math/big" 27 "os" 28 29 "github.com/hyperledger/fabric/bccsp" 30 "github.com/hyperledger/fabric/bccsp/sw" 31 "github.com/hyperledger/fabric/bccsp/utils" 32 "github.com/hyperledger/fabric/common/flogging" 33 "github.com/miekg/pkcs11" 34 ) 35 36 var ( 37 logger = flogging.MustGetLogger("bccsp_p11") 38 sessionCacheSize = 10 39 ) 40 41 // New returns a new instance of the software-based BCCSP 42 // set at the passed security level, hash family and KeyStore. 43 func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { 44 // Init config 45 conf := &config{} 46 err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily) 47 if err != nil { 48 return nil, fmt.Errorf("Failed initializing configuration [%s]", err) 49 } 50 51 swCSP, err := sw.New(opts.SecLevel, opts.HashFamily, keyStore) 52 if err != nil { 53 return nil, fmt.Errorf("Failed initializing fallback SW BCCSP [%s]", err) 54 } 55 56 // Check KeyStore 57 if keyStore == nil { 58 return nil, errors.New("Invalid bccsp.KeyStore instance. It must be different from nil.") 59 } 60 61 lib := opts.Library 62 pin := opts.Pin 63 label := opts.Label 64 ctx, slot, session, err := loadLib(lib, pin, label) 65 if err != nil { 66 return nil, fmt.Errorf("Failed initializing PKCS11 library %s %s [%s]", 67 lib, label, err) 68 } 69 70 sessions := make(chan pkcs11.SessionHandle, sessionCacheSize) 71 csp := &impl{swCSP, conf, keyStore, ctx, sessions, slot, lib, opts.Sensitive, opts.SoftVerify} 72 csp.returnSession(*session) 73 return csp, nil 74 } 75 76 type impl struct { 77 bccsp.BCCSP 78 79 conf *config 80 ks bccsp.KeyStore 81 82 ctx *pkcs11.Ctx 83 sessions chan pkcs11.SessionHandle 84 slot uint 85 86 lib string 87 noPrivImport bool 88 softVerify bool 89 } 90 91 // KeyGen generates a key using opts. 92 func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { 93 // Validate arguments 94 if opts == nil { 95 return nil, errors.New("Invalid Opts parameter. It must not be nil.") 96 } 97 98 // Parse algorithm 99 switch opts.(type) { 100 case *bccsp.ECDSAKeyGenOpts: 101 ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) 102 if err != nil { 103 return nil, fmt.Errorf("Failed generating ECDSA key [%s]", err) 104 } 105 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 106 107 case *bccsp.ECDSAP256KeyGenOpts: 108 ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) 109 if err != nil { 110 return nil, fmt.Errorf("Failed generating ECDSA P256 key [%s]", err) 111 } 112 113 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 114 115 case *bccsp.ECDSAP384KeyGenOpts: 116 ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) 117 if err != nil { 118 return nil, fmt.Errorf("Failed generating ECDSA P384 key [%s]", err) 119 } 120 121 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 122 123 default: 124 return csp.BCCSP.KeyGen(opts) 125 } 126 127 return k, nil 128 } 129 130 // KeyDeriv derives a key from k using opts. 131 // The opts argument should be appropriate for the primitive used. 132 func (csp *impl) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { 133 // Validate arguments 134 if k == nil { 135 return nil, errors.New("Invalid Key. It must not be nil.") 136 } 137 138 // Derive key 139 switch k.(type) { 140 case *ecdsaPublicKey: 141 // Validate opts 142 if opts == nil { 143 return nil, errors.New("Invalid Opts parameter. It must not be nil.") 144 } 145 146 ecdsaK := k.(*ecdsaPublicKey) 147 148 switch opts.(type) { 149 150 // Re-randomized an ECDSA public key 151 case *bccsp.ECDSAReRandKeyOpts: 152 pubKey := ecdsaK.pub 153 if pubKey == nil { 154 return nil, errors.New("Public base key cannot be nil.") 155 } 156 reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) 157 tempSK := &ecdsa.PublicKey{ 158 Curve: pubKey.Curve, 159 X: new(big.Int), 160 Y: new(big.Int), 161 } 162 163 var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) 164 var one = new(big.Int).SetInt64(1) 165 n := new(big.Int).Sub(pubKey.Params().N, one) 166 k.Mod(k, n) 167 k.Add(k, one) 168 169 // Compute temporary public key 170 tempX, tempY := pubKey.ScalarBaseMult(k.Bytes()) 171 tempSK.X, tempSK.Y = tempSK.Add( 172 pubKey.X, pubKey.Y, 173 tempX, tempY, 174 ) 175 176 // Verify temporary public key is a valid point on the reference curve 177 isOn := tempSK.Curve.IsOnCurve(tempSK.X, tempSK.Y) 178 if !isOn { 179 return nil, errors.New("Failed temporary public key IsOnCurve check.") 180 } 181 182 ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) 183 oid, ok := oidFromNamedCurve(tempSK.Curve) 184 if !ok { 185 return nil, errors.New("Do not know OID for this Curve.") 186 } 187 188 ski, err := csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) 189 if err != nil { 190 return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) 191 } 192 reRandomizedKey := &ecdsaPublicKey{ski, tempSK} 193 194 return reRandomizedKey, nil 195 196 default: 197 return nil, fmt.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) 198 199 } 200 case *ecdsaPrivateKey: 201 // Validate opts 202 if opts == nil { 203 return nil, errors.New("Invalid Opts parameter. It must not be nil.") 204 } 205 206 ecdsaK := k.(*ecdsaPrivateKey) 207 208 switch opts.(type) { 209 210 // Re-randomized an ECDSA private key 211 case *bccsp.ECDSAReRandKeyOpts: 212 reRandOpts := opts.(*bccsp.ECDSAReRandKeyOpts) 213 pubKey := ecdsaK.pub.pub 214 if pubKey == nil { 215 return nil, errors.New("Public base key cannot be nil.") 216 } 217 218 secret := csp.getSecretValue(ecdsaK.ski) 219 if secret == nil { 220 return nil, errors.New("Could not obtain EC Private Key") 221 } 222 bigSecret := new(big.Int).SetBytes(secret) 223 224 tempSK := &ecdsa.PrivateKey{ 225 PublicKey: ecdsa.PublicKey{ 226 Curve: pubKey.Curve, 227 X: new(big.Int), 228 Y: new(big.Int), 229 }, 230 D: new(big.Int), 231 } 232 233 var k = new(big.Int).SetBytes(reRandOpts.ExpansionValue()) 234 var one = new(big.Int).SetInt64(1) 235 n := new(big.Int).Sub(pubKey.Params().N, one) 236 k.Mod(k, n) 237 k.Add(k, one) 238 239 tempSK.D.Add(bigSecret, k) 240 tempSK.D.Mod(tempSK.D, pubKey.Params().N) 241 242 // Compute temporary public key 243 tempSK.PublicKey.X, tempSK.PublicKey.Y = pubKey.ScalarBaseMult(tempSK.D.Bytes()) 244 245 // Verify temporary public key is a valid point on the reference curve 246 isOn := tempSK.Curve.IsOnCurve(tempSK.PublicKey.X, tempSK.PublicKey.Y) 247 if !isOn { 248 return nil, errors.New("Failed temporary public key IsOnCurve check.") 249 } 250 251 ecPt := elliptic.Marshal(tempSK.Curve, tempSK.X, tempSK.Y) 252 oid, ok := oidFromNamedCurve(tempSK.Curve) 253 if !ok { 254 return nil, errors.New("Do not know OID for this Curve.") 255 } 256 257 ski, err := csp.importECKey(oid, tempSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) 258 if err != nil { 259 return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) 260 } 261 reRandomizedKey := &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &tempSK.PublicKey}} 262 263 return reRandomizedKey, nil 264 265 default: 266 return nil, fmt.Errorf("Unrecognized KeyDerivOpts provided [%s]", opts.Algorithm()) 267 268 } 269 270 default: 271 return csp.BCCSP.KeyDeriv(k, opts) 272 273 } 274 } 275 276 // KeyImport imports a key from its raw representation using opts. 277 // The opts argument should be appropriate for the primitive used. 278 func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { 279 // Validate arguments 280 if raw == nil { 281 return nil, errors.New("Invalid raw. Cannot be nil.") 282 } 283 284 if opts == nil { 285 return nil, errors.New("Invalid Opts parameter. It must not be nil.") 286 } 287 288 switch opts.(type) { 289 290 case *bccsp.ECDSAPKIXPublicKeyImportOpts: 291 der, ok := raw.([]byte) 292 if !ok { 293 return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw material. Expected byte array.") 294 } 295 296 if len(der) == 0 { 297 return nil, errors.New("[ECDSAPKIXPublicKeyImportOpts] Invalid raw. It must not be nil.") 298 } 299 300 lowLevelKey, err := utils.DERToPublicKey(der) 301 if err != nil { 302 return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) 303 } 304 305 ecdsaPK, ok := lowLevelKey.(*ecdsa.PublicKey) 306 if !ok { 307 return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") 308 } 309 310 ecPt := elliptic.Marshal(ecdsaPK.Curve, ecdsaPK.X, ecdsaPK.Y) 311 oid, ok := oidFromNamedCurve(ecdsaPK.Curve) 312 if !ok { 313 return nil, errors.New("Do not know OID for this Curve.") 314 } 315 316 var ski []byte 317 if csp.noPrivImport { 318 // opencryptoki does not support public ec key imports. This is a sufficient 319 // workaround for now to use soft verify 320 hash := sha256.Sum256(ecPt) 321 ski = hash[:] 322 } else { 323 // Warn about potential future problems 324 if !csp.softVerify { 325 logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + 326 "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + 327 "in pkcs11 options, if suspect this issue.") 328 } 329 ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) 330 if err != nil { 331 return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) 332 } 333 } 334 335 k = &ecdsaPublicKey{ski, ecdsaPK} 336 return k, nil 337 338 case *bccsp.ECDSAPrivateKeyImportOpts: 339 if csp.noPrivImport { 340 return nil, errors.New("[ECDSADERPrivateKeyImportOpts] PKCS11 options 'sensitivekeys' is set to true. Cannot import.") 341 } 342 343 der, ok := raw.([]byte) 344 if !ok { 345 return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw material. Expected byte array.") 346 } 347 348 if len(der) == 0 { 349 return nil, errors.New("[ECDSADERPrivateKeyImportOpts] Invalid raw. It must not be nil.") 350 } 351 352 lowLevelKey, err := utils.DERToPrivateKey(der) 353 if err != nil { 354 return nil, fmt.Errorf("Failed converting PKIX to ECDSA public key [%s]", err) 355 } 356 357 ecdsaSK, ok := lowLevelKey.(*ecdsa.PrivateKey) 358 if !ok { 359 return nil, errors.New("Failed casting to ECDSA public key. Invalid raw material.") 360 } 361 362 ecPt := elliptic.Marshal(ecdsaSK.Curve, ecdsaSK.X, ecdsaSK.Y) 363 oid, ok := oidFromNamedCurve(ecdsaSK.Curve) 364 if !ok { 365 return nil, errors.New("Do not know OID for this Curve.") 366 } 367 368 ski, err := csp.importECKey(oid, ecdsaSK.D.Bytes(), ecPt, opts.Ephemeral(), privateKeyFlag) 369 if err != nil { 370 return nil, fmt.Errorf("Failed getting importing EC Private Key [%s]", err) 371 } 372 373 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, &ecdsaSK.PublicKey}} 374 return k, nil 375 376 case *bccsp.ECDSAGoPublicKeyImportOpts: 377 lowLevelKey, ok := raw.(*ecdsa.PublicKey) 378 if !ok { 379 return nil, errors.New("[ECDSAGoPublicKeyImportOpts] Invalid raw material. Expected *ecdsa.PublicKey.") 380 } 381 382 ecPt := elliptic.Marshal(lowLevelKey.Curve, lowLevelKey.X, lowLevelKey.Y) 383 oid, ok := oidFromNamedCurve(lowLevelKey.Curve) 384 if !ok { 385 return nil, errors.New("Do not know OID for this Curve.") 386 } 387 388 var ski []byte 389 if csp.noPrivImport { 390 // opencryptoki does not support public ec key imports. This is a sufficient 391 // workaround for now to use soft verify 392 hash := sha256.Sum256(ecPt) 393 ski = hash[:] 394 } else { 395 // Warn about potential future problems 396 if !csp.softVerify { 397 logger.Debugf("opencryptoki workaround warning: Importing public EC Key does not store out to pkcs11 store,\n" + 398 "so verify with this key will fail, unless key is already present in store. Enable 'softwareverify'\n" + 399 "in pkcs11 options, if suspect this issue.") 400 } 401 ski, err = csp.importECKey(oid, nil, ecPt, opts.Ephemeral(), publicKeyFlag) 402 if err != nil { 403 return nil, fmt.Errorf("Failed getting importing EC Public Key [%s]", err) 404 } 405 } 406 407 k = &ecdsaPublicKey{ski, lowLevelKey} 408 return k, nil 409 410 case *bccsp.X509PublicKeyImportOpts: 411 x509Cert, ok := raw.(*x509.Certificate) 412 if !ok { 413 return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate.") 414 } 415 416 pk := x509Cert.PublicKey 417 418 switch pk.(type) { 419 case *ecdsa.PublicKey: 420 return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 421 case *rsa.PublicKey: 422 return csp.KeyImport(pk, &bccsp.RSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 423 default: 424 return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA, RSA]") 425 } 426 427 default: 428 return csp.BCCSP.KeyImport(raw, opts) 429 430 } 431 } 432 433 // GetKey returns the key this CSP associates to 434 // the Subject Key Identifier ski. 435 func (csp *impl) GetKey(ski []byte) (k bccsp.Key, err error) { 436 pubKey, isPriv, err := csp.getECKey(ski) 437 if err == nil { 438 if isPriv { 439 return &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}}, nil 440 } else { 441 return &ecdsaPublicKey{ski, pubKey}, nil 442 } 443 } 444 return csp.BCCSP.GetKey(ski) 445 } 446 447 // Sign signs digest using key k. 448 // The opts argument should be appropriate for the primitive used. 449 // 450 // Note that when a signature of a hash of a larger message is needed, 451 // the caller is responsible for hashing the larger message and passing 452 // the hash (as digest). 453 func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { 454 // Validate arguments 455 if k == nil { 456 return nil, errors.New("Invalid Key. It must not be nil.") 457 } 458 if len(digest) == 0 { 459 return nil, errors.New("Invalid digest. Cannot be empty.") 460 } 461 462 // Check key type 463 switch k.(type) { 464 case *ecdsaPrivateKey: 465 return csp.signECDSA(*k.(*ecdsaPrivateKey), digest, opts) 466 default: 467 return csp.BCCSP.Sign(k, digest, opts) 468 } 469 } 470 471 // Verify verifies signature against key k and digest 472 func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { 473 // Validate arguments 474 if k == nil { 475 return false, errors.New("Invalid Key. It must not be nil.") 476 } 477 if len(signature) == 0 { 478 return false, errors.New("Invalid signature. Cannot be empty.") 479 } 480 if len(digest) == 0 { 481 return false, errors.New("Invalid digest. Cannot be empty.") 482 } 483 484 // Check key type 485 switch k.(type) { 486 case *ecdsaPrivateKey: 487 return csp.verifyECDSA(k.(*ecdsaPrivateKey).pub, signature, digest, opts) 488 case *ecdsaPublicKey: 489 return csp.verifyECDSA(*k.(*ecdsaPublicKey), signature, digest, opts) 490 default: 491 return csp.BCCSP.Verify(k, signature, digest, opts) 492 } 493 } 494 495 // Encrypt encrypts plaintext using key k. 496 // The opts argument should be appropriate for the primitive used. 497 func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) { 498 // TODO: Add PKCS11 support for encryption, when fabric starts requiring it 499 return csp.BCCSP.Encrypt(k, plaintext, opts) 500 } 501 502 // Decrypt decrypts ciphertext using key k. 503 // The opts argument should be appropriate for the primitive used. 504 func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) { 505 return csp.BCCSP.Decrypt(k, ciphertext, opts) 506 } 507 508 // THIS IS ONLY USED FOR TESTING 509 // This is a convenience function. Useful to self-configure, for tests where usual configuration is not 510 // available 511 func FindPKCS11Lib() (lib, pin, label string) { 512 //FIXME: Till we workout the configuration piece, look for the libraries in the familiar places 513 lib = os.Getenv("PKCS11_LIB") 514 if lib == "" { 515 pin = "98765432" 516 label = "ForFabric" 517 possibilities := []string{ 518 "/usr/lib/softhsm/libsofthsm2.so", //Debian 519 "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 520 "/usr/lib/s390x-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 521 "/usr/lib/powerpc64le-linux-gnu/softhsm/libsofthsm2.so", //Power 522 "/usr/local/Cellar/softhsm/2.1.0/lib/softhsm/libsofthsm2.so", //MacOS 523 } 524 for _, path := range possibilities { 525 if _, err := os.Stat(path); !os.IsNotExist(err) { 526 lib = path 527 break 528 } 529 } 530 } else { 531 pin = os.Getenv("PKCS11_PIN") 532 label = os.Getenv("PKCS11_LABEL") 533 } 534 return lib, pin, label 535 }