Skip to content

Commit

Permalink
Enforce strong hash (SHA256, SHA512) in subtle's digital signature.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 206035572
GitOrigin-RevId: daf347df71221d2033fac1a6d624f3a7a7106c41
  • Loading branch information
cryptosubtlety authored and chuckx committed Jul 27, 2018
1 parent 65c0767 commit f1d5f84
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 16 deletions.
4 changes: 4 additions & 0 deletions cc/subtle/ecdsa_sign_boringssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ util::StatusOr<std::unique_ptr<EcdsaSignBoringSsl>>
EcdsaSignBoringSsl::New(const SubtleUtilBoringSSL::EcKey& ec_key,
HashType hash_type) {
// Check hash.
auto hash_status = SubtleUtilBoringSSL::ValidateSignatureHash(hash_type);
if (!hash_status.ok()) {
return hash_status;
}
auto hash_result = SubtleUtilBoringSSL::EvpHash(hash_type);
if (!hash_result.ok()) return hash_result.status();
const EVP_MD* hash = hash_result.ValueOrDie();
Expand Down
7 changes: 7 additions & 0 deletions cc/subtle/ecdsa_sign_boringssl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ TEST_F(EcdsaSignBoringSslTest, testBasicSigning) {
EXPECT_TRUE(status.ok()) << status;
}

TEST_F(EcdsaSignBoringSslTest, testNewErrors) {
auto ec_key = SubtleUtilBoringSSL::GetNewEcKey(EllipticCurveType::NIST_P256)
.ValueOrDie();
auto signer_result = EcdsaSignBoringSsl::New(ec_key, HashType::SHA1);
EXPECT_FALSE(signer_result.ok()) << signer_result.status();
}

// TODO(bleichen): add Wycheproof tests.

} // namespace
Expand Down
4 changes: 4 additions & 0 deletions cc/subtle/ecdsa_verify_boringssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ util::StatusOr<std::unique_ptr<EcdsaVerifyBoringSsl>>
EcdsaVerifyBoringSsl::New(const SubtleUtilBoringSSL::EcKey& ec_key,
HashType hash_type) {
// Check hash.
auto hash_status = SubtleUtilBoringSSL::ValidateSignatureHash(hash_type);
if (!hash_status.ok()) {
return hash_status;
}
auto hash_result = SubtleUtilBoringSSL::EvpHash(hash_type);
if (!hash_result.ok()) return hash_result.status();
const EVP_MD* hash = hash_result.ValueOrDie();
Expand Down
18 changes: 12 additions & 6 deletions cc/subtle/ecdsa_verify_boringssl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ namespace tink {
namespace subtle {
namespace {

class EcdsaSignBoringSslTest : public ::testing::Test {
};
class EcdsaVerifyBoringSslTest : public ::testing::Test {};

TEST_F(EcdsaSignBoringSslTest, testBasicSigning) {
TEST_F(EcdsaVerifyBoringSslTest, testBasicSigning) {
auto ec_key_result = SubtleUtilBoringSSL::GetNewEcKey(
EllipticCurveType::NIST_P256);
ASSERT_TRUE(ec_key_result.ok()) << ec_key_result.status();
Expand Down Expand Up @@ -71,6 +70,13 @@ TEST_F(EcdsaSignBoringSslTest, testBasicSigning) {
EXPECT_FALSE(status.ok());
}

TEST_F(EcdsaVerifyBoringSslTest, testNewErrors) {
auto ec_key = SubtleUtilBoringSSL::GetNewEcKey(EllipticCurveType::NIST_P256)
.ValueOrDie();
auto verifier_result = EcdsaVerifyBoringSsl::New(ec_key, HashType::SHA1);
EXPECT_FALSE(verifier_result.ok()) << verifier_result.status();
}

// Integers in Wycheproof are represented as signed bigendian hexadecimal
// strings in twos complement representation.
// Integers in EcKey are unsigned and are represented as an array of bytes
Expand Down Expand Up @@ -179,15 +185,15 @@ bool TestSignatures(const std::string& filename, bool allow_skipping) {
return failed_tests == 0;
}

TEST_F(EcdsaSignBoringSslTest, testVectorsNistP256) {
TEST_F(EcdsaVerifyBoringSslTest, testVectorsNistP256) {
ASSERT_TRUE(TestSignatures("ecdsa_secp256r1_sha256_test.json", false));
}

TEST_F(EcdsaSignBoringSslTest, testVectorsNistP384) {
TEST_F(EcdsaVerifyBoringSslTest, testVectorsNistP384) {
ASSERT_TRUE(TestSignatures("ecdsa_secp384r1_sha512_test.json", false));
}

TEST_F(EcdsaSignBoringSslTest, testVectorsNistP521) {
TEST_F(EcdsaVerifyBoringSslTest, testVectorsNistP521) {
ASSERT_TRUE(TestSignatures("ecdsa_secp521r1_sha512_test.json", false));
}

Expand Down
14 changes: 4 additions & 10 deletions cc/subtle/rsa_ssa_pss_verify_boringssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,10 @@ RsaSsaPssVerifyBoringSsl::New(
const SubtleUtilBoringSSL::RsaPublicKey& pub_key,
const SubtleUtilBoringSSL::RsaSsaPssParams& params) {
// Check hash.
switch (params.sig_hash) {
case HashType::SHA256: /* fall through */
case HashType::SHA512:
break;
case HashType::SHA1:
return util::Status(util::error::INVALID_ARGUMENT,
"SHA1 is not safe for digital signature");
default:
return util::Status(util::error::INVALID_ARGUMENT,
"Unsupported hash function");
auto hash_status =
SubtleUtilBoringSSL::ValidateSignatureHash(params.sig_hash);
if (!hash_status.ok()) {
return hash_status;
}
auto sig_hash_result = SubtleUtilBoringSSL::EvpHash(params.sig_hash);
if (!sig_hash_result.ok()) return sig_hash_result.status();
Expand Down
14 changes: 14 additions & 0 deletions cc/subtle/subtle_util_boringssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,20 @@ util::StatusOr<std::string> SubtleUtilBoringSSL::EcPointEncode(
}
}

// static
util::Status SubtleUtilBoringSSL::ValidateSignatureHash(HashType sig_hash) {
switch (sig_hash) {
case HashType::SHA256: /* fall through */
case HashType::SHA512:
return util::Status::OK;
case HashType::SHA1:
return util::Status(util::error::INVALID_ARGUMENT,
"SHA1 is not safe for digital signature");
default:
return util::Status(util::error::INVALID_ARGUMENT,
"Unsupported hash function");
}
}

// static
std::string SubtleUtilBoringSSL::GetErrors() {
Expand Down
4 changes: 4 additions & 0 deletions cc/subtle/subtle_util_boringssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class SubtleUtilBoringSSL {
// The EVP_MD instances are sigletons owned by BoringSSL.
static crypto::tink::util::StatusOr<const EVP_MD *> EvpHash(
HashType hash_type);

// Validates whether 'sig_hash' is safe to use for digital signature.
static crypto::tink::util::Status ValidateSignatureHash(
subtle::HashType sig_hash);
};

} // namespace subtle
Expand Down
10 changes: 10 additions & 0 deletions cc/subtle/subtle_util_boringssl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ TEST(SubtleUtilBoringSSLTest, testEcPointDecode) {
}
}

TEST(SubtleUtilBoringSSLTest, testValidateSignatureHash) {
EXPECT_TRUE(
SubtleUtilBoringSSL::ValidateSignatureHash(HashType::SHA256).ok());
EXPECT_TRUE(
SubtleUtilBoringSSL::ValidateSignatureHash(HashType::SHA512).ok());
EXPECT_FALSE(SubtleUtilBoringSSL::ValidateSignatureHash(HashType::SHA1).ok());
EXPECT_FALSE(
SubtleUtilBoringSSL::ValidateSignatureHash(HashType::UNKNOWN_HASH).ok());
}

static std::string GetError() {
auto err = ERR_peek_last_error();
// Sometimes there is no error message on the stack.
Expand Down

0 comments on commit f1d5f84

Please sign in to comment.