| 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 "content/child/webcrypto/webcrypto_util.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/numerics/safe_math.h" | |
| 9 #include "content/child/webcrypto/status.h" | |
| 10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
| 11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
| 13 | |
| 14 namespace content { | |
| 15 | |
| 16 namespace webcrypto { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | |
| 21 // to unsigned int. | |
| 22 bool BigIntegerToUint(const uint8_t* data, | |
| 23 unsigned int data_size, | |
| 24 unsigned int* result) { | |
| 25 if (data_size == 0) | |
| 26 return false; | |
| 27 | |
| 28 *result = 0; | |
| 29 for (size_t i = 0; i < data_size; ++i) { | |
| 30 size_t reverse_i = data_size - i - 1; | |
| 31 | |
| 32 if (reverse_i >= sizeof(*result) && data[i]) | |
| 33 return false; // Too large for a uint. | |
| 34 | |
| 35 *result |= data[i] << 8 * reverse_i; | |
| 36 } | |
| 37 return true; | |
| 38 } | |
| 39 | |
| 40 Status GetShaBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm, | |
| 41 unsigned int* block_size_bits) { | |
| 42 switch (algorithm.id()) { | |
| 43 case blink::WebCryptoAlgorithmIdSha1: | |
| 44 case blink::WebCryptoAlgorithmIdSha256: | |
| 45 *block_size_bits = 512; | |
| 46 return Status::Success(); | |
| 47 case blink::WebCryptoAlgorithmIdSha384: | |
| 48 case blink::WebCryptoAlgorithmIdSha512: | |
| 49 *block_size_bits = 1024; | |
| 50 return Status::Success(); | |
| 51 default: | |
| 52 return Status::ErrorUnsupported(); | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 } // namespace | |
| 57 | |
| 58 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | |
| 59 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | |
| 60 } | |
| 61 | |
| 62 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( | |
| 63 blink::WebCryptoAlgorithmId hash_id, | |
| 64 unsigned int length_bits) { | |
| 65 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
| 66 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 67 blink::WebCryptoAlgorithmIdHmac, | |
| 68 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true, | |
| 69 length_bits)); | |
| 70 } | |
| 71 | |
| 72 blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength( | |
| 73 blink::WebCryptoAlgorithmId hash_id) { | |
| 74 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
| 75 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 76 blink::WebCryptoAlgorithmIdHmac, | |
| 77 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0)); | |
| 78 } | |
| 79 | |
| 80 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( | |
| 81 blink::WebCryptoAlgorithmId id, | |
| 82 blink::WebCryptoAlgorithmId hash_id) { | |
| 83 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
| 84 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 85 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); | |
| 86 } | |
| 87 | |
| 88 blink::WebCryptoAlgorithm CreateEcImportAlgorithm( | |
| 89 blink::WebCryptoAlgorithmId id, | |
| 90 blink::WebCryptoNamedCurve named_curve) { | |
| 91 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 92 id, new blink::WebCryptoEcKeyImportParams(named_curve)); | |
| 93 } | |
| 94 | |
| 95 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, | |
| 96 blink::WebCryptoKeyUsageMask b) { | |
| 97 return (a & b) == b; | |
| 98 } | |
| 99 | |
| 100 // TODO(eroman): Move this helper to WebCryptoKey. | |
| 101 bool KeyUsageAllows(const blink::WebCryptoKey& key, | |
| 102 const blink::WebCryptoKeyUsage usage) { | |
| 103 return ((key.usages() & usage) != 0); | |
| 104 } | |
| 105 | |
| 106 // The WebCrypto spec defines the default value for the tag length, as well as | |
| 107 // the allowed values for tag length. | |
| 108 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params, | |
| 109 unsigned int* tag_length_bits) { | |
| 110 *tag_length_bits = 128; | |
| 111 if (params->hasTagLengthBits()) | |
| 112 *tag_length_bits = params->optionalTagLengthBits(); | |
| 113 | |
| 114 if (*tag_length_bits != 32 && *tag_length_bits != 64 && | |
| 115 *tag_length_bits != 96 && *tag_length_bits != 104 && | |
| 116 *tag_length_bits != 112 && *tag_length_bits != 120 && | |
| 117 *tag_length_bits != 128) | |
| 118 return Status::ErrorInvalidAesGcmTagLength(); | |
| 119 | |
| 120 return Status::Success(); | |
| 121 } | |
| 122 | |
| 123 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params, | |
| 124 unsigned int* keylen_bits) { | |
| 125 *keylen_bits = params->lengthBits(); | |
| 126 | |
| 127 if (*keylen_bits == 128 || *keylen_bits == 256) | |
| 128 return Status::Success(); | |
| 129 | |
| 130 // BoringSSL does not support 192-bit AES. | |
| 131 if (*keylen_bits == 192) | |
| 132 return Status::ErrorAes192BitUnsupported(); | |
| 133 | |
| 134 return Status::ErrorGenerateAesKeyLength(); | |
| 135 } | |
| 136 | |
| 137 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params, | |
| 138 unsigned int* keylen_bits) { | |
| 139 if (!params->hasLengthBits()) | |
| 140 return GetShaBlockSizeBits(params->hash(), keylen_bits); | |
| 141 | |
| 142 *keylen_bits = params->optionalLengthBits(); | |
| 143 | |
| 144 // Zero-length HMAC keys are disallowed by the spec. | |
| 145 if (*keylen_bits == 0) | |
| 146 return Status::ErrorGenerateHmacKeyLengthZero(); | |
| 147 | |
| 148 return Status::Success(); | |
| 149 } | |
| 150 | |
| 151 Status GetHmacImportKeyLengthBits( | |
| 152 const blink::WebCryptoHmacImportParams* params, | |
| 153 unsigned int key_data_byte_length, | |
| 154 unsigned int* keylen_bits) { | |
| 155 if (key_data_byte_length == 0) | |
| 156 return Status::ErrorHmacImportEmptyKey(); | |
| 157 | |
| 158 // Make sure that the key data's length can be represented in bits without | |
| 159 // overflow. | |
| 160 base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length); | |
| 161 checked_keylen_bits *= 8; | |
| 162 | |
| 163 if (!checked_keylen_bits.IsValid()) | |
| 164 return Status::ErrorDataTooLarge(); | |
| 165 | |
| 166 unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie(); | |
| 167 | |
| 168 // Determine how many bits of the input to use. | |
| 169 *keylen_bits = data_keylen_bits; | |
| 170 if (params->hasLengthBits()) { | |
| 171 // The requested bit length must be: | |
| 172 // * No longer than the input data length | |
| 173 // * At most 7 bits shorter. | |
| 174 if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length) | |
| 175 return Status::ErrorHmacImportBadLength(); | |
| 176 *keylen_bits = params->optionalLengthBits(); | |
| 177 } | |
| 178 | |
| 179 return Status::Success(); | |
| 180 } | |
| 181 | |
| 182 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) { | |
| 183 if (keylen_bytes == 16 || keylen_bytes == 32) | |
| 184 return Status::Success(); | |
| 185 | |
| 186 // BoringSSL does not support 192-bit AES. | |
| 187 if (keylen_bytes == 24) | |
| 188 return Status::ErrorAes192BitUnsupported(); | |
| 189 | |
| 190 return Status::ErrorImportAesKeyLength(); | |
| 191 } | |
| 192 | |
| 193 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, | |
| 194 blink::WebCryptoKeyUsageMask actual_usages, | |
| 195 bool allow_empty_usages) { | |
| 196 if (!allow_empty_usages && actual_usages == 0) | |
| 197 return Status::ErrorCreateKeyEmptyUsages(); | |
| 198 | |
| 199 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) | |
| 200 return Status::ErrorCreateKeyBadUsages(); | |
| 201 return Status::Success(); | |
| 202 } | |
| 203 | |
| 204 Status GetRsaKeyGenParameters( | |
| 205 const blink::WebCryptoRsaHashedKeyGenParams* params, | |
| 206 unsigned int* public_exponent, | |
| 207 unsigned int* modulus_length_bits) { | |
| 208 *modulus_length_bits = params->modulusLengthBits(); | |
| 209 | |
| 210 // Limit key sizes to those supported by NSS: | |
| 211 // * Multiple of 8 bits | |
| 212 // * 256 bits to 16K bits | |
| 213 if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 || | |
| 214 (*modulus_length_bits % 8) != 0) { | |
| 215 return Status::ErrorGenerateRsaUnsupportedModulus(); | |
| 216 } | |
| 217 | |
| 218 if (!BigIntegerToUint(params->publicExponent().data(), | |
| 219 params->publicExponent().size(), public_exponent)) { | |
| 220 return Status::ErrorGenerateKeyPublicExponent(); | |
| 221 } | |
| 222 | |
| 223 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To | |
| 224 // avoid feeding OpenSSL data that will hang use a whitelist. | |
| 225 if (*public_exponent != 3 && *public_exponent != 65537) | |
| 226 return Status::ErrorGenerateKeyPublicExponent(); | |
| 227 | |
| 228 return Status::Success(); | |
| 229 } | |
| 230 | |
| 231 Status VerifyUsagesBeforeImportAsymmetricKey( | |
| 232 blink::WebCryptoKeyFormat format, | |
| 233 blink::WebCryptoKeyUsageMask all_public_key_usages, | |
| 234 blink::WebCryptoKeyUsageMask all_private_key_usages, | |
| 235 blink::WebCryptoKeyUsageMask usages) { | |
| 236 switch (format) { | |
| 237 case blink::WebCryptoKeyFormatSpki: | |
| 238 return CheckKeyCreationUsages(all_public_key_usages, usages, true); | |
| 239 case blink::WebCryptoKeyFormatPkcs8: | |
| 240 return CheckKeyCreationUsages(all_private_key_usages, usages, false); | |
| 241 case blink::WebCryptoKeyFormatJwk: { | |
| 242 // The JWK could represent either a public key or private key. The usages | |
| 243 // must make sense for one of the two. The usages will be checked again by | |
| 244 // ImportKeyJwk() once the key type has been determined. | |
| 245 if (CheckKeyCreationUsages( | |
| 246 all_public_key_usages, usages, true).IsError() && | |
| 247 CheckKeyCreationUsages( | |
| 248 all_private_key_usages, usages, false).IsError()) { | |
| 249 return Status::ErrorCreateKeyBadUsages(); | |
| 250 } | |
| 251 return Status::Success(); | |
| 252 } | |
| 253 default: | |
| 254 return Status::ErrorUnsupportedImportKeyFormat(); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) { | |
| 259 size_t length_bytes = NumBitsToBytes(length_bits); | |
| 260 | |
| 261 if (bytes->size() != length_bytes) { | |
| 262 CHECK_LT(length_bytes, bytes->size()); | |
| 263 bytes->resize(length_bytes); | |
| 264 } | |
| 265 | |
| 266 size_t remainder_bits = length_bits % 8; | |
| 267 | |
| 268 // Zero any "unused bits" in the final byte | |
| 269 if (remainder_bits) | |
| 270 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits); | |
| 271 } | |
| 272 | |
| 273 Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
| 274 bool* has_length_bits, | |
| 275 unsigned int* length_bits) { | |
| 276 const blink::WebCryptoAesDerivedKeyParams* params = | |
| 277 key_length_algorithm.aesDerivedKeyParams(); | |
| 278 | |
| 279 *has_length_bits = true; | |
| 280 *length_bits = params->lengthBits(); | |
| 281 | |
| 282 if (*length_bits == 128 || *length_bits == 256) | |
| 283 return Status::Success(); | |
| 284 | |
| 285 // BoringSSL does not support 192-bit AES. | |
| 286 if (*length_bits == 192) | |
| 287 return Status::ErrorAes192BitUnsupported(); | |
| 288 | |
| 289 return Status::ErrorGetAesKeyLength(); | |
| 290 } | |
| 291 | |
| 292 Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
| 293 bool* has_length_bits, | |
| 294 unsigned int* length_bits) { | |
| 295 const blink::WebCryptoHmacImportParams* params = | |
| 296 key_length_algorithm.hmacImportParams(); | |
| 297 | |
| 298 if (params->hasLengthBits()) { | |
| 299 *has_length_bits = true; | |
| 300 *length_bits = params->optionalLengthBits(); | |
| 301 if (*length_bits == 0) | |
| 302 return Status::ErrorGetHmacKeyLengthZero(); | |
| 303 return Status::Success(); | |
| 304 } | |
| 305 | |
| 306 *has_length_bits = true; | |
| 307 return GetShaBlockSizeBits(params->hash(), length_bits); | |
| 308 } | |
| 309 | |
| 310 Status GetUsagesForGenerateAsymmetricKey( | |
| 311 blink::WebCryptoKeyUsageMask combined_usages, | |
| 312 blink::WebCryptoKeyUsageMask all_public_usages, | |
| 313 blink::WebCryptoKeyUsageMask all_private_usages, | |
| 314 blink::WebCryptoKeyUsageMask* public_usages, | |
| 315 blink::WebCryptoKeyUsageMask* private_usages) { | |
| 316 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages, | |
| 317 combined_usages, true); | |
| 318 if (status.IsError()) | |
| 319 return status; | |
| 320 | |
| 321 *public_usages = combined_usages & all_public_usages; | |
| 322 *private_usages = combined_usages & all_private_usages; | |
| 323 | |
| 324 if (*private_usages == 0) | |
| 325 return Status::ErrorCreateKeyEmptyUsages(); | |
| 326 | |
| 327 return Status::Success(); | |
| 328 } | |
| 329 | |
| 330 } // namespace webcrypto | |
| 331 | |
| 332 } // namespace content | |
| OLD | NEW |