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 "chrome/common/net/x509_certificate_model_nss.h"
6
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>
15 #include <stddef.h>
16 #include <stdint.h>
17 #include <string.h>
18 #include <unicode/uidna.h>
19
20 #include <algorithm>
21 #include <memory>
22
23 #include "base/logging.h"
24 #include "base/numerics/safe_conversions.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
29 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
30 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
31 #include "components/url_formatter/url_formatter.h"
32 #include "crypto/nss_util.h"
33 #include "crypto/scoped_nss_types.h"
34 #include "net/cert/x509_util_nss.h"
35 #include "ui/base/l10n/l10n_util.h"
36
37 namespace psm = mozilla_security_manager;
38
39 namespace {
40
41 // Convert a char* return value from NSS into a std::string and free the NSS
42 // memory. If the arg is NULL, an empty string will be returned instead.
Stringize(char * nss_text,const std::string & alternative_text)43 std::string Stringize(char* nss_text, const std::string& alternative_text) {
44 if (!nss_text)
45 return alternative_text;
46
47 std::string s = nss_text;
48 PORT_Free(nss_text);
49 return s;
50 }
51
52 // Hash a certificate using the given algorithm, return the result as a
53 // colon-seperated hex string. The len specified is the number of bytes
54 // required for storing the raw fingerprint.
55 // (It's a bit redundant that the caller needs to specify len in addition to the
56 // algorithm, but given the limited uses, not worth fixing.)
HashCert(CERTCertificate * cert,HASH_HashType algorithm,int len)57 std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
58 unsigned char fingerprint[HASH_LENGTH_MAX];
59
60 DCHECK(NULL != cert->derCert.data);
61 DCHECK_NE(0U, cert->derCert.len);
62 DCHECK_LE(len, HASH_LENGTH_MAX);
63 memset(fingerprint, 0, len);
64 SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
65 cert->derCert.len);
66 DCHECK_EQ(rv, SECSuccess);
67 return x509_certificate_model::ProcessRawBytes(fingerprint, len);
68 }
69
ProcessSecAlgorithmInternal(SECAlgorithmID * algorithm_id)70 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
71 return psm::GetOIDText(&algorithm_id->algorithm);
72 }
73
ProcessExtension(const std::string & critical_label,const std::string & non_critical_label,CERTCertExtension * extension)74 std::string ProcessExtension(
75 const std::string& critical_label,
76 const std::string& non_critical_label,
77 CERTCertExtension* extension) {
78 std::string criticality =
79 extension->critical.data && extension->critical.data[0] ?
80 critical_label : non_critical_label;
81 return criticality + "\n" + psm::ProcessExtensionData(extension);
82 }
83
GetNickname(CERTCertificate * cert_handle)84 std::string GetNickname(CERTCertificate* cert_handle) {
85 std::string name;
86 if (cert_handle->nickname) {
87 name = cert_handle->nickname;
88 // Hack copied from mozilla: Cut off text before first :, which seems to
89 // just be the token name.
90 size_t colon_pos = name.find(':');
91 if (colon_pos != std::string::npos)
92 name = name.substr(colon_pos + 1);
93 }
94 return name;
95 }
96
97 ////////////////////////////////////////////////////////////////////////////////
98 // NSS certificate export functions.
99
100 struct NSSCMSMessageDeleter {
operator ()__anon4b89dcca0111::NSSCMSMessageDeleter101 inline void operator()(NSSCMSMessage* x) const {
102 NSS_CMSMessage_Destroy(x);
103 }
104 };
105 typedef std::unique_ptr<NSSCMSMessage, NSSCMSMessageDeleter>
106 ScopedNSSCMSMessage;
107
108 struct FreeNSSCMSSignedData {
operator ()__anon4b89dcca0111::FreeNSSCMSSignedData109 inline void operator()(NSSCMSSignedData* x) const {
110 NSS_CMSSignedData_Destroy(x);
111 }
112 };
113 typedef std::unique_ptr<NSSCMSSignedData, FreeNSSCMSSignedData>
114 ScopedNSSCMSSignedData;
115
116 } // namespace
117
118 namespace x509_certificate_model {
119
120 using std::string;
121
GetCertNameOrNickname(CERTCertificate * cert_handle)122 string GetCertNameOrNickname(CERTCertificate* cert_handle) {
123 string name = ProcessIDN(
124 Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
125 if (!name.empty())
126 return name;
127 return GetNickname(cert_handle);
128 }
129
GetVersion(CERTCertificate * cert_handle)130 string GetVersion(CERTCertificate* cert_handle) {
131 // If the version field is omitted from the certificate, the default
132 // value is v1(0).
133 unsigned long version = 0;
134 if (cert_handle->version.len == 0 ||
135 SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess) {
136 return base::NumberToString(base::strict_cast<uint64_t>(version + 1));
137 }
138 return std::string();
139 }
140
GetType(CERTCertificate * cert_handle)141 net::CertType GetType(CERTCertificate* cert_handle) {
142 return psm::GetCertType(cert_handle);
143 }
144
GetUsageStrings(CERTCertificate * cert_handle,std::vector<string> * usages)145 void GetUsageStrings(CERTCertificate* cert_handle,
146 std::vector<string>* usages) {
147 psm::GetCertUsageStrings(cert_handle, usages);
148 }
149
GetSerialNumberHexified(CERTCertificate * cert_handle,const string & alternative_text)150 string GetSerialNumberHexified(CERTCertificate* cert_handle,
151 const string& alternative_text) {
152 return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
153 alternative_text);
154 }
155
GetIssuerCommonName(CERTCertificate * cert_handle,const string & alternative_text)156 string GetIssuerCommonName(CERTCertificate* cert_handle,
157 const string& alternative_text) {
158 return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
159 }
160
GetIssuerOrgName(CERTCertificate * cert_handle,const string & alternative_text)161 string GetIssuerOrgName(CERTCertificate* cert_handle,
162 const string& alternative_text) {
163 return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
164 }
165
GetIssuerOrgUnitName(CERTCertificate * cert_handle,const string & alternative_text)166 string GetIssuerOrgUnitName(CERTCertificate* cert_handle,
167 const string& alternative_text) {
168 return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
169 }
170
GetSubjectOrgName(CERTCertificate * cert_handle,const string & alternative_text)171 string GetSubjectOrgName(CERTCertificate* cert_handle,
172 const string& alternative_text) {
173 return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
174 }
175
GetSubjectOrgUnitName(CERTCertificate * cert_handle,const string & alternative_text)176 string GetSubjectOrgUnitName(CERTCertificate* cert_handle,
177 const string& alternative_text) {
178 return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
179 alternative_text);
180 }
181
GetSubjectCommonName(CERTCertificate * cert_handle,const string & alternative_text)182 string GetSubjectCommonName(CERTCertificate* cert_handle,
183 const string& alternative_text) {
184 return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
185 }
186
GetTimes(CERTCertificate * cert_handle,base::Time * issued,base::Time * expires)187 bool GetTimes(CERTCertificate* cert_handle,
188 base::Time* issued,
189 base::Time* expires) {
190 return net::x509_util::GetValidityTimes(cert_handle, issued, expires);
191 }
192
GetTitle(CERTCertificate * cert_handle)193 string GetTitle(CERTCertificate* cert_handle) {
194 return psm::GetCertTitle(cert_handle);
195 }
196
GetIssuerName(CERTCertificate * cert_handle)197 string GetIssuerName(CERTCertificate* cert_handle) {
198 return psm::ProcessName(&cert_handle->issuer);
199 }
200
GetSubjectName(CERTCertificate * cert_handle)201 string GetSubjectName(CERTCertificate* cert_handle) {
202 return psm::ProcessName(&cert_handle->subject);
203 }
204
GetIssuerDisplayName(CERTCertificate * cert_handle)205 std::string GetIssuerDisplayName(CERTCertificate* cert_handle) {
206 return net::x509_util::GetCERTNameDisplayName(&cert_handle->issuer);
207 }
208
GetSubjectDisplayName(CERTCertificate * cert_handle)209 std::string GetSubjectDisplayName(CERTCertificate* cert_handle) {
210 return net::x509_util::GetCERTNameDisplayName(&cert_handle->subject);
211 }
212
GetExtensions(const string & critical_label,const string & non_critical_label,CERTCertificate * cert_handle,Extensions * extensions)213 void GetExtensions(const string& critical_label,
214 const string& non_critical_label,
215 CERTCertificate* cert_handle,
216 Extensions* extensions) {
217 if (cert_handle->extensions) {
218 for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
219 Extension extension;
220 extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
221 extension.value = ProcessExtension(
222 critical_label, non_critical_label, cert_handle->extensions[i]);
223 extensions->push_back(extension);
224 }
225 }
226 }
227
HashCertSHA256(CERTCertificate * cert_handle)228 string HashCertSHA256(CERTCertificate* cert_handle) {
229 return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
230 }
231
HashCertSHA1(CERTCertificate * cert_handle)232 string HashCertSHA1(CERTCertificate* cert_handle) {
233 return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
234 }
235
GetCMSString(const net::ScopedCERTCertificateList & cert_chain,size_t start,size_t end)236 string GetCMSString(const net::ScopedCERTCertificateList& cert_chain,
237 size_t start,
238 size_t end) {
239 crypto::ScopedPLArenaPool arena(PORT_NewArena(1024));
240 DCHECK(arena.get());
241
242 ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
243 DCHECK(message.get());
244
245 // First, create SignedData with the certificate only (no chain).
246 ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
247 message.get(), cert_chain[start].get(), PR_FALSE));
248 if (!signed_data.get()) {
249 DLOG(ERROR) << "NSS_CMSSignedData_Create failed";
250 return std::string();
251 }
252 // Add the rest of the chain (if any).
253 for (size_t i = start + 1; i < end; ++i) {
254 if (NSS_CMSSignedData_AddCertificate(signed_data.get(),
255 cert_chain[i].get()) != SECSuccess) {
256 DLOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
257 return std::string();
258 }
259 }
260
261 NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
262 if (NSS_CMSContentInfo_SetContent_SignedData(
263 message.get(), cinfo, signed_data.get()) == SECSuccess) {
264 ignore_result(signed_data.release());
265 } else {
266 DLOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
267 return std::string();
268 }
269
270 SECItem cert_p7 = { siBuffer, NULL, 0 };
271 NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
272 &cert_p7, arena.get(), NULL,
273 NULL, NULL, NULL, NULL,
274 NULL);
275 if (!ecx) {
276 DLOG(ERROR) << "NSS_CMSEncoder_Start failed";
277 return std::string();
278 }
279
280 if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
281 DLOG(ERROR) << "NSS_CMSEncoder_Finish failed";
282 return std::string();
283 }
284
285 return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
286 }
287
ProcessSecAlgorithmSignature(CERTCertificate * cert_handle)288 string ProcessSecAlgorithmSignature(CERTCertificate* cert_handle) {
289 return ProcessSecAlgorithmInternal(&cert_handle->signature);
290 }
291
ProcessSecAlgorithmSubjectPublicKey(CERTCertificate * cert_handle)292 string ProcessSecAlgorithmSubjectPublicKey(CERTCertificate* cert_handle) {
293 return ProcessSecAlgorithmInternal(
294 &cert_handle->subjectPublicKeyInfo.algorithm);
295 }
296
ProcessSecAlgorithmSignatureWrap(CERTCertificate * cert_handle)297 string ProcessSecAlgorithmSignatureWrap(CERTCertificate* cert_handle) {
298 return ProcessSecAlgorithmInternal(
299 &cert_handle->signatureWrap.signatureAlgorithm);
300 }
301
ProcessSubjectPublicKeyInfo(CERTCertificate * cert_handle)302 string ProcessSubjectPublicKeyInfo(CERTCertificate* cert_handle) {
303 return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
304 }
305
ProcessRawBitsSignatureWrap(CERTCertificate * cert_handle)306 string ProcessRawBitsSignatureWrap(CERTCertificate* cert_handle) {
307 return ProcessRawBits(cert_handle->signatureWrap.signature.data,
308 cert_handle->signatureWrap.signature.len);
309 }
310
ProcessIDN(const std::string & input)311 std::string ProcessIDN(const std::string& input) {
312 // Convert the ASCII input to a string16 for ICU.
313 base::string16 input16;
314 input16.reserve(input.length());
315 input16.insert(input16.end(), input.begin(), input.end());
316
317 base::string16 output16 = url_formatter::IDNToUnicode(input);
318 if (input16 == output16)
319 return input; // Input did not contain any encoded data.
320
321 // Input contained encoded data, return formatted string showing original and
322 // decoded forms.
323 return l10n_util::GetStringFUTF8(IDS_CERT_INFO_IDN_VALUE_FORMAT, input16,
324 output16);
325 }
326
ProcessRawBytesWithSeparators(const unsigned char * data,size_t data_length,char hex_separator,char line_separator)327 std::string ProcessRawBytesWithSeparators(const unsigned char* data,
328 size_t data_length,
329 char hex_separator,
330 char line_separator) {
331 static const char kHexChars[] = "0123456789ABCDEF";
332
333 // Each input byte creates two output hex characters + a space or newline,
334 // except for the last byte.
335 std::string ret;
336 size_t kMin = 0U;
337
338 if (!data_length)
339 return std::string();
340
341 ret.reserve(std::max(kMin, data_length * 3 - 1));
342
343 for (size_t i = 0; i < data_length; ++i) {
344 unsigned char b = data[i];
345 ret.push_back(kHexChars[(b >> 4) & 0xf]);
346 ret.push_back(kHexChars[b & 0xf]);
347 if (i + 1 < data_length) {
348 if ((i + 1) % 16 == 0)
349 ret.push_back(line_separator);
350 else
351 ret.push_back(hex_separator);
352 }
353 }
354 return ret;
355 }
356
ProcessRawBytes(const unsigned char * data,size_t data_length)357 std::string ProcessRawBytes(const unsigned char* data, size_t data_length) {
358 return ProcessRawBytesWithSeparators(data, data_length, ' ', '\n');
359 }
360
ProcessRawBits(const unsigned char * data,size_t data_length)361 std::string ProcessRawBits(const unsigned char* data, size_t data_length) {
362 return ProcessRawBytes(data, (data_length + 7) / 8);
363 }
364
365 } // namespace x509_certificate_model
366