#include "config.h"
#include "CryptoKeyRSA.h"
#include "CryptoKeyDataRSAComponents.h"
#include "JsonWebKey.h"
#include <wtf/text/Base64.h>
#if ENABLE(SUBTLE_CRYPTO)
namespace WebCore {
RefPtr<CryptoKeyRSA> CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm, std::optional<CryptoAlgorithmIdentifier> hash, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
if (keyData.kty != "RSA")
return nullptr;
if (keyData.key_ops && ((keyData.usages & usages) != usages))
return nullptr;
if (keyData.ext && !keyData.ext.value() && extractable)
return nullptr;
if (keyData.n.isNull() || keyData.e.isNull())
return nullptr;
Vector<uint8_t> modulus;
if (!WTF::base64URLDecode(keyData.n, modulus))
return nullptr;
if (!modulus.isEmpty() && !modulus[0])
modulus.remove(0);
Vector<uint8_t> exponent;
if (!WTF::base64URLDecode(keyData.e, exponent))
return nullptr;
if (keyData.d.isNull()) {
auto publicKeyComponents = CryptoKeyDataRSAComponents::createPublic(WTFMove(modulus), WTFMove(exponent));
return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *publicKeyComponents, extractable, usages);
}
Vector<uint8_t> privateExponent;
if (!WTF::base64URLDecode(keyData.d, privateExponent))
return nullptr;
if (keyData.p.isNull() && keyData.q.isNull() && keyData.dp.isNull() && keyData.dp.isNull() && keyData.qi.isNull()) {
auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivate(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent));
return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
}
if (keyData.p.isNull() || keyData.q.isNull() || keyData.dp.isNull() || keyData.dq.isNull() || keyData.qi.isNull())
return nullptr;
CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
if (!WTF::base64URLDecode(keyData.p, firstPrimeInfo.primeFactor))
return nullptr;
if (!WTF::base64URLDecode(keyData.dp, firstPrimeInfo.factorCRTExponent))
return nullptr;
if (!WTF::base64URLDecode(keyData.q, secondPrimeInfo.primeFactor))
return nullptr;
if (!WTF::base64URLDecode(keyData.dq, secondPrimeInfo.factorCRTExponent))
return nullptr;
if (!WTF::base64URLDecode(keyData.qi, secondPrimeInfo.factorCRTCoefficient))
return nullptr;
if (!keyData.oth) {
auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), { });
return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
}
Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos;
for (auto value : keyData.oth.value()) {
CryptoKeyDataRSAComponents::PrimeInfo info;
if (!WTF::base64URLDecode(value.r, info.primeFactor))
return nullptr;
if (!WTF::base64URLDecode(value.d, info.factorCRTExponent))
return nullptr;
if (!WTF::base64URLDecode(value.t, info.factorCRTCoefficient))
return nullptr;
otherPrimeInfos.append(info);
}
auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), WTFMove(otherPrimeInfos));
return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
}
JsonWebKey CryptoKeyRSA::exportJwk() const
{
JsonWebKey result;
result.kty = "RSA";
result.key_ops = usages();
result.ext = extractable();
auto keyData = exportData();
const auto& rsaKeyData = downcast<CryptoKeyDataRSAComponents>(*keyData);
result.n = base64URLEncode(rsaKeyData.modulus());
result.e = base64URLEncode(rsaKeyData.exponent());
if (rsaKeyData.type() == CryptoKeyDataRSAComponents::Type::Public)
return result;
result.d = base64URLEncode(rsaKeyData.privateExponent());
if (!rsaKeyData.hasAdditionalPrivateKeyParameters())
return result;
result.p = base64URLEncode(rsaKeyData.firstPrimeInfo().primeFactor);
result.q = base64URLEncode(rsaKeyData.secondPrimeInfo().primeFactor);
result.dp = base64URLEncode(rsaKeyData.firstPrimeInfo().factorCRTExponent);
result.dq = base64URLEncode(rsaKeyData.secondPrimeInfo().factorCRTExponent);
result.qi = base64URLEncode(rsaKeyData.secondPrimeInfo().factorCRTCoefficient);
if (rsaKeyData.otherPrimeInfos().isEmpty())
return result;
Vector<RsaOtherPrimesInfo> oth;
for (auto info : rsaKeyData.otherPrimeInfos()) {
RsaOtherPrimesInfo otherInfo;
otherInfo.r = base64URLEncode(info.primeFactor);
otherInfo.d = base64URLEncode(info.factorCRTExponent);
otherInfo.t = base64URLEncode(info.factorCRTCoefficient);
oth.append(WTFMove(otherInfo));
}
result.oth = WTFMove(oth);
return result;
}
}
#endif // ENABLE(SUBTLE_CRYPTO)