Suppress tabs permission warning if there is already a browsingHistory warning.
[chromium-blink-merge.git] / chrome / common / net / x509_certificate_model_nss.cc
blob3fccdc092e0d82aba8dfc1eeea0d7be1f0a23ce8
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.
5 #include "chrome/common/net/x509_certificate_model.h"
7 #include <cert.h>
8 #include <cms.h>
9 #include <hasht.h>
10 #include <keyhi.h> // SECKEY_DestroyPrivateKey
11 #include <keythi.h> // SECKEYPrivateKey
12 #include <pk11pub.h> // PK11_FindKeyByAnyCert
13 #include <seccomon.h> // SECItem
14 #include <sechash.h>
16 #include "base/logging.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
19 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
20 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
21 #include "crypto/nss_util.h"
22 #include "crypto/scoped_nss_types.h"
23 #include "net/cert/x509_certificate.h"
25 namespace psm = mozilla_security_manager;
27 namespace {
29 // Convert a char* return value from NSS into a std::string and free the NSS
30 // memory. If the arg is NULL, an empty string will be returned instead.
31 std::string Stringize(char* nss_text, const std::string& alternative_text) {
32 if (!nss_text)
33 return alternative_text;
35 std::string s = nss_text;
36 PORT_Free(nss_text);
37 return s;
40 // Hash a certificate using the given algorithm, return the result as a
41 // colon-seperated hex string. The len specified is the number of bytes
42 // required for storing the raw fingerprint.
43 // (It's a bit redundant that the caller needs to specify len in addition to the
44 // algorithm, but given the limited uses, not worth fixing.)
45 std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
46 unsigned char fingerprint[HASH_LENGTH_MAX];
48 DCHECK(NULL != cert->derCert.data);
49 DCHECK_NE(0U, cert->derCert.len);
50 DCHECK_LE(len, HASH_LENGTH_MAX);
51 memset(fingerprint, 0, len);
52 SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
53 cert->derCert.len);
54 DCHECK_EQ(rv, SECSuccess);
55 return x509_certificate_model::ProcessRawBytes(fingerprint, len);
58 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
59 return psm::GetOIDText(&algorithm_id->algorithm);
62 std::string ProcessExtension(
63 const std::string& critical_label,
64 const std::string& non_critical_label,
65 CERTCertExtension* extension) {
66 std::string criticality =
67 extension->critical.data && extension->critical.data[0] ?
68 critical_label : non_critical_label;
69 return criticality + "\n" +
70 psm::ProcessExtensionData(SECOID_FindOIDTag(&extension->id),
71 &extension->value);
74 ////////////////////////////////////////////////////////////////////////////////
75 // NSS certificate export functions.
77 struct NSSCMSMessageDeleter {
78 inline void operator()(NSSCMSMessage* x) const {
79 NSS_CMSMessage_Destroy(x);
82 typedef scoped_ptr<NSSCMSMessage, NSSCMSMessageDeleter> ScopedNSSCMSMessage;
84 struct FreeNSSCMSSignedData {
85 inline void operator()(NSSCMSSignedData* x) const {
86 NSS_CMSSignedData_Destroy(x);
89 typedef scoped_ptr<NSSCMSSignedData, FreeNSSCMSSignedData>
90 ScopedNSSCMSSignedData;
92 } // namespace
94 namespace x509_certificate_model {
96 using net::X509Certificate;
97 using std::string;
99 string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
100 string name = ProcessIDN(
101 Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
102 if (!name.empty())
103 return name;
104 return GetNickname(cert_handle);
107 string GetNickname(X509Certificate::OSCertHandle cert_handle) {
108 string name;
109 if (cert_handle->nickname) {
110 name = cert_handle->nickname;
111 // Hack copied from mozilla: Cut off text before first :, which seems to
112 // just be the token name.
113 size_t colon_pos = name.find(':');
114 if (colon_pos != string::npos)
115 name = name.substr(colon_pos + 1);
117 return name;
120 string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
121 return psm::GetCertTokenName(cert_handle);
124 string GetVersion(X509Certificate::OSCertHandle cert_handle) {
125 // If the version field is omitted from the certificate, the default
126 // value is v1(0).
127 unsigned long version = 0;
128 if (cert_handle->version.len == 0 ||
129 SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess) {
130 return base::UintToString(version + 1);
132 return std::string();
135 net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
136 return psm::GetCertType(cert_handle);
139 string GetEmailAddress(X509Certificate::OSCertHandle cert_handle) {
140 if (cert_handle->emailAddr)
141 return cert_handle->emailAddr;
142 return std::string();
145 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
146 std::vector<string>* usages) {
147 psm::GetCertUsageStrings(cert_handle, usages);
150 string GetKeyUsageString(X509Certificate::OSCertHandle cert_handle) {
151 SECItem key_usage;
152 key_usage.data = NULL;
153 string key_usage_str;
154 if (CERT_FindKeyUsageExtension(cert_handle, &key_usage) == SECSuccess) {
155 key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ',');
156 PORT_Free(key_usage.data);
158 return key_usage_str;
161 string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
162 const string& alternative_text) {
163 return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
164 alternative_text);
167 string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
168 const string& alternative_text) {
169 return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
172 string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
173 const string& alternative_text) {
174 return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
177 string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
178 const string& alternative_text) {
179 return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
182 string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
183 const string& alternative_text) {
184 return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
187 string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
188 const string& alternative_text) {
189 return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
190 alternative_text);
193 string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
194 const string& alternative_text) {
195 return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
198 bool GetTimes(X509Certificate::OSCertHandle cert_handle,
199 base::Time* issued, base::Time* expires) {
200 PRTime pr_issued, pr_expires;
201 if (CERT_GetCertTimes(cert_handle, &pr_issued, &pr_expires) == SECSuccess) {
202 *issued = crypto::PRTimeToBaseTime(pr_issued);
203 *expires = crypto::PRTimeToBaseTime(pr_expires);
204 return true;
206 return false;
209 string GetTitle(X509Certificate::OSCertHandle cert_handle) {
210 return psm::GetCertTitle(cert_handle);
213 string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
214 return psm::ProcessName(&cert_handle->issuer);
217 string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
218 return psm::ProcessName(&cert_handle->subject);
221 void GetEmailAddresses(X509Certificate::OSCertHandle cert_handle,
222 std::vector<string>* email_addresses) {
223 for (const char* addr = CERT_GetFirstEmailAddress(cert_handle);
224 addr; addr = CERT_GetNextEmailAddress(cert_handle, addr)) {
225 // The first email addr (from Subject) may be duplicated in Subject
226 // Alternative Name, so check subsequent addresses are not equal to the
227 // first one before adding to the list.
228 if (!email_addresses->size() || (*email_addresses)[0] != addr)
229 email_addresses->push_back(addr);
233 void GetNicknameStringsFromCertList(
234 const std::vector<scoped_refptr<X509Certificate> >& certs,
235 const string& cert_expired,
236 const string& cert_not_yet_valid,
237 std::vector<string>* nick_names) {
238 CERTCertList* cert_list = CERT_NewCertList();
239 for (size_t i = 0; i < certs.size(); ++i) {
240 CERT_AddCertToListTail(
241 cert_list,
242 CERT_DupCertificate(certs[i]->os_cert_handle()));
244 // Would like to use CERT_GetCertNicknameWithValidity on each cert
245 // individually instead of having to build a CERTCertList for this, but that
246 // function is not exported.
247 CERTCertNicknames* cert_nicknames = CERT_NicknameStringsFromCertList(
248 cert_list,
249 const_cast<char*>(cert_expired.c_str()),
250 const_cast<char*>(cert_not_yet_valid.c_str()));
251 DCHECK_EQ(cert_nicknames->numnicknames,
252 static_cast<int>(certs.size()));
254 for (int i = 0; i < cert_nicknames->numnicknames; ++i)
255 nick_names->push_back(cert_nicknames->nicknames[i]);
257 CERT_FreeNicknames(cert_nicknames);
258 CERT_DestroyCertList(cert_list);
261 void GetExtensions(
262 const string& critical_label,
263 const string& non_critical_label,
264 X509Certificate::OSCertHandle cert_handle,
265 Extensions* extensions) {
266 if (cert_handle->extensions) {
267 for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
268 Extension extension;
269 extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
270 extension.value = ProcessExtension(
271 critical_label, non_critical_label, cert_handle->extensions[i]);
272 extensions->push_back(extension);
277 string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
278 return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
281 string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
282 return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
285 void GetCertChainFromCert(X509Certificate::OSCertHandle cert_handle,
286 X509Certificate::OSCertHandles* cert_handles) {
287 CERTCertList* cert_list =
288 CERT_GetCertChainFromCert(cert_handle, PR_Now(), certUsageSSLServer);
289 CERTCertListNode* node;
290 for (node = CERT_LIST_HEAD(cert_list);
291 !CERT_LIST_END(node, cert_list);
292 node = CERT_LIST_NEXT(node)) {
293 cert_handles->push_back(CERT_DupCertificate(node->cert));
295 CERT_DestroyCertList(cert_list);
298 void DestroyCertChain(X509Certificate::OSCertHandles* cert_handles) {
299 for (X509Certificate::OSCertHandles::iterator i(cert_handles->begin());
300 i != cert_handles->end(); ++i)
301 CERT_DestroyCertificate(*i);
302 cert_handles->clear();
305 string GetDerString(X509Certificate::OSCertHandle cert_handle) {
306 return string(reinterpret_cast<const char*>(cert_handle->derCert.data),
307 cert_handle->derCert.len);
310 string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
311 size_t start, size_t end) {
312 crypto::ScopedPLArenaPool arena(PORT_NewArena(1024));
313 DCHECK(arena.get());
315 ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
316 DCHECK(message.get());
318 // First, create SignedData with the certificate only (no chain).
319 ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
320 message.get(), cert_chain[start], PR_FALSE));
321 if (!signed_data.get()) {
322 DLOG(ERROR) << "NSS_CMSSignedData_Create failed";
323 return std::string();
325 // Add the rest of the chain (if any).
326 for (size_t i = start + 1; i < end; ++i) {
327 if (NSS_CMSSignedData_AddCertificate(signed_data.get(), cert_chain[i]) !=
328 SECSuccess) {
329 DLOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
330 return std::string();
334 NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
335 if (NSS_CMSContentInfo_SetContent_SignedData(
336 message.get(), cinfo, signed_data.get()) == SECSuccess) {
337 ignore_result(signed_data.release());
338 } else {
339 DLOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
340 return std::string();
343 SECItem cert_p7 = { siBuffer, NULL, 0 };
344 NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
345 &cert_p7, arena.get(), NULL,
346 NULL, NULL, NULL, NULL,
347 NULL);
348 if (!ecx) {
349 DLOG(ERROR) << "NSS_CMSEncoder_Start failed";
350 return std::string();
353 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
354 DLOG(ERROR) << "NSS_CMSEncoder_Finish failed";
355 return std::string();
358 return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
361 string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
362 return ProcessSecAlgorithmInternal(&cert_handle->signature);
365 string ProcessSecAlgorithmSubjectPublicKey(
366 X509Certificate::OSCertHandle cert_handle) {
367 return ProcessSecAlgorithmInternal(
368 &cert_handle->subjectPublicKeyInfo.algorithm);
371 string ProcessSecAlgorithmSignatureWrap(
372 X509Certificate::OSCertHandle cert_handle) {
373 return ProcessSecAlgorithmInternal(
374 &cert_handle->signatureWrap.signatureAlgorithm);
377 string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
378 return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
381 string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
382 return ProcessRawBits(cert_handle->signatureWrap.signature.data,
383 cert_handle->signatureWrap.signature.len);
386 void RegisterDynamicOids() {
387 psm::RegisterDynamicOids();
390 } // namespace x509_certificate_model