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 }