RefPtr CryptoKeyRSA::importJwk()

in src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp [38:132]


RefPtr<CryptoKeyRSA> CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm, std::optional<CryptoAlgorithmIdentifier> hash, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
    if (keyData.kty != "RSA"_s)
        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;
    auto modulus = base64URLDecode(keyData.n);
    if (!modulus)
        return nullptr;
    // Per RFC 7518 Section 6.3.1.1: https://tools.ietf.org/html/rfc7518#section-6.3.1.1
    if (!modulus->isEmpty() && !modulus->at(0))
        modulus->remove(0);
    auto exponent = base64URLDecode(keyData.e);
    if (!exponent)
        return nullptr;
    if (keyData.d.isNull()) {
        // import public key
        auto publicKeyComponents = CryptoKeyRSAComponents::createPublic(WTFMove(*modulus), WTFMove(*exponent));
        // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
        return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *publicKeyComponents, extractable, usages);
    }

    // import private key
    auto privateExponent = base64URLDecode(keyData.d);
    if (!privateExponent)
        return nullptr;
    if (keyData.p.isNull() && keyData.q.isNull() && keyData.dp.isNull() && keyData.dp.isNull() && keyData.qi.isNull()) {
        auto privateKeyComponents = CryptoKeyRSAComponents::createPrivate(WTFMove(*modulus), WTFMove(*exponent), WTFMove(*privateExponent));
        // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
        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;

    auto firstPrimeFactor = base64URLDecode(keyData.p);
    if (!firstPrimeFactor)
        return nullptr;
    auto firstFactorCRTExponent = base64URLDecode(keyData.dp);
    if (!firstFactorCRTExponent)
        return nullptr;
    auto secondPrimeFactor = base64URLDecode(keyData.q);
    if (!secondPrimeFactor)
        return nullptr;
    auto secondFactorCRTExponent = base64URLDecode(keyData.dq);
    if (!secondFactorCRTExponent)
        return nullptr;
    auto secondFactorCRTCoefficient = base64URLDecode(keyData.qi);
    if (!secondFactorCRTCoefficient)
        return nullptr;

    CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
    firstPrimeInfo.primeFactor = WTFMove(*firstPrimeFactor);
    firstPrimeInfo.factorCRTExponent = WTFMove(*firstFactorCRTExponent);

    CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
    secondPrimeInfo.primeFactor = WTFMove(*secondPrimeFactor);
    secondPrimeInfo.factorCRTExponent = WTFMove(*secondFactorCRTExponent);
    secondPrimeInfo.factorCRTCoefficient = WTFMove(*secondFactorCRTCoefficient);

    if (!keyData.oth) {
        auto privateKeyComponents = CryptoKeyRSAComponents::createPrivateWithAdditionalData(WTFMove(*modulus), WTFMove(*exponent), WTFMove(*privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), {});
        // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
        return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
    }

    Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos;
    for (const auto& value : keyData.oth.value()) {
        auto primeFactor = base64URLDecode(value.r);
        if (!primeFactor)
            return nullptr;
        auto factorCRTExponent = base64URLDecode(value.d);
        if (!factorCRTExponent)
            return nullptr;
        auto factorCRTCoefficient = base64URLDecode(value.t);
        if (!factorCRTCoefficient)
            return nullptr;

        CryptoKeyRSAComponents::PrimeInfo info;
        info.primeFactor = WTFMove(*primeFactor);
        info.factorCRTExponent = WTFMove(*factorCRTExponent);
        info.factorCRTCoefficient = WTFMove(*factorCRTCoefficient);

        otherPrimeInfos.append(WTFMove(info));
    }

    auto privateKeyComponents = CryptoKeyRSAComponents::createPrivateWithAdditionalData(WTFMove(*modulus), WTFMove(*exponent), WTFMove(*privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), WTFMove(otherPrimeInfos));
    // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
    return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
}