github.com/letsencrypt/boulder@v0.20251208.0/cmd/ceremony/ecdsa.go (about) 1 package main 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/elliptic" 6 "errors" 7 "fmt" 8 "log" 9 10 "github.com/miekg/pkcs11" 11 12 "github.com/letsencrypt/boulder/pkcs11helpers" 13 ) 14 15 var stringToCurve = map[string]elliptic.Curve{ 16 elliptic.P256().Params().Name: elliptic.P256(), 17 elliptic.P384().Params().Name: elliptic.P384(), 18 elliptic.P521().Params().Name: elliptic.P521(), 19 } 20 21 // curveToOIDDER maps the name of the curves to their DER encoded OIDs 22 var curveToOIDDER = map[string][]byte{ 23 elliptic.P256().Params().Name: {6, 8, 42, 134, 72, 206, 61, 3, 1, 7}, 24 elliptic.P384().Params().Name: {6, 5, 43, 129, 4, 0, 34}, 25 elliptic.P521().Params().Name: {6, 5, 43, 129, 4, 0, 35}, 26 } 27 28 // ecArgs constructs the private and public key template attributes sent to the 29 // device and specifies which mechanism should be used. curve determines which 30 // type of key should be generated. 31 func ecArgs(label string, curve elliptic.Curve, keyID []byte) generateArgs { 32 encodedCurve := curveToOIDDER[curve.Params().Name] 33 log.Printf("\tEncoded curve parameters for %s: %X\n", curve.Params().Name, encodedCurve) 34 return generateArgs{ 35 mechanism: []*pkcs11.Mechanism{ 36 pkcs11.NewMechanism(pkcs11.CKM_EC_KEY_PAIR_GEN, nil), 37 }, 38 publicAttrs: []*pkcs11.Attribute{ 39 pkcs11.NewAttribute(pkcs11.CKA_ID, keyID), 40 pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), 41 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), 42 pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true), 43 pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, encodedCurve), 44 }, 45 privateAttrs: []*pkcs11.Attribute{ 46 pkcs11.NewAttribute(pkcs11.CKA_ID, keyID), 47 pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), 48 pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true), 49 // Prevent attributes being retrieved 50 pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true), 51 // Prevent the key being extracted from the device 52 pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false), 53 // Allow the key to sign data 54 pkcs11.NewAttribute(pkcs11.CKA_SIGN, true), 55 }, 56 } 57 } 58 59 // ecPub extracts the generated public key, specified by the provided object 60 // handle, and constructs an ecdsa.PublicKey. It also checks that the key is of 61 // the correct curve type. 62 func ecPub( 63 session *pkcs11helpers.Session, 64 object pkcs11.ObjectHandle, 65 expectedCurve elliptic.Curve, 66 ) (*ecdsa.PublicKey, error) { 67 pubKey, err := session.GetECDSAPublicKey(object) 68 if err != nil { 69 return nil, err 70 } 71 if pubKey.Curve != expectedCurve { 72 return nil, errors.New("returned EC parameters doesn't match expected curve") 73 } 74 log.Printf("\tX: %X\n", pubKey.X.Bytes()) 75 log.Printf("\tY: %X\n", pubKey.Y.Bytes()) 76 return pubKey, nil 77 } 78 79 // ecGenerate is used to generate and verify a ECDSA key pair of the type 80 // specified by curveStr and with the provided label. It returns the public 81 // part of the generated key pair as a ecdsa.PublicKey and the random key ID 82 // that the HSM uses to identify the key pair. 83 func ecGenerate(session *pkcs11helpers.Session, label, curveStr string) (*ecdsa.PublicKey, []byte, error) { 84 curve, present := stringToCurve[curveStr] 85 if !present { 86 return nil, nil, fmt.Errorf("curve %q not supported", curveStr) 87 } 88 keyID := make([]byte, 4) 89 _, err := newRandReader(session).Read(keyID) 90 if err != nil { 91 return nil, nil, err 92 } 93 log.Printf("Generating ECDSA key with curve %s and ID %x\n", curveStr, keyID) 94 args := ecArgs(label, curve, keyID) 95 pub, _, err := session.GenerateKeyPair(args.mechanism, args.publicAttrs, args.privateAttrs) 96 if err != nil { 97 return nil, nil, err 98 } 99 log.Println("Key generated") 100 log.Println("Extracting public key") 101 pk, err := ecPub(session, pub, curve) 102 if err != nil { 103 return nil, nil, err 104 } 105 log.Println("Extracted public key") 106 return pk, keyID, nil 107 }