| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 "components/webcrypto/openssl/ec_algorithm_openssl.h" |  | 
| 6 |  | 
| 7 #include <openssl/ec.h> |  | 
| 8 #include <openssl/ec_key.h> |  | 
| 9 #include <openssl/evp.h> |  | 
| 10 #include <openssl/pkcs12.h> |  | 
| 11 |  | 
| 12 #include "base/logging.h" |  | 
| 13 #include "base/stl_util.h" |  | 
| 14 #include "components/webcrypto/crypto_data.h" |  | 
| 15 #include "components/webcrypto/generate_key_result.h" |  | 
| 16 #include "components/webcrypto/jwk.h" |  | 
| 17 #include "components/webcrypto/openssl/key_openssl.h" |  | 
| 18 #include "components/webcrypto/openssl/util_openssl.h" |  | 
| 19 #include "components/webcrypto/status.h" |  | 
| 20 #include "components/webcrypto/webcrypto_util.h" |  | 
| 21 #include "crypto/openssl_util.h" |  | 
| 22 #include "crypto/scoped_openssl_types.h" |  | 
| 23 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |  | 
| 24 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |  | 
| 25 |  | 
| 26 namespace webcrypto { |  | 
| 27 |  | 
| 28 namespace { |  | 
| 29 |  | 
| 30 // Maps a blink::WebCryptoNamedCurve to the corresponding NID used by |  | 
| 31 // BoringSSL. |  | 
| 32 Status WebCryptoCurveToNid(blink::WebCryptoNamedCurve named_curve, int* nid) { |  | 
| 33   switch (named_curve) { |  | 
| 34     case blink::WebCryptoNamedCurveP256: |  | 
| 35       *nid = NID_X9_62_prime256v1; |  | 
| 36       return Status::Success(); |  | 
| 37     case blink::WebCryptoNamedCurveP384: |  | 
| 38       *nid = NID_secp384r1; |  | 
| 39       return Status::Success(); |  | 
| 40     case blink::WebCryptoNamedCurveP521: |  | 
| 41       *nid = NID_secp521r1; |  | 
| 42       return Status::Success(); |  | 
| 43   } |  | 
| 44   return Status::ErrorUnsupported(); |  | 
| 45 } |  | 
| 46 |  | 
| 47 // Maps a BoringSSL NID to the corresponding WebCrypto named curve. |  | 
| 48 Status NidToWebCryptoCurve(int nid, blink::WebCryptoNamedCurve* named_curve) { |  | 
| 49   switch (nid) { |  | 
| 50     case NID_X9_62_prime256v1: |  | 
| 51       *named_curve = blink::WebCryptoNamedCurveP256; |  | 
| 52       return Status::Success(); |  | 
| 53     case NID_secp384r1: |  | 
| 54       *named_curve = blink::WebCryptoNamedCurveP384; |  | 
| 55       return Status::Success(); |  | 
| 56     case NID_secp521r1: |  | 
| 57       *named_curve = blink::WebCryptoNamedCurveP521; |  | 
| 58       return Status::Success(); |  | 
| 59   } |  | 
| 60   return Status::ErrorImportedEcKeyIncorrectCurve(); |  | 
| 61 } |  | 
| 62 |  | 
| 63 struct JwkCrvMapping { |  | 
| 64   const char* jwk_curve; |  | 
| 65   blink::WebCryptoNamedCurve named_curve; |  | 
| 66 }; |  | 
| 67 |  | 
| 68 const JwkCrvMapping kJwkCrvMappings[] = { |  | 
| 69     {"P-256", blink::WebCryptoNamedCurveP256}, |  | 
| 70     {"P-384", blink::WebCryptoNamedCurveP384}, |  | 
| 71     {"P-521", blink::WebCryptoNamedCurveP521}, |  | 
| 72 }; |  | 
| 73 |  | 
| 74 // Gets the "crv" parameter from a JWK and converts it to a WebCryptoNamedCurve. |  | 
| 75 Status ReadJwkCrv(const JwkReader& jwk, |  | 
| 76                   blink::WebCryptoNamedCurve* named_curve) { |  | 
| 77   std::string jwk_curve; |  | 
| 78   Status status = jwk.GetString("crv", &jwk_curve); |  | 
| 79   if (status.IsError()) |  | 
| 80     return status; |  | 
| 81 |  | 
| 82   for (size_t i = 0; i < arraysize(kJwkCrvMappings); ++i) { |  | 
| 83     if (kJwkCrvMappings[i].jwk_curve == jwk_curve) { |  | 
| 84       *named_curve = kJwkCrvMappings[i].named_curve; |  | 
| 85       return Status::Success(); |  | 
| 86     } |  | 
| 87   } |  | 
| 88 |  | 
| 89   return Status::ErrorJwkIncorrectCrv(); |  | 
| 90 } |  | 
| 91 |  | 
| 92 // Converts a WebCryptoNamedCurve to an equivalent JWK "crv". |  | 
| 93 Status WebCryptoCurveToJwkCrv(blink::WebCryptoNamedCurve named_curve, |  | 
| 94                               std::string* jwk_crv) { |  | 
| 95   for (size_t i = 0; i < arraysize(kJwkCrvMappings); ++i) { |  | 
| 96     if (kJwkCrvMappings[i].named_curve == named_curve) { |  | 
| 97       *jwk_crv = kJwkCrvMappings[i].jwk_curve; |  | 
| 98       return Status::Success(); |  | 
| 99     } |  | 
| 100   } |  | 
| 101   return Status::ErrorUnexpected(); |  | 
| 102 } |  | 
| 103 |  | 
| 104 // Verifies that an EC key imported from PKCS8 or SPKI format is correct. |  | 
| 105 // This involves verifying the key validity, and the NID for the named curve. |  | 
| 106 // Also removes the EC_PKEY_NO_PUBKEY flag if present. |  | 
| 107 Status VerifyEcKeyAfterSpkiOrPkcs8Import( |  | 
| 108     EVP_PKEY* pkey, |  | 
| 109     blink::WebCryptoNamedCurve expected_named_curve) { |  | 
| 110   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |  | 
| 111 |  | 
| 112   crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey)); |  | 
| 113   if (!ec.get()) |  | 
| 114     return Status::ErrorUnexpected(); |  | 
| 115 |  | 
| 116   // When importing an ECPrivateKey, the public key is optional. If it was |  | 
| 117   // omitted then the public key will be calculated by BoringSSL and added into |  | 
| 118   // the EC_KEY. However an encoding flag is set such that when exporting to |  | 
| 119   // PKCS8 format the public key is once again omitted. Remove this flag. |  | 
| 120   unsigned int enc_flags = EC_KEY_get_enc_flags(ec.get()); |  | 
| 121   enc_flags &= ~EC_PKEY_NO_PUBKEY; |  | 
| 122   EC_KEY_set_enc_flags(ec.get(), enc_flags); |  | 
| 123 |  | 
| 124   if (!EC_KEY_check_key(ec.get())) |  | 
| 125     return Status::ErrorEcKeyInvalid(); |  | 
| 126 |  | 
| 127   // Make sure the curve matches the expected curve name. |  | 
| 128   int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get())); |  | 
| 129   blink::WebCryptoNamedCurve named_curve = blink::WebCryptoNamedCurveP256; |  | 
| 130   Status status = NidToWebCryptoCurve(curve_nid, &named_curve); |  | 
| 131   if (status.IsError()) |  | 
| 132     return status; |  | 
| 133 |  | 
| 134   if (named_curve != expected_named_curve) |  | 
| 135     return Status::ErrorImportedEcKeyIncorrectCurve(); |  | 
| 136 |  | 
| 137   return Status::Success(); |  | 
| 138 } |  | 
| 139 |  | 
| 140 // Creates an EC_KEY for the given WebCryptoNamedCurve. |  | 
| 141 Status CreateEC_KEY(blink::WebCryptoNamedCurve named_curve, |  | 
| 142                     crypto::ScopedEC_KEY* ec) { |  | 
| 143   int curve_nid = 0; |  | 
| 144   Status status = WebCryptoCurveToNid(named_curve, &curve_nid); |  | 
| 145   if (status.IsError()) |  | 
| 146     return status; |  | 
| 147 |  | 
| 148   ec->reset(EC_KEY_new_by_curve_name(curve_nid)); |  | 
| 149   if (!ec->get()) |  | 
| 150     return Status::OperationError(); |  | 
| 151 |  | 
| 152   return Status::Success(); |  | 
| 153 } |  | 
| 154 |  | 
| 155 // Writes an unsigned BIGNUM into |jwk|, zero-padding it to a length of |  | 
| 156 // |padded_length|. |  | 
| 157 Status WritePaddedBIGNUM(const std::string& member_name, |  | 
| 158                          const BIGNUM* value, |  | 
| 159                          size_t padded_length, |  | 
| 160                          JwkWriter* jwk) { |  | 
| 161   std::vector<uint8_t> padded_bytes(padded_length); |  | 
| 162   if (!BN_bn2bin_padded(vector_as_array(&padded_bytes), padded_bytes.size(), |  | 
| 163                         value)) { |  | 
| 164     return Status::OperationError(); |  | 
| 165   } |  | 
| 166   jwk->SetBytes(member_name, CryptoData(padded_bytes)); |  | 
| 167   return Status::Success(); |  | 
| 168 } |  | 
| 169 |  | 
| 170 // Reads a fixed length BIGNUM from a JWK. |  | 
| 171 Status ReadPaddedBIGNUM(const JwkReader& jwk, |  | 
| 172                         const std::string& member_name, |  | 
| 173                         size_t expected_length, |  | 
| 174                         crypto::ScopedBIGNUM* out) { |  | 
| 175   std::string bytes; |  | 
| 176   Status status = jwk.GetBytes(member_name, &bytes); |  | 
| 177   if (status.IsError()) |  | 
| 178     return status; |  | 
| 179 |  | 
| 180   if (bytes.size() != expected_length) { |  | 
| 181     return Status::JwkOctetStringWrongLength(member_name, expected_length, |  | 
| 182                                              bytes.size()); |  | 
| 183   } |  | 
| 184 |  | 
| 185   out->reset(CreateBIGNUM(bytes)); |  | 
| 186   return Status::Success(); |  | 
| 187 } |  | 
| 188 |  | 
| 189 int GetGroupDegreeInBytes(EC_KEY* ec) { |  | 
| 190   const EC_GROUP* group = EC_KEY_get0_group(ec); |  | 
| 191   return NumBitsToBytes(EC_GROUP_get_degree(group)); |  | 
| 192 } |  | 
| 193 |  | 
| 194 // Extracts the public key as affine coordinates (x,y). |  | 
| 195 Status GetPublicKey(EC_KEY* ec, |  | 
| 196                     crypto::ScopedBIGNUM* x, |  | 
| 197                     crypto::ScopedBIGNUM* y) { |  | 
| 198   const EC_GROUP* group = EC_KEY_get0_group(ec); |  | 
| 199   const EC_POINT* point = EC_KEY_get0_public_key(ec); |  | 
| 200 |  | 
| 201   x->reset(BN_new()); |  | 
| 202   y->reset(BN_new()); |  | 
| 203 |  | 
| 204   if (!EC_POINT_get_affine_coordinates_GFp(group, point, x->get(), y->get(), |  | 
| 205                                            NULL)) { |  | 
| 206     return Status::OperationError(); |  | 
| 207   } |  | 
| 208 |  | 
| 209   return Status::Success(); |  | 
| 210 } |  | 
| 211 |  | 
| 212 }  // namespace |  | 
| 213 |  | 
| 214 Status EcAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm, |  | 
| 215                                 bool extractable, |  | 
| 216                                 blink::WebCryptoKeyUsageMask combined_usages, |  | 
| 217                                 GenerateKeyResult* result) const { |  | 
| 218   blink::WebCryptoKeyUsageMask public_usages = 0; |  | 
| 219   blink::WebCryptoKeyUsageMask private_usages = 0; |  | 
| 220 |  | 
| 221   Status status = GetUsagesForGenerateAsymmetricKey( |  | 
| 222       combined_usages, all_public_key_usages_, all_private_key_usages_, |  | 
| 223       &public_usages, &private_usages); |  | 
| 224   if (status.IsError()) |  | 
| 225     return status; |  | 
| 226 |  | 
| 227   const blink::WebCryptoEcKeyGenParams* params = algorithm.ecKeyGenParams(); |  | 
| 228 |  | 
| 229   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |  | 
| 230 |  | 
| 231   // Generate an EC key pair. |  | 
| 232   crypto::ScopedEC_KEY ec_private_key; |  | 
| 233   status = CreateEC_KEY(params->namedCurve(), &ec_private_key); |  | 
| 234   if (status.IsError()) |  | 
| 235     return status; |  | 
| 236 |  | 
| 237   if (!EC_KEY_generate_key(ec_private_key.get())) |  | 
| 238     return Status::OperationError(); |  | 
| 239 |  | 
| 240   // Construct an EVP_PKEY for the private key. |  | 
| 241   crypto::ScopedEVP_PKEY private_pkey(EVP_PKEY_new()); |  | 
| 242   if (!private_pkey || |  | 
| 243       !EVP_PKEY_set1_EC_KEY(private_pkey.get(), ec_private_key.get())) { |  | 
| 244     return Status::OperationError(); |  | 
| 245   } |  | 
| 246 |  | 
| 247   // Construct an EVP_PKEY for just the public key. |  | 
| 248   crypto::ScopedEC_KEY ec_public_key; |  | 
| 249   crypto::ScopedEVP_PKEY public_pkey(EVP_PKEY_new()); |  | 
| 250   status = CreateEC_KEY(params->namedCurve(), &ec_public_key); |  | 
| 251   if (status.IsError()) |  | 
| 252     return status; |  | 
| 253   if (!EC_KEY_set_public_key(ec_public_key.get(), |  | 
| 254                              EC_KEY_get0_public_key(ec_private_key.get()))) { |  | 
| 255     return Status::OperationError(); |  | 
| 256   } |  | 
| 257   if (!public_pkey || |  | 
| 258       !EVP_PKEY_set1_EC_KEY(public_pkey.get(), ec_public_key.get())) { |  | 
| 259     return Status::OperationError(); |  | 
| 260   } |  | 
| 261 |  | 
| 262   blink::WebCryptoKey public_key; |  | 
| 263   blink::WebCryptoKey private_key; |  | 
| 264 |  | 
| 265   blink::WebCryptoKeyAlgorithm key_algorithm = |  | 
| 266       blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(), |  | 
| 267                                              params->namedCurve()); |  | 
| 268 |  | 
| 269   // Note that extractable is unconditionally set to true. This is because per |  | 
| 270   // the WebCrypto spec generated public keys are always extractable. |  | 
| 271   status = CreateWebCryptoPublicKey(public_pkey.Pass(), key_algorithm, true, |  | 
| 272                                     public_usages, &public_key); |  | 
| 273   if (status.IsError()) |  | 
| 274     return status; |  | 
| 275 |  | 
| 276   status = CreateWebCryptoPrivateKey(private_pkey.Pass(), key_algorithm, |  | 
| 277                                      extractable, private_usages, &private_key); |  | 
| 278   if (status.IsError()) |  | 
| 279     return status; |  | 
| 280 |  | 
| 281   result->AssignKeyPair(public_key, private_key); |  | 
| 282   return Status::Success(); |  | 
| 283 } |  | 
| 284 |  | 
| 285 Status EcAlgorithm::VerifyKeyUsagesBeforeImportKey( |  | 
| 286     blink::WebCryptoKeyFormat format, |  | 
| 287     blink::WebCryptoKeyUsageMask usages) const { |  | 
| 288   return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_, |  | 
| 289                                                all_private_key_usages_, usages); |  | 
| 290 } |  | 
| 291 |  | 
| 292 Status EcAlgorithm::ImportKeyPkcs8(const CryptoData& key_data, |  | 
| 293                                    const blink::WebCryptoAlgorithm& algorithm, |  | 
| 294                                    bool extractable, |  | 
| 295                                    blink::WebCryptoKeyUsageMask usages, |  | 
| 296                                    blink::WebCryptoKey* key) const { |  | 
| 297   crypto::ScopedEVP_PKEY private_key; |  | 
| 298   Status status = |  | 
| 299       ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_EC, &private_key); |  | 
| 300   if (status.IsError()) |  | 
| 301     return status; |  | 
| 302 |  | 
| 303   const blink::WebCryptoEcKeyImportParams* params = |  | 
| 304       algorithm.ecKeyImportParams(); |  | 
| 305 |  | 
| 306   status = VerifyEcKeyAfterSpkiOrPkcs8Import(private_key.get(), |  | 
| 307                                              params->namedCurve()); |  | 
| 308   if (status.IsError()) |  | 
| 309     return status; |  | 
| 310 |  | 
| 311   return CreateWebCryptoPrivateKey(private_key.Pass(), |  | 
| 312                                    blink::WebCryptoKeyAlgorithm::createEc( |  | 
| 313                                        algorithm.id(), params->namedCurve()), |  | 
| 314                                    extractable, usages, key); |  | 
| 315 } |  | 
| 316 |  | 
| 317 Status EcAlgorithm::ImportKeySpki(const CryptoData& key_data, |  | 
| 318                                   const blink::WebCryptoAlgorithm& algorithm, |  | 
| 319                                   bool extractable, |  | 
| 320                                   blink::WebCryptoKeyUsageMask usages, |  | 
| 321                                   blink::WebCryptoKey* key) const { |  | 
| 322   crypto::ScopedEVP_PKEY public_key; |  | 
| 323   Status status = |  | 
| 324       ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_EC, &public_key); |  | 
| 325   if (status.IsError()) |  | 
| 326     return status; |  | 
| 327 |  | 
| 328   const blink::WebCryptoEcKeyImportParams* params = |  | 
| 329       algorithm.ecKeyImportParams(); |  | 
| 330 |  | 
| 331   status = |  | 
| 332       VerifyEcKeyAfterSpkiOrPkcs8Import(public_key.get(), params->namedCurve()); |  | 
| 333   if (status.IsError()) |  | 
| 334     return status; |  | 
| 335 |  | 
| 336   return CreateWebCryptoPublicKey(public_key.Pass(), |  | 
| 337                                   blink::WebCryptoKeyAlgorithm::createEc( |  | 
| 338                                       algorithm.id(), params->namedCurve()), |  | 
| 339                                   extractable, usages, key); |  | 
| 340 } |  | 
| 341 |  | 
| 342 // The format for JWK EC keys is given by: |  | 
| 343 // https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.
     2 |  | 
