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  }