Don't allow trailing data when creating an RSAPrivateKey.
CreateFromPrivateKeyInfo should not silently discard data after the PrivateKeyInfo. BUG=432279 Review URL: https://codereview.chromium.org/713523004 Cr-Commit-Position: refs/heads/master@{#305503}
This commit is contained in:
@@ -278,29 +278,37 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfoWithParams(
|
|||||||
|
|
||||||
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
|
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
|
||||||
|
|
||||||
SECItem der_private_key_info;
|
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||||
der_private_key_info.data = const_cast<unsigned char*>(&input.front());
|
if (!arena) {
|
||||||
der_private_key_info.len = input.size();
|
|
||||||
// Allow the private key to be used for key unwrapping, data decryption,
|
|
||||||
// and signature generation.
|
|
||||||
const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
|
|
||||||
KU_DIGITAL_SIGNATURE;
|
|
||||||
// TODO(davidben): PK11_ImportDERPrivateKeyInfoAndReturnKey calls NSS's
|
|
||||||
// SEC_ASN1DecodeItem which does not enforce that there is no trailing
|
|
||||||
// data.
|
|
||||||
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
|
||||||
slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
|
|
||||||
key_usage, &result->key_, NULL);
|
|
||||||
if (rv != SECSuccess) {
|
|
||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
|
// Excess data is illegal, but NSS silently accepts it, so first ensure that
|
||||||
if (!result->public_key_) {
|
// |input| consists of a single ASN.1 element.
|
||||||
NOTREACHED();
|
SECItem input_item;
|
||||||
|
input_item.data = const_cast<unsigned char*>(&input.front());
|
||||||
|
input_item.len = input.size();
|
||||||
|
SECItem der_private_key_info;
|
||||||
|
SECStatus rv = SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
|
||||||
|
SEC_ASN1_GET(SEC_AnyTemplate),
|
||||||
|
&input_item);
|
||||||
|
if (rv != SECSuccess)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Allow the private key to be used for key unwrapping, data decryption,
|
||||||
|
// and signature generation.
|
||||||
|
const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
|
||||||
|
KU_DIGITAL_SIGNATURE;
|
||||||
|
rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||||
|
slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
|
||||||
|
key_usage, &result->key_, NULL);
|
||||||
|
if (rv != SECSuccess)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
|
||||||
|
if (!result->public_key_)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return result.release();
|
return result.release();
|
||||||
}
|
}
|
||||||
|
@@ -83,13 +83,10 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
|
|||||||
// Importing is a little more involved than exporting, as we must first
|
// Importing is a little more involved than exporting, as we must first
|
||||||
// PKCS#8 decode the input, and then import the EVP_PKEY from Private Key
|
// PKCS#8 decode the input, and then import the EVP_PKEY from Private Key
|
||||||
// Info structure returned.
|
// Info structure returned.
|
||||||
//
|
|
||||||
// TODO(davidben): This should check that |ptr| advanced to the end of |input|
|
|
||||||
// to ensure there is no trailing data.
|
|
||||||
const uint8_t* ptr = &input[0];
|
const uint8_t* ptr = &input[0];
|
||||||
ScopedPKCS8_PRIV_KEY_INFO p8inf(
|
ScopedPKCS8_PRIV_KEY_INFO p8inf(
|
||||||
d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size()));
|
d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size()));
|
||||||
if (!p8inf.get())
|
if (!p8inf.get() || ptr != &input[0] + input.size())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
|
scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
|
||||||
|
@@ -150,6 +150,20 @@ TEST(RSAPrivateKeyUnitTest, CopyTest) {
|
|||||||
ASSERT_EQ(input, privkey_copy);
|
ASSERT_EQ(input, privkey_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that CreateFromPrivateKeyInfo fails if there is extra data after the RSA
|
||||||
|
// key.
|
||||||
|
TEST(RSAPrivateKeyUnitTest, ExtraData) {
|
||||||
|
std::vector<uint8> input(
|
||||||
|
kTestPrivateKeyInfo, kTestPrivateKeyInfo + sizeof(kTestPrivateKeyInfo));
|
||||||
|
input.push_back(0);
|
||||||
|
|
||||||
|
scoped_ptr<crypto::RSAPrivateKey> key(
|
||||||
|
crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(input));
|
||||||
|
|
||||||
|
// Import should fail.
|
||||||
|
EXPECT_FALSE(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Verify that generated public keys look good. This test data was generated
|
// Verify that generated public keys look good. This test data was generated
|
||||||
// with the openssl command line tool.
|
// with the openssl command line tool.
|
||||||
|
Reference in New Issue
Block a user