...

Source file src/github.com/letsencrypt/boulder/privatekey/privatekey.go

Documentation: github.com/letsencrypt/boulder/privatekey

     1  package privatekey
     2  
     3  import (
     4  	"crypto"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	"crypto/rsa"
     8  	"crypto/sha256"
     9  	"crypto/x509"
    10  	"encoding/pem"
    11  	"errors"
    12  	"fmt"
    13  	"hash"
    14  	"os"
    15  )
    16  
    17  func makeVerifyHash() (hash.Hash, error) {
    18  	randBytes := make([]byte, 32)
    19  	_, err := rand.Read(randBytes)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  
    24  	hash := sha256.New()
    25  	_, err = hash.Write(randBytes)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	return hash, nil
    30  }
    31  
    32  // verifyRSA is broken out of Verify for testing purposes.
    33  func verifyRSA(privKey *rsa.PrivateKey, pubKey *rsa.PublicKey, msgHash hash.Hash) (crypto.Signer, crypto.PublicKey, error) {
    34  	signatureRSA, err := rsa.SignPSS(rand.Reader, privKey, crypto.SHA256, msgHash.Sum(nil), nil)
    35  	if err != nil {
    36  		return nil, nil, fmt.Errorf("failed to sign using the provided RSA private key: %s", err)
    37  	}
    38  
    39  	err = rsa.VerifyPSS(pubKey, crypto.SHA256, msgHash.Sum(nil), signatureRSA, nil)
    40  	if err != nil {
    41  		return nil, nil, fmt.Errorf("the provided RSA private key failed signature verification: %s", err)
    42  	}
    43  	return privKey, privKey.Public(), nil
    44  }
    45  
    46  // verifyECDSA is broken out of Verify for testing purposes.
    47  func verifyECDSA(privKey *ecdsa.PrivateKey, pubKey *ecdsa.PublicKey, msgHash hash.Hash) (crypto.Signer, crypto.PublicKey, error) {
    48  	r, s, err := ecdsa.Sign(rand.Reader, privKey, msgHash.Sum(nil))
    49  	if err != nil {
    50  		return nil, nil, fmt.Errorf("failed to sign using the provided ECDSA private key: %s", err)
    51  	}
    52  
    53  	verify := ecdsa.Verify(pubKey, msgHash.Sum(nil), r, s)
    54  	if !verify {
    55  		return nil, nil, errors.New("the provided ECDSA private key failed signature verification")
    56  	}
    57  	return privKey, privKey.Public(), nil
    58  }
    59  
    60  // verify ensures that the embedded PublicKey of the provided privateKey is
    61  // actually a match for the private key. For an example of private keys
    62  // embedding a mismatched public key, see:
    63  // https://blog.hboeck.de/archives/888-How-I-tricked-Symantec-with-a-Fake-Private-Key.html.
    64  func verify(privateKey crypto.Signer) (crypto.Signer, crypto.PublicKey, error) {
    65  	verifyHash, err := makeVerifyHash()
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  
    70  	switch k := privateKey.(type) {
    71  	case *rsa.PrivateKey:
    72  		return verifyRSA(k, &k.PublicKey, verifyHash)
    73  
    74  	case *ecdsa.PrivateKey:
    75  		return verifyECDSA(k, &k.PublicKey, verifyHash)
    76  
    77  	default:
    78  		// This should never happen.
    79  		return nil, nil, errors.New("the provided private key could not be asserted to ECDSA or RSA")
    80  	}
    81  }
    82  
    83  // Load decodes and parses a private key from the provided file path and returns
    84  // the private key as crypto.Signer. keyPath is expected to be a PEM formatted
    85  // RSA or ECDSA private key in a PKCS #1, PKCS# 8, or SEC 1 container. The
    86  // embedded PublicKey of the provided private key will be verified as an actual
    87  // match for the private key and returned as a crypto.PublicKey. This function
    88  // is only intended for use in administrative tooling and tests.
    89  func Load(keyPath string) (crypto.Signer, crypto.PublicKey, error) {
    90  	keyBytes, err := os.ReadFile(keyPath)
    91  	if err != nil {
    92  		return nil, nil, fmt.Errorf("could not read key file %q", keyPath)
    93  	}
    94  
    95  	var keyDER *pem.Block
    96  	for {
    97  		keyDER, keyBytes = pem.Decode(keyBytes)
    98  		if keyDER == nil || keyDER.Type != "EC PARAMETERS" {
    99  			break
   100  		}
   101  	}
   102  	if keyDER == nil {
   103  		return nil, nil, fmt.Errorf("no PEM formatted block found in %q", keyPath)
   104  	}
   105  
   106  	// Attempt to parse the PEM block as a private key in a PKCS #8 container.
   107  	signer, err := x509.ParsePKCS8PrivateKey(keyDER.Bytes)
   108  	if err == nil {
   109  		cryptoSigner, ok := signer.(crypto.Signer)
   110  		if ok {
   111  			return verify(cryptoSigner)
   112  		}
   113  	}
   114  
   115  	// Attempt to parse the PEM block as a private key in a PKCS #1 container.
   116  	rsaSigner, err := x509.ParsePKCS1PrivateKey(keyDER.Bytes)
   117  	if err != nil && keyDER.Type == "RSA PRIVATE KEY" {
   118  		return nil, nil, fmt.Errorf("unable to parse %q as a PKCS#1 RSA private key: %w", keyPath, err)
   119  	}
   120  	if err == nil {
   121  		return verify(rsaSigner)
   122  	}
   123  
   124  	// Attempt to parse the PEM block as a private key in a SEC 1 container.
   125  	ecdsaSigner, err := x509.ParseECPrivateKey(keyDER.Bytes)
   126  	if err == nil {
   127  		return verify(ecdsaSigner)
   128  	}
   129  	return nil, nil, fmt.Errorf("unable to parse %q as a private key", keyPath)
   130  }
   131  

View as plain text