1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/cert/x509_util_ios.h"
6
7#include <cert.h>
8#include <CommonCrypto/CommonDigest.h>
9#include <nss.h>
10#include <prtypes.h>
11
12#include "base/mac/scoped_cftyperef.h"
13#include "crypto/nss_util.h"
14#include "net/cert/x509_certificate.h"
15#include "net/cert/x509_util_nss.h"
16
17using base::ScopedCFTypeRef;
18
19namespace net {
20namespace x509_util_ios {
21
22namespace {
23
24// Creates an NSS certificate handle from |data|, which is |length| bytes in
25// size.
26CERTCertificate* CreateNSSCertHandleFromBytes(const char* data,
27                                              int length) {
28  if (length < 0)
29    return NULL;
30
31  crypto::EnsureNSSInit();
32
33  if (!NSS_IsInitialized())
34    return NULL;
35
36  SECItem der_cert;
37  der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
38  der_cert.len  = length;
39  der_cert.type = siDERCertBuffer;
40
41  // Parse into a certificate structure.
42  return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &der_cert, NULL,
43                                 PR_FALSE, PR_TRUE);
44}
45
46}  // namespace
47
48CERTCertificate* CreateNSSCertHandleFromOSHandle(
49    SecCertificateRef cert_handle) {
50  ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle));
51  return CreateNSSCertHandleFromBytes(
52      reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)),
53      CFDataGetLength(cert_data));
54}
55
56SecCertificateRef CreateOSCertHandleFromNSSHandle(
57    CERTCertificate* nss_cert_handle) {
58  return X509Certificate::CreateOSCertHandleFromBytes(
59      reinterpret_cast<const char*>(nss_cert_handle->derCert.data),
60      nss_cert_handle->derCert.len);
61}
62
63X509Certificate* CreateCertFromNSSHandles(
64    CERTCertificate* cert_handle,
65    const std::vector<CERTCertificate*>& intermediates) {
66  ScopedCFTypeRef<SecCertificateRef> os_server_cert(
67      CreateOSCertHandleFromNSSHandle(cert_handle));
68  if (!os_server_cert)
69    return NULL;
70  std::vector<SecCertificateRef> os_intermediates;
71  for (size_t i = 0; i < intermediates.size(); ++i) {
72    SecCertificateRef intermediate =
73        CreateOSCertHandleFromNSSHandle(intermediates[i]);
74    if (!intermediate)
75      break;
76    os_intermediates.push_back(intermediate);
77  }
78
79  X509Certificate* cert = NULL;
80  if (intermediates.size() == os_intermediates.size()) {
81    cert = X509Certificate::CreateFromHandle(os_server_cert,
82                                             os_intermediates);
83  }
84
85  for (size_t i = 0; i < os_intermediates.size(); ++i)
86    CFRelease(os_intermediates[i]);
87  return cert;
88}
89
90SHA1HashValue CalculateFingerprintNSS(CERTCertificate* cert) {
91  DCHECK(cert->derCert.data);
92  DCHECK_NE(0U, cert->derCert.len);
93  SHA1HashValue sha1;
94  memset(sha1.data, 0, sizeof(sha1.data));
95  CC_SHA1(cert->derCert.data, cert->derCert.len, sha1.data);
96  return sha1;
97}
98
99// NSSCertificate implementation.
100
101NSSCertificate::NSSCertificate(SecCertificateRef cert_handle) {
102  nss_cert_handle_ = CreateNSSCertHandleFromOSHandle(cert_handle);
103  DLOG_IF(INFO, cert_handle && !nss_cert_handle_)
104      << "Could not convert SecCertificateRef to CERTCertificate*";
105}
106
107NSSCertificate::~NSSCertificate() {
108  CERT_DestroyCertificate(nss_cert_handle_);
109}
110
111CERTCertificate* NSSCertificate::cert_handle() const {
112  return nss_cert_handle_;
113}
114
115// NSSCertChain implementation
116
117NSSCertChain::NSSCertChain(X509Certificate* certificate) {
118  DCHECK(certificate);
119  certs_.push_back(CreateNSSCertHandleFromOSHandle(
120      certificate->os_cert_handle()));
121  const X509Certificate::OSCertHandles& cert_intermediates =
122      certificate->GetIntermediateCertificates();
123  for (size_t i = 0; i < cert_intermediates.size(); ++i)
124    certs_.push_back(CreateNSSCertHandleFromOSHandle(cert_intermediates[i]));
125}
126
127NSSCertChain::~NSSCertChain() {
128  for (size_t i = 0; i < certs_.size(); ++i)
129    CERT_DestroyCertificate(certs_[i]);
130}
131
132CERTCertificate* NSSCertChain::cert_handle() const {
133  return certs_.empty() ? NULL : certs_.front();
134}
135
136const std::vector<CERTCertificate*>& NSSCertChain::cert_chain() const {
137  return certs_;
138}
139
140}  // namespace x509_util_ios
141}  // namespace net
142