| 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/rsa_hashed_algorithm_openssl.h" | |
| 6 | |
| 7 #include <openssl/evp.h> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/stl_util.h" | |
| 11 #include "components/webcrypto/crypto_data.h" | |
| 12 #include "components/webcrypto/generate_key_result.h" | |
| 13 #include "components/webcrypto/jwk.h" | |
| 14 #include "components/webcrypto/openssl/key_openssl.h" | |
| 15 #include "components/webcrypto/openssl/util_openssl.h" | |
| 16 #include "components/webcrypto/status.h" | |
| 17 #include "components/webcrypto/webcrypto_util.h" | |
| 18 #include "crypto/openssl_util.h" | |
| 19 #include "crypto/scoped_openssl_types.h" | |
| 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 21 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
| 22 | |
| 23 namespace webcrypto { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 // Describes the RSA components for a parsed key. The names of the properties | |
| 28 // correspond with those from the JWK spec. Note that Chromium's WebCrypto | |
| 29 // implementation does not support multi-primes, so there is no parsed field | |
| 30 // for othinfo. | |
| 31 struct JwkRsaInfo { | |
| 32 bool is_private_key = false; | |
| 33 std::string n; | |
| 34 std::string e; | |
| 35 std::string d; | |
| 36 std::string p; | |
| 37 std::string q; | |
| 38 std::string dp; | |
| 39 std::string dq; | |
| 40 std::string qi; | |
| 41 }; | |
| 42 | |
| 43 // Parses a UTF-8 encoded JWK (key_data), and extracts the RSA components to | |
| 44 // |*result|. Returns Status::Success() on success, otherwise an error. | |
| 45 // In order for this to succeed: | |
| 46 // * expected_alg must match the JWK's "alg", if present. | |
| 47 // * expected_extractable must be consistent with the JWK's "ext", if | |
| 48 // present. | |
| 49 // * expected_usages must be a subset of the JWK's "key_ops" if present. | |
| 50 Status ReadRsaKeyJwk(const CryptoData& key_data, | |
| 51 const std::string& expected_alg, | |
| 52 bool expected_extractable, | |
| 53 blink::WebCryptoKeyUsageMask expected_usages, | |
| 54 JwkRsaInfo* result) { | |
| 55 JwkReader jwk; | |
| 56 Status status = jwk.Init(key_data, expected_extractable, expected_usages, | |
| 57 "RSA", expected_alg); | |
| 58 if (status.IsError()) | |
| 59 return status; | |
| 60 | |
| 61 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | |
| 62 // in the JWK, while an RSA private key must have those, plus at least a "d" | |
| 63 // (private exponent) entry. | |
| 64 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | |
| 65 // section 6.3. | |
| 66 status = jwk.GetBigInteger("n", &result->n); | |
| 67 if (status.IsError()) | |
| 68 return status; | |
| 69 status = jwk.GetBigInteger("e", &result->e); | |
| 70 if (status.IsError()) | |
| 71 return status; | |
| 72 | |
| 73 result->is_private_key = jwk.HasMember("d"); | |
| 74 if (!result->is_private_key) | |
| 75 return Status::Success(); | |
| 76 | |
| 77 status = jwk.GetBigInteger("d", &result->d); | |
| 78 if (status.IsError()) | |
| 79 return status; | |
| 80 | |
| 81 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA | |
| 82 // spec. However they are required by Chromium's WebCrypto implementation. | |
| 83 | |
| 84 status = jwk.GetBigInteger("p", &result->p); | |
| 85 if (status.IsError()) | |
| 86 return status; | |
| 87 | |
| 88 status = jwk.GetBigInteger("q", &result->q); | |
| 89 if (status.IsError()) | |
| 90 return status; | |
| 91 | |
| 92 status = jwk.GetBigInteger("dp", &result->dp); | |
| 93 if (status.IsError()) | |
| 94 return status; | |
| 95 | |
| 96 status = jwk.GetBigInteger("dq", &result->dq); | |
| 97 if (status.IsError()) | |
| 98 return status; | |
| 99 | |
| 100 status = jwk.GetBigInteger("qi", &result->qi); | |
| 101 if (status.IsError()) | |
| 102 return status; | |
| 103 | |
| 104 return Status::Success(); | |
| 105 } | |
| 106 | |
| 107 // Creates a blink::WebCryptoAlgorithm having the modulus length and public | |
| 108 // exponent of |key|. | |
| 109 Status CreateRsaHashedKeyAlgorithm( | |
| 110 blink::WebCryptoAlgorithmId rsa_algorithm, | |
| 111 blink::WebCryptoAlgorithmId hash_algorithm, | |
| 112 EVP_PKEY* key, | |
| 113 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
| 114 DCHECK_EQ(EVP_PKEY_RSA, EVP_PKEY_id(key)); | |
| 115 | |
| 116 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(key)); | |
| 117 if (!rsa.get()) | |
| 118 return Status::ErrorUnexpected(); | |
| 119 | |
| 120 unsigned int modulus_length_bits = BN_num_bits(rsa.get()->n); | |
| 121 | |
| 122 // Convert the public exponent to big-endian representation. | |
| 123 std::vector<uint8_t> e(BN_num_bytes(rsa.get()->e)); | |
| 124 if (e.size() == 0) | |
| 125 return Status::ErrorUnexpected(); | |
| 126 if (e.size() != BN_bn2bin(rsa.get()->e, &e[0])) | |
| 127 return Status::ErrorUnexpected(); | |
| 128 | |
| 129 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed( | |
| 130 rsa_algorithm, modulus_length_bits, &e[0], | |
| 131 static_cast<unsigned int>(e.size()), hash_algorithm); | |
| 132 | |
| 133 return Status::Success(); | |
| 134 } | |
| 135 | |
| 136 // Creates a WebCryptoKey that wraps |private_key|. | |
| 137 Status CreateWebCryptoRsaPrivateKey( | |
| 138 crypto::ScopedEVP_PKEY private_key, | |
| 139 const blink::WebCryptoAlgorithmId rsa_algorithm_id, | |
| 140 const blink::WebCryptoAlgorithm& hash, | |
| 141 bool extractable, | |
| 142 blink::WebCryptoKeyUsageMask usages, | |
| 143 blink::WebCryptoKey* key) { | |
| 144 blink::WebCryptoKeyAlgorithm key_algorithm; | |
| 145 Status status = CreateRsaHashedKeyAlgorithm( | |
| 146 rsa_algorithm_id, hash.id(), private_key.get(), &key_algorithm); | |
| 147 if (status.IsError()) | |
| 148 return status; | |
| 149 | |
| 150 return CreateWebCryptoPrivateKey(private_key.Pass(), key_algorithm, | |
| 151 extractable, usages, key); | |
| 152 } | |
| 153 | |
| 154 // Creates a WebCryptoKey that wraps |public_key|. | |
| 155 Status CreateWebCryptoRsaPublicKey( | |
| 156 crypto::ScopedEVP_PKEY public_key, | |
| 157 const blink::WebCryptoAlgorithmId rsa_algorithm_id, | |
| 158 const blink::WebCryptoAlgorithm& hash, | |
| 159 bool extractable, | |
| 160 blink::WebCryptoKeyUsageMask usages, | |
| 161 blink::WebCryptoKey* key) { | |
| 162 blink::WebCryptoKeyAlgorithm key_algorithm; | |
| 163 Status status = CreateRsaHashedKeyAlgorithm(rsa_algorithm_id, hash.id(), | |
| 164 public_key.get(), &key_algorithm); | |
| 165 if (status.IsError()) | |
| 166 return status; | |
| 167 | |
| 168 return CreateWebCryptoPublicKey(public_key.Pass(), key_algorithm, extractable, | |
| 169 usages, key); | |
| 170 } | |
| 171 | |
| 172 Status ImportRsaPrivateKey(const blink::WebCryptoAlgorithm& algorithm, | |
| 173 bool extractable, | |
| 174 blink::WebCryptoKeyUsageMask usages, | |
| 175 const JwkRsaInfo& params, | |
| 176 blink::WebCryptoKey* key) { | |
| 177 crypto::ScopedRSA rsa(RSA_new()); | |
| 178 | |
| 179 rsa->n = CreateBIGNUM(params.n); | |
| 180 rsa->e = CreateBIGNUM(params.e); | |
| 181 rsa->d = CreateBIGNUM(params.d); | |
| 182 rsa->p = CreateBIGNUM(params.p); | |
| 183 rsa->q = CreateBIGNUM(params.q); | |
| 184 rsa->dmp1 = CreateBIGNUM(params.dp); | |
| 185 rsa->dmq1 = CreateBIGNUM(params.dq); | |
| 186 rsa->iqmp = CreateBIGNUM(params.qi); | |
| 187 | |
| 188 if (!rsa->n || !rsa->e || !rsa->d || !rsa->p || !rsa->q || !rsa->dmp1 || | |
| 189 !rsa->dmq1 || !rsa->iqmp) { | |
| 190 return Status::OperationError(); | |
| 191 } | |
| 192 | |
| 193 // TODO(eroman): This should be a DataError. | |
| 194 if (!RSA_check_key(rsa.get())) | |
| 195 return Status::OperationError(); | |
| 196 | |
| 197 // Create a corresponding EVP_PKEY. | |
| 198 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 199 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | |
| 200 return Status::OperationError(); | |
| 201 | |
| 202 return CreateWebCryptoRsaPrivateKey(pkey.Pass(), algorithm.id(), | |
| 203 algorithm.rsaHashedImportParams()->hash(), | |
| 204 extractable, usages, key); | |
| 205 } | |
| 206 | |
| 207 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, | |
| 208 bool extractable, | |
| 209 blink::WebCryptoKeyUsageMask usages, | |
| 210 const CryptoData& n, | |
| 211 const CryptoData& e, | |
| 212 blink::WebCryptoKey* key) { | |
| 213 crypto::ScopedRSA rsa(RSA_new()); | |
| 214 | |
| 215 rsa->n = BN_bin2bn(n.bytes(), n.byte_length(), NULL); | |
| 216 rsa->e = BN_bin2bn(e.bytes(), e.byte_length(), NULL); | |
| 217 | |
| 218 if (!rsa->n || !rsa->e) | |
| 219 return Status::OperationError(); | |
| 220 | |
| 221 // Create a corresponding EVP_PKEY. | |
| 222 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 223 if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) | |
| 224 return Status::OperationError(); | |
| 225 | |
| 226 return CreateWebCryptoRsaPublicKey(pkey.Pass(), algorithm.id(), | |
| 227 algorithm.rsaHashedImportParams()->hash(), | |
| 228 extractable, usages, key); | |
| 229 } | |
| 230 | |
| 231 } // namespace | |
| 232 | |
| 233 Status RsaHashedAlgorithm::GenerateKey( | |
| 234 const blink::WebCryptoAlgorithm& algorithm, | |
| 235 bool extractable, | |
| 236 blink::WebCryptoKeyUsageMask combined_usages, | |
| 237 GenerateKeyResult* result) const { | |
| 238 blink::WebCryptoKeyUsageMask public_usages = 0; | |
| 239 blink::WebCryptoKeyUsageMask private_usages = 0; | |
| 240 | |
| 241 Status status = GetUsagesForGenerateAsymmetricKey( | |
| 242 combined_usages, all_public_key_usages_, all_private_key_usages_, | |
| 243 &public_usages, &private_usages); | |
| 244 if (status.IsError()) | |
| 245 return status; | |
| 246 | |
| 247 const blink::WebCryptoRsaHashedKeyGenParams* params = | |
| 248 algorithm.rsaHashedKeyGenParams(); | |
| 249 | |
| 250 unsigned int public_exponent = 0; | |
| 251 unsigned int modulus_length_bits = 0; | |
| 252 status = | |
| 253 GetRsaKeyGenParameters(params, &public_exponent, &modulus_length_bits); | |
| 254 if (status.IsError()) | |
| 255 return status; | |
| 256 | |
| 257 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 258 | |
| 259 // Generate an RSA key pair. | |
| 260 crypto::ScopedRSA rsa_private_key(RSA_new()); | |
| 261 crypto::ScopedBIGNUM bn(BN_new()); | |
| 262 if (!rsa_private_key.get() || !bn.get() || | |
| 263 !BN_set_word(bn.get(), public_exponent)) { | |
| 264 return Status::OperationError(); | |
| 265 } | |
| 266 | |
| 267 if (!RSA_generate_key_ex(rsa_private_key.get(), modulus_length_bits, bn.get(), | |
| 268 NULL)) { | |
| 269 return Status::OperationError(); | |
| 270 } | |
| 271 | |
| 272 // Construct an EVP_PKEY for the private key. | |
| 273 crypto::ScopedEVP_PKEY private_pkey(EVP_PKEY_new()); | |
| 274 if (!private_pkey || | |
| 275 !EVP_PKEY_set1_RSA(private_pkey.get(), rsa_private_key.get())) { | |
| 276 return Status::OperationError(); | |
| 277 } | |
| 278 | |
| 279 // Construct an EVP_PKEY for the public key. | |
| 280 crypto::ScopedRSA rsa_public_key(RSAPublicKey_dup(rsa_private_key.get())); | |
| 281 crypto::ScopedEVP_PKEY public_pkey(EVP_PKEY_new()); | |
| 282 if (!public_pkey || | |
| 283 !EVP_PKEY_set1_RSA(public_pkey.get(), rsa_public_key.get())) { | |
| 284 return Status::OperationError(); | |
| 285 } | |
| 286 | |
| 287 blink::WebCryptoKey public_key; | |
| 288 blink::WebCryptoKey private_key; | |
| 289 | |
| 290 // Note that extractable is unconditionally set to true. This is because per | |
| 291 // the WebCrypto spec generated public keys are always extractable. | |
| 292 status = CreateWebCryptoRsaPublicKey(public_pkey.Pass(), algorithm.id(), | |
| 293 params->hash(), true, public_usages, | |
| 294 &public_key); | |
| 295 if (status.IsError()) | |
| 296 return status; | |
| 297 | |
| 298 status = CreateWebCryptoRsaPrivateKey(private_pkey.Pass(), algorithm.id(), | |
| 299 params->hash(), extractable, | |
| 300 private_usages, &private_key); | |
| 301 if (status.IsError()) | |
| 302 return status; | |
| 303 | |
| 304 result->AssignKeyPair(public_key, private_key); | |
| 305 return Status::Success(); | |
| 306 } | |
| 307 | |
| 308 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey( | |
| 309 blink::WebCryptoKeyFormat format, | |
| 310 blink::WebCryptoKeyUsageMask usages) const { | |
| 311 return VerifyUsagesBeforeImportAsymmetricKey(format, all_public_key_usages_, | |
| 312 all_private_key_usages_, usages); | |
| 313 } | |
| 314 | |
| 315 Status RsaHashedAlgorithm::ImportKeyPkcs8( | |
| 316 const CryptoData& key_data, | |
| 317 const blink::WebCryptoAlgorithm& algorithm, | |
| 318 bool extractable, | |
| 319 blink::WebCryptoKeyUsageMask usages, | |
| 320 blink::WebCryptoKey* key) const { | |
| 321 crypto::ScopedEVP_PKEY private_key; | |
| 322 Status status = | |
| 323 ImportUnverifiedPkeyFromPkcs8(key_data, EVP_PKEY_RSA, &private_key); | |
| 324 if (status.IsError()) | |
| 325 return status; | |
| 326 | |
| 327 // Verify the parameters of the key. | |
| 328 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(private_key.get())); | |
| 329 if (!rsa.get()) | |
| 330 return Status::ErrorUnexpected(); | |
| 331 if (!RSA_check_key(rsa.get())) | |
| 332 return Status::DataError(); | |
| 333 | |
| 334 // TODO(eroman): Validate the algorithm OID against the webcrypto provided | |
| 335 // hash. http://crbug.com/389400 | |
| 336 | |
| 337 return CreateWebCryptoRsaPrivateKey(private_key.Pass(), algorithm.id(), | |
| 338 algorithm.rsaHashedImportParams()->hash(), | |
| 339 extractable, usages, key); | |
| 340 } | |
| 341 | |
| 342 Status RsaHashedAlgorithm::ImportKeySpki( | |
| 343 const CryptoData& key_data, | |
| 344 const blink::WebCryptoAlgorithm& algorithm, | |
| 345 bool extractable, | |
| 346 blink::WebCryptoKeyUsageMask usages, | |
| 347 blink::WebCryptoKey* key) const { | |
| 348 crypto::ScopedEVP_PKEY public_key; | |
| 349 Status status = | |
| 350 ImportUnverifiedPkeyFromSpki(key_data, EVP_PKEY_RSA, &public_key); | |
| 351 if (status.IsError()) | |
| 352 return status; | |
| 353 | |
| 354 // TODO(eroman): Validate the algorithm OID against the webcrypto provided | |
| 355 // hash. http://crbug.com/389400 | |
| 356 | |
| 357 return CreateWebCryptoRsaPublicKey(public_key.Pass(), algorithm.id(), | |
| 358 algorithm.rsaHashedImportParams()->hash(), | |
| 359 extractable, usages, key); | |
| 360 } | |
| 361 | |
| 362 Status RsaHashedAlgorithm::ImportKeyJwk( | |
| 363 const CryptoData& key_data, | |
| 364 const blink::WebCryptoAlgorithm& algorithm, | |
| 365 bool extractable, | |
| 366 blink::WebCryptoKeyUsageMask usages, | |
| 367 blink::WebCryptoKey* key) const { | |
| 368 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 369 | |
| 370 const char* jwk_algorithm = | |
| 371 GetJwkAlgorithm(algorithm.rsaHashedImportParams()->hash().id()); | |
| 372 | |
| 373 if (!jwk_algorithm) | |
| 374 return Status::ErrorUnexpected(); | |
| 375 | |
| 376 JwkRsaInfo jwk; | |
| 377 Status status = | |
| 378 ReadRsaKeyJwk(key_data, jwk_algorithm, extractable, usages, &jwk); | |
| 379 if (status.IsError()) | |
| 380 return status; | |
| 381 | |
| 382 // Once the key type is known, verify the usages. | |
| 383 status = CheckKeyCreationUsages( | |
| 384 jwk.is_private_key ? all_private_key_usages_ : all_public_key_usages_, | |
| 385 usages, !jwk.is_private_key); | |
| 386 if (status.IsError()) | |
| 387 return status; | |
| 388 | |
| 389 return jwk.is_private_key | |
| 390 ? ImportRsaPrivateKey(algorithm, extractable, usages, jwk, key) | |
| 391 : ImportRsaPublicKey(algorithm, extractable, usages, | |
| 392 CryptoData(jwk.n), CryptoData(jwk.e), key); | |
| 393 } | |
| 394 | |
| 395 Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key, | |
| 396 std::vector<uint8_t>* buffer) const { | |
| 397 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
| 398 return Status::ErrorUnexpectedKeyType(); | |
| 399 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); | |
| 400 return Status::Success(); | |
| 401 } | |
| 402 | |
| 403 Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key, | |
| 404 std::vector<uint8_t>* buffer) const { | |
| 405 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 406 return Status::ErrorUnexpectedKeyType(); | |
| 407 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); | |
| 408 return Status::Success(); | |
| 409 } | |
| 410 | |
| 411 Status RsaHashedAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key, | |
| 412 std::vector<uint8_t>* buffer) const { | |
| 413 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 414 | |
| 415 EVP_PKEY* pkey = AsymKeyOpenSsl::Cast(key)->key(); | |
| 416 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey)); | |
| 417 if (!rsa.get()) | |
| 418 return Status::ErrorUnexpected(); | |
| 419 | |
| 420 const char* jwk_algorithm = | |
| 421 GetJwkAlgorithm(key.algorithm().rsaHashedParams()->hash().id()); | |
| 422 if (!jwk_algorithm) | |
| 423 return Status::ErrorUnexpected(); | |
| 424 | |
| 425 switch (key.type()) { | |
| 426 case blink::WebCryptoKeyTypePublic: { | |
| 427 JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA"); | |
| 428 writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n))); | |
| 429 writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e))); | |
| 430 writer.ToJson(buffer); | |
| 431 return Status::Success(); | |
| 432 } | |
| 433 case blink::WebCryptoKeyTypePrivate: { | |
| 434 JwkWriter writer(jwk_algorithm, key.extractable(), key.usages(), "RSA"); | |
| 435 writer.SetBytes("n", CryptoData(BIGNUMToVector(rsa->n))); | |
| 436 writer.SetBytes("e", CryptoData(BIGNUMToVector(rsa->e))); | |
| 437 writer.SetBytes("d", CryptoData(BIGNUMToVector(rsa->d))); | |
| 438 // Although these are "optional" in the JWA, WebCrypto spec requires them | |
| 439 // to be emitted. | |
| 440 writer.SetBytes("p", CryptoData(BIGNUMToVector(rsa->p))); | |
| 441 writer.SetBytes("q", CryptoData(BIGNUMToVector(rsa->q))); | |
| 442 writer.SetBytes("dp", CryptoData(BIGNUMToVector(rsa->dmp1))); | |
| 443 writer.SetBytes("dq", CryptoData(BIGNUMToVector(rsa->dmq1))); | |
| 444 writer.SetBytes("qi", CryptoData(BIGNUMToVector(rsa->iqmp))); | |
| 445 writer.ToJson(buffer); | |
| 446 return Status::Success(); | |
| 447 } | |
| 448 | |
| 449 default: | |
| 450 return Status::ErrorUnexpected(); | |
| 451 } | |
| 452 } | |
| 453 | |
| 454 Status RsaHashedAlgorithm::SerializeKeyForClone( | |
| 455 const blink::WebCryptoKey& key, | |
| 456 blink::WebVector<uint8_t>* key_data) const { | |
| 457 key_data->assign(AsymKeyOpenSsl::Cast(key)->serialized_key_data()); | |
| 458 return Status::Success(); | |
| 459 } | |
| 460 | |
| 461 // TODO(eroman): Defer import to the crypto thread. http://crbug.com/430763 | |
| 462 Status RsaHashedAlgorithm::DeserializeKeyForClone( | |
| 463 const blink::WebCryptoKeyAlgorithm& algorithm, | |
| 464 blink::WebCryptoKeyType type, | |
| 465 bool extractable, | |
| 466 blink::WebCryptoKeyUsageMask usages, | |
| 467 const CryptoData& key_data, | |
| 468 blink::WebCryptoKey* key) const { | |
| 469 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
| 470 algorithm.id(), algorithm.rsaHashedParams()->hash().id()); | |
| 471 | |
| 472 Status status; | |
| 473 | |
| 474 switch (type) { | |
| 475 case blink::WebCryptoKeyTypePublic: | |
| 476 status = | |
| 477 ImportKeySpki(key_data, import_algorithm, extractable, usages, key); | |
| 478 break; | |
| 479 case blink::WebCryptoKeyTypePrivate: | |
| 480 status = | |
| 481 ImportKeyPkcs8(key_data, import_algorithm, extractable, usages, key); | |
| 482 break; | |
| 483 default: | |
| 484 return Status::ErrorUnexpected(); | |
| 485 } | |
| 486 | |
| 487 // There is some duplicated information in the serialized format used by | |
| 488 // structured clone (since the KeyAlgorithm is serialized separately from the | |
| 489 // key data). Use this extra information to further validate what was | |
| 490 // deserialized from the key data. | |
| 491 | |
| 492 if (algorithm.id() != key->algorithm().id()) | |
| 493 return Status::ErrorUnexpected(); | |
| 494 | |
| 495 if (key->type() != type) | |
| 496 return Status::ErrorUnexpected(); | |
| 497 | |
| 498 if (algorithm.rsaHashedParams()->modulusLengthBits() != | |
| 499 key->algorithm().rsaHashedParams()->modulusLengthBits()) { | |
| 500 return Status::ErrorUnexpected(); | |
| 501 } | |
| 502 | |
| 503 if (algorithm.rsaHashedParams()->publicExponent().size() != | |
| 504 key->algorithm().rsaHashedParams()->publicExponent().size() || | |
| 505 0 != | |
| 506 memcmp(algorithm.rsaHashedParams()->publicExponent().data(), | |
| 507 key->algorithm().rsaHashedParams()->publicExponent().data(), | |
| 508 key->algorithm().rsaHashedParams()->publicExponent().size())) { | |
| 509 return Status::ErrorUnexpected(); | |
| 510 } | |
| 511 | |
| 512 return Status::Success(); | |
| 513 } | |
| 514 | |
| 515 } // namespace webcrypto | |
| OLD | NEW |