| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/webcrypto/webcrypto_util.h" | 5 #include "components/webcrypto/webcrypto_util.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/numerics/safe_math.h" | |
| 9 #include "components/webcrypto/status.h" | 8 #include "components/webcrypto/status.h" |
| 10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
| 11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
| 12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 11 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
| 13 | 12 |
| 14 namespace webcrypto { | 13 namespace webcrypto { |
| 15 | 14 |
| 16 namespace { | 15 namespace { |
| 17 | 16 |
| 18 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | 17 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, |
| 19 // to unsigned int. | 18 // to unsigned int. |
| 20 bool BigIntegerToUint(const uint8_t* data, | 19 bool BigIntegerToUint(const uint8_t* data, |
| 21 size_t data_size, | 20 size_t data_size, |
| 22 unsigned int* result) { | 21 unsigned int* result) { |
| 23 if (data_size == 0) | 22 if (data_size == 0) |
| 24 return false; | 23 return false; |
| 25 | 24 |
| 26 *result = 0; | 25 *result = 0; |
| 27 for (size_t i = 0; i < data_size; ++i) { | 26 for (size_t i = 0; i < data_size; ++i) { |
| 28 size_t reverse_i = data_size - i - 1; | 27 size_t reverse_i = data_size - i - 1; |
| 29 | 28 |
| 30 if (reverse_i >= sizeof(*result) && data[i]) | 29 if (reverse_i >= sizeof(*result) && data[i]) |
| 31 return false; // Too large for a uint. | 30 return false; // Too large for a uint. |
| 32 | 31 |
| 33 *result |= data[i] << 8 * reverse_i; | 32 *result |= data[i] << 8 * reverse_i; |
| 34 } | 33 } |
| 35 return true; | 34 return true; |
| 36 } | 35 } |
| 37 | 36 |
| 38 Status GetShaBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm, | |
| 39 unsigned int* block_size_bits) { | |
| 40 switch (algorithm.id()) { | |
| 41 case blink::WebCryptoAlgorithmIdSha1: | |
| 42 case blink::WebCryptoAlgorithmIdSha256: | |
| 43 *block_size_bits = 512; | |
| 44 return Status::Success(); | |
| 45 case blink::WebCryptoAlgorithmIdSha384: | |
| 46 case blink::WebCryptoAlgorithmIdSha512: | |
| 47 *block_size_bits = 1024; | |
| 48 return Status::Success(); | |
| 49 default: | |
| 50 return Status::ErrorUnsupported(); | |
| 51 } | |
| 52 } | |
| 53 | 37 |
| 54 } // namespace | 38 } // namespace |
| 55 | 39 |
| 56 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | 40 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { |
| 57 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | 41 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); |
| 58 } | 42 } |
| 59 | 43 |
| 60 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( | |
| 61 blink::WebCryptoAlgorithmId hash_id, | |
| 62 unsigned int length_bits) { | |
| 63 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
| 64 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 65 blink::WebCryptoAlgorithmIdHmac, | |
| 66 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true, | |
| 67 length_bits)); | |
| 68 } | |
| 69 | |
| 70 blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength( | |
| 71 blink::WebCryptoAlgorithmId hash_id) { | |
| 72 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
| 73 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 74 blink::WebCryptoAlgorithmIdHmac, | |
| 75 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0)); | |
| 76 } | |
| 77 | |
| 78 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( | 44 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( |
| 79 blink::WebCryptoAlgorithmId id, | 45 blink::WebCryptoAlgorithmId id, |
| 80 blink::WebCryptoAlgorithmId hash_id) { | 46 blink::WebCryptoAlgorithmId hash_id) { |
| 81 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | 47 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); |
| 82 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 48 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
| 83 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); | 49 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); |
| 84 } | 50 } |
| 85 | 51 |
| 86 blink::WebCryptoAlgorithm CreateEcImportAlgorithm( | 52 blink::WebCryptoAlgorithm CreateEcImportAlgorithm( |
| 87 blink::WebCryptoAlgorithmId id, | 53 blink::WebCryptoAlgorithmId id, |
| 88 blink::WebCryptoNamedCurve named_curve) { | 54 blink::WebCryptoNamedCurve named_curve) { |
| 89 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 55 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
| 90 id, new blink::WebCryptoEcKeyImportParams(named_curve)); | 56 id, new blink::WebCryptoEcKeyImportParams(named_curve)); |
| 91 } | 57 } |
| 92 | 58 |
| 93 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, | 59 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, |
| 94 blink::WebCryptoKeyUsageMask b) { | 60 blink::WebCryptoKeyUsageMask b) { |
| 95 return (a & b) == b; | 61 return (a & b) == b; |
| 96 } | 62 } |
| 97 | 63 |
| 98 // The WebCrypto spec defines the default value for the tag length, as well as | |
| 99 // the allowed values for tag length. | |
| 100 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params, | |
| 101 unsigned int* tag_length_bits) { | |
| 102 *tag_length_bits = 128; | |
| 103 if (params->hasTagLengthBits()) | |
| 104 *tag_length_bits = params->optionalTagLengthBits(); | |
| 105 | |
| 106 if (*tag_length_bits != 32 && *tag_length_bits != 64 && | |
| 107 *tag_length_bits != 96 && *tag_length_bits != 104 && | |
| 108 *tag_length_bits != 112 && *tag_length_bits != 120 && | |
| 109 *tag_length_bits != 128) | |
| 110 return Status::ErrorInvalidAesGcmTagLength(); | |
| 111 | |
| 112 return Status::Success(); | |
| 113 } | |
| 114 | |
| 115 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params, | |
| 116 unsigned int* keylen_bits) { | |
| 117 *keylen_bits = params->lengthBits(); | |
| 118 | |
| 119 if (*keylen_bits == 128 || *keylen_bits == 256) | |
| 120 return Status::Success(); | |
| 121 | |
| 122 // BoringSSL does not support 192-bit AES. | |
| 123 if (*keylen_bits == 192) | |
| 124 return Status::ErrorAes192BitUnsupported(); | |
| 125 | |
| 126 return Status::ErrorGenerateAesKeyLength(); | |
| 127 } | |
| 128 | |
| 129 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params, | |
| 130 unsigned int* keylen_bits) { | |
| 131 if (!params->hasLengthBits()) | |
| 132 return GetShaBlockSizeBits(params->hash(), keylen_bits); | |
| 133 | |
| 134 *keylen_bits = params->optionalLengthBits(); | |
| 135 | |
| 136 // Zero-length HMAC keys are disallowed by the spec. | |
| 137 if (*keylen_bits == 0) | |
| 138 return Status::ErrorGenerateHmacKeyLengthZero(); | |
| 139 | |
| 140 return Status::Success(); | |
| 141 } | |
| 142 | |
| 143 Status GetHmacImportKeyLengthBits( | |
| 144 const blink::WebCryptoHmacImportParams* params, | |
| 145 unsigned int key_data_byte_length, | |
| 146 unsigned int* keylen_bits) { | |
| 147 if (key_data_byte_length == 0) | |
| 148 return Status::ErrorHmacImportEmptyKey(); | |
| 149 | |
| 150 // Make sure that the key data's length can be represented in bits without | |
| 151 // overflow. | |
| 152 base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length); | |
| 153 checked_keylen_bits *= 8; | |
| 154 | |
| 155 if (!checked_keylen_bits.IsValid()) | |
| 156 return Status::ErrorDataTooLarge(); | |
| 157 | |
| 158 unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie(); | |
| 159 | |
| 160 // Determine how many bits of the input to use. | |
| 161 *keylen_bits = data_keylen_bits; | |
| 162 if (params->hasLengthBits()) { | |
| 163 // The requested bit length must be: | |
| 164 // * No longer than the input data length | |
| 165 // * At most 7 bits shorter. | |
| 166 if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length) | |
| 167 return Status::ErrorHmacImportBadLength(); | |
| 168 *keylen_bits = params->optionalLengthBits(); | |
| 169 } | |
| 170 | |
| 171 return Status::Success(); | |
| 172 } | |
| 173 | |
| 174 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) { | |
| 175 if (keylen_bytes == 16 || keylen_bytes == 32) | |
| 176 return Status::Success(); | |
| 177 | |
| 178 // BoringSSL does not support 192-bit AES. | |
| 179 if (keylen_bytes == 24) | |
| 180 return Status::ErrorAes192BitUnsupported(); | |
| 181 | |
| 182 return Status::ErrorImportAesKeyLength(); | |
| 183 } | |
| 184 | 64 |
| 185 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, | 65 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, |
| 186 blink::WebCryptoKeyUsageMask actual_usages, | 66 blink::WebCryptoKeyUsageMask actual_usages, |
| 187 bool allow_empty_usages) { | 67 bool allow_empty_usages) { |
| 188 if (!allow_empty_usages && actual_usages == 0) | 68 if (!allow_empty_usages && actual_usages == 0) |
| 189 return Status::ErrorCreateKeyEmptyUsages(); | 69 return Status::ErrorCreateKeyEmptyUsages(); |
| 190 | 70 |
| 191 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) | 71 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) |
| 192 return Status::ErrorCreateKeyBadUsages(); | 72 return Status::ErrorCreateKeyBadUsages(); |
| 193 return Status::Success(); | 73 return Status::Success(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 bytes->resize(length_bytes); | 137 bytes->resize(length_bytes); |
| 258 } | 138 } |
| 259 | 139 |
| 260 size_t remainder_bits = length_bits % 8; | 140 size_t remainder_bits = length_bits % 8; |
| 261 | 141 |
| 262 // Zero any "unused bits" in the final byte | 142 // Zero any "unused bits" in the final byte |
| 263 if (remainder_bits) | 143 if (remainder_bits) |
| 264 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits); | 144 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits); |
| 265 } | 145 } |
| 266 | 146 |
| 267 Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
| 268 bool* has_length_bits, | |
| 269 unsigned int* length_bits) { | |
| 270 const blink::WebCryptoAesDerivedKeyParams* params = | |
| 271 key_length_algorithm.aesDerivedKeyParams(); | |
| 272 | |
| 273 *has_length_bits = true; | |
| 274 *length_bits = params->lengthBits(); | |
| 275 | |
| 276 if (*length_bits == 128 || *length_bits == 256) | |
| 277 return Status::Success(); | |
| 278 | |
| 279 // BoringSSL does not support 192-bit AES. | |
| 280 if (*length_bits == 192) | |
| 281 return Status::ErrorAes192BitUnsupported(); | |
| 282 | |
| 283 return Status::ErrorGetAesKeyLength(); | |
| 284 } | |
| 285 | |
| 286 Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
| 287 bool* has_length_bits, | |
| 288 unsigned int* length_bits) { | |
| 289 const blink::WebCryptoHmacImportParams* params = | |
| 290 key_length_algorithm.hmacImportParams(); | |
| 291 | |
| 292 if (params->hasLengthBits()) { | |
| 293 *has_length_bits = true; | |
| 294 *length_bits = params->optionalLengthBits(); | |
| 295 if (*length_bits == 0) | |
| 296 return Status::ErrorGetHmacKeyLengthZero(); | |
| 297 return Status::Success(); | |
| 298 } | |
| 299 | |
| 300 *has_length_bits = true; | |
| 301 return GetShaBlockSizeBits(params->hash(), length_bits); | |
| 302 } | |
| 303 | 147 |
| 304 Status GetUsagesForGenerateAsymmetricKey( | 148 Status GetUsagesForGenerateAsymmetricKey( |
| 305 blink::WebCryptoKeyUsageMask combined_usages, | 149 blink::WebCryptoKeyUsageMask combined_usages, |
| 306 blink::WebCryptoKeyUsageMask all_public_usages, | 150 blink::WebCryptoKeyUsageMask all_public_usages, |
| 307 blink::WebCryptoKeyUsageMask all_private_usages, | 151 blink::WebCryptoKeyUsageMask all_private_usages, |
| 308 blink::WebCryptoKeyUsageMask* public_usages, | 152 blink::WebCryptoKeyUsageMask* public_usages, |
| 309 blink::WebCryptoKeyUsageMask* private_usages) { | 153 blink::WebCryptoKeyUsageMask* private_usages) { |
| 310 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages, | 154 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages, |
| 311 combined_usages, true); | 155 combined_usages, true); |
| 312 if (status.IsError()) | 156 if (status.IsError()) |
| 313 return status; | 157 return status; |
| 314 | 158 |
| 315 *public_usages = combined_usages & all_public_usages; | 159 *public_usages = combined_usages & all_public_usages; |
| 316 *private_usages = combined_usages & all_private_usages; | 160 *private_usages = combined_usages & all_private_usages; |
| 317 | 161 |
| 318 if (*private_usages == 0) | 162 if (*private_usages == 0) |
| 319 return Status::ErrorCreateKeyEmptyUsages(); | 163 return Status::ErrorCreateKeyEmptyUsages(); |
| 320 | 164 |
| 321 return Status::Success(); | 165 return Status::Success(); |
| 322 } | 166 } |
| 323 | 167 |
| 324 } // namespace webcrypto | 168 } // namespace webcrypto |
| OLD | NEW |