Don't preload rarely seen large images
[chromium-blink-merge.git] / components / webcrypto / openssl / hmac_openssl.cc
blob9962bfd8c55c8da3e91168c167e086a695e2f1cb
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.
5 #include <openssl/hmac.h>
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "components/webcrypto/algorithm_implementation.h"
10 #include "components/webcrypto/crypto_data.h"
11 #include "components/webcrypto/jwk.h"
12 #include "components/webcrypto/openssl/key_openssl.h"
13 #include "components/webcrypto/openssl/util_openssl.h"
14 #include "components/webcrypto/status.h"
15 #include "components/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"
21 namespace webcrypto {
23 namespace {
25 const blink::WebCryptoKeyUsageMask kAllKeyUsages =
26 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
28 Status SignHmac(const std::vector<uint8_t>& raw_key,
29 const blink::WebCryptoAlgorithm& hash,
30 const CryptoData& data,
31 std::vector<uint8_t>* buffer) {
32 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
34 const EVP_MD* digest_algorithm = GetDigest(hash.id());
35 if (!digest_algorithm)
36 return Status::ErrorUnsupported();
37 size_t hmac_expected_length = EVP_MD_size(digest_algorithm);
39 buffer->resize(hmac_expected_length);
40 crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
41 vector_as_array(buffer), hmac_expected_length);
43 unsigned int hmac_actual_length;
44 unsigned char* const success = HMAC(
45 digest_algorithm, vector_as_array(&raw_key), raw_key.size(), data.bytes(),
46 data.byte_length(), hmac_result.safe_buffer(), &hmac_actual_length);
47 if (!success || hmac_actual_length != hmac_expected_length)
48 return Status::OperationError();
50 return Status::Success();
53 class HmacImplementation : public AlgorithmImplementation {
54 public:
55 HmacImplementation() {}
57 Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
58 bool extractable,
59 blink::WebCryptoKeyUsageMask usages,
60 GenerateKeyResult* result) const override {
61 Status status = CheckKeyCreationUsages(kAllKeyUsages, usages, false);
62 if (status.IsError())
63 return status;
65 const blink::WebCryptoHmacKeyGenParams* params =
66 algorithm.hmacKeyGenParams();
68 unsigned int keylen_bits = 0;
69 status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
70 if (status.IsError())
71 return status;
73 return GenerateWebCryptoSecretKey(blink::WebCryptoKeyAlgorithm::createHmac(
74 params->hash().id(), keylen_bits),
75 extractable, usages, keylen_bits, result);
78 Status VerifyKeyUsagesBeforeImportKey(
79 blink::WebCryptoKeyFormat format,
80 blink::WebCryptoKeyUsageMask usages) const override {
81 switch (format) {
82 case blink::WebCryptoKeyFormatRaw:
83 case blink::WebCryptoKeyFormatJwk:
84 return CheckKeyCreationUsages(kAllKeyUsages, usages, false);
85 default:
86 return Status::ErrorUnsupportedImportKeyFormat();
90 Status ImportKeyRaw(const CryptoData& key_data,
91 const blink::WebCryptoAlgorithm& algorithm,
92 bool extractable,
93 blink::WebCryptoKeyUsageMask usages,
94 blink::WebCryptoKey* key) const override {
95 const blink::WebCryptoHmacImportParams* params =
96 algorithm.hmacImportParams();
98 unsigned int keylen_bits = 0;
99 Status status = GetHmacImportKeyLengthBits(params, key_data.byte_length(),
100 &keylen_bits);
101 if (status.IsError())
102 return status;
104 const blink::WebCryptoKeyAlgorithm key_algorithm =
105 blink::WebCryptoKeyAlgorithm::createHmac(params->hash().id(),
106 keylen_bits);
108 // If no bit truncation was requested, then done!
109 if ((keylen_bits % 8) == 0) {
110 return CreateWebCryptoSecretKey(key_data, key_algorithm, extractable,
111 usages, key);
114 // Otherwise zero out the unused bits in the key data before importing.
115 std::vector<uint8_t> modified_key_data(
116 key_data.bytes(), key_data.bytes() + key_data.byte_length());
117 TruncateToBitLength(keylen_bits, &modified_key_data);
118 return CreateWebCryptoSecretKey(CryptoData(modified_key_data),
119 key_algorithm, extractable, usages, key);
122 Status ImportKeyJwk(const CryptoData& key_data,
123 const blink::WebCryptoAlgorithm& algorithm,
124 bool extractable,
125 blink::WebCryptoKeyUsageMask usages,
126 blink::WebCryptoKey* key) const override {
127 const char* algorithm_name =
128 GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
129 if (!algorithm_name)
130 return Status::ErrorUnexpected();
132 std::vector<uint8_t> raw_data;
133 Status status = ReadSecretKeyJwk(key_data, algorithm_name, extractable,
134 usages, &raw_data);
135 if (status.IsError())
136 return status;
138 return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
139 key);
142 Status ExportKeyRaw(const blink::WebCryptoKey& key,
143 std::vector<uint8_t>* buffer) const override {
144 *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
145 return Status::Success();
148 Status ExportKeyJwk(const blink::WebCryptoKey& key,
149 std::vector<uint8_t>* buffer) const override {
150 SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key);
151 const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
153 const char* algorithm_name =
154 GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
155 if (!algorithm_name)
156 return Status::ErrorUnexpected();
158 WriteSecretKeyJwk(CryptoData(raw_data), algorithm_name, key.extractable(),
159 key.usages(), buffer);
161 return Status::Success();
164 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
165 const blink::WebCryptoKey& key,
166 const CryptoData& data,
167 std::vector<uint8_t>* buffer) const override {
168 const blink::WebCryptoAlgorithm& hash =
169 key.algorithm().hmacParams()->hash();
171 return SignHmac(SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data,
172 buffer);
175 Status Verify(const blink::WebCryptoAlgorithm& algorithm,
176 const blink::WebCryptoKey& key,
177 const CryptoData& signature,
178 const CryptoData& data,
179 bool* signature_match) const override {
180 std::vector<uint8_t> result;
181 Status status = Sign(algorithm, key, data, &result);
183 if (status.IsError())
184 return status;
186 // Do not allow verification of truncated MACs.
187 *signature_match =
188 result.size() == signature.byte_length() &&
189 crypto::SecureMemEqual(vector_as_array(&result), signature.bytes(),
190 signature.byte_length());
192 return Status::Success();
195 Status SerializeKeyForClone(
196 const blink::WebCryptoKey& key,
197 blink::WebVector<uint8_t>* key_data) const override {
198 key_data->assign(SymKeyOpenSsl::Cast(key)->serialized_key_data());
199 return Status::Success();
202 Status DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
203 blink::WebCryptoKeyType type,
204 bool extractable,
205 blink::WebCryptoKeyUsageMask usages,
206 const CryptoData& key_data,
207 blink::WebCryptoKey* key) const override {
208 return CreateWebCryptoSecretKey(key_data, algorithm, extractable, usages,
209 key);
212 Status GetKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
213 bool* has_length_bits,
214 unsigned int* length_bits) const override {
215 return GetHmacKeyLength(key_length_algorithm, has_length_bits, length_bits);
219 } // namespace
221 AlgorithmImplementation* CreatePlatformHmacImplementation() {
222 return new HmacImplementation;
225 } // namespace webcrypto