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 }