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"
10 #include <keyhi.h> // SECKEY_DestroyPrivateKey
11 #include <keythi.h> // SECKEYPrivateKey
12 #include <pk11pub.h> // PK11_FindKeyByAnyCert
13 #include <seccomon.h> // SECItem
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
;
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
) {
33 return alternative_text
;
35 std::string s
= nss_text
;
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
,
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
),
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
;
94 namespace x509_certificate_model
{
96 using net::X509Certificate
;
99 string
GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle
) {
100 string name
= ProcessIDN(
101 Stringize(CERT_GetCommonName(&cert_handle
->subject
), std::string()));
104 return GetNickname(cert_handle
);
107 string
GetNickname(X509Certificate::OSCertHandle cert_handle
) {
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);
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
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
) {
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),
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
),
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
);
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(
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(
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
);
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
) {
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));
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
]) !=
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());
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
,
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