Home | History | Annotate | Download | only in nss
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/child/webcrypto/nss/rsa_key_nss.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/child/webcrypto/crypto_data.h"
      9 #include "content/child/webcrypto/jwk.h"
     10 #include "content/child/webcrypto/nss/key_nss.h"
     11 #include "content/child/webcrypto/nss/util_nss.h"
     12 #include "content/child/webcrypto/status.h"
     13 #include "content/child/webcrypto/webcrypto_util.h"
     14 #include "crypto/scoped_nss_types.h"
     15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
     16 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
     17 
     18 namespace content {
     19 
     20 namespace webcrypto {
     21 
     22 namespace {
     23 
     24 #if defined(USE_NSS) && !defined(OS_CHROMEOS)
     25 Status ErrorRsaPrivateKeyImportNotSupported() {
     26   return Status::ErrorUnsupported(
     27       "NSS version must be at least 3.16.2 for RSA private key import. See "
     28       "http://crbug.com/380424");
     29 }
     30 
     31 // Prior to NSS 3.16.2 RSA key parameters were not validated. This is
     32 // a security problem for RSA private key import from JWK which uses a
     33 // CKA_ID based on the public modulus to retrieve the private key.
     34 Status NssSupportsRsaPrivateKeyImport() {
     35   if (!NSS_VersionCheck("3.16.2"))
     36     return ErrorRsaPrivateKeyImportNotSupported();
     37 
     38   // Also ensure that the version of Softoken is 3.16.2 or later.
     39   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
     40   CK_SLOT_INFO info = {};
     41   if (PK11_GetSlotInfo(slot.get(), &info) != SECSuccess)
     42     return ErrorRsaPrivateKeyImportNotSupported();
     43 
     44   // CK_SLOT_INFO.hardwareVersion contains the major.minor
     45   // version info for Softoken in the corresponding .major/.minor
     46   // fields, and .firmwareVersion contains the patch.build
     47   // version info (in the .major/.minor fields)
     48   if ((info.hardwareVersion.major > 3) ||
     49       (info.hardwareVersion.major == 3 &&
     50        (info.hardwareVersion.minor > 16 ||
     51         (info.hardwareVersion.minor == 16 &&
     52          info.firmwareVersion.major >= 2)))) {
     53     return Status::Success();
     54   }
     55 
     56   return ErrorRsaPrivateKeyImportNotSupported();
     57 }
     58 #else
     59 Status NssSupportsRsaPrivateKeyImport() {
     60   return Status::Success();
     61 }
     62 #endif
     63 
     64 bool CreateRsaHashedPublicKeyAlgorithm(
     65     blink::WebCryptoAlgorithmId rsa_algorithm,
     66     blink::WebCryptoAlgorithmId hash_algorithm,
     67     SECKEYPublicKey* key,
     68     blink::WebCryptoKeyAlgorithm* key_algorithm) {
     69   // TODO(eroman): What about other key types rsaPss, rsaOaep.
     70   if (!key || key->keyType != rsaKey)
     71     return false;
     72 
     73   unsigned int modulus_length_bits = SECKEY_PublicKeyStrength(key) * 8;
     74   CryptoData public_exponent(key->u.rsa.publicExponent.data,
     75                              key->u.rsa.publicExponent.len);
     76 
     77   *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
     78       rsa_algorithm,
     79       modulus_length_bits,
     80       public_exponent.bytes(),
     81       public_exponent.byte_length(),
     82       hash_algorithm);
     83   return true;
     84 }
     85 
     86 bool CreateRsaHashedPrivateKeyAlgorithm(
     87     blink::WebCryptoAlgorithmId rsa_algorithm,
     88     blink::WebCryptoAlgorithmId hash_algorithm,
     89     SECKEYPrivateKey* key,
     90     blink::WebCryptoKeyAlgorithm* key_algorithm) {
     91   crypto::ScopedSECKEYPublicKey public_key(SECKEY_ConvertToPublicKey(key));
     92   if (!public_key)
     93     return false;
     94   return CreateRsaHashedPublicKeyAlgorithm(
     95       rsa_algorithm, hash_algorithm, public_key.get(), key_algorithm);
     96 }
     97 
     98 // From PKCS#1 [http://tools.ietf.org/html/rfc3447]:
     99 //
    100 //    RSAPrivateKey ::= SEQUENCE {
    101 //      version           Version,
    102 //      modulus           INTEGER,  -- n
    103 //      publicExponent    INTEGER,  -- e
    104 //      privateExponent   INTEGER,  -- d
    105 //      prime1            INTEGER,  -- p
    106 //      prime2            INTEGER,  -- q
    107 //      exponent1         INTEGER,  -- d mod (p-1)
    108 //      exponent2         INTEGER,  -- d mod (q-1)
    109 //      coefficient       INTEGER,  -- (inverse of q) mod p
    110 //      otherPrimeInfos   OtherPrimeInfos OPTIONAL
    111 //    }
    112 //
    113 // Note that otherPrimeInfos is only applicable for version=1. Since NSS
    114 // doesn't use multi-prime can safely use version=0.
    115 struct RSAPrivateKey {
    116   SECItem version;
    117   SECItem modulus;
    118   SECItem public_exponent;
    119   SECItem private_exponent;
    120   SECItem prime1;
    121   SECItem prime2;
    122   SECItem exponent1;
    123   SECItem exponent2;
    124   SECItem coefficient;
    125 };
    126 
    127 // The system NSS library doesn't have the new PK11_ExportDERPrivateKeyInfo
    128 // function yet (https://bugzilla.mozilla.org/show_bug.cgi?id=519255). So we
    129 // provide a fallback implementation.
    130 #if defined(USE_NSS)
    131 const SEC_ASN1Template RSAPrivateKeyTemplate[] = {
    132     {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey)},
    133     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, version)},
    134     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, modulus)},
    135     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, public_exponent)},
    136     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, private_exponent)},
    137     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime1)},
    138     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, prime2)},
    139     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent1)},
    140     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, exponent2)},
    141     {SEC_ASN1_INTEGER, offsetof(RSAPrivateKey, coefficient)},
    142     {0}};
    143 #endif  // defined(USE_NSS)
    144 
    145 // On success |value| will be filled with data which must be freed by
    146 // SECITEM_FreeItem(value, PR_FALSE);
    147 bool ReadUint(SECKEYPrivateKey* key,
    148               CK_ATTRIBUTE_TYPE attribute,
    149               SECItem* value) {
    150   SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, attribute, value);
    151 
    152   // PK11_ReadRawAttribute() returns items of type siBuffer. However in order
    153   // for the ASN.1 encoding to be correct, the items must be of type
    154   // siUnsignedInteger.
    155   value->type = siUnsignedInteger;
    156 
    157   return rv == SECSuccess;
    158 }
    159 
    160 // Fills |out| with the RSA private key properties. Returns true on success.
    161 // Regardless of the return value, the caller must invoke FreeRSAPrivateKey()
    162 // to free up any allocated memory.
    163 //
    164 // The passed in RSAPrivateKey must be zero-initialized.
    165 bool InitRSAPrivateKey(SECKEYPrivateKey* key, RSAPrivateKey* out) {
    166   if (key->keyType != rsaKey)
    167     return false;
    168 
    169   // Everything should be zero-ed out. These are just some spot checks.
    170   DCHECK(!out->version.data);
    171   DCHECK(!out->version.len);
    172   DCHECK(!out->modulus.data);
    173   DCHECK(!out->modulus.len);
    174 
    175   // Always use version=0 since not using multi-prime.
    176   if (!SEC_ASN1EncodeInteger(NULL, &out->version, 0))
    177     return false;
    178 
    179   if (!ReadUint(key, CKA_MODULUS, &out->modulus))
    180     return false;
    181   if (!ReadUint(key, CKA_PUBLIC_EXPONENT, &out->public_exponent))
    182     return false;
    183   if (!ReadUint(key, CKA_PRIVATE_EXPONENT, &out->private_exponent))
    184     return false;
    185   if (!ReadUint(key, CKA_PRIME_1, &out->prime1))
    186     return false;
    187   if (!ReadUint(key, CKA_PRIME_2, &out->prime2))
    188     return false;
    189   if (!ReadUint(key, CKA_EXPONENT_1, &out->exponent1))
    190     return false;
    191   if (!ReadUint(key, CKA_EXPONENT_2, &out->exponent2))
    192     return false;
    193   if (!ReadUint(key, CKA_COEFFICIENT, &out->coefficient))
    194     return false;
    195 
    196   return true;
    197 }
    198 
    199 struct FreeRsaPrivateKey {
    200   void operator()(RSAPrivateKey* out) {
    201     SECITEM_FreeItem(&out->version, PR_FALSE);
    202     SECITEM_FreeItem(&out->modulus, PR_FALSE);
    203     SECITEM_FreeItem(&out->public_exponent, PR_FALSE);
    204     SECITEM_FreeItem(&out->private_exponent, PR_FALSE);
    205     SECITEM_FreeItem(&out->prime1, PR_FALSE);
    206     SECITEM_FreeItem(&out->prime2, PR_FALSE);
    207     SECITEM_FreeItem(&out->exponent1, PR_FALSE);
    208     SECITEM_FreeItem(&out->exponent2, PR_FALSE);
    209     SECITEM_FreeItem(&out->coefficient, PR_FALSE);
    210   }
    211 };
    212 
    213 typedef scoped_ptr<CERTSubjectPublicKeyInfo,
    214                    crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
    215                                         SECKEY_DestroySubjectPublicKeyInfo> >
    216     ScopedCERTSubjectPublicKeyInfo;
    217 
    218 struct DestroyGenericObject {
    219   void operator()(PK11GenericObject* o) const {
    220     if (o)
    221       PK11_DestroyGenericObject(o);
    222   }
    223 };
    224 
    225 typedef scoped_ptr<PK11GenericObject, DestroyGenericObject>
    226     ScopedPK11GenericObject;
    227 
    228 // Helper to add an attribute to a template.
    229 void AddAttribute(CK_ATTRIBUTE_TYPE type,
    230                   void* value,
    231                   unsigned long length,
    232                   std::vector<CK_ATTRIBUTE>* templ) {
    233   CK_ATTRIBUTE attribute = {type, value, length};
    234   templ->push_back(attribute);
    235 }
    236 
    237 void AddAttribute(CK_ATTRIBUTE_TYPE type,
    238                   const CryptoData& data,
    239                   std::vector<CK_ATTRIBUTE>* templ) {
    240   CK_ATTRIBUTE attribute = {type, const_cast<unsigned char*>(data.bytes()),
    241                             data.byte_length()};
    242   templ->push_back(attribute);
    243 }
    244 
    245 void AddAttribute(CK_ATTRIBUTE_TYPE type,
    246                   const std::string& data,
    247                   std::vector<CK_ATTRIBUTE>* templ) {
    248   AddAttribute(type, CryptoData(data), templ);
    249 }
    250 
    251 Status ExportKeyPkcs8Nss(SECKEYPrivateKey* key, std::vector<uint8_t>* buffer) {
    252   if (key->keyType != rsaKey)
    253     return Status::ErrorUnsupported();
    254 
    255 // TODO(rsleevi): Implement OAEP support according to the spec.
    256 
    257 #if defined(USE_NSS)
    258   // PK11_ExportDERPrivateKeyInfo isn't available. Use our fallback code.
    259   const SECOidTag algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
    260   const int kPrivateKeyInfoVersion = 0;
    261 
    262   SECKEYPrivateKeyInfo private_key_info = {};
    263   RSAPrivateKey rsa_private_key = {};
    264   scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(
    265       &rsa_private_key);
    266 
    267   // http://crbug.com/366427: the spec does not define any other failures for
    268   // exporting, so none of the subsequent errors are spec compliant.
    269   if (!InitRSAPrivateKey(key, &rsa_private_key))
    270     return Status::OperationError();
    271 
    272   crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
    273   if (!arena.get())
    274     return Status::OperationError();
    275 
    276   if (!SEC_ASN1EncodeItem(arena.get(),
    277                           &private_key_info.privateKey,
    278                           &rsa_private_key,
    279                           RSAPrivateKeyTemplate))
    280     return Status::OperationError();
    281 
    282   if (SECSuccess !=
    283       SECOID_SetAlgorithmID(
    284           arena.get(), &private_key_info.algorithm, algorithm, NULL))
    285     return Status::OperationError();
    286 
    287   if (!SEC_ASN1EncodeInteger(
    288           arena.get(), &private_key_info.version, kPrivateKeyInfoVersion))
    289     return Status::OperationError();
    290 
    291   crypto::ScopedSECItem encoded_key(
    292       SEC_ASN1EncodeItem(NULL,
    293                          NULL,
    294                          &private_key_info,
    295                          SEC_ASN1_GET(SECKEY_PrivateKeyInfoTemplate)));
    296 #else   // defined(USE_NSS)
    297   crypto::ScopedSECItem encoded_key(PK11_ExportDERPrivateKeyInfo(key, NULL));
    298 #endif  // defined(USE_NSS)
    299 
    300   if (!encoded_key.get())
    301     return Status::OperationError();
    302 
    303   buffer->assign(encoded_key->data, encoded_key->data + encoded_key->len);
    304   return Status::Success();
    305 }
    306 
    307 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm,
    308                            bool extractable,
    309                            blink::WebCryptoKeyUsageMask usage_mask,
    310                            const JwkRsaInfo& params,
    311                            blink::WebCryptoKey* key) {
    312   Status status = NssSupportsRsaPrivateKeyImport();
    313   if (status.IsError())
    314     return status;
    315 
    316   CK_OBJECT_CLASS obj_class = CKO_PRIVATE_KEY;
    317   CK_KEY_TYPE key_type = CKK_RSA;
    318   CK_BBOOL ck_false = CK_FALSE;
    319 
    320   std::vector<CK_ATTRIBUTE> key_template;
    321 
    322   AddAttribute(CKA_CLASS, &obj_class, sizeof(obj_class), &key_template);
    323   AddAttribute(CKA_KEY_TYPE, &key_type, sizeof(key_type), &key_template);
    324   AddAttribute(CKA_TOKEN, &ck_false, sizeof(ck_false), &key_template);
    325   AddAttribute(CKA_SENSITIVE, &ck_false, sizeof(ck_false), &key_template);
    326   AddAttribute(CKA_PRIVATE, &ck_false, sizeof(ck_false), &key_template);
    327 
    328   // Required properties by JWA.
    329   AddAttribute(CKA_MODULUS, params.n, &key_template);
    330   AddAttribute(CKA_PUBLIC_EXPONENT, params.e, &key_template);
    331   AddAttribute(CKA_PRIVATE_EXPONENT, params.d, &key_template);
    332 
    333   // Manufacture a CKA_ID so the created key can be retrieved later as a
    334   // SECKEYPrivateKey using FindKeyByKeyID(). Unfortunately there isn't a more
    335   // direct way to do this in NSS.
    336   //
    337   // For consistency with other NSS key creation methods, set the CKA_ID to
    338   // PK11_MakeIDFromPubKey(). There are some problems with
    339   // this approach:
    340   //
    341   //  (1) Prior to NSS 3.16.2, there is no parameter validation when creating
    342   //      private keys. It is therefore possible to construct a key using the
    343   //      known public modulus, and where all the other parameters are bogus.
    344   //      FindKeyByKeyID() returns the first key matching the ID. So this would
    345   //      effectively allow an attacker to retrieve a private key of their
    346   //      choice.
    347   //
    348   //  (2) The ID space is shared by different key types. So theoretically
    349   //      possible to retrieve a key of the wrong type which has a matching
    350   //      CKA_ID. In practice I am told this is not likely except for small key
    351   //      sizes, since would require constructing keys with the same public
    352   //      data.
    353   //
    354   //  (3) FindKeyByKeyID() doesn't necessarily return the object that was just
    355   //      created by CreateGenericObject. If the pre-existing key was
    356   //      provisioned with flags incompatible with WebCrypto (for instance
    357   //      marked sensitive) then this will break things.
    358   SECItem modulus_item = MakeSECItemForBuffer(CryptoData(params.n));
    359   crypto::ScopedSECItem object_id(PK11_MakeIDFromPubKey(&modulus_item));
    360   AddAttribute(
    361       CKA_ID, CryptoData(object_id->data, object_id->len), &key_template);
    362 
    363   // Optional properties by JWA, however guaranteed to be present by Chromium's
    364   // implementation.
    365   AddAttribute(CKA_PRIME_1, params.p, &key_template);
    366   AddAttribute(CKA_PRIME_2, params.q, &key_template);
    367   AddAttribute(CKA_EXPONENT_1, params.dp, &key_template);
    368   AddAttribute(CKA_EXPONENT_2, params.dq, &key_template);
    369   AddAttribute(CKA_COEFFICIENT, params.qi, &key_template);
    370 
    371   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
    372 
    373   ScopedPK11GenericObject key_object(PK11_CreateGenericObject(
    374       slot.get(), &key_template[0], key_template.size(), PR_FALSE));
    375 
    376   if (!key_object)
    377     return Status::OperationError();
    378 
    379   crypto::ScopedSECKEYPrivateKey private_key_tmp(
    380       PK11_FindKeyByKeyID(slot.get(), object_id.get(), NULL));
    381 
    382   // PK11_FindKeyByKeyID() may return a handle to an existing key, rather than
    383   // the object created by PK11_CreateGenericObject().
    384   crypto::ScopedSECKEYPrivateKey private_key(
    385       SECKEY_CopyPrivateKey(private_key_tmp.get()));
    386 
    387   if (!private_key)
    388     return Status::OperationError();
    389 
    390   blink::WebCryptoKeyAlgorithm key_algorithm;
    391   if (!CreateRsaHashedPrivateKeyAlgorithm(
    392           algorithm.id(),
    393           algorithm.rsaHashedImportParams()->hash().id(),
    394           private_key.get(),
    395           &key_algorithm)) {
    396     return Status::ErrorUnexpected();
    397   }
    398 
    399   std::vector<uint8_t> pkcs8_data;
    400   status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
    401   if (status.IsError())
    402     return status;
    403 
    404   scoped_ptr<PrivateKeyNss> key_handle(
    405       new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
    406 
    407   *key = blink::WebCryptoKey::create(key_handle.release(),
    408                                      blink::WebCryptoKeyTypePrivate,
    409                                      extractable,
    410                                      key_algorithm,
    411                                      usage_mask);
    412   return Status::Success();
    413 }
    414 
    415 Status ExportKeySpkiNss(SECKEYPublicKey* key, std::vector<uint8_t>* buffer) {
    416   const crypto::ScopedSECItem spki_der(
    417       SECKEY_EncodeDERSubjectPublicKeyInfo(key));
    418   if (!spki_der)
    419     return Status::OperationError();
    420 
    421   buffer->assign(spki_der->data, spki_der->data + spki_der->len);
    422   return Status::Success();
    423 }
    424 
    425 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm,
    426                           bool extractable,
    427                           blink::WebCryptoKeyUsageMask usage_mask,
    428                           const CryptoData& modulus_data,
    429                           const CryptoData& exponent_data,
    430                           blink::WebCryptoKey* key) {
    431   if (!modulus_data.byte_length())
    432     return Status::ErrorImportRsaEmptyModulus();
    433 
    434   if (!exponent_data.byte_length())
    435     return Status::ErrorImportRsaEmptyExponent();
    436 
    437   DCHECK(modulus_data.bytes());
    438   DCHECK(exponent_data.bytes());
    439 
    440   // NSS does not provide a way to create an RSA public key directly from the
    441   // modulus and exponent values, but it can import an DER-encoded ASN.1 blob
    442   // with these values and create the public key from that. The code below
    443   // follows the recommendation described in
    444   // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7
    445 
    446   // Pack the input values into a struct compatible with NSS ASN.1 encoding, and
    447   // set up an ASN.1 encoder template for it.
    448   struct RsaPublicKeyData {
    449     SECItem modulus;
    450     SECItem exponent;
    451   };
    452   const RsaPublicKeyData pubkey_in = {
    453       {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()),
    454        modulus_data.byte_length()},
    455       {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()),
    456        exponent_data.byte_length()}};
    457   const SEC_ASN1Template rsa_public_key_template[] = {
    458       {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)},
    459       {
    460        SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus),
    461       },
    462       {
    463        SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent),
    464       },
    465       {
    466        0,
    467       }};
    468 
    469   // DER-encode the public key.
    470   crypto::ScopedSECItem pubkey_der(
    471       SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template));
    472   if (!pubkey_der)
    473     return Status::OperationError();
    474 
    475   // Import the DER-encoded public key to create an RSA SECKEYPublicKey.
    476   crypto::ScopedSECKEYPublicKey pubkey(
    477       SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA));
    478   if (!pubkey)
    479     return Status::OperationError();
    480 
    481   blink::WebCryptoKeyAlgorithm key_algorithm;
    482   if (!CreateRsaHashedPublicKeyAlgorithm(
    483           algorithm.id(),
    484           algorithm.rsaHashedImportParams()->hash().id(),
    485           pubkey.get(),
    486           &key_algorithm)) {
    487     return Status::ErrorUnexpected();
    488   }
    489 
    490   std::vector<uint8_t> spki_data;
    491   Status status = ExportKeySpkiNss(pubkey.get(), &spki_data);
    492   if (status.IsError())
    493     return status;
    494 
    495   scoped_ptr<PublicKeyNss> key_handle(
    496       new PublicKeyNss(pubkey.Pass(), CryptoData(spki_data)));
    497 
    498   *key = blink::WebCryptoKey::create(key_handle.release(),
    499                                      blink::WebCryptoKeyTypePublic,
    500                                      extractable,
    501                                      key_algorithm,
    502                                      usage_mask);
    503   return Status::Success();
    504 }
    505 
    506 }  // namespace
    507 
    508 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeGenerateKeyPair(
    509     blink::WebCryptoKeyUsageMask combined_usage_mask,
    510     blink::WebCryptoKeyUsageMask* public_usage_mask,
    511     blink::WebCryptoKeyUsageMask* private_usage_mask) const {
    512   Status status = CheckKeyCreationUsages(
    513       all_public_key_usages_ | all_private_key_usages_, combined_usage_mask);
    514   if (status.IsError())
    515     return status;
    516 
    517   *public_usage_mask = combined_usage_mask & all_public_key_usages_;
    518   *private_usage_mask = combined_usage_mask & all_private_key_usages_;
    519 
    520   return Status::Success();
    521 }
    522 
    523 Status RsaHashedAlgorithm::GenerateKeyPair(
    524     const blink::WebCryptoAlgorithm& algorithm,
    525     bool extractable,
    526     blink::WebCryptoKeyUsageMask public_usage_mask,
    527     blink::WebCryptoKeyUsageMask private_usage_mask,
    528     blink::WebCryptoKey* public_key,
    529     blink::WebCryptoKey* private_key) const {
    530   unsigned int public_exponent = 0;
    531   unsigned int modulus_length_bits = 0;
    532   Status status = GetRsaKeyGenParameters(algorithm.rsaHashedKeyGenParams(),
    533                                          &public_exponent,
    534                                          &modulus_length_bits);
    535   if (status.IsError())
    536     return status;
    537 
    538   crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot());
    539   if (!slot)
    540     return Status::OperationError();
    541 
    542   PK11RSAGenParams rsa_gen_params;
    543   rsa_gen_params.keySizeInBits = modulus_length_bits;
    544   rsa_gen_params.pe = public_exponent;
    545 
    546   const CK_FLAGS operation_flags_mask =
    547       CKF_ENCRYPT | CKF_DECRYPT | CKF_SIGN | CKF_VERIFY | CKF_WRAP | CKF_UNWRAP;
    548 
    549   // The private key must be marked as insensitive and extractable, otherwise it
    550   // cannot later be exported in unencrypted form or structured-cloned.
    551   const PK11AttrFlags attribute_flags =
    552       PK11_ATTR_INSENSITIVE | PK11_ATTR_EXTRACTABLE;
    553 
    554   // Note: NSS does not generate an sec_public_key if the call below fails,
    555   // so there is no danger of a leaked sec_public_key.
    556   SECKEYPublicKey* sec_public_key;
    557   crypto::ScopedSECKEYPrivateKey scoped_sec_private_key(
    558       PK11_GenerateKeyPairWithOpFlags(slot.get(),
    559                                       CKM_RSA_PKCS_KEY_PAIR_GEN,
    560                                       &rsa_gen_params,
    561                                       &sec_public_key,
    562                                       attribute_flags,
    563                                       generate_flags_,
    564                                       operation_flags_mask,
    565                                       NULL));
    566   if (!scoped_sec_private_key)
    567     return Status::OperationError();
    568 
    569   blink::WebCryptoKeyAlgorithm key_algorithm;
    570   if (!CreateRsaHashedPublicKeyAlgorithm(
    571           algorithm.id(),
    572           algorithm.rsaHashedKeyGenParams()->hash().id(),
    573           sec_public_key,
    574           &key_algorithm)) {
    575     return Status::ErrorUnexpected();
    576   }
    577 
    578   std::vector<uint8_t> spki_data;
    579   status = ExportKeySpkiNss(sec_public_key, &spki_data);
    580   if (status.IsError())
    581     return status;
    582 
    583   scoped_ptr<PublicKeyNss> public_key_handle(new PublicKeyNss(
    584       crypto::ScopedSECKEYPublicKey(sec_public_key), CryptoData(spki_data)));
    585 
    586   std::vector<uint8_t> pkcs8_data;
    587   status = ExportKeyPkcs8Nss(scoped_sec_private_key.get(), &pkcs8_data);
    588   if (status.IsError())
    589     return status;
    590 
    591   scoped_ptr<PrivateKeyNss> private_key_handle(
    592       new PrivateKeyNss(scoped_sec_private_key.Pass(), CryptoData(pkcs8_data)));
    593 
    594   *public_key = blink::WebCryptoKey::create(public_key_handle.release(),
    595                                             blink::WebCryptoKeyTypePublic,
    596                                             true,
    597                                             key_algorithm,
    598                                             public_usage_mask);
    599   *private_key = blink::WebCryptoKey::create(private_key_handle.release(),
    600                                              blink::WebCryptoKeyTypePrivate,
    601                                              extractable,
    602                                              key_algorithm,
    603                                              private_usage_mask);
    604 
    605   return Status::Success();
    606 }
    607 
    608 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
    609     blink::WebCryptoKeyFormat format,
    610     blink::WebCryptoKeyUsageMask usage_mask) const {
    611   switch (format) {
    612     case blink::WebCryptoKeyFormatSpki:
    613       return CheckKeyCreationUsages(all_public_key_usages_, usage_mask);
    614     case blink::WebCryptoKeyFormatPkcs8:
    615       return CheckKeyCreationUsages(all_private_key_usages_, usage_mask);
    616     case blink::WebCryptoKeyFormatJwk:
    617       return CheckKeyCreationUsages(
    618           all_public_key_usages_ | all_private_key_usages_, usage_mask);
    619     default:
    620       return Status::ErrorUnsupportedImportKeyFormat();
    621   }
    622 }
    623 
    624 Status RsaHashedAlgorithm::ImportKeyPkcs8(
    625     const CryptoData& key_data,
    626     const blink::WebCryptoAlgorithm& algorithm,
    627     bool extractable,
    628     blink::WebCryptoKeyUsageMask usage_mask,
    629     blink::WebCryptoKey* key) const {
    630   Status status = NssSupportsRsaPrivateKeyImport();
    631   if (status.IsError())
    632     return status;
    633 
    634   if (!key_data.byte_length())
    635     return Status::ErrorImportEmptyKeyData();
    636 
    637   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8
    638   // private key info object.
    639   SECItem pki_der = MakeSECItemForBuffer(key_data);
    640 
    641   SECKEYPrivateKey* seckey_private_key = NULL;
    642   crypto::ScopedPK11Slot slot(PK11_GetInternalSlot());
    643   if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(),
    644                                                &pki_der,
    645                                                NULL,    // nickname
    646                                                NULL,    // publicValue
    647                                                false,   // isPerm
    648                                                false,   // isPrivate
    649                                                KU_ALL,  // usage
    650                                                &seckey_private_key,
    651                                                NULL) != SECSuccess) {
    652     return Status::DataError();
    653   }
    654   DCHECK(seckey_private_key);
    655   crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key);
    656 
    657   const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get());
    658   if (sec_key_type != rsaKey)
    659     return Status::DataError();
    660 
    661   blink::WebCryptoKeyAlgorithm key_algorithm;
    662   if (!CreateRsaHashedPrivateKeyAlgorithm(
    663           algorithm.id(),
    664           algorithm.rsaHashedImportParams()->hash().id(),
    665           private_key.get(),
    666           &key_algorithm)) {
    667     return Status::ErrorUnexpected();
    668   }
    669 
    670   // TODO(eroman): This is probably going to be the same as the input.
    671   std::vector<uint8_t> pkcs8_data;
    672   status = ExportKeyPkcs8Nss(private_key.get(), &pkcs8_data);
    673   if (status.IsError())
    674     return status;
    675 
    676   scoped_ptr<PrivateKeyNss> key_handle(
    677       new PrivateKeyNss(private_key.Pass(), CryptoData(pkcs8_data)));
    678 
    679   *key = blink::WebCryptoKey::create(key_handle.release(),
    680                                      blink::WebCryptoKeyTypePrivate,
    681                                      extractable,
    682                                      key_algorithm,
    683                                      usage_mask);
    684 
    685   return Status::Success();
    686 }
    687 
    688 Status RsaHashedAlgorithm::ImportKeySpki(
    689     const CryptoData& key_data,
    690     const blink::WebCryptoAlgorithm& algorithm,
    691     bool extractable,
    692     blink::WebCryptoKeyUsageMask usage_mask,
    693     blink::WebCryptoKey* key) const {
    694   if (!key_data.byte_length())
    695     return Status::ErrorImportEmptyKeyData();
    696 
    697   // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject
    698   // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo.
    699   SECItem spki_item = MakeSECItemForBuffer(key_data);
    700   const ScopedCERTSubjectPublicKeyInfo spki(
    701       SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
    702   if (!spki)
    703     return Status::DataError();
    704 
    705   crypto::ScopedSECKEYPublicKey sec_public_key(
    706       SECKEY_ExtractPublicKey(spki.get()));
    707   if (!sec_public_key)
    708     return Status::DataError();
    709 
    710   const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get());
    711   if (sec_key_type != rsaKey)
    712     return Status::DataError();
    713 
    714   blink::WebCryptoKeyAlgorithm key_algorithm;
    715   if (!CreateRsaHashedPublicKeyAlgorithm(
    716           algorithm.id(),
    717           algorithm.rsaHashedImportParams()->hash().id(),
    718           sec_public_key.get(),
    719           &key_algorithm)) {
    720     return Status::ErrorUnexpected();
    721   }
    722 
    723   // TODO(eroman): This is probably going to be the same as the input.
    724   std::vector<uint8_t> spki_data;
    725   Status status = ExportKeySpkiNss(sec_public_key.get(), &spki_data);
    726   if (status.IsError())
    727     return status;
    728 
    729   scoped_ptr<PublicKeyNss> key_handle(
    730       new PublicKeyNss(sec_public_key.Pass(), CryptoData(spki_data)));
    731 
    732   *key = blink::WebCryptoKey::create(key_handle.release(),
    733                                      blink::WebCryptoKeyTypePublic,
    734                                      extractable,
    735                                      key_algorithm,
    736                                      usage_mask);
    737 
    738   return Status::Success();
    739 }
    740 
    741 Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
    742                                           std::vector<uint8_t>* buffer) const {
    743   if (key.type() != blink::WebCryptoKeyTypePrivate)
    744     return Status::ErrorUnexpectedKeyType();
    745   *buffer = PrivateKeyNss::Cast(key)->pkcs8_data();
    746   return Status::Success();
    747 }
    748 
    749 Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
    750                                          std::vector<uint8_t>* buffer) const {
    751   if (key.type() != blink::WebCryptoKeyTypePublic)
    752     return Status::ErrorUnexpectedKeyType();
    753   *buffer = PublicKeyNss::Cast(key)->spki_data();
    754   return Status::Success();
    755 }
    756 
    757 Status RsaHashedAlgorithm::ImportKeyJwk(
    758     const CryptoData& key_data,
    759     const blink::WebCryptoAlgorithm& algorithm,
    760     bool extractable,
    761     blink::WebCryptoKeyUsageMask usage_mask,
    762     blink::WebCryptoKey* key) const {
    763   const char* jwk_algorithm =
    764       GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id());
    765 
    766   if (!jwk_algorithm)
    767     return Status::ErrorUnexpected();
    768 
    769   JwkRsaInfo jwk;
    770   Status status =
    771       ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usage_mask, &jwk);
    772   if (status.IsError())
    773     return status;
    774 
    775   // Once the key type is known, verify the usages.
    776   status = CheckKeyCreationUsages(
    777       jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_,
    778       usage_mask);
    779   if (status.IsError())
    780     return Status::ErrorCreateKeyBadUsages();
    781 
    782   return jwk.is_private_key
    783              ? ImportRsaPrivateKey(algorithm, extractable, usage_mask, jwk, key)
    784              : ImportRsaPublicKey(algorithm,
    785                                   extractable,
    786                                   usage_mask,
    787                                   CryptoData(jwk.n),
    788                                   CryptoData(jwk.e),
    789                                   key);
    790 }
    791 
    792 Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
    793                                         std::vector<uint8_t>* buffer) const {
    794   const char* jwk_algorithm =
    795       GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id());
    796 
    797   if (!jwk_algorithm)
    798     return Status::ErrorUnexpected();
    799 
    800   switch (key.type()) {
    801     case blink::WebCryptoKeyTypePublic: {
    802       SECKEYPublicKey* nss_key = PublicKeyNss::Cast(key)->key();
    803       if (nss_key->keyType != rsaKey)
    804         return Status::ErrorUnsupported();
    805 
    806       WriteRsaPublicKeyJwk(SECItemToCryptoData(nss_key->u.rsa.modulus),
    807                            SECItemToCryptoData(nss_key->u.rsa.publicExponent),
    808                            jwk_algorithm,
    809                            key.extractable(),
    810                            key.usages(),
    811                            buffer);
    812 
    813       return Status::Success();
    814     }
    815 
    816     case blink::WebCryptoKeyTypePrivate: {
    817       SECKEYPrivateKey* nss_key = PrivateKeyNss::Cast(key)->key();
    818       RSAPrivateKey key_props = {};
    819       scoped_ptr<RSAPrivateKey, FreeRsaPrivateKey> free_private_key(&key_props);
    820 
    821       if (!InitRSAPrivateKey(nss_key, &key_props))
    822         return Status::OperationError();
    823 
    824       WriteRsaPrivateKeyJwk(SECItemToCryptoData(key_props.modulus),
    825                             SECItemToCryptoData(key_props.public_exponent),
    826                             SECItemToCryptoData(key_props.private_exponent),
    827                             SECItemToCryptoData(key_props.prime1),
    828                             SECItemToCryptoData(key_props.prime2),
    829                             SECItemToCryptoData(key_props.exponent1),
    830                             SECItemToCryptoData(key_props.exponent2),
    831                             SECItemToCryptoData(key_props.coefficient),
    832                             jwk_algorithm,
    833                             key.extractable(),
    834                             key.usages(),
    835                             buffer);
    836 
    837       return Status::Success();
    838     }
    839     default:
    840       return Status::ErrorUnexpected();
    841   }
    842 }
    843 
    844 }  // namespace webcrypto
    845 
    846 }  // namespace content
    847