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/strings/stringprintf.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 // TODO(eroman): Fix handling of empty biginteger. http://crbug.com/373552 26 if (data_size == 0) 27 return false; 28 29 *result = 0; 30 for (size_t i = 0; i < data_size; ++i) { 31 size_t reverse_i = data_size - i - 1; 32 33 if (reverse_i >= sizeof(*result) && data[i]) 34 return false; // Too large for a uint. 35 36 *result |= data[i] << 8 * reverse_i; 37 } 38 return true; 39 } 40 41 } // namespace 42 43 struct JwkToWebCryptoUsage { 44 const char* const jwk_key_op; 45 const blink::WebCryptoKeyUsage webcrypto_usage; 46 }; 47 48 // Keep this ordered according to the definition 49 // order of WebCrypto's "recognized key usage 50 // values". 51 // 52 // This is not required for spec compliance, 53 // however it makes the ordering of key_ops match 54 // that of WebCrypto's Key.usages. 55 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = { 56 {"encrypt", blink::WebCryptoKeyUsageEncrypt}, 57 {"decrypt", blink::WebCryptoKeyUsageDecrypt}, 58 {"sign", blink::WebCryptoKeyUsageSign}, 59 {"verify", blink::WebCryptoKeyUsageVerify}, 60 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey}, 61 {"deriveBits", blink::WebCryptoKeyUsageDeriveBits}, 62 {"wrapKey", blink::WebCryptoKeyUsageWrapKey}, 63 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}}; 64 65 // Modifies the input usage_mask by according to the key_op value. 66 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op, 67 blink::WebCryptoKeyUsageMask* usage_mask) { 68 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { 69 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) { 70 *usage_mask |= kJwkWebCryptoUsageMap[i].webcrypto_usage; 71 return true; 72 } 73 } 74 return false; 75 } 76 77 // Composes a Web Crypto usage mask from an array of JWK key_ops values. 78 Status GetWebCryptoUsagesFromJwkKeyOps( 79 const base::ListValue* jwk_key_ops_value, 80 blink::WebCryptoKeyUsageMask* usage_mask) { 81 *usage_mask = 0; 82 for (size_t i = 0; i < jwk_key_ops_value->GetSize(); ++i) { 83 std::string key_op; 84 if (!jwk_key_ops_value->GetString(i, &key_op)) { 85 return Status::ErrorJwkPropertyWrongType( 86 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string"); 87 } 88 // Unrecognized key_ops are silently skipped. 89 ignore_result(JwkKeyOpToWebCryptoUsage(key_op, usage_mask)); 90 } 91 return Status::Success(); 92 } 93 94 // Composes a JWK key_ops List from a Web Crypto usage mask. 95 // Note: Caller must assume ownership of returned instance. 96 base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages( 97 blink::WebCryptoKeyUsageMask usage_mask) { 98 base::ListValue* jwk_key_ops = new base::ListValue(); 99 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { 100 if (usage_mask & kJwkWebCryptoUsageMap[i].webcrypto_usage) 101 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op); 102 } 103 return jwk_key_ops; 104 } 105 106 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { 107 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); 108 } 109 110 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( 111 blink::WebCryptoAlgorithmId hash_id) { 112 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); 113 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( 114 blink::WebCryptoAlgorithmIdHmac, 115 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id))); 116 } 117 118 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( 119 blink::WebCryptoAlgorithmId id, 120 blink::WebCryptoAlgorithmId hash_id) { 121 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); 122 DCHECK(id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || 123 id == blink::WebCryptoAlgorithmIdRsaOaep); 124 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( 125 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); 126 } 127 128 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, 129 blink::WebCryptoKeyUsageMask b) { 130 return (a & b) == b; 131 } 132 133 // TODO(eroman): Move this helper to WebCryptoKey. 134 bool KeyUsageAllows(const blink::WebCryptoKey& key, 135 const blink::WebCryptoKeyUsage usage) { 136 return ((key.usages() & usage) != 0); 137 } 138 139 bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id) { 140 return alg_id == blink::WebCryptoAlgorithmIdRsaOaep || 141 alg_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5; 142 } 143 144 bool IsAlgorithmAsymmetric(blink::WebCryptoAlgorithmId alg_id) { 145 // TODO(padolph): include all other asymmetric algorithms once they are 146 // defined, e.g. EC and DH. 147 return IsAlgorithmRsa(alg_id); 148 } 149 150 // The WebCrypto spec defines the default value for the tag length, as well as 151 // the allowed values for tag length. 152 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params, 153 unsigned int* tag_length_bits) { 154 *tag_length_bits = 128; 155 if (params->hasTagLengthBits()) 156 *tag_length_bits = params->optionalTagLengthBits(); 157 158 if (*tag_length_bits != 32 && *tag_length_bits != 64 && 159 *tag_length_bits != 96 && *tag_length_bits != 104 && 160 *tag_length_bits != 112 && *tag_length_bits != 120 && 161 *tag_length_bits != 128) 162 return Status::ErrorInvalidAesGcmTagLength(); 163 164 return Status::Success(); 165 } 166 167 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params, 168 unsigned int* keylen_bits) { 169 *keylen_bits = params->lengthBits(); 170 171 if (*keylen_bits == 128 || *keylen_bits == 256) 172 return Status::Success(); 173 174 // BoringSSL does not support 192-bit AES. 175 if (*keylen_bits == 192) 176 return Status::ErrorAes192BitUnsupported(); 177 178 return Status::ErrorGenerateKeyLength(); 179 } 180 181 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params, 182 unsigned int* keylen_bits) { 183 if (!params->hasLengthBits()) { 184 switch (params->hash().id()) { 185 case blink::WebCryptoAlgorithmIdSha1: 186 case blink::WebCryptoAlgorithmIdSha256: 187 *keylen_bits = 512; 188 return Status::Success(); 189 case blink::WebCryptoAlgorithmIdSha384: 190 case blink::WebCryptoAlgorithmIdSha512: 191 *keylen_bits = 1024; 192 return Status::Success(); 193 default: 194 return Status::ErrorUnsupported(); 195 } 196 } 197 198 if (params->optionalLengthBits() % 8) 199 return Status::ErrorGenerateKeyLength(); 200 201 *keylen_bits = params->optionalLengthBits(); 202 203 // TODO(eroman): NSS fails when generating a zero-length secret key. 204 if (*keylen_bits == 0) 205 return Status::ErrorGenerateKeyLength(); 206 207 return Status::Success(); 208 } 209 210 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) { 211 if (keylen_bytes == 16 || keylen_bytes == 32) 212 return Status::Success(); 213 214 // BoringSSL does not support 192-bit AES. 215 if (keylen_bytes == 24) 216 return Status::ErrorAes192BitUnsupported(); 217 218 return Status::ErrorImportAesKeyLength(); 219 } 220 221 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, 222 blink::WebCryptoKeyUsageMask actual_usages) { 223 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) 224 return Status::ErrorCreateKeyBadUsages(); 225 return Status::Success(); 226 } 227 228 Status GetRsaKeyGenParameters( 229 const blink::WebCryptoRsaHashedKeyGenParams* params, 230 unsigned int* public_exponent, 231 unsigned int* modulus_length_bits) { 232 *modulus_length_bits = params->modulusLengthBits(); 233 234 // Limit key sizes to those supported by NSS: 235 // * Multiple of 8 bits 236 // * 256 bits to 16K bits 237 if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 || 238 (*modulus_length_bits % 8) != 0) { 239 return Status::ErrorGenerateRsaUnsupportedModulus(); 240 } 241 242 if (!BigIntegerToUint(params->publicExponent().data(), 243 params->publicExponent().size(), 244 public_exponent)) { 245 return Status::ErrorGenerateKeyPublicExponent(); 246 } 247 248 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To 249 // avoid feeding OpenSSL data that will hang use a whitelist. 250 if (*public_exponent != 3 && *public_exponent != 65537) 251 return Status::ErrorGenerateKeyPublicExponent(); 252 253 return Status::Success(); 254 } 255 256 } // namespace webcrypto 257 258 } // namespace content 259