github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/bccsp/pkcs11/pkcs11.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/elliptic" 12 "crypto/sha256" 13 "crypto/x509" 14 "encoding/asn1" 15 "encoding/hex" 16 "fmt" 17 "math/big" 18 "os" 19 "regexp" 20 "sync" 21 "time" 22 23 "github.com/miekg/pkcs11" 24 "github.com/osdi23p228/fabric/bccsp" 25 "github.com/osdi23p228/fabric/bccsp/sw" 26 "github.com/osdi23p228/fabric/common/flogging" 27 "github.com/pkg/errors" 28 "go.uber.org/zap/zapcore" 29 ) 30 31 const createSessionRetries = 10 32 33 var ( 34 logger = flogging.MustGetLogger("bccsp_p11") 35 regex = regexp.MustCompile(".*0xB.:\\sCKR.+") 36 sessionCacheSize = 10 37 ) 38 39 type impl struct { 40 bccsp.BCCSP 41 42 slot uint 43 pin string 44 ctx *pkcs11.Ctx 45 conf *config 46 softVerify bool 47 immutable bool 48 49 sessLock sync.Mutex 50 sessPool chan pkcs11.SessionHandle 51 sessions map[pkcs11.SessionHandle]struct{} 52 53 cacheLock sync.RWMutex 54 handleCache map[string]pkcs11.ObjectHandle 55 keyCache map[string]bccsp.Key 56 } 57 58 // New WithParams returns a new instance of the software-based BCCSP 59 // set at the passed security level, hash family and KeyStore. 60 func New(opts PKCS11Opts, keyStore bccsp.KeyStore) (bccsp.BCCSP, error) { 61 // Init config 62 conf := &config{} 63 err := conf.setSecurityLevel(opts.SecLevel, opts.HashFamily) 64 if err != nil { 65 return nil, errors.Wrapf(err, "Failed initializing configuration") 66 } 67 68 swCSP, err := sw.NewWithParams(opts.SecLevel, opts.HashFamily, keyStore) 69 if err != nil { 70 return nil, errors.Wrapf(err, "Failed initializing fallback SW BCCSP") 71 } 72 73 var sessPool chan pkcs11.SessionHandle 74 if sessionCacheSize > 0 { 75 sessPool = make(chan pkcs11.SessionHandle, sessionCacheSize) 76 } 77 78 csp := &impl{ 79 BCCSP: swCSP, 80 conf: conf, 81 sessPool: sessPool, 82 sessions: map[pkcs11.SessionHandle]struct{}{}, 83 handleCache: map[string]pkcs11.ObjectHandle{}, 84 softVerify: opts.SoftVerify, 85 keyCache: map[string]bccsp.Key{}, 86 immutable: opts.Immutable, 87 } 88 89 return csp.initialize(opts) 90 } 91 92 func (csp *impl) initialize(opts PKCS11Opts) (*impl, error) { 93 if opts.Library == "" { 94 return nil, fmt.Errorf("pkcs11: library path not provided") 95 } 96 97 ctx := pkcs11.New(opts.Library) 98 if ctx == nil { 99 return nil, fmt.Errorf("pkcs11: instantiation failed for %s", opts.Library) 100 } 101 if err := ctx.Initialize(); err != nil { 102 logger.Debugf("initialize failed: %v", err) 103 } 104 105 csp.ctx = ctx 106 csp.pin = opts.Pin 107 108 slots, err := ctx.GetSlotList(true) 109 if err != nil { 110 return nil, errors.Wrap(err, "pkcs11: get slot list") 111 } 112 113 for _, s := range slots { 114 info, err := ctx.GetTokenInfo(s) 115 if err != nil || opts.Label != info.Label { 116 continue 117 } 118 119 csp.slot = s 120 121 session, err := csp.createSession() 122 if err != nil { 123 return nil, err 124 } 125 126 csp.returnSession(session) 127 return csp, nil 128 } 129 130 return nil, errors.Errorf("pkcs11: could not find token with label %s", opts.Label) 131 } 132 133 // KeyGen generates a key using opts. 134 func (csp *impl) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { 135 // Validate arguments 136 if opts == nil { 137 return nil, errors.New("Invalid Opts parameter. It must not be nil") 138 } 139 140 // Parse algorithm 141 switch opts.(type) { 142 case *bccsp.ECDSAKeyGenOpts: 143 ski, pub, err := csp.generateECKey(csp.conf.ellipticCurve, opts.Ephemeral()) 144 if err != nil { 145 return nil, errors.Wrapf(err, "Failed generating ECDSA key") 146 } 147 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 148 149 case *bccsp.ECDSAP256KeyGenOpts: 150 ski, pub, err := csp.generateECKey(oidNamedCurveP256, opts.Ephemeral()) 151 if err != nil { 152 return nil, errors.Wrapf(err, "Failed generating ECDSA P256 key") 153 } 154 155 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 156 157 case *bccsp.ECDSAP384KeyGenOpts: 158 ski, pub, err := csp.generateECKey(oidNamedCurveP384, opts.Ephemeral()) 159 if err != nil { 160 return nil, errors.Wrapf(err, "Failed generating ECDSA P384 key") 161 } 162 163 k = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pub}} 164 165 default: 166 return csp.BCCSP.KeyGen(opts) 167 } 168 169 return k, nil 170 } 171 172 // KeyImport imports a key from its raw representation using opts. 173 // The opts argument should be appropriate for the primitive used. 174 func (csp *impl) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { 175 // Validate arguments 176 if raw == nil { 177 return nil, errors.New("Invalid raw. Cannot be nil") 178 } 179 180 if opts == nil { 181 return nil, errors.New("Invalid Opts parameter. It must not be nil") 182 } 183 184 switch opts.(type) { 185 186 case *bccsp.X509PublicKeyImportOpts: 187 x509Cert, ok := raw.(*x509.Certificate) 188 if !ok { 189 return nil, errors.New("[X509PublicKeyImportOpts] Invalid raw material. Expected *x509.Certificate") 190 } 191 192 pk := x509Cert.PublicKey 193 194 switch pk.(type) { 195 case *ecdsa.PublicKey: 196 return csp.KeyImport(pk, &bccsp.ECDSAGoPublicKeyImportOpts{Temporary: opts.Ephemeral()}) 197 default: 198 return nil, errors.New("Certificate's public key type not recognized. Supported keys: [ECDSA]") 199 } 200 201 default: 202 return csp.BCCSP.KeyImport(raw, opts) 203 204 } 205 } 206 207 func (csp *impl) cacheKey(ski []byte, key bccsp.Key) { 208 csp.cacheLock.Lock() 209 csp.keyCache[hex.EncodeToString(ski)] = key 210 csp.cacheLock.Unlock() 211 } 212 213 func (csp *impl) cachedKey(ski []byte) (bccsp.Key, bool) { 214 csp.cacheLock.RLock() 215 defer csp.cacheLock.RUnlock() 216 key, ok := csp.keyCache[hex.EncodeToString(ski)] 217 return key, ok 218 } 219 220 // GetKey returns the key this CSP associates to 221 // the Subject Key Identifier ski. 222 func (csp *impl) GetKey(ski []byte) (bccsp.Key, error) { 223 if key, ok := csp.cachedKey(ski); ok { 224 return key, nil 225 } 226 227 pubKey, isPriv, err := csp.getECKey(ski) 228 if err != nil { 229 logger.Debugf("Key not found using PKCS11: %v", err) 230 return csp.BCCSP.GetKey(ski) 231 } 232 233 var key bccsp.Key = &ecdsaPublicKey{ski, pubKey} 234 if isPriv { 235 key = &ecdsaPrivateKey{ski, ecdsaPublicKey{ski, pubKey}} 236 } 237 238 csp.cacheKey(ski, key) 239 return key, nil 240 } 241 242 // Sign signs digest using key k. 243 // The opts argument should be appropriate for the primitive used. 244 // 245 // Note that when a signature of a hash of a larger message is needed, 246 // the caller is responsible for hashing the larger message and passing 247 // the hash (as digest). 248 func (csp *impl) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { 249 // Validate arguments 250 if k == nil { 251 return nil, errors.New("Invalid Key. It must not be nil") 252 } 253 if len(digest) == 0 { 254 return nil, errors.New("Invalid digest. Cannot be empty") 255 } 256 257 // Check key type 258 switch key := k.(type) { 259 case *ecdsaPrivateKey: 260 return csp.signECDSA(*key, digest, opts) 261 default: 262 return csp.BCCSP.Sign(key, digest, opts) 263 } 264 } 265 266 // Verify verifies signature against key k and digest 267 func (csp *impl) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { 268 // Validate arguments 269 if k == nil { 270 return false, errors.New("Invalid Key. It must not be nil") 271 } 272 if len(signature) == 0 { 273 return false, errors.New("Invalid signature. Cannot be empty") 274 } 275 if len(digest) == 0 { 276 return false, errors.New("Invalid digest. Cannot be empty") 277 } 278 279 // Check key type 280 switch key := k.(type) { 281 case *ecdsaPrivateKey: 282 return csp.verifyECDSA(key.pub, signature, digest, opts) 283 case *ecdsaPublicKey: 284 return csp.verifyECDSA(*key, signature, digest, opts) 285 default: 286 return csp.BCCSP.Verify(k, signature, digest, opts) 287 } 288 } 289 290 // Encrypt encrypts plaintext using key k. 291 // The opts argument should be appropriate for the primitive used. 292 func (csp *impl) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) ([]byte, error) { 293 // TODO: Add PKCS11 support for encryption, when fabric starts requiring it 294 return csp.BCCSP.Encrypt(k, plaintext, opts) 295 } 296 297 // Decrypt decrypts ciphertext using key k. 298 // The opts argument should be appropriate for the primitive used. 299 func (csp *impl) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) ([]byte, error) { 300 return csp.BCCSP.Decrypt(k, ciphertext, opts) 301 } 302 303 func (csp *impl) getSession() (session pkcs11.SessionHandle, err error) { 304 for { 305 select { 306 case session = <-csp.sessPool: 307 return 308 default: 309 // cache is empty (or completely in use), create a new session 310 return csp.createSession() 311 } 312 } 313 } 314 315 func (csp *impl) createSession() (pkcs11.SessionHandle, error) { 316 var sess pkcs11.SessionHandle 317 var err error 318 319 // attempt to open a session with a 100ms delay after each attempt 320 for i := 0; i < createSessionRetries; i++ { 321 sess, err = csp.ctx.OpenSession(csp.slot, pkcs11.CKF_SERIAL_SESSION|pkcs11.CKF_RW_SESSION) 322 if err == nil { 323 logger.Debugf("Created new pkcs11 session %d on slot %d\n", sess, csp.slot) 324 break 325 } 326 327 logger.Warningf("OpenSession failed, retrying [%s]\n", err) 328 time.Sleep(100 * time.Millisecond) 329 } 330 if err != nil { 331 return 0, errors.Wrap(err, "OpenSession failed") 332 } 333 334 err = csp.ctx.Login(sess, pkcs11.CKU_USER, csp.pin) 335 if err != nil && err != pkcs11.Error(pkcs11.CKR_USER_ALREADY_LOGGED_IN) { 336 csp.ctx.CloseSession(sess) 337 return 0, errors.Wrap(err, "Login failed") 338 } 339 340 csp.sessLock.Lock() 341 csp.sessions[sess] = struct{}{} 342 csp.sessLock.Unlock() 343 344 return sess, nil 345 } 346 347 func (csp *impl) closeSession(session pkcs11.SessionHandle) { 348 if err := csp.ctx.CloseSession(session); err != nil { 349 logger.Debug("CloseSession failed", err) 350 } 351 352 csp.sessLock.Lock() 353 defer csp.sessLock.Unlock() 354 355 // purge the handle cache if the last session closes 356 delete(csp.sessions, session) 357 if len(csp.sessions) == 0 { 358 csp.clearCaches() 359 } 360 } 361 362 func (csp *impl) returnSession(session pkcs11.SessionHandle) { 363 select { 364 case csp.sessPool <- session: 365 // returned session back to session cache 366 default: 367 // have plenty of sessions in cache, dropping 368 csp.closeSession(session) 369 } 370 } 371 372 // Look for an EC key by SKI, stored in CKA_ID 373 func (csp *impl) getECKey(ski []byte) (pubKey *ecdsa.PublicKey, isPriv bool, err error) { 374 session, err := csp.getSession() 375 if err != nil { 376 return nil, false, err 377 } 378 defer func() { csp.handleSessionReturn(err, session) }() 379 380 isPriv = true 381 _, err = csp.findKeyPairFromSKI(session, ski, privateKeyType) 382 if err != nil { 383 isPriv = false 384 logger.Debugf("Private key not found [%s] for SKI [%s], looking for Public key", err, hex.EncodeToString(ski)) 385 } 386 387 publicKey, err := csp.findKeyPairFromSKI(session, ski, publicKeyType) 388 if err != nil { 389 return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) 390 } 391 392 ecpt, marshaledOid, err := csp.ecPoint(session, publicKey) 393 if err != nil { 394 return nil, false, fmt.Errorf("Public key not found [%s] for SKI [%s]", err, hex.EncodeToString(ski)) 395 } 396 397 curveOid := new(asn1.ObjectIdentifier) 398 _, err = asn1.Unmarshal(marshaledOid, curveOid) 399 if err != nil { 400 return nil, false, fmt.Errorf("Failed Unmarshaling Curve OID [%s]\n%s", err.Error(), hex.EncodeToString(marshaledOid)) 401 } 402 403 curve := namedCurveFromOID(*curveOid) 404 if curve == nil { 405 return nil, false, fmt.Errorf("Cound not recognize Curve from OID") 406 } 407 x, y := elliptic.Unmarshal(curve, ecpt) 408 if x == nil { 409 return nil, false, fmt.Errorf("Failed Unmarshaling Public Key") 410 } 411 412 pubKey = &ecdsa.PublicKey{Curve: curve, X: x, Y: y} 413 return pubKey, isPriv, nil 414 } 415 416 // RFC 5480, 2.1.1.1. Named Curve 417 // 418 // secp224r1 OBJECT IDENTIFIER ::= { 419 // iso(1) identified-organization(3) certicom(132) curve(0) 33 } 420 // 421 // secp256r1 OBJECT IDENTIFIER ::= { 422 // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) 423 // prime(1) 7 } 424 // 425 // secp384r1 OBJECT IDENTIFIER ::= { 426 // iso(1) identified-organization(3) certicom(132) curve(0) 34 } 427 // 428 // secp521r1 OBJECT IDENTIFIER ::= { 429 // iso(1) identified-organization(3) certicom(132) curve(0) 35 } 430 // 431 var ( 432 oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} 433 oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} 434 oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} 435 oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} 436 ) 437 438 func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { 439 switch { 440 case oid.Equal(oidNamedCurveP224): 441 return elliptic.P224() 442 case oid.Equal(oidNamedCurveP256): 443 return elliptic.P256() 444 case oid.Equal(oidNamedCurveP384): 445 return elliptic.P384() 446 case oid.Equal(oidNamedCurveP521): 447 return elliptic.P521() 448 } 449 return nil 450 } 451 452 func (csp *impl) generateECKey(curve asn1.ObjectIdentifier, ephemeral bool) (ski []byte, pubKey *ecdsa.PublicKey, err error) { 453 session, err := csp.getSession() 454 if err != nil { 455 return nil, nil, err 456 } 457 defer func() { csp.handleSessionReturn(err, session) }() 458 459 id := nextIDCtr() 460 publabel := fmt.Sprintf("BCPUB%s", id.Text(16)) 461 prvlabel := fmt.Sprintf("BCPRV%s", id.Text(16)) 462 463 marshaledOID, err := asn1.Marshal(curve) 464 if err != nil { 465 return nil, nil, fmt.Errorf("Could not marshal OID [%s]", err.Error()) 466 } 467 468 pubkeyT := []*pkcs11.Attribute{ 469 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), 470 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), 471 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), 472 pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), 473 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, marshaledOID), 474 475 pkcs11.NewAttribute(pkcs11.CKA_ID, publabel), 476 pkcs11.NewAttribute(pkcs11.CKA_LABEL, publabel), 477 } 478 479 prvkeyT := []*pkcs11.Attribute{ 480 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, pkcs11.CKK_EC), 481 pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), 482 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, !ephemeral), 483 pkcs11.NewAttribute(pkcs11.CKA_PRIVATE, true), 484 pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), 485 486 pkcs11.NewAttribute(pkcs11.CKA_ID, prvlabel), 487 pkcs11.NewAttribute(pkcs11.CKA_LABEL, prvlabel), 488 489 pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false), 490 pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true), 491 } 492 493 pub, prv, err := csp.ctx.GenerateKeyPair(session, 494 []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil)}, 495 pubkeyT, 496 prvkeyT, 497 ) 498 if err != nil { 499 return nil, nil, fmt.Errorf("P11: keypair generate failed [%s]", err) 500 } 501 502 ecpt, _, err := csp.ecPoint(session, pub) 503 if err != nil { 504 return nil, nil, fmt.Errorf("Error querying EC-point: [%s]", err) 505 } 506 hash := sha256.Sum256(ecpt) 507 ski = hash[:] 508 509 // set CKA_ID of the both keys to SKI(public key) and CKA_LABEL to hex string of SKI 510 setskiT := []*pkcs11.Attribute{ 511 pkcs11.NewAttribute(pkcs11.CKA_ID, ski), 512 pkcs11.NewAttribute(pkcs11.CKA_LABEL, hex.EncodeToString(ski)), 513 } 514 515 logger.Infof("Generated new P11 key, SKI %x\n", ski) 516 err = csp.ctx.SetAttributeValue(session, pub, setskiT) 517 if err != nil { 518 return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[public] failed [%s]", err) 519 } 520 521 err = csp.ctx.SetAttributeValue(session, prv, setskiT) 522 if err != nil { 523 return nil, nil, fmt.Errorf("P11: set-ID-to-SKI[private] failed [%s]", err) 524 } 525 526 //Set CKA_Modifible to false for both public key and private keys 527 if csp.immutable { 528 setCKAModifiable := []*pkcs11.Attribute{ 529 pkcs11.NewAttribute(pkcs11.CKA_MODIFIABLE, false), 530 } 531 532 _, pubCopyerror := csp.ctx.CopyObject(session, pub, setCKAModifiable) 533 if pubCopyerror != nil { 534 return nil, nil, fmt.Errorf("P11: Public Key copy failed with error [%s] . Please contact your HSM vendor", pubCopyerror) 535 } 536 537 pubKeyDestroyError := csp.ctx.DestroyObject(session, pub) 538 if pubKeyDestroyError != nil { 539 return nil, nil, fmt.Errorf("P11: Public Key destroy failed with error [%s]. Please contact your HSM vendor", pubCopyerror) 540 } 541 542 _, prvCopyerror := csp.ctx.CopyObject(session, prv, setCKAModifiable) 543 if prvCopyerror != nil { 544 return nil, nil, fmt.Errorf("P11: Private Key copy failed with error [%s]. Please contact your HSM vendor", prvCopyerror) 545 } 546 prvKeyDestroyError := csp.ctx.DestroyObject(session, prv) 547 if prvKeyDestroyError != nil { 548 return nil, nil, fmt.Errorf("P11: Private Key destroy failed with error [%s]. Please contact your HSM vendor", prvKeyDestroyError) 549 } 550 } 551 552 nistCurve := namedCurveFromOID(curve) 553 if curve == nil { 554 return nil, nil, fmt.Errorf("Cound not recognize Curve from OID") 555 } 556 x, y := elliptic.Unmarshal(nistCurve, ecpt) 557 if x == nil { 558 return nil, nil, fmt.Errorf("Failed Unmarshaling Public Key") 559 } 560 561 pubGoKey := &ecdsa.PublicKey{Curve: nistCurve, X: x, Y: y} 562 563 if logger.IsEnabledFor(zapcore.DebugLevel) { 564 listAttrs(csp.ctx, session, prv) 565 listAttrs(csp.ctx, session, pub) 566 } 567 568 return ski, pubGoKey, nil 569 } 570 571 func (csp *impl) signP11ECDSA(ski []byte, msg []byte) (R, S *big.Int, err error) { 572 session, err := csp.getSession() 573 if err != nil { 574 return nil, nil, err 575 } 576 defer func() { csp.handleSessionReturn(err, session) }() 577 578 privateKey, err := csp.findKeyPairFromSKI(session, ski, privateKeyType) 579 if err != nil { 580 return nil, nil, fmt.Errorf("Private key not found [%s]", err) 581 } 582 583 err = csp.ctx.SignInit(session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, privateKey) 584 if err != nil { 585 return nil, nil, fmt.Errorf("Sign-initialize failed [%s]", err) 586 } 587 588 var sig []byte 589 590 sig, err = csp.ctx.Sign(session, msg) 591 if err != nil { 592 return nil, nil, fmt.Errorf("P11: sign failed [%s]", err) 593 } 594 595 R = new(big.Int) 596 S = new(big.Int) 597 R.SetBytes(sig[0 : len(sig)/2]) 598 S.SetBytes(sig[len(sig)/2:]) 599 600 return R, S, nil 601 } 602 603 func (csp *impl) verifyP11ECDSA(ski []byte, msg []byte, R, S *big.Int, byteSize int) (bool, error) { 604 session, err := csp.getSession() 605 if err != nil { 606 return false, err 607 } 608 defer func() { csp.handleSessionReturn(err, session) }() 609 610 logger.Debugf("Verify ECDSA\n") 611 612 publicKey, err := csp.findKeyPairFromSKI(session, ski, publicKeyType) 613 if err != nil { 614 return false, fmt.Errorf("Public key not found [%s]", err) 615 } 616 617 r := R.Bytes() 618 s := S.Bytes() 619 620 // Pad front of R and S with Zeroes if needed 621 sig := make([]byte, 2*byteSize) 622 copy(sig[byteSize-len(r):byteSize], r) 623 copy(sig[2*byteSize-len(s):], s) 624 625 err = csp.ctx.VerifyInit( 626 session, 627 []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_ECDSA, nil)}, 628 publicKey, 629 ) 630 if err != nil { 631 return false, fmt.Errorf("PKCS11: Verify-initialize [%s]", err) 632 } 633 err = csp.ctx.Verify(session, msg, sig) 634 if err == pkcs11.Error(pkcs11.CKR_SIGNATURE_INVALID) { 635 return false, nil 636 } 637 if err != nil { 638 return false, fmt.Errorf("PKCS11: Verify failed [%s]", err) 639 } 640 641 return true, nil 642 } 643 644 type keyType int8 645 646 const ( 647 publicKeyType keyType = iota 648 privateKeyType 649 ) 650 651 func (csp *impl) cachedHandle(keyType keyType, ski []byte) (pkcs11.ObjectHandle, bool) { 652 cacheKey := hex.EncodeToString(append([]byte{byte(keyType)}, ski...)) 653 csp.cacheLock.RLock() 654 defer csp.cacheLock.RUnlock() 655 656 handle, ok := csp.handleCache[cacheKey] 657 return handle, ok 658 } 659 660 func (csp *impl) cacheHandle(keyType keyType, ski []byte, handle pkcs11.ObjectHandle) { 661 cacheKey := hex.EncodeToString(append([]byte{byte(keyType)}, ski...)) 662 csp.cacheLock.Lock() 663 defer csp.cacheLock.Unlock() 664 665 csp.handleCache[cacheKey] = handle 666 } 667 668 func (csp *impl) clearCaches() { 669 csp.cacheLock.Lock() 670 defer csp.cacheLock.Unlock() 671 csp.handleCache = map[string]pkcs11.ObjectHandle{} 672 csp.keyCache = map[string]bccsp.Key{} 673 } 674 675 func (csp *impl) findKeyPairFromSKI(session pkcs11.SessionHandle, ski []byte, keyType keyType) (pkcs11.ObjectHandle, error) { 676 // check for cached handle 677 if handle, ok := csp.cachedHandle(keyType, ski); ok { 678 return handle, nil 679 } 680 681 ktype := pkcs11.CKO_PUBLIC_KEY 682 if keyType == privateKeyType { 683 ktype = pkcs11.CKO_PRIVATE_KEY 684 } 685 686 template := []*pkcs11.Attribute{ 687 pkcs11.NewAttribute(pkcs11.CKA_CLASS, ktype), 688 pkcs11.NewAttribute(pkcs11.CKA_ID, ski), 689 } 690 if err := csp.ctx.FindObjectsInit(session, template); err != nil { 691 return 0, err 692 } 693 defer csp.ctx.FindObjectsFinal(session) 694 695 // single session instance, assume one hit only 696 objs, _, err := csp.ctx.FindObjects(session, 1) 697 if err != nil { 698 return 0, err 699 } 700 701 if len(objs) == 0 { 702 return 0, fmt.Errorf("Key not found [%s]", hex.Dump(ski)) 703 } 704 705 // cache the found handle 706 csp.cacheHandle(keyType, ski, objs[0]) 707 708 return objs[0], nil 709 } 710 711 // Fairly straightforward EC-point query, other than opencryptoki 712 // mis-reporting length, including the 04 Tag of the field following 713 // the SPKI in EP11-returned MACed publickeys: 714 // 715 // attr type 385/x181, length 66 b -- SHOULD be 1+64 716 // EC point: 717 // 00000000 04 ce 30 31 6d 5a fd d3 53 2d 54 9a 27 54 d8 7c 718 // 00000010 d9 80 35 91 09 2d 6f 06 5a 8e e3 cb c0 01 b7 c9 719 // 00000020 13 5d 70 d4 e5 62 f2 1b 10 93 f7 d5 77 41 ba 9d 720 // 00000030 93 3e 18 3e 00 c6 0a 0e d2 36 cc 7f be 50 16 ef 721 // 00000040 06 04 722 // 723 // cf. correct field: 724 // 0 89: SEQUENCE { 725 // 2 19: SEQUENCE { 726 // 4 7: OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1) 727 // 13 8: OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7) 728 // : } 729 // 23 66: BIT STRING 730 // : 04 CE 30 31 6D 5A FD D3 53 2D 54 9A 27 54 D8 7C 731 // : D9 80 35 91 09 2D 6F 06 5A 8E E3 CB C0 01 B7 C9 732 // : 13 5D 70 D4 E5 62 F2 1B 10 93 F7 D5 77 41 BA 9D 733 // : 93 3E 18 3E 00 C6 0A 0E D2 36 CC 7F BE 50 16 EF 734 // : 06 735 // : } 736 // 737 // as a short-term workaround, remove the trailing byte if: 738 // - receiving an even number of bytes == 2*prime-coordinate +2 bytes 739 // - starting byte is 04: uncompressed EC point 740 // - trailing byte is 04: assume it belongs to the next OCTET STRING 741 // 742 // [mis-parsing encountered with v3.5.1, 2016-10-22] 743 // 744 // SoftHSM reports extra two bytes before the uncompressed point 745 // 0x04 || <Length*2+1> 746 // VV< Actual start of point 747 // 00000000 04 41 04 6c c8 57 32 13 02 12 6a 19 23 1d 5a 64 |.A.l.W2...j.#.Zd| 748 // 00000010 33 0c eb 75 4d e8 99 22 92 35 96 b2 39 58 14 1e |3..uM..".5..9X..| 749 // 00000020 19 de ef 32 46 50 68 02 24 62 36 db ed b1 84 7b |...2FPh.$b6....{| 750 // 00000030 93 d8 40 c3 d5 a6 b7 38 16 d2 35 0a 53 11 f9 51 |..@....8..5.S..Q| 751 // 00000040 fc a7 16 |...| 752 func (csp *impl) ecPoint(session pkcs11.SessionHandle, key pkcs11.ObjectHandle) (ecpt, oid []byte, err error) { 753 template := []*pkcs11.Attribute{ 754 pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), 755 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), 756 } 757 758 attr, err := csp.ctx.GetAttributeValue(session, key, template) 759 if err != nil { 760 return nil, nil, fmt.Errorf("PKCS11: get(EC point) [%s]", err) 761 } 762 763 for _, a := range attr { 764 if a.Type == pkcs11.CKA_EC_POINT { 765 logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) 766 767 // workarounds, see above 768 if ((len(a.Value) % 2) == 0) && 769 (byte(0x04) == a.Value[0]) && 770 (byte(0x04) == a.Value[len(a.Value)-1]) { 771 logger.Debugf("Detected opencryptoki bug, trimming trailing 0x04") 772 ecpt = a.Value[0 : len(a.Value)-1] // Trim trailing 0x04 773 } else if byte(0x04) == a.Value[0] && byte(0x04) == a.Value[2] { 774 logger.Debugf("Detected SoftHSM bug, trimming leading 0x04 0xXX") 775 ecpt = a.Value[2:len(a.Value)] 776 } else { 777 ecpt = a.Value 778 } 779 } else if a.Type == pkcs11.CKA_EC_PARAMS { 780 logger.Debugf("EC point: attr type %d/0x%x, len %d\n%s\n", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) 781 782 oid = a.Value 783 } 784 } 785 if oid == nil || ecpt == nil { 786 return nil, nil, fmt.Errorf("CKA_EC_POINT not found, perhaps not an EC Key?") 787 } 788 789 return ecpt, oid, nil 790 } 791 792 func (csp *impl) handleSessionReturn(err error, session pkcs11.SessionHandle) { 793 if err != nil { 794 if regex.MatchString(err.Error()) { 795 logger.Infof("PKCS11 session invalidated, closing session: %v", err) 796 csp.closeSession(session) 797 return 798 } 799 } 800 csp.returnSession(session) 801 } 802 803 func listAttrs(p11lib *pkcs11.Ctx, session pkcs11.SessionHandle, obj pkcs11.ObjectHandle) { 804 var cktype, ckclass uint 805 var ckaid, cklabel []byte 806 807 if p11lib == nil { 808 return 809 } 810 811 template := []*pkcs11.Attribute{ 812 pkcs11.NewAttribute(pkcs11.CKA_CLASS, ckclass), 813 pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, cktype), 814 pkcs11.NewAttribute(pkcs11.CKA_ID, ckaid), 815 pkcs11.NewAttribute(pkcs11.CKA_LABEL, cklabel), 816 } 817 818 // certain errors are tolerated, if value is missing 819 attr, err := p11lib.GetAttributeValue(session, obj, template) 820 if err != nil { 821 logger.Debugf("P11: get(attrlist) [%s]\n", err) 822 } 823 824 for _, a := range attr { 825 // Would be friendlier if the bindings provided a way convert Attribute hex to string 826 logger.Debugf("ListAttr: type %d/0x%x, length %d\n%s", a.Type, a.Type, len(a.Value), hex.Dump(a.Value)) 827 } 828 } 829 830 var ( 831 bigone = new(big.Int).SetInt64(1) 832 idCtr = new(big.Int) 833 idMutex sync.Mutex 834 ) 835 836 func nextIDCtr() *big.Int { 837 idMutex.Lock() 838 idCtr = new(big.Int).Add(idCtr, bigone) 839 idMutex.Unlock() 840 return idCtr 841 } 842 843 // FindPKCS11Lib IS ONLY USED FOR TESTING 844 // This is a convenience function. Useful to self-configure, for tests where 845 // usual configuration is not available. 846 func FindPKCS11Lib() (lib, pin, label string) { 847 if lib = os.Getenv("PKCS11_LIB"); lib == "" { 848 possibilities := []string{ 849 "/usr/lib/softhsm/libsofthsm2.so", //Debian 850 "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so", //Ubuntu 851 } 852 for _, path := range possibilities { 853 if _, err := os.Stat(path); !os.IsNotExist(err) { 854 lib = path 855 break 856 } 857 } 858 } 859 if pin = os.Getenv("PKCS11_PIN"); pin == "" { 860 pin = "98765432" 861 } 862 if label = os.Getenv("PKCS11_LABEL"); label == "" { 863 label = "ForFabric" 864 } 865 866 return lib, pin, label 867 }