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