OLD | NEW |
| (Empty) |
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/base/x509_certificate.h" | |
6 | |
7 #include <CommonCrypto/CommonDigest.h> | |
8 #include <Security/Security.h> | |
9 #include <vector> | |
10 | |
11 #include <cryptohi.h> | |
12 #include <cert.h> | |
13 #include <keyhi.h> | |
14 #include <nss.h> | |
15 #include <pk11pub.h> | |
16 #include <prerror.h> | |
17 #include <prtime.h> | |
18 #include <prtypes.h> | |
19 #include <secder.h> | |
20 #include <secerr.h> | |
21 #include <sslerr.h> | |
22 | |
23 #include "base/logging.h" | |
24 #include "base/mac/scoped_cftyperef.h" | |
25 #include "base/memory/scoped_ptr.h" | |
26 #include "base/pickle.h" | |
27 #include "base/time.h" | |
28 #include "crypto/nss_util.h" | |
29 #include "crypto/scoped_nss_types.h" | |
30 #include "net/base/asn1_util.h" | |
31 #include "net/base/cert_status_flags.h" | |
32 #include "net/base/cert_verify_result.h" | |
33 #include "net/base/ev_root_ca_metadata.h" | |
34 #include "net/base/net_errors.h" | |
35 #include "net/base/x509_util_ios.h" | |
36 #include "net/base/x509_util_nss.h" | |
37 | |
38 using base::mac::ScopedCFTypeRef; | |
39 | |
40 namespace net { | |
41 namespace { | |
42 // Returns true if a given |cert_handle| is actually a valid X.509 certificate | |
43 // handle. | |
44 // | |
45 // SecCertificateCreateFromData() does not always force the immediate parsing of | |
46 // the certificate, and as such, may return a SecCertificateRef for an | |
47 // invalid/unparsable certificate. Force parsing to occur to ensure that the | |
48 // SecCertificateRef is correct. On later versions where | |
49 // SecCertificateCreateFromData() immediately parses, rather than lazily, this | |
50 // call is cheap, as the subject is cached. | |
51 bool IsValidOSCertHandle(SecCertificateRef cert_handle) { | |
52 ScopedCFTypeRef<CFStringRef> sanity_check( | |
53 SecCertificateCopySubjectSummary(cert_handle)); | |
54 return sanity_check != NULL; | |
55 } | |
56 } // namespace | |
57 | |
58 void X509Certificate::Initialize() { | |
59 x509_util_ios::NSSCertificate nss_cert(cert_handle_); | |
60 CERTCertificate* cert_handle = nss_cert.cert_handle(); | |
61 if (cert_handle) { | |
62 x509_util::ParsePrincipal(&cert_handle->subject, &subject_); | |
63 x509_util::ParsePrincipal(&cert_handle->issuer, &issuer_); | |
64 x509_util::ParseDate(&cert_handle->validity.notBefore, &valid_start_); | |
65 x509_util::ParseDate(&cert_handle->validity.notAfter, &valid_expiry_); | |
66 serial_number_ = x509_util::ParseSerialNumber(cert_handle); | |
67 } | |
68 fingerprint_ = CalculateFingerprint(cert_handle_); | |
69 ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_); | |
70 } | |
71 | |
72 bool X509Certificate::IsIssuedByEncoded( | |
73 const std::vector<std::string>& valid_issuers) { | |
74 x509_util_ios::NSSCertChain nss_chain(this); | |
75 // Convert to scoped CERTName* list. | |
76 std::vector<CERTName*> issuers; | |
77 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); | |
78 if (!x509_util::GetIssuersFromEncodedList(valid_issuers, | |
79 arena.get(), | |
80 &issuers)) { | |
81 return false; | |
82 } | |
83 return x509_util::IsCertificateIssuedBy( | |
84 nss_chain.cert_chain(), issuers); | |
85 } | |
86 | |
87 // static | |
88 X509Certificate* X509Certificate::CreateSelfSigned( | |
89 crypto::RSAPrivateKey* key, | |
90 const std::string& subject, | |
91 uint32 serial_number, | |
92 base::TimeDelta valid_duration) { | |
93 DCHECK(key); | |
94 DCHECK(!subject.empty()); | |
95 NOTIMPLEMENTED(); | |
96 return NULL; | |
97 } | |
98 | |
99 void X509Certificate::GetSubjectAltName( | |
100 std::vector<std::string>* dns_names, | |
101 std::vector<std::string>* ip_addrs) const { | |
102 x509_util_ios::NSSCertificate nss_cert(cert_handle_); | |
103 CERTCertificate* cert_handle = nss_cert.cert_handle(); | |
104 if (!cert_handle) { | |
105 if (dns_names) | |
106 dns_names->clear(); | |
107 if (ip_addrs) | |
108 ip_addrs->clear(); | |
109 return; | |
110 } | |
111 x509_util::GetSubjectAltName(cert_handle, dns_names, ip_addrs); | |
112 } | |
113 | |
114 // static | |
115 bool X509Certificate::GetDEREncoded(OSCertHandle cert_handle, | |
116 std::string* encoded) { | |
117 ScopedCFTypeRef<CFDataRef> der_data(SecCertificateCopyData(cert_handle)); | |
118 if (!der_data) | |
119 return false; | |
120 encoded->assign(reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)), | |
121 CFDataGetLength(der_data)); | |
122 return true; | |
123 } | |
124 | |
125 // static | |
126 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a, | |
127 X509Certificate::OSCertHandle b) { | |
128 DCHECK(a && b); | |
129 if (a == b) | |
130 return true; | |
131 if (CFEqual(a, b)) | |
132 return true; | |
133 ScopedCFTypeRef<CFDataRef> a_data(SecCertificateCopyData(a)); | |
134 ScopedCFTypeRef<CFDataRef> b_data(SecCertificateCopyData(b)); | |
135 return a_data && b_data && | |
136 CFDataGetLength(a_data) == CFDataGetLength(b_data) && | |
137 memcmp(CFDataGetBytePtr(a_data), CFDataGetBytePtr(b_data), | |
138 CFDataGetLength(a_data)) == 0; | |
139 } | |
140 | |
141 // static | |
142 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes( | |
143 const char* data, int length) { | |
144 ScopedCFTypeRef<CFDataRef> cert_data(CFDataCreateWithBytesNoCopy( | |
145 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(data), length, | |
146 kCFAllocatorNull)); | |
147 if (!cert_data) | |
148 return NULL; | |
149 OSCertHandle cert_handle = SecCertificateCreateWithData(NULL, cert_data); | |
150 if (!cert_handle) | |
151 return NULL; | |
152 if (!IsValidOSCertHandle(cert_handle)) { | |
153 CFRelease(cert_handle); | |
154 return NULL; | |
155 } | |
156 return cert_handle; | |
157 } | |
158 | |
159 // static | |
160 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes( | |
161 const char* data, | |
162 int length, | |
163 Format format) { | |
164 return x509_util::CreateOSCertHandlesFromBytes(data, length, format); | |
165 } | |
166 | |
167 // static | |
168 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle( | |
169 OSCertHandle handle) { | |
170 if (!handle) | |
171 return NULL; | |
172 return reinterpret_cast<OSCertHandle>(const_cast<void*>(CFRetain(handle))); | |
173 } | |
174 | |
175 // static | |
176 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) { | |
177 CFRelease(cert_handle); | |
178 } | |
179 | |
180 // static | |
181 SHA1HashValue X509Certificate::CalculateFingerprint( | |
182 OSCertHandle cert) { | |
183 SHA1HashValue sha1; | |
184 memset(sha1.data, 0, sizeof(sha1.data)); | |
185 | |
186 ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert)); | |
187 if (!cert_data) | |
188 return sha1; | |
189 DCHECK(CFDataGetBytePtr(cert_data)); | |
190 DCHECK_NE(0, CFDataGetLength(cert_data)); | |
191 CC_SHA1(CFDataGetBytePtr(cert_data), CFDataGetLength(cert_data), sha1.data); | |
192 | |
193 return sha1; | |
194 } | |
195 | |
196 // static | |
197 SHA1HashValue X509Certificate::CalculateCAFingerprint( | |
198 const OSCertHandles& intermediates) { | |
199 SHA1HashValue sha1; | |
200 memset(sha1.data, 0, sizeof(sha1.data)); | |
201 | |
202 // The CC_SHA(3cc) man page says all CC_SHA1_xxx routines return 1, so | |
203 // we don't check their return values. | |
204 CC_SHA1_CTX sha1_ctx; | |
205 CC_SHA1_Init(&sha1_ctx); | |
206 for (size_t i = 0; i < intermediates.size(); ++i) { | |
207 ScopedCFTypeRef<CFDataRef> | |
208 cert_data(SecCertificateCopyData(intermediates[i])); | |
209 if (!cert_data) | |
210 return sha1; | |
211 CC_SHA1_Update(&sha1_ctx, | |
212 CFDataGetBytePtr(cert_data), | |
213 CFDataGetLength(cert_data)); | |
214 } | |
215 CC_SHA1_Final(sha1.data, &sha1_ctx); | |
216 return sha1; | |
217 } | |
218 | |
219 // static | |
220 X509Certificate::OSCertHandle | |
221 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) { | |
222 return x509_util::ReadOSCertHandleFromPickle(pickle_iter); | |
223 } | |
224 | |
225 // static | |
226 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle, | |
227 Pickle* pickle) { | |
228 ScopedCFTypeRef<CFDataRef> cert_data(SecCertificateCopyData(cert_handle)); | |
229 if (!cert_data) | |
230 return false; | |
231 | |
232 return pickle->WriteData( | |
233 reinterpret_cast<const char*>(CFDataGetBytePtr(cert_data)), | |
234 CFDataGetLength(cert_data)); | |
235 } | |
236 | |
237 // static | |
238 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle, | |
239 size_t* size_bits, | |
240 PublicKeyType* type) { | |
241 x509_util_ios::NSSCertificate nss_cert(cert_handle); | |
242 x509_util::GetPublicKeyInfo(nss_cert.cert_handle(), size_bits, type); | |
243 } | |
244 | |
245 } // namespace net | |
OLD | NEW |