Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsXPIDLString.h"
7 #include "nsCOMPtr.h"
8 #include "nsISupports.h"
9 #include "nsIInterfaceRequestor.h"
10 #include "nsCRT.h"
12 #include "nsICMSSecureMessage.h"
14 #include "nsCMSSecureMessage.h"
15 #include "nsNSSCertificate.h"
16 #include "nsNSSHelper.h"
17 #include "nsNSSShutDown.h"
19 #include <string.h>
20 #include "plbase64.h"
21 #include "cert.h"
22 #include "cms.h"
24 #include "nsIServiceManager.h"
25 #include "nsIPrefService.h"
26 #include "nsIPrefBranch.h"
28 #include "prlog.h"
29 #ifdef PR_LOGGING
30 extern PRLogModuleInfo* gPIPNSSLog;
31 #endif
33 // Standard ISupports implementation
34 // NOTE: Should these be the thread-safe versions?
36 /*****
37 * nsCMSSecureMessage
38 *****/
40 // Standard ISupports implementation
41 NS_IMPL_ISUPPORTS(nsCMSSecureMessage, nsICMSSecureMessage)
43 // nsCMSSecureMessage constructor
44 nsCMSSecureMessage::nsCMSSecureMessage()
45 {
46 // initialize superclass
47 }
49 // nsCMSMessage destructor
50 nsCMSSecureMessage::~nsCMSSecureMessage()
51 {
52 }
54 /* string getCertByPrefID (in string certID); */
55 NS_IMETHODIMP nsCMSSecureMessage::
56 GetCertByPrefID(const char *certID, char **_retval)
57 {
58 nsNSSShutDownPreventionLock locker;
59 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::GetCertByPrefID\n"));
60 nsresult rv = NS_OK;
61 CERTCertificate *cert = 0;
62 nsXPIDLCString nickname;
63 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
65 *_retval = 0;
67 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
68 if (NS_FAILED(rv)) {
69 goto done;
70 }
72 rv = prefs->GetCharPref(certID,
73 getter_Copies(nickname));
74 if (NS_FAILED(rv)) goto done;
76 /* Find a good cert in the user's database */
77 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), const_cast<char*>(nickname.get()),
78 certUsageEmailRecipient, true, ctx);
80 if (!cert) {
81 /* Success, but no value */
82 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::GetCertByPrefID - can't find user cert\n"));
83 goto done;
84 }
86 /* Convert the DER to a BASE64 String */
87 encode(cert->derCert.data, cert->derCert.len, _retval);
89 done:
90 if (cert) CERT_DestroyCertificate(cert);
91 return rv;
92 }
95 // nsCMSSecureMessage::DecodeCert
96 nsresult nsCMSSecureMessage::
97 DecodeCert(const char *value, nsIX509Cert ** _retval)
98 {
99 nsNSSShutDownPreventionLock locker;
100 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::DecodeCert\n"));
101 nsresult rv = NS_OK;
102 int32_t length;
103 unsigned char *data = 0;
105 *_retval = 0;
107 if (!value) { return NS_ERROR_FAILURE; }
109 rv = decode(value, &data, &length);
110 if (NS_FAILED(rv)) {
111 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::DecodeCert - can't decode cert\n"));
112 return rv;
113 }
115 nsCOMPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER((char *)data, length);
117 if (cert) {
118 *_retval = cert;
119 NS_ADDREF(*_retval);
120 }
121 else {
122 rv = NS_ERROR_FAILURE;
123 }
125 free((char*)data);
126 return rv;
127 }
129 // nsCMSSecureMessage::SendMessage
130 nsresult nsCMSSecureMessage::
131 SendMessage(const char *msg, const char *base64Cert, char ** _retval)
132 {
133 nsNSSShutDownPreventionLock locker;
134 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage\n"));
135 nsresult rv = NS_OK;
136 CERTCertificate *cert = 0;
137 NSSCMSMessage *cmsMsg = 0;
138 unsigned char *certDER = 0;
139 int32_t derLen;
140 NSSCMSEnvelopedData *env;
141 NSSCMSContentInfo *cinfo;
142 NSSCMSRecipientInfo *rcpt;
143 SECItem output;
144 PLArenaPool *arena = PORT_NewArena(1024);
145 SECStatus s;
146 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
148 /* Step 0. Create a CMS Message */
149 cmsMsg = NSS_CMSMessage_Create(nullptr);
150 if (!cmsMsg) {
151 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create NSSCMSMessage\n"));
152 rv = NS_ERROR_FAILURE;
153 goto done;
154 }
156 /* Step 1. Import the certificate into NSS */
157 rv = decode(base64Cert, &certDER, &derLen);
158 if (NS_FAILED(rv)) {
159 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode / import cert into NSS\n"));
160 goto done;
161 }
163 cert = CERT_DecodeCertFromPackage((char *)certDER, derLen);
164 if (!cert) {
165 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode cert from package\n"));
166 rv = NS_ERROR_FAILURE;
167 goto done;
168 }
170 /* Step 2. Get a signature cert */
172 /* Step 3. Build inner (signature) content */
174 /* Step 4. Build outer (enveloped) content */
175 env = NSS_CMSEnvelopedData_Create(cmsMsg, SEC_OID_DES_EDE3_CBC, 0);
176 if (!env) {
177 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create envelope data\n"));
178 rv = NS_ERROR_FAILURE;
179 goto done;
180 }
182 cinfo = NSS_CMSEnvelopedData_GetContentInfo(env);
183 s = NSS_CMSContentInfo_SetContent_Data(cmsMsg, cinfo, 0, false);
184 if (s != SECSuccess) {
185 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content data\n"));
186 rv = NS_ERROR_FAILURE;
187 goto done;
188 }
190 rcpt = NSS_CMSRecipientInfo_Create(cmsMsg, cert);
191 if (!rcpt) {
192 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create recipient info\n"));
193 rv = NS_ERROR_FAILURE;
194 goto done;
195 }
197 s = NSS_CMSEnvelopedData_AddRecipient(env, rcpt);
198 if (s != SECSuccess) {
199 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't add recipient\n"));
200 rv = NS_ERROR_FAILURE;
201 goto done;
202 }
204 /* Step 5. Add content to message */
205 cinfo = NSS_CMSMessage_GetContentInfo(cmsMsg);
206 s = NSS_CMSContentInfo_SetContent_EnvelopedData(cmsMsg, cinfo, env);
207 if (s != SECSuccess) {
208 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content enveloped data\n"));
209 rv = NS_ERROR_FAILURE;
210 goto done;
211 }
213 /* Step 6. Encode */
214 NSSCMSEncoderContext *ecx;
216 output.data = 0; output.len = 0;
217 ecx = NSS_CMSEncoder_Start(cmsMsg, 0, 0, &output, arena,
218 0, ctx, 0, 0, 0, 0);
219 if (!ecx) {
220 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't start cms encoder\n"));
221 rv = NS_ERROR_FAILURE;
222 goto done;
223 }
225 s = NSS_CMSEncoder_Update(ecx, msg, strlen(msg));
226 if (s != SECSuccess) {
227 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't update encoder\n"));
228 rv = NS_ERROR_FAILURE;
229 goto done;
230 }
232 s = NSS_CMSEncoder_Finish(ecx);
233 if (s != SECSuccess) {
234 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't finish encoder\n"));
235 rv = NS_ERROR_FAILURE;
236 goto done;
237 }
239 /* Step 7. Base64 encode and return the result */
240 rv = encode(output.data, output.len, _retval);
242 done:
243 if (certDER) free((char *)certDER);
244 if (cert) CERT_DestroyCertificate(cert);
245 if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg);
246 if (arena) PORT_FreeArena(arena, false); /* false? */
248 return rv;
249 }
251 /*
252 * nsCMSSecureMessage::ReceiveMessage
253 */
254 nsresult nsCMSSecureMessage::
255 ReceiveMessage(const char *msg, char **_retval)
256 {
257 nsNSSShutDownPreventionLock locker;
258 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage\n"));
259 nsresult rv = NS_OK;
260 NSSCMSDecoderContext *dcx;
261 unsigned char *der = 0;
262 int32_t derLen;
263 NSSCMSMessage *cmsMsg = 0;
264 SECItem *content;
265 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();
267 /* Step 1. Decode the base64 wrapper */
268 rv = decode(msg, &der, &derLen);
269 if (NS_FAILED(rv)) {
270 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't base64 decode\n"));
271 goto done;
272 }
274 dcx = NSS_CMSDecoder_Start(0, 0, 0, /* pw */ 0, ctx, /* key */ 0, 0);
275 if (!dcx) {
276 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't start decoder\n"));
277 rv = NS_ERROR_FAILURE;
278 goto done;
279 }
281 (void)NSS_CMSDecoder_Update(dcx, (char *)der, derLen);
282 cmsMsg = NSS_CMSDecoder_Finish(dcx);
283 if (!cmsMsg) {
284 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't finish decoder\n"));
285 rv = NS_ERROR_FAILURE;
286 /* Memory leak on dcx?? */
287 goto done;
288 }
290 content = NSS_CMSMessage_GetContent(cmsMsg);
291 if (!content) {
292 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't get content\n"));
293 rv = NS_ERROR_FAILURE;
294 goto done;
295 }
297 /* Copy the data */
298 *_retval = (char*)malloc(content->len+1);
299 memcpy(*_retval, content->data, content->len);
300 (*_retval)[content->len] = 0;
302 done:
303 if (der) free(der);
304 if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg);
306 return rv;
307 }
309 nsresult nsCMSSecureMessage::
310 encode(const unsigned char *data, int32_t dataLen, char **_retval)
311 {
312 nsresult rv = NS_OK;
314 *_retval = PL_Base64Encode((const char *)data, dataLen, nullptr);
315 if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto loser; }
317 loser:
318 return rv;
319 }
321 nsresult nsCMSSecureMessage::
322 decode(const char *data, unsigned char **result, int32_t * _retval)
323 {
324 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::decode\n"));
325 nsresult rv = NS_OK;
326 uint32_t len = strlen(data);
327 int adjust = 0;
329 /* Compute length adjustment */
330 if (data[len-1] == '=') {
331 adjust++;
332 if (data[len-2] == '=') adjust++;
333 }
335 *result = (unsigned char *)PL_Base64Decode(data, len, nullptr);
336 if (!*result) {
337 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::decode - error decoding base64\n"));
338 rv = NS_ERROR_ILLEGAL_VALUE;
339 goto loser;
340 }
342 *_retval = (len*3)/4 - adjust;
344 loser:
345 return rv;
346 }