diff --git a/core/good_key.go b/core/good_key.go index f80dd9310..68727bf5d 100644 --- a/core/good_key.go +++ b/core/good_key.go @@ -7,8 +7,10 @@ package core import ( "crypto" + "crypto/ecdsa" "crypto/rsa" "fmt" + "reflect" blog "github.com/letsencrypt/boulder/log" ) @@ -17,22 +19,40 @@ import ( // strength and algorithm checking. func GoodKey(key crypto.PublicKey) bool { log := blog.GetAuditLogger() - rsaKey, ok := key.(rsa.PublicKey) - if !ok { - log.Debug("Non-RSA keys not yet supported.") - return false + switch t := key.(type) { + case rsa.PublicKey: + return GoodKeyRSA(t) + case *rsa.PublicKey: + return GoodKeyRSA(*t) + case ecdsa.PublicKey: + return GoodKeyECDSA(t) + case *ecdsa.PublicKey: + return GoodKeyECDSA(*t) + default: + log.Debug(fmt.Sprintf("Unknown key type %s", reflect.TypeOf(key))) + return false } +} + +func GoodKeyECDSA(key ecdsa.PublicKey) bool { + log := blog.GetAuditLogger() + log.Debug(fmt.Sprintf("ECDSA keys not yet supported.")) + return false +} + +func GoodKeyRSA(key rsa.PublicKey) bool { + log := blog.GetAuditLogger() // Baseline Requirements Appendix A // Modulus must be >= 2048 bits - modulus := rsaKey.N + modulus := key.N if modulus.BitLen() < 2048 { log.Debug(fmt.Sprintf("Key too small: %d", modulus.BitLen())) return false } // The CA SHALL confirm that the value of the public exponent // is an odd number equal to 3 or more - if rsaKey.E % 2 == 0 { - log.Debug(fmt.Sprintf("Key exponent is an even number: %d", rsaKey.E)) + if key.E % 2 == 0 { + log.Debug(fmt.Sprintf("Key exponent is an even number: %d", key.E)) return false } // Additionally, the public exponent SHOULD be in the range between @@ -40,8 +60,8 @@ func GoodKey(key crypto.PublicKey) bool { // NOTE: rsa.PublicKey cannot represent an exponent part greater than // 2^256 - 1, because it stores E as an integer. So we don't check the upper // bound. - if rsaKey.E < ((1 << 6) + 1) { - log.Debug(fmt.Sprintf("Key exponent is too small: %d", rsaKey.E)) + if key.E < ((1 << 6) + 1) { + log.Debug(fmt.Sprintf("Key exponent is too small: %d", key.E)) return false } // TODO: The modulus SHOULD also have the following diff --git a/core/good_key_test.go b/core/good_key_test.go index aeb2a6387..ffdf25d4f 100644 --- a/core/good_key_test.go +++ b/core/good_key_test.go @@ -6,18 +6,67 @@ package core import ( - "testing" "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "math/big" + "testing" + "github.com/letsencrypt/boulder/test" - //"crypto/rsa" ) func TestWrongKeyType(t *testing.T) { ecdsaKey := ecdsa.PublicKey{} - test.Assert(t, !GoodKey(ecdsaKey), "Should have rejected ECDSA key.") + test.Assert(t, !GoodKey(&ecdsaKey), "Should have rejected ECDSA key.") } -func TestWrongKeyType(t *testing.T) { - ecdsaKey := ecdsa.PublicKey{} - test.Assert(t, !GoodKey(ecdsaKey), "Should have rejected ECDSA key.") +func TestSmallModulus(t *testing.T) { + private, err := rsa.GenerateKey(rand.Reader, 2040) + test.AssertNotError(t, err, "Error generating key") + test.Assert(t, !GoodKey(&private.PublicKey), "Should have rejected too-short key.") +} + +func TestSmallExponent(t *testing.T) { + bigOne := big.NewInt(1) + key := rsa.PublicKey{ + N: bigOne.Lsh(bigOne, 2048), + E: 5, + } + test.Assert(t, !GoodKey(&key), "Should have rejected small exponent.") +} + +func TestEvenExponent(t *testing.T) { + bigOne := big.NewInt(1) + key := rsa.PublicKey{ + N: bigOne.Lsh(bigOne, 2048), + E: 1 << 17, + } + test.Assert(t, !GoodKey(&key), "Should have rejected even exponent.") +} + +func TestEvenModulus(t *testing.T) { + bigOne := big.NewInt(1) + key := rsa.PublicKey{ + N: bigOne.Lsh(bigOne, 2048), + E: (1 << 17) + 1, + } + test.Assert(t, !GoodKey(&key), "Should have rejected even modulus.") +} + +func TestModulusDivisibleBy752(t *testing.T) { + N := big.NewInt(1) + N.Lsh(N, 2048) + N.Add(N, big.NewInt(1)) + N.Mul(N, big.NewInt(751)) + key := rsa.PublicKey{ + N: N, + E: (1 << 17) + 1, + } + test.Assert(t, !GoodKey(&key), "Should have rejected modulus divisible by 751.") +} + +func TestGoodKey(t *testing.T) { + private, err := rsa.GenerateKey(rand.Reader, 2048) + test.AssertNotError(t, err, "Error generating key") + test.Assert(t, GoodKey(&private.PublicKey), "Should have accepted good key.") }