void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsage& suggestedUsages) const { CryptoKeyUsage jwkUsages = 0; JSArray* keyOps; if (getJSArrayFromJSON(m_exec, m_json.get(), "key_ops", keyOps)) { for (size_t i = 0; i < keyOps->length(); ++i) { JSValue jsValue = keyOps->getIndex(m_exec, i); String operation; if (!jsValue.getString(m_exec, operation)) { if (!m_exec->hadException()) throwTypeError(m_exec, "JWK key_ops attribute could not be processed"); return; } if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("sign"), CryptoKeyUsageSign)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("verify"), CryptoKeyUsageVerify)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("encrypt"), CryptoKeyUsageEncrypt)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("decrypt"), CryptoKeyUsageDecrypt)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("wrapKey"), CryptoKeyUsageWrapKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("unwrapKey"), CryptoKeyUsageUnwrapKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveKey"), CryptoKeyUsageDeriveKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveBits"), CryptoKeyUsageDeriveBits)) return; } } else { if (m_exec->hadException()) return; String jwkUseString; if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) { // We have neither key_ops nor use. return; } if (jwkUseString == "enc") jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); else if (jwkUseString == "sig") jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify); else { throwTypeError(m_exec, "Unsupported JWK key use value \"" + jwkUseString + "\""); return; } } suggestedUsages = suggestedUsages & jwkUsages; }
std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyData() const { String jwkKeyType; if (!getStringFromJSON(m_exec, m_json.get(), "kty", jwkKeyType)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Required JWK \"kty\" member is missing"); return nullptr; } if (jwkKeyType == "oct") return keyDataOctetSequence(); if (jwkKeyType == "RSA") return keyDataRSAComponents(); throwTypeError(m_exec, "Unsupported JWK key type " + jwkKeyType); return nullptr; }
static bool getBigIntegerVectorFromJSON(ExecState* exec, JSObject* json, const char* key, Vector<uint8_t>& result) { String base64urlEncodedNumber; if (!getStringFromJSON(exec, json, key, base64urlEncodedNumber)) return false; if (!base64URLDecode(base64urlEncodedNumber, result)) { throwTypeError(exec, "Cannot decode base64url key data in JWK"); return false; } if (result[0] == 0) { throwTypeError(exec, "JWK BigInteger must utilize the minimum number of octets to represent the value"); return false; } return true; }
void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsage& suggestedUsage) const { String jwkUseString; if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) { // "use" is optional in JWK. return; } // FIXME: CryptoKeyUsageDeriveKey, CryptoKeyUsageDeriveBits - should these be implicitly allowed by any JWK use value? // FIXME: "use" mapping is in flux, see <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796>. if (jwkUseString == "sig") suggestedUsage = suggestedUsage & (CryptoKeyUsageSign | CryptoKeyUsageVerify); else if (jwkUseString == "enc") suggestedUsage = suggestedUsage & (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); else if (jwkUseString == "wrap") suggestedUsage = suggestedUsage & (CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); else suggestedUsage = 0; // Unknown usage, better be safe. }
std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataOctetSequence() const { String keyBase64URL; if (!getStringFromJSON(m_exec, m_json.get(), "k", keyBase64URL)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Secret key data is not present is JWK"); return nullptr; } Vector<uint8_t> octetSequence; if (!base64URLDecode(keyBase64URL, octetSequence)) { throwTypeError(m_exec, "Cannot decode base64url key data in JWK"); return nullptr; } if (!keySizeIsValid(octetSequence.size() * 8)) { throwTypeError(m_exec, "Key size is not valid for " + m_jwkAlgorithmName); return nullptr; } return CryptoKeyDataOctetSequence::create(octetSequence); }
bool JSCryptoKeySerializationJWK::reconcileAlgorithm(std::unique_ptr<CryptoAlgorithm>& suggestedAlgorithm, std::unique_ptr<CryptoAlgorithmParameters>& suggestedParameters) const { if (!getStringFromJSON(m_exec, m_json.get(), "alg", m_jwkAlgorithmName)) { // Algorithm is optional in JWK. return true; } std::unique_ptr<CryptoAlgorithm> algorithm; std::unique_ptr<CryptoAlgorithmParameters> parameters; if (m_jwkAlgorithmName == "HS256") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_256); } else if (m_jwkAlgorithmName == "HS384") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_384); } else if (m_jwkAlgorithmName == "HS512") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::HMAC); parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_512); } else if (m_jwkAlgorithmName == "RS256") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); parameters = createRSASSAKeyParameters(CryptoAlgorithmIdentifier::SHA_256); } else if (m_jwkAlgorithmName == "RS384") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); parameters = createRSASSAKeyParameters(CryptoAlgorithmIdentifier::SHA_384); } else if (m_jwkAlgorithmName == "RS512") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); parameters = createRSASSAKeyParameters(CryptoAlgorithmIdentifier::SHA_512); } else if (m_jwkAlgorithmName == "A128CBC") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); parameters = std::make_unique<CryptoAlgorithmParameters>(); } else if (m_jwkAlgorithmName == "A192CBC") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); parameters = std::make_unique<CryptoAlgorithmParameters>(); } else if (m_jwkAlgorithmName == "A256CBC") { algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC); parameters = std::make_unique<CryptoAlgorithmParameters>(); } else { throwTypeError(m_exec, "Unsupported JWK algorithm " + m_jwkAlgorithmName); return false; } if (!suggestedAlgorithm) { suggestedAlgorithm = std::move(algorithm); suggestedParameters = std::move(parameters); return true; } if (!algorithm) return true; if (algorithm->identifier() != suggestedAlgorithm->identifier()) return false; if (algorithm->identifier() == CryptoAlgorithmIdentifier::HMAC) return toCryptoAlgorithmHmacParams(*parameters).hash == toCryptoAlgorithmHmacParams(*suggestedParameters).hash; if (algorithm->identifier() == CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5) { CryptoAlgorithmRsaSsaKeyParams& rsaSSAParameters = toCryptoAlgorithmRsaSsaKeyParams(*parameters); CryptoAlgorithmRsaSsaKeyParams& suggestedRSASSAParameters = toCryptoAlgorithmRsaSsaKeyParams(*suggestedParameters); ASSERT(rsaSSAParameters.hasHash); if (suggestedRSASSAParameters.hasHash) return suggestedRSASSAParameters.hash == rsaSSAParameters.hash; suggestedRSASSAParameters.hasHash = true; suggestedRSASSAParameters.hash = rsaSSAParameters.hash; } // Other algorithms don't have parameters. return true; }