Commit 6f82af2c authored by eroman@chromium.org's avatar eroman@chromium.org

[webcrypto] Add JWK import/export of RSA private keys (NSS).

BUG=373543,373542,245025
R=rsleevi@chromium.org

Review URL: https://codereview.chromium.org/287133004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271901 0039d316-1c4b-4281-b951-d872f2087c98
parent a97a161e
This diff is collapsed.
...@@ -194,6 +194,24 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -194,6 +194,24 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& exponent_data, const CryptoData& exponent_data,
blink::WebCryptoKey* key); blink::WebCryptoKey* key);
// Preconditions:
// * algorithm.id() is for an RSA algorithm.
// * modulus, public_exponent, and private_exponent will be non-empty. The
// others will either all be specified (non-empty), or all be unspecified
// (empty).
Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
const CryptoData& modulus,
const CryptoData& public_exponent,
const CryptoData& private_exponent,
const CryptoData& prime1,
const CryptoData& prime2,
const CryptoData& exponent1,
const CryptoData& exponent2,
const CryptoData& coefficient,
blink::WebCryptoKey* key);
// Note that this may be called from target Blink thread. // Note that this may be called from target Blink thread.
Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm, Status ImportKeySpki(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data, const CryptoData& key_data,
...@@ -222,6 +240,18 @@ Status ExportRsaPublicKey(PublicKey* key, ...@@ -222,6 +240,18 @@ Status ExportRsaPublicKey(PublicKey* key,
std::vector<uint8>* modulus, std::vector<uint8>* modulus,
std::vector<uint8>* public_exponent); std::vector<uint8>* public_exponent);
// Preconditions:
// * |key| is non-null.
Status ExportRsaPrivateKey(PrivateKey* key,
std::vector<uint8>* modulus,
std::vector<uint8>* public_exponent,
std::vector<uint8>* private_exponent,
std::vector<uint8>* prime1,
std::vector<uint8>* prime2,
std::vector<uint8>* exponent1,
std::vector<uint8>* exponent2,
std::vector<uint8>* coefficient);
// Preconditions: // Preconditions:
// * |key| is non-null. // * |key| is non-null.
Status ExportKeyPkcs8(PrivateKey* key, Status ExportKeyPkcs8(PrivateKey* key,
......
...@@ -596,10 +596,6 @@ void CopySECItemToVector(const SECItem& item, std::vector<uint8>* out) { ...@@ -596,10 +596,6 @@ void CopySECItemToVector(const SECItem& item, std::vector<uint8>* out) {
out->assign(item.data, item.data + item.len); out->assign(item.data, item.data + item.len);
} }
// The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
// function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
// provide a fallback implementation.
#if defined(USE_NSS)
// From PKCS#1 [http://tools.ietf.org/html/rfc3447]: // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
// //
// RSAPrivateKey ::= SEQUENCE { // RSAPrivateKey ::= SEQUENCE {
...@@ -629,6 +625,10 @@ struct RSAPrivateKey { ...@@ -629,6 +625,10 @@ struct RSAPrivateKey {
SECItem coefficient; SECItem coefficient;
}; };
// The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
// function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
// provide a fallback implementation.
#if defined(USE_NSS)
const SEC_ASN1Template RSAPrivateKeyTemplate[] = { const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
{SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)}, {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
{SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)}, {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
...@@ -641,6 +641,7 @@ const SEC_ASN1Template RSAPrivateKeyTemplate[] = { ...@@ -641,6 +641,7 @@ const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
{SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)}, {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
{SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)}, {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
{0}}; {0}};
#endif // defined(USE_NSS)
// On success |value| will be filled with data which must be freed by // On success |value| will be filled with data which must be freed by
// SECITEM_FreeItem(value, PR_FALSE); // SECITEM_FreeItem(value, PR_FALSE);
...@@ -709,7 +710,6 @@ struct FreeRsaPrivateKey { ...@@ -709,7 +710,6 @@ struct FreeRsaPrivateKey {
SECITEM_FreeItem(&out->coefficient, PR_FALSE); SECITEM_FreeItem(&out->coefficient, PR_FALSE);
} }
}; };
#endif // defined(USE_NSS)
} // namespace } // namespace
...@@ -968,6 +968,37 @@ Status ExportRsaPublicKey(PublicKey* key, ...@@ -968,6 +968,37 @@ Status ExportRsaPublicKey(PublicKey* key,
return Status::Success(); return Status::Success();
} }
void AssignVectorFromSecItem(const SECItem& item, std::vector<uint8>* output) {
output->assign(item.data, item.data + item.len);
}
Status ExportRsaPrivateKey(PrivateKey* key,
std::vector<uint8>* modulus,
std::vector<uint8>* public_exponent,
std::vector<uint8>* private_exponent,
std::vector<uint8>* prime1,
std::vector<uint8>* prime2,
std::vector<uint8>* exponent1,
std::vector<uint8>* exponent2,
std::vector<uint8>* coefficient) {
RSAPrivateKey key_props = {};
scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
if (!InitRSAPrivateKey(key->key(), &key_props))
return Status::OperationError();
AssignVectorFromSecItem(key_props.modulus, modulus);
AssignVectorFromSecItem(key_props.public_exponent, public_exponent);
AssignVectorFromSecItem(key_props.private_exponent, private_exponent);
AssignVectorFromSecItem(key_props.prime1, prime1);
AssignVectorFromSecItem(key_props.prime2, prime2);
AssignVectorFromSecItem(key_props.exponent1, exponent1);
AssignVectorFromSecItem(key_props.exponent2, exponent2);
AssignVectorFromSecItem(key_props.coefficient, coefficient);
return Status::Success();
}
Status ExportKeyPkcs8(PrivateKey* key, Status ExportKeyPkcs8(PrivateKey* key,
const blink::WebCryptoKeyAlgorithm& key_algorithm, const blink::WebCryptoKeyAlgorithm& key_algorithm,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
...@@ -1494,6 +1525,111 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -1494,6 +1525,111 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::Success(); return Status::Success();
} }
struct DestroyGenericObject {
void operator()(PK11GenericObject* o) const {
if (o)
PK11_DestroyGenericObject(o);
}
};
typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
ScopedPK11GenericObject;
// Helper to add an attribute to a template.
void AddAttribute(CK_ATTRIBUTE_TYPE type,
void* value,
unsigned long length,
std::vector<CK_ATTRIBUTE>* templ) {
CK_ATTRIBUTE attribute = {type, value, length};
templ->push_back(attribute);
}
// Helper to optionally add an attribute to a template, if the provided data is
// non-empty.
void AddOptionalAttribute(CK_ATTRIBUTE_TYPE type,
const CryptoData& data,
std::vector<CK_ATTRIBUTE>* templ) {
if (!data.byte_length())
return;
CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()),
data.byte_length()};
templ->push_back(attribute);
}
Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
const CryptoData& modulus,
const CryptoData& public_exponent,
const CryptoData& private_exponent,
const CryptoData& prime1,
const CryptoData& prime2,
const CryptoData& exponent1,
const CryptoData& exponent2,
const CryptoData& coefficient,
blink::WebCryptoKey* key) {
CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
CK_KEY_TYPE key_type = CKK_RSA;
CK_BBOOL ck_false = CK_FALSE;
std::vector<CK_ATTRIBUTE> key_template;
AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
// Required properties.
AddOptionalAttribute(CKA_MODULUS, modulus, &key_template);
AddOptionalAttribute(CKA_PUBLIC_EXPONENT, public_exponent, &key_template);
AddOptionalAttribute(CKA_PRIVATE_EXPONENT, private_exponent, &key_template);
// Optional properties (all of these will have been specified or none).
AddOptionalAttribute(CKA_PRIME_1, prime1, &key_template);
AddOptionalAttribute(CKA_PRIME_2, prime2, &key_template);
AddOptionalAttribute(CKA_EXPONENT_1, exponent1, &key_template);
AddOptionalAttribute(CKA_EXPONENT_2, exponent2, &key_template);
AddOptionalAttribute(CKA_COEFFICIENT, coefficient, &key_template);
crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
slot.get(), &key_template[0], key_template.size(), PR_FALSE));
if (!key_object)
return Status::OperationError();
// The ID isn't guaranteed to be set by PKCS#11. However it is by softtoken so
// this should work.
SECItem object_id = {};
if (PK11_ReadRawAttribute(
PK11_TypeGeneric, key_object.get(), CKA_ID, &object_id) != SECSuccess)
return Status::OperationError();
crypto::ScopedSECKEYPrivateKey private_key(
PK11_FindKeyByKeyID(slot.get(), &object_id, NULL));
if (!private_key)
return Status::OperationError();
blink::WebCryptoKeyAlgorithm key_algorithm;
if (!CreatePrivateKeyAlgorithm(algorithm, private_key.get(), &key_algorithm))
return Status::ErrorUnexpected();
scoped_ptr<PrivateKey> key_handle;
Status status =
PrivateKey::Create(private_key.Pass(), key_algorithm, &key_handle);
if (status.IsError())
return status;
*key = blink::WebCryptoKey::create(key_handle.release(),
blink::WebCryptoKeyTypePrivate,
extractable,
key_algorithm,
usage_mask);
return Status::Success();
}
Status WrapSymKeyAesKw(SymKey* key, Status WrapSymKeyAesKw(SymKey* key,
SymKey* wrapping_key, SymKey* wrapping_key,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
......
...@@ -381,6 +381,22 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, ...@@ -381,6 +381,22 @@ Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
} }
Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
bool extractable,
blink::WebCryptoKeyUsageMask usage_mask,
const CryptoData& modulus,
const CryptoData& public_exponent,
const CryptoData& private_exponent,
const CryptoData& prime1,
const CryptoData& prime2,
const CryptoData& exponent1,
const CryptoData& exponent2,
const CryptoData& coefficient,
blink::WebCryptoKey* key) {
// TODO(eroman): http://crbug.com/267888
return Status::ErrorUnsupported();
}
Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
SymKey* key, SymKey* key,
const CryptoData& data, const CryptoData& data,
...@@ -462,6 +478,19 @@ Status ExportRsaPublicKey(PublicKey* key, ...@@ -462,6 +478,19 @@ Status ExportRsaPublicKey(PublicKey* key,
return Status::ErrorUnsupported(); return Status::ErrorUnsupported();
} }
Status ExportRsaPrivateKey(PrivateKey* key,
std::vector<uint8>* modulus,
std::vector<uint8>* public_exponent,
std::vector<uint8>* private_exponent,
std::vector<uint8>* prime1,
std::vector<uint8>* prime2,
std::vector<uint8>* exponent1,
std::vector<uint8>* exponent2,
std::vector<uint8>* coefficient) {
// TODO(eroman): http://crbug.com/267888
return Status::ErrorUnsupported();
}
Status WrapSymKeyAesKw(SymKey* key, Status WrapSymKeyAesKw(SymKey* key,
SymKey* wrapping_key, SymKey* wrapping_key,
std::vector<uint8>* buffer) { std::vector<uint8>* buffer) {
......
...@@ -47,30 +47,6 @@ bool IsValidAesKeyLengthBytes(unsigned int length_bytes) { ...@@ -47,30 +47,6 @@ bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
return length_bytes == 16 || length_bytes == 24 || length_bytes == 32; return length_bytes == 16 || length_bytes == 24 || length_bytes == 32;
} }
Status ToPlatformSymKey(const blink::WebCryptoKey& key,
platform::SymKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsSymKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
platform::PublicKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
platform::PrivateKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
const size_t kAesBlockSizeBytes = 16; const size_t kAesBlockSizeBytes = 16;
Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
...@@ -848,6 +824,30 @@ bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, ...@@ -848,6 +824,30 @@ bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
return ValidateDeserializedKey(*key, algorithm, type); return ValidateDeserializedKey(*key, algorithm, type);
} }
Status ToPlatformSymKey(const blink::WebCryptoKey& key,
platform::SymKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsSymKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
platform::PublicKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
platform::PrivateKey** out) {
*out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
if (!*out)
return Status::ErrorUnexpectedKeyType();
return Status::Success();
}
} // namespace webcrypto } // namespace webcrypto
} // namespace content } // namespace content
...@@ -160,6 +160,20 @@ CONTENT_EXPORT bool DeserializeKeyForClone( ...@@ -160,6 +160,20 @@ CONTENT_EXPORT bool DeserializeKeyForClone(
const CryptoData& key_data, const CryptoData& key_data,
blink::WebCryptoKey* key); blink::WebCryptoKey* key);
namespace platform {
class SymKey;
class PublicKey;
class PrivateKey;
}
Status ToPlatformSymKey(const blink::WebCryptoKey& key, platform::SymKey** out);
Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
platform::PublicKey** out);
Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
platform::PrivateKey** out);
} // namespace webcrypto } // namespace webcrypto
} // namespace content } // namespace content
......
...@@ -143,7 +143,7 @@ blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(const std::vector<uint8>& iv) { ...@@ -143,7 +143,7 @@ blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(const std::vector<uint8>& iv) {
new blink::WebCryptoAesCbcParams(Uint8VectorStart(iv), iv.size())); new blink::WebCryptoAesCbcParams(Uint8VectorStart(iv), iv.size()));
} }
// Creates and AES-GCM algorithm. // Creates an AES-GCM algorithm.
blink::WebCryptoAlgorithm CreateAesGcmAlgorithm( blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
const std::vector<uint8>& iv, const std::vector<uint8>& iv,
const std::vector<uint8>& additional_data, const std::vector<uint8>& additional_data,
...@@ -1564,13 +1564,6 @@ TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) { ...@@ -1564,13 +1564,6 @@ TEST_F(SharedCryptoTest, MAYBE(ImportJwkRsaFailures)) {
ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key)); ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
RestoreJwkRsaDictionary(&dict); RestoreJwkRsaDictionary(&dict);
} }
// Fail if "d" parameter is present, implying the JWK is a private key, which
// is not supported.
dict.SetString("d", "Qk3f0Dsyt");
EXPECT_EQ(Status::ErrorJwkRsaPrivateKeyUnsupported(),
ImportKeyJwkFromDict(dict, algorithm, false, usage_mask, &key));
RestoreJwkRsaDictionary(&dict);
} }
TEST_F(SharedCryptoTest, MAYBE(ImportJwkInputConsistency)) { TEST_F(SharedCryptoTest, MAYBE(ImportJwkInputConsistency)) {
...@@ -2042,6 +2035,149 @@ TEST_F(SharedCryptoTest, MAYBE(ImportExportPkcs8)) { ...@@ -2042,6 +2035,149 @@ TEST_F(SharedCryptoTest, MAYBE(ImportExportPkcs8)) {
&key)); &key));
} }
// Tests JWK import and export by doing a roundtrip key conversion and ensuring
// it was lossless:
//
// PKCS8 --> JWK --> PKCS8
TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkToPkcs8RoundTrip)) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
ASSERT_EQ(Status::Success(),
ImportKey(blink::WebCryptoKeyFormatPkcs8,
CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::WebCryptoAlgorithmIdSha1),
true,
blink::WebCryptoKeyUsageSign,
&key));
std::vector<uint8> exported_key_jwk;
ASSERT_EQ(Status::Success(),
ExportKey(blink::WebCryptoKeyFormatJwk, key, &exported_key_jwk));
// All of the optional parameters (p, q, dp, dq, qi) should be present in the
// output.
const char* expected_jwk =
"{\"alg\":\"RS1\",\"d\":\"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
"kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
"GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU\",\"dp\":"
"\"KPoTk4ZVvh-"
"KFZy6ylpy6hkMMAieGc0nSlVvNsT24Z9VSzTAd3kEJ7vdjdPt4kSDKPOF2Bsw6OQ7L_-"
"gJ4YZeQ\",\"dq\":\"Gos485j6cSBJiY1_t57gp3ZoeRKZzfoJ78DlB6yyHtdDAe9b_Ui-"
"RV6utuFnglWCdYCo5OjhQVHRUQqCo_LnKQ\",\"e\":\"AQAB\",\"ext\":true,\"key_"
"ops\":[\"sign\"],\"kty\":\"RSA\",\"n\":"
"\"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
"1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
"DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc\",\"p\":\"5-"
"iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31WhU1vZs8w0Fg"
"s7bc0-2o5kQw\",\"q\":\"tp3KHPfU1-yB51uQ_MqHSrzeEj_"
"ScAGAqpBHm25I3o1n7ST58Z2FuidYdPVCzSDccj5pYzZKH5QlRSsmmmeZ_Q\",\"qi\":"
"\"JxVqukEm0kqB86Uoy_sn9WiG-"
"ECp9uhuF6RLlP6TGVhLjiL93h5aLjvYqluo2FhBlOshkKz4MrhH8To9JKefTQ\"}";
ASSERT_EQ(CryptoData(std::string(expected_jwk)),
CryptoData(exported_key_jwk));
ASSERT_EQ(Status::Success(),
ImportKey(blink::WebCryptoKeyFormatJwk,
CryptoData(exported_key_jwk),
CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::WebCryptoAlgorithmIdSha1),
true,
blink::WebCryptoKeyUsageSign,
&key));
std::vector<uint8> exported_key_pkcs8;
ASSERT_EQ(
Status::Success(),
ExportKey(blink::WebCryptoKeyFormatPkcs8, key, &exported_key_pkcs8));
ASSERT_EQ(CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
CryptoData(exported_key_pkcs8));
}
// Import a JWK RSA private key with some optional parameters missing (q, dp,
// dq, qi).
//
// The only optional parameter included is "p".
//
// This fails because JWA says that producers must include either ALL optional
// parameters or NONE.
TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkMissingOptionalParams)) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
base::DictionaryValue dict;
dict.SetString("kty", "RSA");
dict.SetString("alg", "RS1");
dict.SetString(
"n",
"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
"1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
"DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
dict.SetString("e", "AQAB");
dict.SetString(
"d",
"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
"kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
"GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
dict.SetString("p",
"5-"
"iUJyCod1Fyc6NWBT6iobwMlKpy1VxuhilrLfyWeUjApyy8zKfqyzVwbgmh31W"
"hU1vZs8w0Fgs7bc0-2o5kQw");
ASSERT_EQ(Status::ErrorJwkIncompleteOptionalRsaPrivateKey(),
ImportKeyJwkFromDict(dict,
CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::WebCryptoAlgorithmIdSha1),
true,
blink::WebCryptoKeyUsageSign,
&key));
}
// Import a JWK RSA private key, without any of the optional parameters.
//
// This is expected to work, however based on the current NSS implementation it
// does not.
//
// TODO(eroman): http://crbug/com/374927
TEST_F(SharedCryptoTest, MAYBE(ImportRsaPrivateKeyJwkIncorrectOptionalEmpty)) {
blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
base::DictionaryValue dict;
dict.SetString("kty", "RSA");
dict.SetString("alg", "RS1");
dict.SetString(
"n",
"pW5KDnAQF1iaUYfcfqhB0Vby7A42rVKkTf6x5h962ZHYxRBW_-2xYrTA8oOhKoijlN_"
"1JqtykcuzB86r_OCx39XNlQgJbVsri2311nHvY3fAkhyyPCcKcOJZjm_4nRnxBazC0_"
"DLNfKSgOE4a29kxO8i4eHyDQzoz_siSb2aITc");
dict.SetString("e", "AQAB");
dict.SetString(
"d",
"M6UEKpCyfU9UUcqbu9C0R3GhAa-IQ0Cu-YhfKku-"
"kuiUpySsPFaMj5eFOtB8AmbIxqPKCSnx6PESMYhEKfxNmuVf7olqEM5wfD7X5zTkRyejlXRQ"
"GlMmgxCcKrrKuig8MbS9L1PD7jfjUs7jT55QO9gMBiKtecbc7og1R8ajsyU");
// TODO(eroman): This should pass, see: http://crbug/com/374927
//
// Technically it is OK to fail since JWA says that consumer are not required
// to support lack of the optional parameters.
ASSERT_EQ(Status::OperationError(),
ImportKeyJwkFromDict(dict,
CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
blink::WebCryptoAlgorithmIdSha1),
true,
blink::WebCryptoKeyUsageSign,
&key));
}
TEST_F(SharedCryptoTest, MAYBE(GenerateKeyPairRsa)) { TEST_F(SharedCryptoTest, MAYBE(GenerateKeyPairRsa)) {
// Note: using unrealistic short key lengths here to avoid bogging down tests. // Note: using unrealistic short key lengths here to avoid bogging down tests.
......
...@@ -99,12 +99,6 @@ Status Status::ErrorJwkUseAndKeyopsInconsistent() { ...@@ -99,12 +99,6 @@ Status Status::ErrorJwkUseAndKeyopsInconsistent() {
"but are inconsistent with each other."); "but are inconsistent with each other.");
} }
Status Status::ErrorJwkRsaPrivateKeyUnsupported() {
return Status(blink::WebCryptoErrorTypeNotSupported,
"JWK RSA key contained \"d\" property: Private key import is "
"not yet supported");
}
Status Status::ErrorJwkUnrecognizedKty() { Status Status::ErrorJwkUnrecognizedKty() {
return Status(blink::WebCryptoErrorTypeData, return Status(blink::WebCryptoErrorTypeData,
"The JWK \"kty\" property was unrecognized"); "The JWK \"kty\" property was unrecognized");
...@@ -116,6 +110,12 @@ Status Status::ErrorJwkIncorrectKeyLength() { ...@@ -116,6 +110,12 @@ Status Status::ErrorJwkIncorrectKeyLength() {
"of key data for the given algorithm."); "of key data for the given algorithm.");
} }
Status Status::ErrorJwkIncompleteOptionalRsaPrivateKey() {
return Status(blink::WebCryptoErrorTypeData,
"The optional JWK properties p, q, dp, dq, qi must either all "
"be provided, or none provided");
}
Status Status::ErrorImportEmptyKeyData() { Status Status::ErrorImportEmptyKeyData() {
return Status(blink::WebCryptoErrorTypeData, "No key data was provided"); return Status(blink::WebCryptoErrorTypeData, "No key data was provided");
} }
......
...@@ -102,9 +102,6 @@ class CONTENT_EXPORT Status { ...@@ -102,9 +102,6 @@ class CONTENT_EXPORT Status {
// are incompatible with each other. // are incompatible with each other.
static Status ErrorJwkUseAndKeyopsInconsistent(); static Status ErrorJwkUseAndKeyopsInconsistent();
// TODO(eroman): Private key import through JWK is not yet supported.
static Status ErrorJwkRsaPrivateKeyUnsupported();
// The "kty" parameter was given and was a string, however it was // The "kty" parameter was given and was a string, however it was
// unrecognized. // unrecognized.
static Status ErrorJwkUnrecognizedKty(); static Status ErrorJwkUnrecognizedKty();
...@@ -115,6 +112,10 @@ class CONTENT_EXPORT Status { ...@@ -115,6 +112,10 @@ class CONTENT_EXPORT Status {
// given that is an error. // given that is an error.
static Status ErrorJwkIncorrectKeyLength(); static Status ErrorJwkIncorrectKeyLength();
// The JWK was for an RSA private key but only partially provided the optional
// parameters (p, q, dq, dq, qi).
static Status ErrorJwkIncompleteOptionalRsaPrivateKey();
// ------------------------------------ // ------------------------------------
// Other errors // Other errors
// ------------------------------------ // ------------------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment