/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */

#include "gtest/gtest.h"

#include "cert.h"
#include "certdb.h"
#include "certt.h"
#include "nss_scoped_ptrs.h"
#include "prerror.h"
#include "secerr.h"

extern "C" SECStatus __CERT_AddTempCertToPerm(CERTCertificate* cert,
                                              char* nickname,
                                              CERTCertTrust* trust);

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

TEST_F(DecodeCertsTest, EmptyCertPackage) {
  // This represents a PKCS#7 ContentInfo with a contentType of
  // '2.16.840.1.113730.2.5' (Netscape data-type cert-sequence) and a content
  // consisting of an empty SEQUENCE. This is valid ASN.1, but it contains no
  // certificates, so CERT_DecodeCertFromPackage should just return a null
  // pointer.
  unsigned char emptyCertPackage[] = {0x30, 0x0f, 0x06, 0x09, 0x60, 0x86,
                                      0x48, 0x01, 0x86, 0xf8, 0x42, 0x02,
                                      0x05, 0xa0, 0x02, 0x30, 0x00};
  EXPECT_EQ(nullptr, CERT_DecodeCertFromPackage(
                         reinterpret_cast<char*>(emptyCertPackage),
                         sizeof(emptyCertPackage)));
  EXPECT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
}

TEST_F(DecodeCertsTest, EmptySignedData) {
  // This represents a PKCS#7 ContentInfo of contentType
  // 1.2.840.113549.1.7.2 (signedData) with missing content.
  unsigned char emptySignedData[] = {0x30, 0x80, 0x06, 0x09, 0x2a, 0x86,
                                     0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
                                     0x02, 0x00, 0x00, 0x05, 0x00};

  EXPECT_EQ(nullptr,
            CERT_DecodeCertFromPackage(reinterpret_cast<char*>(emptySignedData),
                                       sizeof(emptySignedData)));
  EXPECT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
}

// Generated with pycert, but the details are unimportant. This can just be any
// unique certificate. In this case, the specification used was:
// issuer:test temp to perm cert
// subject:test temp to perm cert
// issuerKey:secp256r1
// subjectKey:secp256r1
// serialNumber:1
uint8_t kTestTempToPermCertDER[] = {
    0x30, 0x82, 0x01, 0x37, 0x30, 0x81, 0xdc, 0xa0, 0x03, 0x02, 0x01, 0x02,
    0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d,
    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x74, 0x65, 0x73, 0x74, 0x20,
    0x74, 0x65, 0x6d, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x6d,
    0x20, 0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0f, 0x32, 0x30, 0x32,
    0x34, 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
    0x18, 0x0f, 0x32, 0x30, 0x32, 0x37, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30,
    0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d, 0x06,
    0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x74, 0x65, 0x73, 0x74, 0x20, 0x74,
    0x65, 0x6d, 0x70, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x20,
    0x63, 0x65, 0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61,
    0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec,
    0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79,
    0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11,
    0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99,
    0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30,
    0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
    0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5c, 0x75, 0x51,
    0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06,
    0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb,
    0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x20, 0x43, 0xee, 0xef, 0x45, 0x3d,
    0xbb, 0xf3, 0x3c, 0x61, 0x9a, 0xbb, 0x95, 0x89, 0xb4, 0x23, 0x3c, 0xc7,
    0x1e, 0x39, 0x01, 0x74, 0x9e, 0xef, 0x04, 0x44, 0x86, 0x8c, 0xc9, 0x0f,
    0x8b, 0x2d, 0x0d};

