| 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/jwk.h" | |
| 6 | |
| 7 #include <set> | |
| 8 | |
| 9 #include "base/base64.h" | |
| 10 #include "base/json/json_reader.h" | |
| 11 #include "base/json/json_writer.h" | |
| 12 #include "base/stl_util.h" | |
| 13 #include "base/strings/string_piece.h" | |
| 14 #include "base/strings/stringprintf.h" | |
| 15 #include "content/child/webcrypto/crypto_data.h" | |
| 16 #include "content/child/webcrypto/status.h" | |
| 17 #include "content/child/webcrypto/webcrypto_util.h" | |
| 18 | |
| 19 // TODO(eroman): The algorithm-specific logic in this file for AES and RSA | |
| 20 // should be moved into the corresponding AlgorithmImplementation file. It | |
| 21 // exists in this file to avoid duplication between OpenSSL and NSS | |
| 22 // implementations. | |
| 23 | |
| 24 // JSON Web Key Format (JWK) is defined by: | |
| 25 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key | |
| 26 // | |
| 27 // A JWK is a simple JSON dictionary with the following members: | |
| 28 // - "kty" (Key Type) Parameter, REQUIRED | |
| 29 // - <kty-specific parameters, see below>, REQUIRED | |
| 30 // - "use" (Key Use) OPTIONAL | |
| 31 // - "key_ops" (Key Operations) OPTIONAL | |
| 32 // - "alg" (Algorithm) OPTIONAL | |
| 33 // - "ext" (Key Exportability), OPTIONAL | |
| 34 // (all other entries are ignored) | |
| 35 // | |
| 36 // The <kty-specific parameters> are defined by the JWA spec: | |
| 37 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms | |
| 38 | |
| 39 namespace content { | |
| 40 | |
| 41 namespace webcrypto { | |
| 42 | |
| 43 namespace { | |
| 44 | |
| 45 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'. | |
| 46 const blink::WebCryptoKeyUsageMask kJwkEncUsage = | |
| 47 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | | |
| 48 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; | |
| 49 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'. | |
| 50 const blink::WebCryptoKeyUsageMask kJwkSigUsage = | |
| 51 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
| 52 | |
| 53 // Checks that the "ext" member of the JWK is consistent with | |
| 54 // "expected_extractable". | |
| 55 Status VerifyExt(const JwkReader& jwk, bool expected_extractable) { | |
| 56 // JWK "ext" (optional) --> extractable parameter | |
| 57 bool jwk_ext_value = false; | |
| 58 bool has_jwk_ext; | |
| 59 Status status = jwk.GetOptionalBool("ext", &jwk_ext_value, &has_jwk_ext); | |
| 60 if (status.IsError()) | |
| 61 return status; | |
| 62 if (has_jwk_ext && expected_extractable && !jwk_ext_value) | |
| 63 return Status::ErrorJwkExtInconsistent(); | |
| 64 return Status::Success(); | |
| 65 } | |
| 66 | |
| 67 struct JwkToWebCryptoUsageMapping { | |
| 68 const char* const jwk_key_op; | |
| 69 const blink::WebCryptoKeyUsage webcrypto_usage; | |
| 70 }; | |
| 71 | |
| 72 // Keep this ordered the same as WebCrypto's "recognized key usage | |
| 73 // values". While this is not required for spec compliance, | |
| 74 // it makes the ordering of key_ops match that of WebCrypto's Key.usages. | |
| 75 const JwkToWebCryptoUsageMapping kJwkWebCryptoUsageMap[] = { | |
| 76 {"encrypt", blink::WebCryptoKeyUsageEncrypt}, | |
| 77 {"decrypt", blink::WebCryptoKeyUsageDecrypt}, | |
| 78 {"sign", blink::WebCryptoKeyUsageSign}, | |
| 79 {"verify", blink::WebCryptoKeyUsageVerify}, | |
| 80 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey}, | |
| 81 {"deriveBits", blink::WebCryptoKeyUsageDeriveBits}, | |
| 82 {"wrapKey", blink::WebCryptoKeyUsageWrapKey}, | |
| 83 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}}; | |
| 84 | |
| 85 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op, | |
| 86 blink::WebCryptoKeyUsage* usage) { | |
| 87 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
| 88 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) { | |
| 89 *usage = kJwkWebCryptoUsageMap[i].webcrypto_usage; | |
| 90 return true; | |
| 91 } | |
| 92 } | |
| 93 return false; | |
| 94 } | |
| 95 | |
| 96 // Creates a JWK key_ops list from a Web Crypto usage mask. | |
| 97 scoped_ptr<base::ListValue> CreateJwkKeyOpsFromWebCryptoUsages( | |
| 98 blink::WebCryptoKeyUsageMask usages) { | |
| 99 scoped_ptr<base::ListValue> jwk_key_ops(new base::ListValue()); | |
| 100 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) { | |
| 101 if (usages & kJwkWebCryptoUsageMap[i].webcrypto_usage) | |
| 102 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op); | |
| 103 } | |
| 104 return jwk_key_ops.Pass(); | |
| 105 } | |
| 106 | |
| 107 // Composes a Web Crypto usage mask from an array of JWK key_ops values. | |
| 108 Status GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops, | |
| 109 blink::WebCryptoKeyUsageMask* usages) { | |
| 110 // This set keeps track of all unrecognized key_ops values. | |
| 111 std::set<std::string> unrecognized_usages; | |
| 112 | |
| 113 *usages = 0; | |
| 114 for (size_t i = 0; i < key_ops->GetSize(); ++i) { | |
| 115 std::string key_op; | |
| 116 if (!key_ops->GetString(i, &key_op)) { | |
| 117 return Status::ErrorJwkMemberWrongType( | |
| 118 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string"); | |
| 119 } | |
| 120 | |
| 121 blink::WebCryptoKeyUsage usage; | |
| 122 if (JwkKeyOpToWebCryptoUsage(key_op, &usage)) { | |
| 123 // Ensure there are no duplicate usages. | |
| 124 if (*usages & usage) | |
| 125 return Status::ErrorJwkDuplicateKeyOps(); | |
| 126 *usages |= usage; | |
| 127 } | |
| 128 | |
| 129 // Reaching here means the usage was unrecognized. Such usages are skipped | |
| 130 // over, however they are kept track of in a set to ensure there were no | |
| 131 // duplicates. | |
| 132 if (!unrecognized_usages.insert(key_op).second) | |
| 133 return Status::ErrorJwkDuplicateKeyOps(); | |
| 134 } | |
| 135 return Status::Success(); | |
| 136 } | |
| 137 | |
| 138 // Checks that the usages ("use" and "key_ops") of the JWK is consistent with | |
| 139 // "expected_usages". | |
| 140 Status VerifyUsages(const JwkReader& jwk, | |
| 141 blink::WebCryptoKeyUsageMask expected_usages) { | |
| 142 // JWK "key_ops" (optional) --> usages parameter | |
| 143 base::ListValue* jwk_key_ops_value = NULL; | |
| 144 bool has_jwk_key_ops; | |
| 145 Status status = | |
| 146 jwk.GetOptionalList("key_ops", &jwk_key_ops_value, &has_jwk_key_ops); | |
| 147 if (status.IsError()) | |
| 148 return status; | |
| 149 blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0; | |
| 150 if (has_jwk_key_ops) { | |
| 151 status = | |
| 152 GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask); | |
| 153 if (status.IsError()) | |
| 154 return status; | |
| 155 // The input usages must be a subset of jwk_key_ops_mask. | |
| 156 if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usages)) | |
| 157 return Status::ErrorJwkKeyopsInconsistent(); | |
| 158 } | |
| 159 | |
| 160 // JWK "use" (optional) --> usages parameter | |
| 161 std::string jwk_use_value; | |
| 162 bool has_jwk_use; | |
| 163 status = jwk.GetOptionalString("use", &jwk_use_value, &has_jwk_use); | |
| 164 if (status.IsError()) | |
| 165 return status; | |
| 166 blink::WebCryptoKeyUsageMask jwk_use_mask = 0; | |
| 167 if (has_jwk_use) { | |
| 168 if (jwk_use_value == "enc") | |
| 169 jwk_use_mask = kJwkEncUsage; | |
| 170 else if (jwk_use_value == "sig") | |
| 171 jwk_use_mask = kJwkSigUsage; | |
| 172 else | |
| 173 return Status::ErrorJwkUnrecognizedUse(); | |
| 174 // The input usages must be a subset of jwk_use_mask. | |
| 175 if (!ContainsKeyUsages(jwk_use_mask, expected_usages)) | |
| 176 return Status::ErrorJwkUseInconsistent(); | |
| 177 } | |
| 178 | |
| 179 // If both 'key_ops' and 'use' are present, ensure they are consistent. | |
| 180 if (has_jwk_key_ops && has_jwk_use && | |
| 181 !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask)) | |
| 182 return Status::ErrorJwkUseAndKeyopsInconsistent(); | |
| 183 | |
| 184 return Status::Success(); | |
| 185 } | |
| 186 | |
| 187 } // namespace | |
| 188 | |
| 189 JwkReader::JwkReader() { | |
| 190 } | |
| 191 | |
| 192 JwkReader::~JwkReader() { | |
| 193 } | |
| 194 | |
| 195 Status JwkReader::Init(const CryptoData& bytes, | |
| 196 bool expected_extractable, | |
| 197 blink::WebCryptoKeyUsageMask expected_usages, | |
| 198 const std::string& expected_kty, | |
| 199 const std::string& expected_alg) { | |
| 200 // Parse the incoming JWK JSON. | |
| 201 base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()), | |
| 202 bytes.byte_length()); | |
| 203 | |
| 204 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
| 205 base::DictionaryValue* dict_value = NULL; | |
| 206 | |
| 207 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
| 208 return Status::ErrorJwkNotDictionary(); | |
| 209 | |
| 210 // Release |value|, as ownership will be transferred to |dict| via | |
| 211 // |dict_value|, which points to the same object as |value|. | |
| 212 ignore_result(value.release()); | |
| 213 dict_.reset(dict_value); | |
| 214 | |
| 215 // JWK "kty". Exit early if this required JWK parameter is missing. | |
| 216 std::string kty; | |
| 217 Status status = GetString("kty", &kty); | |
| 218 if (status.IsError()) | |
| 219 return status; | |
| 220 | |
| 221 if (kty != expected_kty) | |
| 222 return Status::ErrorJwkUnexpectedKty(expected_kty); | |
| 223 | |
| 224 status = VerifyExt(*this, expected_extractable); | |
| 225 if (status.IsError()) | |
| 226 return status; | |
| 227 | |
| 228 status = VerifyUsages(*this, expected_usages); | |
| 229 if (status.IsError()) | |
| 230 return status; | |
| 231 | |
| 232 // Verify the algorithm if an expectation was provided. | |
| 233 if (!expected_alg.empty()) { | |
| 234 status = VerifyAlg(expected_alg); | |
| 235 if (status.IsError()) | |
| 236 return status; | |
| 237 } | |
| 238 | |
| 239 return Status::Success(); | |
| 240 } | |
| 241 | |
| 242 bool JwkReader::HasMember(const std::string& member_name) const { | |
| 243 return dict_->HasKey(member_name); | |
| 244 } | |
| 245 | |
| 246 Status JwkReader::GetString(const std::string& member_name, | |
| 247 std::string* result) const { | |
| 248 base::Value* value = NULL; | |
| 249 if (!dict_->Get(member_name, &value)) | |
| 250 return Status::ErrorJwkMemberMissing(member_name); | |
| 251 if (!value->GetAsString(result)) | |
| 252 return Status::ErrorJwkMemberWrongType(member_name, "string"); | |
| 253 return Status::Success(); | |
| 254 } | |
| 255 | |
| 256 Status JwkReader::GetOptionalString(const std::string& member_name, | |
| 257 std::string* result, | |
| 258 bool* member_exists) const { | |
| 259 *member_exists = false; | |
| 260 base::Value* value = NULL; | |
| 261 if (!dict_->Get(member_name, &value)) | |
| 262 return Status::Success(); | |
| 263 | |
| 264 if (!value->GetAsString(result)) | |
| 265 return Status::ErrorJwkMemberWrongType(member_name, "string"); | |
| 266 | |
| 267 *member_exists = true; | |
| 268 return Status::Success(); | |
| 269 } | |
| 270 | |
| 271 Status JwkReader::GetOptionalList(const std::string& member_name, | |
| 272 base::ListValue** result, | |
| 273 bool* member_exists) const { | |
| 274 *member_exists = false; | |
| 275 base::Value* value = NULL; | |
| 276 if (!dict_->Get(member_name, &value)) | |
| 277 return Status::Success(); | |
| 278 | |
| 279 if (!value->GetAsList(result)) | |
| 280 return Status::ErrorJwkMemberWrongType(member_name, "list"); | |
| 281 | |
| 282 *member_exists = true; | |
| 283 return Status::Success(); | |
| 284 } | |
| 285 | |
| 286 Status JwkReader::GetBytes(const std::string& member_name, | |
| 287 std::string* result) const { | |
| 288 std::string base64_string; | |
| 289 Status status = GetString(member_name, &base64_string); | |
| 290 if (status.IsError()) | |
| 291 return status; | |
| 292 | |
| 293 if (!Base64DecodeUrlSafe(base64_string, result)) | |
| 294 return Status::ErrorJwkBase64Decode(member_name); | |
| 295 | |
| 296 return Status::Success(); | |
| 297 } | |
| 298 | |
| 299 Status JwkReader::GetBigInteger(const std::string& member_name, | |
| 300 std::string* result) const { | |
| 301 Status status = GetBytes(member_name, result); | |
| 302 if (status.IsError()) | |
| 303 return status; | |
| 304 | |
| 305 if (result->empty()) | |
| 306 return Status::ErrorJwkEmptyBigInteger(member_name); | |
| 307 | |
| 308 // The JWA spec says that "The octet sequence MUST utilize the minimum number | |
| 309 // of octets to represent the value." This means there shouldn't be any | |
| 310 // leading zeros. | |
| 311 if (result->size() > 1 && (*result)[0] == 0) | |
| 312 return Status::ErrorJwkBigIntegerHasLeadingZero(member_name); | |
| 313 | |
| 314 return Status::Success(); | |
| 315 } | |
| 316 | |
| 317 Status JwkReader::GetOptionalBool(const std::string& member_name, | |
| 318 bool* result, | |
| 319 bool* member_exists) const { | |
| 320 *member_exists = false; | |
| 321 base::Value* value = NULL; | |
| 322 if (!dict_->Get(member_name, &value)) | |
| 323 return Status::Success(); | |
| 324 | |
| 325 if (!value->GetAsBoolean(result)) | |
| 326 return Status::ErrorJwkMemberWrongType(member_name, "boolean"); | |
| 327 | |
| 328 *member_exists = true; | |
| 329 return Status::Success(); | |
| 330 } | |
| 331 | |
| 332 Status JwkReader::GetAlg(std::string* alg, bool* has_alg) const { | |
| 333 return GetOptionalString("alg", alg, has_alg); | |
| 334 } | |
| 335 | |
| 336 Status JwkReader::VerifyAlg(const std::string& expected_alg) const { | |
| 337 bool has_jwk_alg; | |
| 338 std::string jwk_alg_value; | |
| 339 Status status = GetAlg(&jwk_alg_value, &has_jwk_alg); | |
| 340 if (status.IsError()) | |
| 341 return status; | |
| 342 | |
| 343 if (has_jwk_alg && jwk_alg_value != expected_alg) | |
| 344 return Status::ErrorJwkAlgorithmInconsistent(); | |
| 345 | |
| 346 return Status::Success(); | |
| 347 } | |
| 348 | |
| 349 JwkWriter::JwkWriter(const std::string& algorithm, | |
| 350 bool extractable, | |
| 351 blink::WebCryptoKeyUsageMask usages, | |
| 352 const std::string& kty) { | |
| 353 if (!algorithm.empty()) | |
| 354 dict_.SetString("alg", algorithm); | |
| 355 dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usages).release()); | |
| 356 dict_.SetBoolean("ext", extractable); | |
| 357 dict_.SetString("kty", kty); | |
| 358 } | |
| 359 | |
| 360 void JwkWriter::SetString(const std::string& member_name, | |
| 361 const std::string& value) { | |
| 362 dict_.SetString(member_name, value); | |
| 363 } | |
| 364 | |
| 365 void JwkWriter::SetBytes(const std::string& member_name, | |
| 366 const CryptoData& value) { | |
| 367 dict_.SetString(member_name, Base64EncodeUrlSafe(base::StringPiece( | |
| 368 reinterpret_cast<const char*>(value.bytes()), | |
| 369 value.byte_length()))); | |
| 370 } | |
| 371 | |
| 372 void JwkWriter::ToJson(std::vector<uint8_t>* utf8_bytes) const { | |
| 373 std::string json; | |
| 374 base::JSONWriter::Write(&dict_, &json); | |
| 375 utf8_bytes->assign(json.begin(), json.end()); | |
| 376 } | |
| 377 | |
| 378 Status ReadSecretKeyNoExpectedAlg(const CryptoData& key_data, | |
| 379 bool expected_extractable, | |
| 380 blink::WebCryptoKeyUsageMask expected_usages, | |
| 381 std::vector<uint8_t>* raw_key_data, | |
| 382 JwkReader* jwk) { | |
| 383 Status status = jwk->Init(key_data, expected_extractable, expected_usages, | |
| 384 "oct", std::string()); | |
| 385 if (status.IsError()) | |
| 386 return status; | |
| 387 | |
| 388 std::string jwk_k_value; | |
| 389 status = jwk->GetBytes("k", &jwk_k_value); | |
| 390 if (status.IsError()) | |
| 391 return status; | |
| 392 raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end()); | |
| 393 | |
| 394 return Status::Success(); | |
| 395 } | |
| 396 | |
| 397 void WriteSecretKeyJwk(const CryptoData& raw_key_data, | |
| 398 const std::string& algorithm, | |
| 399 bool extractable, | |
| 400 blink::WebCryptoKeyUsageMask usages, | |
| 401 std::vector<uint8_t>* jwk_key_data) { | |
| 402 JwkWriter writer(algorithm, extractable, usages, "oct"); | |
| 403 writer.SetBytes("k", raw_key_data); | |
| 404 writer.ToJson(jwk_key_data); | |
| 405 } | |
| 406 | |
| 407 Status ReadSecretKeyJwk(const CryptoData& key_data, | |
| 408 const std::string& expected_alg, | |
| 409 bool expected_extractable, | |
| 410 blink::WebCryptoKeyUsageMask expected_usages, | |
| 411 std::vector<uint8_t>* raw_key_data) { | |
| 412 JwkReader jwk; | |
| 413 Status status = ReadSecretKeyNoExpectedAlg( | |
| 414 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); | |
| 415 if (status.IsError()) | |
| 416 return status; | |
| 417 return jwk.VerifyAlg(expected_alg); | |
| 418 } | |
| 419 | |
| 420 std::string MakeJwkAesAlgorithmName(const std::string& suffix, | |
| 421 unsigned int keylen_bytes) { | |
| 422 if (keylen_bytes == 16) | |
| 423 return std::string("A128") + suffix; | |
| 424 if (keylen_bytes == 24) | |
| 425 return std::string("A192") + suffix; | |
| 426 if (keylen_bytes == 32) | |
| 427 return std::string("A256") + suffix; | |
| 428 return std::string(); | |
| 429 } | |
| 430 | |
| 431 Status ReadAesSecretKeyJwk(const CryptoData& key_data, | |
| 432 const std::string& algorithm_name_suffix, | |
| 433 bool expected_extractable, | |
| 434 blink::WebCryptoKeyUsageMask expected_usages, | |
| 435 std::vector<uint8_t>* raw_key_data) { | |
| 436 JwkReader jwk; | |
| 437 Status status = ReadSecretKeyNoExpectedAlg( | |
| 438 key_data, expected_extractable, expected_usages, raw_key_data, &jwk); | |
| 439 if (status.IsError()) | |
| 440 return status; | |
| 441 | |
| 442 bool has_jwk_alg; | |
| 443 std::string jwk_alg; | |
| 444 status = jwk.GetAlg(&jwk_alg, &has_jwk_alg); | |
| 445 if (status.IsError()) | |
| 446 return status; | |
| 447 | |
| 448 if (has_jwk_alg) { | |
| 449 std::string expected_algorithm_name = | |
| 450 MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size()); | |
| 451 | |
| 452 if (jwk_alg != expected_algorithm_name) { | |
| 453 // Give a different error message if the key length was wrong. | |
| 454 if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) || | |
| 455 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) || | |
| 456 jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) { | |
| 457 return Status::ErrorJwkIncorrectKeyLength(); | |
| 458 } | |
| 459 return Status::ErrorJwkAlgorithmInconsistent(); | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 return Status::Success(); | |
| 464 } | |
| 465 | |
| 466 // Writes an RSA public key to a JWK dictionary | |
| 467 void WriteRsaPublicKeyJwk(const CryptoData& n, | |
| 468 const CryptoData& e, | |
| 469 const std::string& algorithm, | |
| 470 bool extractable, | |
| 471 blink::WebCryptoKeyUsageMask usages, | |
| 472 std::vector<uint8_t>* jwk_key_data) { | |
| 473 JwkWriter writer(algorithm, extractable, usages, "RSA"); | |
| 474 writer.SetBytes("n", n); | |
| 475 writer.SetBytes("e", e); | |
| 476 writer.ToJson(jwk_key_data); | |
| 477 } | |
| 478 | |
| 479 // Writes an RSA private key to a JWK dictionary | |
| 480 void WriteRsaPrivateKeyJwk(const CryptoData& n, | |
| 481 const CryptoData& e, | |
| 482 const CryptoData& d, | |
| 483 const CryptoData& p, | |
| 484 const CryptoData& q, | |
| 485 const CryptoData& dp, | |
| 486 const CryptoData& dq, | |
| 487 const CryptoData& qi, | |
| 488 const std::string& algorithm, | |
| 489 bool extractable, | |
| 490 blink::WebCryptoKeyUsageMask usages, | |
| 491 std::vector<uint8_t>* jwk_key_data) { | |
| 492 JwkWriter writer(algorithm, extractable, usages, "RSA"); | |
| 493 | |
| 494 writer.SetBytes("n", n); | |
| 495 writer.SetBytes("e", e); | |
| 496 writer.SetBytes("d", d); | |
| 497 // Although these are "optional" in the JWA, WebCrypto spec requires them to | |
| 498 // be emitted. | |
| 499 writer.SetBytes("p", p); | |
| 500 writer.SetBytes("q", q); | |
| 501 writer.SetBytes("dp", dp); | |
| 502 writer.SetBytes("dq", dq); | |
| 503 writer.SetBytes("qi", qi); | |
| 504 writer.ToJson(jwk_key_data); | |
| 505 } | |
| 506 | |
| 507 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) { | |
| 508 } | |
| 509 | |
| 510 JwkRsaInfo::~JwkRsaInfo() { | |
| 511 } | |
| 512 | |
| 513 Status ReadRsaKeyJwk(const CryptoData& key_data, | |
| 514 const std::string& expected_alg, | |
| 515 bool expected_extractable, | |
| 516 blink::WebCryptoKeyUsageMask expected_usages, | |
| 517 JwkRsaInfo* result) { | |
| 518 JwkReader jwk; | |
| 519 Status status = jwk.Init(key_data, expected_extractable, expected_usages, | |
| 520 "RSA", expected_alg); | |
| 521 if (status.IsError()) | |
| 522 return status; | |
| 523 | |
| 524 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | |
| 525 // in the JWK, while an RSA private key must have those, plus at least a "d" | |
| 526 // (private exponent) entry. | |
| 527 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | |
| 528 // section 6.3. | |
| 529 status = jwk.GetBigInteger("n", &result->n); | |
| 530 if (status.IsError()) | |
| 531 return status; | |
| 532 status = jwk.GetBigInteger("e", &result->e); | |
| 533 if (status.IsError()) | |
| 534 return status; | |
| 535 | |
| 536 result->is_private_key = jwk.HasMember("d"); | |
| 537 if (!result->is_private_key) | |
| 538 return Status::Success(); | |
| 539 | |
| 540 status = jwk.GetBigInteger("d", &result->d); | |
| 541 if (status.IsError()) | |
| 542 return status; | |
| 543 | |
| 544 // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA | |
| 545 // spec. However they are required by Chromium's WebCrypto implementation. | |
| 546 | |
| 547 status = jwk.GetBigInteger("p", &result->p); | |
| 548 if (status.IsError()) | |
| 549 return status; | |
| 550 | |
| 551 status = jwk.GetBigInteger("q", &result->q); | |
| 552 if (status.IsError()) | |
| 553 return status; | |
| 554 | |
| 555 status = jwk.GetBigInteger("dp", &result->dp); | |
| 556 if (status.IsError()) | |
| 557 return status; | |
| 558 | |
| 559 status = jwk.GetBigInteger("dq", &result->dq); | |
| 560 if (status.IsError()) | |
| 561 return status; | |
| 562 | |
| 563 status = jwk.GetBigInteger("qi", &result->qi); | |
| 564 if (status.IsError()) | |
| 565 return status; | |
| 566 | |
| 567 return Status::Success(); | |
| 568 } | |
| 569 | |
| 570 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) { | |
| 571 switch (hash) { | |
| 572 case blink::WebCryptoAlgorithmIdSha1: | |
| 573 return "HS1"; | |
| 574 case blink::WebCryptoAlgorithmIdSha256: | |
| 575 return "HS256"; | |
| 576 case blink::WebCryptoAlgorithmIdSha384: | |
| 577 return "HS384"; | |
| 578 case blink::WebCryptoAlgorithmIdSha512: | |
| 579 return "HS512"; | |
| 580 default: | |
| 581 return NULL; | |
| 582 } | |
| 583 } | |
| 584 | |
| 585 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
| 586 // The JSON web signature spec specifically says that padding is omitted. | |
| 587 if (input.find_first_of("+/=") != std::string::npos) | |
| 588 return false; | |
| 589 | |
| 590 std::string base64_encoded_text(input); | |
| 591 std::replace(base64_encoded_text.begin(), base64_encoded_text.end(), '-', | |
| 592 '+'); | |
| 593 std::replace(base64_encoded_text.begin(), base64_encoded_text.end(), '_', | |
| 594 '/'); | |
| 595 base64_encoded_text.append((4 - base64_encoded_text.size() % 4) % 4, '='); | |
| 596 return base::Base64Decode(base64_encoded_text, output); | |
| 597 } | |
| 598 | |
| 599 std::string Base64EncodeUrlSafe(const base::StringPiece& input) { | |
| 600 std::string output; | |
| 601 base::Base64Encode(input, &output); | |
| 602 std::replace(output.begin(), output.end(), '+', '-'); | |
| 603 std::replace(output.begin(), output.end(), '/', '_'); | |
| 604 output.erase(std::remove(output.begin(), output.end(), '='), output.end()); | |
| 605 return output; | |
| 606 } | |
| 607 | |
| 608 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) { | |
| 609 const base::StringPiece string_piece( | |
| 610 reinterpret_cast<const char*>(vector_as_array(&input)), input.size()); | |
| 611 return Base64EncodeUrlSafe(string_piece); | |
| 612 } | |
| 613 | |
| 614 Status GetWebCryptoUsagesFromJwkKeyOpsForTest( | |
| 615 const base::ListValue* key_ops, | |
| 616 blink::WebCryptoKeyUsageMask* usages) { | |
| 617 return GetWebCryptoUsagesFromJwkKeyOps(key_ops, usages); | |
| 618 } | |
| 619 | |
| 620 } // namespace webcrypto | |
| 621 | |
| 622 } // namespace content | |
| OLD | NEW |