15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util.h"
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_nss.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cert.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secoid.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/ec_private_key.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/scoped_nss_types.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/signature_verifier.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CERTCertificate* CreateNSSCertHandleFromBytes(const char* data, size_t length) {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem der_cert;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  der_cert.len  = length;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  der_cert.type = siDERCertBuffer;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse into a certificate structure.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 PR_FALSE, PR_TRUE);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_WIN) && !defined(OS_MACOSX)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void VerifyCertificateSignature(const std::string& der_cert,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::vector<uint8>& der_spki) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTSignedData sd;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&sd, 0, sizeof(sd));
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem der_cert_item = {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siDERCertBuffer,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(const_cast<char*>(der_cert.data())),
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static_cast<unsigned int>(der_cert.size())
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SEC_ASN1DecodeItem(arena.get(), &sd,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    SEC_ASN1_GET(CERT_SignedDataTemplate),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &der_cert_item);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SECSuccess, rv);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The CERTSignedData.signatureAlgorithm is decoded, but SignatureVerifier
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // wants the DER encoded form, so re-encode it again.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem* signature_algorithm = SEC_ASN1EncodeItem(
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arena.get(),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &sd.signatureAlgorithm,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(signature_algorithm);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  crypto::SignatureVerifier verifier;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ok = verifier.VerifyInit(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signature_algorithm->data,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      signature_algorithm->len,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sd.signature.data,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sd.signature.len / 8,  // Signature is a BIT STRING, convert to bytes.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &der_spki[0],
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      der_spki.size());
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(ok);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  verifier.VerifyUpdate(sd.data.data,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        sd.data.len);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = verifier.VerifyFinal();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(ok);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // !defined(OS_WIN) && !defined(OS_MACOSX)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VerifyChannelID(const std::string& domain,
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                     const std::string& der_cert) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Origin Bound Cert OID.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char oid_string[] = "1.3.6.1.4.1.11129.2.1.6";
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create object neccessary for extension lookup call.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem extension_object = {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siAsciiString,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (unsigned char*)domain.data(),
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static_cast<unsigned int>(domain.size())
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // IA5Encode and arena allocate SECItem.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem* expected = SEC_ASN1EncodeItem(arena,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         NULL,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &extension_object,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         SEC_ASN1_GET(SEC_IA5StringTemplate));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NE(static_cast<SECItem*>(NULL), expected);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create OID SECItem.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem ob_cert_oid = { siDEROID, NULL, 0 };
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus ok = SEC_StringToOID(arena, &ob_cert_oid,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 oid_string, 0);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SECSuccess, ok);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidTag ob_cert_oid_tag = SECOID_FindOIDTag(&ob_cert_oid);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NE(SEC_OID_UNKNOWN, ob_cert_oid_tag);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This test is run on Mac and Win where X509Certificate::os_cert_handle isn't
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an NSS type, so we have to manually create a NSS certificate object so we
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // can use CERT_FindCertExtension.  We also check the subject and validity
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // times using NSS since X509Certificate will fail with EC certs on OSX 10.5
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (http://crbug.com/101231).
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTCertificate* nss_cert = CreateNSSCertHandleFromBytes(
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      der_cert.data(), der_cert.size());
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* common_name = CERT_GetCommonName(&nss_cert->subject);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(common_name);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_STREQ("anonymous.invalid", common_name);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PORT_Free(common_name);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SECSuccess, CERT_CertTimesValid(nss_cert));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lookup Origin Bound Cert extension in generated cert.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem actual = { siBuffer, NULL, 0 };
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ok = CERT_FindCertExtension(nss_cert,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              ob_cert_oid_tag,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              &actual);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERT_DestroyCertificate(nss_cert);
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_EQ(SECSuccess, ok);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Compare expected and actual extension values.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PRBool result = SECITEM_ItemsAreEqual(expected, &actual);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(result);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do Cleanup.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECITEM_FreeItem(&actual, PR_FALSE);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PORT_FreeArena(arena, PR_FALSE);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// This test creates a domain-bound cert and an EC private key and
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// then verifies the content of the certificate.
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST(X509UtilNSSTest, CreateKeyAndChannelIDEC) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a sample ASCII weborigin.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string domain = "weborigin.com";
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  scoped_ptr<crypto::ECPrivateKey> private_key;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string der_cert;
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_TRUE(x509_util::CreateKeyAndChannelIDEC(
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      domain, 1,
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      now + base::TimeDelta::FromDays(1),
1570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      &private_key,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &der_cert));
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  VerifyChannelID(domain, der_cert);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_WIN) && !defined(OS_MACOSX)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // signature_verifier_win and signature_verifier_mac can't handle EC certs.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<uint8> spki;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(private_key->ExportPublicKey(&spki));
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyCertificateSignature(der_cert, spki);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
171