Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / common / net / x509_certificate_model_nss.cc
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.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
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"
24
25 namespace psm = mozilla_security_manager;
26
27 namespace {
28
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;
34
35   std::string s = nss_text;
36   PORT_Free(nss_text);
37   return s;
38 }
39
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];
47
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);
56 }
57
58 std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
59   return psm::GetOIDText(&algorithm_id->algorithm);
60 }
61
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);
70 }
71
72 std::string GetNickname(net::X509Certificate::OSCertHandle cert_handle) {
73   std::string name;
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);
81   }
82   return name;
83 }
84
85 ////////////////////////////////////////////////////////////////////////////////
86 // NSS certificate export functions.
87
88 struct NSSCMSMessageDeleter {
89   inline void operator()(NSSCMSMessage* x) const {
90     NSS_CMSMessage_Destroy(x);
91   }
92 };
93 typedef scoped_ptr<NSSCMSMessage, NSSCMSMessageDeleter> ScopedNSSCMSMessage;
94
95 struct FreeNSSCMSSignedData {
96   inline void operator()(NSSCMSSignedData* x) const {
97     NSS_CMSSignedData_Destroy(x);
98   }
99 };
100 typedef scoped_ptr<NSSCMSSignedData, FreeNSSCMSSignedData>
101     ScopedNSSCMSSignedData;
102
103 }  // namespace
104
105 namespace x509_certificate_model {
106
107 using net::X509Certificate;
108 using std::string;
109
110 string GetCertNameOrNickname(X509Certificate::OSCertHandle cert_handle) {
111   string name = ProcessIDN(
112       Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
113   if (!name.empty())
114     return name;
115   return GetNickname(cert_handle);
116 }
117
118 string GetTokenName(X509Certificate::OSCertHandle cert_handle) {
119   return psm::GetCertTokenName(cert_handle);
120 }
121
122 string GetVersion(X509Certificate::OSCertHandle cert_handle) {
123   // If the version field is omitted from the certificate, the default
124   // value is v1(0).
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);
129   }
130   return std::string();
131 }
132
133 net::CertType GetType(X509Certificate::OSCertHandle cert_handle) {
134     return psm::GetCertType(cert_handle);
135 }
136
137 void GetUsageStrings(X509Certificate::OSCertHandle cert_handle,
138                      std::vector<string>* usages) {
139   psm::GetCertUsageStrings(cert_handle, usages);
140 }
141
142 string GetSerialNumberHexified(X509Certificate::OSCertHandle cert_handle,
143                                const string& alternative_text) {
144   return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
145                    alternative_text);
146 }
147
148 string GetIssuerCommonName(X509Certificate::OSCertHandle cert_handle,
149                            const string& alternative_text) {
150   return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
151 }
152
153 string GetIssuerOrgName(X509Certificate::OSCertHandle cert_handle,
154                         const string& alternative_text) {
155   return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
156 }
157
158 string GetIssuerOrgUnitName(X509Certificate::OSCertHandle cert_handle,
159                             const string& alternative_text) {
160   return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
161 }
162
163 string GetSubjectOrgName(X509Certificate::OSCertHandle cert_handle,
164                          const string& alternative_text) {
165   return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
166 }
167
168 string GetSubjectOrgUnitName(X509Certificate::OSCertHandle cert_handle,
169                              const string& alternative_text) {
170   return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
171                    alternative_text);
172 }
173
174 string GetSubjectCommonName(X509Certificate::OSCertHandle cert_handle,
175                             const string& alternative_text) {
176   return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
177 }
178
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);
185     return true;
186   }
187   return false;
188 }
189
190 string GetTitle(X509Certificate::OSCertHandle cert_handle) {
191   return psm::GetCertTitle(cert_handle);
192 }
193
194 string GetIssuerName(X509Certificate::OSCertHandle cert_handle) {
195   return psm::ProcessName(&cert_handle->issuer);
196 }
197
198 string GetSubjectName(X509Certificate::OSCertHandle cert_handle) {
199   return psm::ProcessName(&cert_handle->subject);
200 }
201
202 void GetExtensions(
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) {
209       Extension extension;
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);
214     }
215   }
216 }
217
218 string HashCertSHA256(X509Certificate::OSCertHandle cert_handle) {
219   return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
220 }
221
222 string HashCertSHA1(X509Certificate::OSCertHandle cert_handle) {
223   return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
224 }
225
226 string GetCMSString(const X509Certificate::OSCertHandles& cert_chain,
227                     size_t start, size_t end) {
228   crypto::ScopedPLArenaPool arena(PORT_NewArena(1024));
229   DCHECK(arena.get());
230
231   ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
232   DCHECK(message.get());
233
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();
240   }
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]) !=
244         SECSuccess) {
245       DLOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
246       return std::string();
247     }
248   }
249
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());
254   } else {
255     DLOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
256     return std::string();
257   }
258
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,
263                                                    NULL);
264   if (!ecx) {
265     DLOG(ERROR) << "NSS_CMSEncoder_Start failed";
266     return std::string();
267   }
268
269   if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
270     DLOG(ERROR) << "NSS_CMSEncoder_Finish failed";
271     return std::string();
272   }
273
274   return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
275 }
276
277 string ProcessSecAlgorithmSignature(X509Certificate::OSCertHandle cert_handle) {
278   return ProcessSecAlgorithmInternal(&cert_handle->signature);
279 }
280
281 string ProcessSecAlgorithmSubjectPublicKey(
282     X509Certificate::OSCertHandle cert_handle) {
283   return ProcessSecAlgorithmInternal(
284       &cert_handle->subjectPublicKeyInfo.algorithm);
285 }
286
287 string ProcessSecAlgorithmSignatureWrap(
288     X509Certificate::OSCertHandle cert_handle) {
289   return ProcessSecAlgorithmInternal(
290       &cert_handle->signatureWrap.signatureAlgorithm);
291 }
292
293 string ProcessSubjectPublicKeyInfo(X509Certificate::OSCertHandle cert_handle) {
294   return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
295 }
296
297 string ProcessRawBitsSignatureWrap(X509Certificate::OSCertHandle cert_handle) {
298   return ProcessRawBits(cert_handle->signatureWrap.signature.data,
299                         cert_handle->signatureWrap.signature.len);
300 }
301
302 }  // namespace x509_certificate_model