/*
 * Copyright (C) 2017 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 "CryptoKeyEC.h"

#if ENABLE(SUBTLE_CRYPTO)

#include "CryptoAlgorithmRegistry.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 const char* const P521 = "P-521";

static std::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 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)
{
    // Only CryptoKeyEC objects for supported curves should be created.
    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()) {
        // import public key
        return platformImportJWKPublic(identifier, *namedCurve, WTFMove(x), WTFMove(y), extractable, usages);
    }

    Vector<uint8_t> d;
    if (!WTF::base64URLDecode(keyData.d, d))
        return nullptr;
    // import private key
    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 = ASCIILiteral(P256);
        break;
    case NamedCurve::P384:
        result.namedCurve = ASCIILiteral(P384);
        break;
    case NamedCurve::P521:
        result.namedCurve = ASCIILiteral(P521);
        break;
    }

    return result;
}

} // namespace WebCore

#endif // ENABLE(SUBTLE_CRYPTO)
