Gracefully handle DSA objects with missing fields OpenSSL's APIs are full of empty objects that aren't captured in the type system. A DSA object may represent any of nothing, a group, a public key, or a private key. Since the type system doesn't capture this, better to check which type we've got and NULL-check the fields we need for the operation. Change-Id: I32b09ebaad58fcb2a0bfc9ad56d381f95099bf7b Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/57225 Reviewed-by: Adam Langley <agl@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c index 4d9b1f0..0418e09 100644 --- a/crypto/dsa/dsa.c +++ b/crypto/dsa/dsa.c
@@ -592,6 +592,11 @@ return NULL; } + if (dsa->priv_key == NULL) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return NULL; + } + BIGNUM *kinv = NULL, *r = NULL, *s = NULL; BIGNUM m; BIGNUM xr; @@ -687,6 +692,11 @@ return 0; } + if (dsa->pub_key == NULL) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return 0; + } + int ret = 0; BIGNUM u1, u2, t1; BN_init(&u1); @@ -842,6 +852,10 @@ } int DSA_size(const DSA *dsa) { + if (dsa->q == NULL) { + return 0; + } + size_t order_len = BN_num_bytes(dsa->q); // Compute the maximum length of an |order_len| byte integer. Defensively // assume that the leading 0x00 is included. @@ -864,11 +878,6 @@ static int dsa_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, BIGNUM **out_r) { - if (!dsa->p || !dsa->q || !dsa->g) { - OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); - return 0; - } - int ret = 0; BIGNUM k; BN_init(&k);
diff --git a/crypto/dsa/dsa_test.cc b/crypto/dsa/dsa_test.cc index dc1956e..878e67d 100644 --- a/crypto/dsa/dsa_test.cc +++ b/crypto/dsa/dsa_test.cc
@@ -169,7 +169,7 @@ 0xdc, 0xd8, 0xc8, }; -static bssl::UniquePtr<DSA> GetFIPSDSA(void) { +static bssl::UniquePtr<DSA> GetFIPSDSAGroup(void) { bssl::UniquePtr<DSA> dsa(DSA_new()); if (!dsa) { return nullptr; @@ -184,6 +184,14 @@ p.release(); q.release(); g.release(); + return dsa; +} + +static bssl::UniquePtr<DSA> GetFIPSDSA(void) { + bssl::UniquePtr<DSA> dsa = GetFIPSDSAGroup(); + if (!dsa) { + return nullptr; + } bssl::UniquePtr<BIGNUM> pub_key(BN_bin2bn(fips_y, sizeof(fips_y), nullptr)); bssl::UniquePtr<BIGNUM> priv_key(BN_bin2bn(fips_x, sizeof(fips_x), nullptr)); if (!pub_key || !priv_key || @@ -259,3 +267,35 @@ EXPECT_EQ(ERR_LIB_DSA, ERR_GET_LIB(err)); EXPECT_EQ(DSA_R_INVALID_PARAMETERS, ERR_GET_REASON(err)); } + +// Signing and verifying should cleanly fail when the DSA object is empty. +TEST(DSATest, MissingParameters) { + bssl::UniquePtr<DSA> dsa(DSA_new()); + ASSERT_TRUE(dsa); + EXPECT_EQ(-1, DSA_verify(0, fips_digest, sizeof(fips_digest), fips_sig, + sizeof(fips_sig), dsa.get())); + + std::vector<uint8_t> sig(DSA_size(dsa.get())); + unsigned sig_len; + EXPECT_FALSE(DSA_sign(0, fips_digest, sizeof(fips_digest), sig.data(), + &sig_len, dsa.get())); +} + +// Verifying should cleanly fail when the public key is missing. +TEST(DSATest, MissingPublic) { + bssl::UniquePtr<DSA> dsa = GetFIPSDSAGroup(); + ASSERT_TRUE(dsa); + EXPECT_EQ(-1, DSA_verify(0, fips_digest, sizeof(fips_digest), fips_sig, + sizeof(fips_sig), dsa.get())); +} + +// Signing should cleanly fail when the private key is missing. +TEST(DSATest, MissingPrivate) { + bssl::UniquePtr<DSA> dsa = GetFIPSDSAGroup(); + ASSERT_TRUE(dsa); + + std::vector<uint8_t> sig(DSA_size(dsa.get())); + unsigned sig_len; + EXPECT_FALSE(DSA_sign(0, fips_digest, sizeof(fips_digest), sig.data(), + &sig_len, dsa.get())); +}