| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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/renderer/webcrypto/webcrypto_util.h" | |
| 6 | |
| 7 #include "base/base64.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
| 10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 11 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
| 12 | |
| 13 namespace content { | |
| 14 | |
| 15 namespace webcrypto { | |
| 16 | |
| 17 bool Status::IsError() const { return type_ == TYPE_ERROR; } | |
| 18 | |
| 19 bool Status::IsSuccess() const { return type_ == TYPE_SUCCESS; } | |
| 20 | |
| 21 bool Status::HasErrorDetails() const { return !error_details_.empty(); } | |
| 22 | |
| 23 std::string Status::ToString() const { | |
| 24 return IsSuccess() ? "Success" : error_details_; | |
| 25 } | |
| 26 | |
| 27 Status Status::Success() { return Status(TYPE_SUCCESS); } | |
| 28 | |
| 29 Status Status::Error() { return Status(TYPE_ERROR); } | |
| 30 | |
| 31 Status Status::ErrorJwkNotDictionary() { | |
| 32 return Status("JWK input could not be parsed to a JSON dictionary"); | |
| 33 } | |
| 34 | |
| 35 Status Status::ErrorJwkPropertyMissing(const std::string& property) { | |
| 36 return Status("The required JWK property \"" + property + "\" was missing"); | |
| 37 } | |
| 38 | |
| 39 Status Status::ErrorJwkPropertyWrongType(const std::string& property, | |
| 40 const std::string& expected_type) { | |
| 41 return Status("The JWK property \"" + property + "\" must be a " + | |
| 42 expected_type); | |
| 43 } | |
| 44 | |
| 45 Status Status::ErrorJwkBase64Decode(const std::string& property) { | |
| 46 return Status("The JWK property \"" + property + | |
| 47 "\" could not be base64 decoded"); | |
| 48 } | |
| 49 | |
| 50 Status Status::ErrorJwkExtractableInconsistent() { | |
| 51 return Status( | |
| 52 "The \"extractable\" property of the JWK dictionary is " | |
| 53 "inconsistent what that specified by the Web Crypto call"); | |
| 54 } | |
| 55 | |
| 56 Status Status::ErrorJwkUnrecognizedAlgorithm() { | |
| 57 return Status("The JWK \"alg\" property was not recognized"); | |
| 58 } | |
| 59 | |
| 60 Status Status::ErrorJwkAlgorithmInconsistent() { | |
| 61 return Status( | |
| 62 "The JWK \"alg\" property was inconsistent with that specified " | |
| 63 "by the Web Crypto call"); | |
| 64 } | |
| 65 | |
| 66 Status Status::ErrorJwkAlgorithmMissing() { | |
| 67 return Status( | |
| 68 "The JWK optional \"alg\" property is missing or not a string, " | |
| 69 "and one wasn't specified by the Web Crypto call"); | |
| 70 } | |
| 71 | |
| 72 Status Status::ErrorJwkUnrecognizedUsage() { | |
| 73 return Status("The JWK \"use\" property could not be parsed"); | |
| 74 } | |
| 75 | |
| 76 Status Status::ErrorJwkUsageInconsistent() { | |
| 77 return Status( | |
| 78 "The JWK \"use\" property was inconsistent with that specified " | |
| 79 "by the Web Crypto call. The JWK usage must be a superset of " | |
| 80 "those requested"); | |
| 81 } | |
| 82 | |
| 83 Status Status::ErrorJwkRsaPrivateKeyUnsupported() { | |
| 84 return Status( | |
| 85 "JWK RSA key contained \"d\" property: Private key import is " | |
| 86 "not yet supported"); | |
| 87 } | |
| 88 | |
| 89 Status Status::ErrorJwkUnrecognizedKty() { | |
| 90 return Status("The JWK \"kty\" property was unrecognized"); | |
| 91 } | |
| 92 | |
| 93 Status Status::ErrorJwkIncorrectKeyLength() { | |
| 94 return Status( | |
| 95 "The JWK \"k\" property did not include the right length " | |
| 96 "of key data for the given algorithm."); | |
| 97 } | |
| 98 | |
| 99 Status Status::ErrorImportEmptyKeyData() { | |
| 100 return Status("No key data was provided"); | |
| 101 } | |
| 102 | |
| 103 Status Status::ErrorUnexpectedKeyType() { | |
| 104 return Status("The key is not of the expected type"); | |
| 105 } | |
| 106 | |
| 107 Status Status::ErrorIncorrectSizeAesCbcIv() { | |
| 108 return Status("The \"iv\" has an unexpected length -- must be 16 bytes"); | |
| 109 } | |
| 110 | |
| 111 Status Status::ErrorDataTooLarge() { | |
| 112 return Status("The provided data is too large"); | |
| 113 } | |
| 114 | |
| 115 Status Status::ErrorUnsupported() { | |
| 116 return Status("The requested operation is unsupported"); | |
| 117 } | |
| 118 | |
| 119 Status Status::ErrorUnexpected() { | |
| 120 return Status("Something unexpected happened..."); | |
| 121 } | |
| 122 | |
| 123 Status Status::ErrorInvalidAesGcmTagLength() { | |
| 124 return Status( | |
| 125 "The tag length is invalid: Must be 32, 64, 96, 104, 112, 120, or 128 " | |
| 126 "bits"); | |
| 127 } | |
| 128 | |
| 129 Status Status::ErrorGenerateKeyPublicExponent() { | |
| 130 return Status("The \"publicExponent\" is either empty, zero, or too large"); | |
| 131 } | |
| 132 | |
| 133 Status Status::ErrorMissingAlgorithmImportRawKey() { | |
| 134 return Status( | |
| 135 "The key's algorithm must be specified when importing " | |
| 136 "raw-formatted key."); | |
| 137 } | |
| 138 | |
| 139 Status Status::ErrorImportRsaEmptyModulus() { | |
| 140 return Status("The modulus is empty"); | |
| 141 } | |
| 142 | |
| 143 Status Status::ErrorGenerateRsaZeroModulus() { | |
| 144 return Status("The modulus bit length cannot be zero"); | |
| 145 } | |
| 146 | |
| 147 Status Status::ErrorImportRsaEmptyExponent() { | |
| 148 return Status("No bytes for the exponent were provided"); | |
| 149 } | |
| 150 | |
| 151 Status Status::ErrorKeyNotExtractable() { | |
| 152 return Status("They key is not extractable"); | |
| 153 } | |
| 154 | |
| 155 Status Status::ErrorGenerateKeyLength() { | |
| 156 return Status( | |
| 157 "Invalid key length: it is either zero or not a multiple of 8 " | |
| 158 "bits"); | |
| 159 } | |
| 160 | |
| 161 Status::Status(const std::string& error_details_utf8) | |
| 162 : type_(TYPE_ERROR), error_details_(error_details_utf8) {} | |
| 163 | |
| 164 Status::Status(Type type) : type_(type) {} | |
| 165 | |
| 166 const uint8* Uint8VectorStart(const std::vector<uint8>& data) { | |
| 167 if (data.empty()) | |
| 168 return NULL; | |
| 169 return &data[0]; | |
| 170 } | |
| 171 | |
| 172 void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size) { | |
| 173 DCHECK_LE(new_size, buffer->byteLength()); | |
| 174 | |
| 175 if (new_size == buffer->byteLength()) | |
| 176 return; | |
| 177 | |
| 178 blink::WebArrayBuffer new_buffer = blink::WebArrayBuffer::create(new_size, 1); | |
| 179 DCHECK(!new_buffer.isNull()); | |
| 180 memcpy(new_buffer.data(), buffer->data(), new_size); | |
| 181 *buffer = new_buffer; | |
| 182 } | |
| 183 | |
| 184 blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, | |
| 185 unsigned int data_size) { | |
| 186 blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(data_size, 1); | |
| 187 DCHECK(!buffer.isNull()); | |
| 188 if (data_size) // data_size == 0 might mean the data pointer is invalid | |
| 189 memcpy(buffer.data(), data, data_size); | |
| 190 return buffer; | |
| 191 } | |
| 192 | |
| 193 // This function decodes unpadded 'base64url' encoded data, as described in | |
| 194 // RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. To do this, first | |
| 195 // change the incoming data to 'base64' encoding by applying the appropriate | |
| 196 // transformation including adding padding if required, and then call a base64 | |
| 197 // decoder. | |
| 198 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
| 199 std::string base64EncodedText(input); | |
| 200 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); | |
| 201 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); | |
| 202 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); | |
| 203 return base::Base64Decode(base64EncodedText, output); | |
| 204 } | |
| 205 | |
| 206 bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) { | |
| 207 return alg_id == blink::WebCryptoAlgorithmIdSha1 || | |
| 208 alg_id == blink::WebCryptoAlgorithmIdSha224 || | |
| 209 alg_id == blink::WebCryptoAlgorithmIdSha256 || | |
| 210 alg_id == blink::WebCryptoAlgorithmIdSha384 || | |
| 211 alg_id == blink::WebCryptoAlgorithmIdSha512; | |
| 212 } | |
| 213 | |
| 214 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( | |
| 215 const blink::WebCryptoAlgorithm& algorithm) { | |
| 216 DCHECK(!algorithm.isNull()); | |
| 217 switch (algorithm.paramsType()) { | |
| 218 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams: | |
| 219 return algorithm.hmacImportParams()->hash(); | |
| 220 case blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams: | |
| 221 return algorithm.hmacKeyGenParams()->hash(); | |
| 222 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams: | |
| 223 return algorithm.rsaHashedImportParams()->hash(); | |
| 224 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: | |
| 225 return algorithm.rsaHashedKeyGenParams()->hash(); | |
| 226 default: | |
| 227 return blink::WebCryptoAlgorithm::createNull(); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | |
| 232 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | |
| 233 } | |
| 234 | |
| 235 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( | |
| 236 blink::WebCryptoAlgorithmId hash_id) { | |
| 237 DCHECK(IsHashAlgorithm(hash_id)); | |
| 238 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 239 blink::WebCryptoAlgorithmIdHmac, | |
| 240 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id))); | |
| 241 } | |
| 242 | |
| 243 blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( | |
| 244 blink::WebCryptoAlgorithmId hash_id) { | |
| 245 DCHECK(IsHashAlgorithm(hash_id)); | |
| 246 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 247 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
| 248 new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); | |
| 249 } | |
| 250 | |
| 251 blink::WebCryptoAlgorithm CreateRsaOaepImportAlgorithm( | |
| 252 blink::WebCryptoAlgorithmId hash_id) { | |
| 253 DCHECK(IsHashAlgorithm(hash_id)); | |
| 254 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
| 255 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 256 new blink::WebCryptoRsaHashedImportParams( | |
| 257 CreateAlgorithm(hash_id))); | |
| 258 } | |
| 259 | |
| 260 | |
| 261 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { | |
| 262 switch (hash_id) { | |
| 263 case blink::WebCryptoAlgorithmIdSha1: | |
| 264 case blink::WebCryptoAlgorithmIdSha224: | |
| 265 case blink::WebCryptoAlgorithmIdSha256: | |
| 266 return 64; | |
| 267 case blink::WebCryptoAlgorithmIdSha384: | |
| 268 case blink::WebCryptoAlgorithmIdSha512: | |
| 269 return 128; | |
| 270 default: | |
| 271 NOTREACHED(); | |
| 272 return 0; | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | |
| 277 unsigned keylen_bytes, | |
| 278 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
| 279 switch (algorithm.id()) { | |
| 280 case blink::WebCryptoAlgorithmIdHmac: { | |
| 281 blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm); | |
| 282 if (hash.isNull()) | |
| 283 return false; | |
| 284 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
| 285 algorithm.id(), | |
| 286 new blink::WebCryptoHmacKeyAlgorithmParams(hash)); | |
| 287 return true; | |
| 288 } | |
| 289 case blink::WebCryptoAlgorithmIdAesKw: | |
| 290 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 291 case blink::WebCryptoAlgorithmIdAesCtr: | |
| 292 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 293 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
| 294 algorithm.id(), | |
| 295 new blink::WebCryptoAesKeyAlgorithmParams(keylen_bytes * 8)); | |
| 296 return true; | |
| 297 default: | |
| 298 return false; | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 } // namespace webcrypto | |
| 303 | |
| 304 } // namespace content | |
| OLD | NEW |