OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <openssl/hmac.h> | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/stl_util.h" | |
9 #include "content/child/webcrypto/algorithm_implementation.h" | |
10 #include "content/child/webcrypto/crypto_data.h" | |
11 #include "content/child/webcrypto/jwk.h" | |
12 #include "content/child/webcrypto/openssl/key_openssl.h" | |
13 #include "content/child/webcrypto/openssl/util_openssl.h" | |
14 #include "content/child/webcrypto/status.h" | |
15 #include "content/child/webcrypto/webcrypto_util.h" | |
16 #include "crypto/openssl_util.h" | |
17 #include "crypto/secure_util.h" | |
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
19 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
20 | |
21 namespace content { | |
22 | |
23 namespace webcrypto { | |
24 | |
25 namespace { | |
26 | |
27 const blink::WebCryptoKeyUsageMask kAllKeyUsages = | |
28 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
29 | |
30 Status SignHmac(const std::vector<uint8_t>& raw_key, | |
31 const blink::WebCryptoAlgorithm& hash, | |
32 const CryptoData& data, | |
33 std::vector<uint8_t>* buffer) { | |
34 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
35 | |
36 const EVP_MD* digest_algorithm = GetDigest(hash.id()); | |
37 if (!digest_algorithm) | |
38 return Status::ErrorUnsupported(); | |
39 unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm); | |
40 | |
41 buffer->resize(hmac_expected_length); | |
42 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result( | |
43 vector_as_array(buffer), hmac_expected_length); | |
44 | |
45 unsigned int hmac_actual_length; | |
46 unsigned char* const success = HMAC( | |
47 digest_algorithm, vector_as_array(&raw_key), raw_key.size(), data.bytes(), | |
48 data.byte_length(), hmac_result.safe_buffer(), &hmac_actual_length); | |
49 if (!success || hmac_actual_length != hmac_expected_length) | |
50 return Status::OperationError(); | |
51 | |
52 return Status::Success(); | |
53 } | |
54 | |
55 class HmacImplementation : public AlgorithmImplementation { | |
56 public: | |
57 HmacImplementation() {} | |
58 | |
59 Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm, | |
60 bool extractable, | |
61 blink::WebCryptoKeyUsageMask usages, | |
62 GenerateKeyResult* result) const override { | |
63 Status status = CheckKeyCreationUsages(kAllKeyUsages, usages, false); | |
64 if (status.IsError()) | |
65 return status; | |
66 | |
67 const blink::WebCryptoHmacKeyGenParams* params = | |
68 algorithm.hmacKeyGenParams(); | |
69 | |
70 unsigned int keylen_bits = 0; | |
71 status = GetHmacKeyGenLengthInBits(params, &keylen_bits); | |
72 if (status.IsError()) | |
73 return status; | |
74 | |
75 return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac( | |
76 params->hash().id(), keylen_bits), | |
77 extractable, usages, keylen_bits, result); | |
78 } | |
79 | |
80 Status VerifyKeyUsagesBeforeImportKey( | |
81 blink::WebCryptoKeyFormat format, | |
82 blink::WebCryptoKeyUsageMask usages) const override { | |
83 switch (format) { | |
84 case blink::WebCryptoKeyFormatRaw: | |
85 case blink::WebCryptoKeyFormatJwk: | |
86 return CheckKeyCreationUsages(kAllKeyUsages, usages, false); | |
87 default: | |
88 return Status::ErrorUnsupportedImportKeyFormat(); | |
89 } | |
90 } | |
91 | |
92 Status ImportKeyRaw(const CryptoData& key_data, | |
93 const blink::WebCryptoAlgorithm& algorithm, | |
94 bool extractable, | |
95 blink::WebCryptoKeyUsageMask usages, | |
96 blink::WebCryptoKey* key) const override { | |
97 const blink::WebCryptoHmacImportParams* params = | |
98 algorithm.hmacImportParams(); | |
99 | |
100 unsigned int keylen_bits = 0; | |
101 Status status = GetHmacImportKeyLengthBits(params, key_data.byte_length(), | |
102 &keylen_bits); | |
103 if (status.IsError()) | |
104 return status; | |
105 | |
106 const blink::WebCryptoKeyAlgorithm key_algorithm = | |
107 blink::WebCryptoKeyAlgorithm::createHmac(params->hash().id(), | |
108 keylen_bits); | |
109 | |
110 // If no bit truncation was requested, then done! | |
111 if ((keylen_bits % 8) == 0) { | |
112 return CreateWebCryptoSecretKey(key_data, key_algorithm, extractable, | |
113 usages, key); | |
114 } | |
115 | |
116 // Otherwise zero out the unused bits in the key data before importing. | |
117 std::vector<uint8_t> modified_key_data( | |
118 key_data.bytes(), key_data.bytes() + key_data.byte_length()); | |
119 TruncateToBitLength(keylen_bits, &modified_key_data); | |
120 return CreateWebCryptoSecretKey(CryptoData(modified_key_data), | |
121 key_algorithm, extractable, usages, key); | |
122 } | |
123 | |
124 Status ImportKeyJwk(const CryptoData& key_data, | |
125 const blink::WebCryptoAlgorithm& algorithm, | |
126 bool extractable, | |
127 blink::WebCryptoKeyUsageMask usages, | |
128 blink::WebCryptoKey* key) const override { | |
129 const char* algorithm_name = | |
130 GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id()); | |
131 if (!algorithm_name) | |
132 return Status::ErrorUnexpected(); | |
133 | |
134 std::vector<uint8_t> raw_data; | |
135 Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable, | |
136 usages, &raw_data); | |
137 if (status.IsError()) | |
138 return status; | |
139 | |
140 return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages, | |
141 key); | |
142 } | |
143 | |
144 Status ExportKeyRaw(const blink::WebCryptoKey& key, | |
145 std::vector<uint8_t>* buffer) const override { | |
146 *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data(); | |
147 return Status::Success(); | |
148 } | |
149 | |
150 Status ExportKeyJwk(const blink::WebCryptoKey& key, | |
151 std::vector<uint8_t>* buffer) const override { | |
152 SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key); | |
153 const std::vector<uint8_t>& raw_data = sym_key->raw_key_data(); | |
154 | |
155 const char* algorithm_name = | |
156 GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id()); | |
157 if (!algorithm_name) | |
158 return Status::ErrorUnexpected(); | |
159 | |
160 WriteSecretKeyJwk(CryptoData(raw_data), algorithm_name, key.extractable(), | |
161 key.usages(), buffer); | |
162 | |
163 return Status::Success(); | |
164 } | |
165 | |
166 Status Sign(const blink::WebCryptoAlgorithm& algorithm, | |
167 const blink::WebCryptoKey& key, | |
168 const CryptoData& data, | |
169 std::vector<uint8_t>* buffer) const override { | |
170 const blink::WebCryptoAlgorithm& hash = | |
171 key.algorithm().hmacParams()->hash(); | |
172 | |
173 return SignHmac(SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data, | |
174 buffer); | |
175 } | |
176 | |
177 Status Verify(const blink::WebCryptoAlgorithm& algorithm, | |
178 const blink::WebCryptoKey& key, | |
179 const CryptoData& signature, | |
180 const CryptoData& data, | |
181 bool* signature_match) const override { | |
182 std::vector<uint8_t> result; | |
183 Status status = Sign(algorithm, key, data, &result); | |
184 | |
185 if (status.IsError()) | |
186 return status; | |
187 | |
188 // Do not allow verification of truncated MACs. | |
189 *signature_match = | |
190 result.size() == signature.byte_length() && | |
191 crypto::SecureMemEqual(vector_as_array(&result), signature.bytes(), | |
192 signature.byte_length()); | |
193 | |
194 return Status::Success(); | |
195 } | |
196 | |
197 Status SerializeKeyForClone( | |
198 const blink::WebCryptoKey& key, | |
199 blink::WebVector<uint8_t>* key_data) const override { | |
200 key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data()); | |
201 return Status::Success(); | |
202 } | |
203 | |
204 Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, | |
205 blink::WebCryptoKeyType type, | |
206 bool extractable, | |
207 blink::WebCryptoKeyUsageMask usages, | |
208 const CryptoData& key_data, | |
209 blink::WebCryptoKey* key) const override { | |
210 return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages, | |
211 key); | |
212 } | |
213 | |
214 Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
215 bool* has_length_bits, | |
216 unsigned int* length_bits) const override { | |
217 return GetHmacKeyLength(key_length_algorithm, has_length_bits, length_bits); | |
218 } | |
219 }; | |
220 | |
221 } // namespace | |
222 | |
223 AlgorithmImplementation* CreatePlatformHmacImplementation() { | |
224 return new HmacImplementation; | |
225 } | |
226 | |
227 } // namespace webcrypto | |
228 | |
229 } // namespace content | |
OLD | NEW |