github.com/letsencrypt/boulder@v0.20251208.0/cmd/ceremony/rsa.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/rsa"
     5  	"errors"
     6  	"log"
     7  	"math/big"
     8  
     9  	"github.com/miekg/pkcs11"
    10  
    11  	"github.com/letsencrypt/boulder/pkcs11helpers"
    12  )
    13  
    14  const (
    15  	rsaExp = 65537
    16  )
    17  
    18  // rsaArgs constructs the private and public key template attributes sent to the
    19  // device and specifies which mechanism should be used. modulusLen specifies the
    20  // length of the modulus to be generated on the device in bits and exponent
    21  // specifies the public exponent that should be used.
    22  func rsaArgs(label string, modulusLen int, keyID []byte) generateArgs {
    23  	// Encode as unpadded big endian encoded byte slice
    24  	expSlice := big.NewInt(rsaExp).Bytes()
    25  	log.Printf("\tEncoded public exponent (%d) as: %0X\n", rsaExp, expSlice)
    26  	return generateArgs{
    27  		mechanism: []*pkcs11.Mechanism{
    28  			pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_KEY_PAIR_GEN, nil),
    29  		},
    30  		publicAttrs: []*pkcs11.Attribute{
    31  			pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
    32  			pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
    33  			pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
    34  			// Allow the key to verify signatures
    35  			pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true),
    36  			// Set requested modulus length
    37  			pkcs11.NewAttribute(pkcs11.CKA_MODULUS_BITS, modulusLen),
    38  			// Set requested public exponent
    39  			pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, expSlice),
    40  		},
    41  		privateAttrs: []*pkcs11.Attribute{
    42  			pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
    43  			pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
    44  			pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
    45  			// Prevent attributes being retrieved
    46  			pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
    47  			// Prevent the key being extracted from the device
    48  			pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
    49  			// Allow the key to create signatures
    50  			pkcs11.NewAttribute(pkcs11.CKA_SIGN, true),
    51  		},
    52  	}
    53  }
    54  
    55  // rsaPub extracts the generated public key, specified by the provided object
    56  // handle, and constructs a rsa.PublicKey. It also checks that the key has the
    57  // correct length modulus and that the public exponent is what was requested in
    58  // the public key template.
    59  func rsaPub(session *pkcs11helpers.Session, object pkcs11.ObjectHandle, modulusLen int) (*rsa.PublicKey, error) {
    60  	pubKey, err := session.GetRSAPublicKey(object)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	if pubKey.E != rsaExp {
    65  		return nil, errors.New("returned CKA_PUBLIC_EXPONENT doesn't match expected exponent")
    66  	}
    67  	if pubKey.N.BitLen() != modulusLen {
    68  		return nil, errors.New("returned CKA_MODULUS isn't of the expected bit length")
    69  	}
    70  	log.Printf("\tPublic exponent: %d\n", pubKey.E)
    71  	log.Printf("\tModulus: (%d bits) %X\n", pubKey.N.BitLen(), pubKey.N.Bytes())
    72  	return pubKey, nil
    73  }
    74  
    75  // rsaGenerate is used to generate and verify a RSA key pair of the size
    76  // specified by modulusLen and with the exponent 65537.
    77  // It returns the public part of the generated key pair as a rsa.PublicKey
    78  // and the random key ID that the HSM uses to identify the key pair.
    79  func rsaGenerate(session *pkcs11helpers.Session, label string, modulusLen int) (*rsa.PublicKey, []byte, error) {
    80  	keyID := make([]byte, 4)
    81  	_, err := newRandReader(session).Read(keyID)
    82  	if err != nil {
    83  		return nil, nil, err
    84  	}
    85  	log.Printf("Generating RSA key with %d bit modulus and public exponent %d and ID %x\n", modulusLen, rsaExp, keyID)
    86  	args := rsaArgs(label, modulusLen, keyID)
    87  	pub, _, err := session.GenerateKeyPair(args.mechanism, args.publicAttrs, args.privateAttrs)
    88  	if err != nil {
    89  		return nil, nil, err
    90  	}
    91  	log.Println("Key generated")
    92  	log.Println("Extracting public key")
    93  	pk, err := rsaPub(session, pub, modulusLen)
    94  	if err != nil {
    95  		return nil, nil, err
    96  	}
    97  	log.Println("Extracted public key")
    98  	return pk, keyID, nil
    99  }