/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This code is made available to you under your choice of the following sets
 * of licensing terms:
 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/* Copyright 2013 Mozilla Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <functional>
#include <vector>

#include "pkixgtest.h"

#include "mozpkix/pkixtypes.h"
#include "mozpkix/pkixder.h"

using namespace mozilla::pkix;
using namespace mozilla::pkix::der;
using namespace mozilla::pkix::test;

class pkixder_pki_types_tests : public ::testing::Test { };

TEST_F(pkixder_pki_types_tests, CertificateSerialNumber)
{
  const uint8_t DER_CERT_SERIAL[] = {
    0x02,                       // INTEGER
    8,                          // length
    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
  };
  Input input(DER_CERT_SERIAL);
  Reader reader(input);

  Input item;
  ASSERT_EQ(Success, CertificateSerialNumber(reader, item));

  Input expected;
  ASSERT_EQ(Success,
            expected.Init(DER_CERT_SERIAL + 2, sizeof DER_CERT_SERIAL - 2));
  ASSERT_TRUE(InputsAreEqual(expected, item));
}

TEST_F(pkixder_pki_types_tests, CertificateSerialNumberLongest)
{
  const uint8_t DER_CERT_SERIAL_LONGEST[] = {
    0x02,                       // INTEGER
    20,                         // length
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
  };
  Input input(DER_CERT_SERIAL_LONGEST);
  Reader reader(input);

  Input item;
  ASSERT_EQ(Success, CertificateSerialNumber(reader, item));

  Input expected;
  ASSERT_EQ(Success,
            expected.Init(DER_CERT_SERIAL_LONGEST + 2,
                          sizeof DER_CERT_SERIAL_LONGEST - 2));
  ASSERT_TRUE(InputsAreEqual(expected, item));
}

TEST_F(pkixder_pki_types_tests, CertificateSerialNumberCrazyLong)
{
  const uint8_t DER_CERT_SERIAL_CRAZY_LONG[] = {
    0x02,                       // INTEGER
    32,                         // length
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
  };
  Input input(DER_CERT_SERIAL_CRAZY_LONG);
  Reader reader(input);

  Input item;
  ASSERT_EQ(Success, CertificateSerialNumber(reader, item));
}

TEST_F(pkixder_pki_types_tests, CertificateSerialNumberZeroLength)
{
  const uint8_t DER_CERT_SERIAL_ZERO_LENGTH[] = {
    0x02,                       // INTEGER
    0x00                        // length
  };
  Input input(DER_CERT_SERIAL_ZERO_LENGTH);
  Reader reader(input);

  Input item;
  ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING,
            CertificateSerialNumber(reader, item));
}

TEST_F(pkixder_pki_types_tests, OptionalVersionV1ExplicitEncodingAllowed)
{
  const uint8_t DER_OPTIONAL_VERSION_V1[] = {
    0xa0, 0x03,                   // context specific 0
    0x02, 0x01, 0x00              // INTEGER(0)
  };
  Input input(DER_OPTIONAL_VERSION_V1);
  Reader reader(input);

  // XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
  // do here for compatibility reasons.
  // Version version;
  // ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
  der::Version version = der::Version::v3;
  ASSERT_EQ(Success, OptionalVersion(reader, version));
  ASSERT_EQ(der::Version::v1, version);
}

TEST_F(pkixder_pki_types_tests, OptionalVersionV2)
{
  const uint8_t DER_OPTIONAL_VERSION_V2[] = {
    0xa0, 0x03,                   // context specific 0
    0x02, 0x01, 0x01              // INTEGER(1)
  };
  Input input(DER_OPTIONAL_VERSION_V2);
  Reader reader(input);

  der::Version version = der::Version::v1;
  ASSERT_EQ(Success, OptionalVersion(reader, version));
  ASSERT_EQ(der::Version::v2, version);
}

TEST_F(pkixder_pki_types_tests, OptionalVersionV3)
{
  const uint8_t DER_OPTIONAL_VERSION_V3[] = {
    0xa0, 0x03,                   // context specific 0
    0x02, 0x01, 0x02              // INTEGER(2)
  };
  Input input(DER_OPTIONAL_VERSION_V3);
  Reader reader(input);

  der::Version version = der::Version::v1;
  ASSERT_EQ(Success, OptionalVersion(reader, version));
  ASSERT_EQ(der::Version::v3, version);
}

TEST_F(pkixder_pki_types_tests, OptionalVersionUnknown)
{
  const uint8_t DER_OPTIONAL_VERSION_INVALID[] = {
    0xa0, 0x03,                   // context specific 0
    0x02, 0x01, 0x42              // INTEGER(0x42)
  };
  Input input(DER_OPTIONAL_VERSION_INVALID);
  Reader reader(input);

  der::Version version = der::Version::v1;
  ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
}

TEST_F(pkixder_pki_types_tests, OptionalVersionInvalidTooLong)
{
  const uint8_t DER_OPTIONAL_VERSION_INVALID_TOO_LONG[] = {
    0xa0, 0x03,                   // context specific 0
    0x02, 0x02, 0x12, 0x34        // INTEGER(0x1234)
  };
  Input input(DER_OPTIONAL_VERSION_INVALID_TOO_LONG);
  Reader reader(input);

  der::Version version;
  ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(reader, version));
}

TEST_F(pkixder_pki_types_tests, OptionalVersionMissing)
{
  const uint8_t DER_OPTIONAL_VERSION_MISSING[] = {
    0x02, 0x11, 0x22              // INTEGER
  };
  Input input(DER_OPTIONAL_VERSION_MISSING);
  Reader reader(input);

  der::Version version = der::Version::v3;
  ASSERT_EQ(Success, OptionalVersion(reader, version));
  ASSERT_EQ(der::Version::v1, version);
}

static const size_t MAX_ALGORITHM_OID_DER_LENGTH = 65;

struct InvalidAlgorithmIdentifierTestInfo
{
  uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
  size_t derLength;
};

struct ValidDigestAlgorithmIdentifierTestInfo
{
  DigestAlgorithm algorithm;
  uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
  size_t derLength;
};

class pkixder_DigestAlgorithmIdentifier_Valid
  : public ::testing::Test
  , public ::testing::WithParamInterface<ValidDigestAlgorithmIdentifierTestInfo>
{
};

static const ValidDigestAlgorithmIdentifierTestInfo
  VALID_DIGEST_ALGORITHM_TEST_INFO[] =
{
  { DigestAlgorithm::sha512,
    { 0x30, 0x0b, 0x06, 0x09,
      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 },
    13
  },
  { DigestAlgorithm::sha384,
    { 0x30, 0x0b, 0x06, 0x09,
      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 },
    13
  },
  { DigestAlgorithm::sha256,
    { 0x30, 0x0b, 0x06, 0x09,
      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 },
    13
  },
  { DigestAlgorithm::sha1,
    { 0x30, 0x07, 0x06, 0x05,
      0x2b, 0x0e, 0x03, 0x02, 0x1a },
    9
  },
};

TEST_P(pkixder_DigestAlgorithmIdentifier_Valid, Valid)
{
  const ValidDigestAlgorithmIdentifierTestInfo& param(GetParam());

  {
    Input input;
    ASSERT_EQ(Success, input.Init(param.der, param.derLength));
    Reader reader(input);
    DigestAlgorithm alg;
    ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg));
    ASSERT_EQ(param.algorithm, alg);
    ASSERT_EQ(Success, End(reader));
  }

  {
    uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2];
    memcpy(derWithNullParam, param.der, param.derLength);
    derWithNullParam[1] += 2; // we're going to expand the value by 2 bytes
    derWithNullParam[param.derLength] = 0x05; // NULL tag
    derWithNullParam[param.derLength + 1] = 0x00; // length zero

    Input input;
    ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
    Reader reader(input);
    DigestAlgorithm alg;
    ASSERT_EQ(Success, DigestAlgorithmIdentifier(reader, alg));
    ASSERT_EQ(param.algorithm, alg);
    ASSERT_EQ(Success, End(reader));
  }
}

INSTANTIATE_TEST_SUITE_P(pkixder_DigestAlgorithmIdentifier_Valid,
                        pkixder_DigestAlgorithmIdentifier_Valid,
                        testing::ValuesIn(VALID_DIGEST_ALGORITHM_TEST_INFO));

class pkixder_DigestAlgorithmIdentifier_Invalid
  : public ::testing::Test
  , public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo>
{
};

static const InvalidAlgorithmIdentifierTestInfo
  INVALID_DIGEST_ALGORITHM_TEST_INFO[] =
{
  { // MD5
    { 0x30, 0x0a, 0x06, 0x08,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05 },
    12,
  },
  { // ecdsa-with-SHA256 (1.2.840.10045.4.3.2) (not a hash algorithm)
    { 0x30, 0x0a, 0x06, 0x08,
      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 },
    12,
  },
};

TEST_P(pkixder_DigestAlgorithmIdentifier_Invalid, Invalid)
{
  const InvalidAlgorithmIdentifierTestInfo& param(GetParam());
  Input input;
  ASSERT_EQ(Success, input.Init(param.der, param.derLength));
  Reader reader(input);
  DigestAlgorithm alg;
  ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
            DigestAlgorithmIdentifier(reader, alg));
}

INSTANTIATE_TEST_SUITE_P(pkixder_DigestAlgorithmIdentifier_Invalid,
                        pkixder_DigestAlgorithmIdentifier_Invalid,
                        testing::ValuesIn(INVALID_DIGEST_ALGORITHM_TEST_INFO));

struct ValidSignatureAlgorithmIdentifierValueTestInfo
{
  PublicKeyAlgorithm publicKeyAlg;
  DigestAlgorithm digestAlg;
  uint8_t der[MAX_ALGORITHM_OID_DER_LENGTH];
  size_t derLength;
  bool explicitNullAllowed;
};

static const ValidSignatureAlgorithmIdentifierValueTestInfo
  VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] =
{
  // ECDSA
  { PublicKeyAlgorithm::ECDSA,
    DigestAlgorithm::sha512,
    { 0x06, 0x08,
      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04 },
    10,
    true,
  },
  { PublicKeyAlgorithm::ECDSA,
    DigestAlgorithm::sha384,
    { 0x06, 0x08,
      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03 },
    10,
    true,
  },
  { PublicKeyAlgorithm::ECDSA,
    DigestAlgorithm::sha256,
    { 0x06, 0x08,
      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02 },
    10,
    true,
  },
  { PublicKeyAlgorithm::ECDSA,
    DigestAlgorithm::sha1,
    { 0x06, 0x07,
      0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01 },
    9,
    true,
  },

  // RSA PKCS#1 1.5
  { PublicKeyAlgorithm::RSA_PKCS1,
    DigestAlgorithm::sha512,
    { 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d },
    11,
    true,
  },
  { PublicKeyAlgorithm::RSA_PKCS1,
    DigestAlgorithm::sha384,
    { 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c },
    11,
    true,
  },
  { PublicKeyAlgorithm::RSA_PKCS1,
    DigestAlgorithm::sha256,
    { 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b },
    11,
    true,
  },
  { PublicKeyAlgorithm::RSA_PKCS1,
    DigestAlgorithm::sha1,
    // IETF Standard OID
    { 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05 },
    11,
    true,
  },
  { PublicKeyAlgorithm::RSA_PKCS1,
    DigestAlgorithm::sha1,
    // Legacy OIW OID (bug 1042479)
    { 0x06, 0x05,
      0x2b, 0x0e, 0x03, 0x02, 0x1d },
    7,
    true,
  },

  // RSA-PSS
  { PublicKeyAlgorithm::RSA_PSS,
    DigestAlgorithm::sha256,
    { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
      0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
      0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06,
      0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
      0xa2, 0x03, 0x02, 0x01, 0x20  },
    65,
    false,
  },

  { PublicKeyAlgorithm::RSA_PSS,
    DigestAlgorithm::sha384,
    { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
      0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
      0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06,
      0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
      0xa2, 0x03, 0x02, 0x01, 0x30 },
    65,
    false,
  },

  { PublicKeyAlgorithm::RSA_PSS,
    DigestAlgorithm::sha512,
    { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
      0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
      0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06,
      0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00,
      0xa2, 0x03, 0x02, 0x01, 0x40 },
    65,
    false,
  },
};

class pkixder_SignatureAlgorithmIdentifierValue_Valid
  : public ::testing::Test
  , public ::testing::WithParamInterface<
             ValidSignatureAlgorithmIdentifierValueTestInfo>
{
};

TEST_P(pkixder_SignatureAlgorithmIdentifierValue_Valid, Valid)
{
  const ValidSignatureAlgorithmIdentifierValueTestInfo& param(GetParam());

  {
    Input input;
    ASSERT_EQ(Success, input.Init(param.der, param.derLength));
    Reader reader(input);
    PublicKeyAlgorithm publicKeyAlg;
    DigestAlgorithm digestAlg;
    ASSERT_EQ(Success,
              SignatureAlgorithmIdentifierValue(reader, publicKeyAlg,
                                                digestAlg));
    ASSERT_EQ(param.publicKeyAlg, publicKeyAlg);
    ASSERT_EQ(param.digestAlg, digestAlg);
    ASSERT_EQ(Success, End(reader));
  }

  uint8_t derWithNullParam[MAX_ALGORITHM_OID_DER_LENGTH + 2];
  memcpy(derWithNullParam, param.der, param.derLength);
  derWithNullParam[param.derLength] = 0x05; // NULL tag
  derWithNullParam[param.derLength + 1] = 0x00; // length zero

  Input input;
  ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
  Reader reader(input);
  PublicKeyAlgorithm publicKeyAlg;
  DigestAlgorithm digestAlg;
  ASSERT_EQ(param.explicitNullAllowed
              ? Success
              : Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
            SignatureAlgorithmIdentifierValue(reader, publicKeyAlg,
                                              digestAlg));
  if (param.explicitNullAllowed) {
    ASSERT_EQ(param.publicKeyAlg, publicKeyAlg);
    ASSERT_EQ(param.digestAlg, digestAlg);
    ASSERT_EQ(Success, End(reader));
  }
}

INSTANTIATE_TEST_SUITE_P(
  pkixder_SignatureAlgorithmIdentifierValue_Valid,
  pkixder_SignatureAlgorithmIdentifierValue_Valid,
  testing::ValuesIn(VALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO));

static const InvalidAlgorithmIdentifierTestInfo
  INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO[] =
{
  // id-dsa-with-sha256 (2.16.840.1.101.3.4.3.2)
  { { 0x06, 0x09,
      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x02 },
    11,
  },

  // id-dsa-with-sha1 (1.2.840.10040.4.3)
  { { 0x06, 0x07,
      0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x03 },
    9,
  },

  // RSA-with-MD5 (1.2.840.113549.1.1.4)
  { { 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04 },
    11,
  },

  // id-sha256 (2.16.840.1.101.3.4.2.1). It is invalid because SHA-256 is not
  // a signature algorithm.
  { { 0x06, 0x09,
      0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 },
    11,
  },

  // RSA-PSS with SHA-256, MGF-1 with SHA-256, and a salt length of 48 bytes
  { { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
      0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
      0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06,
      0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
      0xa2, 0x03, 0x02, 0x01, 0x30 },
    65,
  },

  // RSA-PSS with SHA-512, MGF-1 with SHA-256, and a salt length of 32 bytes
  { { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
      0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
      0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09,
      0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06,
      0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
      0xa2, 0x03, 0x02, 0x01, 0x20 },
    65,
  },

  // RSA-PSS with omitted parameters
  { { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a },
    11,
  },

  // RSA-PSS with NULL parameters
  { { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a,
      0x05, 0x00 },
    13,
  },
};

class pkixder_SignatureAlgorithmIdentifier_Invalid
  : public ::testing::Test
  , public ::testing::WithParamInterface<InvalidAlgorithmIdentifierTestInfo>
{
};

TEST_P(pkixder_SignatureAlgorithmIdentifier_Invalid, Invalid)
{
  const InvalidAlgorithmIdentifierTestInfo& param(GetParam());
  Input input;
  ASSERT_EQ(Success, input.Init(param.der, param.derLength));
  Reader reader(input);
  der::PublicKeyAlgorithm publicKeyAlg;
  DigestAlgorithm digestAlg;
  ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
            SignatureAlgorithmIdentifierValue(reader, publicKeyAlg, digestAlg));
}

INSTANTIATE_TEST_SUITE_P(
  pkixder_SignatureAlgorithmIdentifier_Invalid,
  pkixder_SignatureAlgorithmIdentifier_Invalid,
  testing::ValuesIn(INVALID_SIGNATURE_ALGORITHM_VALUE_TEST_INFO));

struct EncodedECDSASignatureValidParams {
  std::vector<uint8_t> signature;
  std::vector<uint8_t> rExpected;
  std::vector<uint8_t> sExpected;
};

::std::ostream& operator<<(::std::ostream& os, const EncodedECDSASignatureValidParams&)
{
  return os << "TODO (bug 1318770)";
}

static const EncodedECDSASignatureValidParams
  ENCODEDECDSASIGNATURE_VALID_PARAMS[] =
{
  {
    { 0x30, 0x07, // SEQUENCE
        0x02, 0x01, 0x01, // INTEGER (0x01)
        0x02, 0x02, 0x05, 0x06 }, // INTEGER ([0x05, 0x06])
    { 0x01 },
    { 0x05, 0x06 },
  },
  {
    { 0x30, 0x08, // SEQUENCE
        0x02, 0x03, 0x00, 0xb7, 0x0a, // INTEGER ([0xb7, 0x0a]) highest bit set
        0x02, 0x01, 0x02 }, // INTEGER (0x02)
    { 0xb7, 0x0a },
    { 0x02 },
  },
  {
    { 0x30, 0x09, // SEQUENCE
        0x02, 0x03, 0x23, 0x00, 0x55, // INTEGER ([0x23, 0x00, 0x55])
        0x02, 0x02, 0x00, 0xf0 }, // INTEGER (0xf0) highest bit set
    { 0x23, 0x00, 0x55 },
    { 0xf0 },
  },
  {
    { 0x30, 0x09, // SEQUENCE
        0x02, 0x03, 0x00, 0x93, 0x10, // INTEGER ([0x93, 0xl0]) highest bit set
        0x02, 0x02, 0x00, 0xcf }, // INTEGER (0xcf) highest bit set
    { 0x93, 0x10, },
    { 0xcf },
  },
};

class pkixder_ECDSASigValue_valid
  : public ::testing::Test
  , public ::testing::WithParamInterface<EncodedECDSASignatureValidParams>
{
};


TEST_P(pkixder_ECDSASigValue_valid, pkixder_ECDSASigValue_valid)
{
  const EncodedECDSASignatureValidParams& params(GetParam());

  Input signature;
  ASSERT_EQ(Success,
            signature.Init(params.signature.data(), params.signature.size()));
  Input r;
  Input s;
  ASSERT_EQ(Success, ECDSASigValue(signature, r, s));

  Input rExpected;
  ASSERT_EQ(Success,
            rExpected.Init(params.rExpected.data(), params.rExpected.size()));
  ASSERT_TRUE(InputsAreEqual(r, rExpected));

  Input sExpected;
  ASSERT_EQ(Success,
            sExpected.Init(params.sExpected.data(), params.sExpected.size()));
  ASSERT_TRUE(InputsAreEqual(s, sExpected));
}

INSTANTIATE_TEST_SUITE_P(pkixder_ECDSASigValue_valid,
    pkixder_ECDSASigValue_valid,
    testing::ValuesIn(ENCODEDECDSASIGNATURE_VALID_PARAMS));

struct EncodedECDSASignatureInvalidParams {
  std::vector<uint8_t> signature;
  Result expectedResult;
};

::std::ostream& operator<<(::std::ostream& os, const EncodedECDSASignatureInvalidParams&)
{
  return os << "TODO (bug 1318770)";
}

static const EncodedECDSASignatureInvalidParams
  ENCODEDECDSASIGNATURE_INVALID_PARAMS[] =
{
  {
    { 0x05, 0x00 }, // not a SEQUENCE
    Result::ERROR_BAD_DER
  },
  {
    { 0x30, 0x00 }, // empty SEQUENCE
    Result::ERROR_BAD_DER
  },
  {
    { 0x30, 0x06,
        0x05, 0x01, 0x01, // NULL, not INTEGER
        0x02, 0x01, 0x01 },
    Result::ERROR_BAD_DER
  },
  {
    { 0x30, 0x08,
        0x02, 0x01, 0x01,
        0x02, 0x01, 0x01,
        0x05, 0x00 }, // trailing data in SEQUENCE
    Result::ERROR_BAD_DER
  },
  { { 0x30, 0x06,
        0x02, 0x01, 0x01,
        0x02, 0x01, 0x01,
      0x05, 0x00 }, // trailing data after SEQUENCE
    Result::ERROR_BAD_DER
  },
  {
    { 0x30, 0x07,
        0x02, 0x01, 0x00, // not a positive INTEGER
        0x02, 0x02, 0x0f, 0x02 },
    Result::ERROR_INVALID_INTEGER_ENCODING
  },
  {
    { 0x30, 0x08,
        0x02, 0x02, 0x00, 0x01, // unnecessary zero padding
        0x02, 0x02, 0x0f, 0x02 },
    Result::ERROR_INVALID_INTEGER_ENCODING
  },
  {
    { 0x30, 0x07,
        0x02, 0x01, 0x01,
        0x02, 0x02, 0xff, 0x02 }, // negative INTEGER
    Result::ERROR_INVALID_INTEGER_ENCODING
  },
  {
    { 0x30, 0x06,
        0x02, 0x01, 0x01,
        0x02, 0x01, 0xf0 }, // negative INTEGER
    Result::ERROR_INVALID_INTEGER_ENCODING
  },
};

class pkixder_ECDSASigValue_invalid
  : public ::testing::Test
  , public ::testing::WithParamInterface<EncodedECDSASignatureInvalidParams>
{
};


TEST_P(pkixder_ECDSASigValue_invalid, pkixder_ECDSASigValue_invalid)
{
  const EncodedECDSASignatureInvalidParams& params(GetParam());

  Input signature;
  ASSERT_EQ(Success,
            signature.Init(params.signature.data(), params.signature.size()));
  Input r;
  Input s;
  ASSERT_EQ(params.expectedResult, ECDSASigValue(signature, r, s));
}

INSTANTIATE_TEST_SUITE_P(
  pkixder_ECDSASigValue_invalid, pkixder_ECDSASigValue_invalid,
  testing::ValuesIn(ENCODEDECDSASIGNATURE_INVALID_PARAMS));
