blob: 273218721b37c70f4b99c764f4afe9ef0c2d420c [file] [log] [blame]
/*
* 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)