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) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/ec_private_key.h" 78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "crypto/openssl_util.h" 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "crypto/scoped_openssl_types.h" 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_util_openssl.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace { 168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdochtypedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; 18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Verify that a given certificate was signed with the private key corresponding 208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// to a given public key. 218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// |der_cert| is the DER-encoded X.509 certificate. 228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// |der_spki| is the DER-encoded public key of the signer. 238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void VerifyCertificateSignature(const std::string& der_cert, 248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const std::vector<uint8>& der_spki) { 258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const unsigned char* cert_data = 268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) reinterpret_cast<const unsigned char*>(der_cert.data()); 278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int cert_data_len = static_cast<int>(der_cert.size()); 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ScopedX509 cert(d2i_X509(NULL, &cert_data, cert_data_len)); 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(cert.get()); 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // NOTE: SignatureVerifier wants the DER-encoded ASN.1 AlgorithmIdentifier 328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // but there is no OpenSSL API to extract it from an X509 object (!?) 338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Use X509_verify() directly instead, which takes an EVP_PKEY. 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const unsigned char* pub_key_data = &der_spki.front(); 358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int pub_key_len = static_cast<int>(der_spki.size()); 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch crypto::ScopedEVP_PKEY pub_key(d2i_PUBKEY(NULL, &pub_key_data, pub_key_len)); 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(pub_key.get()); 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // NOTE: X509_verify() returns 1 in case of succes, 0 or -1 on error. 408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) EXPECT_EQ(1, X509_verify(cert.get(), pub_key.get())); 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Verify the attributes of a domain-bound certificate. 448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// |domain| is the bound domain name. 458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// |der_cert| is the DER-encoded X.509 certificate. 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VerifyChannelID(const std::string& domain, 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::string& der_cert) { 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Origin Bound Cert OID. 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) static const char oid_string[] = "1.3.6.1.4.1.11129.2.1.6"; 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch crypto::ScopedOpenSSL<ASN1_OBJECT, ASN1_OBJECT_free>::Type oid_obj( 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) OBJ_txt2obj(oid_string, 0)); 528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(oid_obj.get()); 538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const unsigned char* cert_data = 558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) reinterpret_cast<const unsigned char*>(der_cert.data()); 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int cert_data_len = static_cast<int>(der_cert.size()); 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ScopedX509 cert(d2i_X509(NULL, &cert_data, cert_data_len)); 588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(cert.get()); 598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Find the extension. 618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) int ext_pos = X509_get_ext_by_OBJ(cert.get(), oid_obj.get(), -1); 628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_NE(-1, ext_pos); 638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) X509_EXTENSION* ext = X509_get_ext(cert.get(), ext_pos); 648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(ext); 658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Check its value, it must be an ASN.1 IA5STRING 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Which means <tag> <length> <domain>, with: 688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // <tag> == 22 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // <length> is the domain length, a single byte for short forms. 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // <domain> are the domain characters. 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // See http://en.wikipedia.org/wiki/X.690 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASN1_STRING* value_asn1 = X509_EXTENSION_get_data(ext); 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(value_asn1); 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string value_str(reinterpret_cast<const char*>(value_asn1->data), 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) value_asn1->length); 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Check that the domain size is small enough for short form. 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_LE(domain.size(), 127U) << "Domain is too long!"; 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string value_expected; 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) value_expected.resize(2); 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) value_expected[0] = 22; 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) value_expected[1] = static_cast<char>(domain.size()); 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) value_expected += domain; 848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) EXPECT_EQ(value_expected, value_str); 868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} // namespace 898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(X509UtilOpenSSLTest, IsSupportedValidityRange) { 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Time now = base::Time::Now(); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_TRUE(x509_util::IsSupportedValidityRange(now, now)); 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(x509_util::IsSupportedValidityRange( 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) now, now - base::TimeDelta::FromSeconds(1))); 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // See x509_util_openssl.cc to see how these were computed. 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int64 kDaysFromYear0001ToUnixEpoch = 719162; 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int64 kDaysFromUnixEpochToYear10000 = 2932896 + 1; 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // When computing too_old / too_late, add one day to account for 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // possible leap seconds. 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Time too_old = base::Time::UnixEpoch() - 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromDays(kDaysFromYear0001ToUnixEpoch + 1); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Time too_late = base::Time::UnixEpoch() + 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromDays(kDaysFromUnixEpochToYear10000 + 1); 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_old, too_old)); 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_old, now)); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(x509_util::IsSupportedValidityRange(now, too_late)); 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) EXPECT_FALSE(x509_util::IsSupportedValidityRange(too_late, too_late)); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST(X509UtilOpenSSLTest, CreateChannelIDEC) { 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Create a sample ASCII weborigin. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string domain = "weborigin.com"; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Time now = base::Time::Now(); 1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<crypto::ECPrivateKey> private_key( 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) crypto::ECPrivateKey::Create()); 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string der_cert; 1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE( 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) x509_util::CreateChannelIDEC(private_key.get(), 1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) x509_util::DIGEST_SHA1, 1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) domain, 1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1, 1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) now, 1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) now + base::TimeDelta::FromDays(1), 1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &der_cert)); 1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VerifyChannelID(domain, der_cert); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // signature_verifier_win and signature_verifier_mac can't handle EC certs. 1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::vector<uint8> spki; 1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) ASSERT_TRUE(private_key->ExportPublicKey(&spki)); 1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) VerifyCertificateSignature(der_cert, spki); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 141