diff options
author | 2022-10-23 20:25:18 -0700 | |
---|---|---|
committer | 2022-10-23 20:25:18 -0700 | |
commit | 76652ac3cad64dbc2fd54e976ce4bad0a37caa03 (patch) | |
tree | 179865bc417dc6bf2f224dd310b77b931ee45c73 /src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp | |
parent | 14cec299f5170b8ed35eed28e53b88724b8cc04f (diff) | |
download | bun-76652ac3cad64dbc2fd54e976ce4bad0a37caa03.tar.gz bun-76652ac3cad64dbc2fd54e976ce4bad0a37caa03.tar.zst bun-76652ac3cad64dbc2fd54e976ce4bad0a37caa03.zip |
Add Web Crypto API (#1384)
* Add Web Crypto API
* Duplicate symbols
* Update c_cpp_properties.json
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp')
-rw-r--r-- | src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp new file mode 100644 index 000000000..273218721 --- /dev/null +++ b/src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp @@ -0,0 +1,178 @@ +/* + * 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"_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); +} + +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<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) |