| /* |
| * 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 <wtf/text/Base64.h> |
| |
| #if ENABLE(WEB_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; |
| 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); |
| } |
| |
| JsonWebKey CryptoKeyRSA::exportJwk() const |
| { |
| JsonWebKey result; |
| result.kty = "RSA"; |
| 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<RsaOtherPrimesInfo> 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) |