| 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 |