| 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 |