/*
 * Copyright (C) 2017-2019 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(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 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, PlatformECKeyContainer&& platformKey, bool extractable, CryptoKeyUsageBitmap usages)
    : CryptoKey(identifier, type, extractable, usages)
    , m_platformKey(WTFMove(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;
    auto x = base64URLDecode(keyData.x);
    if (!x)
        return nullptr;
    auto y = base64URLDecode(keyData.y);
    if (!y)
        return nullptr;
    if (keyData.d.isNull()) {
        // import public key
        return platformImportJWKPublic(identifier, *namedCurve, WTFMove(*x), WTFMove(*y), extractable, usages);
    }

    auto d = base64URLDecode(keyData.d);
    if (!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 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;
}

} // namespace WebCore

#endif // ENABLE(WEB_CRYPTO)
