// Copyright (c) 2012 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/base/x509_util_ios.h" #include #include #include #include #include "base/mac/scoped_cftyperef.h" #include "crypto/nss_util.h" #include "net/base/x509_certificate.h" using base::mac::ScopedCFTypeRef; namespace net { namespace x509_util_ios { namespace { // Creates an NSS certificate handle from |data|, which is |length| bytes in // size. CERTCertificate* CreateNSSCertHandleFromBytes(const char* data, int length) { if (length < 0) return NULL; crypto::EnsureNSSInit(); if (!NSS_IsInitialized()) return NULL; SECItem der_cert; der_cert.data = reinterpret_cast(const_cast(data)); der_cert.len = length; der_cert.type = siDERCertBuffer; // Parse into a certificate structure. return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE); } } // namespace CERTCertificate* CreateNSSCertHandleFromOSHandle( SecCertificateRef cert_handle) { ScopedCFTypeRef cert_data(SecCertificateCopyData(cert_handle)); return CreateNSSCertHandleFromBytes( reinterpret_cast(CFDataGetBytePtr(cert_data)), CFDataGetLength(cert_data)); } SecCertificateRef CreateOSCertHandleFromNSSHandle( CERTCertificate* nss_cert_handle) { return X509Certificate::CreateOSCertHandleFromBytes( reinterpret_cast(nss_cert_handle->derCert.data), nss_cert_handle->derCert.len); } X509Certificate* CreateCertFromNSSHandles( CERTCertificate* cert_handle, const std::vector& intermediates) { ScopedCFTypeRef os_server_cert( CreateOSCertHandleFromNSSHandle(cert_handle)); if (!os_server_cert) return NULL; std::vector os_intermediates; for (size_t i = 0; i < intermediates.size(); ++i) { SecCertificateRef intermediate = CreateOSCertHandleFromNSSHandle(intermediates[i]); if (!intermediate) break; os_intermediates.push_back(intermediate); } X509Certificate* cert = NULL; if (intermediates.size() == os_intermediates.size()) { cert = X509Certificate::CreateFromHandle(os_server_cert, os_intermediates); } for (size_t i = 0; i < os_intermediates.size(); ++i) CFRelease(os_intermediates[i]); return cert; } SHA1HashValue CalculateFingerprintNSS(CERTCertificate* cert) { DCHECK(cert->derCert.data); DCHECK_NE(0U, cert->derCert.len); SHA1HashValue sha1; memset(sha1.data, 0, sizeof(sha1.data)); CC_SHA1(cert->derCert.data, cert->derCert.len, sha1.data); return sha1; } // NSSCertificate implementation. NSSCertificate::NSSCertificate(SecCertificateRef cert_handle) { nss_cert_handle_ = CreateNSSCertHandleFromOSHandle(cert_handle); DLOG_IF(INFO, cert_handle && !nss_cert_handle_) << "Could not convert SecCertificateRef to CERTCertificate*"; } NSSCertificate::~NSSCertificate() { CERT_DestroyCertificate(nss_cert_handle_); } CERTCertificate* NSSCertificate::cert_handle() const { return nss_cert_handle_; } // NSSCertChain implementation NSSCertChain::NSSCertChain(X509Certificate* certificate) { DCHECK(certificate); certs_.push_back(CreateNSSCertHandleFromOSHandle( certificate->os_cert_handle())); const X509Certificate::OSCertHandles& cert_intermediates = certificate->GetIntermediateCertificates(); for (size_t i = 0; i < cert_intermediates.size(); ++i) certs_.push_back(CreateNSSCertHandleFromOSHandle(cert_intermediates[i])); } NSSCertChain::~NSSCertChain() { for (size_t i = 0; i < certs_.size(); ++i) CERT_DestroyCertificate(certs_[i]); } CERTCertificate* NSSCertChain::cert_handle() const { return certs_.empty() ? NULL : certs_.front(); } } // namespace x509_util_ios } // namespace net