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