| 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/webcrypto_impl.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 #include <openssl/aes.h> | 8 #include <openssl/aes.h> |
| 9 #include <openssl/evp.h> | 9 #include <openssl/evp.h> |
| 10 #include <openssl/hmac.h> | 10 #include <openssl/hmac.h> |
| 11 #include <openssl/rand.h> | 11 #include <openssl/rand.h> |
| 12 #include <openssl/sha.h> | 12 #include <openssl/sha.h> |
| 13 | 13 |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "content/renderer/webcrypto/webcrypto_util.h" | 15 #include "content/renderer/webcrypto/webcrypto_util.h" |
| 16 #include "crypto/openssl_util.h" | 16 #include "crypto/openssl_util.h" |
| 17 #include "crypto/secure_util.h" | 17 #include "crypto/secure_util.h" |
| 18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 18 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 19 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| 21 | 21 |
| 22 namespace content { | 22 namespace content { |
| 23 | 23 |
| 24 using webcrypto::Status; |
| 25 |
| 24 namespace { | 26 namespace { |
| 25 | 27 |
| 26 class SymKeyHandle : public blink::WebCryptoKeyHandle { | 28 class SymKeyHandle : public blink::WebCryptoKeyHandle { |
| 27 public: | 29 public: |
| 28 SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) | 30 SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) |
| 29 : key_(key_data, key_data + key_data_size) {} | 31 : key_(key_data, key_data + key_data_size) {} |
| 30 | 32 |
| 31 const std::vector<unsigned char>& key() const { return key_; } | 33 const std::vector<unsigned char>& key() const { return key_; } |
| 32 | 34 |
| 33 private: | 35 private: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 49 return NULL; | 51 return NULL; |
| 50 } | 52 } |
| 51 } | 53 } |
| 52 | 54 |
| 53 // OpenSSL constants for EVP_CipherInit_ex(), do not change | 55 // OpenSSL constants for EVP_CipherInit_ex(), do not change |
| 54 enum CipherOperation { | 56 enum CipherOperation { |
| 55 kDoDecrypt = 0, | 57 kDoDecrypt = 0, |
| 56 kDoEncrypt = 1 | 58 kDoEncrypt = 1 |
| 57 }; | 59 }; |
| 58 | 60 |
| 59 bool AesCbcEncryptDecrypt(CipherOperation cipher_operation, | 61 Status AesCbcEncryptDecrypt(CipherOperation cipher_operation, |
| 60 const blink::WebCryptoAlgorithm& algorithm, | 62 const blink::WebCryptoAlgorithm& algorithm, |
| 61 const blink::WebCryptoKey& key, | 63 const blink::WebCryptoKey& key, |
| 62 const unsigned char* data, | 64 const unsigned char* data, |
| 63 unsigned data_size, | 65 unsigned data_size, |
| 64 blink::WebArrayBuffer* buffer) { | 66 blink::WebArrayBuffer* buffer) { |
| 65 | 67 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesCbc, algorithm.id()); |
| 66 // TODO(padolph): Handle other encrypt operations and then remove this gate | |
| 67 if (algorithm.id() != blink::WebCryptoAlgorithmIdAesCbc) | |
| 68 return false; | |
| 69 | |
| 70 DCHECK_EQ(algorithm.id(), key.algorithm().id()); | 68 DCHECK_EQ(algorithm.id(), key.algorithm().id()); |
| 71 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | 69 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); |
| 72 | 70 |
| 73 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { | 71 if (data_size >= INT_MAX - AES_BLOCK_SIZE) { |
| 74 // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right | 72 // TODO(padolph): Handle this by chunking the input fed into OpenSSL. Right |
| 75 // now it doesn't make much difference since the one-shot API would end up | 73 // now it doesn't make much difference since the one-shot API would end up |
| 76 // blowing out the memory and crashing anyway. However a newer version of | 74 // blowing out the memory and crashing anyway. |
| 77 // the spec allows for a sequence<CryptoData> so this will be relevant. | 75 return Status::ErrorDataTooLarge(); |
| 78 return false; | |
| 79 } | 76 } |
| 80 | 77 |
| 81 // Note: PKCS padding is enabled by default | 78 // Note: PKCS padding is enabled by default |
| 82 crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context( | 79 crypto::ScopedOpenSSL<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> context( |
| 83 EVP_CIPHER_CTX_new()); | 80 EVP_CIPHER_CTX_new()); |
| 84 | 81 |
| 85 if (!context.get()) | 82 if (!context.get()) |
| 86 return false; | 83 return Status::Error(); |
| 87 | 84 |
| 88 SymKeyHandle* const sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 85 SymKeyHandle* const sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 89 | 86 |
| 90 const EVP_CIPHER* const cipher = | 87 const EVP_CIPHER* const cipher = |
| 91 GetAESCipherByKeyLength(sym_key->key().size()); | 88 GetAESCipherByKeyLength(sym_key->key().size()); |
| 92 DCHECK(cipher); | 89 DCHECK(cipher); |
| 93 | 90 |
| 94 const blink::WebCryptoAesCbcParams* const params = algorithm.aesCbcParams(); | 91 const blink::WebCryptoAesCbcParams* const params = algorithm.aesCbcParams(); |
| 95 if (params->iv().size() != AES_BLOCK_SIZE) | 92 if (params->iv().size() != AES_BLOCK_SIZE) |
| 96 return false; | 93 return Status::ErrorIncorrectSizeAesCbcIv(); |
| 97 | 94 |
| 98 if (!EVP_CipherInit_ex(context.get(), | 95 if (!EVP_CipherInit_ex(context.get(), |
| 99 cipher, | 96 cipher, |
| 100 NULL, | 97 NULL, |
| 101 &sym_key->key()[0], | 98 &sym_key->key()[0], |
| 102 params->iv().data(), | 99 params->iv().data(), |
| 103 cipher_operation)) { | 100 cipher_operation)) { |
| 104 return false; | 101 return Status::Error(); |
| 105 } | 102 } |
| 106 | 103 |
| 107 // According to the openssl docs, the amount of data written may be as large | 104 // According to the openssl docs, the amount of data written may be as large |
| 108 // as (data_size + cipher_block_size - 1), constrained to a multiple of | 105 // as (data_size + cipher_block_size - 1), constrained to a multiple of |
| 109 // cipher_block_size. | 106 // cipher_block_size. |
| 110 unsigned output_max_len = data_size + AES_BLOCK_SIZE - 1; | 107 unsigned output_max_len = data_size + AES_BLOCK_SIZE - 1; |
| 111 const unsigned remainder = output_max_len % AES_BLOCK_SIZE; | 108 const unsigned remainder = output_max_len % AES_BLOCK_SIZE; |
| 112 if (remainder != 0) | 109 if (remainder != 0) |
| 113 output_max_len += AES_BLOCK_SIZE - remainder; | 110 output_max_len += AES_BLOCK_SIZE - remainder; |
| 114 DCHECK_GT(output_max_len, data_size); | 111 DCHECK_GT(output_max_len, data_size); |
| 115 | 112 |
| 116 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); | 113 *buffer = blink::WebArrayBuffer::create(output_max_len, 1); |
| 117 | 114 |
| 118 unsigned char* const buffer_data = | 115 unsigned char* const buffer_data = |
| 119 reinterpret_cast<unsigned char*>(buffer->data()); | 116 reinterpret_cast<unsigned char*>(buffer->data()); |
| 120 | 117 |
| 121 int output_len = 0; | 118 int output_len = 0; |
| 122 if (!EVP_CipherUpdate( | 119 if (!EVP_CipherUpdate( |
| 123 context.get(), buffer_data, &output_len, data, data_size)) | 120 context.get(), buffer_data, &output_len, data, data_size)) |
| 124 return false; | 121 return Status::Error(); |
| 125 int final_output_chunk_len = 0; | 122 int final_output_chunk_len = 0; |
| 126 if (!EVP_CipherFinal_ex( | 123 if (!EVP_CipherFinal_ex( |
| 127 context.get(), buffer_data + output_len, &final_output_chunk_len)) | 124 context.get(), buffer_data + output_len, &final_output_chunk_len)) |
| 128 return false; | 125 return Status::Error(); |
| 129 | 126 |
| 130 const unsigned final_output_len = | 127 const unsigned final_output_len = |
| 131 static_cast<unsigned>(output_len) + | 128 static_cast<unsigned>(output_len) + |
| 132 static_cast<unsigned>(final_output_chunk_len); | 129 static_cast<unsigned>(final_output_chunk_len); |
| 133 DCHECK_LE(final_output_len, output_max_len); | 130 DCHECK_LE(final_output_len, output_max_len); |
| 134 | 131 |
| 135 webcrypto::ShrinkBuffer(buffer, final_output_len); | 132 webcrypto::ShrinkBuffer(buffer, final_output_len); |
| 136 | 133 |
| 137 return true; | 134 return Status::Success(); |
| 138 } | 135 } |
| 139 | 136 |
| 140 bool ExportKeyInternalRaw( | 137 Status ExportKeyInternalRaw( |
| 141 const blink::WebCryptoKey& key, | 138 const blink::WebCryptoKey& key, |
| 142 blink::WebArrayBuffer* buffer) { | 139 blink::WebArrayBuffer* buffer) { |
| 143 | 140 |
| 144 DCHECK(key.handle()); | 141 DCHECK(key.handle()); |
| 145 DCHECK(buffer); | 142 DCHECK(buffer); |
| 146 | 143 |
| 147 if (key.type() != blink::WebCryptoKeyTypeSecret || !key.extractable()) | 144 if (key.type() != blink::WebCryptoKeyTypeSecret) |
| 148 return false; | 145 return Status::ErrorUnexpectedKeyType(); |
| 146 |
| 147 // TODO(eroman): This should be in a more generic location. |
| 148 if (!key.extractable()) |
| 149 return Status::ErrorKeyNotExtractable(); |
| 149 | 150 |
| 150 const SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | 151 const SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 151 | 152 |
| 152 *buffer = webcrypto::CreateArrayBuffer( | 153 *buffer = webcrypto::CreateArrayBuffer( |
| 153 webcrypto::Uint8VectorStart(sym_key->key()), sym_key->key().size()); | 154 webcrypto::Uint8VectorStart(sym_key->key()), sym_key->key().size()); |
| 154 | 155 |
| 155 return true; | 156 return Status::Success(); |
| 156 } | 157 } |
| 157 | 158 |
| 158 } // namespace | 159 } // namespace |
| 159 | 160 |
| 160 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } | 161 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } |
| 161 | 162 |
| 162 bool WebCryptoImpl::EncryptInternal(const blink::WebCryptoAlgorithm& algorithm, | 163 Status WebCryptoImpl::EncryptInternal( |
| 163 const blink::WebCryptoKey& key, | 164 const blink::WebCryptoAlgorithm& algorithm, |
| 164 const unsigned char* data, | 165 const blink::WebCryptoKey& key, |
| 165 unsigned data_size, | 166 const unsigned char* data, |
| 166 blink::WebArrayBuffer* buffer) { | 167 unsigned data_size, |
| 168 blink::WebArrayBuffer* buffer) { |
| 167 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 169 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 168 return AesCbcEncryptDecrypt( | 170 return AesCbcEncryptDecrypt( |
| 169 kDoEncrypt, algorithm, key, data, data_size, buffer); | 171 kDoEncrypt, algorithm, key, data, data_size, buffer); |
| 170 } | 172 } |
| 171 | 173 |
| 172 return false; | 174 return Status::ErrorUnsupported(); |
| 173 } | 175 } |
| 174 | 176 |
| 175 bool WebCryptoImpl::DecryptInternal(const blink::WebCryptoAlgorithm& algorithm, | 177 Status WebCryptoImpl::DecryptInternal( |
| 176 const blink::WebCryptoKey& key, | 178 const blink::WebCryptoAlgorithm& algorithm, |
| 177 const unsigned char* data, | 179 const blink::WebCryptoKey& key, |
| 178 unsigned data_size, | 180 const unsigned char* data, |
| 179 blink::WebArrayBuffer* buffer) { | 181 unsigned data_size, |
| 182 blink::WebArrayBuffer* buffer) { |
| 180 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 183 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
| 181 return AesCbcEncryptDecrypt( | 184 return AesCbcEncryptDecrypt( |
| 182 kDoDecrypt, algorithm, key, data, data_size, buffer); | 185 kDoDecrypt, algorithm, key, data, data_size, buffer); |
| 183 } | 186 } |
| 184 | 187 |
| 185 return false; | 188 return Status::ErrorUnsupported(); |
| 186 } | 189 } |
| 187 | 190 |
| 188 bool WebCryptoImpl::DigestInternal(const blink::WebCryptoAlgorithm& algorithm, | 191 Status WebCryptoImpl::DigestInternal(const blink::WebCryptoAlgorithm& algorithm, |
| 189 const unsigned char* data, | 192 const unsigned char* data, |
| 190 unsigned data_size, | 193 unsigned data_size, |
| 191 blink::WebArrayBuffer* buffer) { | 194 blink::WebArrayBuffer* buffer) { |
| 192 | 195 |
| 193 crypto::OpenSSLErrStackTracer(FROM_HERE); | 196 crypto::OpenSSLErrStackTracer(FROM_HERE); |
| 194 | 197 |
| 195 const EVP_MD* digest_algorithm; | 198 const EVP_MD* digest_algorithm; |
| 196 switch (algorithm.id()) { | 199 switch (algorithm.id()) { |
| 197 case blink::WebCryptoAlgorithmIdSha1: | 200 case blink::WebCryptoAlgorithmIdSha1: |
| 198 digest_algorithm = EVP_sha1(); | 201 digest_algorithm = EVP_sha1(); |
| 199 break; | 202 break; |
| 200 case blink::WebCryptoAlgorithmIdSha224: | 203 case blink::WebCryptoAlgorithmIdSha224: |
| 201 digest_algorithm = EVP_sha224(); | 204 digest_algorithm = EVP_sha224(); |
| 202 break; | 205 break; |
| 203 case blink::WebCryptoAlgorithmIdSha256: | 206 case blink::WebCryptoAlgorithmIdSha256: |
| 204 digest_algorithm = EVP_sha256(); | 207 digest_algorithm = EVP_sha256(); |
| 205 break; | 208 break; |
| 206 case blink::WebCryptoAlgorithmIdSha384: | 209 case blink::WebCryptoAlgorithmIdSha384: |
| 207 digest_algorithm = EVP_sha384(); | 210 digest_algorithm = EVP_sha384(); |
| 208 break; | 211 break; |
| 209 case blink::WebCryptoAlgorithmIdSha512: | 212 case blink::WebCryptoAlgorithmIdSha512: |
| 210 digest_algorithm = EVP_sha512(); | 213 digest_algorithm = EVP_sha512(); |
| 211 break; | 214 break; |
| 212 default: | 215 default: |
| 213 // Not a digest algorithm. | 216 // Not a digest algorithm. |
| 214 return false; | 217 return Status::ErrorUnsupported(); |
| 215 } | 218 } |
| 216 | 219 |
| 217 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( | 220 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( |
| 218 EVP_MD_CTX_create()); | 221 EVP_MD_CTX_create()); |
| 219 if (!digest_context.get()) { | 222 if (!digest_context.get()) { |
| 220 return false; | 223 return Status::Error(); |
| 221 } | 224 } |
| 222 | 225 |
| 223 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || | 226 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || |
| 224 !EVP_DigestUpdate(digest_context.get(), data, data_size)) { | 227 !EVP_DigestUpdate(digest_context.get(), data, data_size)) { |
| 225 return false; | 228 return Status::Error(); |
| 226 } | 229 } |
| 227 | 230 |
| 228 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); | 231 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); |
| 229 if (hash_expected_size <= 0) { | 232 if (hash_expected_size <= 0) { |
| 230 return false; | 233 return Status::ErrorUnexpected(); |
| 231 } | 234 } |
| 232 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); | 235 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); |
| 233 | 236 |
| 234 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); | 237 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); |
| 235 unsigned char* const hash_buffer = | 238 unsigned char* const hash_buffer = |
| 236 reinterpret_cast<unsigned char* const>(buffer->data()); | 239 reinterpret_cast<unsigned char* const>(buffer->data()); |
| 237 | 240 |
| 238 unsigned hash_size = 0; | 241 unsigned hash_size = 0; |
| 239 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || | 242 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || |
| 240 static_cast<int>(hash_size) != hash_expected_size) { | 243 static_cast<int>(hash_size) != hash_expected_size) { |
| 241 buffer->reset(); | 244 buffer->reset(); |
| 242 return false; | 245 return Status::Error(); |
| 243 } | 246 } |
| 244 | 247 |
| 245 return true; | 248 return Status::Success(); |
| 246 } | 249 } |
| 247 | 250 |
| 248 bool WebCryptoImpl::GenerateKeyInternal( | 251 Status WebCryptoImpl::GenerateKeyInternal( |
| 249 const blink::WebCryptoAlgorithm& algorithm, | 252 const blink::WebCryptoAlgorithm& algorithm, |
| 250 bool extractable, | 253 bool extractable, |
| 251 blink::WebCryptoKeyUsageMask usage_mask, | 254 blink::WebCryptoKeyUsageMask usage_mask, |
| 252 blink::WebCryptoKey* key) { | 255 blink::WebCryptoKey* key) { |
| 253 | 256 |
| 254 unsigned keylen_bytes = 0; | 257 unsigned keylen_bytes = 0; |
| 255 blink::WebCryptoKeyType key_type; | 258 blink::WebCryptoKeyType key_type; |
| 256 switch (algorithm.id()) { | 259 switch (algorithm.id()) { |
| 257 case blink::WebCryptoAlgorithmIdAesCbc: { | 260 case blink::WebCryptoAlgorithmIdAesCbc: { |
| 258 const blink::WebCryptoAesKeyGenParams* params = | 261 const blink::WebCryptoAesKeyGenParams* params = |
| 259 algorithm.aesKeyGenParams(); | 262 algorithm.aesKeyGenParams(); |
| 260 DCHECK(params); | 263 DCHECK(params); |
| 261 if (params->lengthBits() % 8) | 264 if (params->lengthBits() % 8) |
| 262 return false; | 265 return Status::ErrorGenerateKeyLength(); |
| 263 keylen_bytes = params->lengthBits() / 8; | 266 keylen_bytes = params->lengthBits() / 8; |
| 264 if (!GetAESCipherByKeyLength(keylen_bytes)) { | 267 if (!GetAESCipherByKeyLength(keylen_bytes)) { |
| 265 return false; | 268 return Status::Error(); |
| 266 } | 269 } |
| 267 key_type = blink::WebCryptoKeyTypeSecret; | 270 key_type = blink::WebCryptoKeyTypeSecret; |
| 268 break; | 271 break; |
| 269 } | 272 } |
| 270 case blink::WebCryptoAlgorithmIdHmac: { | 273 case blink::WebCryptoAlgorithmIdHmac: { |
| 271 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); | 274 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams(); |
| 272 DCHECK(params); | 275 DCHECK(params); |
| 273 if (params->hasLengthBytes()) { | 276 if (params->hasLengthBytes()) { |
| 274 keylen_bytes = params->optionalLengthBytes(); | 277 keylen_bytes = params->optionalLengthBytes(); |
| 275 } else { | 278 } else { |
| 276 keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id()); | 279 keylen_bytes = webcrypto::ShaBlockSizeBytes(params->hash().id()); |
| 277 } | 280 } |
| 278 key_type = blink::WebCryptoKeyTypeSecret; | 281 key_type = blink::WebCryptoKeyTypeSecret; |
| 279 break; | 282 break; |
| 280 } | 283 } |
| 281 | 284 |
| 282 default: { return false; } | 285 default: { return Status::ErrorUnsupported(); } |
| 283 } | 286 } |
| 284 | 287 |
| 285 if (keylen_bytes == 0) { | 288 if (keylen_bytes == 0) { |
| 286 return false; | 289 return Status::ErrorGenerateKeyLength(); |
| 287 } | 290 } |
| 288 | 291 |
| 289 crypto::OpenSSLErrStackTracer(FROM_HERE); | 292 crypto::OpenSSLErrStackTracer(FROM_HERE); |
| 290 | 293 |
| 291 std::vector<unsigned char> random_bytes(keylen_bytes, 0); | 294 std::vector<unsigned char> random_bytes(keylen_bytes, 0); |
| 292 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) { | 295 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) { |
| 293 return false; | 296 return Status::Error(); |
| 294 } | 297 } |
| 295 | 298 |
| 296 *key = blink::WebCryptoKey::create( | 299 *key = blink::WebCryptoKey::create( |
| 297 new SymKeyHandle(&random_bytes[0], random_bytes.size()), | 300 new SymKeyHandle(&random_bytes[0], random_bytes.size()), |
| 298 key_type, extractable, algorithm, usage_mask); | 301 key_type, extractable, algorithm, usage_mask); |
| 299 | 302 |
| 300 return true; | 303 return Status::Success(); |
| 301 } | 304 } |
| 302 | 305 |
| 303 bool WebCryptoImpl::GenerateKeyPairInternal( | 306 Status WebCryptoImpl::GenerateKeyPairInternal( |
| 304 const blink::WebCryptoAlgorithm& algorithm, | 307 const blink::WebCryptoAlgorithm& algorithm, |
| 305 bool extractable, | 308 bool extractable, |
| 306 blink::WebCryptoKeyUsageMask usage_mask, | 309 blink::WebCryptoKeyUsageMask usage_mask, |
| 307 blink::WebCryptoKey* public_key, | 310 blink::WebCryptoKey* public_key, |
| 308 blink::WebCryptoKey* private_key) { | 311 blink::WebCryptoKey* private_key) { |
| 309 // TODO(padolph): Placeholder for OpenSSL implementation. | 312 // TODO(padolph): Placeholder for OpenSSL implementation. |
| 310 // Issue http://crbug.com/267888. | 313 // Issue http://crbug.com/267888. |
| 311 return false; | 314 return Status::ErrorUnsupported(); |
| 312 } | 315 } |
| 313 | 316 |
| 314 bool WebCryptoImpl::ImportKeyInternal( | 317 Status WebCryptoImpl::ImportKeyInternal( |
| 315 blink::WebCryptoKeyFormat format, | 318 blink::WebCryptoKeyFormat format, |
| 316 const unsigned char* key_data, | 319 const unsigned char* key_data, |
| 317 unsigned key_data_size, | 320 unsigned key_data_size, |
| 318 const blink::WebCryptoAlgorithm& algorithm_or_null, | 321 const blink::WebCryptoAlgorithm& algorithm_or_null, |
| 319 bool extractable, | 322 bool extractable, |
| 320 blink::WebCryptoKeyUsageMask usage_mask, | 323 blink::WebCryptoKeyUsageMask usage_mask, |
| 321 blink::WebCryptoKey* key) { | 324 blink::WebCryptoKey* key) { |
| 322 // TODO(eroman): Currently expects algorithm to always be specified, as it is | 325 // TODO(eroman): Currently expects algorithm to always be specified, as it is |
| 323 // required for raw format. | 326 // required for raw format. |
| 324 if (algorithm_or_null.isNull()) | 327 if (algorithm_or_null.isNull()) |
| 325 return false; | 328 return Status::ErrorMissingAlgorithmImportRawKey(); |
| 326 const blink::WebCryptoAlgorithm& algorithm = algorithm_or_null; | 329 const blink::WebCryptoAlgorithm& algorithm = algorithm_or_null; |
| 327 | 330 |
| 328 // TODO(padolph): Support all relevant alg types and then remove this gate. | 331 // TODO(padolph): Support all relevant alg types and then remove this gate. |
| 329 if (algorithm.id() != blink::WebCryptoAlgorithmIdHmac && | 332 if (algorithm.id() != blink::WebCryptoAlgorithmIdHmac && |
| 330 algorithm.id() != blink::WebCryptoAlgorithmIdAesCbc) { | 333 algorithm.id() != blink::WebCryptoAlgorithmIdAesCbc) { |
| 331 return false; | 334 return Status::ErrorUnsupported(); |
| 332 } | 335 } |
| 333 | 336 |
| 334 // TODO(padolph): Need to split handling for symmetric (raw format) and | 337 // TODO(padolph): Need to split handling for symmetric (raw format) and |
| 335 // asymmetric (spki or pkcs8 format) keys. | 338 // asymmetric (spki or pkcs8 format) keys. |
| 336 // Currently only supporting symmetric. | 339 // Currently only supporting symmetric. |
| 337 | 340 |
| 338 // Symmetric keys are always type secret | 341 // Symmetric keys are always type secret |
| 339 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret; | 342 blink::WebCryptoKeyType type = blink::WebCryptoKeyTypeSecret; |
| 340 | 343 |
| 341 const unsigned char* raw_key_data; | 344 const unsigned char* raw_key_data; |
| 342 unsigned raw_key_data_size; | 345 unsigned raw_key_data_size; |
| 343 switch (format) { | 346 switch (format) { |
| 344 case blink::WebCryptoKeyFormatRaw: | 347 case blink::WebCryptoKeyFormatRaw: |
| 345 raw_key_data = key_data; | 348 raw_key_data = key_data; |
| 346 raw_key_data_size = key_data_size; | 349 raw_key_data_size = key_data_size; |
| 347 // The NSS implementation fails when importing a raw AES key with a length | 350 // The NSS implementation fails when importing a raw AES key with a length |
| 348 // incompatible with AES. The line below is to match this behavior. | 351 // incompatible with AES. The line below is to match this behavior. |
| 349 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc && | 352 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc && |
| 350 !GetAESCipherByKeyLength(raw_key_data_size)) { | 353 !GetAESCipherByKeyLength(raw_key_data_size)) { |
| 351 return false; | 354 return Status::Error(); |
| 352 } | 355 } |
| 353 break; | 356 break; |
| 354 case blink::WebCryptoKeyFormatJwk: | 357 case blink::WebCryptoKeyFormatJwk: |
| 355 // TODO(padolph): Handle jwk format; need simple JSON parser. | 358 return Status::ErrorUnexpected(); |
| 356 // break; | |
| 357 return false; | |
| 358 default: | 359 default: |
| 359 return false; | 360 return Status::ErrorUnsupported(); |
| 360 } | 361 } |
| 361 | 362 |
| 362 *key = blink::WebCryptoKey::create( | 363 *key = blink::WebCryptoKey::create( |
| 363 new SymKeyHandle(raw_key_data, raw_key_data_size), | 364 new SymKeyHandle(raw_key_data, raw_key_data_size), |
| 364 type, extractable, algorithm, usage_mask); | 365 type, extractable, algorithm, usage_mask); |
| 365 | 366 |
| 366 return true; | 367 return Status::Success(); |
| 367 } | 368 } |
| 368 | 369 |
| 369 bool WebCryptoImpl::ExportKeyInternal( | 370 Status WebCryptoImpl::ExportKeyInternal( |
| 370 blink::WebCryptoKeyFormat format, | 371 blink::WebCryptoKeyFormat format, |
| 371 const blink::WebCryptoKey& key, | 372 const blink::WebCryptoKey& key, |
| 372 blink::WebArrayBuffer* buffer) { | 373 blink::WebArrayBuffer* buffer) { |
| 373 switch (format) { | 374 switch (format) { |
| 374 case blink::WebCryptoKeyFormatRaw: | 375 case blink::WebCryptoKeyFormatRaw: |
| 375 return ExportKeyInternalRaw(key, buffer); | 376 return ExportKeyInternalRaw(key, buffer); |
| 376 case blink::WebCryptoKeyFormatSpki: | 377 case blink::WebCryptoKeyFormatSpki: |
| 377 // TODO(padolph): Implement spki export | 378 // TODO(padolph): Implement spki export |
| 378 return false; | 379 return Status::ErrorUnsupported(); |
| 379 case blink::WebCryptoKeyFormatPkcs8: | 380 case blink::WebCryptoKeyFormatPkcs8: |
| 380 // TODO(padolph): Implement pkcs8 export | 381 // TODO(padolph): Implement pkcs8 export |
| 381 return false; | 382 return Status::ErrorUnsupported(); |
| 382 default: | 383 default: |
| 383 return false; | 384 return Status::ErrorUnsupported(); |
| 384 } | 385 } |
| 385 return false; | 386 return Status::ErrorUnsupported(); |
| 386 } | 387 } |
| 387 | 388 |
| 388 bool WebCryptoImpl::SignInternal( | 389 Status WebCryptoImpl::SignInternal( |
| 389 const blink::WebCryptoAlgorithm& algorithm, | 390 const blink::WebCryptoAlgorithm& algorithm, |
| 390 const blink::WebCryptoKey& key, | 391 const blink::WebCryptoKey& key, |
| 391 const unsigned char* data, | 392 const unsigned char* data, |
| 392 unsigned data_size, | 393 unsigned data_size, |
| 393 blink::WebArrayBuffer* buffer) { | 394 blink::WebArrayBuffer* buffer) { |
| 394 | 395 |
| 395 blink::WebArrayBuffer result; | 396 blink::WebArrayBuffer result; |
| 396 | 397 |
| 397 switch (algorithm.id()) { | 398 switch (algorithm.id()) { |
| 398 case blink::WebCryptoAlgorithmIdHmac: { | 399 case blink::WebCryptoAlgorithmIdHmac: { |
| 399 | 400 |
| 400 DCHECK_EQ(key.algorithm().id(), blink::WebCryptoAlgorithmIdHmac); | 401 DCHECK_EQ(key.algorithm().id(), blink::WebCryptoAlgorithmIdHmac); |
| 401 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); | 402 DCHECK_NE(0, key.usages() & blink::WebCryptoKeyUsageSign); |
| 402 | 403 |
| 403 const blink::WebCryptoHmacParams* const params = algorithm.hmacParams(); | 404 const blink::WebCryptoHmacParams* const params = algorithm.hmacParams(); |
| 404 if (!params) | 405 if (!params) |
| 405 return false; | 406 return Status::ErrorUnexpected(); |
| 406 | 407 |
| 407 const EVP_MD* evp_sha = 0; | 408 const EVP_MD* evp_sha = 0; |
| 408 unsigned int hmac_expected_length = 0; | 409 unsigned int hmac_expected_length = 0; |
| 409 // Note that HMAC length is determined by the hash used. | 410 // Note that HMAC length is determined by the hash used. |
| 410 switch (params->hash().id()) { | 411 switch (params->hash().id()) { |
| 411 case blink::WebCryptoAlgorithmIdSha1: | 412 case blink::WebCryptoAlgorithmIdSha1: |
| 412 evp_sha = EVP_sha1(); | 413 evp_sha = EVP_sha1(); |
| 413 hmac_expected_length = SHA_DIGEST_LENGTH; | 414 hmac_expected_length = SHA_DIGEST_LENGTH; |
| 414 break; | 415 break; |
| 415 case blink::WebCryptoAlgorithmIdSha224: | 416 case blink::WebCryptoAlgorithmIdSha224: |
| 416 evp_sha = EVP_sha224(); | 417 evp_sha = EVP_sha224(); |
| 417 hmac_expected_length = SHA224_DIGEST_LENGTH; | 418 hmac_expected_length = SHA224_DIGEST_LENGTH; |
| 418 break; | 419 break; |
| 419 case blink::WebCryptoAlgorithmIdSha256: | 420 case blink::WebCryptoAlgorithmIdSha256: |
| 420 evp_sha = EVP_sha256(); | 421 evp_sha = EVP_sha256(); |
| 421 hmac_expected_length = SHA256_DIGEST_LENGTH; | 422 hmac_expected_length = SHA256_DIGEST_LENGTH; |
| 422 break; | 423 break; |
| 423 case blink::WebCryptoAlgorithmIdSha384: | 424 case blink::WebCryptoAlgorithmIdSha384: |
| 424 evp_sha = EVP_sha384(); | 425 evp_sha = EVP_sha384(); |
| 425 hmac_expected_length = SHA384_DIGEST_LENGTH; | 426 hmac_expected_length = SHA384_DIGEST_LENGTH; |
| 426 break; | 427 break; |
| 427 case blink::WebCryptoAlgorithmIdSha512: | 428 case blink::WebCryptoAlgorithmIdSha512: |
| 428 evp_sha = EVP_sha512(); | 429 evp_sha = EVP_sha512(); |
| 429 hmac_expected_length = SHA512_DIGEST_LENGTH; | 430 hmac_expected_length = SHA512_DIGEST_LENGTH; |
| 430 break; | 431 break; |
| 431 default: | 432 default: |
| 432 // Not a digest algorithm. | 433 // Not a digest algorithm. |
| 433 return false; | 434 return Status::ErrorUnsupported(); |
| 434 } | 435 } |
| 435 | 436 |
| 436 SymKeyHandle* const sym_key = | 437 SymKeyHandle* const sym_key = |
| 437 reinterpret_cast<SymKeyHandle*>(key.handle()); | 438 reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 438 const std::vector<unsigned char>& raw_key = sym_key->key(); | 439 const std::vector<unsigned char>& raw_key = sym_key->key(); |
| 439 | 440 |
| 440 // OpenSSL wierdness here. | 441 // OpenSSL wierdness here. |
| 441 // First, HMAC() needs a void* for the key data, so make one up front as a | 442 // First, HMAC() needs a void* for the key data, so make one up front as a |
| 442 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, | 443 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, |
| 443 // which will result if the raw_key vector is empty; an entirely valid | 444 // which will result if the raw_key vector is empty; an entirely valid |
| (...skipping 10 matching lines...) Expand all Loading... |
| 454 | 455 |
| 455 unsigned int hmac_actual_length; | 456 unsigned int hmac_actual_length; |
| 456 unsigned char* const success = HMAC(evp_sha, | 457 unsigned char* const success = HMAC(evp_sha, |
| 457 raw_key_voidp, | 458 raw_key_voidp, |
| 458 raw_key.size(), | 459 raw_key.size(), |
| 459 data, | 460 data, |
| 460 data_size, | 461 data_size, |
| 461 hmac_result.safe_buffer(), | 462 hmac_result.safe_buffer(), |
| 462 &hmac_actual_length); | 463 &hmac_actual_length); |
| 463 if (!success || hmac_actual_length != hmac_expected_length) | 464 if (!success || hmac_actual_length != hmac_expected_length) |
| 464 return false; | 465 return Status::Error(); |
| 465 | 466 |
| 466 break; | 467 break; |
| 467 } | 468 } |
| 468 default: | 469 default: |
| 469 return false; | 470 return Status::ErrorUnsupported(); |
| 470 } | 471 } |
| 471 | 472 |
| 472 *buffer = result; | 473 *buffer = result; |
| 473 return true; | 474 return Status::Success(); |
| 474 } | 475 } |
| 475 | 476 |
| 476 bool WebCryptoImpl::VerifySignatureInternal( | 477 Status WebCryptoImpl::VerifySignatureInternal( |
| 477 const blink::WebCryptoAlgorithm& algorithm, | 478 const blink::WebCryptoAlgorithm& algorithm, |
| 478 const blink::WebCryptoKey& key, | 479 const blink::WebCryptoKey& key, |
| 479 const unsigned char* signature, | 480 const unsigned char* signature, |
| 480 unsigned signature_size, | 481 unsigned signature_size, |
| 481 const unsigned char* data, | 482 const unsigned char* data, |
| 482 unsigned data_size, | 483 unsigned data_size, |
| 483 bool* signature_match) { | 484 bool* signature_match) { |
| 484 switch (algorithm.id()) { | 485 switch (algorithm.id()) { |
| 485 case blink::WebCryptoAlgorithmIdHmac: { | 486 case blink::WebCryptoAlgorithmIdHmac: { |
| 486 blink::WebArrayBuffer result; | 487 blink::WebArrayBuffer result; |
| 487 if (!SignInternal(algorithm, key, data, data_size, &result)) { | 488 Status status = SignInternal(algorithm, key, data, data_size, &result); |
| 488 return false; | 489 if (status.IsError()) { |
| 490 return status; |
| 489 } | 491 } |
| 490 | 492 |
| 491 // Handling of truncated signatures is underspecified in the WebCrypto | 493 // Handling of truncated signatures is underspecified in the WebCrypto |
| 492 // spec, so here we fail verification if a truncated signature is being | 494 // spec, so here we fail verification if a truncated signature is being |
| 493 // verified. | 495 // verified. |
| 494 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | 496 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
| 495 *signature_match = | 497 *signature_match = |
| 496 result.byteLength() == signature_size && | 498 result.byteLength() == signature_size && |
| 497 crypto::SecureMemEqual(result.data(), signature, signature_size); | 499 crypto::SecureMemEqual(result.data(), signature, signature_size); |
| 498 | 500 |
| 499 break; | 501 break; |
| 500 } | 502 } |
| 501 default: | 503 default: |
| 502 return false; | 504 return Status::ErrorUnsupported(); |
| 503 } | 505 } |
| 504 return true; | 506 return Status::Success(); |
| 505 } | 507 } |
| 506 | 508 |
| 507 bool WebCryptoImpl::ImportRsaPublicKeyInternal( | 509 Status WebCryptoImpl::ImportRsaPublicKeyInternal( |
| 508 const unsigned char* modulus_data, | 510 const unsigned char* modulus_data, |
| 509 unsigned modulus_size, | 511 unsigned modulus_size, |
| 510 const unsigned char* exponent_data, | 512 const unsigned char* exponent_data, |
| 511 unsigned exponent_size, | 513 unsigned exponent_size, |
| 512 const blink::WebCryptoAlgorithm& algorithm, | 514 const blink::WebCryptoAlgorithm& algorithm, |
| 513 bool extractable, | 515 bool extractable, |
| 514 blink::WebCryptoKeyUsageMask usage_mask, | 516 blink::WebCryptoKeyUsageMask usage_mask, |
| 515 blink::WebCryptoKey* key) { | 517 blink::WebCryptoKey* key) { |
| 516 // TODO(padolph): Placeholder for OpenSSL implementation. | 518 // TODO(padolph): Placeholder for OpenSSL implementation. |
| 517 // Issue http://crbug.com/267888. | 519 // Issue http://crbug.com/267888. |
| 518 return false; | 520 return Status::ErrorUnsupported(); |
| 519 } | 521 } |
| 520 | 522 |
| 521 } // namespace content | 523 } // namespace content |
| OLD | NEW |