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" + psm::ProcessExtensionData(extension
);
72 std::string
GetNickname(net::X509Certificate::OSCertHandle cert_handle
) {
74 if (cert_handle
->nickname
) {
75 name
= cert_handle
->nickname
;
76 // Hack copied from mozilla: Cut off text before first :, which seems to
77 // just be the token name.
78 size_t colon_pos
= name
.find(':');
79 if (colon_pos
!= std::string::npos
)
80 name
= name
.substr(colon_pos
+ 1);
85 ////////////////////////////////////////////////////////////////////////////////
86 // NSS certificate export functions.
88 struct NSSCMSMessageDeleter
{
89 inline void operator()(NSSCMSMessage
* x
) const {
90 NSS_CMSMessage_Destroy(x
);
93 typedef scoped_ptr
<NSSCMSMessage
, NSSCMSMessageDeleter
> ScopedNSSCMSMessage
;
95 struct FreeNSSCMSSignedData
{
96 inline void operator()(NSSCMSSignedData
* x
) const {
97 NSS_CMSSignedData_Destroy(x
);
100 typedef scoped_ptr
<NSSCMSSignedData
, FreeNSSCMSSignedData
>
101 ScopedNSSCMSSignedData
;
105 namespace x509_certificate_model
{
107 using net::X509Certificate
;
110 string
GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle
) {
111 string name
= ProcessIDN(
112 Stringize(CERT_GetCommonName(&cert_handle
->subject
), std::string()));
115 return GetNickname(cert_handle
);
118 string
GetTokenName(X509Certificate::OSCertHandle cert_handle
) {
119 return psm::GetCertTokenName(cert_handle
);
122 string
GetVersion(X509Certificate::OSCertHandle cert_handle
) {
123 // If the version field is omitted from the certificate, the default
125 unsigned long version
= 0;
126 if (cert_handle
->version
.len
== 0 ||
127 SEC_ASN1DecodeInteger(&cert_handle
->version
, &version
) == SECSuccess
) {
128 return base::UintToString(version
+ 1);
130 return std::string();
133 net::CertType
GetType(X509Certificate::OSCertHandle cert_handle
) {
134 return psm::GetCertType(cert_handle
);
137 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle
,
138 std::vector
<string
>* usages
) {
139 psm::GetCertUsageStrings(cert_handle
, usages
);
142 string
GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle
,
143 const string
& alternative_text
) {
144 return Stringize(CERT_Hexify(&cert_handle
->serialNumber
, true),
148 string
GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle
,
149 const string
& alternative_text
) {
150 return Stringize(CERT_GetCommonName(&cert_handle
->issuer
), alternative_text
);
153 string
GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle
,
154 const string
& alternative_text
) {
155 return Stringize(CERT_GetOrgName(&cert_handle
->issuer
), alternative_text
);
158 string
GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle
,
159 const string
& alternative_text
) {
160 return Stringize(CERT_GetOrgUnitName(&cert_handle
->issuer
), alternative_text
);
163 string
GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle
,
164 const string
& alternative_text
) {
165 return Stringize(CERT_GetOrgName(&cert_handle
->subject
), alternative_text
);
168 string
GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle
,
169 const string
& alternative_text
) {
170 return Stringize(CERT_GetOrgUnitName(&cert_handle
->subject
),
174 string
GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle
,
175 const string
& alternative_text
) {
176 return Stringize(CERT_GetCommonName(&cert_handle
->subject
), alternative_text
);
179 bool GetTimes(X509Certificate::OSCertHandle cert_handle
,
180 base::Time
* issued
, base::Time
* expires
) {
181 PRTime pr_issued
, pr_expires
;
182 if (CERT_GetCertTimes(cert_handle
, &pr_issued
, &pr_expires
) == SECSuccess
) {
183 *issued
= crypto::PRTimeToBaseTime(pr_issued
);
184 *expires
= crypto::PRTimeToBaseTime(pr_expires
);
190 string
GetTitle(X509Certificate::OSCertHandle cert_handle
) {
191 return psm::GetCertTitle(cert_handle
);
194 string
GetIssuerName(X509Certificate::OSCertHandle cert_handle
) {
195 return psm::ProcessName(&cert_handle
->issuer
);
198 string
GetSubjectName(X509Certificate::OSCertHandle cert_handle
) {
199 return psm::ProcessName(&cert_handle
->subject
);
203 const string
& critical_label
,
204 const string
& non_critical_label
,
205 X509Certificate::OSCertHandle cert_handle
,
206 Extensions
* extensions
) {
207 if (cert_handle
->extensions
) {
208 for (size_t i
= 0; cert_handle
->extensions
[i
] != NULL
; ++i
) {
210 extension
.name
= psm::GetOIDText(&cert_handle
->extensions
[i
]->id
);
211 extension
.value
= ProcessExtension(
212 critical_label
, non_critical_label
, cert_handle
->extensions
[i
]);
213 extensions
->push_back(extension
);
218 string
HashCertSHA256(X509Certificate::OSCertHandle cert_handle
) {
219 return HashCert(cert_handle
, HASH_AlgSHA256
, SHA256_LENGTH
);
222 string
HashCertSHA1(X509Certificate::OSCertHandle cert_handle
) {
223 return HashCert(cert_handle
, HASH_AlgSHA1
, SHA1_LENGTH
);
226 string
GetCMSString(const X509Certificate::OSCertHandles
& cert_chain
,
227 size_t start
, size_t end
) {
228 crypto::ScopedPLArenaPool
arena(PORT_NewArena(1024));
231 ScopedNSSCMSMessage
message(NSS_CMSMessage_Create(arena
.get()));
232 DCHECK(message
.get());
234 // First, create SignedData with the certificate only (no chain).
235 ScopedNSSCMSSignedData
signed_data(NSS_CMSSignedData_CreateCertsOnly(
236 message
.get(), cert_chain
[start
], PR_FALSE
));
237 if (!signed_data
.get()) {
238 DLOG(ERROR
) << "NSS_CMSSignedData_Create failed";
239 return std::string();
241 // Add the rest of the chain (if any).
242 for (size_t i
= start
+ 1; i
< end
; ++i
) {
243 if (NSS_CMSSignedData_AddCertificate(signed_data
.get(), cert_chain
[i
]) !=
245 DLOG(ERROR
) << "NSS_CMSSignedData_AddCertificate failed on " << i
;
246 return std::string();
250 NSSCMSContentInfo
*cinfo
= NSS_CMSMessage_GetContentInfo(message
.get());
251 if (NSS_CMSContentInfo_SetContent_SignedData(
252 message
.get(), cinfo
, signed_data
.get()) == SECSuccess
) {
253 ignore_result(signed_data
.release());
255 DLOG(ERROR
) << "NSS_CMSMessage_GetContentInfo failed";
256 return std::string();
259 SECItem cert_p7
= { siBuffer
, NULL
, 0 };
260 NSSCMSEncoderContext
*ecx
= NSS_CMSEncoder_Start(message
.get(), NULL
, NULL
,
261 &cert_p7
, arena
.get(), NULL
,
262 NULL
, NULL
, NULL
, NULL
,
265 DLOG(ERROR
) << "NSS_CMSEncoder_Start failed";
266 return std::string();
269 if (NSS_CMSEncoder_Finish(ecx
) != SECSuccess
) {
270 DLOG(ERROR
) << "NSS_CMSEncoder_Finish failed";
271 return std::string();
274 return string(reinterpret_cast<const char*>(cert_p7
.data
), cert_p7
.len
);
277 string
ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle
) {
278 return ProcessSecAlgorithmInternal(&cert_handle
->signature
);
281 string
ProcessSecAlgorithmSubjectPublicKey(
282 X509Certificate::OSCertHandle cert_handle
) {
283 return ProcessSecAlgorithmInternal(
284 &cert_handle
->subjectPublicKeyInfo
.algorithm
);
287 string
ProcessSecAlgorithmSignatureWrap(
288 X509Certificate::OSCertHandle cert_handle
) {
289 return ProcessSecAlgorithmInternal(
290 &cert_handle
->signatureWrap
.signatureAlgorithm
);
293 string
ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle
) {
294 return psm::ProcessSubjectPublicKeyInfo(&cert_handle
->subjectPublicKeyInfo
);
297 string
ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle
) {
298 return ProcessRawBits(cert_handle
->signatureWrap
.signature
.data
,
299 cert_handle
->signatureWrap
.signature
.len
);
302 } // namespace x509_certificate_model