TEST_F(DecodeCertsTest, AddTempCertToPerm) {
  SECItem certDER = {siBuffer, kTestTempToPermCertDER,
                     sizeof(kTestTempToPermCertDER)};
  ScopedCERTCertificate cert1(CERT_NewTempCertificate(
      CERT_GetDefaultCertDB(), &certDER, nullptr, PR_TRUE, PR_TRUE));
  EXPECT_NE(cert1.get(), nullptr);
  CERTCertTrust trust = {0};
  char nickname1[] = "test temp to perm cert 1";
  SECStatus rv = __CERT_AddTempCertToPerm(cert1.get(), nickname1, &trust);
  EXPECT_EQ(rv, SECSuccess);

  ScopedCERTCertificate cert2(CERT_NewTempCertificate(
      CERT_GetDefaultCertDB(), &certDER, nullptr, PR_TRUE, PR_TRUE));
  EXPECT_NE(cert2.get(), cert1.get());
  char nickname2[] = "test temp to perm cert 2";
  rv = __CERT_AddTempCertToPerm(cert2.get(), nickname2, &trust);
  EXPECT_EQ(rv, SECSuccess);
}

// Generated with pycert, but the details are unimportant. This can just be any
// unique certificate. In this case, the specification used was:
// issuer:test import cert
// subject:test import cert
// issuerKey:secp256r1
// subjectKey:secp256r1
// serialNumber:1
uint8_t kTestImportCertDER[] = {
    0x30, 0x82, 0x01, 0x2c, 0x30, 0x81, 0xd0, 0xa0, 0x03, 0x02, 0x01, 0x02,
    0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
    0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x1b, 0x31, 0x19, 0x30, 0x17,
    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x74, 0x65, 0x73, 0x74, 0x20,
    0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x30,
    0x22, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x34, 0x31, 0x31, 0x32, 0x37, 0x30,
    0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x37,
    0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
    0x1b, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10,
    0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20,
    0x63, 0x65, 0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
    0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61,
    0xe0, 0xf8, 0xf9, 0xb1, 0xa6, 0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec,
    0x05, 0x0b, 0x42, 0x3e, 0x3c, 0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79,
    0x4b, 0x45, 0x5c, 0x2a, 0x69, 0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11,
    0x9d, 0x07, 0x06, 0xe0, 0x0e, 0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99,
    0x1b, 0x7b, 0x2d, 0x07, 0xa3, 0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0, 0x30,
    0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
    0x05, 0x00, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x5c, 0x75, 0x51,
    0x9f, 0x13, 0x11, 0x50, 0xcd, 0x5d, 0x8a, 0xde, 0x20, 0xa3, 0xbc, 0x06,
    0x30, 0x91, 0xff, 0xb2, 0x73, 0x75, 0x5f, 0x31, 0x64, 0xec, 0xfd, 0xcb,
    0x42, 0x80, 0x0a, 0x70, 0xe6, 0x02, 0x21, 0x00, 0xe9, 0x58, 0x16, 0x07,
    0xbf, 0x0b, 0xdc, 0x64, 0x35, 0x7a, 0x92, 0x51, 0xb2, 0xee, 0x77, 0x22,
    0xd4, 0xec, 0x98, 0xb6, 0x35, 0x96, 0xa6, 0x5b, 0x96, 0xbe, 0x73, 0x1a,
    0xa3, 0xa4, 0xfe, 0x5c};

TEST_F(DecodeCertsTest, ImportCert) {
  SECItem certDER = {siBuffer, kTestImportCertDER, sizeof(kTestImportCertDER)};
  ScopedCERTCertificate cert1(CERT_NewTempCertificate(
      CERT_GetDefaultCertDB(), &certDER, nullptr, PR_TRUE, PR_TRUE));
  EXPECT_NE(cert1.get(), nullptr);
  char nickname1[] = "test import cert 1";
  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
  SECStatus rv = PK11_ImportCert(slot.get(), cert1.get(), CK_INVALID_HANDLE,
                                 nickname1, PR_TRUE);
  EXPECT_EQ(rv, SECSuccess);

  ScopedCERTCertificate cert2(CERT_NewTempCertificate(
      CERT_GetDefaultCertDB(), &certDER, nullptr, PR_TRUE, PR_TRUE));
  EXPECT_NE(cert2.get(), cert1.get());
  char nickname2[] = "test import cert 2";
  rv = PK11_ImportCert(slot.get(), cert2.get(), CK_INVALID_HANDLE, nickname2,
                       PR_TRUE);
  EXPECT_EQ(rv, SECSuccess);
}
