Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(686)

Side by Side Diff: content/child/webcrypto/platform_crypto_nss.cc

Issue 275943004: Add support for RSA-OAEP when using NSS 3.16.2 or later (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/child/webcrypto/platform_crypto.h" 5 #include "content/child/webcrypto/platform_crypto.h"
6 6
7 #include <cryptohi.h> 7 #include <cryptohi.h>
8 #include <pk11pub.h> 8 #include <pk11pub.h>
9 #include <secerr.h> 9 #include <secerr.h>
10 #include <sechash.h> 10 #include <sechash.h>
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 53
54 struct CK_GCM_PARAMS { 54 struct CK_GCM_PARAMS {
55 CK_BYTE_PTR pIv; 55 CK_BYTE_PTR pIv;
56 CK_ULONG ulIvLen; 56 CK_ULONG ulIvLen;
57 CK_BYTE_PTR pAAD; 57 CK_BYTE_PTR pAAD;
58 CK_ULONG ulAADLen; 58 CK_ULONG ulAADLen;
59 CK_ULONG ulTagBits; 59 CK_ULONG ulTagBits;
60 }; 60 };
61 #endif // !defined(CKM_AES_GCM) 61 #endif // !defined(CKM_AES_GCM)
62 62
63 namespace {
64
63 // Signature for PK11_Encrypt and PK11_Decrypt. 65 // Signature for PK11_Encrypt and PK11_Decrypt.
64 typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*, 66 typedef SECStatus (*PK11_EncryptDecryptFunction)(PK11SymKey*,
65 CK_MECHANISM_TYPE, 67 CK_MECHANISM_TYPE,
66 SECItem*, 68 SECItem*,
67 unsigned char*, 69 unsigned char*,
68 unsigned int*, 70 unsigned int*,
69 unsigned int, 71 unsigned int,
70 const unsigned char*, 72 const unsigned char*,
71 unsigned int); 73 unsigned int);
72 74
75 // Signature for PK11_PubEncrypt
76 typedef SECStatus (*PK11_PubEncryptFunction)(SECKEYPublicKey*,
77 CK_MECHANISM_TYPE,
78 SECItem*,
79 unsigned char*,
80 unsigned int*,
81 unsigned int,
82 const unsigned char*,
83 unsigned int);
84
85 // Signature for PK11_PubDecrypt
86 typedef SECStatus (*PK11_PubDecryptFunction)(SECKEYPrivateKey*,
87 CK_MECHANISM_TYPE,
88 SECItem*,
89 unsigned char*,
90 unsigned int*,
91 unsigned int,
92 const unsigned char*,
93 unsigned int);
94
73 // Singleton to abstract away dynamically loading libnss3.so 95 // Singleton to abstract away dynamically loading libnss3.so
74 class AesGcmSupport { 96 class NssRuntimeSupport {
75 public: 97 public:
76 bool IsSupported() const { return pk11_encrypt_func_ && pk11_decrypt_func_; } 98 bool IsAesGcmSupported() const {
99 return pk11_encrypt_func_ && pk11_decrypt_func_;
100 }
101
102 bool IsRsaOaepSupported() const {
103 return pk11_pub_encrypt_func_ && pk11_pub_decrypt_func_;
104 }
Ryan Sleevi 2014/05/14 01:26:00 Note: For both the AES-GCM case and the RSA-OAEP,
77 105
78 // Returns NULL if unsupported. 106 // Returns NULL if unsupported.
79 PK11_EncryptDecryptFunction pk11_encrypt_func() const { 107 PK11_EncryptDecryptFunction pk11_encrypt_func() const {
80 return pk11_encrypt_func_; 108 return pk11_encrypt_func_;
81 } 109 }
82 110
83 // Returns NULL if unsupported. 111 // Returns NULL if unsupported.
84 PK11_EncryptDecryptFunction pk11_decrypt_func() const { 112 PK11_EncryptDecryptFunction pk11_decrypt_func() const {
85 return pk11_decrypt_func_; 113 return pk11_decrypt_func_;
86 } 114 }
87 115
116 // Returns NULL if unsupported.
117 PK11_PubEncryptFunction pk11_pub_encrypt_func() const {
118 return pk11_pub_encrypt_func_;
119 }
120
121 // Returns NULL if unsupported.
122 PK11_PubDecryptFunction pk11_pub_decrypt_func() const {
123 return pk11_pub_decrypt_func_;
124 }
125
88 private: 126 private:
89 friend struct base::DefaultLazyInstanceTraits<AesGcmSupport>; 127 friend struct base::DefaultLazyInstanceTraits<NssRuntimeSupport>;
90 128
91 AesGcmSupport() { 129 NssRuntimeSupport() {
92 #if !defined(USE_NSS) 130 #if !defined(USE_NSS)
93 // Using a bundled version of NSS that is guaranteed to have this symbol. 131 // Using a bundled version of NSS that is guaranteed to have this symbol.
94 pk11_encrypt_func_ = PK11_Encrypt; 132 pk11_encrypt_func_ = PK11_Encrypt;
95 pk11_decrypt_func_ = PK11_Decrypt; 133 pk11_decrypt_func_ = PK11_Decrypt;
134 pk11_pub_encrypt_func_ = PK11_PubEncrypt;
135 pk11_pub_decrypt_func_ = PK11_PubDecrypt;
96 #else 136 #else
97 // Using system NSS libraries and PCKS #11 modules, which may not have the 137 // Using system NSS libraries and PCKS #11 modules, which may not have the
98 // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM). 138 // necessary function (PK11_Encrypt) or mechanism support (CKM_AES_GCM).
99 139
100 // If PK11_Encrypt() was successfully resolved, then NSS will support 140 // If PK11_Encrypt() was successfully resolved, then NSS will support
101 // AES-GCM directly. This was introduced in NSS 3.15. 141 // AES-GCM directly. This was introduced in NSS 3.15.
102 pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>( 142 pk11_encrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
103 dlsym(RTLD_DEFAULT, "PK11_Encrypt")); 143 dlsym(RTLD_DEFAULT, "PK11_Encrypt"));
104 pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>( 144 pk11_decrypt_func_ = reinterpret_cast<PK11_EncryptDecryptFunction>(
105 dlsym(RTLD_DEFAULT, "PK11_Decrypt")); 145 dlsym(RTLD_DEFAULT, "PK11_Decrypt"));
146 pk11_pub_encrypt_func_ = reinterpret_cast<PK11_PubEncryptFunction>(
147 dlsym(RTLD_DEFAULT, "PK11_PubEncrypt"));
148 pk11_pub_decrypt_func_ = reinterpret_cast<PK11_PubDecryptFunction>(
149 dlsym(RTLD_DEFAULT, "PK11_PubDecrypt"));
106 #endif 150 #endif
107 } 151 }
108 152
109 PK11_EncryptDecryptFunction pk11_encrypt_func_; 153 PK11_EncryptDecryptFunction pk11_encrypt_func_;
110 PK11_EncryptDecryptFunction pk11_decrypt_func_; 154 PK11_EncryptDecryptFunction pk11_decrypt_func_;
155 PK11_PubEncryptFunction pk11_pub_encrypt_func_;
156 PK11_PubDecryptFunction pk11_pub_decrypt_func_;
111 }; 157 };
112 158
113 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = 159 base::LazyInstance<NssRuntimeSupport>::Leaky g_nss_runtime_support =
114 LAZY_INSTANCE_INITIALIZER; 160 LAZY_INSTANCE_INITIALIZER;
115 161
162 } // namespace
163
116 namespace content { 164 namespace content {
117 165
118 namespace webcrypto { 166 namespace webcrypto {
119 167
120 namespace platform { 168 namespace platform {
121 169
122 // Each key maintains a copy of its serialized form 170 // Each key maintains a copy of its serialized form
123 // in either 'raw', 'pkcs8', or 'spki' format. This is to allow 171 // in either 'raw', 'pkcs8', or 'spki' format. This is to allow
124 // structured cloning of keys synchronously from the target Blink 172 // structured cloning of keys synchronously from the target Blink
125 // thread without having to lock access to the key. 173 // thread without having to lock access to the key.
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 case blink::WebCryptoAlgorithmIdSha384: 301 case blink::WebCryptoAlgorithmIdSha384:
254 return CKM_SHA384_HMAC; 302 return CKM_SHA384_HMAC;
255 case blink::WebCryptoAlgorithmIdSha512: 303 case blink::WebCryptoAlgorithmIdSha512:
256 return CKM_SHA512_HMAC; 304 return CKM_SHA512_HMAC;
257 default: 305 default:
258 // Not a supported algorithm. 306 // Not a supported algorithm.
259 return CKM_INVALID_MECHANISM; 307 return CKM_INVALID_MECHANISM;
260 } 308 }
261 } 309 }
262 310
311 CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism(
312 const blink::WebCryptoAlgorithm& algorithm) {
313 switch (algorithm.id()) {
314 case blink::WebCryptoAlgorithmIdSha1:
315 return CKM_SHA_1;
316 case blink::WebCryptoAlgorithmIdSha256:
317 return CKM_SHA256;
318 case blink::WebCryptoAlgorithmIdSha384:
319 return CKM_SHA384;
320 case blink::WebCryptoAlgorithmIdSha512:
321 return CKM_SHA512;
322 default:
323 // Not a supported algorithm.
324 return CKM_INVALID_MECHANISM;
325 }
326 }
327
328 CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism(
329 const blink::WebCryptoAlgorithm& algorithm) {
330 switch (algorithm.id()) {
331 case blink::WebCryptoAlgorithmIdSha1:
332 return CKG_MGF1_SHA1;
333 case blink::WebCryptoAlgorithmIdSha256:
334 return CKG_MGF1_SHA256;
335 case blink::WebCryptoAlgorithmIdSha384:
336 return CKG_MGF1_SHA384;
337 case blink::WebCryptoAlgorithmIdSha512:
338 return CKG_MGF1_SHA512;
339 default:
340 return CKM_INVALID_MECHANISM;
341 }
342 }
343
344 void InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash,
345 const CryptoData& label,
346 CK_RSA_PKCS_OAEP_PARAMS* oaep_params) {
347 oaep_params->source = CKZ_DATA_SPECIFIED;
348 oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes());
349 oaep_params->ulSourceDataLen = label.byte_length();
350 oaep_params->mgf = WebCryptoHashToMGFMechanism(hash);
eroman 2014/05/14 01:50:47 What is the consequence of failure for WebCryptoHa
Ryan Sleevi 2014/05/14 06:09:57 Officially: "It depends". Practically: No PKCS#11
351 oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
eroman 2014/05/14 01:50:47 Same question above, for the sake of future proofi
352 }
353
263 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, 354 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode,
264 SymKey* key, 355 SymKey* key,
265 const CryptoData& iv, 356 const CryptoData& iv,
266 const CryptoData& data, 357 const CryptoData& data,
267 std::vector<uint8>* buffer) { 358 std::vector<uint8>* buffer) {
268 CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT; 359 CK_ATTRIBUTE_TYPE operation = (mode == ENCRYPT) ? CKA_ENCRYPT : CKA_DECRYPT;
269 360
270 SECItem iv_item = MakeSECItemForBuffer(iv); 361 SECItem iv_item = MakeSECItemForBuffer(iv);
271 362
272 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); 363 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item));
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is 421 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is
331 // the concatenation of the ciphertext and the authentication tag. Similarly, 422 // the concatenation of the ciphertext and the authentication tag. Similarly,
332 // this is the expectation for the input to decryption. 423 // this is the expectation for the input to decryption.
333 Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode, 424 Status AesGcmEncryptDecrypt(EncryptOrDecrypt mode,
334 SymKey* key, 425 SymKey* key,
335 const CryptoData& data, 426 const CryptoData& data,
336 const CryptoData& iv, 427 const CryptoData& iv,
337 const CryptoData& additional_data, 428 const CryptoData& additional_data,
338 unsigned int tag_length_bits, 429 unsigned int tag_length_bits,
339 std::vector<uint8>* buffer) { 430 std::vector<uint8>* buffer) {
340 if (!g_aes_gcm_support.Get().IsSupported()) 431 if (!g_nss_runtime_support.Get().IsAesGcmSupported())
341 return Status::ErrorUnsupported(); 432 return Status::ErrorUnsupported();
342 433
343 unsigned int tag_length_bytes = tag_length_bits / 8; 434 unsigned int tag_length_bytes = tag_length_bits / 8;
344 435
345 CK_GCM_PARAMS gcm_params = {0}; 436 CK_GCM_PARAMS gcm_params = {0};
346 gcm_params.pIv = const_cast<unsigned char*>(iv.bytes()); 437 gcm_params.pIv = const_cast<unsigned char*>(iv.bytes());
347 gcm_params.ulIvLen = iv.byte_length(); 438 gcm_params.ulIvLen = iv.byte_length();
348 439
349 gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes()); 440 gcm_params.pAAD = const_cast<unsigned char*>(additional_data.bytes());
350 gcm_params.ulAADLen = additional_data.byte_length(); 441 gcm_params.ulAADLen = additional_data.byte_length();
(...skipping 25 matching lines...) Expand all
376 // From the analysis of that bug it looks like it might be safe to pass a 467 // From the analysis of that bug it looks like it might be safe to pass a
377 // correctly sized buffer but lie about its size. Since resizing the 468 // correctly sized buffer but lie about its size. Since resizing the
378 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. 469 // WebCryptoArrayBuffer is expensive that hack may be worth looking into.
379 buffer_size = data.byte_length(); 470 buffer_size = data.byte_length();
380 } 471 }
381 472
382 buffer->resize(buffer_size); 473 buffer->resize(buffer_size);
383 unsigned char* buffer_data = Uint8VectorStart(buffer); 474 unsigned char* buffer_data = Uint8VectorStart(buffer);
384 475
385 PK11_EncryptDecryptFunction func = 476 PK11_EncryptDecryptFunction func =
386 (mode == ENCRYPT) ? g_aes_gcm_support.Get().pk11_encrypt_func() 477 (mode == ENCRYPT) ? g_nss_runtime_support.Get().pk11_encrypt_func()
387 : g_aes_gcm_support.Get().pk11_decrypt_func(); 478 : g_nss_runtime_support.Get().pk11_decrypt_func();
388 479
389 unsigned int output_len = 0; 480 unsigned int output_len = 0;
390 SECStatus result = func(key->key(), 481 SECStatus result = func(key->key(),
391 CKM_AES_GCM, 482 CKM_AES_GCM,
392 &param, 483 &param,
393 buffer_data, 484 buffer_data,
394 &output_len, 485 &output_len,
395 buffer->size(), 486 buffer->size(),
396 data.bytes(), 487 data.bytes(),
397 data.byte_length()); 488 data.byte_length());
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 *mechanism = CKM_AES_CBC; 606 *mechanism = CKM_AES_CBC;
516 *flags = CKF_ENCRYPT | CKF_DECRYPT; 607 *flags = CKF_ENCRYPT | CKF_DECRYPT;
517 break; 608 break;
518 } 609 }
519 case blink::WebCryptoAlgorithmIdAesKw: { 610 case blink::WebCryptoAlgorithmIdAesKw: {
520 *mechanism = CKM_NSS_AES_KEY_WRAP; 611 *mechanism = CKM_NSS_AES_KEY_WRAP;
521 *flags = CKF_WRAP | CKF_WRAP; 612 *flags = CKF_WRAP | CKF_WRAP;
522 break; 613 break;
523 } 614 }
524 case blink::WebCryptoAlgorithmIdAesGcm: { 615 case blink::WebCryptoAlgorithmIdAesGcm: {
525 if (!g_aes_gcm_support.Get().IsSupported()) 616 if (!g_nss_runtime_support.Get().IsAesGcmSupported())
526 return Status::ErrorUnsupported(); 617 return Status::ErrorUnsupported();
527 *mechanism = CKM_AES_GCM; 618 *mechanism = CKM_AES_GCM;
528 *flags = CKF_ENCRYPT | CKF_DECRYPT; 619 *flags = CKF_ENCRYPT | CKF_DECRYPT;
529 break; 620 break;
530 } 621 }
531 default: 622 default:
532 return Status::ErrorUnsupported(); 623 return Status::ErrorUnsupported();
533 } 624 }
534 return Status::Success(); 625 return Status::Success();
535 } 626 }
(...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 const_cast<unsigned char*>(data.bytes()), 1260 const_cast<unsigned char*>(data.bytes()),
1170 data.byte_length()) != SECSuccess) { 1261 data.byte_length()) != SECSuccess) {
1171 return Status::OperationError(); 1262 return Status::OperationError();
1172 } 1263 }
1173 DCHECK_LE(output_length_bytes, max_output_length_bytes); 1264 DCHECK_LE(output_length_bytes, max_output_length_bytes);
1174 buffer->resize(output_length_bytes); 1265 buffer->resize(output_length_bytes);
1175 return Status::Success(); 1266 return Status::Success();
1176 } 1267 }
1177 1268
1178 // ----------------------------------- 1269 // -----------------------------------
1270 // RsaOaep
1271 // -----------------------------------
1272 Status EncryptRsaOaep(PublicKey* key,
eroman 2014/05/14 01:50:47 nit: for consistency add a new line after --------
1273 const blink::WebCryptoAlgorithm& hash,
1274 const CryptoData& label,
1275 const CryptoData& data,
1276 std::vector<uint8>* buffer) {
1277 if (!g_nss_runtime_support.Get().IsRsaOaepSupported())
1278 return Status::ErrorUnsupported();
1279
1280 CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
1281 InitializeRsaOaepParams(hash, label, &oaep_params);
1282
padolph 2014/05/14 02:00:03 Do we need to check the length of the input |data|
1283 SECItem param;
1284 param.type = siBuffer;
1285 param.data = reinterpret_cast<unsigned char*>(&oaep_params);
1286 param.len = sizeof(oaep_params);
1287
1288 buffer->resize(SECKEY_PublicKeyStrength(key->key()));
1289 unsigned char* buffer_data = Uint8VectorStart(buffer);
1290 unsigned int output_len;
1291 if (g_nss_runtime_support.Get().pk11_pub_encrypt_func()(
1292 key->key(),
1293 CKM_RSA_PKCS_OAEP,
1294 &param,
1295 buffer_data,
1296 &output_len,
1297 buffer->size(),
1298 data.bytes(),
1299 data.byte_length() != SECSuccess)) {
1300 return Status::OperationError();
1301 }
1302
1303 DCHECK_LE(output_len, buffer->size());
1304 buffer->resize(output_len);
1305 return Status::Success();
1306 }
1307
1308 Status DecryptRsaOaep(PrivateKey* key,
1309 const blink::WebCryptoAlgorithm& hash,
1310 const CryptoData& label,
1311 const CryptoData& data,
1312 std::vector<uint8>* buffer) {
1313 if (!g_nss_runtime_support.Get().IsRsaOaepSupported())
eroman 2014/05/14 01:50:47 We might consider failing with ErrorUnsupported du
Ryan Sleevi 2014/05/14 02:34:30 Good point.
1314 return Status::ErrorUnsupported();
1315
1316 CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
1317 InitializeRsaOaepParams(hash, label, &oaep_params);
1318
1319 SECItem param;
1320 param.type = siBuffer;
1321 param.data = reinterpret_cast<unsigned char*>(&oaep_params);
1322 param.len = sizeof(oaep_params);
1323
1324 const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key());
1325 if (modulus_length_bytes <= 0)
1326 return Status::ErrorUnexpected();
1327
1328 buffer->resize(modulus_length_bytes);
1329
1330 unsigned char* buffer_data = Uint8VectorStart(buffer);
1331 unsigned int output_len;
1332 if (g_nss_runtime_support.Get().pk11_pub_decrypt_func()(
1333 key->key(),
1334 CKM_RSA_PKCS_OAEP,
1335 &param,
1336 buffer_data,
1337 &output_len,
1338 buffer->size(),
1339 data.bytes(),
1340 data.byte_length() != SECSuccess)) {
1341 return Status::OperationError();
1342 }
1343
1344 DCHECK_LE(output_len, buffer->size());
1345 buffer->resize(output_len);
1346 return Status::Success();
1347 }
1348
1349 // -----------------------------------
1179 // RsaSsaPkcs1v1_5 1350 // RsaSsaPkcs1v1_5
1180 // ----------------------------------- 1351 // -----------------------------------
1181 1352
1182 Status SignRsaSsaPkcs1v1_5(PrivateKey* key, 1353 Status SignRsaSsaPkcs1v1_5(PrivateKey* key,
1183 const blink::WebCryptoAlgorithm& hash, 1354 const blink::WebCryptoAlgorithm& hash,
1184 const CryptoData& data, 1355 const CryptoData& data,
1185 std::vector<uint8>* buffer) { 1356 std::vector<uint8>* buffer) {
1186 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the 1357 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the
1187 // inner hash of the input Web Crypto algorithm. 1358 // inner hash of the input Web Crypto algorithm.
1188 SECOidTag sign_alg_tag; 1359 SECOidTag sign_alg_tag;
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after
1675 key_algorithm, 1846 key_algorithm,
1676 usage_mask); 1847 usage_mask);
1677 return Status::Success(); 1848 return Status::Success();
1678 } 1849 }
1679 1850
1680 } // namespace platform 1851 } // namespace platform
1681 1852
1682 } // namespace webcrypto 1853 } // namespace webcrypto
1683 1854
1684 } // namespace content 1855 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698