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 "base/logging.h" 6#include "base/stl_util.h" 7#include "content/child/webcrypto/algorithm_dispatch.h" 8#include "content/child/webcrypto/crypto_data.h" 9#include "content/child/webcrypto/jwk.h" 10#include "content/child/webcrypto/status.h" 11#include "content/child/webcrypto/test/test_helpers.h" 12#include "content/child/webcrypto/webcrypto_util.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" 15#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 16 17namespace content { 18 19namespace webcrypto { 20 21namespace { 22 23// Creates an RSA-OAEP algorithm 24blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm( 25 const std::vector<uint8_t>& label) { 26 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( 27 blink::WebCryptoAlgorithmIdRsaOaep, 28 new blink::WebCryptoRsaOaepParams( 29 !label.empty(), vector_as_array(&label), label.size())); 30} 31 32scoped_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() { 33 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue()); 34 jwk->SetString("kty", "RSA"); 35 jwk->SetString("n", 36 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex))); 37 jwk->SetString("e", 38 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex))); 39 return jwk.Pass(); 40} 41 42// Import a PKCS#8 private key that uses RSAPrivateKey with the 43// id-rsaEncryption OID. 44TEST(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) { 45 if (!SupportsRsaOaep()) { 46 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 47 return; 48 } 49 50 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 51 ASSERT_EQ(Status::Success(), 52 ImportKey(blink::WebCryptoKeyFormatPkcs8, 53 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), 54 CreateRsaHashedImportAlgorithm( 55 blink::WebCryptoAlgorithmIdRsaOaep, 56 blink::WebCryptoAlgorithmIdSha1), 57 true, 58 blink::WebCryptoKeyUsageDecrypt, 59 &private_key)); 60} 61 62TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) { 63 if (!SupportsRsaOaep()) { 64 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 65 return; 66 } 67 68 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 69 70 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 71 ASSERT_EQ(Status::Success(), 72 ImportKeyJwkFromDict(*jwk.get(), 73 CreateRsaHashedImportAlgorithm( 74 blink::WebCryptoAlgorithmIdRsaOaep, 75 blink::WebCryptoAlgorithmIdSha1), 76 true, 77 blink::WebCryptoKeyUsageEncrypt, 78 &public_key)); 79} 80 81TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) { 82 if (!SupportsRsaOaep()) { 83 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 84 return; 85 } 86 87 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 88 jwk->SetString("alg", "RSA-OAEP"); 89 90 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 91 ASSERT_EQ(Status::Success(), 92 ImportKeyJwkFromDict(*jwk.get(), 93 CreateRsaHashedImportAlgorithm( 94 blink::WebCryptoAlgorithmIdRsaOaep, 95 blink::WebCryptoAlgorithmIdSha1), 96 true, 97 blink::WebCryptoKeyUsageEncrypt, 98 &public_key)); 99} 100 101TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) { 102 if (!SupportsRsaOaep()) { 103 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 104 return; 105 } 106 107 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 108 jwk->SetString("alg", "RSA-OAEP-512"); 109 110 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 111 ASSERT_EQ(Status::ErrorJwkAlgorithmInconsistent(), 112 ImportKeyJwkFromDict(*jwk.get(), 113 CreateRsaHashedImportAlgorithm( 114 blink::WebCryptoAlgorithmIdRsaOaep, 115 blink::WebCryptoAlgorithmIdSha1), 116 true, 117 blink::WebCryptoKeyUsageEncrypt, 118 &public_key)); 119} 120 121TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) { 122 if (!SupportsRsaOaep()) { 123 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 124 return; 125 } 126 127 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 128 jwk->SetString("kty", "oct"); 129 jwk->SetString("alg", "RSA-OAEP"); 130 131 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 132 ASSERT_EQ(Status::ErrorJwkUnexpectedKty("RSA"), 133 ImportKeyJwkFromDict(*jwk.get(), 134 CreateRsaHashedImportAlgorithm( 135 blink::WebCryptoAlgorithmIdRsaOaep, 136 blink::WebCryptoAlgorithmIdSha1), 137 true, 138 blink::WebCryptoKeyUsageEncrypt, 139 &public_key)); 140} 141 142TEST(WebCryptoRsaOaepTest, ExportPublicJwk) { 143 if (!SupportsRsaOaep()) { 144 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 145 return; 146 } 147 148 struct TestData { 149 blink::WebCryptoAlgorithmId hash_alg; 150 const char* expected_jwk_alg; 151 } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"}, 152 {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"}, 153 {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"}, 154 {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}}; 155 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestData); ++i) { 156 const TestData& test_data = kTestData[i]; 157 SCOPED_TRACE(test_data.expected_jwk_alg); 158 159 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 160 jwk->SetString("alg", test_data.expected_jwk_alg); 161 162 // Import the key in a known-good format 163 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 164 ASSERT_EQ(Status::Success(), 165 ImportKeyJwkFromDict( 166 *jwk.get(), 167 CreateRsaHashedImportAlgorithm( 168 blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg), 169 true, 170 blink::WebCryptoKeyUsageEncrypt, 171 &public_key)); 172 173 // Now export the key as JWK and verify its contents 174 std::vector<uint8_t> jwk_data; 175 ASSERT_EQ(Status::Success(), 176 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data)); 177 EXPECT_TRUE(VerifyPublicJwk(jwk_data, 178 test_data.expected_jwk_alg, 179 kPublicKeyModulusHex, 180 kPublicKeyExponentHex, 181 blink::WebCryptoKeyUsageEncrypt)); 182 } 183} 184 185TEST(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) { 186 if (!SupportsRsaOaep()) { 187 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 188 return; 189 } 190 191 scoped_ptr<base::ListValue> tests; 192 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests)); 193 194 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) { 195 SCOPED_TRACE(test_index); 196 197 base::DictionaryValue* test = NULL; 198 ASSERT_TRUE(tests->GetDictionary(test_index, &test)); 199 200 blink::WebCryptoAlgorithm digest_algorithm = 201 GetDigestAlgorithm(test, "hash"); 202 ASSERT_FALSE(digest_algorithm.isNull()); 203 std::vector<uint8_t> public_key_der = 204 GetBytesFromHexString(test, "public_key"); 205 std::vector<uint8_t> private_key_der = 206 GetBytesFromHexString(test, "private_key"); 207 std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext"); 208 std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext"); 209 std::vector<uint8_t> label = GetBytesFromHexString(test, "label"); 210 211 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( 212 blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id()); 213 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 214 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 215 216 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(public_key_der, 217 private_key_der, 218 import_algorithm, 219 false, 220 blink::WebCryptoKeyUsageEncrypt, 221 blink::WebCryptoKeyUsageDecrypt, 222 &public_key, 223 &private_key)); 224 225 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); 226 std::vector<uint8_t> decrypted_data; 227 ASSERT_EQ(Status::Success(), 228 Decrypt(op_algorithm, 229 private_key, 230 CryptoData(ciphertext), 231 &decrypted_data)); 232 EXPECT_BYTES_EQ(plaintext, decrypted_data); 233 std::vector<uint8_t> encrypted_data; 234 ASSERT_EQ( 235 Status::Success(), 236 Encrypt( 237 op_algorithm, public_key, CryptoData(plaintext), &encrypted_data)); 238 std::vector<uint8_t> redecrypted_data; 239 ASSERT_EQ(Status::Success(), 240 Decrypt(op_algorithm, 241 private_key, 242 CryptoData(encrypted_data), 243 &redecrypted_data)); 244 EXPECT_BYTES_EQ(plaintext, redecrypted_data); 245 } 246} 247 248TEST(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) { 249 if (!SupportsRsaOaep()) { 250 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 251 return; 252 } 253 254 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1; 255 const size_t kHashSize = 20; 256 257 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 258 259 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 260 ASSERT_EQ(Status::Success(), 261 ImportKeyJwkFromDict(*jwk.get(), 262 CreateRsaHashedImportAlgorithm( 263 blink::WebCryptoAlgorithmIdRsaOaep, kHash), 264 true, 265 blink::WebCryptoKeyUsageEncrypt, 266 &public_key)); 267 268 // The maximum size of an encrypted message is: 269 // modulus length 270 // - 1 (leading octet) 271 // - hash size (maskedSeed) 272 // - hash size (lHash portion of maskedDB) 273 // - 1 (at least one octet for the padding string) 274 size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize); 275 276 // The label has no influence on the maximum message size. For simplicity, 277 // use the empty string. 278 std::vector<uint8_t> label; 279 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); 280 281 // Test that a message just before the boundary succeeds. 282 std::string large_message; 283 large_message.resize(kMaxMessageSize - 1, 'A'); 284 285 std::vector<uint8_t> ciphertext; 286 ASSERT_EQ( 287 Status::Success(), 288 Encrypt( 289 op_algorithm, public_key, CryptoData(large_message), &ciphertext)); 290 291 // Test that a message at the boundary succeeds. 292 large_message.resize(kMaxMessageSize, 'A'); 293 ciphertext.clear(); 294 295 ASSERT_EQ( 296 Status::Success(), 297 Encrypt( 298 op_algorithm, public_key, CryptoData(large_message), &ciphertext)); 299 300 // Test that a message greater than the largest size fails. 301 large_message.resize(kMaxMessageSize + 1, 'A'); 302 ciphertext.clear(); 303 304 ASSERT_EQ( 305 Status::OperationError(), 306 Encrypt( 307 op_algorithm, public_key, CryptoData(large_message), &ciphertext)); 308} 309 310// Ensures that if the selected hash algorithm for the RSA-OAEP message is too 311// large, then it is rejected, independent of the actual message to be 312// encrypted. 313// For example, a 1024-bit RSA key is too small to accomodate a message that 314// uses OAEP with SHA-512, since it requires 1040 bits to encode 315// (2 * hash size + 2 padding bytes). 316TEST(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) { 317 if (!SupportsRsaOaep()) { 318 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 319 return; 320 } 321 322 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512; 323 324 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); 325 326 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 327 ASSERT_EQ(Status::Success(), 328 ImportKeyJwkFromDict(*jwk.get(), 329 CreateRsaHashedImportAlgorithm( 330 blink::WebCryptoAlgorithmIdRsaOaep, kHash), 331 true, 332 blink::WebCryptoKeyUsageEncrypt, 333 &public_key)); 334 335 // The label has no influence on the maximum message size. For simplicity, 336 // use the empty string. 337 std::vector<uint8_t> label; 338 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); 339 340 std::string small_message("A"); 341 std::vector<uint8_t> ciphertext; 342 // This is an operation error, as the internal consistency checking of the 343 // algorithm parameters is up to the implementation. 344 ASSERT_EQ( 345 Status::OperationError(), 346 Encrypt( 347 op_algorithm, public_key, CryptoData(small_message), &ciphertext)); 348} 349 350TEST(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) { 351 if (!SupportsRsaOaep()) { 352 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 353 return; 354 } 355 356 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 357 ASSERT_EQ(Status::Success(), 358 ImportKey(blink::WebCryptoKeyFormatPkcs8, 359 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), 360 CreateRsaHashedImportAlgorithm( 361 blink::WebCryptoAlgorithmIdRsaOaep, 362 blink::WebCryptoAlgorithmIdSha1), 363 true, 364 blink::WebCryptoKeyUsageDecrypt, 365 &private_key)); 366 367 // The label has no influence on the maximum message size. For simplicity, 368 // use the empty string. 369 std::vector<uint8_t> label; 370 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); 371 372 std::string large_dummy_message(kModulusLengthBits / 8, 'A'); 373 std::vector<uint8_t> plaintext; 374 375 ASSERT_EQ(Status::OperationError(), 376 Decrypt(op_algorithm, 377 private_key, 378 CryptoData(large_dummy_message), 379 &plaintext)); 380} 381 382TEST(WebCryptoRsaOaepTest, WrapUnwrapRawKey) { 383 if (!SupportsRsaOaep()) { 384 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 385 return; 386 } 387 388 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( 389 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); 390 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 391 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 392 393 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( 394 HexStringToBytes(kPublicKeySpkiDerHex), 395 HexStringToBytes(kPrivateKeyPkcs8DerHex), 396 import_algorithm, 397 false, 398 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, 399 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, 400 &public_key, 401 &private_key)); 402 403 std::vector<uint8_t> label; 404 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); 405 406 const std::string key_hex = "000102030405060708090A0B0C0D0E0F"; 407 const blink::WebCryptoAlgorithm key_algorithm = 408 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); 409 410 blink::WebCryptoKey key = 411 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), 412 key_algorithm, 413 blink::WebCryptoKeyUsageEncrypt); 414 ASSERT_FALSE(key.isNull()); 415 416 std::vector<uint8_t> wrapped_key; 417 ASSERT_EQ(Status::Success(), 418 WrapKey(blink::WebCryptoKeyFormatRaw, 419 key, 420 public_key, 421 wrapping_algorithm, 422 &wrapped_key)); 423 424 // Verify that |wrapped_key| can be decrypted and yields the key data. 425 // Because |private_key| supports both decrypt and unwrap, this is valid. 426 std::vector<uint8_t> decrypted_key; 427 ASSERT_EQ(Status::Success(), 428 Decrypt(wrapping_algorithm, 429 private_key, 430 CryptoData(wrapped_key), 431 &decrypted_key)); 432 EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key); 433 434 // Now attempt to unwrap the key, which should also decrypt the data. 435 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull(); 436 ASSERT_EQ(Status::Success(), 437 UnwrapKey(blink::WebCryptoKeyFormatRaw, 438 CryptoData(wrapped_key), 439 private_key, 440 wrapping_algorithm, 441 key_algorithm, 442 true, 443 blink::WebCryptoKeyUsageEncrypt, 444 &unwrapped_key)); 445 ASSERT_FALSE(unwrapped_key.isNull()); 446 447 std::vector<uint8_t> raw_key; 448 ASSERT_EQ(Status::Success(), 449 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); 450 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); 451} 452 453TEST(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) { 454 if (!SupportsRsaOaep()) { 455 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 456 return; 457 } 458 459 // The public and private portions of a 2048-bit RSA key with the 460 // id-rsaEncryption OID 461 const char kPublicKey2048SpkiDerHex[] = 462 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce" 463 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764" 464 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68" 465 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f" 466 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08" 467 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606" 468 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca" 469 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d" 470 "5d0203010001"; 471 const char kPrivateKey2048Pkcs8DerHex[] = 472 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201" 473 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30" 474 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448" 475 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872" 476 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34" 477 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936" 478 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7" 479 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b" 480 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3" 481 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c" 482 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42" 483 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4" 484 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62" 485 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a" 486 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339" 487 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c" 488 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3" 489 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a" 490 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c" 491 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133" 492 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622" 493 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277" 494 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5" 495 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945" 496 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b" 497 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb" 498 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af" 499 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562" 500 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792" 501 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab" 502 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0" 503 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca" 504 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0" 505 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b"; 506 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( 507 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); 508 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 509 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 510 511 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( 512 HexStringToBytes(kPublicKey2048SpkiDerHex), 513 HexStringToBytes(kPrivateKey2048Pkcs8DerHex), 514 import_algorithm, 515 false, 516 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, 517 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, 518 &public_key, 519 &private_key)); 520 521 std::vector<uint8_t> label; 522 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); 523 524 const std::string key_hex = "000102030405060708090a0b0c0d0e0f"; 525 const blink::WebCryptoAlgorithm key_algorithm = 526 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); 527 528 blink::WebCryptoKey key = 529 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), 530 key_algorithm, 531 blink::WebCryptoKeyUsageEncrypt); 532 ASSERT_FALSE(key.isNull()); 533 534 std::vector<uint8_t> wrapped_key; 535 ASSERT_EQ(Status::Success(), 536 WrapKey(blink::WebCryptoKeyFormatJwk, 537 key, 538 public_key, 539 wrapping_algorithm, 540 &wrapped_key)); 541 542 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object. 543 // Because |private_key| supports both decrypt and unwrap, this is valid. 544 std::vector<uint8_t> decrypted_jwk; 545 ASSERT_EQ(Status::Success(), 546 Decrypt(wrapping_algorithm, 547 private_key, 548 CryptoData(wrapped_key), 549 &decrypted_jwk)); 550 EXPECT_TRUE(VerifySecretJwk( 551 decrypted_jwk, "A128CBC", key_hex, blink::WebCryptoKeyUsageEncrypt)); 552 553 // Now attempt to unwrap the key, which should also decrypt the data. 554 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull(); 555 ASSERT_EQ(Status::Success(), 556 UnwrapKey(blink::WebCryptoKeyFormatJwk, 557 CryptoData(wrapped_key), 558 private_key, 559 wrapping_algorithm, 560 key_algorithm, 561 true, 562 blink::WebCryptoKeyUsageEncrypt, 563 &unwrapped_key)); 564 ASSERT_FALSE(unwrapped_key.isNull()); 565 566 std::vector<uint8_t> raw_key; 567 ASSERT_EQ(Status::Success(), 568 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); 569 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); 570} 571 572TEST(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) { 573 if (!SupportsRsaOaep()) { 574 LOG(WARNING) << "RSA-OAEP support not present; skipping."; 575 return; 576 } 577 578 struct TestCase { 579 const blink::WebCryptoAlgorithmId hash; 580 const blink::WebCryptoKeyUsageMask usage; 581 const char* const jwk_alg; 582 }; 583 const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1, 584 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP"}, 585 {blink::WebCryptoAlgorithmIdSha256, 586 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-256"}, 587 {blink::WebCryptoAlgorithmIdSha384, 588 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-384"}, 589 {blink::WebCryptoAlgorithmIdSha512, 590 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-512"}}; 591 592 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests); 593 ++test_index) { 594 SCOPED_TRACE(test_index); 595 const TestCase& test = kTests[test_index]; 596 597 const blink::WebCryptoAlgorithm import_algorithm = 598 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep, 599 test.hash); 600 601 // Import the spki to create a public key 602 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 603 ASSERT_EQ(Status::Success(), 604 ImportKey(blink::WebCryptoKeyFormatSpki, 605 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)), 606 import_algorithm, 607 true, 608 test.usage, 609 &public_key)); 610 611 // Export the public key as JWK and verify its contents 612 std::vector<uint8_t> jwk; 613 ASSERT_EQ(Status::Success(), 614 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk)); 615 EXPECT_TRUE(VerifyPublicJwk(jwk, 616 test.jwk_alg, 617 kPublicKeyModulusHex, 618 kPublicKeyExponentHex, 619 test.usage)); 620 621 // Import the JWK back in to create a new key 622 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull(); 623 ASSERT_EQ(Status::Success(), 624 ImportKey(blink::WebCryptoKeyFormatJwk, 625 CryptoData(jwk), 626 import_algorithm, 627 true, 628 test.usage, 629 &public_key2)); 630 ASSERT_TRUE(public_key2.handle()); 631 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type()); 632 EXPECT_TRUE(public_key2.extractable()); 633 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id()); 634 635 // TODO(eroman): Export the SPKI and verify matches. 636 } 637} 638 639} // namespace 640 641} // namespace webcrypto 642 643} // namespace content 644