| 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 "content/child/webcrypto/webcrypto_util.h" | 5 #include "content/child/webcrypto/webcrypto_util.h" |
| 6 | 6 |
| 7 #include "base/base64.h" | 7 #include "base/base64.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/strings/stringprintf.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 content { | 13 namespace content { |
| 15 | 14 |
| 16 namespace webcrypto { | 15 namespace webcrypto { |
| 17 | 16 |
| 18 bool Status::IsError() const { return type_ == TYPE_ERROR; } | 17 bool Status::IsError() const { return type_ == TYPE_ERROR; } |
| 19 | 18 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 41 const std::string& expected_type) { | 40 const std::string& expected_type) { |
| 42 return Status("The JWK property \"" + property + "\" must be a " + | 41 return Status("The JWK property \"" + property + "\" must be a " + |
| 43 expected_type); | 42 expected_type); |
| 44 } | 43 } |
| 45 | 44 |
| 46 Status Status::ErrorJwkBase64Decode(const std::string& property) { | 45 Status Status::ErrorJwkBase64Decode(const std::string& property) { |
| 47 return Status("The JWK property \"" + property + | 46 return Status("The JWK property \"" + property + |
| 48 "\" could not be base64 decoded"); | 47 "\" could not be base64 decoded"); |
| 49 } | 48 } |
| 50 | 49 |
| 51 Status Status::ErrorJwkExtInconsistent() { | 50 Status Status::ErrorJwkExtractableInconsistent() { |
| 52 return Status( | 51 return Status( |
| 53 "The \"ext\" property of the JWK dictionary is inconsistent what that " | 52 "The \"extractable\" property of the JWK dictionary is " |
| 54 "specified by the Web Crypto call"); | 53 "inconsistent what that specified by the Web Crypto call"); |
| 55 } | 54 } |
| 56 | 55 |
| 57 Status Status::ErrorJwkUnrecognizedAlgorithm() { | 56 Status Status::ErrorJwkUnrecognizedAlgorithm() { |
| 58 return Status("The JWK \"alg\" property was not recognized"); | 57 return Status("The JWK \"alg\" property was not recognized"); |
| 59 } | 58 } |
| 60 | 59 |
| 61 Status Status::ErrorJwkAlgorithmInconsistent() { | 60 Status Status::ErrorJwkAlgorithmInconsistent() { |
| 62 return Status( | 61 return Status( |
| 63 "The JWK \"alg\" property was inconsistent with that specified " | 62 "The JWK \"alg\" property was inconsistent with that specified " |
| 64 "by the Web Crypto call"); | 63 "by the Web Crypto call"); |
| 65 } | 64 } |
| 66 | 65 |
| 67 Status Status::ErrorJwkAlgorithmMissing() { | 66 Status Status::ErrorJwkAlgorithmMissing() { |
| 68 return Status( | 67 return Status( |
| 69 "The JWK optional \"alg\" property is missing or not a string, " | 68 "The JWK optional \"alg\" property is missing or not a string, " |
| 70 "and one wasn't specified by the Web Crypto call"); | 69 "and one wasn't specified by the Web Crypto call"); |
| 71 } | 70 } |
| 72 | 71 |
| 73 Status Status::ErrorJwkUnrecognizedUse() { | 72 Status Status::ErrorJwkUnrecognizedUsage() { |
| 74 return Status("The JWK \"use\" property could not be parsed"); | 73 return Status("The JWK \"use\" property could not be parsed"); |
| 75 } | 74 } |
| 76 | 75 |
| 77 Status Status::ErrorJwkUnrecognizedKeyop() { | 76 Status Status::ErrorJwkUsageInconsistent() { |
| 78 return Status("The JWK \"key_ops\" property could not be parsed"); | |
| 79 } | |
| 80 | |
| 81 Status Status::ErrorJwkUseInconsistent() { | |
| 82 return Status( | 77 return Status( |
| 83 "The JWK \"use\" property was inconsistent with that specified " | 78 "The JWK \"use\" property was inconsistent with that specified " |
| 84 "by the Web Crypto call. The JWK usage must be a superset of " | 79 "by the Web Crypto call. The JWK usage must be a superset of " |
| 85 "those requested"); | 80 "those requested"); |
| 86 } | 81 } |
| 87 | 82 |
| 88 Status Status::ErrorJwkKeyopsInconsistent() { | |
| 89 return Status( | |
| 90 "The JWK \"key_ops\" property was inconsistent with that " | |
| 91 "specified by the Web Crypto call. The JWK usage must be a " | |
| 92 "superset of those requested"); | |
| 93 } | |
| 94 | |
| 95 Status Status::ErrorJwkUseAndKeyopsInconsistent() { | |
| 96 return Status( | |
| 97 "The JWK \"use\" and \"key_ops\" properties were both found " | |
| 98 "but are inconsistent with each other."); | |
| 99 } | |
| 100 | |
| 101 Status Status::ErrorJwkRsaPrivateKeyUnsupported() { | 83 Status Status::ErrorJwkRsaPrivateKeyUnsupported() { |
| 102 return Status( | 84 return Status( |
| 103 "JWK RSA key contained \"d\" property: Private key import is " | 85 "JWK RSA key contained \"d\" property: Private key import is " |
| 104 "not yet supported"); | 86 "not yet supported"); |
| 105 } | 87 } |
| 106 | 88 |
| 107 Status Status::ErrorJwkUnrecognizedKty() { | 89 Status Status::ErrorJwkUnrecognizedKty() { |
| 108 return Status("The JWK \"kty\" property was unrecognized"); | 90 return Status("The JWK \"kty\" property was unrecognized"); |
| 109 } | 91 } |
| 110 | 92 |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 // transformation including adding padding if required, and then call a base64 | 212 // transformation including adding padding if required, and then call a base64 |
| 231 // decoder. | 213 // decoder. |
| 232 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | 214 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { |
| 233 std::string base64EncodedText(input); | 215 std::string base64EncodedText(input); |
| 234 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); | 216 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); |
| 235 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); | 217 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); |
| 236 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); | 218 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); |
| 237 return base::Base64Decode(base64EncodedText, output); | 219 return base::Base64Decode(base64EncodedText, output); |
| 238 } | 220 } |
| 239 | 221 |
| 240 // Returns an unpadded 'base64url' encoding of the input data, using the | |
| 241 // inverse of the process above. | |
| 242 std::string Base64EncodeUrlSafe(const base::StringPiece& input) { | |
| 243 std::string output; | |
| 244 base::Base64Encode(input, &output); | |
| 245 std::replace(output.begin(), output.end(), '+', '-'); | |
| 246 std::replace(output.begin(), output.end(), '/', '_'); | |
| 247 output.erase(std::remove(output.begin(), output.end(), '='), output.end()); | |
| 248 return output; | |
| 249 } | |
| 250 | |
| 251 struct JwkToWebCryptoUsage { | |
| 252 const char* const jwk_key_op; | |
| 253 const blink::WebCryptoKeyUsage webcrypto_usage; | |
| 254 }; | |
| 255 | |
| 256 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = { | |
| 257 {"encrypt", blink::WebCryptoKeyUsageEncrypt}, | |
| 258 {"decrypt", blink::WebCryptoKeyUsageDecrypt}, | |
| 259 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey}, | |
| 260 // TODO(padolph): Add 'deriveBits' once supported by Blink. | |
| 261 {"sign", blink::WebCryptoKeyUsageSign}, | |
| 262 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}, | |
| 263 {"verify", blink::WebCryptoKeyUsageVerify}, | |
| 264 {"wrapKey", blink::WebCryptoKeyUsageWrapKey}}; | |
| 265 | |
| 266 // Modifies the input usage_mask by according to the key_op value. | |
| 267 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op, | |
| 268 blink::WebCryptoKeyUsageMask* usage_mask) { | |
| 269 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
| 270 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) { | |
| 271 *usage_mask |= kJwkWebCryptoUsageMap[i].webcrypto_usage; | |
| 272 return true; | |
| 273 } | |
| 274 } | |
| 275 return false; | |
| 276 } | |
| 277 | |
| 278 // Composes a Web Crypto usage mask from an array of JWK key_ops values. | |
| 279 Status GetWebCryptoUsagesFromJwkKeyOps( | |
| 280 const base::ListValue* jwk_key_ops_value, | |
| 281 blink::WebCryptoKeyUsageMask* usage_mask) { | |
| 282 *usage_mask = 0; | |
| 283 for (size_t i = 0; i < jwk_key_ops_value->GetSize(); ++i) { | |
| 284 std::string key_op; | |
| 285 if (!jwk_key_ops_value->GetString(i, &key_op)) { | |
| 286 return Status::ErrorJwkPropertyWrongType( | |
| 287 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string"); | |
| 288 } | |
| 289 if (!JwkKeyOpToWebCryptoUsage(key_op, usage_mask)) | |
| 290 return Status::ErrorJwkUnrecognizedKeyop(); | |
| 291 } | |
| 292 return Status::Success(); | |
| 293 } | |
| 294 | |
| 295 // Composes a JWK key_ops List from a Web Crypto usage mask. | |
| 296 // Note: Caller must assume ownership of returned instance. | |
| 297 base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages( | |
| 298 blink::WebCryptoKeyUsageMask usage_mask) { | |
| 299 base::ListValue* jwk_key_ops = new base::ListValue(); | |
| 300 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
| 301 if (usage_mask & kJwkWebCryptoUsageMap[i].webcrypto_usage) | |
| 302 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op); | |
| 303 } | |
| 304 return jwk_key_ops; | |
| 305 } | |
| 306 | |
| 307 bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) { | 222 bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) { |
| 308 return alg_id == blink::WebCryptoAlgorithmIdSha1 || | 223 return alg_id == blink::WebCryptoAlgorithmIdSha1 || |
| 309 alg_id == blink::WebCryptoAlgorithmIdSha256 || | 224 alg_id == blink::WebCryptoAlgorithmIdSha256 || |
| 310 alg_id == blink::WebCryptoAlgorithmIdSha384 || | 225 alg_id == blink::WebCryptoAlgorithmIdSha384 || |
| 311 alg_id == blink::WebCryptoAlgorithmIdSha512; | 226 alg_id == blink::WebCryptoAlgorithmIdSha512; |
| 312 } | 227 } |
| 313 | 228 |
| 314 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( | 229 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( |
| 315 const blink::WebCryptoAlgorithm& algorithm) { | 230 const blink::WebCryptoAlgorithm& algorithm) { |
| 316 DCHECK(!algorithm.isNull()); | 231 DCHECK(!algorithm.isNull()); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 new blink::WebCryptoAesKeyAlgorithmParams(keylen_bytes * 8)); | 306 new blink::WebCryptoAesKeyAlgorithmParams(keylen_bytes * 8)); |
| 392 return true; | 307 return true; |
| 393 default: | 308 default: |
| 394 return false; | 309 return false; |
| 395 } | 310 } |
| 396 } | 311 } |
| 397 | 312 |
| 398 } // namespace webcrypto | 313 } // namespace webcrypto |
| 399 | 314 |
| 400 } // namespace content | 315 } // namespace content |
| OLD | NEW |