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