github.com/letsencrypt/boulder@v0.20251208.0/goodkey/good_key.go (about)

     1  package goodkey
     2  
     3  import (
     4  	"context"
     5  	"crypto"
     6  	"crypto/ecdsa"
     7  	"crypto/elliptic"
     8  	"crypto/rsa"
     9  	"errors"
    10  	"fmt"
    11  	"math/big"
    12  	"sync"
    13  
    14  	"github.com/letsencrypt/boulder/core"
    15  
    16  	"github.com/titanous/rocacheck"
    17  )
    18  
    19  // To generate, run: primes 2 752 | tr '\n' ,
    20  var smallPrimeInts = []int64{
    21  	2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
    22  	53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107,
    23  	109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
    24  	173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
    25  	233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
    26  	293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
    27  	367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
    28  	433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491,
    29  	499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
    30  	577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
    31  	643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709,
    32  	719, 727, 733, 739, 743, 751,
    33  }
    34  
    35  // singleton defines the object of a Singleton pattern
    36  var (
    37  	smallPrimesSingleton sync.Once
    38  	smallPrimesProduct   *big.Int
    39  )
    40  
    41  type Config struct {
    42  	// AllowedKeys enables or disables specific key algorithms and sizes. If
    43  	// nil, defaults to just those keys allowed by the Let's Encrypt CPS.
    44  	AllowedKeys *AllowedKeys
    45  	// FermatRounds is an integer number of rounds of Fermat's factorization
    46  	// method that should be performed to attempt to detect keys whose modulus can
    47  	// be trivially factored because the two factors are very close to each other.
    48  	// If this config value is empty or 0, it will default to 110 rounds.
    49  	FermatRounds int
    50  }
    51  
    52  // AllowedKeys is a map of six specific key algorithm and size combinations to
    53  // booleans indicating whether keys of that type are considered good.
    54  type AllowedKeys struct {
    55  	// Baseline Requirements, Section 6.1.5 requires key size >= 2048 and a multiple
    56  	// of 8 bits: https://github.com/cabforum/servercert/blob/main/docs/BR.md#615-key-sizes
    57  	// Baseline Requirements, Section 6.1.1.3 requires that we reject any keys which
    58  	// have a known method to easily compute their private key, such as Debian Weak
    59  	// Keys. Our enforcement mechanism relies on enumerating all Debian Weak Keys at
    60  	// common key sizes, so we restrict all issuance to those common key sizes.
    61  	RSA2048 bool
    62  	RSA3072 bool
    63  	RSA4096 bool
    64  	// Baseline Requirements, Section 6.1.5 requires that ECDSA keys be valid
    65  	// points on the NIST P-256, P-384, or P-521 elliptic curves.
    66  	ECDSAP256 bool
    67  	ECDSAP384 bool
    68  	ECDSAP521 bool
    69  }
    70  
    71  // LetsEncryptCPS encodes the five key algorithms and sizes allowed by the Let's
    72  // Encrypt CPS CV-SSL Subscriber Certificate Profile: RSA 2048, RSA 3076, RSA
    73  // 4096, ECDSA 256 and ECDSA P384.
    74  // https://github.com/letsencrypt/cp-cps/blob/main/CP-CPS.md#dv-ssl-subscriber-certificate
    75  // If this is ever changed, the CP/CPS MUST be changed first.
    76  func LetsEncryptCPS() AllowedKeys {
    77  	return AllowedKeys{
    78  		RSA2048:   true,
    79  		RSA3072:   true,
    80  		RSA4096:   true,
    81  		ECDSAP256: true,
    82  		ECDSAP384: true,
    83  	}
    84  }
    85  
    86  // ErrBadKey represents an error with a key. It is distinct from the various
    87  // ways in which an ACME request can have an erroneous key (BadPublicKeyError,
    88  // BadCSRError) because this library is used to check both JWS signing keys and
    89  // keys in CSRs.
    90  var ErrBadKey = errors.New("")
    91  
    92  func badKey(msg string, args ...any) error {
    93  	return fmt.Errorf("%w%s", ErrBadKey, fmt.Errorf(msg, args...))
    94  }
    95  
    96  // BlockedKeyCheckFunc is used to pass in the sa.BlockedKey functionality to KeyPolicy,
    97  // rather than storing a full sa.SQLStorageAuthority. This allows external
    98  // users who don’t want to import all of boulder/sa, and makes testing
    99  // significantly simpler.
   100  // On success, the function returns a boolean which is true if the key is blocked.
   101  type BlockedKeyCheckFunc func(ctx context.Context, keyHash []byte) (bool, error)
   102  
   103  // KeyPolicy determines which types of key may be used with various boulder
   104  // operations.
   105  type KeyPolicy struct {
   106  	allowedKeys  AllowedKeys
   107  	fermatRounds int
   108  	blockedCheck BlockedKeyCheckFunc
   109  }
   110  
   111  // NewPolicy returns a key policy based on the given configuration, with sane
   112  // defaults. If the config's AllowedKeys is nil, the LetsEncryptCPS AllowedKeys
   113  // is used. If the configured FermatRounds is 0, Fermat Factorization defaults to
   114  // attempting 110 rounds.
   115  func NewPolicy(config *Config, bkc BlockedKeyCheckFunc) (KeyPolicy, error) {
   116  	if config == nil {
   117  		config = &Config{}
   118  	}
   119  	kp := KeyPolicy{
   120  		blockedCheck: bkc,
   121  	}
   122  	if config.AllowedKeys == nil {
   123  		kp.allowedKeys = LetsEncryptCPS()
   124  	} else {
   125  		kp.allowedKeys = *config.AllowedKeys
   126  	}
   127  	if config.FermatRounds == 0 {
   128  		// The BRs require 100 rounds, so give ourselves a margin above that.
   129  		kp.fermatRounds = 110
   130  	} else if config.FermatRounds < 100 {
   131  		return KeyPolicy{}, fmt.Errorf("Fermat factorization rounds must be at least 100: %d", config.FermatRounds)
   132  	} else {
   133  		kp.fermatRounds = config.FermatRounds
   134  	}
   135  	return kp, nil
   136  }
   137  
   138  // GoodKey returns true if the key is acceptable for both TLS use and account
   139  // key use (our requirements are the same for either one), according to basic
   140  // strength and algorithm checking. GoodKey only supports pointers: *rsa.PublicKey
   141  // and *ecdsa.PublicKey. It will reject non-pointer types.
   142  // TODO: Support JSONWebKeys once go-jose migration is done.
   143  func (policy *KeyPolicy) GoodKey(ctx context.Context, key crypto.PublicKey) error {
   144  	// Early rejection of unacceptable key types to guard subsequent checks.
   145  	switch t := key.(type) {
   146  	case *rsa.PublicKey, *ecdsa.PublicKey:
   147  		break
   148  	default:
   149  		return badKey("unsupported key type %T", t)
   150  	}
   151  	if policy.blockedCheck != nil {
   152  		digest, err := core.KeyDigest(key)
   153  		if err != nil {
   154  			return badKey("%w", err)
   155  		}
   156  		exists, err := policy.blockedCheck(ctx, digest[:])
   157  		if err != nil {
   158  			return err
   159  		} else if exists {
   160  			return badKey("public key is forbidden")
   161  		}
   162  	}
   163  	switch t := key.(type) {
   164  	case *rsa.PublicKey:
   165  		return policy.goodKeyRSA(t)
   166  	case *ecdsa.PublicKey:
   167  		return policy.goodKeyECDSA(t)
   168  	default:
   169  		return badKey("unsupported key type %T", key)
   170  	}
   171  }
   172  
   173  // GoodKeyECDSA determines if an ECDSA pubkey meets our requirements
   174  func (policy *KeyPolicy) goodKeyECDSA(key *ecdsa.PublicKey) (err error) {
   175  	// Check the curve.
   176  	//
   177  	// The validity of the curve is an assumption for all following tests.
   178  	err = policy.goodCurve(key.Curve)
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	// Key validation routine adapted from NIST SP800-56A § 5.6.2.3.2.
   184  	// <http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf>
   185  	//
   186  	// Assuming a prime field since a) we are only allowing such curves and b)
   187  	// crypto/elliptic only supports prime curves. Where this assumption
   188  	// simplifies the code below, it is explicitly stated and explained. If ever
   189  	// adapting this code to support non-prime curves, refer to NIST SP800-56A §
   190  	// 5.6.2.3.2 and adapt this code appropriately.
   191  	params := key.Params()
   192  
   193  	// SP800-56A § 5.6.2.3.2 Step 1.
   194  	// Partial check of the public key for an invalid range in the EC group:
   195  	// Verify that key is not the point at infinity O.
   196  	// This code assumes that the point at infinity is (0,0), which is the
   197  	// case for all supported curves.
   198  	if isPointAtInfinityNISTP(key.X, key.Y) {
   199  		return badKey("key x, y must not be the point at infinity")
   200  	}
   201  
   202  	// SP800-56A § 5.6.2.3.2 Step 2.
   203  	//   "Verify that x_Q and y_Q are integers in the interval [0,p-1] in the
   204  	//    case that q is an odd prime p, or that x_Q and y_Q are bit strings
   205  	//    of length m bits in the case that q = 2**m."
   206  	//
   207  	// Prove prime field: ASSUMED.
   208  	// Prove q != 2: ASSUMED. (Curve parameter. No supported curve has q == 2.)
   209  	// Prime field && q != 2  => q is an odd prime p
   210  	// Therefore "verify that x, y are in [0, p-1]" satisfies step 2.
   211  	//
   212  	// Therefore verify that both x and y of the public key point have the unique
   213  	// correct representation of an element in the underlying field by verifying
   214  	// that x and y are integers in [0, p-1].
   215  	if key.X.Sign() < 0 || key.Y.Sign() < 0 {
   216  		return badKey("key x, y must not be negative")
   217  	}
   218  
   219  	if key.X.Cmp(params.P) >= 0 || key.Y.Cmp(params.P) >= 0 {
   220  		return badKey("key x, y must not exceed P-1")
   221  	}
   222  
   223  	// SP800-56A § 5.6.2.3.2 Step 3.
   224  	//   "If q is an odd prime p, verify that (y_Q)**2 === (x_Q)***3 + a*x_Q + b (mod p).
   225  	//    If q = 2**m, verify that (y_Q)**2 + (x_Q)*(y_Q) == (x_Q)**3 + a*(x_Q)*2 + b in
   226  	//    the finite field of size 2**m.
   227  	//    (Ensures that the public key is on the correct elliptic curve.)"
   228  	//
   229  	// q is an odd prime p: proven/assumed above.
   230  	// a = -3 for all supported curves.
   231  	//
   232  	// Therefore step 3 is satisfied simply by showing that
   233  	//   y**2 === x**3 - 3*x + B (mod P).
   234  	//
   235  	// This proves that the public key is on the correct elliptic curve.
   236  	// But in practice, this test is provided by crypto/elliptic, so use that.
   237  	if !key.Curve.IsOnCurve(key.X, key.Y) {
   238  		return badKey("key point is not on the curve")
   239  	}
   240  
   241  	// SP800-56A § 5.6.2.3.2 Step 4.
   242  	//   "Verify that n*Q == Ø.
   243  	//    (Ensures that the public key has the correct order. Along with check 1,
   244  	//     ensures that the public key is in the correct range in the correct EC
   245  	//     subgroup, that is, it is in the correct EC subgroup and is not the
   246  	//     identity element.)"
   247  	//
   248  	// Ensure that public key has the correct order:
   249  	// verify that n*Q = Ø.
   250  	//
   251  	// n*Q = Ø iff n*Q is the point at infinity (see step 1).
   252  	ox, oy := key.Curve.ScalarMult(key.X, key.Y, params.N.Bytes())
   253  	if !isPointAtInfinityNISTP(ox, oy) {
   254  		return badKey("public key does not have correct order")
   255  	}
   256  
   257  	// End of SP800-56A § 5.6.2.3.2 Public Key Validation Routine.
   258  	// Key is valid.
   259  	return nil
   260  }
   261  
   262  // Returns true iff the point (x,y) on NIST P-256, NIST P-384 or NIST P-521 is
   263  // the point at infinity. These curves all have the same point at infinity
   264  // (0,0). This function must ONLY be used on points on curves verified to have
   265  // (0,0) as their point at infinity.
   266  func isPointAtInfinityNISTP(x, y *big.Int) bool {
   267  	return x.Sign() == 0 && y.Sign() == 0
   268  }
   269  
   270  // GoodCurve determines if an elliptic curve meets our requirements.
   271  func (policy *KeyPolicy) goodCurve(c elliptic.Curve) (err error) {
   272  	// Simply use a whitelist for now.
   273  	params := c.Params()
   274  	switch {
   275  	case policy.allowedKeys.ECDSAP256 && params == elliptic.P256().Params():
   276  		return nil
   277  	case policy.allowedKeys.ECDSAP384 && params == elliptic.P384().Params():
   278  		return nil
   279  	case policy.allowedKeys.ECDSAP521 && params == elliptic.P521().Params():
   280  		return nil
   281  	default:
   282  		return badKey("ECDSA curve %v not allowed", params.Name)
   283  	}
   284  }
   285  
   286  // GoodKeyRSA determines if a RSA pubkey meets our requirements
   287  func (policy *KeyPolicy) goodKeyRSA(key *rsa.PublicKey) error {
   288  	modulus := key.N
   289  
   290  	err := policy.goodRSABitLen(key)
   291  	if err != nil {
   292  		return err
   293  	}
   294  
   295  	// Rather than support arbitrary exponents, which significantly increases
   296  	// the size of the key space we allow, we restrict E to the defacto standard
   297  	// RSA exponent 65537. There is no specific standards document that specifies
   298  	// 65537 as the 'best' exponent, but ITU X.509 Annex C suggests there are
   299  	// notable merits for using it if using a fixed exponent.
   300  	//
   301  	// The CABF Baseline Requirements state:
   302  	//   The CA SHALL confirm that the value of the public exponent is an
   303  	//   odd number equal to 3 or more. Additionally, the public exponent
   304  	//   SHOULD be in the range between 2^16 + 1 and 2^256-1.
   305  	//
   306  	// By only allowing one exponent, which fits these constraints, we satisfy
   307  	// these requirements.
   308  	if key.E != 65537 {
   309  		return badKey("key exponent must be 65537")
   310  	}
   311  
   312  	// The modulus SHOULD also have the following characteristics: an odd
   313  	// number, not the power of a prime, and have no factors smaller than 752.
   314  	// TODO: We don't yet check for "power of a prime."
   315  	if checkSmallPrimes(modulus) {
   316  		return badKey("key divisible by small prime")
   317  	}
   318  	// Check for weak keys generated by Infineon hardware
   319  	// (see https://crocs.fi.muni.cz/public/papers/rsa_ccs17)
   320  	if rocacheck.IsWeak(key) {
   321  		return badKey("key generated by vulnerable Infineon-based hardware")
   322  	}
   323  
   324  	// Check if the key can be easily factored via Fermat's factorization method.
   325  	err = checkPrimeFactorsTooClose(modulus, policy.fermatRounds)
   326  	if err != nil {
   327  		return badKey("key generated with factors too close together: %w", err)
   328  	}
   329  
   330  	return nil
   331  }
   332  
   333  func (policy *KeyPolicy) goodRSABitLen(key *rsa.PublicKey) error {
   334  	// See comment on AllowedKeys above.
   335  	modulusBitLen := key.N.BitLen()
   336  	switch {
   337  	case modulusBitLen == 2048 && policy.allowedKeys.RSA2048:
   338  		return nil
   339  	case modulusBitLen == 3072 && policy.allowedKeys.RSA3072:
   340  		return nil
   341  	case modulusBitLen == 4096 && policy.allowedKeys.RSA4096:
   342  		return nil
   343  	default:
   344  		return badKey("key size not supported: %d", modulusBitLen)
   345  	}
   346  }
   347  
   348  // Returns true iff integer i is divisible by any of the primes in smallPrimes.
   349  //
   350  // Short circuits; execution time is dependent on i. Do not use this on secret
   351  // values.
   352  //
   353  // Rather than checking each prime individually (invoking Mod on each),
   354  // multiply the primes together and let GCD do our work for us: if the
   355  // GCD between <key> and <product of primes> is not one, we know we have
   356  // a bad key. This is substantially faster than checking each prime
   357  // individually.
   358  func checkSmallPrimes(i *big.Int) bool {
   359  	smallPrimesSingleton.Do(func() {
   360  		smallPrimesProduct = big.NewInt(1)
   361  		for _, prime := range smallPrimeInts {
   362  			smallPrimesProduct.Mul(smallPrimesProduct, big.NewInt(prime))
   363  		}
   364  	})
   365  
   366  	// When the GCD is 1, i and smallPrimesProduct are coprime, meaning they
   367  	// share no common factors. When the GCD is not one, it is the product of
   368  	// all common factors, meaning we've identified at least one small prime
   369  	// which invalidates i as a valid key.
   370  
   371  	var result big.Int
   372  	result.GCD(nil, nil, i, smallPrimesProduct)
   373  	return result.Cmp(big.NewInt(1)) != 0
   374  }
   375  
   376  // Returns an error if the modulus n is able to be factored into primes p and q
   377  // via Fermat's factorization method. This method relies on the two primes being
   378  // very close together, which means that they were almost certainly not picked
   379  // independently from a uniform random distribution. Basically, if we can factor
   380  // the key this easily, so can anyone else.
   381  func checkPrimeFactorsTooClose(n *big.Int, rounds int) error {
   382  	// Pre-allocate some big numbers that we'll use a lot down below.
   383  	one := big.NewInt(1)
   384  	bb := new(big.Int)
   385  
   386  	// Any odd integer is equal to a difference of squares of integers:
   387  	//   n = a^2 - b^2 = (a + b)(a - b)
   388  	// Any RSA public key modulus is equal to a product of two primes:
   389  	//   n = pq
   390  	// Here we try to find values for a and b, since doing so also gives us the
   391  	// prime factors p = (a + b) and q = (a - b).
   392  
   393  	// We start with a close to the square root of the modulus n, to start with
   394  	// two candidate prime factors that are as close together as possible and
   395  	// work our way out from there. Specifically, we set a = ceil(sqrt(n)), the
   396  	// first integer greater than the square root of n. Unfortunately, big.Int's
   397  	// built-in square root function takes the floor, so we have to add one to get
   398  	// the ceil.
   399  	a := new(big.Int)
   400  	a.Sqrt(n).Add(a, one)
   401  
   402  	// We calculate b2 to see if it is a perfect square (i.e. b^2), and therefore
   403  	// b is an integer. Specifically, b2 = a^2 - n.
   404  	b2 := new(big.Int)
   405  	b2.Mul(a, a).Sub(b2, n)
   406  
   407  	for round := range rounds {
   408  		// To see if b2 is a perfect square, we take its square root, square that,
   409  		// and check to see if we got the same result back.
   410  		bb.Sqrt(b2).Mul(bb, bb)
   411  		if b2.Cmp(bb) == 0 {
   412  			// b2 is a perfect square, so we've found integer values of a and b,
   413  			// and can easily compute p and q as their sum and difference.
   414  			bb.Sqrt(bb)
   415  			p := new(big.Int).Add(a, bb)
   416  			q := new(big.Int).Sub(a, bb)
   417  			return fmt.Errorf("public modulus n = pq factored in %d rounds into p: %s and q: %s", round+1, p, q)
   418  		}
   419  
   420  		// Set up the next iteration by incrementing a by one and recalculating b2.
   421  		a.Add(a, one)
   422  		b2.Mul(a, a).Sub(b2, n)
   423  	}
   424  	return nil
   425  }