// Copyright 2017 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 "net/ssl/client_cert_identity.h" #include #include "base/bind.h" #include "net/cert/x509_util.h" #include "net/ssl/ssl_private_key.h" namespace net { namespace { void IdentityOwningPrivateKeyCallback( std::unique_ptr identity, base::OnceCallback)> private_key_callback, scoped_refptr private_key) { std::move(private_key_callback).Run(std::move(private_key)); } } // namespace ClientCertIdentity::ClientCertIdentity(scoped_refptr cert) : cert_(std::move(cert)) {} ClientCertIdentity::~ClientCertIdentity() = default; // static void ClientCertIdentity::SelfOwningAcquirePrivateKey( std::unique_ptr self, base::OnceCallback)> private_key_callback) { ClientCertIdentity* self_ptr = self.get(); auto wrapped_private_key_callback = base::BindOnce(&IdentityOwningPrivateKeyCallback, std::move(self), std::move(private_key_callback)); self_ptr->AcquirePrivateKey(std::move(wrapped_private_key_callback)); } void ClientCertIdentity::SetIntermediates( std::vector> intermediates) { // Allow UTF-8 inside PrintableStrings in client certificates. See // crbug.com/770323. // TODO(mattm): Perhaps X509Certificate should have a method to clone the // X509Certificate but with different intermediates, to avoid reparsing here // (and avoid needing to match the parsing options here with where the // X509Certificate was initially created.) X509Certificate::UnsafeCreateOptions options; options.printable_string_is_utf8 = true; cert_ = X509Certificate::CreateFromBufferUnsafeOptions( bssl::UpRef(cert_->cert_buffer()), std::move(intermediates), options); // |cert_->cert_buffer()| was already successfully parsed, so this should // never fail. DCHECK(cert_); } ClientCertIdentitySorter::ClientCertIdentitySorter() : now_(base::Time::Now()) {} bool ClientCertIdentitySorter::operator()( const std::unique_ptr& a_identity, const std::unique_ptr& b_identity) const { X509Certificate* a = a_identity->certificate(); X509Certificate* b = b_identity->certificate(); DCHECK(a); DCHECK(b); // Certificates that are expired/not-yet-valid are sorted last. bool a_is_valid = now_ >= a->valid_start() && now_ <= a->valid_expiry(); bool b_is_valid = now_ >= b->valid_start() && now_ <= b->valid_expiry(); if (a_is_valid != b_is_valid) return a_is_valid && !b_is_valid; // Certificates with longer expirations appear as higher priority (less // than) certificates with shorter expirations. if (a->valid_expiry() != b->valid_expiry()) return a->valid_expiry() > b->valid_expiry(); // If the expiration dates are equivalent, certificates that were issued // more recently should be prioritized over older certificates. if (a->valid_start() != b->valid_start()) return a->valid_start() > b->valid_start(); // Otherwise, prefer client certificates with shorter chains. const auto& a_intermediates = a->intermediate_buffers(); const auto& b_intermediates = b->intermediate_buffers(); return a_intermediates.size() < b_intermediates.size(); } } // namespace net