blob: 3bc0cc84cb248e777d00d86f2c96d417c9824563 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/net/x509_certificate_model_nss.h"
#include <stddef.h>
#include "base/files/file_path.h"
#include "crypto/scoped_test_nss_db.h"
#include "net/cert/nss_cert_database.h"
#include "net/cert/scoped_nss_types.h"
#include "net/cert/x509_util_nss.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(X509CertificateModelTest, GetCertNameOrNicknameAndGetTitle) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("Test Root CA",
x509_certificate_model::GetCertNameOrNickname(cert.get()));
net::ScopedCERTCertificate punycode_cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "punycodetest.pem"));
ASSERT_TRUE(punycode_cert.get());
EXPECT_EQ("xn--wgv71a119e.com (日本語.com)",
x509_certificate_model::GetCertNameOrNickname(punycode_cert.get()));
net::ScopedCERTCertificate no_cn_cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "no_subject_common_name_cert.pem"));
ASSERT_TRUE(no_cn_cert.get());
// Temp cert has no nickname.
EXPECT_EQ("",
x509_certificate_model::GetCertNameOrNickname(no_cn_cert.get()));
EXPECT_EQ("xn--wgv71a119e.com",
x509_certificate_model::GetTitle(punycode_cert.get()));
EXPECT_EQ("E=wtc@google.com",
x509_certificate_model::GetTitle(no_cn_cert.get()));
net::ScopedCERTCertificate no_cn_cert2(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "ct-test-embedded-cert.pem"));
ASSERT_TRUE(no_cn_cert2.get());
EXPECT_EQ("L=Erw Wen,ST=Wales,O=Certificate Transparency,C=GB",
x509_certificate_model::GetTitle(no_cn_cert2.get()));
}
TEST(X509CertificateModelTest, GetExtensions) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(3U, extensions.size());
EXPECT_EQ("Certificate Basic Constraints", extensions[0].name);
EXPECT_EQ(
"critical\nIs a Certification Authority\n"
"Maximum number of intermediate CAs: unlimited",
extensions[0].value);
EXPECT_EQ("Certificate Subject Key ID", extensions[1].name);
EXPECT_EQ(
"notcrit\nKey ID: 9B 26 0B 8A 98 A9 BB 1D B9 1F 1C E3 1A 40 33 ED\n8E "
"17 88 AB",
extensions[1].value);
EXPECT_EQ("Certificate Key Usage", extensions[2].name);
EXPECT_EQ("critical\nCertificate Signer\nCRL Signer", extensions[2].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "subjectAltName_sanity_check.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(2U, extensions.size());
EXPECT_EQ("Certificate Subject Alternative Name", extensions[1].name);
EXPECT_EQ(
"notcrit\nIP Address: 127.0.0.2\nIP Address: fe80::1\nDNS Name: "
"test.example\nEmail Address: test@test.example\nOID.1.2.3.4: 0C 09 69 "
"67 6E 6F 72 65 20 6D 65\nX.500 Name: CN = 127.0.0.3\n\n",
extensions[1].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "foaf.me.chromium-test-cert.der"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(5U, extensions.size());
EXPECT_EQ("Netscape Certificate Comment", extensions[1].name);
EXPECT_EQ("notcrit\nOpenSSL Generated Certificate", extensions[1].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "2029_globalsign_com_cert.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(9U, extensions.size());
EXPECT_EQ("Certificate Subject Key ID", extensions[0].name);
EXPECT_EQ(
"notcrit\nKey ID: 59 BC D9 69 F7 B0 65 BB C8 34 C5 D2 C2 EF 17 78\nA6 "
"47 1E 8B",
extensions[0].value);
EXPECT_EQ("Certification Authority Key ID", extensions[1].name);
EXPECT_EQ(
"notcrit\nKey ID: 8A FC 14 1B 3D A3 59 67 A5 3B E1 73 92 A6 62 91\n7F "
"E4 78 30\n",
extensions[1].value);
EXPECT_EQ("Authority Information Access", extensions[2].name);
EXPECT_EQ(
"notcrit\nCA Issuers: "
"URI: http://secure.globalsign.net/cacert/SHA256extendval1.crt\n",
extensions[2].value);
EXPECT_EQ("CRL Distribution Points", extensions[3].name);
EXPECT_EQ("notcrit\nURI: http://crl.globalsign.net/SHA256ExtendVal1.crl\n",
extensions[3].value);
EXPECT_EQ("Certificate Basic Constraints", extensions[4].name);
EXPECT_EQ("notcrit\nIs not a Certification Authority\n",
extensions[4].value);
EXPECT_EQ("Certificate Key Usage", extensions[5].name);
EXPECT_EQ(
"critical\nSigning\nNon-repudiation\nKey Encipherment\n"
"Data Encipherment",
extensions[5].value);
EXPECT_EQ("Extended Key Usage", extensions[6].name);
EXPECT_EQ(
"notcrit\nTLS WWW Server Authentication (OID.1.3.6.1.5.5.7.3.1)\n"
"TLS WWW Client Authentication (OID.1.3.6.1.5.5.7.3.2)\n",
extensions[6].value);
EXPECT_EQ("Certificate Policies", extensions[7].name);
EXPECT_EQ(
"notcrit\nOID.1.3.6.1.4.1.4146.1.1:\n"
" Certification Practice Statement Pointer:"
" http://www.globalsign.net/repository/\n",
extensions[7].value);
EXPECT_EQ("Netscape Certificate Type", extensions[8].name);
EXPECT_EQ("notcrit\nSSL Client Certificate\nSSL Server Certificate",
extensions[8].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "diginotar_public_ca_2025.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(7U, extensions.size());
EXPECT_EQ("Authority Information Access", extensions[0].name);
EXPECT_EQ(
"notcrit\nOCSP Responder: "
"URI: http://validation.diginotar.nl\n",
extensions[0].value);
EXPECT_EQ("Certificate Basic Constraints", extensions[2].name);
EXPECT_EQ(
"critical\nIs a Certification Authority\n"
"Maximum number of intermediate CAs: 0",
extensions[2].value);
EXPECT_EQ("Certificate Policies", extensions[3].name);
EXPECT_EQ(
"notcrit\nOID.2.16.528.1.1001.1.1.1.1.5.2.6.4:\n"
" Certification Practice Statement Pointer:"
" http://www.diginotar.nl/cps\n"
" User Notice:\n"
" Conditions, as mentioned on our website (www.diginotar.nl), are "
"applicable to all our products and services.\n",
extensions[3].value);
}
}
TEST(X509CertificateModelTest, GetTypeCA) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(net::CA_CERT, x509_certificate_model::GetType(cert.get()));
crypto::ScopedTestNSSDB test_nssdb;
net::NSSCertDatabase db(crypto::ScopedPK11Slot(PK11_ReferenceSlot(
test_nssdb.slot())) /* public slot */,
crypto::ScopedPK11Slot(PK11_ReferenceSlot(
test_nssdb.slot())) /* private slot */);
// Test that explicitly distrusted CA certs are still returned as CA_CERT
// type. See http://crbug.com/96654.
EXPECT_TRUE(db.SetCertTrust(cert.get(), net::CA_CERT,
net::NSSCertDatabase::DISTRUSTED_SSL));
EXPECT_EQ(net::CA_CERT, x509_certificate_model::GetType(cert.get()));
}
TEST(X509CertificateModelTest, GetTypeServer) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "google.single.der"));
ASSERT_TRUE(cert.get());
// Test mozilla_security_manager::GetCertType with server certs and default
// trust. Currently this doesn't work.
// TODO(mattm): make mozilla_security_manager::GetCertType smarter so we can
// tell server certs even if they have no trust bits set.
EXPECT_EQ(net::OTHER_CERT, x509_certificate_model::GetType(cert.get()));
crypto::ScopedTestNSSDB test_nssdb;
net::NSSCertDatabase db(crypto::ScopedPK11Slot(PK11_ReferenceSlot(
test_nssdb.slot())) /* public slot */,
crypto::ScopedPK11Slot(PK11_ReferenceSlot(
test_nssdb.slot())) /* private slot */);
// Test GetCertType with server certs and explicit trust.
EXPECT_TRUE(db.SetCertTrust(cert.get(), net::SERVER_CERT,
net::NSSCertDatabase::TRUSTED_SSL));
EXPECT_EQ(net::SERVER_CERT, x509_certificate_model::GetType(cert.get()));
// Test GetCertType with server certs and explicit distrust.
EXPECT_TRUE(db.SetCertTrust(cert.get(), net::SERVER_CERT,
net::NSSCertDatabase::DISTRUSTED_SSL));
EXPECT_EQ(net::SERVER_CERT, x509_certificate_model::GetType(cert.get()));
}
// An X.509 v1 certificate with the version field omitted should get
// the default value v1.
TEST(X509CertificateModelTest, GetVersionOmitted) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "ndn.ca.crt"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("1", x509_certificate_model::GetVersion(cert.get()));
}
TEST(X509CertificateModelTest, GetCMSString) {
net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
net::GetTestCertsDirectory(), "multi-root-chain1.pem",
net::X509Certificate::FORMAT_AUTO);
{
// Write the full chain.
std::string pkcs7_string =
x509_certificate_model::GetCMSString(certs, 0, certs.size());
ASSERT_FALSE(pkcs7_string.empty());
net::ScopedCERTCertificateList decoded_certs =
net::x509_util::CreateCERTCertificateListFromBytes(
pkcs7_string.data(), pkcs7_string.size(),
net::X509Certificate::FORMAT_PKCS7);
ASSERT_EQ(certs.size(), decoded_certs.size());
// NSS sorts the certs before writing the file.
EXPECT_TRUE(net::x509_util::IsSameCertificate(certs[0].get(),
decoded_certs.back().get()));
for (size_t i = 1; i < certs.size(); ++i)
EXPECT_TRUE(net::x509_util::IsSameCertificate(
certs[i].get(), decoded_certs[i - 1].get()));
}
{
// Write only the first cert.
std::string pkcs7_string =
x509_certificate_model::GetCMSString(certs, 0, 1);
net::ScopedCERTCertificateList decoded_certs =
net::x509_util::CreateCERTCertificateListFromBytes(
pkcs7_string.data(), pkcs7_string.size(),
net::X509Certificate::FORMAT_PKCS7);
ASSERT_EQ(1U, decoded_certs.size());
EXPECT_TRUE(net::x509_util::IsSameCertificate(certs[0].get(),
decoded_certs[0].get()));
}
}
TEST(X509CertificateModelTest, ProcessSecAlgorithms) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("PKCS #1 SHA-256 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
EXPECT_EQ(
"PKCS #1 SHA-256 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
EXPECT_EQ("PKCS #1 RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
cert.get()));
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "weak_digest_md5_root.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("PKCS #1 MD5 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
EXPECT_EQ(
"PKCS #1 MD5 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
EXPECT_EQ("PKCS #1 RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
cert.get()));
}
}
TEST(X509CertificateModelTest, ProcessSubjectPublicKeyInfo) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"Modulus (2048 bits):\n"
" C6 81 1F 92 73 B6 58 85 D9 8D AC B7 20 FD C7 BF\n"
"40 B2 EA FA E5 0B 52 01 8F 9A C1 EB 7A 80 C1 F3\n"
"89 A4 3E D5 1B 61 CC B5 CF 80 B1 1A DB BB 25 E0\n"
"18 BF 92 69 26 50 CD E7 3F FF 0D 3C B4 1F 14 12\n"
"AB 67 37 DE 07 03 6C 12 74 82 36 AC C3 D4 D3 64\n"
"9F 91 ED 5B F6 A9 7A A4 9C 98 E8 65 6C 94 E1 CB\n"
"55 73 AE F8 1D 50 B0 78 E5 74 FF B1 37 2C CB 19\n"
"3D A4 8C E7 76 4E 86 5C 3F DF B3 ED 45 23 4F 54\n"
"9B 33 C6 89 5E 13 1D DD 7D 59 A5 07 34 28 86 27\n"
"1F FA 9E 53 4F 2A B6 42 AD 37 12 62 F5 72 36 B6\n"
"02 12 40 44 FE C7 9E 95 89 43 51 5E B4 6E C7 67\n"
"80 58 43 BE CC 07 28 BD 59 FF 1C 4C 8D 90 42 F4\n"
"CF FD 54 00 4F 48 72 2B E1 67 3C 84 17 68 95 BF\n"
"CA 07 7B DF 86 9D 56 E3 32 E3 70 87 B7 F8 3A F7\n"
"E3 6E 65 14 7C BB 76 B7 17 F1 42 8C 6F 2A 34 64\n"
"10 35 14 8C 85 F6 57 BF F3 5C 55 9D AD 03 10 F3\n"
"\n"
" Public Exponent (24 bits):\n"
" 01 00 01",
x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "prime256v1-ecdsa-intermediate.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"04 D5 C1 4A 32 95 95 C5 88 FA 01 FA C5 9E DC E2\n"
"99 62 EB 13 E5 35 42 B3 7A FC 46 C0 FA 29 12 C8\n"
"2D EA 30 0F D2 9A 47 97 2C 7E 89 E6 EF 49 55 06\n"
"C9 37 C7 99 56 16 B2 2B C9 7C 69 8E 10 7A DD 1F\n"
"42",
x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
}
}
TEST(X509CertificateModelTest, ProcessRawBitsSignatureWrap) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"5B 53 FF 6D D5 0A 43 A5 0F D4 7D C6 5D 88 E3 98\n"
"9D 67 EB 32 82 B3 0F F5 C1 78 F8 05 4A BF BC 21\n"
"05 EE 21 08 2C B2 15 A1 B8 B2 F6 A3 15 61 E4 C1\n"
"AD 84 A4 A7 40 0C 87 09 5F 2B 1B F9 4D 6C 92 7D\n"
"CB 7E 2B B0 01 0A ED 40 E5 4E AF 1A F1 0D EC 1D\n"
"9E 96 C7 D4 61 64 39 23 FA 5F 29 C4 2A 3A B8 ED\n"
"8A 72 50 6A AC 45 04 76 09 A8 3D 57 D7 F0 4B AE\n"
"46 B4 83 C1 14 50 2A 19 59 53 B2 4D AE FC 2F 40\n"
"49 C8 AD 4D 9D C8 22 8D 8C 01 DB 31 33 5A F4 BC\n"
"4C 9B ED D7 E3 43 D9 E8 1D 53 8B 30 D8 81 9E 72\n"
"AB 9E CE B8 F5 83 93 F2 72 DB DE CD B0 52 9A 45\n"
"4D CF E7 21 D8 CE 16 64 8F 42 AF C1 87 A8 F9 D5\n"
"E2 03 DD BA 6B 1B 7C 7D A0 38 33 61 39 B4 DD 5C\n"
"69 17 79 02 3A EC 1D 6F 5E BB 13 FB A6 82 5D 07\n"
"20 FC 86 FE 6E 8B AC E1 C2 18 A2 FE 3F 95 66 D3\n"
"69 8A 00 06 2C 56 37 34 B9 B6 31 DE 0F F6 44 39",
x509_certificate_model::ProcessRawBitsSignatureWrap(cert.get()));
}