| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/webcrypto/platform_crypto.h" | 5 #include "content/renderer/webcrypto/platform_crypto.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> |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 case 24: | 52 case 24: |
| 53 return EVP_aes_192_cbc(); | 53 return EVP_aes_192_cbc(); |
| 54 case 32: | 54 case 32: |
| 55 return EVP_aes_256_cbc(); | 55 return EVP_aes_256_cbc(); |
| 56 default: | 56 default: |
| 57 return NULL; | 57 return NULL; |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 | 60 |
| 61 // OpenSSL constants for EVP_CipherInit_ex(), do not change | 61 // OpenSSL constants for EVP_CipherInit_ex(), do not change |
| 62 enum CipherOperation { | 62 enum CipherOperation { kDoDecrypt = 0, kDoEncrypt = 1 }; |
| 63 kDoDecrypt = 0, | |
| 64 kDoEncrypt = 1 | |
| 65 }; | |
| 66 | 63 |
| 67 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, | 64 Status AesCbcEncryptDecrypt(EncryptOrDecrypt mode, |
| 68 SymKey* key, | 65 SymKey* key, |
| 69 const CryptoData& iv, | 66 const CryptoData& iv, |
| 70 const CryptoData& data, | 67 const CryptoData& data, |
| 71 blink::WebArrayBuffer* buffer) { | 68 blink::WebArrayBuffer* buffer) { |
| 72 CipherOperation cipher_operation = | 69 CipherOperation cipher_operation = |
| 73 (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt; | 70 (mode == ENCRYPT) ? kDoEncrypt : kDoDecrypt; |
| 74 | 71 |
| 75 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { | 72 if (data.byte_length() >= INT_MAX - AES_BLOCK_SIZE) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 return Status::Success(); | 132 return Status::Success(); |
| 136 } | 133 } |
| 137 | 134 |
| 138 } // namespace | 135 } // namespace |
| 139 | 136 |
| 140 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { | 137 Status ExportKeyRaw(SymKey* key, blink::WebArrayBuffer* buffer) { |
| 141 *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size()); | 138 *buffer = CreateArrayBuffer(Uint8VectorStart(key->key()), key->key().size()); |
| 142 return Status::Success(); | 139 return Status::Success(); |
| 143 } | 140 } |
| 144 | 141 |
| 145 void Init() { | 142 void Init() { crypto::EnsureOpenSSLInit(); } |
| 146 crypto::EnsureOpenSSLInit(); | |
| 147 } | |
| 148 | 143 |
| 149 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, | 144 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, |
| 150 SymKey* key, | 145 SymKey* key, |
| 151 const CryptoData& data, | 146 const CryptoData& data, |
| 152 const CryptoData& iv, | 147 const CryptoData& iv, |
| 153 blink::WebArrayBuffer* buffer) { | 148 blink::WebArrayBuffer* buffer) { |
| 154 // TODO(eroman): inline the function here. | 149 // TODO(eroman): inline the function here. |
| 155 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); | 150 return AesCbcEncryptDecrypt(mode, key, iv, data, buffer); |
| 156 } | 151 } |
| 157 | 152 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 182 return Status::ErrorUnexpected(); | 177 return Status::ErrorUnexpected(); |
| 183 } | 178 } |
| 184 | 179 |
| 185 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( | 180 crypto::ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> digest_context( |
| 186 EVP_MD_CTX_create()); | 181 EVP_MD_CTX_create()); |
| 187 if (!digest_context.get()) | 182 if (!digest_context.get()) |
| 188 return Status::Error(); | 183 return Status::Error(); |
| 189 | 184 |
| 190 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || | 185 if (!EVP_DigestInit_ex(digest_context.get(), digest_algorithm, NULL) || |
| 191 !EVP_DigestUpdate( | 186 !EVP_DigestUpdate( |
| 192 digest_context.get(), data.bytes(), data.byte_length())) { | 187 digest_context.get(), data.bytes(), data.byte_length())) { |
| 193 return Status::Error(); | 188 return Status::Error(); |
| 194 } | 189 } |
| 195 | 190 |
| 196 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); | 191 const int hash_expected_size = EVP_MD_CTX_size(digest_context.get()); |
| 197 if (hash_expected_size <= 0) | 192 if (hash_expected_size <= 0) |
| 198 return Status::ErrorUnexpected(); | 193 return Status::ErrorUnexpected(); |
| 199 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); | 194 DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE); |
| 200 | 195 |
| 201 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); | 196 *buffer = blink::WebArrayBuffer::create(hash_expected_size, 1); |
| 202 unsigned char* const hash_buffer = | 197 unsigned char* const hash_buffer = |
| 203 reinterpret_cast<unsigned char* const>(buffer->data()); | 198 reinterpret_cast<unsigned char* const>(buffer->data()); |
| 204 | 199 |
| 205 unsigned int hash_size = 0; | 200 unsigned int hash_size = 0; |
| 206 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || | 201 if (!EVP_DigestFinal_ex(digest_context.get(), hash_buffer, &hash_size) || |
| 207 static_cast<int>(hash_size) != hash_expected_size) { | 202 static_cast<int>(hash_size) != hash_expected_size) { |
| 208 buffer->reset(); | 203 buffer->reset(); |
| 209 return Status::Error(); | 204 return Status::Error(); |
| 210 } | 205 } |
| 211 | 206 |
| 212 return Status::Success(); | 207 return Status::Success(); |
| 213 } | 208 } |
| 214 | 209 |
| 215 Status GenerateSecretKey( | 210 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, |
| 216 const blink::WebCryptoAlgorithm& algorithm, | 211 bool extractable, |
| 217 bool extractable, | 212 blink::WebCryptoKeyUsageMask usage_mask, |
| 218 blink::WebCryptoKeyUsageMask usage_mask, | 213 unsigned keylen_bytes, |
| 219 unsigned keylen_bytes, | 214 blink::WebCryptoKey* key) { |
| 220 blink::WebCryptoKey* key) { | |
| 221 // TODO(eroman): Is this right? | 215 // TODO(eroman): Is this right? |
| 222 if (keylen_bytes == 0) | 216 if (keylen_bytes == 0) |
| 223 return Status::ErrorGenerateKeyLength(); | 217 return Status::ErrorGenerateKeyLength(); |
| 224 | 218 |
| 225 crypto::OpenSSLErrStackTracer(FROM_HERE); | 219 crypto::OpenSSLErrStackTracer(FROM_HERE); |
| 226 | 220 |
| 227 std::vector<unsigned char> random_bytes(keylen_bytes, 0); | 221 std::vector<unsigned char> random_bytes(keylen_bytes, 0); |
| 228 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) | 222 if (!(RAND_bytes(&random_bytes[0], keylen_bytes))) |
| 229 return Status::Error(); | 223 return Status::Error(); |
| 230 | 224 |
| 231 *key = blink::WebCryptoKey::create(new SymKey(CryptoData(random_bytes)), | 225 *key = blink::WebCryptoKey::create(new SymKey(CryptoData(random_bytes)), |
| 232 blink::WebCryptoKeyTypeSecret, | 226 blink::WebCryptoKeyTypeSecret, |
| 233 extractable, | 227 extractable, |
| 234 algorithm, | 228 algorithm, |
| 235 usage_mask); | 229 usage_mask); |
| 236 | 230 |
| 237 return Status::Success(); | 231 return Status::Success(); |
| 238 } | 232 } |
| 239 | 233 |
| 240 Status GenerateRsaKeyPair( | 234 Status GenerateRsaKeyPair(const blink::WebCryptoAlgorithm& algorithm, |
| 241 const blink::WebCryptoAlgorithm& algorithm, | 235 bool extractable, |
| 242 bool extractable, | 236 blink::WebCryptoKeyUsageMask usage_mask, |
| 243 blink::WebCryptoKeyUsageMask usage_mask, | 237 blink::WebCryptoKey* public_key, |
| 244 blink::WebCryptoKey* public_key, | 238 blink::WebCryptoKey* private_key) { |
| 245 blink::WebCryptoKey* private_key) { | |
| 246 // TODO(padolph): Placeholder for OpenSSL implementation. | 239 // TODO(padolph): Placeholder for OpenSSL implementation. |
| 247 // Issue http://crbug.com/267888. | 240 // Issue http://crbug.com/267888. |
| 248 return Status::ErrorUnsupported(); | 241 return Status::ErrorUnsupported(); |
| 249 } | 242 } |
| 250 | 243 |
| 251 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, | 244 Status ImportKeyRaw(const blink::WebCryptoAlgorithm& algorithm, |
| 252 const CryptoData& key_data, | 245 const CryptoData& key_data, |
| 253 bool extractable, | 246 bool extractable, |
| 254 blink::WebCryptoKeyUsageMask usage_mask, | 247 blink::WebCryptoKeyUsageMask usage_mask, |
| 255 blink::WebCryptoKey* key) { | 248 blink::WebCryptoKey* key) { |
| 256 *key = blink::WebCryptoKey::create(new SymKey(key_data), | 249 *key = blink::WebCryptoKey::create(new SymKey(key_data), |
| 257 blink::WebCryptoKeyTypeSecret, | 250 blink::WebCryptoKeyTypeSecret, |
| 258 extractable, | 251 extractable, |
| 259 algorithm, | 252 algorithm, |
| 260 usage_mask); | 253 usage_mask); |
| 261 | 254 |
| 262 return Status::Success(); | 255 return Status::Success(); |
| 263 } | 256 } |
| 264 | 257 |
| 265 Status SignHmac(SymKey* key, | 258 Status SignHmac(SymKey* key, |
| 266 const blink::WebCryptoAlgorithm& hash, | 259 const blink::WebCryptoAlgorithm& hash, |
| 267 const CryptoData& data, | 260 const CryptoData& data, |
| 268 blink::WebArrayBuffer* buffer) { | 261 blink::WebArrayBuffer* buffer) { |
| 269 blink::WebArrayBuffer result; | 262 blink::WebArrayBuffer result; |
| 270 | 263 |
| 271 // TODO(eroman): De-indent this code. | 264 const EVP_MD* evp_sha = 0; |
| 272 const EVP_MD* evp_sha = 0; | 265 unsigned int hmac_expected_length = 0; |
| 273 unsigned int hmac_expected_length = 0; | 266 // Note that HMAC length is determined by the hash used. |
| 274 // Note that HMAC length is determined by the hash used. | 267 switch (hash.id()) { |
| 275 switch (hash.id()) { | 268 case blink::WebCryptoAlgorithmIdSha1: |
| 276 case blink::WebCryptoAlgorithmIdSha1: | 269 evp_sha = EVP_sha1(); |
| 277 evp_sha = EVP_sha1(); | 270 hmac_expected_length = SHA_DIGEST_LENGTH; |
| 278 hmac_expected_length = SHA_DIGEST_LENGTH; | 271 break; |
| 279 break; | 272 case blink::WebCryptoAlgorithmIdSha224: |
| 280 case blink::WebCryptoAlgorithmIdSha224: | 273 evp_sha = EVP_sha224(); |
| 281 evp_sha = EVP_sha224(); | 274 hmac_expected_length = SHA224_DIGEST_LENGTH; |
| 282 hmac_expected_length = SHA224_DIGEST_LENGTH; | 275 break; |
| 283 break; | 276 case blink::WebCryptoAlgorithmIdSha256: |
| 284 case blink::WebCryptoAlgorithmIdSha256: | 277 evp_sha = EVP_sha256(); |
| 285 evp_sha = EVP_sha256(); | 278 hmac_expected_length = SHA256_DIGEST_LENGTH; |
| 286 hmac_expected_length = SHA256_DIGEST_LENGTH; | 279 break; |
| 287 break; | 280 case blink::WebCryptoAlgorithmIdSha384: |
| 288 case blink::WebCryptoAlgorithmIdSha384: | 281 evp_sha = EVP_sha384(); |
| 289 evp_sha = EVP_sha384(); | 282 hmac_expected_length = SHA384_DIGEST_LENGTH; |
| 290 hmac_expected_length = SHA384_DIGEST_LENGTH; | 283 break; |
| 291 break; | 284 case blink::WebCryptoAlgorithmIdSha512: |
| 292 case blink::WebCryptoAlgorithmIdSha512: | 285 evp_sha = EVP_sha512(); |
| 293 evp_sha = EVP_sha512(); | 286 hmac_expected_length = SHA512_DIGEST_LENGTH; |
| 294 hmac_expected_length = SHA512_DIGEST_LENGTH; | 287 break; |
| 295 break; | 288 default: |
| 296 default: | 289 // Not a digest algorithm. |
| 297 // Not a digest algorithm. | 290 return Status::ErrorUnsupported(); |
| 298 return Status::ErrorUnsupported(); | 291 } |
| 299 } | |
| 300 | 292 |
| 301 const std::vector<unsigned char>& raw_key = key->key(); | 293 const std::vector<unsigned char>& raw_key = key->key(); |
| 302 | 294 |
| 303 // OpenSSL wierdness here. | 295 // OpenSSL wierdness here. |
| 304 // First, HMAC() needs a void* for the key data, so make one up front as a | 296 // First, HMAC() needs a void* for the key data, so make one up front as a |
| 305 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, | 297 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, |
| 306 // which will result if the raw_key vector is empty; an entirely valid | 298 // which will result if the raw_key vector is empty; an entirely valid |
| 307 // case. Handle this specific case by pointing to an empty array. | 299 // case. Handle this specific case by pointing to an empty array. |
| 308 const unsigned char null_key[] = {}; | 300 const unsigned char null_key[] = {}; |
| 309 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; | 301 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; |
| 310 | 302 |
| 311 result = blink::WebArrayBuffer::create(hmac_expected_length, 1); | 303 result = blink::WebArrayBuffer::create(hmac_expected_length, 1); |
| 312 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( | 304 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( |
| 313 reinterpret_cast<unsigned char*>(result.data()), | 305 reinterpret_cast<unsigned char*>(result.data()), hmac_expected_length); |
| 314 hmac_expected_length); | |
| 315 | 306 |
| 316 crypto::OpenSSLErrStackTracer(FROM_HERE); | 307 crypto::OpenSSLErrStackTracer(FROM_HERE); |
| 317 | 308 |
| 318 unsigned int hmac_actual_length; | 309 unsigned int hmac_actual_length; |
| 319 unsigned char* const success = HMAC(evp_sha, | 310 unsigned char* const success = HMAC(evp_sha, |
| 320 raw_key_voidp, | 311 raw_key_voidp, |
| 321 raw_key.size(), | 312 raw_key.size(), |
| 322 data.bytes(), | 313 data.bytes(), |
| 323 data.byte_length(), | 314 data.byte_length(), |
| 324 hmac_result.safe_buffer(), | 315 hmac_result.safe_buffer(), |
| 325 &hmac_actual_length); | 316 &hmac_actual_length); |
| 326 if (!success || hmac_actual_length != hmac_expected_length) | 317 if (!success || hmac_actual_length != hmac_expected_length) |
| 327 return Status::Error(); | 318 return Status::Error(); |
| 328 | 319 |
| 329 *buffer = result; | 320 *buffer = result; |
| 330 return Status::Success(); | 321 return Status::Success(); |
| 331 } | 322 } |
| 332 | 323 |
| 333 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, | 324 Status ImportRsaPublicKey(const blink::WebCryptoAlgorithm& algorithm, |
| 334 bool extractable, | 325 bool extractable, |
| 335 blink::WebCryptoKeyUsageMask usage_mask, | 326 blink::WebCryptoKeyUsageMask usage_mask, |
| 336 const CryptoData& modulus_data, | 327 const CryptoData& modulus_data, |
| 337 const CryptoData& exponent_data, | 328 const CryptoData& exponent_data, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { | 397 Status ExportKeySpki(PublicKey* key, blink::WebArrayBuffer* buffer) { |
| 407 // TODO(eroman): http://crbug.com/267888 | 398 // TODO(eroman): http://crbug.com/267888 |
| 408 return Status::ErrorUnsupported(); | 399 return Status::ErrorUnsupported(); |
| 409 } | 400 } |
| 410 | 401 |
| 411 } // namespace platform | 402 } // namespace platform |
| 412 | 403 |
| 413 } // namespace webcrypto | 404 } // namespace webcrypto |
| 414 | 405 |
| 415 } // namespace content | 406 } // namespace content |
| OLD | NEW |