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> |
| 8 #include <openssl/hmac.h> |
| 9 #include <openssl/sha.h> |
| 10 |
| 11 #include "base/logging.h" |
| 12 #include "crypto/openssl_util.h" |
| 13 #include "crypto/secure_util.h" |
| 14 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" |
| 15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| 16 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| 17 |
7 namespace content { | 18 namespace content { |
8 | 19 |
9 void WebCryptoImpl::Init() { | 20 namespace { |
10 } | 21 |
| 22 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { |
| 23 public: |
| 24 SymKeyHandle(const unsigned char* key_data, unsigned key_data_size) |
| 25 : key_(key_data, key_data + key_data_size) {} |
| 26 |
| 27 const std::vector<unsigned char>& key() const { return key_; } |
| 28 |
| 29 private: |
| 30 const std::vector<unsigned char> key_; |
| 31 |
| 32 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); |
| 33 }; |
| 34 |
| 35 } // anonymous namespace |
| 36 |
| 37 void WebCryptoImpl::Init() { crypto::EnsureOpenSSLInit(); } |
11 | 38 |
12 bool WebCryptoImpl::EncryptInternal( | 39 bool WebCryptoImpl::EncryptInternal( |
13 const WebKit::WebCryptoAlgorithm& algorithm, | 40 const WebKit::WebCryptoAlgorithm& algorithm, |
14 const WebKit::WebCryptoKey& key, | 41 const WebKit::WebCryptoKey& key, |
15 const unsigned char* data, | 42 const unsigned char* data, |
16 unsigned data_size, | 43 unsigned data_size, |
17 WebKit::WebArrayBuffer* buffer) { | 44 WebKit::WebArrayBuffer* buffer) { |
| 45 // TODO(padolph): Placeholder for OpenSSL implementation. |
| 46 // Issue http://crbug.com/267888. |
18 return false; | 47 return false; |
19 } | 48 } |
20 | 49 |
21 bool WebCryptoImpl::DecryptInternal( | 50 bool WebCryptoImpl::DecryptInternal( |
22 const WebKit::WebCryptoAlgorithm& algorithm, | 51 const WebKit::WebCryptoAlgorithm& algorithm, |
23 const WebKit::WebCryptoKey& key, | 52 const WebKit::WebCryptoKey& key, |
24 const unsigned char* data, | 53 const unsigned char* data, |
25 unsigned data_size, | 54 unsigned data_size, |
26 WebKit::WebArrayBuffer* buffer) { | 55 WebKit::WebArrayBuffer* buffer) { |
27 return false; | 56 return false; |
28 } | 57 } |
29 | 58 |
30 bool WebCryptoImpl::DigestInternal( | 59 bool WebCryptoImpl::DigestInternal( |
31 const WebKit::WebCryptoAlgorithm& algorithm, | 60 const WebKit::WebCryptoAlgorithm& algorithm, |
32 const unsigned char* data, | 61 const unsigned char* data, |
33 unsigned data_size, | 62 unsigned data_size, |
34 WebKit::WebArrayBuffer* buffer) { | 63 WebKit::WebArrayBuffer* buffer) { |
35 // TODO(bryaneyler): Placeholder for OpenSSL implementation. | 64 // TODO(padolph): Placeholder for OpenSSL implementation. |
36 // Issue http://crbug.com/267888. | 65 // Issue http://crbug.com/267888. |
37 return false; | 66 return false; |
38 } | 67 } |
39 | 68 |
40 bool WebCryptoImpl::ImportKeyInternal( | 69 bool WebCryptoImpl::ImportKeyInternal( |
41 WebKit::WebCryptoKeyFormat format, | 70 WebKit::WebCryptoKeyFormat format, |
42 const unsigned char* key_data, | 71 const unsigned char* key_data, |
43 unsigned key_data_size, | 72 unsigned key_data_size, |
44 const WebKit::WebCryptoAlgorithm& algorithm, | 73 const WebKit::WebCryptoAlgorithm& algorithm, |
45 WebKit::WebCryptoKeyUsageMask usage_mask, | 74 WebKit::WebCryptoKeyUsageMask /*usage_mask*/, |
46 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | 75 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, |
47 WebKit::WebCryptoKeyType* type) { | 76 WebKit::WebCryptoKeyType* type) { |
48 // TODO(bryaneyler): Placeholder for OpenSSL implementation. | 77 |
49 // Issue http://crbug.com/267888. | 78 // TODO(padolph): Support all relevant alg types and then remove this gate. |
50 return false; | 79 if (algorithm.id() != WebKit::WebCryptoAlgorithmIdHmac && |
| 80 algorithm.id() != WebKit::WebCryptoAlgorithmIdAesCbc) { |
| 81 return false; |
| 82 } |
| 83 |
| 84 // TODO(padolph): Need to split handling for symmetric (raw or jwk format) and |
| 85 // asymmetric (jwk, spki, or pkcs8 format) keys. |
| 86 // Currently only supporting symmetric. |
| 87 |
| 88 // TODO(padolph): jwk handling. Define precedence between jwk contents and |
| 89 // this method's parameters, e.g. 'alg' in jwk vs algorithm.id(). Who wins if |
| 90 // they differ? (jwk, probably) |
| 91 |
| 92 // Symmetric keys are always type secret |
| 93 *type = WebKit::WebCryptoKeyTypeSecret; |
| 94 |
| 95 const unsigned char* raw_key_data; |
| 96 unsigned raw_key_data_size; |
| 97 switch (format) { |
| 98 case WebKit::WebCryptoKeyFormatRaw: |
| 99 raw_key_data = key_data; |
| 100 raw_key_data_size = key_data_size; |
| 101 break; |
| 102 case WebKit::WebCryptoKeyFormatJwk: |
| 103 // TODO(padolph): Handle jwk format; need simple JSON parser. |
| 104 // break; |
| 105 return false; |
| 106 default: |
| 107 return false; |
| 108 } |
| 109 |
| 110 handle->reset(new SymKeyHandle(raw_key_data, raw_key_data_size)); |
| 111 |
| 112 return true; |
51 } | 113 } |
52 | 114 |
53 bool WebCryptoImpl::SignInternal( | 115 bool WebCryptoImpl::SignInternal( |
54 const WebKit::WebCryptoAlgorithm& algorithm, | 116 const WebKit::WebCryptoAlgorithm& algorithm, |
55 const WebKit::WebCryptoKey& key, | 117 const WebKit::WebCryptoKey& key, |
56 const unsigned char* data, | 118 const unsigned char* data, |
57 unsigned data_size, | 119 unsigned data_size, |
58 WebKit::WebArrayBuffer* buffer) { | 120 WebKit::WebArrayBuffer* buffer) { |
59 // TODO(bryaneyler): Placeholder for OpenSSL implementation. | 121 |
60 // Issue http://crbug.com/267888. | 122 WebKit::WebArrayBuffer result; |
61 return false; | 123 |
| 124 switch (algorithm.id()) { |
| 125 case WebKit::WebCryptoAlgorithmIdHmac: { |
| 126 |
| 127 DCHECK_EQ(key.algorithm().id(), WebKit::WebCryptoAlgorithmIdHmac); |
| 128 DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); |
| 129 |
| 130 const WebKit::WebCryptoHmacParams* const params = algorithm.hmacParams(); |
| 131 if (!params) |
| 132 return false; |
| 133 |
| 134 const EVP_MD* evp_sha = 0; |
| 135 unsigned int hmac_expected_length = 0; |
| 136 // Note that HMAC length is determined by the hash used. |
| 137 switch (params->hash().id()) { |
| 138 case WebKit::WebCryptoAlgorithmIdSha1: |
| 139 evp_sha = EVP_sha1(); |
| 140 hmac_expected_length = SHA_DIGEST_LENGTH; |
| 141 break; |
| 142 case WebKit::WebCryptoAlgorithmIdSha224: |
| 143 evp_sha = EVP_sha224(); |
| 144 hmac_expected_length = SHA224_DIGEST_LENGTH; |
| 145 break; |
| 146 case WebKit::WebCryptoAlgorithmIdSha256: |
| 147 evp_sha = EVP_sha256(); |
| 148 hmac_expected_length = SHA256_DIGEST_LENGTH; |
| 149 break; |
| 150 case WebKit::WebCryptoAlgorithmIdSha384: |
| 151 evp_sha = EVP_sha384(); |
| 152 hmac_expected_length = SHA384_DIGEST_LENGTH; |
| 153 break; |
| 154 case WebKit::WebCryptoAlgorithmIdSha512: |
| 155 evp_sha = EVP_sha512(); |
| 156 hmac_expected_length = SHA512_DIGEST_LENGTH; |
| 157 break; |
| 158 default: |
| 159 // Not a digest algorithm. |
| 160 return false; |
| 161 } |
| 162 |
| 163 SymKeyHandle* const sym_key = |
| 164 reinterpret_cast<SymKeyHandle*>(key.handle()); |
| 165 const std::vector<unsigned char>& raw_key = sym_key->key(); |
| 166 |
| 167 // OpenSSL wierdness here. |
| 168 // First, HMAC() needs a void* for the key data, so make one up front as a |
| 169 // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key, |
| 170 // which will result if the raw_key vector is empty; an entirely valid |
| 171 // case. Handle this specific case by pointing to an empty array. |
| 172 const unsigned char null_key[] = {}; |
| 173 const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key; |
| 174 |
| 175 result = WebKit::WebArrayBuffer::create(hmac_expected_length, 1); |
| 176 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( |
| 177 reinterpret_cast<unsigned char*>(result.data()), |
| 178 hmac_expected_length); |
| 179 |
| 180 crypto::OpenSSLErrStackTracer(FROM_HERE); |
| 181 |
| 182 unsigned int hmac_actual_length; |
| 183 unsigned char* const success = HMAC(evp_sha, |
| 184 raw_key_voidp, |
| 185 raw_key.size(), |
| 186 data, |
| 187 data_size, |
| 188 hmac_result.safe_buffer(), |
| 189 &hmac_actual_length); |
| 190 if (!success || hmac_actual_length != hmac_expected_length) |
| 191 return false; |
| 192 |
| 193 break; |
| 194 } |
| 195 default: |
| 196 return false; |
| 197 } |
| 198 |
| 199 *buffer = result; |
| 200 return true; |
62 } | 201 } |
63 | 202 |
64 bool WebCryptoImpl::VerifySignatureInternal( | 203 bool WebCryptoImpl::VerifySignatureInternal( |
65 const WebKit::WebCryptoAlgorithm& algorithm, | 204 const WebKit::WebCryptoAlgorithm& algorithm, |
66 const WebKit::WebCryptoKey& key, | 205 const WebKit::WebCryptoKey& key, |
67 const unsigned char* signature, | 206 const unsigned char* signature, |
68 unsigned signature_size, | 207 unsigned signature_size, |
69 const unsigned char* data, | 208 const unsigned char* data, |
70 unsigned data_size, | 209 unsigned data_size, |
71 bool* signature_match) { | 210 bool* signature_match) { |
72 // TODO(bryaneyler): Placeholder for OpenSSL implementation. | 211 switch (algorithm.id()) { |
73 // Issue http://crbug.com/267888. | 212 case WebKit::WebCryptoAlgorithmIdHmac: { |
74 return false; | 213 WebKit::WebArrayBuffer result; |
| 214 if (!SignInternal(algorithm, key, data, data_size, &result)) { |
| 215 return false; |
| 216 } |
| 217 |
| 218 // Handling of truncated signatures is underspecified in the WebCrypto |
| 219 // spec, so here we fail verification if a truncated signature is being |
| 220 // verified. |
| 221 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 |
| 222 *signature_match = |
| 223 result.byteLength() == signature_size && |
| 224 crypto::SecureMemEqual(result.data(), signature, signature_size); |
| 225 |
| 226 break; |
| 227 } |
| 228 default: |
| 229 return false; |
| 230 } |
| 231 return true; |
75 } | 232 } |
76 | 233 |
77 } // namespace content | 234 } // namespace content |
OLD | NEW |