#include "config.h"
#include "CryptoKeyEC.h"
#if ENABLE(WEB_CRYPTO)
#include "CryptoAlgorithmRegistry.h"
#include "JsonWebKey.h"
#include <wtf/text/Base64.h>
namespace WebCore {
static const ASCIILiteral P256 { "P-256"_s };
static const ASCIILiteral P384 { "P-384"_s };
static const ASCIILiteral P521 { "P-521"_s };
static Optional<CryptoKeyEC::NamedCurve> toNamedCurve(const String& curve)
{
if (curve == P256)
return CryptoKeyEC::NamedCurve::P256;
if (curve == P384)
return CryptoKeyEC::NamedCurve::P384;
if (curve == P521)
return CryptoKeyEC::NamedCurve::P521;
return WTF::nullopt;
}
CryptoKeyEC::CryptoKeyEC(CryptoAlgorithmIdentifier identifier, NamedCurve curve, CryptoKeyType type, PlatformECKey platformKey, bool extractable, CryptoKeyUsageBitmap usages)
: CryptoKey(identifier, type, extractable, usages)
, m_platformKey(platformKey)
, m_curve(curve)
{
ASSERT(platformSupportedCurve(curve));
}
ExceptionOr<CryptoKeyPair> CryptoKeyEC::generatePair(CryptoAlgorithmIdentifier identifier, const String& curve, bool extractable, CryptoKeyUsageBitmap usages)
{
auto namedCurve = toNamedCurve(curve);
if (!namedCurve || !platformSupportedCurve(*namedCurve))
return Exception { NotSupportedError };
auto result = platformGeneratePair(identifier, *namedCurve, extractable, usages);
if (!result)
return Exception { OperationError };
return WTFMove(*result);
}
RefPtr<CryptoKeyEC> CryptoKeyEC::importRaw(CryptoAlgorithmIdentifier identifier, const String& curve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
auto namedCurve = toNamedCurve(curve);
if (!namedCurve || !platformSupportedCurve(*namedCurve))
return nullptr;
return platformImportRaw(identifier, *namedCurve, WTFMove(keyData), extractable, usages);
}
RefPtr<CryptoKeyEC> CryptoKeyEC::importJwk(CryptoAlgorithmIdentifier identifier, const String& curve, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
if (keyData.kty != "EC")
return nullptr;
if (keyData.key_ops && ((keyData.usages & usages) != usages))
return nullptr;
if (keyData.ext && !keyData.ext.value() && extractable)
return nullptr;
if (keyData.crv.isNull() || curve != keyData.crv)
return nullptr;
auto namedCurve = toNamedCurve(keyData.crv);
if (!namedCurve || !platformSupportedCurve(*namedCurve))
return nullptr;
if (keyData.x.isNull() || keyData.y.isNull())
return nullptr;
Vector<uint8_t> x;
if (!WTF::base64URLDecode(keyData.x, x))
return nullptr;
Vector<uint8_t> y;
if (!WTF::base64URLDecode(keyData.y, y))
return nullptr;
if (keyData.d.isNull()) {
return platformImportJWKPublic(identifier, *namedCurve, WTFMove(x), WTFMove(y), extractable, usages);
}
Vector<uint8_t> d;
if (!WTF::base64URLDecode(keyData.d, d))
return nullptr;
return platformImportJWKPrivate(identifier, *namedCurve, WTFMove(x), WTFMove(y), WTFMove(d), extractable, usages);
}
RefPtr<CryptoKeyEC> CryptoKeyEC::importSpki(CryptoAlgorithmIdentifier identifier, const String& curve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
auto namedCurve = toNamedCurve(curve);
if (!namedCurve || !platformSupportedCurve(*namedCurve))
return nullptr;
return platformImportSpki(identifier, *namedCurve, WTFMove(keyData), extractable, usages);
}
RefPtr<CryptoKeyEC> CryptoKeyEC::importPkcs8(CryptoAlgorithmIdentifier identifier, const String& curve, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
{
auto namedCurve = toNamedCurve(curve);
if (!namedCurve || !platformSupportedCurve(*namedCurve))
return nullptr;
return platformImportPkcs8(identifier, *namedCurve, WTFMove(keyData), extractable, usages);
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportRaw() const
{
if (type() != CryptoKey::Type::Public)
return Exception { InvalidAccessError };
auto&& result = platformExportRaw();
if (result.isEmpty())
return Exception { OperationError };
return WTFMove(result);
}
ExceptionOr<JsonWebKey> CryptoKeyEC::exportJwk() const
{
JsonWebKey result;
result.kty = "EC";
switch (m_curve) {
case NamedCurve::P256:
result.crv = P256;
break;
case NamedCurve::P384:
result.crv = P384;
break;
case NamedCurve::P521:
result.crv = P521;
break;
}
result.key_ops = usages();
result.ext = extractable();
if (!platformAddFieldElements(result))
return Exception { OperationError };
return WTFMove(result);
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportSpki() const
{
if (type() != CryptoKey::Type::Public)
return Exception { InvalidAccessError };
auto&& result = platformExportSpki();
if (result.isEmpty())
return Exception { OperationError };
return WTFMove(result);
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportPkcs8() const
{
if (type() != CryptoKey::Type::Private)
return Exception { InvalidAccessError };
auto&& result = platformExportPkcs8();
if (result.isEmpty())
return Exception { OperationError };
return WTFMove(result);
}
String CryptoKeyEC::namedCurveString() const
{
switch (m_curve) {
case NamedCurve::P256:
return String(P256);
case NamedCurve::P384:
return String(P384);
case NamedCurve::P521:
return String(P521);
}
ASSERT_NOT_REACHED();
return emptyString();
}
bool CryptoKeyEC::isValidECAlgorithm(CryptoAlgorithmIdentifier algorithm)
{
return algorithm == CryptoAlgorithmIdentifier::ECDSA || algorithm == CryptoAlgorithmIdentifier::ECDH;
}
auto CryptoKeyEC::algorithm() const -> KeyAlgorithm
{
CryptoEcKeyAlgorithm result;
result.name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
switch (m_curve) {
case NamedCurve::P256:
result.namedCurve = P256;
break;
case NamedCurve::P384:
result.namedCurve = P384;
break;
case NamedCurve::P521:
result.namedCurve = P521;
break;
}
return result;
}
}
#endif // ENABLE(WEB_CRYPTO)