github.com/letsencrypt/boulder@v0.20251208.0/cmd/ceremony/key.go (about) 1 package main 2 3 import ( 4 "crypto" 5 "crypto/x509" 6 "encoding/pem" 7 "fmt" 8 "log" 9 10 "github.com/miekg/pkcs11" 11 12 "github.com/letsencrypt/boulder/pkcs11helpers" 13 ) 14 15 type hsmRandReader struct { 16 *pkcs11helpers.Session 17 } 18 19 func newRandReader(session *pkcs11helpers.Session) *hsmRandReader { 20 return &hsmRandReader{session} 21 } 22 23 func (hrr hsmRandReader) Read(p []byte) (n int, err error) { 24 r, err := hrr.Module.GenerateRandom(hrr.Session.Session, len(p)) 25 if err != nil { 26 return 0, err 27 } 28 copy(p[:], r) 29 return len(r), nil 30 } 31 32 type generateArgs struct { 33 mechanism []*pkcs11.Mechanism 34 privateAttrs []*pkcs11.Attribute 35 publicAttrs []*pkcs11.Attribute 36 } 37 38 // keyInfo is a struct used to pass around information about the public key 39 // associated with the generated private key. der contains the DER encoding 40 // of the SubjectPublicKeyInfo structure for the public key. id contains the 41 // HSM key pair object ID. 42 type keyInfo struct { 43 key crypto.PublicKey 44 der []byte 45 id []byte 46 } 47 48 func generateKey(session *pkcs11helpers.Session, label string, outputPath string, config keyGenConfig) (*keyInfo, error) { 49 _, err := session.FindObject([]*pkcs11.Attribute{ 50 {Type: pkcs11.CKA_LABEL, Value: []byte(label)}, 51 }) 52 if err != pkcs11helpers.ErrNoObject { 53 return nil, fmt.Errorf("expected no preexisting objects with label %q in slot for key storage. got error: %w", label, err) 54 } 55 56 var pubKey crypto.PublicKey 57 var keyID []byte 58 switch config.Type { 59 case "rsa": 60 pubKey, keyID, err = rsaGenerate(session, label, config.RSAModLength) 61 if err != nil { 62 return nil, fmt.Errorf("failed to generate RSA key pair: %w", err) 63 } 64 case "ecdsa": 65 pubKey, keyID, err = ecGenerate(session, label, config.ECDSACurve) 66 if err != nil { 67 return nil, fmt.Errorf("failed to generate ECDSA key pair: %w", err) 68 } 69 } 70 71 der, err := x509.MarshalPKIXPublicKey(pubKey) 72 if err != nil { 73 return nil, fmt.Errorf("failed to marshal public key: %w", err) 74 } 75 76 pemBytes := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}) 77 log.Printf("Public key PEM:\n%s\n", pemBytes) 78 err = writeFile(outputPath, pemBytes) 79 if err != nil { 80 return nil, fmt.Errorf("failed to write public key to %q: %w", outputPath, err) 81 } 82 log.Printf("Public key written to %q\n", outputPath) 83 84 return &keyInfo{key: pubKey, der: der, id: keyID}, nil 85 }