| /* |
| * 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, 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; |
| // Per RFC 7518 Section 6.3.1.1: https://tools.ietf.org/html/rfc7518#section-6.3.1.1 |
| if (!modulus.isEmpty() && !modulus[0]) |
| modulus.remove(0); |
| Vector<uint8_t> exponent; |
| if (!WTF::base64URLDecode(keyData.e, 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 WTF::nullopt. |
| return CryptoKeyRSA::create(algorithm, hash.valueOr(CryptoAlgorithmIdentifier::SHA_1), !!hash, *publicKeyComponents, extractable, usages); |
| } |
| |
| // import private key |
| 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 = 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 WTF::nullopt. |
| return CryptoKeyRSA::create(algorithm, hash.valueOr(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; |
| CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo; |
| CryptoKeyRSAComponents::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 = 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 WTF::nullopt. |
| return CryptoKeyRSA::create(algorithm, hash.valueOr(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages); |
| } |
| |
| Vector<CryptoKeyRSAComponents::PrimeInfo> otherPrimeInfos; |
| for (const auto& value : keyData.oth.value()) { |
| CryptoKeyRSAComponents::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 = 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 WTF::nullopt. |
| return CryptoKeyRSA::create(algorithm, hash.valueOr(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(); |
| |
| // public key |
| result.n = base64URLEncode(rsaComponents->modulus()); |
| result.e = base64URLEncode(rsaComponents->exponent()); |
| if (rsaComponents->type() == CryptoKeyRSAComponents::Type::Public) |
| return result; |
| |
| // private key |
| result.d = base64URLEncode(rsaComponents->privateExponent()); |
| if (!rsaComponents->hasAdditionalPrivateKeyParameters()) |
| return result; |
| |
| result.p = base64URLEncode(rsaComponents->firstPrimeInfo().primeFactor); |
| result.q = base64URLEncode(rsaComponents->secondPrimeInfo().primeFactor); |
| result.dp = base64URLEncode(rsaComponents->firstPrimeInfo().factorCRTExponent); |
| result.dq = base64URLEncode(rsaComponents->secondPrimeInfo().factorCRTExponent); |
| result.qi = base64URLEncode(rsaComponents->secondPrimeInfo().factorCRTCoefficient); |
| if (rsaComponents->otherPrimeInfos().isEmpty()) |
| return result; |
| |
| Vector<RsaOtherPrimesInfo> oth; |
| for (const auto& info : rsaComponents->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; |
| } |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(WEB_CRYPTO) |