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