#include "config.h"
#include "CryptoKeyEC.h"
#if ENABLE(SUBTLE_CRYPTO)
#include "CryptoAlgorithmRegistry.h"
#include "CryptoKeyData.h"
#include "ExceptionCode.h"
#include "JsonWebKey.h"
#include <wtf/text/Base64.h>
namespace WebCore {
static const char* const P256 = "P-256";
static const char* const P384 = "P-384";
static std::optional<CryptoKeyEC::NamedCurve> toNamedCurve(const String& curve)
{
if (curve == P256)
return CryptoKeyEC::NamedCurve::P256;
if (curve == P384)
return CryptoKeyEC::NamedCurve::P384;
return std::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)
{
}
ExceptionOr<CryptoKeyPair> CryptoKeyEC::generatePair(CryptoAlgorithmIdentifier identifier, const String& curve, bool extractable, CryptoKeyUsageBitmap usages)
{
auto namedCurve = toNamedCurve(curve);
if (!namedCurve)
return Exception { NOT_SUPPORTED_ERR };
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)
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)
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)
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)
return nullptr;
return platformImportPkcs8(identifier, *namedCurve, WTFMove(keyData), extractable, usages);
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportRaw() const
{
if (type() != CryptoKey::Type::Public)
return Exception { INVALID_ACCESS_ERR };
return platformExportRaw();
}
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;
}
result.key_ops = usages();
result.ext = extractable();
platformAddFieldElements(result);
return result;
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportSpki() const
{
if (type() != CryptoKey::Type::Public)
return Exception { INVALID_ACCESS_ERR };
return platformExportSpki();
}
ExceptionOr<Vector<uint8_t>> CryptoKeyEC::exportPkcs8() const
{
if (type() != CryptoKey::Type::Private)
return Exception { INVALID_ACCESS_ERR };
return platformExportPkcs8();
}
String CryptoKeyEC::namedCurveString() const
{
switch (m_curve) {
case NamedCurve::P256:
return String(P256);
case NamedCurve::P384:
return String(P384);
}
ASSERT_NOT_REACHED();
return emptyString();
}
bool CryptoKeyEC::isValidECAlgorithm(CryptoAlgorithmIdentifier algorithm)
{
return algorithm == CryptoAlgorithmIdentifier::ECDSA || algorithm == CryptoAlgorithmIdentifier::ECDH;
}
std::unique_ptr<KeyAlgorithm> CryptoKeyEC::buildAlgorithm() const
{
String name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
switch (m_curve) {
case NamedCurve::P256:
return std::make_unique<EcKeyAlgorithm>(name, String(P256));
case NamedCurve::P384:
return std::make_unique<EcKeyAlgorithm>(name, String(P384));
}
ASSERT_NOT_REACHED();
return nullptr;
}
std::unique_ptr<CryptoKeyData> CryptoKeyEC::exportData() const
{
return std::make_unique<CryptoKeyData>(CryptoKeyData::Format::OctetSequence);
}
}
#endif // ENABLE(SUBTLE_CRYPTO)