Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / openssl / hmac_openssl.cc
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/numerics/safe_math.h"
9 #include "base/stl_util.h"
10 #include "content/child/webcrypto/algorithm_implementation.h"
11 #include "content/child/webcrypto/crypto_data.h"
12 #include "content/child/webcrypto/jwk.h"
13 #include "content/child/webcrypto/openssl/key_openssl.h"
14 #include "content/child/webcrypto/openssl/sym_key_openssl.h"
15 #include "content/child/webcrypto/openssl/util_openssl.h"
16 #include "content/child/webcrypto/status.h"
17 #include "content/child/webcrypto/webcrypto_util.h"
18 #include "crypto/openssl_util.h"
19 #include "crypto/secure_util.h"
20 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
21 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
22
23 namespace content {
24
25 namespace webcrypto {
26
27 namespace {
28
29 const blink::WebCryptoKeyUsageMask kAllKeyUsages =
30     blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
31
32 Status SignHmac(const std::vector<uint8_t>& raw_key,
33                 const blink::WebCryptoAlgorithm& hash,
34                 const CryptoData& data,
35                 std::vector<uint8_t>* buffer) {
36   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
37
38   const EVP_MD* digest_algorithm = GetDigest(hash.id());
39   if (!digest_algorithm)
40     return Status::ErrorUnsupported();
41   unsigned int hmac_expected_length = EVP_MD_size(digest_algorithm);
42
43   // OpenSSL wierdness here.
44   // First, HMAC() needs a void* for the key data, so make one up front as a
45   // cosmetic to avoid a cast. Second, OpenSSL does not like a NULL key,
46   // which will result if the raw_key vector is empty; an entirely valid
47   // case. Handle this specific case by pointing to an empty array.
48   const unsigned char null_key[] = {};
49   const void* const raw_key_voidp = raw_key.size() ? &raw_key[0] : null_key;
50
51   buffer->resize(hmac_expected_length);
52   crypto::ScopedOpenSSLSafeSizeBuffer<EVP_MAX_MD_SIZE> hmac_result(
53       vector_as_array(buffer), hmac_expected_length);
54
55   unsigned int hmac_actual_length;
56   unsigned char* const success = HMAC(digest_algorithm,
57                                       raw_key_voidp,
58                                       raw_key.size(),
59                                       data.bytes(),
60                                       data.byte_length(),
61                                       hmac_result.safe_buffer(),
62                                       &hmac_actual_length);
63   if (!success || hmac_actual_length != hmac_expected_length)
64     return Status::OperationError();
65
66   return Status::Success();
67 }
68
69 class HmacImplementation : public AlgorithmImplementation {
70  public:
71   HmacImplementation() {}
72
73   virtual Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
74                                    bool extractable,
75                                    blink::WebCryptoKeyUsageMask usage_mask,
76                                    blink::WebCryptoKey* key) const OVERRIDE {
77     const blink::WebCryptoHmacKeyGenParams* params =
78         algorithm.hmacKeyGenParams();
79
80     unsigned int keylen_bits = 0;
81     Status status = GetHmacKeyGenLengthInBits(params, &keylen_bits);
82     if (status.IsError())
83       return status;
84
85     return GenerateSecretKeyOpenSsl(blink::WebCryptoKeyAlgorithm::createHmac(
86                                         params->hash().id(), keylen_bits),
87                                     extractable,
88                                     usage_mask,
89                                     keylen_bits / 8,
90                                     key);
91   }
92
93   virtual Status VerifyKeyUsagesBeforeImportKey(
94       blink::WebCryptoKeyFormat format,
95       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
96     switch (format) {
97       case blink::WebCryptoKeyFormatRaw:
98       case blink::WebCryptoKeyFormatJwk:
99         return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
100       default:
101         return Status::ErrorUnsupportedImportKeyFormat();
102     }
103   }
104
105   virtual Status VerifyKeyUsagesBeforeGenerateKey(
106       blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
107     return CheckKeyCreationUsages(kAllKeyUsages, usage_mask);
108   }
109
110   virtual Status ImportKeyRaw(const CryptoData& key_data,
111                               const blink::WebCryptoAlgorithm& algorithm,
112                               bool extractable,
113                               blink::WebCryptoKeyUsageMask usage_mask,
114                               blink::WebCryptoKey* key) const OVERRIDE {
115     const blink::WebCryptoAlgorithm& hash =
116         algorithm.hmacImportParams()->hash();
117
118     base::CheckedNumeric<unsigned int> keylen_bits(key_data.byte_length());
119     keylen_bits *= 8;
120
121     if (!keylen_bits.IsValid())
122       return Status::ErrorDataTooLarge();
123
124     return ImportKeyRawOpenSsl(key_data,
125                                blink::WebCryptoKeyAlgorithm::createHmac(
126                                    hash.id(), keylen_bits.ValueOrDie()),
127                                extractable,
128                                usage_mask,
129                                key);
130   }
131
132   virtual Status ImportKeyJwk(const CryptoData& key_data,
133                               const blink::WebCryptoAlgorithm& algorithm,
134                               bool extractable,
135                               blink::WebCryptoKeyUsageMask usage_mask,
136                               blink::WebCryptoKey* key) const OVERRIDE {
137     const char* algorithm_name =
138         GetJwkHmacAlgorithmName(algorithm.hmacImportParams()->hash().id());
139     if (!algorithm_name)
140       return Status::ErrorUnexpected();
141
142     std::vector<uint8_t> raw_data;
143     Status status = ReadSecretKeyJwk(
144         key_data, algorithm_name, extractable, usage_mask, &raw_data);
145     if (status.IsError())
146       return status;
147
148     return ImportKeyRaw(
149         CryptoData(raw_data), algorithm, extractable, usage_mask, key);
150   }
151
152   virtual Status ExportKeyRaw(const blink::WebCryptoKey& key,
153                               std::vector<uint8_t>* buffer) const OVERRIDE {
154     *buffer = SymKeyOpenSsl::Cast(key)->raw_key_data();
155     return Status::Success();
156   }
157
158   virtual Status ExportKeyJwk(const blink::WebCryptoKey& key,
159                               std::vector<uint8_t>* buffer) const OVERRIDE {
160     SymKeyOpenSsl* sym_key = SymKeyOpenSsl::Cast(key);
161     const std::vector<uint8_t>& raw_data = sym_key->raw_key_data();
162
163     const char* algorithm_name =
164         GetJwkHmacAlgorithmName(key.algorithm().hmacParams()->hash().id());
165     if (!algorithm_name)
166       return Status::ErrorUnexpected();
167
168     WriteSecretKeyJwk(CryptoData(raw_data),
169                       algorithm_name,
170                       key.extractable(),
171                       key.usages(),
172                       buffer);
173
174     return Status::Success();
175   }
176
177   virtual Status Sign(const blink::WebCryptoAlgorithm& algorithm,
178                       const blink::WebCryptoKey& key,
179                       const CryptoData& data,
180                       std::vector<uint8_t>* buffer) const OVERRIDE {
181     const blink::WebCryptoAlgorithm& hash =
182         key.algorithm().hmacParams()->hash();
183
184     return SignHmac(
185         SymKeyOpenSsl::Cast(key)->raw_key_data(), hash, data, buffer);
186   }
187
188   virtual Status Verify(const blink::WebCryptoAlgorithm& algorithm,
189                         const blink::WebCryptoKey& key,
190                         const CryptoData& signature,
191                         const CryptoData& data,
192                         bool* signature_match) const OVERRIDE {
193     std::vector<uint8_t> result;
194     Status status = Sign(algorithm, key, data, &result);
195
196     if (status.IsError())
197       return status;
198
199     // Do not allow verification of truncated MACs.
200     *signature_match = result.size() == signature.byte_length() &&
201                        crypto::SecureMemEqual(vector_as_array(&result),
202                                               signature.bytes(),
203                                               signature.byte_length());
204
205     return Status::Success();
206   }
207 };
208
209 }  // namespace
210
211 AlgorithmImplementation* CreatePlatformHmacImplementation() {
212   return new HmacImplementation;
213 }
214
215 }  // namespace webcrypto
216
217 }  // namespace content