1/* 2 * Copyright (C) 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "JSCryptoKeySerializationJWK.h" 28 29#if ENABLE(SUBTLE_CRYPTO) 30 31#include "CryptoAlgorithm.h" 32#include "CryptoAlgorithmHmacParams.h" 33#include "CryptoAlgorithmRegistry.h" 34#include "CryptoAlgorithmRsaKeyParamsWithHash.h" 35#include "CryptoKey.h" 36#include "CryptoKeyAES.h" 37#include "CryptoKeyDataOctetSequence.h" 38#include "CryptoKeyDataRSAComponents.h" 39#include "CryptoKeyHMAC.h" 40#include "CryptoKeyRSA.h" 41#include "ExceptionCode.h" 42#include "JSDOMBinding.h" 43#include <heap/StrongInlines.h> 44#include <runtime/JSCInlines.h> 45#include <runtime/JSONObject.h> 46#include <runtime/ObjectConstructor.h> 47#include <wtf/text/Base64.h> 48 49using namespace JSC; 50 51namespace WebCore { 52 53static bool getJSArrayFromJSON(ExecState* exec, JSObject* json, const char* key, JSArray*& result) 54{ 55 Identifier identifier(exec, key); 56 PropertySlot slot(json); 57 58 if (!json->getPropertySlot(exec, identifier, slot)) 59 return false; 60 61 JSValue value = slot.getValue(exec, identifier); 62 ASSERT(!exec->hadException()); 63 if (!isJSArray(value)) { 64 throwTypeError(exec, String::format("Expected an array for \"%s\" JSON key", key)); 65 return false; 66 } 67 68 result = asArray(value); 69 70 return true; 71} 72 73static bool getStringFromJSON(ExecState* exec, JSObject* json, const char* key, String& result) 74{ 75 Identifier identifier(exec, key); 76 PropertySlot slot(json); 77 78 if (!json->getPropertySlot(exec, identifier, slot)) 79 return false; 80 81 JSValue jsValue = slot.getValue(exec, identifier); 82 ASSERT(!exec->hadException()); 83 if (!jsValue.getString(exec, result)) { 84 // Can get an out of memory exception. 85 if (exec->hadException()) 86 return false; 87 throwTypeError(exec, String::format("Expected a string value for \"%s\" JSON key", key)); 88 return false; 89 } 90 91 return true; 92} 93 94static bool getBooleanFromJSON(ExecState* exec, JSObject* json, const char* key, bool& result) 95{ 96 Identifier identifier(exec, key); 97 PropertySlot slot(json); 98 99 if (!json->getPropertySlot(exec, identifier, slot)) 100 return false; 101 102 JSValue jsValue = slot.getValue(exec, identifier); 103 ASSERT(!exec->hadException()); 104 if (!jsValue.isBoolean()) { 105 throwTypeError(exec, String::format("Expected a boolean value for \"%s\" JSON key", key)); 106 return false; 107 } 108 109 result = jsValue.asBoolean(); 110 return true; 111} 112 113static bool getBigIntegerVectorFromJSON(ExecState* exec, JSObject* json, const char* key, Vector<uint8_t>& result) 114{ 115 String base64urlEncodedNumber; 116 if (!getStringFromJSON(exec, json, key, base64urlEncodedNumber)) 117 return false; 118 119 if (!base64URLDecode(base64urlEncodedNumber, result)) { 120 throwTypeError(exec, "Cannot decode base64url key data in JWK"); 121 return false; 122 } 123 124 if (result[0] == 0) { 125 throwTypeError(exec, "JWK BigInteger must utilize the minimum number of octets to represent the value"); 126 return false; 127 } 128 129 return true; 130} 131 132JSCryptoKeySerializationJWK::JSCryptoKeySerializationJWK(ExecState* exec, const String& jsonString) 133 : m_exec(exec) 134{ 135 JSValue jsonValue = JSONParse(exec, jsonString); 136 if (exec->hadException()) 137 return; 138 139 if (!jsonValue || !jsonValue.isObject()) { 140 throwTypeError(exec, "Invalid JWK serialization"); 141 return; 142 } 143 144 m_json.set(m_exec->vm(), asObject(jsonValue)); 145} 146 147JSCryptoKeySerializationJWK::~JSCryptoKeySerializationJWK() 148{ 149} 150 151static std::unique_ptr<CryptoAlgorithmParameters> createHMACParameters(CryptoAlgorithmIdentifier hashFunction) 152{ 153 std::unique_ptr<CryptoAlgorithmHmacParams> hmacParameters = std::make_unique<CryptoAlgorithmHmacParams>(); 154 hmacParameters->hash = hashFunction; 155 return WTF::move(hmacParameters); 156} 157 158static std::unique_ptr<CryptoAlgorithmParameters> createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier hashFunction) 159{ 160 std::unique_ptr<CryptoAlgorithmRsaKeyParamsWithHash> rsaKeyParameters = std::make_unique<CryptoAlgorithmRsaKeyParamsWithHash>(); 161 rsaKeyParameters->hasHash = true; 162 rsaKeyParameters->hash = hashFunction; 163 return WTF::move(rsaKeyParameters); 164} 165 166bool JSCryptoKeySerializationJWK::reconcileAlgorithm(std::unique_ptr<CryptoAlgorithm>& suggestedAlgorithm, std::unique_ptr<CryptoAlgorithmParameters>& suggestedParameters) const 167{ 168 if (!getStringFromJSON(m_exec, m_json.get(), "alg", m_jwkAlgorithmName)) { 169 // Algorithm is optional in JWK. 170 return true; 171 } 172 173 std::unique_ptr<CryptoAlgorithm> algorithm; 174 std::unique_ptr<CryptoAlgorithmParameters> parameters; 175 if (m_jwkAlgorithmName == "HS256") { 176 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); 177 parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_256); 178 } else if (m_jwkAlgorithmName == "HS384") { 179 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); 180 parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_384); 181 } else if (m_jwkAlgorithmName == "HS512") { 182 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); 183 parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_512); 184 } else if (m_jwkAlgorithmName == "RS256") { 185 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); 186 parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_256); 187 } else if (m_jwkAlgorithmName == "RS384") { 188 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); 189 parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_384); 190 } else if (m_jwkAlgorithmName == "RS512") { 191 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); 192 parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_512); 193 } else if (m_jwkAlgorithmName == "RSA1_5") { 194 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5); 195 parameters = std::make_unique<CryptoAlgorithmParameters>(); 196 } else if (m_jwkAlgorithmName == "RSA-OAEP") { 197 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSA_OAEP); 198 parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_1); 199 } else if (m_jwkAlgorithmName == "A128CBC") { 200 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); 201 parameters = std::make_unique<CryptoAlgorithmParameters>(); 202 } else if (m_jwkAlgorithmName == "A192CBC") { 203 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); 204 parameters = std::make_unique<CryptoAlgorithmParameters>(); 205 } else if (m_jwkAlgorithmName == "A256CBC") { 206 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); 207 parameters = std::make_unique<CryptoAlgorithmParameters>(); 208 } else if (m_jwkAlgorithmName == "A128KW") { 209 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_KW); 210 parameters = std::make_unique<CryptoAlgorithmParameters>(); 211 } else if (m_jwkAlgorithmName == "A192KW") { 212 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_KW); 213 parameters = std::make_unique<CryptoAlgorithmParameters>(); 214 } else if (m_jwkAlgorithmName == "A256KW") { 215 algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_KW); 216 parameters = std::make_unique<CryptoAlgorithmParameters>(); 217 } else { 218 throwTypeError(m_exec, "Unsupported JWK algorithm " + m_jwkAlgorithmName); 219 return false; 220 } 221 222 if (!suggestedAlgorithm) { 223 suggestedAlgorithm = WTF::move(algorithm); 224 suggestedParameters = WTF::move(parameters); 225 return true; 226 } 227 228 if (!algorithm) 229 return true; 230 231 if (algorithm->identifier() != suggestedAlgorithm->identifier()) 232 return false; 233 234 if (algorithm->identifier() == CryptoAlgorithmIdentifier::HMAC) 235 return toCryptoAlgorithmHmacParams(*parameters).hash == toCryptoAlgorithmHmacParams(*suggestedParameters).hash; 236 if (algorithm->identifier() == CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5 237 || algorithm->identifier() == CryptoAlgorithmIdentifier::RSA_OAEP) { 238 CryptoAlgorithmRsaKeyParamsWithHash& rsaKeyParameters = toCryptoAlgorithmRsaKeyParamsWithHash(*parameters); 239 CryptoAlgorithmRsaKeyParamsWithHash& suggestedRSAKeyParameters = toCryptoAlgorithmRsaKeyParamsWithHash(*suggestedParameters); 240 ASSERT(rsaKeyParameters.hasHash); 241 if (suggestedRSAKeyParameters.hasHash) 242 return suggestedRSAKeyParameters.hash == rsaKeyParameters.hash; 243 suggestedRSAKeyParameters.hasHash = true; 244 suggestedRSAKeyParameters.hash = rsaKeyParameters.hash; 245 } 246 247 // Other algorithms don't have parameters. 248 return true; 249} 250 251static bool tryJWKKeyOpsValue(ExecState* exec, CryptoKeyUsage& usages, const String& operation, const String& tryOperation, CryptoKeyUsage tryUsage) 252{ 253 if (operation == tryOperation) { 254 if (usages & tryUsage) { 255 throwTypeError(exec, "JWK key_ops contains a duplicate operation"); 256 return false; 257 } 258 usages |= tryUsage; 259 } 260 return true; 261} 262 263void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsage& suggestedUsages) const 264{ 265 CryptoKeyUsage jwkUsages = 0; 266 267 JSArray* keyOps; 268 if (getJSArrayFromJSON(m_exec, m_json.get(), "key_ops", keyOps)) { 269 for (size_t i = 0; i < keyOps->length(); ++i) { 270 JSValue jsValue = keyOps->getIndex(m_exec, i); 271 String operation; 272 if (!jsValue.getString(m_exec, operation)) { 273 if (!m_exec->hadException()) 274 throwTypeError(m_exec, "JWK key_ops attribute could not be processed"); 275 return; 276 } 277 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("sign"), CryptoKeyUsageSign)) 278 return; 279 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("verify"), CryptoKeyUsageVerify)) 280 return; 281 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("encrypt"), CryptoKeyUsageEncrypt)) 282 return; 283 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("decrypt"), CryptoKeyUsageDecrypt)) 284 return; 285 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("wrapKey"), CryptoKeyUsageWrapKey)) 286 return; 287 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("unwrapKey"), CryptoKeyUsageUnwrapKey)) 288 return; 289 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveKey"), CryptoKeyUsageDeriveKey)) 290 return; 291 if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveBits"), CryptoKeyUsageDeriveBits)) 292 return; 293 } 294 } else { 295 if (m_exec->hadException()) 296 return; 297 298 String jwkUseString; 299 if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) { 300 // We have neither key_ops nor use. 301 return; 302 } 303 304 if (jwkUseString == "enc") 305 jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); 306 else if (jwkUseString == "sig") 307 jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify); 308 else { 309 throwTypeError(m_exec, "Unsupported JWK key use value \"" + jwkUseString + "\""); 310 return; 311 } 312 } 313 314 suggestedUsages = suggestedUsages & jwkUsages; 315} 316 317void JSCryptoKeySerializationJWK::reconcileExtractable(bool& suggestedExtractable) const 318{ 319 bool jwkExtractable; 320 if (!getBooleanFromJSON(m_exec, m_json.get(), "ext", jwkExtractable)) 321 return; 322 323 suggestedExtractable = suggestedExtractable && jwkExtractable; 324} 325 326bool JSCryptoKeySerializationJWK::keySizeIsValid(size_t sizeInBits) const 327{ 328 if (m_jwkAlgorithmName == "HS256") 329 return sizeInBits >= 256; 330 if (m_jwkAlgorithmName == "HS384") 331 return sizeInBits >= 384; 332 if (m_jwkAlgorithmName == "HS512") 333 return sizeInBits >= 512; 334 if (m_jwkAlgorithmName == "A128CBC") 335 return sizeInBits == 128; 336 if (m_jwkAlgorithmName == "A192CBC") 337 return sizeInBits == 192; 338 if (m_jwkAlgorithmName == "A256CBC") 339 return sizeInBits == 256; 340 if (m_jwkAlgorithmName == "A128KW") 341 return sizeInBits == 128; 342 if (m_jwkAlgorithmName == "A192KW") 343 return sizeInBits == 192; 344 if (m_jwkAlgorithmName == "A256KW") 345 return sizeInBits == 256; 346 if (m_jwkAlgorithmName == "RS256") 347 return sizeInBits >= 2048; 348 if (m_jwkAlgorithmName == "RS384") 349 return sizeInBits >= 2048; 350 if (m_jwkAlgorithmName == "RS512") 351 return sizeInBits >= 2048; 352 if (m_jwkAlgorithmName == "RSA1_5") 353 return sizeInBits >= 2048; 354 if (m_jwkAlgorithmName == "RSA_OAEP") 355 return sizeInBits >= 2048; 356 return true; 357} 358 359std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataOctetSequence() const 360{ 361 String keyBase64URL; 362 if (!getStringFromJSON(m_exec, m_json.get(), "k", keyBase64URL)) { 363 if (!m_exec->hadException()) 364 throwTypeError(m_exec, "Secret key data is not present is JWK"); 365 return nullptr; 366 } 367 368 Vector<uint8_t> octetSequence; 369 if (!base64URLDecode(keyBase64URL, octetSequence)) { 370 throwTypeError(m_exec, "Cannot decode base64url key data in JWK"); 371 return nullptr; 372 } 373 374 if (!keySizeIsValid(octetSequence.size() * 8)) { 375 throwTypeError(m_exec, "Key size is not valid for " + m_jwkAlgorithmName); 376 return nullptr; 377 } 378 379 return CryptoKeyDataOctetSequence::create(octetSequence); 380} 381 382std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataRSAComponents() const 383{ 384 Vector<uint8_t> modulus; 385 Vector<uint8_t> exponent; 386 Vector<uint8_t> privateExponent; 387 388 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "n", modulus)) { 389 if (!m_exec->hadException()) 390 throwTypeError(m_exec, "Required JWK \"n\" member is missing"); 391 return nullptr; 392 } 393 394 if (!keySizeIsValid(modulus.size() * 8)) { 395 throwTypeError(m_exec, "Key size is not valid for " + m_jwkAlgorithmName); 396 return nullptr; 397 } 398 399 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "e", exponent)) { 400 if (!m_exec->hadException()) 401 throwTypeError(m_exec, "Required JWK \"e\" member is missing"); 402 return nullptr; 403 } 404 405 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "d", modulus)) { 406 if (m_exec->hadException()) 407 return nullptr; 408 return CryptoKeyDataRSAComponents::createPublic(modulus, exponent); 409 } 410 411 CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo; 412 CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo; 413 Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; 414 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "p", firstPrimeInfo.primeFactor)) { 415 if (m_exec->hadException()) 416 return nullptr; 417 return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); 418 } 419 420 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dp", firstPrimeInfo.factorCRTExponent)) { 421 if (m_exec->hadException()) 422 return nullptr; 423 return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); 424 } 425 426 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "q", secondPrimeInfo.primeFactor)) { 427 if (m_exec->hadException()) 428 return nullptr; 429 return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); 430 } 431 432 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dq", secondPrimeInfo.factorCRTExponent)) { 433 if (m_exec->hadException()) 434 return nullptr; 435 return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); 436 } 437 438 if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "qi", secondPrimeInfo.factorCRTCoefficient)) { 439 if (m_exec->hadException()) 440 return nullptr; 441 return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); 442 } 443 444 JSArray* otherPrimeInfoJSArray; 445 if (!getJSArrayFromJSON(m_exec, m_json.get(), "oth", otherPrimeInfoJSArray)) { 446 if (m_exec->hadException()) 447 return nullptr; 448 return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); 449 } 450 451 for (size_t i = 0; i < otherPrimeInfoJSArray->length(); ++i) { 452 CryptoKeyDataRSAComponents::PrimeInfo info; 453 JSValue element = otherPrimeInfoJSArray->getIndex(m_exec, i); 454 if (m_exec->hadException()) 455 return nullptr; 456 if (!element.isObject()) { 457 throwTypeError(m_exec, "JWK \"oth\" array member is not an object"); 458 return nullptr; 459 } 460 if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "r", info.primeFactor)) { 461 if (!m_exec->hadException()) 462 throwTypeError(m_exec, "Cannot get prime factor for a prime in \"oth\" dictionary"); 463 return nullptr; 464 } 465 if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "d", info.factorCRTExponent)) { 466 if (!m_exec->hadException()) 467 throwTypeError(m_exec, "Cannot get factor CRT exponent for a prime in \"oth\" dictionary"); 468 return nullptr; 469 } 470 if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "t", info.factorCRTCoefficient)) { 471 if (!m_exec->hadException()) 472 throwTypeError(m_exec, "Cannot get factor CRT coefficient for a prime in \"oth\" dictionary"); 473 return nullptr; 474 } 475 otherPrimeInfos.append(info); 476 } 477 478 return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); 479} 480 481std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyData() const 482{ 483 String jwkKeyType; 484 if (!getStringFromJSON(m_exec, m_json.get(), "kty", jwkKeyType)) { 485 if (!m_exec->hadException()) 486 throwTypeError(m_exec, "Required JWK \"kty\" member is missing"); 487 return nullptr; 488 } 489 490 if (jwkKeyType == "oct") 491 return keyDataOctetSequence(); 492 493 if (jwkKeyType == "RSA") 494 return keyDataRSAComponents(); 495 496 throwTypeError(m_exec, "Unsupported JWK key type " + jwkKeyType); 497 return nullptr; 498} 499 500static void addToJSON(ExecState* exec, JSObject* json, const char* key, const String& value) 501{ 502 VM& vm = exec->vm(); 503 Identifier identifier(&vm, key); 504 json->putDirect(vm, identifier, jsString(exec, value)); 505} 506 507static void buildJSONForOctetSequence(ExecState* exec, const Vector<uint8_t>& keyData, JSObject* result) 508{ 509 addToJSON(exec, result, "kty", "oct"); 510 addToJSON(exec, result, "k", base64URLEncode(keyData)); 511} 512 513static void buildJSONForRSAComponents(JSC::ExecState* exec, const CryptoKeyDataRSAComponents& data, JSC::JSObject* result) 514{ 515 addToJSON(exec, result, "kty", "RSA"); 516 addToJSON(exec, result, "n", base64URLEncode(data.modulus())); 517 addToJSON(exec, result, "e", base64URLEncode(data.exponent())); 518 519 if (data.type() == CryptoKeyDataRSAComponents::Type::Public) 520 return; 521 522 addToJSON(exec, result, "d", base64URLEncode(data.privateExponent())); 523 524 if (!data.hasAdditionalPrivateKeyParameters()) 525 return; 526 527 addToJSON(exec, result, "p", base64URLEncode(data.firstPrimeInfo().primeFactor)); 528 addToJSON(exec, result, "q", base64URLEncode(data.secondPrimeInfo().primeFactor)); 529 addToJSON(exec, result, "dp", base64URLEncode(data.firstPrimeInfo().factorCRTExponent)); 530 addToJSON(exec, result, "dq", base64URLEncode(data.secondPrimeInfo().factorCRTExponent)); 531 addToJSON(exec, result, "qi", base64URLEncode(data.secondPrimeInfo().factorCRTCoefficient)); 532 533 if (data.otherPrimeInfos().isEmpty()) 534 return; 535 536 JSArray* oth = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), data.otherPrimeInfos().size()); 537 for (size_t i = 0, size = data.otherPrimeInfos().size(); i < size; ++i) { 538 JSObject* jsPrimeInfo = constructEmptyObject(exec); 539 addToJSON(exec, jsPrimeInfo, "r", base64URLEncode(data.otherPrimeInfos()[i].primeFactor)); 540 addToJSON(exec, jsPrimeInfo, "d", base64URLEncode(data.otherPrimeInfos()[i].factorCRTExponent)); 541 addToJSON(exec, jsPrimeInfo, "t", base64URLEncode(data.otherPrimeInfos()[i].factorCRTCoefficient)); 542 oth->putDirectIndex(exec, i, jsPrimeInfo); 543 } 544 result->putDirect(exec->vm(), Identifier(exec, "oth"), oth); 545} 546 547static void addBoolToJSON(ExecState* exec, JSObject* json, const char* key, bool value) 548{ 549 VM& vm = exec->vm(); 550 Identifier identifier(&vm, key); 551 json->putDirect(vm, identifier, jsBoolean(value)); 552} 553 554static void addJWKAlgorithmToJSON(ExecState* exec, JSObject* json, const CryptoKey& key) 555{ 556 String jwkAlgorithm; 557 switch (key.algorithmIdentifier()) { 558 case CryptoAlgorithmIdentifier::HMAC: 559 switch (toCryptoKeyHMAC(key).hashAlgorithmIdentifier()) { 560 case CryptoAlgorithmIdentifier::SHA_256: 561 if (toCryptoKeyHMAC(key).key().size() * 8 >= 256) 562 jwkAlgorithm = "HS256"; 563 break; 564 case CryptoAlgorithmIdentifier::SHA_384: 565 if (toCryptoKeyHMAC(key).key().size() * 8 >= 384) 566 jwkAlgorithm = "HS384"; 567 break; 568 case CryptoAlgorithmIdentifier::SHA_512: 569 if (toCryptoKeyHMAC(key).key().size() * 8 >= 512) 570 jwkAlgorithm = "HS512"; 571 break; 572 default: 573 break; 574 } 575 break; 576 case CryptoAlgorithmIdentifier::AES_CBC: 577 switch (toCryptoKeyAES(key).key().size() * 8) { 578 case 128: 579 jwkAlgorithm = "A128CBC"; 580 break; 581 case 192: 582 jwkAlgorithm = "A192CBC"; 583 break; 584 case 256: 585 jwkAlgorithm = "A256CBC"; 586 break; 587 } 588 break; 589 case CryptoAlgorithmIdentifier::AES_KW: 590 switch (toCryptoKeyAES(key).key().size() * 8) { 591 case 128: 592 jwkAlgorithm = "A128KW"; 593 break; 594 case 192: 595 jwkAlgorithm = "A192KW"; 596 break; 597 case 256: 598 jwkAlgorithm = "A256KW"; 599 break; 600 } 601 break; 602 case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: { 603 const CryptoKeyRSA& rsaKey = toCryptoKeyRSA(key); 604 CryptoAlgorithmIdentifier hash; 605 if (!rsaKey.isRestrictedToHash(hash)) 606 break; 607 if (rsaKey.keySizeInBits() < 2048) 608 break; 609 switch (hash) { 610 case CryptoAlgorithmIdentifier::SHA_256: 611 jwkAlgorithm = "RS256"; 612 break; 613 case CryptoAlgorithmIdentifier::SHA_384: 614 jwkAlgorithm = "RS384"; 615 break; 616 case CryptoAlgorithmIdentifier::SHA_512: 617 jwkAlgorithm = "RS512"; 618 break; 619 default: 620 break; 621 } 622 break; 623 } 624 case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: { 625 const CryptoKeyRSA& rsaKey = toCryptoKeyRSA(key); 626 if (rsaKey.keySizeInBits() < 2048) 627 break; 628 jwkAlgorithm = "RSA1_5"; 629 break; 630 } 631 case CryptoAlgorithmIdentifier::RSA_OAEP: { 632 const CryptoKeyRSA& rsaKey = toCryptoKeyRSA(key); 633 CryptoAlgorithmIdentifier hash; 634 // WebCrypto RSA-OAEP keys are not tied to any particular hash, unless previously imported from JWK, which only supports SHA-1. 635 if (rsaKey.isRestrictedToHash(hash) && hash != CryptoAlgorithmIdentifier::SHA_1) 636 break; 637 if (rsaKey.keySizeInBits() < 2048) 638 break; 639 jwkAlgorithm = "RSA-OAEP"; 640 break; 641 } 642 default: 643 break; 644 } 645 646 if (jwkAlgorithm.isNull()) { 647 // The spec doesn't currently tell whether export should fail, or just skip "alg" (which is an optional key in JWK). 648 throwTypeError(exec, "Key algorithm and size do not map to any JWK algorithm identifier"); 649 return; 650 } 651 652 addToJSON(exec, json, "alg", jwkAlgorithm); 653} 654 655static void addUsagesToJSON(ExecState* exec, JSObject* json, CryptoKeyUsage usages) 656{ 657 JSArray* keyOps = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), 0); 658 659 unsigned index = 0; 660 if (usages & CryptoKeyUsageSign) 661 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("sign"))); 662 if (usages & CryptoKeyUsageVerify) 663 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("verify"))); 664 if (usages & CryptoKeyUsageEncrypt) 665 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("encrypt"))); 666 if (usages & CryptoKeyUsageDecrypt) 667 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("decrypt"))); 668 if (usages & CryptoKeyUsageWrapKey) 669 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("wrapKey"))); 670 if (usages & CryptoKeyUsageUnwrapKey) 671 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("unwrapKey"))); 672 if (usages & CryptoKeyUsageDeriveKey) 673 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveKey"))); 674 if (usages & CryptoKeyUsageDeriveBits) 675 keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveBits"))); 676 677 json->putDirect(exec->vm(), Identifier(exec, "key_ops"), keyOps); 678} 679 680String JSCryptoKeySerializationJWK::serialize(ExecState* exec, const CryptoKey& key) 681{ 682 std::unique_ptr<CryptoKeyData> keyData = key.exportData(); 683 if (!keyData) { 684 // This generally shouldn't happen as long as all key types implement exportData(), but as underlying libraries return errors, there may be some rare failure conditions. 685 throwTypeError(exec, "Couldn't export key material"); 686 return String(); 687 } 688 689 JSObject* result = constructEmptyObject(exec); 690 691 addJWKAlgorithmToJSON(exec, result, key); 692 if (exec->hadException()) 693 return String(); 694 695 addBoolToJSON(exec, result, "ext", key.extractable()); 696 697 addUsagesToJSON(exec, result, key.usagesBitmap()); 698 if (exec->hadException()) 699 return String(); 700 701 if (isCryptoKeyDataOctetSequence(*keyData)) 702 buildJSONForOctetSequence(exec, toCryptoKeyDataOctetSequence(*keyData).octetSequence(), result); 703 else if (isCryptoKeyDataRSAComponents(*keyData)) 704 buildJSONForRSAComponents(exec, toCryptoKeyDataRSAComponents(*keyData), result); 705 else { 706 throwTypeError(exec, "Key doesn't support exportKey"); 707 return String(); 708 } 709 if (exec->hadException()) 710 return String(); 711 712 return JSONStringify(exec, result, 0); 713} 714 715} // namespace WebCore 716 717#endif // ENABLE(SUBTLE_CRYPTO) 718