| 344 Status EcAlgorithm::ImportKeyJwk(const CryptoData& key_data, |  | 
| 345                                  const blink::WebCryptoAlgorithm& algorithm, |  | 
| 346                                  bool extractable, |  | 
| 347                                  blink::WebCryptoKeyUsageMask usages, |  | 
| 348                                  blink::WebCryptoKey* key) const { |  | 
| 349   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |  | 
| 350 |  | 
| 351   const blink::WebCryptoEcKeyImportParams* params = |  | 
| 352       algorithm.ecKeyImportParams(); |  | 
| 353 |  | 
| 354   // When importing EC keys from JWK there may be up to *three* separate curve |  | 
| 355   // names: |  | 
| 356   // |  | 
| 357   //   (1) The one given to WebCrypto's importKey (params->namedCurve()). |  | 
| 358   //   (2) JWK's "crv" member |  | 
| 359   //   (3) A curve implied by JWK's "alg" member. |  | 
| 360   // |  | 
| 361   // (In the case of ECDSA, the "alg" member implicitly names a curve and hash) |  | 
| 362 |  | 
| 363   JwkReader jwk; |  | 
| 364   Status status = jwk.Init(key_data, extractable, usages, "EC", |  | 
| 365                            GetJwkAlgorithm(params->namedCurve())); |  | 
| 366   if (status.IsError()) |  | 
| 367     return status; |  | 
| 368 |  | 
| 369   // Verify that "crv" matches expected curve. |  | 
| 370   blink::WebCryptoNamedCurve jwk_crv = blink::WebCryptoNamedCurveP256; |  | 
| 371   status = ReadJwkCrv(jwk, &jwk_crv); |  | 
| 372   if (status.IsError()) |  | 
| 373     return status; |  | 
| 374   if (jwk_crv != params->namedCurve()) |  | 
| 375     return Status::ErrorJwkIncorrectCrv(); |  | 
| 376 |  | 
| 377   // Only private keys have a "d" parameter. The key may still be invalid, but |  | 
| 378   // tentatively decide if it is a public or private key. |  | 
| 379   bool is_private_key = jwk.HasMember("d"); |  | 
| 380 |  | 
| 381   // Now that the key type is known, verify the usages. |  | 
| 382   status = CheckKeyCreationUsages( |  | 
| 383       is_private_key ? all_private_key_usages_ : all_public_key_usages_, usages, |  | 
| 384       !is_private_key); |  | 
| 385   if (status.IsError()) |  | 
| 386     return status; |  | 
| 387 |  | 
| 388   // Create an EC_KEY. |  | 
| 389   crypto::ScopedEC_KEY ec; |  | 
| 390   status = CreateEC_KEY(params->namedCurve(), &ec); |  | 
| 391   if (status.IsError()) |  | 
| 392     return status; |  | 
| 393 |  | 
| 394   // JWK requires the length of x, y, d to match the group degree. |  | 
| 395   int degree_bytes = GetGroupDegreeInBytes(ec.get()); |  | 
| 396 |  | 
| 397   // Read the public key's uncompressed affine coordinates. |  | 
| 398   crypto::ScopedBIGNUM x; |  | 
| 399   status = ReadPaddedBIGNUM(jwk, "x", degree_bytes, &x); |  | 
| 400   if (status.IsError()) |  | 
| 401     return status; |  | 
| 402 |  | 
| 403   crypto::ScopedBIGNUM y; |  | 
| 404   status = ReadPaddedBIGNUM(jwk, "y", degree_bytes, &y); |  | 
| 405   if (status.IsError()) |  | 
| 406     return status; |  | 
| 407 |  | 
| 408   // TODO(eroman): Distinguish more accurately between a DataError and |  | 
| 409   // OperationError. In general if this fails it was due to the key being an |  | 
| 410   // invalid EC key. |  | 
| 411   if (!EC_KEY_set_public_key_affine_coordinates(ec.get(), x.get(), y.get())) |  | 
| 412     return Status::DataError(); |  | 
| 413 |  | 
| 414   // Extract the "d" parameters. |  | 
| 415   if (is_private_key) { |  | 
| 416     crypto::ScopedBIGNUM d; |  | 
| 417     status = ReadPaddedBIGNUM(jwk, "d", degree_bytes, &d); |  | 
| 418     if (status.IsError()) |  | 
| 419       return status; |  | 
| 420 |  | 
| 421     if (!EC_KEY_set_private_key(ec.get(), d.get())) |  | 
| 422       return Status::OperationError(); |  | 
| 423   } |  | 
| 424 |  | 
| 425   // Verify the key. |  | 
| 426   if (!EC_KEY_check_key(ec.get())) |  | 
| 427     return Status::ErrorEcKeyInvalid(); |  | 
| 428 |  | 
| 429   // Wrap the EC_KEY into an EVP_PKEY. |  | 
| 430   crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); |  | 
| 431   if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get())) |  | 
| 432     return Status::OperationError(); |  | 
| 433 |  | 
| 434   blink::WebCryptoKeyAlgorithm key_algorithm = |  | 
| 435       blink::WebCryptoKeyAlgorithm::createEc(algorithm.id(), |  | 
| 436                                              params->namedCurve()); |  | 
| 437 |  | 
| 438   // Wrap the EVP_PKEY into a WebCryptoKey |  | 
| 439   if (is_private_key) { |  | 
| 440     return CreateWebCryptoPrivateKey(pkey.Pass(), key_algorithm, extractable, |  | 
| 441                                      usages, key); |  | 
| 442   } |  | 
| 443   return CreateWebCryptoPublicKey(pkey.Pass(), key_algorithm, extractable, |  | 
| 444                                   usages, key); |  | 
| 445 } |  | 
| 446 |  | 
| 447 Status EcAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key, |  | 
| 448                                    std::vector<uint8_t>* buffer) const { |  | 
| 449   if (key.type() != blink::WebCryptoKeyTypePrivate) |  | 
| 450     return Status::ErrorUnexpectedKeyType(); |  | 
| 451   *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); |  | 
| 452   return Status::Success(); |  | 
| 453 } |  | 
| 454 |  | 
| 455 Status EcAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key, |  | 
| 456                                   std::vector<uint8_t>* buffer) const { |  | 
| 457   if (key.type() != blink::WebCryptoKeyTypePublic) |  | 
| 458     return Status::ErrorUnexpectedKeyType(); |  | 
| 459   *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); |  | 
| 460   return Status::Success(); |  | 
| 461 } |  | 
| 462 |  | 
| 463 // The format for JWK EC keys is given by: |  | 
| 464 // https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-36#section-6.
     2 |  | 
