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  }