Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1179)

Unified Diff: content/child/webcrypto/platform_crypto_nss.cc

Issue 203753009: [webcrypto] Add PKCS#8 export for RSA private keys for NSS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/child/webcrypto/platform_crypto_nss.cc
diff --git a/content/child/webcrypto/platform_crypto_nss.cc b/content/child/webcrypto/platform_crypto_nss.cc
index 478c7aaff73fbb6c873cdcab6465c6de80a146ec..5192cf4f7989c353bd866030ef72029b2bbae10f 100644
--- a/content/child/webcrypto/platform_crypto_nss.cc
+++ b/content/child/webcrypto/platform_crypto_nss.cc
@@ -7,6 +7,7 @@
#include <cryptohi.h>
#include <pk11pub.h>
#include <sechash.h>
+#include <secoid.h>
#include <vector>
@@ -552,6 +553,116 @@ Status DoUnwrapSymKeyAesKw(const CryptoData& wrapped_key_data,
return Status::Success();
}
+// From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
+//
+// RSAPrivateKey ::= SEQUENCE {
+// version Version,
+// modulus INTEGER, -- n
+// publicExponent INTEGER, -- e
+// privateExponent INTEGER, -- d
+// prime1 INTEGER, -- p
+// prime2 INTEGER, -- q
+// exponent1 INTEGER, -- d mod (p-1)
+// exponent2 INTEGER, -- d mod (q-1)
+// coefficient INTEGER, -- (inverse of q) mod p
+// otherPrimeInfos OtherPrimeInfos OPTIONAL
+// }
+//
+// Note that otherPrimeInfos is only applicable for version=1. Since NSS
+// doesn't use multi-prime can safely use version=0.
+struct RSAPrivateKey {
+ SECItem version;
+ SECItem modulus;
+ SECItem public_exponent;
+ SECItem private_exponent;
+ SECItem prime1;
+ SECItem prime2;
+ SECItem exponent1;
+ SECItem exponent2;
+ SECItem coefficient;
+};
+
+const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
+ {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
+ {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
+ {0}};
+
+// On success |value| will be filled with data which must be freed by
+// SECITEM_FreeItem(value, PR_FALSE);
+bool ReadUint(SECKEYPrivateKey* key,
+ CK_ATTRIBUTE_TYPE attribute,
+ SECItem* value) {
+ SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
+
+ // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
+ // for the ASN.1 encoding to be correct, the items must be of type
+ // siUnsignedInteger.
+ value->type = siUnsignedInteger;
+
+ return rv == SECSuccess;
+}
+
+// Fills |out| with the RSA private key properties. Returns true on success.
+// Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
+// to free up any allocated memory.
+//
+// The passed in RSAPrivateKey must be zero-initialized.
+bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
+ if (key->keyType != rsaKey)
+ return false;
+
+ // Everything should be zero-ed out. These are just some spot checks.
+ DCHECK(!out->version.data);
+ DCHECK(!out->version.len);
+ DCHECK(!out->modulus.data);
+ DCHECK(!out->modulus.len);
+
+ // Always use version=0 since not using multi-prime.
+ if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
+ return false;
+
+ if (!ReadUint(key, CKA_MODULUS, &out->modulus))
+ return false;
+ if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
+ return false;
+ if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
+ return false;
+ if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
+ return false;
+ if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
+ return false;
+ if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
+ return false;
+ if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
+ return false;
+ if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
+ return false;
+
+ return true;
+}
+
+struct FreeRsaPrivateKey {
+ void operator()(RSAPrivateKey* out) {
+ SECITEM_FreeItem(&out->version, PR_FALSE);
+ SECITEM_FreeItem(&out->modulus, PR_FALSE);
+ SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
+ SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
+ SECITEM_FreeItem(&out->prime1, PR_FALSE);
+ SECITEM_FreeItem(&out->prime2, PR_FALSE);
+ SECITEM_FreeItem(&out->exponent1, PR_FALSE);
+ SECITEM_FreeItem(&out->exponent2, PR_FALSE);
+ SECITEM_FreeItem(&out->coefficient, PR_FALSE);
+ }
+};
+
} // namespace
Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm,
@@ -695,6 +806,57 @@ Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) {
return Status::Success();
}
+Status ExportKeyPkcs8(PrivateKey* key,
+ const blink::WebCryptoKeyAlgorithm& key_algorithm,
+ blink::WebArrayBuffer* buffer) {
+ // TODO(eroman): Support other RSA key types as they are added to Blink.
+ if (key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 &&
+ key_algorithm.id() != blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5)
+ return Status::ErrorUnsupported();
+
+ const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ const int kPrivateKeyInfoVersion = 0;
+
+ SECKEYPrivateKeyInfo private_key_info = {};
+ RSAPrivateKey rsa_private_key = {};
+ scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
+ &rsa_private_key);
+
+ if (!InitRSAPrivateKey(key->key(), &rsa_private_key))
+ return Status::Error();
+
+ crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ if (!arena.get())
+ return Status::Error();
+
+ if (!SEC_ASN1EncodeItem(arena.get(),
+ &private_key_info.privateKey,
+ &rsa_private_key,
+ RSAPrivateKeyTemplate))
+ return Status::Error();
+
+ if (SECSuccess !=
+ SECOID_SetAlgorithmID(
+ arena.get(), &private_key_info.algorithm, algorithm, NULL))
+ return Status::Error();
+
+ if (!SEC_ASN1EncodeInteger(
+ arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
+ return Status::Error();
+
+ crypto::ScopedSECItem encoded_key(
+ SEC_ASN1EncodeItem(NULL,
+ NULL,
+ &private_key_info,
+ SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
+
+ if (!encoded_key.get())
+ return Status::Error();
+
+ *buffer = CreateArrayBuffer(encoded_key->data, encoded_key->len);
+ return Status::Success();
+}
+
Status ImportKeyPkcs8(const blink::WebCryptoAlgorithm& algorithm,
const CryptoData& key_data,
bool extractable,
« no previous file with comments | « content/child/webcrypto/platform_crypto.h ('k') | content/child/webcrypto/platform_crypto_openssl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698