| 465 Status EcAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key, |  | 
| 466                                  std::vector<uint8_t>* buffer) const { |  | 
| 467   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |  | 
| 468 |  | 
| 469   EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key(); |  | 
| 470 |  | 
| 471   crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey)); |  | 
| 472   if (!ec.get()) |  | 
| 473     return Status::ErrorUnexpected(); |  | 
| 474 |  | 
| 475   // No "alg" is set for EC keys. |  | 
| 476   JwkWriter jwk(std::string(), key.extractable(), key.usages(), "EC"); |  | 
| 477 |  | 
| 478   // Set the crv |  | 
| 479   std::string crv; |  | 
| 480   Status status = |  | 
| 481       WebCryptoCurveToJwkCrv(key.algorithm().ecParams()->namedCurve(), &crv); |  | 
| 482   if (status.IsError()) |  | 
| 483     return status; |  | 
| 484 |  | 
| 485   int degree_bytes = GetGroupDegreeInBytes(ec.get()); |  | 
| 486 |  | 
| 487   jwk.SetString("crv", crv); |  | 
| 488 |  | 
| 489   crypto::ScopedBIGNUM x; |  | 
| 490   crypto::ScopedBIGNUM y; |  | 
| 491   status = GetPublicKey(ec.get(), &x, &y); |  | 
| 492   if (status.IsError()) |  | 
| 493     return status; |  | 
| 494 |  | 
| 495   status = WritePaddedBIGNUM("x", x.get(), degree_bytes, &jwk); |  | 
| 496   if (status.IsError()) |  | 
| 497     return status; |  | 
| 498 |  | 
| 499   status = WritePaddedBIGNUM("y", y.get(), degree_bytes, &jwk); |  | 
| 500   if (status.IsError()) |  | 
| 501     return status; |  | 
| 502 |  | 
| 503   if (key.type() == blink::WebCryptoKeyTypePrivate) { |  | 
| 504     const BIGNUM* d = EC_KEY_get0_private_key(ec.get()); |  | 
| 505     status = WritePaddedBIGNUM("d", d, degree_bytes, &jwk); |  | 
| 506     if (status.IsError()) |  | 
| 507       return status; |  | 
| 508   } |  | 
| 509 |  | 
| 510   jwk.ToJson(buffer); |  | 
| 511   return Status::Success(); |  | 
| 512 } |  | 
| 513 |  | 
| 514 Status EcAlgorithm::SerializeKeyForClone( |  | 
| 515     const blink::WebCryptoKey& key, |  | 
| 516     blink::WebVector<uint8_t>* key_data) const { |  | 
| 517   key_data->assign(AsymKeyOpenSsl::Cast(key)->serialized_key_data()); |  | 
| 518   return Status::Success(); |  | 
| 519 } |  | 
| 520 |  | 
| 521 // TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763 |  | 
| 522 Status EcAlgorithm::DeserializeKeyForClone( |  | 
| 523     const blink::WebCryptoKeyAlgorithm& algorithm, |  | 
| 524     blink::WebCryptoKeyType type, |  | 
| 525     bool extractable, |  | 
| 526     blink::WebCryptoKeyUsageMask usages, |  | 
| 527     const CryptoData& key_data, |  | 
| 528     blink::WebCryptoKey* key) const { |  | 
| 529   blink::WebCryptoAlgorithm import_algorithm = CreateEcImportAlgorithm( |  | 
| 530       algorithm.id(), algorithm.ecParams()->namedCurve()); |  | 
| 531 |  | 
| 532   Status status; |  | 
| 533 |  | 
| 534   switch (type) { |  | 
| 535     case blink::WebCryptoKeyTypePublic: |  | 
| 536       status = |  | 
| 537           ImportKeySpki(key_data, import_algorithm, extractable, usages, key); |  | 
| 538       break; |  | 
| 539     case blink::WebCryptoKeyTypePrivate: |  | 
| 540       status = |  | 
| 541           ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key); |  | 
| 542       break; |  | 
| 543     default: |  | 
| 544       return Status::ErrorUnexpected(); |  | 
| 545   } |  | 
| 546 |  | 
| 547   // There is some duplicated information in the serialized format used by |  | 
| 548   // structured clone (since the KeyAlgorithm is serialized separately from the |  | 
| 549   // key data). Use this extra information to further validate what was |  | 
| 550   // deserialized from the key data. |  | 
| 551 |  | 
| 552   if (algorithm.id() != key->algorithm().id()) |  | 
| 553     return Status::ErrorUnexpected(); |  | 
| 554 |  | 
| 555   if (type != key->type()) |  | 
| 556     return Status::ErrorUnexpected(); |  | 
| 557 |  | 
| 558   if (algorithm.ecParams()->namedCurve() != |  | 
| 559       key->algorithm().ecParams()->namedCurve()) { |  | 
| 560     return Status::ErrorUnexpected(); |  | 
| 561   } |  | 
| 562 |  | 
| 563   return Status::Success(); |  | 
| 564 } |  | 
| 565 |  | 
| 566 }  // namespace webcrypto |  | 
| OLD | NEW | 
|---|