| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/platform_crypto.h" |
| 6 | 6 |
| 7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
| 8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
| 9 #include <sechash.h> | 9 #include <sechash.h> |
| 10 | 10 |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "content/renderer/webcrypto/crypto_data.h" |
| 15 #include "content/renderer/webcrypto/webcrypto_util.h" | 16 #include "content/renderer/webcrypto/webcrypto_util.h" |
| 16 #include "crypto/nss_util.h" | 17 #include "crypto/nss_util.h" |
| 17 #include "crypto/scoped_nss_types.h" | 18 #include "crypto/scoped_nss_types.h" |
| 18 #include "crypto/secure_util.h" | |
| 19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 19 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| 21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 21 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| 22 | 22 |
| 23 #if defined(USE_NSS) | 23 #if defined(USE_NSS) |
| 24 #include <dlfcn.h> | 24 #include <dlfcn.h> |
| 25 #endif | 25 #endif |
| 26 | 26 |
| 27 // At the time of this writing: | 27 // At the time of this writing: |
| 28 // * Windows and Mac builds ship with their own copy of NSS (3.15+) | 28 // * Windows and Mac builds ship with their own copy of NSS (3.15+) |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 } | 104 } |
| 105 | 105 |
| 106 PK11_EncryptDecryptFunction pk11_encrypt_func_; | 106 PK11_EncryptDecryptFunction pk11_encrypt_func_; |
| 107 PK11_EncryptDecryptFunction pk11_decrypt_func_; | 107 PK11_EncryptDecryptFunction pk11_decrypt_func_; |
| 108 }; | 108 }; |
| 109 | 109 |
| 110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = | 110 base::LazyInstance<AesGcmSupport>::Leaky g_aes_gcm_support = |
| 111 LAZY_INSTANCE_INITIALIZER; | 111 LAZY_INSTANCE_INITIALIZER; |
| 112 | 112 |
| 113 namespace content { | 113 namespace content { |
| 114 namespace webcrypto { |
| 114 | 115 |
| 115 using webcrypto::Status; | 116 class PlatformKey : public blink::WebCryptoKeyHandle { |
| 117 public: |
| 118 virtual PlatformSymKey* AsSymKey() { return NULL; } |
| 119 virtual PlatformPublicKey* AsPublicKey() { return NULL; } |
| 120 virtual PlatformPrivateKey* AsPrivateKey() { return NULL; } |
| 121 }; |
| 116 | 122 |
| 117 namespace { | 123 class PlatformSymKey : public PlatformKey { |
| 118 | |
| 119 class SymKeyHandle : public blink::WebCryptoKeyHandle { | |
| 120 public: | 124 public: |
| 121 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} | 125 explicit PlatformSymKey(crypto::ScopedPK11SymKey key) : key_(key.Pass()) {} |
| 122 | 126 |
| 123 PK11SymKey* key() { return key_.get(); } | 127 PK11SymKey* key() { return key_.get(); } |
| 124 | 128 |
| 129 virtual PlatformSymKey* AsSymKey() OVERRIDE { return this; } |
| 130 |
| 125 private: | 131 private: |
| 126 crypto::ScopedPK11SymKey key_; | 132 crypto::ScopedPK11SymKey key_; |
| 127 | 133 |
| 128 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | 134 DISALLOW_COPY_AND_ASSIGN(PlatformSymKey); |
| 129 }; | 135 }; |
| 130 | 136 |
| 131 class PublicKeyHandle : public blink::WebCryptoKeyHandle { | 137 class PlatformPublicKey : public PlatformKey { |
| 132 public: | 138 public: |
| 133 explicit PublicKeyHandle(crypto::ScopedSECKEYPublicKey key) | 139 explicit PlatformPublicKey(crypto::ScopedSECKEYPublicKey key) |
| 134 : key_(key.Pass()) {} | 140 : key_(key.Pass()) {} |
| 135 | 141 |
| 136 SECKEYPublicKey* key() { return key_.get(); } | 142 SECKEYPublicKey* key() { return key_.get(); } |
| 137 | 143 |
| 144 virtual PlatformPublicKey* AsPublicKey() OVERRIDE { return this; } |
| 145 |
| 138 private: | 146 private: |
| 139 crypto::ScopedSECKEYPublicKey key_; | 147 crypto::ScopedSECKEYPublicKey key_; |
| 140 | 148 |
| 141 DISALLOW_COPY_AND_ASSIGN(PublicKeyHandle); | 149 DISALLOW_COPY_AND_ASSIGN(PlatformPublicKey); |
| 142 }; | 150 }; |
| 143 | 151 |
| 144 class PrivateKeyHandle : public blink::WebCryptoKeyHandle { | 152 class PlatformPrivateKey : public PlatformKey { |
| 145 public: | 153 public: |
| 146 explicit PrivateKeyHandle(crypto::ScopedSECKEYPrivateKey key) | 154 explicit PlatformPrivateKey(crypto::ScopedSECKEYPrivateKey key) |
| 147 : key_(key.Pass()) {} | 155 : key_(key.Pass()) {} |
| 148 | 156 |
| 149 SECKEYPrivateKey* key() { return key_.get(); } | 157 SECKEYPrivateKey* key() { return key_.get(); } |
| 150 | 158 |
| 159 virtual PlatformPrivateKey* AsPrivateKey() OVERRIDE { return this; } |
| 160 |
| 151 private: | 161 private: |
| 152 crypto::ScopedSECKEYPrivateKey key_; | 162 crypto::ScopedSECKEYPrivateKey key_; |
| 153 | 163 |
| 154 DISALLOW_COPY_AND_ASSIGN(PrivateKeyHandle); | 164 DISALLOW_COPY_AND_ASSIGN(PlatformPrivateKey); |
| 155 }; | 165 }; |
| 156 | 166 |
| 167 PlatformSymKey* PlatformCrypto::ToSymKey(const blink::WebCryptoKey& key) { |
| 168 return static_cast<PlatformKey*>(key.handle())->AsSymKey(); |
| 169 } |
| 170 |
| 171 PlatformPublicKey* PlatformCrypto::ToPublicKey(const blink::WebCryptoKey& key) { |
| 172 return static_cast<PlatformKey*>(key.handle())->AsPublicKey(); |
| 173 } |
| 174 |
| 175 PlatformPrivateKey* PlatformCrypto::ToPrivateKey( |
| 176 const blink::WebCryptoKey& key) { |
| 177 return static_cast<PlatformKey*>(key.handle())->AsPrivateKey(); |
| 178 } |
| 179 |
| 180 namespace { |
| 181 |
| 182 // Creates a SECItem for the data in |buffer|. This does NOT make a copy, so |
| 183 // |buffer| should outlive the SECItem. |
| 184 SECItem MakeSECItemForBuffer(const CryptoData& buffer) { |
| 185 SECItem item = { |
| 186 siBuffer, |
| 187 // NSS requires non-const data even though it is just for input. |
| 188 const_cast<unsigned char*>(buffer.bytes()), |
| 189 buffer.byte_length() |
| 190 }; |
| 191 return item; |
| 192 } |
| 193 |
| 157 HASH_HashType WebCryptoAlgorithmToNSSHashType( | 194 HASH_HashType WebCryptoAlgorithmToNSSHashType( |
| 158 const blink::WebCryptoAlgorithm& algorithm) { | 195 blink::WebCryptoAlgorithmId algorithm) { |
| 159 switch (algorithm.id()) { | 196 switch (algorithm) { |
| 160 case blink::WebCryptoAlgorithmIdSha1: | 197 case blink::WebCryptoAlgorithmIdSha1: |
| 161 return HASH_AlgSHA1; | 198 return HASH_AlgSHA1; |
| 162 case blink::WebCryptoAlgorithmIdSha224: | 199 case blink::WebCryptoAlgorithmIdSha224: |
| 163 return HASH_AlgSHA224; | 200 return HASH_AlgSHA224; |
| 164 case blink::WebCryptoAlgorithmIdSha256: | 201 case blink::WebCryptoAlgorithmIdSha256: |
| 165 return HASH_AlgSHA256; | 202 return HASH_AlgSHA256; |
| 166 case blink::WebCryptoAlgorithmIdSha384: | 203 case blink::WebCryptoAlgorithmIdSha384: |
| 167 return HASH_AlgSHA384; | 204 return HASH_AlgSHA384; |
| 168 case blink::WebCryptoAlgorithmIdSha512: | 205 case blink::WebCryptoAlgorithmIdSha512: |
| 169 return HASH_AlgSHA512; | 206 return HASH_AlgSHA512; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 187 case blink::WebCryptoAlgorithmIdSha512: | 224 case blink::WebCryptoAlgorithmIdSha512: |
| 188 return CKM_SHA512_HMAC; | 225 return CKM_SHA512_HMAC; |
| 189 default: | 226 default: |
| 190 // Not a supported algorithm. | 227 // Not a supported algorithm. |
| 191 return CKM_INVALID_MECHANISM; | 228 return CKM_INVALID_MECHANISM; |
| 192 } | 229 } |
| 193 } | 230 } |
| 194 | 231 |
| 195 Status AesCbcEncryptDecrypt( | 232 Status AesCbcEncryptDecrypt( |
| 196 CK_ATTRIBUTE_TYPE operation, | 233 CK_ATTRIBUTE_TYPE operation, |
| 197 const blink::WebCryptoAlgorithm& algorithm, | 234 PlatformSymKey* key, |
| 198 const blink::WebCryptoKey& key, | 235 const CryptoData& iv, |
| 199 const unsigned char* data, | 236 const CryptoData& data, |
| 200 unsigned int data_size, | |
| 201 blink::WebArrayBuffer* buffer) { | 237 blink::WebArrayBuffer* buffer) { |
| 202 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id()); | |
| 203 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
| 204 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 205 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); | 238 DCHECK(operation == CKA_ENCRYPT || operation == CKA_DECRYPT); |
| 206 | 239 |
| 207 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 240 SECItem iv_item = MakeSECItemForBuffer(iv); |
| 208 | |
| 209 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); | |
| 210 if (params->iv().size() != AES_BLOCK_SIZE) | |
| 211 return Status::ErrorIncorrectSizeAesCbcIv(); | |
| 212 | |
| 213 SECItem iv_item; | |
| 214 iv_item.type = siBuffer; | |
| 215 iv_item.data = const_cast<unsigned char*>(params->iv().data()); | |
| 216 iv_item.len = params->iv().size(); | |
| 217 | 241 |
| 218 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); | 242 crypto::ScopedSECItem param(PK11_ParamFromIV(CKM_AES_CBC_PAD, &iv_item)); |
| 219 if (!param) | 243 if (!param) |
| 220 return Status::Error(); | 244 return Status::Error(); |
| 221 | 245 |
| 222 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( | 246 crypto::ScopedPK11Context context(PK11_CreateContextBySymKey( |
| 223 CKM_AES_CBC_PAD, operation, sym_key->key(), param.get())); | 247 CKM_AES_CBC_PAD, operation, key->key(), param.get())); |
| 224 | 248 |
| 225 if (!context.get()) | 249 if (!context.get()) |
| 226 return Status::Error(); | 250 return Status::Error(); |
| 227 | 251 |
| 228 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than | 252 // Oddly PK11_CipherOp takes input and output lengths as "int" rather than |
| 229 // "unsigned int". Do some checks now to avoid integer overflowing. | 253 // "unsigned int". Do some checks now to avoid integer overflowing. |
| 230 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { | 254 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { |
| 231 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now | 255 // TODO(eroman): Handle this by chunking the input fed into NSS. Right now |
| 232 // it doesn't make much difference since the one-shot API would end up | 256 // it doesn't make much difference since the one-shot API would end up |
| 233 // blowing out the memory and crashing anyway. | 257 // blowing out the memory and crashing anyway. |
| 234 return Status::ErrorDataTooLarge(); | 258 return Status::ErrorDataTooLarge(); |
| 235 } | 259 } |
| 236 | 260 |
| 237 // PK11_CipherOp does an invalid memory access when given empty decryption | 261 // PK11_CipherOp does an invalid memory access when given empty decryption |
| 238 // input, or input which is not a multiple of the block size. See also | 262 // input, or input which is not a multiple of the block size. See also |
| 239 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. | 263 // https://bugzilla.mozilla.com/show_bug.cgi?id=921687. |
| 240 if (operation == CKA_DECRYPT && | 264 if (operation == CKA_DECRYPT && |
| 241 (data_size == 0 || (data_size % AES_BLOCK_SIZE != 0))) { | 265 (data.byte_length() == 0 || (data.byte_length() % AES_BLOCK_SIZE != 0))) { |
| 242 return Status::Error(); | 266 return Status::Error(); |
| 243 } | 267 } |
| 244 | 268 |
| 245 // TODO(eroman): Refine the output buffer size. It can be computed exactly for | 269 // TODO(eroman): Refine the output buffer size. It can be computed exactly for |
| 246 // encryption, and can be smaller for decryption. | 270 // encryption, and can be smaller for decryption. |
| 247 unsigned int output_max_len = data_size + AES_BLOCK_SIZE; | 271 unsigned int output_max_len = data.byte_length() + AES_BLOCK_SIZE; |
| 248 CHECK_GT(output_max_len, data_size); | 272 CHECK_GT(output_max_len, data.byte_length()); |
| 249 | 273 |
| 250 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); | 274 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); |
| 251 | 275 |
| 252 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | 276 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
| 253 | 277 |
| 254 int output_len; | 278 int output_len; |
| 255 if (SECSuccess != PK11_CipherOp(context.get(), | 279 if (SECSuccess != PK11_CipherOp(context.get(), |
| 256 buffer_data, | 280 buffer_data, |
| 257 &output_len, | 281 &output_len, |
| 258 buffer->byteLength(), | 282 buffer->byteLength(), |
| 259 data, | 283 data.bytes(), |
| 260 data_size)) { | 284 data.byte_length())) { |
| 261 return Status::Error(); | 285 return Status::Error(); |
| 262 } | 286 } |
| 263 | 287 |
| 264 unsigned int final_output_chunk_len; | 288 unsigned int final_output_chunk_len; |
| 265 if (SECSuccess != PK11_DigestFinal(context.get(), | 289 if (SECSuccess != PK11_DigestFinal(context.get(), |
| 266 buffer_data + output_len, | 290 buffer_data + output_len, |
| 267 &final_output_chunk_len, | 291 &final_output_chunk_len, |
| 268 output_max_len - output_len)) { | 292 output_max_len - output_len)) { |
| 269 return Status::Error(); | 293 return Status::Error(); |
| 270 } | 294 } |
| 271 | 295 |
| 272 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); | 296 ShrinkBuffer(buffer, final_output_chunk_len + output_len); |
| 273 return Status::Success(); | 297 return Status::Success(); |
| 274 } | 298 } |
| 275 | 299 |
| 276 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is | 300 // Helper to either encrypt or decrypt for AES-GCM. The result of encryption is |
| 277 // the concatenation of the ciphertext and the authentication tag. Similarly, | 301 // the concatenation of the ciphertext and the authentication tag. Similarly, |
| 278 // this is the expectation for the input to decryption. | 302 // this is the expectation for the input to decryption. |
| 279 Status AesGcmEncryptDecrypt( | 303 Status AesGcmEncryptDecrypt( |
| 280 bool encrypt, | 304 bool encrypt, |
| 281 const blink::WebCryptoAlgorithm& algorithm, | 305 PlatformSymKey* key, |
| 282 const blink::WebCryptoKey& key, | 306 const blink::WebCryptoAesGcmParams* params, |
| 283 const unsigned char* data, | 307 const CryptoData& data, |
| 284 unsigned int data_size, | |
| 285 blink::WebArrayBuffer* buffer) { | 308 blink::WebArrayBuffer* buffer) { |
| 286 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesGcm, algorithm.id()); | |
| 287 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
| 288 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
| 289 | |
| 290 if (!g_aes_gcm_support.Get().IsSupported()) | 309 if (!g_aes_gcm_support.Get().IsSupported()) |
| 291 return Status::ErrorUnsupported(); | 310 return Status::ErrorUnsupported(); |
| 292 | 311 |
| 293 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 294 | |
| 295 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); | |
| 296 if (!params) | |
| 297 return Status::ErrorUnexpected(); | |
| 298 | |
| 299 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now | 312 // TODO(eroman): The spec doesn't define the default value. Assume 128 for now |
| 300 // since that is the maximum tag length: | 313 // since that is the maximum tag length: |
| 301 // http://www.w3.org/2012/webcrypto/track/issues/46 | 314 // http://www.w3.org/2012/webcrypto/track/issues/46 |
| 302 unsigned int tag_length_bits = 128; | 315 unsigned int tag_length_bits = 128; |
| 303 if (params->hasTagLengthBits()) | 316 if (params->hasTagLengthBits()) |
| 304 tag_length_bits = params->optionalTagLengthBits(); | 317 tag_length_bits = params->optionalTagLengthBits(); |
| 305 | 318 |
| 306 if (tag_length_bits > 128 || (tag_length_bits % 8) != 0) | 319 if (tag_length_bits > 128 || (tag_length_bits % 8) != 0) |
| 307 return Status::ErrorInvalidAesGcmTagLength(); | 320 return Status::ErrorInvalidAesGcmTagLength(); |
| 308 | 321 |
| 309 unsigned int tag_length_bytes = tag_length_bits / 8; | 322 unsigned int tag_length_bytes = tag_length_bits / 8; |
| 310 | 323 |
| 311 CK_GCM_PARAMS gcm_params = {0}; | 324 CK_GCM_PARAMS gcm_params = {0}; |
| 312 gcm_params.pIv = | 325 gcm_params.pIv = const_cast<unsigned char*>(params->iv().data()); |
| 313 const_cast<unsigned char*>(algorithm.aesGcmParams()->iv().data()); | 326 gcm_params.ulIvLen = params->iv().size(); |
| 314 gcm_params.ulIvLen = algorithm.aesGcmParams()->iv().size(); | |
| 315 | 327 |
| 316 gcm_params.pAAD = | 328 gcm_params.pAAD = |
| 317 const_cast<unsigned char*>(params->optionalAdditionalData().data()); | 329 const_cast<unsigned char*>(params->optionalAdditionalData().data()); |
| 318 gcm_params.ulAADLen = params->optionalAdditionalData().size(); | 330 gcm_params.ulAADLen = params->optionalAdditionalData().size(); |
| 319 | 331 |
| 320 gcm_params.ulTagBits = tag_length_bits; | 332 gcm_params.ulTagBits = tag_length_bits; |
| 321 | 333 |
| 322 SECItem param; | 334 SECItem param; |
| 323 param.type = siBuffer; | 335 param.type = siBuffer; |
| 324 param.data = reinterpret_cast<unsigned char*>(&gcm_params); | 336 param.data = reinterpret_cast<unsigned char*>(&gcm_params); |
| 325 param.len = sizeof(gcm_params); | 337 param.len = sizeof(gcm_params); |
| 326 | 338 |
| 327 unsigned int buffer_size = 0; | 339 unsigned int buffer_size = 0; |
| 328 | 340 |
| 329 // Calculate the output buffer size. | 341 // Calculate the output buffer size. |
| 330 if (encrypt) { | 342 if (encrypt) { |
| 331 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. | 343 // TODO(eroman): This is ugly, abstract away the safe integer arithmetic. |
| 332 if (data_size > (UINT_MAX - tag_length_bytes)) | 344 if (data.byte_length() > (UINT_MAX - tag_length_bytes)) |
| 333 return Status::ErrorDataTooLarge(); | 345 return Status::ErrorDataTooLarge(); |
| 334 buffer_size = data_size + tag_length_bytes; | 346 buffer_size = data.byte_length() + tag_length_bytes; |
| 335 } else { | 347 } else { |
| 336 // TODO(eroman): In theory the buffer allocated for the plain text should be | 348 // TODO(eroman): In theory the buffer allocated for the plain text should be |
| 337 // sized as |data_size - tag_length_bytes|. | 349 // sized as |data.byte_length() - tag_length_bytes|. |
| 338 // | 350 // |
| 339 // However NSS has a bug whereby it will fail if the output buffer size is | 351 // However NSS has a bug whereby it will fail if the output buffer size is |
| 340 // not at least as large as the ciphertext: | 352 // not at least as large as the ciphertext: |
| 341 // | 353 // |
| 342 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 | 354 // https://bugzilla.mozilla.org/show_bug.cgi?id=%20853674 |
| 343 // | 355 // |
| 344 // From the analysis of that bug it looks like it might be safe to pass a | 356 // From the analysis of that bug it looks like it might be safe to pass a |
| 345 // correctly sized buffer but lie about its size. Since resizing the | 357 // correctly sized buffer but lie about its size. Since resizing the |
| 346 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. | 358 // WebCryptoArrayBuffer is expensive that hack may be worth looking into. |
| 347 buffer_size = data_size; | 359 buffer_size = data.byte_length(); |
| 348 } | 360 } |
| 349 | 361 |
| 350 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); | 362 *buffer = blink::WebArrayBuffer::create(buffer_size, 1); |
| 351 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | 363 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); |
| 352 | 364 |
| 353 PK11_EncryptDecryptFunction func = | 365 PK11_EncryptDecryptFunction func = |
| 354 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() : | 366 encrypt ? g_aes_gcm_support.Get().pk11_encrypt_func() : |
| 355 g_aes_gcm_support.Get().pk11_decrypt_func(); | 367 g_aes_gcm_support.Get().pk11_decrypt_func(); |
| 356 | 368 |
| 357 unsigned int output_len = 0; | 369 unsigned int output_len = 0; |
| 358 SECStatus result = func(sym_key->key(), CKM_AES_GCM, ¶m, | 370 SECStatus result = func(key->key(), CKM_AES_GCM, ¶m, |
| 359 buffer_data, &output_len, buffer->byteLength(), | 371 buffer_data, &output_len, buffer->byteLength(), |
| 360 data, data_size); | 372 data.bytes(), data.byte_length()); |
| 361 | 373 |
| 362 if (result != SECSuccess) | 374 if (result != SECSuccess) |
| 363 return Status::Error(); | 375 return Status::Error(); |
| 364 | 376 |
| 365 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug | 377 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug |
| 366 // above). | 378 // above). |
| 367 webcrypto::ShrinkBuffer(buffer, output_len); | 379 ShrinkBuffer(buffer, output_len); |
| 368 | 380 |
| 369 return Status::Success(); | 381 return Status::Success(); |
| 370 } | 382 } |
| 371 | 383 |
| 372 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 384 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
| 373 const blink::WebCryptoAlgorithm& algorithm) { | 385 const blink::WebCryptoAlgorithm& algorithm) { |
| 374 switch (algorithm.id()) { | 386 switch (algorithm.id()) { |
| 375 case blink::WebCryptoAlgorithmIdAesCbc: | 387 case blink::WebCryptoAlgorithmIdAesCbc: |
| 376 case blink::WebCryptoAlgorithmIdAesGcm: | 388 case blink::WebCryptoAlgorithmIdAesGcm: |
| 377 case blink::WebCryptoAlgorithmIdAesKw: | 389 case blink::WebCryptoAlgorithmIdAesKw: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 404 } | 416 } |
| 405 return true; | 417 return true; |
| 406 } | 418 } |
| 407 | 419 |
| 408 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { | 420 bool IsAlgorithmRsa(const blink::WebCryptoAlgorithm& algorithm) { |
| 409 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || | 421 return algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || |
| 410 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || | 422 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep || |
| 411 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; | 423 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| 412 } | 424 } |
| 413 | 425 |
| 414 Status ImportKeyInternalRaw( | 426 } // namespace |
| 415 const unsigned char* key_data, | 427 |
| 416 unsigned int key_data_size, | 428 Status PlatformCrypto::PlatformImportKeyRaw( |
| 429 const CryptoData& key_data, |
| 417 const blink::WebCryptoAlgorithm& algorithm, | 430 const blink::WebCryptoAlgorithm& algorithm, |
| 418 bool extractable, | 431 bool extractable, |
| 419 blink::WebCryptoKeyUsageMask usage_mask, | 432 blink::WebCryptoKeyUsageMask usage_mask, |
| 420 blink::WebCryptoKey* key) { | 433 blink::WebCryptoKey* key) { |
| 421 | 434 |
| 422 DCHECK(!algorithm.isNull()); | 435 DCHECK(!algorithm.isNull()); |
| 423 | 436 |
| 424 blink::WebCryptoKeyType type; | |
| 425 switch (algorithm.id()) { | |
| 426 case blink::WebCryptoAlgorithmIdHmac: | |
| 427 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 428 case blink::WebCryptoAlgorithmIdAesKw: | |
| 429 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 430 type = blink::WebCryptoKeyTypeSecret; | |
| 431 break; | |
| 432 // TODO(bryaneyler): Support more key types. | |
| 433 default: | |
| 434 return Status::ErrorUnsupported(); | |
| 435 } | |
| 436 | |
| 437 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | 437 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. |
| 438 // Currently only supporting symmetric. | 438 // Currently only supporting symmetric. |
| 439 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | 439 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; |
| 440 // Flags are verified at the Blink layer; here the flags are set to all | 440 // Flags are verified at the Blink layer; here the flags are set to all |
| 441 // possible operations for this key type. | 441 // possible operations for this key type. |
| 442 CK_FLAGS flags = 0; | 442 CK_FLAGS flags = 0; |
| 443 | 443 |
| 444 switch (algorithm.id()) { | 444 switch (algorithm.id()) { |
| 445 case blink::WebCryptoAlgorithmIdHmac: { | 445 case blink::WebCryptoAlgorithmIdHmac: { |
| 446 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | 446 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 472 flags |= CKF_ENCRYPT | CKF_DECRYPT; | 472 flags |= CKF_ENCRYPT | CKF_DECRYPT; |
| 473 break; | 473 break; |
| 474 } | 474 } |
| 475 default: | 475 default: |
| 476 return Status::ErrorUnsupported(); | 476 return Status::ErrorUnsupported(); |
| 477 } | 477 } |
| 478 | 478 |
| 479 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | 479 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); |
| 480 DCHECK_NE(0ul, flags); | 480 DCHECK_NE(0ul, flags); |
| 481 | 481 |
| 482 SECItem key_item = { | 482 SECItem key_item = MakeSECItemForBuffer(key_data); |
| 483 siBuffer, | |
| 484 const_cast<unsigned char*>(key_data), | |
| 485 key_data_size | |
| 486 }; | |
| 487 | 483 |
| 488 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 484 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
| 489 crypto::ScopedPK11SymKey pk11_sym_key( | 485 crypto::ScopedPK11SymKey pk11_sym_key( |
| 490 PK11_ImportSymKeyWithFlags(slot.get(), | 486 PK11_ImportSymKeyWithFlags(slot.get(), |
| 491 mechanism, | 487 mechanism, |
| 492 PK11_OriginUnwrap, | 488 PK11_OriginUnwrap, |
| 493 CKA_FLAGS_ONLY, | 489 CKA_FLAGS_ONLY, |
| 494 &key_item, | 490 &key_item, |
| 495 flags, | 491 flags, |
| 496 false, | 492 false, |
| 497 NULL)); | 493 NULL)); |
| 498 if (!pk11_sym_key.get()) | 494 if (!pk11_sym_key.get()) |
| 499 return Status::Error(); | 495 return Status::Error(); |
| 500 | 496 |
| 501 *key = blink::WebCryptoKey::create(new SymKeyHandle(pk11_sym_key.Pass()), | 497 *key = blink::WebCryptoKey::create(new PlatformSymKey(pk11_sym_key.Pass()), |
| 502 type, extractable, algorithm, usage_mask); | 498 blink::WebCryptoKeyTypeSecret, |
| 499 extractable, |
| 500 algorithm, |
| 501 usage_mask); |
| 503 return Status::Success(); | 502 return Status::Success(); |
| 504 } | 503 } |
| 505 | 504 |
| 506 Status ExportKeyInternalRaw( | 505 Status PlatformCrypto::PlatformExportKeyRaw( |
| 507 const blink::WebCryptoKey& key, | 506 PlatformSymKey* key, |
| 508 blink::WebArrayBuffer* buffer) { | 507 blink::WebArrayBuffer* buffer) { |
| 509 | 508 if (PK11_ExtractKeyValue(key->key()) != SECSuccess) |
| 510 DCHECK(key.handle()); | |
| 511 DCHECK(buffer); | |
| 512 | |
| 513 if (!key.extractable()) | |
| 514 return Status::ErrorKeyNotExtractable(); | |
| 515 if (key.type() != blink::WebCryptoKeyTypeSecret) | |
| 516 return Status::ErrorUnexpectedKeyType(); | |
| 517 | |
| 518 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 519 | |
| 520 if (PK11_ExtractKeyValue(sym_key->key()) != SECSuccess) | |
| 521 return Status::Error(); | 509 return Status::Error(); |
| 522 | 510 |
| 523 const SECItem* key_data = PK11_GetKeyData(sym_key->key()); | 511 const SECItem* key_data = PK11_GetKeyData(key->key()); |
| 524 if (!key_data) | 512 if (!key_data) |
| 525 return Status::Error(); | 513 return Status::Error(); |
| 526 | 514 |
| 527 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | 515 *buffer = CreateArrayBuffer(key_data->data, key_data->len); |
| 528 | 516 |
| 529 return Status::Success(); | 517 return Status::Success(); |
| 530 } | 518 } |
| 531 | 519 |
| 520 namespace { |
| 521 |
| 532 typedef scoped_ptr<CERTSubjectPublicKeyInfo, | 522 typedef scoped_ptr<CERTSubjectPublicKeyInfo, |
| 533 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, | 523 crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, |
| 534 SECKEY_DestroySubjectPublicKeyInfo> > | 524 SECKEY_DestroySubjectPublicKeyInfo> > |
| 535 ScopedCERTSubjectPublicKeyInfo; | 525 ScopedCERTSubjectPublicKeyInfo; |
| 536 | 526 |
| 537 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes | 527 // Validates an NSS KeyType against a WebCrypto algorithm. Some NSS KeyTypes |
| 538 // contain enough information to fabricate a Web Crypto algorithm, which is | 528 // contain enough information to fabricate a Web Crypto algorithm, which is |
| 539 // returned if the input algorithm isNull(). This function indicates failure by | 529 // returned if the input algorithm isNull(). This function indicates failure by |
| 540 // returning a Null algorithm. | 530 // returning a Null algorithm. |
| 541 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( | 531 blink::WebCryptoAlgorithm ResolveNssKeyTypeWithInputAlgorithm( |
| (...skipping 15 matching lines...) Expand all Loading... |
| 557 case rsaPssKey: | 547 case rsaPssKey: |
| 558 case rsaOaepKey: | 548 case rsaOaepKey: |
| 559 // TODO(padolph): Handle other key types. | 549 // TODO(padolph): Handle other key types. |
| 560 break; | 550 break; |
| 561 default: | 551 default: |
| 562 break; | 552 break; |
| 563 } | 553 } |
| 564 return blink::WebCryptoAlgorithm::createNull(); | 554 return blink::WebCryptoAlgorithm::createNull(); |
| 565 } | 555 } |
| 566 | 556 |
| 567 Status ImportKeyInternalSpki( | 557 } // namespace |
| 568 const unsigned char* key_data, | 558 |
| 569 unsigned int key_data_size, | 559 Status PlatformCrypto::PlatformImportKeySpki( |
| 560 const CryptoData& key_data, |
| 570 const blink::WebCryptoAlgorithm& algorithm_or_null, | 561 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 571 bool extractable, | 562 bool extractable, |
| 572 blink::WebCryptoKeyUsageMask usage_mask, | 563 blink::WebCryptoKeyUsageMask usage_mask, |
| 573 blink::WebCryptoKey* key) { | 564 blink::WebCryptoKey* key) { |
| 574 | 565 |
| 575 DCHECK(key); | 566 DCHECK(key); |
| 576 | 567 |
| 577 if (!key_data_size) | 568 if (!key_data.byte_length()) |
| 578 return Status::ErrorImportEmptyKeyData(); | 569 return Status::ErrorImportEmptyKeyData(); |
| 579 DCHECK(key_data); | 570 DCHECK(key_data.bytes()); |
| 580 | 571 |
| 581 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject | 572 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 Subject |
| 582 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. | 573 // Public Key Info. Decode this to a CERTSubjectPublicKeyInfo. |
| 583 SECItem spki_item = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; | 574 SECItem spki_item = MakeSECItemForBuffer(key_data); |
| 584 const ScopedCERTSubjectPublicKeyInfo spki( | 575 const ScopedCERTSubjectPublicKeyInfo spki( |
| 585 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); | 576 SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item)); |
| 586 if (!spki) | 577 if (!spki) |
| 587 return Status::Error(); | 578 return Status::Error(); |
| 588 | 579 |
| 589 crypto::ScopedSECKEYPublicKey sec_public_key( | 580 crypto::ScopedSECKEYPublicKey sec_public_key( |
| 590 SECKEY_ExtractPublicKey(spki.get())); | 581 SECKEY_ExtractPublicKey(spki.get())); |
| 591 if (!sec_public_key) | 582 if (!sec_public_key) |
| 592 return Status::Error(); | 583 return Status::Error(); |
| 593 | 584 |
| 594 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); | 585 const KeyType sec_key_type = SECKEY_GetPublicKeyType(sec_public_key.get()); |
| 595 blink::WebCryptoAlgorithm algorithm = | 586 blink::WebCryptoAlgorithm algorithm = |
| 596 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | 587 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); |
| 597 if (algorithm.isNull()) | 588 if (algorithm.isNull()) |
| 598 return Status::Error(); | 589 return Status::Error(); |
| 599 | 590 |
| 600 *key = blink::WebCryptoKey::create( | 591 *key = blink::WebCryptoKey::create( |
| 601 new PublicKeyHandle(sec_public_key.Pass()), | 592 new PlatformPublicKey(sec_public_key.Pass()), |
| 602 blink::WebCryptoKeyTypePublic, | 593 blink::WebCryptoKeyTypePublic, |
| 603 extractable, | 594 extractable, |
| 604 algorithm, | 595 algorithm, |
| 605 usage_mask); | 596 usage_mask); |
| 606 | 597 |
| 607 return Status::Success(); | 598 return Status::Success(); |
| 608 } | 599 } |
| 609 | 600 |
| 610 Status ExportKeyInternalSpki( | 601 Status PlatformCrypto::PlatformExportKeySpki( |
| 611 const blink::WebCryptoKey& key, | 602 PlatformPublicKey* key, |
| 612 blink::WebArrayBuffer* buffer) { | 603 blink::WebArrayBuffer* buffer) { |
| 613 | |
| 614 DCHECK(key.handle()); | |
| 615 DCHECK(buffer); | |
| 616 | |
| 617 if (!key.extractable()) | |
| 618 return Status::ErrorKeyNotExtractable(); | |
| 619 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 620 return Status::ErrorUnexpectedKeyType(); | |
| 621 | |
| 622 PublicKeyHandle* const pub_key = | |
| 623 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
| 624 | |
| 625 const crypto::ScopedSECItem spki_der( | 604 const crypto::ScopedSECItem spki_der( |
| 626 SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key->key())); | 605 SECKEY_EncodeDERSubjectPublicKeyInfo(key->key())); |
| 627 if (!spki_der) | 606 if (!spki_der) |
| 628 return Status::Error(); | 607 return Status::Error(); |
| 629 | 608 |
| 630 DCHECK(spki_der->data); | 609 DCHECK(spki_der->data); |
| 631 DCHECK(spki_der->len); | 610 DCHECK(spki_der->len); |
| 632 | 611 |
| 633 *buffer = webcrypto::CreateArrayBuffer(spki_der->data, spki_der->len); | 612 *buffer = CreateArrayBuffer(spki_der->data, spki_der->len); |
| 634 | 613 |
| 635 return Status::Success(); | 614 return Status::Success(); |
| 636 } | 615 } |
| 637 | 616 |
| 638 Status ImportKeyInternalPkcs8( | 617 Status PlatformCrypto::PlatformImportKeyPkcs8( |
| 639 const unsigned char* key_data, | 618 const CryptoData& key_data, |
| 640 unsigned int key_data_size, | |
| 641 const blink::WebCryptoAlgorithm& algorithm_or_null, | 619 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 642 bool extractable, | 620 bool extractable, |
| 643 blink::WebCryptoKeyUsageMask usage_mask, | 621 blink::WebCryptoKeyUsageMask usage_mask, |
| 644 blink::WebCryptoKey* key) { | 622 blink::WebCryptoKey* key) { |
| 645 | 623 |
| 646 DCHECK(key); | 624 DCHECK(key); |
| 647 | 625 |
| 648 if (!key_data_size) | 626 if (!key_data.byte_length()) |
| 649 return Status::ErrorImportEmptyKeyData(); | 627 return Status::ErrorImportEmptyKeyData(); |
| 650 DCHECK(key_data); | 628 DCHECK(key_data.bytes()); |
| 651 | 629 |
| 652 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 | 630 // The binary blob 'key_data' is expected to be a DER-encoded ASN.1 PKCS#8 |
| 653 // private key info object. | 631 // private key info object. |
| 654 SECItem pki_der = {siBuffer, const_cast<uint8*>(key_data), key_data_size}; | 632 SECItem pki_der = MakeSECItemForBuffer(key_data); |
| 655 | 633 |
| 656 SECKEYPrivateKey* seckey_private_key = NULL; | 634 SECKEYPrivateKey* seckey_private_key = NULL; |
| 657 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); | 635 crypto::ScopedPK11Slot slot(PK11_GetInternalSlot()); |
| 658 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( | 636 if (PK11_ImportDERPrivateKeyInfoAndReturnKey( |
| 659 slot.get(), | 637 slot.get(), |
| 660 &pki_der, | 638 &pki_der, |
| 661 NULL, // nickname | 639 NULL, // nickname |
| 662 NULL, // publicValue | 640 NULL, // publicValue |
| 663 false, // isPerm | 641 false, // isPerm |
| 664 false, // isPrivate | 642 false, // isPrivate |
| 665 KU_ALL, // usage | 643 KU_ALL, // usage |
| 666 &seckey_private_key, | 644 &seckey_private_key, |
| 667 NULL) != SECSuccess) { | 645 NULL) != SECSuccess) { |
| 668 return Status::Error(); | 646 return Status::Error(); |
| 669 } | 647 } |
| 670 DCHECK(seckey_private_key); | 648 DCHECK(seckey_private_key); |
| 671 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); | 649 crypto::ScopedSECKEYPrivateKey private_key(seckey_private_key); |
| 672 | 650 |
| 673 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); | 651 const KeyType sec_key_type = SECKEY_GetPrivateKeyType(private_key.get()); |
| 674 blink::WebCryptoAlgorithm algorithm = | 652 blink::WebCryptoAlgorithm algorithm = |
| 675 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); | 653 ResolveNssKeyTypeWithInputAlgorithm(sec_key_type, algorithm_or_null); |
| 676 if (algorithm.isNull()) | 654 if (algorithm.isNull()) |
| 677 return Status::Error(); | 655 return Status::Error(); |
| 678 | 656 |
| 679 *key = blink::WebCryptoKey::create( | 657 *key = blink::WebCryptoKey::create( |
| 680 new PrivateKeyHandle(private_key.Pass()), | 658 new PlatformPrivateKey(private_key.Pass()), |
| 681 blink::WebCryptoKeyTypePrivate, | 659 blink::WebCryptoKeyTypePrivate, |
| 682 extractable, | 660 extractable, |
| 683 algorithm, | 661 algorithm, |
| 684 usage_mask); | 662 usage_mask); |
| 685 | 663 |
| 686 return Status::Success(); | 664 return Status::Success(); |
| 687 } | 665 } |
| 688 | 666 |
| 689 // ----------------------------------- | 667 // ----------------------------------- |
| 690 // Hmac | 668 // Hmac |
| 691 // ----------------------------------- | 669 // ----------------------------------- |
| 692 | 670 |
| 693 Status SignHmac( | 671 Status PlatformCrypto::PlatformSignHmac( |
| 694 const blink::WebCryptoAlgorithm& algorithm, | 672 PlatformSymKey* key, |
| 695 const blink::WebCryptoKey& key, | 673 const blink::WebCryptoAlgorithm& hash, |
| 696 const unsigned char* data, | 674 const CryptoData& data, |
| 697 unsigned int data_size, | |
| 698 blink::WebArrayBuffer* buffer) { | 675 blink::WebArrayBuffer* buffer) { |
| 699 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); | 676 DCHECK_EQ(PK11_GetMechanism(key->key()), WebCryptoHashToHMACMechanism(hash)); |
| 700 | |
| 701 const blink::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
| 702 if (!params) | |
| 703 return Status::ErrorUnexpected(); | |
| 704 | |
| 705 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 706 | |
| 707 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | |
| 708 WebCryptoHashToHMACMechanism(params->hash())); | |
| 709 | 677 |
| 710 SECItem param_item = { siBuffer, NULL, 0 }; | 678 SECItem param_item = { siBuffer, NULL, 0 }; |
| 711 SECItem data_item = { | 679 SECItem data_item = MakeSECItemForBuffer(data); |
| 712 siBuffer, | |
| 713 const_cast<unsigned char*>(data), | |
| 714 data_size | |
| 715 }; | |
| 716 // First call is to figure out the length. | 680 // First call is to figure out the length. |
| 717 SECItem signature_item = { siBuffer, NULL, 0 }; | 681 SECItem signature_item = { siBuffer, NULL, 0 }; |
| 718 | 682 |
| 719 if (PK11_SignWithSymKey(sym_key->key(), | 683 if (PK11_SignWithSymKey(key->key(), |
| 720 PK11_GetMechanism(sym_key->key()), | 684 PK11_GetMechanism(key->key()), |
| 721 ¶m_item, | 685 ¶m_item, |
| 722 &signature_item, | 686 &signature_item, |
| 723 &data_item) != SECSuccess) { | 687 &data_item) != SECSuccess) { |
| 724 return Status::Error(); | 688 return Status::Error(); |
| 725 } | 689 } |
| 726 | 690 |
| 727 DCHECK_NE(0u, signature_item.len); | 691 DCHECK_NE(0u, signature_item.len); |
| 728 | 692 |
| 729 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); | 693 *buffer = blink::WebArrayBuffer::create(signature_item.len, 1); |
| 730 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); | 694 signature_item.data = reinterpret_cast<unsigned char*>(buffer->data()); |
| 731 | 695 |
| 732 if (PK11_SignWithSymKey(sym_key->key(), | 696 if (PK11_SignWithSymKey(key->key(), |
| 733 PK11_GetMechanism(sym_key->key()), | 697 PK11_GetMechanism(key->key()), |
| 734 ¶m_item, | 698 ¶m_item, |
| 735 &signature_item, | 699 &signature_item, |
| 736 &data_item) != SECSuccess) { | 700 &data_item) != SECSuccess) { |
| 737 return Status::Error(); | 701 return Status::Error(); |
| 738 } | 702 } |
| 739 | 703 |
| 740 DCHECK_EQ(buffer->byteLength(), signature_item.len); | 704 DCHECK_EQ(buffer->byteLength(), signature_item.len); |
| 741 return Status::Success(); | 705 return Status::Success(); |
| 742 } | 706 } |
| 743 | 707 |
| 744 Status VerifyHmac( | |
| 745 const blink::WebCryptoAlgorithm& algorithm, | |
| 746 const blink::WebCryptoKey& key, | |
| 747 const unsigned char* signature, | |
| 748 unsigned int signature_size, | |
| 749 const unsigned char* data, | |
| 750 unsigned int data_size, | |
| 751 bool* signature_match) { | |
| 752 DCHECK_EQ(blink::WebCryptoAlgorithmIdHmac, algorithm.id()); | |
| 753 | |
| 754 blink::WebArrayBuffer result; | |
| 755 Status status = SignHmac(algorithm, key, data, data_size, &result); | |
| 756 if (status.IsError()) | |
| 757 return status; | |
| 758 | |
| 759 // Handling of truncated signatures is underspecified in the WebCrypto | |
| 760 // spec, so here we fail verification if a truncated signature is being | |
| 761 // verified. | |
| 762 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | |
| 763 *signature_match = | |
| 764 result.byteLength() == signature_size && | |
| 765 crypto::SecureMemEqual(result.data(), signature, signature_size); | |
| 766 | |
| 767 return Status::Success(); | |
| 768 } | |
| 769 | |
| 770 // ----------------------------------- | 708 // ----------------------------------- |
| 771 // RsaEsPkcs1v1_5 | 709 // RsaEsPkcs1v1_5 |
| 772 // ----------------------------------- | 710 // ----------------------------------- |
| 773 | 711 |
| 774 Status EncryptRsaEsPkcs1v1_5( | 712 Status PlatformCrypto::PlatformEncryptRsaEsPkcs1v1_5( |
| 775 const blink::WebCryptoAlgorithm& algorithm, | 713 PlatformPublicKey* key, |
| 776 const blink::WebCryptoKey& key, | 714 const CryptoData& data, |
| 777 const unsigned char* data, | |
| 778 unsigned int data_size, | |
| 779 blink::WebArrayBuffer* buffer) { | 715 blink::WebArrayBuffer* buffer) { |
| 780 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id()); | |
| 781 | |
| 782 // RSAES encryption does not support empty input | |
| 783 if (!data_size) | |
| 784 return Status::Error(); | |
| 785 DCHECK(data); | |
| 786 | |
| 787 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 788 return Status::ErrorUnexpectedKeyType(); | |
| 789 | |
| 790 PublicKeyHandle* const public_key = | |
| 791 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
| 792 | |
| 793 const unsigned int encrypted_length_bytes = | 716 const unsigned int encrypted_length_bytes = |
| 794 SECKEY_PublicKeyStrength(public_key->key()); | 717 SECKEY_PublicKeyStrength(key->key()); |
| 795 | 718 |
| 796 // RSAES can operate on messages up to a length of k - 11, where k is the | 719 // RSAES can operate on messages up to a length of k - 11, where k is the |
| 797 // octet length of the RSA modulus. | 720 // octet length of the RSA modulus. |
| 798 if (encrypted_length_bytes < 11 || encrypted_length_bytes - 11 < data_size) | 721 if (encrypted_length_bytes < 11 || |
| 722 encrypted_length_bytes - 11 < data.byte_length()) |
| 799 return Status::ErrorDataTooLarge(); | 723 return Status::ErrorDataTooLarge(); |
| 800 | 724 |
| 801 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); | 725 *buffer = blink::WebArrayBuffer::create(encrypted_length_bytes, 1); |
| 802 unsigned char* const buffer_data = | 726 unsigned char* const buffer_data = |
| 803 reinterpret_cast<unsigned char*>(buffer->data()); | 727 reinterpret_cast<unsigned char*>(buffer->data()); |
| 804 | 728 |
| 805 if (PK11_PubEncryptPKCS1(public_key->key(), | 729 if (PK11_PubEncryptPKCS1(key->key(), |
| 806 buffer_data, | 730 buffer_data, |
| 807 const_cast<unsigned char*>(data), | 731 const_cast<unsigned char*>(data.bytes()), |
| 808 data_size, | 732 data.byte_length(), |
| 809 NULL) != SECSuccess) { | 733 NULL) != SECSuccess) { |
| 810 return Status::Error(); | 734 return Status::Error(); |
| 811 } | 735 } |
| 812 return Status::Success(); | 736 return Status::Success(); |
| 813 } | 737 } |
| 814 | 738 |
| 815 Status DecryptRsaEsPkcs1v1_5( | 739 Status PlatformCrypto::PlatformDecryptRsaEsPkcs1v1_5( |
| 816 const blink::WebCryptoAlgorithm& algorithm, | 740 PlatformPrivateKey* key, |
| 817 const blink::WebCryptoKey& key, | 741 const CryptoData& data, |
| 818 const unsigned char* data, | |
| 819 unsigned int data_size, | |
| 820 blink::WebArrayBuffer* buffer) { | 742 blink::WebArrayBuffer* buffer) { |
| 821 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5, algorithm.id()); | 743 const int modulus_length_bytes = PK11_GetPrivateModulusLen(key->key()); |
| 822 | |
| 823 // RSAES decryption does not support empty input | |
| 824 if (!data_size) | |
| 825 return Status::Error(); | |
| 826 DCHECK(data); | |
| 827 | |
| 828 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
| 829 return Status::ErrorUnexpectedKeyType(); | |
| 830 | |
| 831 PrivateKeyHandle* const private_key = | |
| 832 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
| 833 | |
| 834 const int modulus_length_bytes = | |
| 835 PK11_GetPrivateModulusLen(private_key->key()); | |
| 836 if (modulus_length_bytes <= 0) | 744 if (modulus_length_bytes <= 0) |
| 837 return Status::ErrorUnexpected(); | 745 return Status::ErrorUnexpected(); |
| 838 const unsigned int max_output_length_bytes = modulus_length_bytes; | 746 const unsigned int max_output_length_bytes = modulus_length_bytes; |
| 839 | 747 |
| 840 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); | 748 *buffer = blink::WebArrayBuffer::create(max_output_length_bytes, 1); |
| 841 unsigned char* const buffer_data = | 749 unsigned char* const buffer_data = |
| 842 reinterpret_cast<unsigned char*>(buffer->data()); | 750 reinterpret_cast<unsigned char*>(buffer->data()); |
| 843 | 751 |
| 844 unsigned int output_length_bytes = 0; | 752 unsigned int output_length_bytes = 0; |
| 845 if (PK11_PrivDecryptPKCS1(private_key->key(), | 753 if (PK11_PrivDecryptPKCS1(key->key(), |
| 846 buffer_data, | 754 buffer_data, |
| 847 &output_length_bytes, | 755 &output_length_bytes, |
| 848 max_output_length_bytes, | 756 max_output_length_bytes, |
| 849 const_cast<unsigned char*>(data), | 757 const_cast<unsigned char*>(data.bytes()), |
| 850 data_size) != SECSuccess) { | 758 data.byte_length()) != SECSuccess) { |
| 851 return Status::Error(); | 759 return Status::Error(); |
| 852 } | 760 } |
| 853 DCHECK_LE(output_length_bytes, max_output_length_bytes); | 761 DCHECK_LE(output_length_bytes, max_output_length_bytes); |
| 854 webcrypto::ShrinkBuffer(buffer, output_length_bytes); | 762 ShrinkBuffer(buffer, output_length_bytes); |
| 855 return Status::Success(); | 763 return Status::Success(); |
| 856 } | 764 } |
| 857 | 765 |
| 858 // ----------------------------------- | 766 // ----------------------------------- |
| 859 // RsaSsaPkcs1v1_5 | 767 // RsaSsaPkcs1v1_5 |
| 860 // ----------------------------------- | 768 // ----------------------------------- |
| 861 | 769 |
| 862 Status SignRsaSsaPkcs1v1_5( | 770 Status PlatformCrypto::PlatformSignRsaSsaPkcs1v1_5( |
| 863 const blink::WebCryptoAlgorithm& algorithm, | 771 PlatformPrivateKey* key, |
| 864 const blink::WebCryptoKey& key, | 772 const blink::WebCryptoAlgorithm& hash, |
| 865 const unsigned char* data, | 773 const CryptoData& data, |
| 866 unsigned int data_size, | |
| 867 blink::WebArrayBuffer* buffer) { | 774 blink::WebArrayBuffer* buffer) { |
| 868 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id()); | |
| 869 | |
| 870 if (key.type() != blink::WebCryptoKeyTypePrivate) | |
| 871 return Status::ErrorUnexpectedKeyType(); | |
| 872 | |
| 873 if (webcrypto::GetInnerHashAlgorithm(algorithm).isNull()) | |
| 874 return Status::ErrorUnexpected(); | |
| 875 | |
| 876 PrivateKeyHandle* const private_key = | |
| 877 reinterpret_cast<PrivateKeyHandle*>(key.handle()); | |
| 878 DCHECK(private_key); | |
| 879 DCHECK(private_key->key()); | |
| 880 | |
| 881 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the | 775 // Pick the NSS signing algorithm by combining RSA-SSA (RSA PKCS1) and the |
| 882 // inner hash of the input Web Crypto algorithm. | 776 // inner hash of the input Web Crypto algorithm. |
| 883 SECOidTag sign_alg_tag; | 777 SECOidTag sign_alg_tag; |
| 884 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) { | 778 switch (hash.id()) { |
| 885 case blink::WebCryptoAlgorithmIdSha1: | 779 case blink::WebCryptoAlgorithmIdSha1: |
| 886 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; | 780 sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; |
| 887 break; | 781 break; |
| 888 case blink::WebCryptoAlgorithmIdSha224: | 782 case blink::WebCryptoAlgorithmIdSha224: |
| 889 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; | 783 sign_alg_tag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; |
| 890 break; | 784 break; |
| 891 case blink::WebCryptoAlgorithmIdSha256: | 785 case blink::WebCryptoAlgorithmIdSha256: |
| 892 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; | 786 sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; |
| 893 break; | 787 break; |
| 894 case blink::WebCryptoAlgorithmIdSha384: | 788 case blink::WebCryptoAlgorithmIdSha384: |
| 895 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; | 789 sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; |
| 896 break; | 790 break; |
| 897 case blink::WebCryptoAlgorithmIdSha512: | 791 case blink::WebCryptoAlgorithmIdSha512: |
| 898 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; | 792 sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; |
| 899 break; | 793 break; |
| 900 default: | 794 default: |
| 901 return Status::ErrorUnsupported(); | 795 return Status::ErrorUnsupported(); |
| 902 } | 796 } |
| 903 | 797 |
| 904 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); | 798 crypto::ScopedSECItem signature_item(SECITEM_AllocItem(NULL, NULL, 0)); |
| 905 if (SEC_SignData(signature_item.get(), | 799 if (SEC_SignData(signature_item.get(), |
| 906 data, | 800 data.bytes(), |
| 907 data_size, | 801 data.byte_length(), |
| 908 private_key->key(), | 802 key->key(), |
| 909 sign_alg_tag) != SECSuccess) { | 803 sign_alg_tag) != SECSuccess) { |
| 910 return Status::Error(); | 804 return Status::Error(); |
| 911 } | 805 } |
| 912 | 806 |
| 913 *buffer = webcrypto::CreateArrayBuffer(signature_item->data, | 807 *buffer = CreateArrayBuffer(signature_item->data, signature_item->len); |
| 914 signature_item->len); | |
| 915 return Status::Success(); | 808 return Status::Success(); |
| 916 } | 809 } |
| 917 | 810 |
| 918 Status VerifyRsaSsaPkcs1v1_5( | 811 Status PlatformCrypto::PlatformVerifyRsaSsaPkcs1v1_5( |
| 919 const blink::WebCryptoAlgorithm& algorithm, | 812 PlatformPublicKey* key, |
| 920 const blink::WebCryptoKey& key, | 813 const blink::WebCryptoAlgorithm& hash, |
| 921 const unsigned char* signature, | 814 const CryptoData& signature, |
| 922 unsigned int signature_size, | 815 const CryptoData& data, |
| 923 const unsigned char* data, | |
| 924 unsigned int data_size, | |
| 925 bool* signature_match) { | 816 bool* signature_match) { |
| 926 DCHECK_EQ(blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, algorithm.id()); | 817 const SECItem signature_item = MakeSECItemForBuffer(signature); |
| 927 | |
| 928 if (key.type() != blink::WebCryptoKeyTypePublic) | |
| 929 return Status::ErrorUnexpectedKeyType(); | |
| 930 | |
| 931 PublicKeyHandle* const public_key = | |
| 932 reinterpret_cast<PublicKeyHandle*>(key.handle()); | |
| 933 DCHECK(public_key); | |
| 934 DCHECK(public_key->key()); | |
| 935 | |
| 936 const SECItem signature_item = { | |
| 937 siBuffer, | |
| 938 const_cast<unsigned char*>(signature), | |
| 939 signature_size | |
| 940 }; | |
| 941 | 818 |
| 942 SECOidTag hash_alg_tag; | 819 SECOidTag hash_alg_tag; |
| 943 switch (webcrypto::GetInnerHashAlgorithm(algorithm).id()) { | 820 switch (hash.id()) { |
| 944 case blink::WebCryptoAlgorithmIdSha1: | 821 case blink::WebCryptoAlgorithmIdSha1: |
| 945 hash_alg_tag = SEC_OID_SHA1; | 822 hash_alg_tag = SEC_OID_SHA1; |
| 946 break; | 823 break; |
| 947 case blink::WebCryptoAlgorithmIdSha224: | 824 case blink::WebCryptoAlgorithmIdSha224: |
| 948 hash_alg_tag = SEC_OID_SHA224; | 825 hash_alg_tag = SEC_OID_SHA224; |
| 949 break; | 826 break; |
| 950 case blink::WebCryptoAlgorithmIdSha256: | 827 case blink::WebCryptoAlgorithmIdSha256: |
| 951 hash_alg_tag = SEC_OID_SHA256; | 828 hash_alg_tag = SEC_OID_SHA256; |
| 952 break; | 829 break; |
| 953 case blink::WebCryptoAlgorithmIdSha384: | 830 case blink::WebCryptoAlgorithmIdSha384: |
| 954 hash_alg_tag = SEC_OID_SHA384; | 831 hash_alg_tag = SEC_OID_SHA384; |
| 955 break; | 832 break; |
| 956 case blink::WebCryptoAlgorithmIdSha512: | 833 case blink::WebCryptoAlgorithmIdSha512: |
| 957 hash_alg_tag = SEC_OID_SHA512; | 834 hash_alg_tag = SEC_OID_SHA512; |
| 958 break; | 835 break; |
| 959 default: | 836 default: |
| 960 return Status::ErrorUnsupported(); | 837 return Status::ErrorUnsupported(); |
| 961 } | 838 } |
| 962 | 839 |
| 963 *signature_match = | 840 *signature_match = |
| 964 SECSuccess == VFY_VerifyDataDirect(data, | 841 SECSuccess == VFY_VerifyDataDirect(data.bytes(), |
| 965 data_size, | 842 data.byte_length(), |
| 966 public_key->key(), | 843 key->key(), |
| 967 &signature_item, | 844 &signature_item, |
| 968 SEC_OID_PKCS1_RSA_ENCRYPTION, | 845 SEC_OID_PKCS1_RSA_ENCRYPTION, |
| 969 hash_alg_tag, | 846 hash_alg_tag, |
| 970 NULL, | 847 NULL, |
| 971 NULL); | 848 NULL); |
| 972 return Status::Success(); | 849 return Status::Success(); |
| 973 } | 850 } |
| 974 | 851 |
| 852 Status PlatformCrypto::PlatformEncryptAesCbc(PlatformSymKey* key, |
| 853 const CryptoData& iv, |
| 854 const CryptoData& data, |
| 855 blink::WebArrayBuffer* buffer) { |
| 856 return AesCbcEncryptDecrypt(CKA_ENCRYPT, key, iv, data, buffer); |
| 857 } |
| 858 |
| 859 Status PlatformCrypto::PlatformDecryptAesCbc(PlatformSymKey* key, |
| 860 const CryptoData& iv, |
| 861 const CryptoData& data, |
| 862 blink::WebArrayBuffer* buffer) { |
| 863 return AesCbcEncryptDecrypt(CKA_DECRYPT, key, iv, data, buffer); |
| 864 } |
| 865 |
| 866 Status PlatformCrypto::PlatformEncryptAesGcm( |
| 867 PlatformSymKey* key, |
| 868 const blink::WebCryptoAesGcmParams* params, |
| 869 const CryptoData& data, |
| 870 blink::WebArrayBuffer* buffer) { |
| 871 return AesGcmEncryptDecrypt(true, key, params, data, buffer); |
| 872 } |
| 873 |
| 874 Status PlatformCrypto::PlatformDecryptAesGcm( |
| 875 PlatformSymKey* key, |
| 876 const blink::WebCryptoAesGcmParams* params, |
| 877 const CryptoData& data, |
| 878 blink::WebArrayBuffer* buffer) { |
| 879 return AesGcmEncryptDecrypt(false, key, params, data, buffer); |
| 880 } |
| 881 |
| 975 // ----------------------------------- | 882 // ----------------------------------- |
| 976 // Key generation | 883 // Key generation |
| 977 // ----------------------------------- | 884 // ----------------------------------- |
| 978 | 885 |
| 979 Status GenerateRsaKeyPair( | 886 Status PlatformCrypto::PlatformGenerateRsaKeyPair( |
| 980 const blink::WebCryptoAlgorithm& algorithm, | 887 const blink::WebCryptoAlgorithm& algorithm, |
| 981 bool extractable, | 888 bool extractable, |
| 982 blink::WebCryptoKeyUsageMask usage_mask, | 889 blink::WebCryptoKeyUsageMask usage_mask, |
| 983 blink::WebCryptoKey* public_key, | 890 blink::WebCryptoKey* public_key, |
| 984 blink::WebCryptoKey* private_key) { | 891 blink::WebCryptoKey* private_key) { |
| 985 const blink::WebCryptoRsaKeyGenParams* const params = | 892 const blink::WebCryptoRsaKeyGenParams* const params = |
| 986 algorithm.rsaKeyGenParams(); | 893 algorithm.rsaKeyGenParams(); |
| 987 DCHECK(params); | 894 DCHECK(params); |
| 988 | 895 |
| 989 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | 896 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 &rsa_gen_params, | 940 &rsa_gen_params, |
| 1034 &sec_public_key, | 941 &sec_public_key, |
| 1035 attribute_flags, | 942 attribute_flags, |
| 1036 operation_flags, | 943 operation_flags, |
| 1037 operation_flags_mask, | 944 operation_flags_mask, |
| 1038 NULL)); | 945 NULL)); |
| 1039 if (!private_key) | 946 if (!private_key) |
| 1040 return Status::Error(); | 947 return Status::Error(); |
| 1041 | 948 |
| 1042 *public_key = blink::WebCryptoKey::create( | 949 *public_key = blink::WebCryptoKey::create( |
| 1043 new PublicKeyHandle(crypto::ScopedSECKEYPublicKey(sec_public_key)), | 950 new PlatformPublicKey(crypto::ScopedSECKEYPublicKey(sec_public_key)), |
| 1044 blink::WebCryptoKeyTypePublic, | 951 blink::WebCryptoKeyTypePublic, |
| 1045 true, | 952 true, |
| 1046 algorithm, | 953 algorithm, |
| 1047 usage_mask); | 954 usage_mask); |
| 1048 *private_key = blink::WebCryptoKey::create( | 955 *private_key = blink::WebCryptoKey::create( |
| 1049 new PrivateKeyHandle(scoped_sec_private_key.Pass()), | 956 new PlatformPrivateKey(scoped_sec_private_key.Pass()), |
| 1050 blink::WebCryptoKeyTypePrivate, | 957 blink::WebCryptoKeyTypePrivate, |
| 1051 extractable, | 958 extractable, |
| 1052 algorithm, | 959 algorithm, |
| 1053 usage_mask); | 960 usage_mask); |
| 1054 | 961 |
| 1055 return Status::Success(); | 962 return Status::Success(); |
| 1056 } | 963 } |
| 1057 | 964 |
| 1058 // Get the secret key length in bytes from generation parameters. This resolves | 965 PlatformCrypto::PlatformCrypto() { |
| 1059 // any defaults. | |
| 1060 Status GetGenerateSecretKeyLength(const blink::WebCryptoAlgorithm& algorithm, | |
| 1061 unsigned int* keylen_bytes) { | |
| 1062 *keylen_bytes = 0; | |
| 1063 | |
| 1064 switch (algorithm.id()) { | |
| 1065 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 1066 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 1067 case blink::WebCryptoAlgorithmIdAesKw: { | |
| 1068 const blink::WebCryptoAesKeyGenParams* params = | |
| 1069 algorithm.aesKeyGenParams(); | |
| 1070 DCHECK(params); | |
| 1071 // Ensure the key length is a multiple of 8 bits. Let NSS verify further | |
| 1072 // algorithm-specific length restrictions. | |
| 1073 if (params->lengthBits() % 8) | |
| 1074 return Status::ErrorGenerateKeyLength(); | |
| 1075 *keylen_bytes = params->lengthBits() / 8; | |
| 1076 break; | |
| 1077 } | |
| 1078 case blink::WebCryptoAlgorithmIdHmac: { | |
| 1079 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); | |
| 1080 DCHECK(params); | |
| 1081 if (params->hasLengthBytes()) | |
| 1082 *keylen_bytes = params->optionalLengthBytes(); | |
| 1083 else | |
| 1084 *keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id()); | |
| 1085 break; | |
| 1086 } | |
| 1087 | |
| 1088 default: | |
| 1089 return Status::ErrorUnsupported(); | |
| 1090 } | |
| 1091 | |
| 1092 if (*keylen_bytes == 0) | |
| 1093 return Status::ErrorGenerateKeyLength(); | |
| 1094 | |
| 1095 return Status::Success(); | |
| 1096 } | |
| 1097 | |
| 1098 } // namespace | |
| 1099 | |
| 1100 void WebCryptoImpl::Init() { | |
| 1101 crypto::EnsureNSSInit(); | 966 crypto::EnsureNSSInit(); |
| 1102 } | 967 } |
| 1103 | 968 |
| 1104 Status WebCryptoImpl::EncryptInternal( | 969 Status PlatformCrypto::PlatformDigestSha( |
| 1105 const blink::WebCryptoAlgorithm& algorithm, | 970 blink::WebCryptoAlgorithmId algorithm, |
| 1106 const blink::WebCryptoKey& key, | 971 const CryptoData& data, |
| 1107 const unsigned char* data, | |
| 1108 unsigned int data_size, | |
| 1109 blink::WebArrayBuffer* buffer) { | |
| 1110 | |
| 1111 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
| 1112 DCHECK(key.handle()); | |
| 1113 DCHECK(buffer); | |
| 1114 | |
| 1115 switch (algorithm.id()) { | |
| 1116 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 1117 return AesCbcEncryptDecrypt( | |
| 1118 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | |
| 1119 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 1120 return AesGcmEncryptDecrypt( | |
| 1121 true, algorithm, key, data, data_size, buffer); | |
| 1122 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
| 1123 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
| 1124 default: | |
| 1125 return Status::ErrorUnsupported(); | |
| 1126 } | |
| 1127 } | |
| 1128 | |
| 1129 Status WebCryptoImpl::DecryptInternal( | |
| 1130 const blink::WebCryptoAlgorithm& algorithm, | |
| 1131 const blink::WebCryptoKey& key, | |
| 1132 const unsigned char* data, | |
| 1133 unsigned int data_size, | |
| 1134 blink::WebArrayBuffer* buffer) { | |
| 1135 | |
| 1136 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | |
| 1137 DCHECK(key.handle()); | |
| 1138 DCHECK(buffer); | |
| 1139 | |
| 1140 switch (algorithm.id()) { | |
| 1141 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 1142 return AesCbcEncryptDecrypt( | |
| 1143 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | |
| 1144 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 1145 return AesGcmEncryptDecrypt( | |
| 1146 false, algorithm, key, data, data_size, buffer); | |
| 1147 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
| 1148 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
| 1149 default: | |
| 1150 return Status::ErrorUnsupported(); | |
| 1151 } | |
| 1152 } | |
| 1153 | |
| 1154 Status WebCryptoImpl::DigestInternal( | |
| 1155 const blink::WebCryptoAlgorithm& algorithm, | |
| 1156 const unsigned char* data, | |
| 1157 unsigned int data_size, | |
| 1158 blink::WebArrayBuffer* buffer) { | 972 blink::WebArrayBuffer* buffer) { |
| 1159 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | 973 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); |
| 1160 if (hash_type == HASH_AlgNULL) | 974 if (hash_type == HASH_AlgNULL) |
| 1161 return Status::ErrorUnsupported(); | 975 return Status::ErrorUnsupported(); |
| 1162 | 976 |
| 1163 HASHContext* context = HASH_Create(hash_type); | 977 HASHContext* context = HASH_Create(hash_type); |
| 1164 if (!context) | 978 if (!context) |
| 1165 return Status::Error(); | 979 return Status::Error(); |
| 1166 | 980 |
| 1167 HASH_Begin(context); | 981 HASH_Begin(context); |
| 1168 | 982 |
| 1169 HASH_Update(context, data, data_size); | 983 HASH_Update(context, data.bytes(), data.byte_length()); |
| 1170 | 984 |
| 1171 unsigned int hash_result_length = HASH_ResultLenContext(context); | 985 unsigned int hash_result_length = HASH_ResultLenContext(context); |
| 1172 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | 986 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); |
| 1173 | 987 |
| 1174 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); | 988 *buffer = blink::WebArrayBuffer::create(hash_result_length, 1); |
| 1175 | 989 |
| 1176 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | 990 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); |
| 1177 | 991 |
| 1178 unsigned int result_length = 0; | 992 unsigned int result_length = 0; |
| 1179 HASH_End(context, digest, &result_length, hash_result_length); | 993 HASH_End(context, digest, &result_length, hash_result_length); |
| 1180 | 994 |
| 1181 HASH_Destroy(context); | 995 HASH_Destroy(context); |
| 1182 | 996 |
| 1183 if (result_length != hash_result_length) | 997 if (result_length != hash_result_length) |
| 1184 return Status::ErrorUnexpected(); | 998 return Status::ErrorUnexpected(); |
| 1185 return Status::Success(); | 999 return Status::Success(); |
| 1186 } | 1000 } |
| 1187 | 1001 |
| 1188 Status WebCryptoImpl::GenerateSecretKeyInternal( | 1002 Status PlatformCrypto::PlatformGenerateSecretKey( |
| 1189 const blink::WebCryptoAlgorithm& algorithm, | 1003 const blink::WebCryptoAlgorithm& algorithm, |
| 1190 bool extractable, | 1004 bool extractable, |
| 1191 blink::WebCryptoKeyUsageMask usage_mask, | 1005 blink::WebCryptoKeyUsageMask usage_mask, |
| 1006 unsigned keylen_bytes, |
| 1192 blink::WebCryptoKey* key) { | 1007 blink::WebCryptoKey* key) { |
| 1193 | |
| 1194 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); | 1008 CK_MECHANISM_TYPE mech = WebCryptoAlgorithmToGenMechanism(algorithm); |
| 1195 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; | 1009 blink::WebCryptoKeyType key_type = blink::WebCryptoKeyTypeSecret; |
| 1196 | 1010 |
| 1197 if (mech == CKM_INVALID_MECHANISM) | 1011 if (mech == CKM_INVALID_MECHANISM) |
| 1198 return Status::ErrorUnsupported(); | 1012 return Status::ErrorUnsupported(); |
| 1199 | 1013 |
| 1200 unsigned int keylen_bytes = 0; | |
| 1201 Status status = GetGenerateSecretKeyLength(algorithm, &keylen_bytes); | |
| 1202 if (status.IsError()) | |
| 1203 return status; | |
| 1204 | |
| 1205 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); | 1014 crypto::ScopedPK11Slot slot(PK11_GetInternalKeySlot()); |
| 1206 if (!slot) | 1015 if (!slot) |
| 1207 return Status::Error(); | 1016 return Status::Error(); |
| 1208 | 1017 |
| 1209 crypto::ScopedPK11SymKey pk11_key( | 1018 crypto::ScopedPK11SymKey pk11_key( |
| 1210 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); | 1019 PK11_KeyGen(slot.get(), mech, NULL, keylen_bytes, NULL)); |
| 1211 | 1020 |
| 1212 if (!pk11_key) | 1021 if (!pk11_key) |
| 1213 return Status::Error(); | 1022 return Status::Error(); |
| 1214 | 1023 |
| 1215 *key = blink::WebCryptoKey::create( | 1024 *key = blink::WebCryptoKey::create(new PlatformSymKey(pk11_key.Pass()), |
| 1216 new SymKeyHandle(pk11_key.Pass()), | 1025 key_type, |
| 1217 key_type, extractable, algorithm, usage_mask); | 1026 extractable, |
| 1027 algorithm, |
| 1028 usage_mask); |
| 1218 return Status::Success(); | 1029 return Status::Success(); |
| 1219 } | 1030 } |
| 1220 | 1031 |
| 1221 Status WebCryptoImpl::GenerateKeyPairInternal( | 1032 Status PlatformCrypto::PlatformImportRsaPublicKey( |
| 1222 const blink::WebCryptoAlgorithm& algorithm, | 1033 const CryptoData& modulus_data, |
| 1223 bool extractable, | 1034 const CryptoData& exponent_data, |
| 1224 blink::WebCryptoKeyUsageMask usage_mask, | |
| 1225 blink::WebCryptoKey* public_key, | |
| 1226 blink::WebCryptoKey* private_key) { | |
| 1227 | |
| 1228 // TODO(padolph): Handle other asymmetric algorithm key generation. | |
| 1229 switch (algorithm.id()) { | |
| 1230 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: | |
| 1231 case blink::WebCryptoAlgorithmIdRsaOaep: | |
| 1232 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
| 1233 return GenerateRsaKeyPair(algorithm, extractable, usage_mask, | |
| 1234 public_key, private_key); | |
| 1235 default: | |
| 1236 return Status::ErrorUnsupported(); | |
| 1237 } | |
| 1238 } | |
| 1239 | |
| 1240 Status WebCryptoImpl::ImportKeyInternal( | |
| 1241 blink::WebCryptoKeyFormat format, | |
| 1242 const unsigned char* key_data, | |
| 1243 unsigned int key_data_size, | |
| 1244 const blink::WebCryptoAlgorithm& algorithm_or_null, | |
| 1245 bool extractable, | |
| 1246 blink::WebCryptoKeyUsageMask usage_mask, | |
| 1247 blink::WebCryptoKey* key) { | |
| 1248 | |
| 1249 switch (format) { | |
| 1250 case blink::WebCryptoKeyFormatRaw: | |
| 1251 // A 'raw'-formatted key import requires an input algorithm. | |
| 1252 if (algorithm_or_null.isNull()) | |
| 1253 return Status::ErrorMissingAlgorithmImportRawKey(); | |
| 1254 return ImportKeyInternalRaw(key_data, | |
| 1255 key_data_size, | |
| 1256 algorithm_or_null, | |
| 1257 extractable, | |
| 1258 usage_mask, | |
| 1259 key); | |
| 1260 case blink::WebCryptoKeyFormatSpki: | |
| 1261 return ImportKeyInternalSpki(key_data, | |
| 1262 key_data_size, | |
| 1263 algorithm_or_null, | |
| 1264 extractable, | |
| 1265 usage_mask, | |
| 1266 key); | |
| 1267 case blink::WebCryptoKeyFormatPkcs8: | |
| 1268 return ImportKeyInternalPkcs8(key_data, | |
| 1269 key_data_size, | |
| 1270 algorithm_or_null, | |
| 1271 extractable, | |
| 1272 usage_mask, | |
| 1273 key); | |
| 1274 default: | |
| 1275 // NOTE: blink::WebCryptoKeyFormatJwk is handled one level above. | |
| 1276 return Status::ErrorUnsupported(); | |
| 1277 } | |
| 1278 } | |
| 1279 | |
| 1280 Status WebCryptoImpl::ExportKeyInternal( | |
| 1281 blink::WebCryptoKeyFormat format, | |
| 1282 const blink::WebCryptoKey& key, | |
| 1283 blink::WebArrayBuffer* buffer) { | |
| 1284 switch (format) { | |
| 1285 case blink::WebCryptoKeyFormatRaw: | |
| 1286 return ExportKeyInternalRaw(key, buffer); | |
| 1287 case blink::WebCryptoKeyFormatSpki: | |
| 1288 return ExportKeyInternalSpki(key, buffer); | |
| 1289 case blink::WebCryptoKeyFormatPkcs8: | |
| 1290 // TODO(padolph): Implement pkcs8 export | |
| 1291 return Status::ErrorUnsupported(); | |
| 1292 default: | |
| 1293 return Status::ErrorUnsupported(); | |
| 1294 } | |
| 1295 } | |
| 1296 | |
| 1297 Status WebCryptoImpl::SignInternal( | |
| 1298 const blink::WebCryptoAlgorithm& algorithm, | |
| 1299 const blink::WebCryptoKey& key, | |
| 1300 const unsigned char* data, | |
| 1301 unsigned int data_size, | |
| 1302 blink::WebArrayBuffer* buffer) { | |
| 1303 | |
| 1304 // Note: It is not an error to sign empty data. | |
| 1305 | |
| 1306 DCHECK(buffer); | |
| 1307 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | |
| 1308 | |
| 1309 switch (algorithm.id()) { | |
| 1310 case blink::WebCryptoAlgorithmIdHmac: | |
| 1311 return SignHmac(algorithm, key, data, data_size, buffer); | |
| 1312 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
| 1313 return SignRsaSsaPkcs1v1_5(algorithm, key, data, data_size, buffer); | |
| 1314 default: | |
| 1315 return Status::ErrorUnsupported(); | |
| 1316 } | |
| 1317 } | |
| 1318 | |
| 1319 Status WebCryptoImpl::VerifySignatureInternal( | |
| 1320 const blink::WebCryptoAlgorithm& algorithm, | |
| 1321 const blink::WebCryptoKey& key, | |
| 1322 const unsigned char* signature, | |
| 1323 unsigned int signature_size, | |
| 1324 const unsigned char* data, | |
| 1325 unsigned int data_size, | |
| 1326 bool* signature_match) { | |
| 1327 | |
| 1328 if (!signature_size) { | |
| 1329 // None of the algorithms generate valid zero-length signatures so this | |
| 1330 // will necessarily fail verification. Early return to protect | |
| 1331 // implementations from dealing with a NULL signature pointer. | |
| 1332 *signature_match = false; | |
| 1333 return Status::Success(); | |
| 1334 } | |
| 1335 | |
| 1336 DCHECK(signature); | |
| 1337 | |
| 1338 switch (algorithm.id()) { | |
| 1339 case blink::WebCryptoAlgorithmIdHmac: | |
| 1340 return VerifyHmac(algorithm, key, signature, signature_size, | |
| 1341 data, data_size, signature_match); | |
| 1342 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
| 1343 return VerifyRsaSsaPkcs1v1_5(algorithm, key, signature, signature_size, | |
| 1344 data, data_size, signature_match); | |
| 1345 default: | |
| 1346 return Status::ErrorUnsupported(); | |
| 1347 } | |
| 1348 } | |
| 1349 | |
| 1350 Status WebCryptoImpl::ImportRsaPublicKeyInternal( | |
| 1351 const unsigned char* modulus_data, | |
| 1352 unsigned int modulus_size, | |
| 1353 const unsigned char* exponent_data, | |
| 1354 unsigned int exponent_size, | |
| 1355 const blink::WebCryptoAlgorithm& algorithm, | 1035 const blink::WebCryptoAlgorithm& algorithm, |
| 1356 bool extractable, | 1036 bool extractable, |
| 1357 blink::WebCryptoKeyUsageMask usage_mask, | 1037 blink::WebCryptoKeyUsageMask usage_mask, |
| 1358 blink::WebCryptoKey* key) { | 1038 blink::WebCryptoKey* key) { |
| 1359 | 1039 |
| 1360 if (!modulus_size) | 1040 if (!modulus_data.byte_length()) |
| 1361 return Status::ErrorImportRsaEmptyModulus(); | 1041 return Status::ErrorImportRsaEmptyModulus(); |
| 1362 | 1042 |
| 1363 if (!exponent_size) | 1043 if (!exponent_data.byte_length()) |
| 1364 return Status::ErrorImportRsaEmptyExponent(); | 1044 return Status::ErrorImportRsaEmptyExponent(); |
| 1365 | 1045 |
| 1366 DCHECK(modulus_data); | 1046 DCHECK(modulus_data.bytes()); |
| 1367 DCHECK(exponent_data); | 1047 DCHECK(exponent_data.bytes()); |
| 1368 | 1048 |
| 1369 // NSS does not provide a way to create an RSA public key directly from the | 1049 // NSS does not provide a way to create an RSA public key directly from the |
| 1370 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob | 1050 // modulus and exponent values, but it can import an DER-encoded ASN.1 blob |
| 1371 // with these values and create the public key from that. The code below | 1051 // with these values and create the public key from that. The code below |
| 1372 // follows the recommendation described in | 1052 // follows the recommendation described in |
| 1373 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 | 1053 // https://developer.mozilla.org/en-US/docs/NSS/NSS_Tech_Notes/nss_tech_note7 |
| 1374 | 1054 |
| 1375 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and | 1055 // Pack the input values into a struct compatible with NSS ASN.1 encoding, and |
| 1376 // set up an ASN.1 encoder template for it. | 1056 // set up an ASN.1 encoder template for it. |
| 1377 struct RsaPublicKeyData { | 1057 struct RsaPublicKeyData { |
| 1378 SECItem modulus; | 1058 SECItem modulus; |
| 1379 SECItem exponent; | 1059 SECItem exponent; |
| 1380 }; | 1060 }; |
| 1381 const RsaPublicKeyData pubkey_in = { | 1061 const RsaPublicKeyData pubkey_in = { |
| 1382 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data), | 1062 {siUnsignedInteger, const_cast<unsigned char*>(modulus_data.bytes()), |
| 1383 modulus_size}, | 1063 modulus_data.byte_length()}, |
| 1384 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data), | 1064 {siUnsignedInteger, const_cast<unsigned char*>(exponent_data.bytes()), |
| 1385 exponent_size}}; | 1065 exponent_data.byte_length()}}; |
| 1386 const SEC_ASN1Template rsa_public_key_template[] = { | 1066 const SEC_ASN1Template rsa_public_key_template[] = { |
| 1387 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, | 1067 {SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RsaPublicKeyData)}, |
| 1388 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, | 1068 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, modulus), }, |
| 1389 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, | 1069 {SEC_ASN1_INTEGER, offsetof(RsaPublicKeyData, exponent), }, |
| 1390 {0, }}; | 1070 {0, }}; |
| 1391 | 1071 |
| 1392 // DER-encode the public key. | 1072 // DER-encode the public key. |
| 1393 crypto::ScopedSECItem pubkey_der(SEC_ASN1EncodeItem( | 1073 crypto::ScopedSECItem pubkey_der( |
| 1394 NULL, NULL, &pubkey_in, rsa_public_key_template)); | 1074 SEC_ASN1EncodeItem(NULL, NULL, &pubkey_in, rsa_public_key_template)); |
| 1395 if (!pubkey_der) | 1075 if (!pubkey_der) |
| 1396 return Status::Error(); | 1076 return Status::Error(); |
| 1397 | 1077 |
| 1398 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. | 1078 // Import the DER-encoded public key to create an RSA SECKEYPublicKey. |
| 1399 crypto::ScopedSECKEYPublicKey pubkey( | 1079 crypto::ScopedSECKEYPublicKey pubkey( |
| 1400 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); | 1080 SECKEY_ImportDERPublicKey(pubkey_der.get(), CKK_RSA)); |
| 1401 if (!pubkey) | 1081 if (!pubkey) |
| 1402 return Status::Error(); | 1082 return Status::Error(); |
| 1403 | 1083 |
| 1404 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1084 *key = blink::WebCryptoKey::create(new PlatformPublicKey(pubkey.Pass()), |
| 1405 blink::WebCryptoKeyTypePublic, | 1085 blink::WebCryptoKeyTypePublic, |
| 1406 extractable, | 1086 extractable, |
| 1407 algorithm, | 1087 algorithm, |
| 1408 usage_mask); | 1088 usage_mask); |
| 1409 return Status::Success(); | 1089 return Status::Success(); |
| 1410 } | 1090 } |
| 1411 | 1091 |
| 1092 } // namespace webcrypto |
| 1412 } // namespace content | 1093 } // namespace content |
| OLD | NEW |