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