// 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/cert/x509_util_ios.h"
#include <cert.h>
#include <CommonCrypto/CommonDigest.h>
#include <nss.h>
#include <prtypes.h>
#include "base/mac/scoped_cftyperef.h"
#include "crypto/nss_util.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util_nss.h"
using base::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<unsigned char*>(const_cast<char*>(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<CFDataRef> cert_data(SecCertificateCopyData(cert_handle));
return CreateNSSCertHandleFromBytes(
reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)),
CFDataGetLength(cert_data));
}
SecCertificateRef CreateOSCertHandleFromNSSHandle(
CERTCertificate* nss_cert_handle) {
return X509Certificate::CreateOSCertHandleFromBytes(
reinterpret_cast<const char*>(nss_cert_handle->derCert.data),
nss_cert_handle->derCert.len);
}
X509Certificate* CreateCertFromNSSHandles(
CERTCertificate* cert_handle,
const std::vector<CERTCertificate*>& intermediates) {
ScopedCFTypeRef<SecCertificateRef> os_server_cert(
CreateOSCertHandleFromNSSHandle(cert_handle));
if (!os_server_cert)
return NULL;
std::vector<SecCertificateRef> 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();
}
const std::vector<CERTCertificate*>& NSSCertChain::cert_chain() const {
return certs_;
}
} // namespace x509_util_ios
} // namespace net