/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "CryptoKeyRSA.h" #include "CryptoKeyRSAComponents.h" #include "JsonWebKey.h" #include #if ENABLE(WEB_CRYPTO) namespace WebCore { RefPtr CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm, std::optional 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 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); } JsonWebKey CryptoKeyRSA::exportJwk() const { JsonWebKey result; result.kty = "RSA"_s; result.key_ops = usages(); result.ext = extractable(); auto rsaComponents = exportData(); if (!rsaComponents) return result; // public key result.n = base64URLEncodeToString(rsaComponents->modulus()); result.e = base64URLEncodeToString(rsaComponents->exponent()); if (rsaComponents->type() == CryptoKeyRSAComponents::Type::Public) return result; // private key result.d = base64URLEncodeToString(rsaComponents->privateExponent()); if (!rsaComponents->hasAdditionalPrivateKeyParameters()) return result; result.p = base64URLEncodeToString(rsaComponents->firstPrimeInfo().primeFactor); result.q = base64URLEncodeToString(rsaComponents->secondPrimeInfo().primeFactor); result.dp = base64URLEncodeToString(rsaComponents->firstPrimeInfo().factorCRTExponent); result.dq = base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTExponent); result.qi = base64URLEncodeToString(rsaComponents->secondPrimeInfo().factorCRTCoefficient); if (rsaComponents->otherPrimeInfos().isEmpty()) return result; Vector oth; for (const auto& info : rsaComponents->otherPrimeInfos()) { RsaOtherPrimesInfo otherInfo; otherInfo.r = base64URLEncodeToString(info.primeFactor); otherInfo.d = base64URLEncodeToString(info.factorCRTExponent); otherInfo.t = base64URLEncodeToString(info.factorCRTCoefficient); oth.append(WTFMove(otherInfo)); } result.oth = WTFMove(oth); return result; } } // namespace WebCore #endif // ENABLE(WEB_CRYPTO)