1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* The following is the mozilla license blurb, as the bodies some of
3  * these functions were derived from the mozilla source. */
4 /* e-cert-db.c
5  *
6  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7  *
8  * The contents of this file are subject to the Mozilla Public License Version
9  * 1.1 (the "License"); you may not use this file except in compliance with
10  * the License. You may obtain a copy of the License at
11  * http://www.mozilla.org/MPL/
12  *
13  * Software distributed under the License is distributed on an "AS IS" basis,
14  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15  * for the specific language governing rights and limitations under the
16  * License.
17  *
18  * The Original Code is the Netscape security libraries.
19  *
20  * The Initial Developer of the Original Code is
21  * Netscape Communications Corporation.
22  * Portions created by the Initial Developer are Copyright (C) 1994-2000
23  * the Initial Developer. All Rights Reserved.
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either the GNU General Public License Version 2 or later (the "GPL"), or
27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  */
37 
38 /*
39  * Author: Chris Toshok (toshok@ximian.com)
40  *
41  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
42  */
43 
44 #include "evolution-config.h"
45 
46 #include <gtk/gtk.h>
47 #include <glib/gi18n.h>
48 #include <glib/gstdio.h>
49 
50 #include <camel/camel.h>
51 
52 /* private NSS defines used by PSM */
53 /* (must be declated before cert.h) */
54 #define CERT_NewTempCertificate __CERT_NewTempCertificate
55 #define CERT_AddTempCertToPerm __CERT_AddTempCertToPerm
56 
57 #include "e-cert-db.h"
58 #include "e-cert-trust.h"
59 #include "e-pkcs12.h"
60 
61 #include "gmodule.h"
62 
63 #include "nss.h"
64 #include "ssl.h"
65 #include "p12plcy.h"
66 #include "pk11func.h"
67 #include "nssckbi.h"
68 #include <secerr.h>
69 #include "secmod.h"
70 #include "certdb.h"
71 #include "plstr.h"
72 #include "prprf.h"
73 #include "prmem.h"
74 #include "e-util/e-util.h"
75 #include "e-util/e-util-private.h"
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #include <unistd.h>
79 
80 enum {
81 	PK11_PASSWD,
82 	PK11_CHANGE_PASSWD,
83 	CONFIRM_CA_CERT_IMPORT,
84 	LAST_SIGNAL
85 };
86 
87 static guint e_cert_db_signals[LAST_SIGNAL];
88 
G_DEFINE_TYPE(ECertDB,e_cert_db,G_TYPE_OBJECT)89 G_DEFINE_TYPE (ECertDB, e_cert_db, G_TYPE_OBJECT)
90 
91 GQuark
92 e_certdb_error_quark (void)
93 {
94 	static GQuark q = 0;
95 	if (q == 0)
96 		q = g_quark_from_static_string ("e-certdb-error-quark");
97 
98 	return q;
99 }
100 
101 const gchar *
e_cert_db_nss_error_to_string(gint errorcode)102 e_cert_db_nss_error_to_string (gint errorcode)
103 {
104 #define cs(a,b) case a: return b;
105 
106 	switch (errorcode) {
107 	cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.")
108 	cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.")
109 	cs (SEC_ERROR_BAD_DATA, "security library: received bad data.")
110 	cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.")
111 	cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.")
112 	cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.")
113 	cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.")
114 	cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.")
115 	cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.")
116 	cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.")
117 	cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.")
118 	cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.")
119 	cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.")
120 	cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.")
121 	cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.")
122 	cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.")
123 	cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly.  Please try again.")
124 	cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.")
125 	cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.")
126 	cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.")
127 	cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.")
128 	cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.")
129 	cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.")
130 	cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.")
131 	cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.")
132 	cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.")
133 	cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database")
134 	cs (SEC_ERROR_CERT_VALID, "This certificate is valid.")
135 	cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.")
136 	cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response")
137 	cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired.  Check your system date and time.")
138 	cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired.  Update it or check your system date and time.")
139 	cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.")
140 	cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.")
141 	cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.")
142 	cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.")
143 	cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.")
144 	cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.")
145 	cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.")
146 	cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**")
147 	cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.")
148 	cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.")
149 	cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.")
150 	cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.")
151 	cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.")
152 	cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.")
153 	cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.")
154 	cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.")
155 	cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.")
156 	cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
157 	cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized.  Please remove it and return it to your issuer.")
158 	cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found")
159 	cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected")
160 	cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on")
161 	cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found")
162 	cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality")
163 	cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin")
164 	cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.")
165 	cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.")
166 	cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.")
167 	cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.")
168 	cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.")
169 	cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.")
170 	cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.")
171 	cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.")
172 	cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.")
173 	cs (SEC_ERROR_READ_ONLY, "security library: read-only database.")
174 	cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.")
175 	cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.")
176 	cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.")
177 	cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object")
178 	cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object")
179 	cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal")
180 	cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege")
181 	cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate")
182 	cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.")
183 	cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.")
184 	cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.")
185 	cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import.  Decoding error.  File not valid.")
186 	cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import.  Invalid MAC.  Incorrect password or corrupt file.")
187 	cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import.  MAC algorithm not supported.")
188 	cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import.  Only password integrity and privacy modes supported.")
189 	cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import.  File structure is corrupt.")
190 	cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import.  Encryption algorithm not supported.")
191 	cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import.  File version not supported.")
192 	cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import.  Incorrect privacy password.")
193 	cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import.  Same nickname already exists in database.")
194 	cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.")
195 	cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.")
196 	cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.")
197 	cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.")
198 	cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.")
199 	cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.")
200 	cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import.  Error attempting to import private key.")
201 	cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import.  Error attempting to import certificate chain.")
202 	cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export.  Unable to locate certificate or key by nickname.")
203 	cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export.  Private Key could not be located and exported.")
204 	cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export.  Unable to write the export file.")
205 	cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import.  Unable to read the import file.")
206 	cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export.  Key database corrupt or deleted.")
207 	cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.")
208 	cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid.  Please pick a different one.")
209 	cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly.  Please try again.")
210 	cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.")
211 	cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
212 	cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.")
213 	cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.")
214 	cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename")
215 	cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module")
216 	cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module")
217 	cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.")
218 	cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL.  Delete current CKL.")
219 	cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.")
220 	cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.")
221 	cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.")
222 	cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.")
223 	cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.")
224 	cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION,	 "The location for the certificate status server has invalid format.")
225 	cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.")
226 	cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.")
227 	cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.")
228 	cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.")
229 	cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.")
230 	cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.")
231 	cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.")
232 	cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.")
233 	cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.")
234 	cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.")
235 	cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.")
236 	cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.")
237 	cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.")
238 	cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).")
239 	cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.")
240 	cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.")
241 	cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.")
242 	cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.")
243 	cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.")
244 	cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.")
245 	cs (SEC_ERROR_REUSED_ISSUER_AND_SERIAL, "You are attempting to import a cert with the same issuer/serial as an existing cert, but that is not the same cert.")
246 	cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.")
247 	cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.")
248 	cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.")
249 	cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.")
250 	cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.")
251 	cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.")
252 	cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.")
253 	cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.")
254 	cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.")
255 	cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.")
256 	cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.")
257 	cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.")
258 	cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.")
259 	cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.")
260 	cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.")
261 	cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.")
262 	cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.")
263 	cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.")
264 	cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.")
265 
266 	#if defined (NSS_VMAJOR) && defined (NSS_VMINOR) && defined (NSS_VPATCH) && (NSS_VMAJOR > 3 || (NSS_VMAJOR == 3 && NSS_VMINOR > 12) || (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 2))
267 	cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits")
268 	cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy")
269 	cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation")
270 	cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension")
271 	cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response")
272 	cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response")
273 	cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder")
274 	cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension")
275 	cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occured during cert validation.")
276 	cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
277 	cs (SEC_ERROR_PKCS11_FUNCTION_FAILED, "A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed.  Trying the same operation again might succeed.")
278 	cs (SEC_ERROR_PKCS11_DEVICE_ERROR, "A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.")
279 	#endif
280 	}
281 
282 	#undef cs
283 
284 	return NULL;
285 }
286 
287 static void
set_nss_error(GError ** error)288 set_nss_error (GError **error)
289 {
290 	gint err_code;
291 	const gchar *err_str;
292 
293 	if (!error)
294 		return;
295 
296 	g_return_if_fail (*error == NULL);
297 
298 	err_code = PORT_GetError ();
299 
300 	if (!err_code)
301 		return;
302 
303 	err_str = e_cert_db_nss_error_to_string (err_code);
304 	if (!err_str)
305 		return;
306 
307 	*error = g_error_new_literal (E_CERTDB_ERROR, err_code, err_str);
308 }
309 
310 static SECStatus PR_CALLBACK
collect_certs(gpointer arg,SECItem ** certs,gint numcerts)311 collect_certs (gpointer arg,
312                SECItem **certs,
313                gint numcerts)
314 {
315 	CERTDERCerts *collectArgs;
316 	SECItem *cert;
317 	SECStatus rv;
318 
319 	collectArgs = (CERTDERCerts *) arg;
320 
321 	collectArgs->numcerts = numcerts;
322 	collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc (
323 		collectArgs->arena, sizeof (SECItem) * numcerts);
324 	if (collectArgs->rawCerts == NULL)
325 		return (SECFailure);
326 
327 	cert = collectArgs->rawCerts;
328 
329 	while (numcerts--) {
330 		rv = SECITEM_CopyItem (collectArgs->arena, cert, *certs);
331 		if (rv == SECFailure)
332 			return (SECFailure);
333 		cert++;
334 		certs++;
335 	}
336 
337 	return (SECSuccess);
338 }
339 
340 static CERTDERCerts *
e_cert_db_get_certs_from_package(PRArenaPool * arena,gchar * data,guint32 length)341 e_cert_db_get_certs_from_package (PRArenaPool *arena,
342                                   gchar *data,
343                                   guint32 length)
344 {
345 	/*nsNSSShutDownPreventionLock locker;*/
346 	CERTDERCerts *collectArgs =
347 		(CERTDERCerts *) PORT_ArenaZAlloc (arena, sizeof (CERTDERCerts));
348 	SECStatus sec_rv;
349 
350 	if (!collectArgs)
351 		return NULL;
352 
353 	collectArgs->arena = arena;
354 	sec_rv = CERT_DecodeCertPackage (
355 		data,
356 					length, collect_certs,
357 					(gpointer) collectArgs);
358 
359 	if (sec_rv != SECSuccess)
360 		return NULL;
361 
362 	return collectArgs;
363 }
364 
365 /*
366  * copy from pk12util.c
367  */
368 static SECStatus
p12u_SwapUnicodeBytes(SECItem * uniItem)369 p12u_SwapUnicodeBytes(SECItem *uniItem)
370 {
371 	unsigned int i;
372 	unsigned char a;
373 	if ((uniItem == NULL) || (uniItem->len % 2)) {
374 		return SECFailure;
375 	}
376 	for (i = 0; i < uniItem->len; i += 2) {
377 		a = uniItem->data[i];
378 		uniItem->data[i] = uniItem->data[i+1];
379 		uniItem->data[i+1] = a;
380 	}
381 	return SECSuccess;
382 }
383 
384 /*
385  * copy from pk12util.c
386  */
387 static PRBool
p12u_ucs2_ascii_conversion_function(PRBool toUnicode,unsigned char * inBuf,unsigned int inBufLen,unsigned char * outBuf,unsigned int maxOutBufLen,unsigned int * outBufLen,PRBool swapBytes)388 p12u_ucs2_ascii_conversion_function(PRBool	   toUnicode,
389 				    unsigned char *inBuf,
390 				    unsigned int   inBufLen,
391 				    unsigned char *outBuf,
392 				    unsigned int   maxOutBufLen,
393 				    unsigned int  *outBufLen,
394 				    PRBool	   swapBytes)
395 {
396 	SECItem it = { 0 };
397 	SECItem *dup = NULL;
398 	PRBool ret;
399 
400 #ifdef DEBUG_CONVERSION
401 	if (pk12_debugging) {
402 		unsigned int i;
403 		printf ("Converted from:\n");
404 		for (i = 0; i < inBufLen; i++) {
405 			printf("%2x ", inBuf[i]);
406 			/*if ((i % 60) == 0) printf ("\n");*/
407 		}
408 		printf ("\n");
409 	}
410 #endif
411 
412 	it.data = inBuf;
413 	it.len = inBufLen;
414 	dup = SECITEM_DupItem(&it);
415 	if (!dup)
416 		return PR_FALSE;
417 
418 	/* If converting Unicode to ASCII, swap bytes before conversion
419 	 * as neccessary.
420 	 */
421 	if (!toUnicode && swapBytes) {
422 		if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
423 			SECITEM_ZfreeItem(dup, PR_TRUE);
424 			return PR_FALSE;
425 		}
426 	}
427 	/* Perform the conversion. */
428 	ret = PORT_UCS2_UTF8Conversion (toUnicode, dup->data, dup->len,
429 					outBuf, maxOutBufLen, outBufLen);
430 	SECITEM_ZfreeItem(dup, PR_TRUE);
431 
432 #ifdef DEBUG_CONVERSION
433 	if (pk12_debugging) {
434 		unsigned int ii;
435 		printf ("Converted to:\n");
436 		for (ii = 0; ii < *outBufLen; ii++) {
437 			printf ("%2x ", outBuf[ii]);
438 			/*if ((i % 60) == 0) printf ("\n");*/
439 		}
440 		printf ("\n");
441 	}
442 #endif
443 
444 	return ret;
445 }
446 
447 static gchar * PR_CALLBACK
pk11_password(PK11SlotInfo * slot,PRBool retry,gpointer arg)448 pk11_password (PK11SlotInfo *slot,
449                PRBool retry,
450                gpointer arg)
451 {
452 	gchar *pwd;
453 	gchar *nsspwd;
454 
455 	gboolean rv = FALSE;
456 
457 	/* For tokens with CKF_PROTECTED_AUTHENTICATION_PATH we
458 	 * need to return a non-empty but unused password */
459 	if (PK11_ProtectedAuthenticationPath(slot))
460 		return PORT_Strdup("");
461 
462 	g_signal_emit (
463 		e_cert_db_peek (),
464 		e_cert_db_signals[PK11_PASSWD], 0,
465 		slot,
466 		retry,
467 		&pwd,
468 		&rv);
469 
470 	if (pwd == NULL)
471 		return NULL;
472 
473 	nsspwd = PORT_Strdup (pwd);
474 	memset (pwd, 0, strlen (pwd));
475 	g_free (pwd);
476 	return nsspwd;
477 }
478 
479 static void
initialize_nss(void)480 initialize_nss (void)
481 {
482 	/* Use camel_init() to initialise NSS consistently... */
483 	camel_init (e_get_user_data_dir (), TRUE);
484 
485 	/* ... except for the bits we only seem to do here. FIXME */
486 	PK11_SetPasswordFunc (pk11_password);
487 
488 	/* Enable ciphers for PKCS#12 */
489 	SEC_PKCS12EnableCipher (PKCS12_RC4_40, 1);
490 	SEC_PKCS12EnableCipher (PKCS12_RC4_128, 1);
491 	SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_40, 1);
492 	SEC_PKCS12EnableCipher (PKCS12_RC2_CBC_128, 1);
493 	SEC_PKCS12EnableCipher (PKCS12_DES_56, 1);
494 	SEC_PKCS12EnableCipher (PKCS12_DES_EDE3_168, 1);
495 	SEC_PKCS12SetPreferredCipher (PKCS12_DES_EDE3_168, 1);
496 	PORT_SetUCS2_ASCIIConversionFunction (p12u_ucs2_ascii_conversion_function);
497 }
498 
499 static void
install_loadable_roots(void)500 install_loadable_roots (void)
501 {
502 	SECMODModuleList *list = SECMOD_GetDefaultModuleList ();
503 	SECMODListLock *lock = SECMOD_GetDefaultModuleListLock ();
504 	SECMODModule *RootsModule = NULL;
505 	gint i;
506 
507 	SECMOD_GetReadLock (lock);
508 	while (!RootsModule && list) {
509 		SECMODModule *module = list->module;
510 
511 		for (i = 0; i < module->slotCount; i++) {
512 			PK11SlotInfo *slot = module->slots[i];
513 			if (PK11_IsPresent (slot)) {
514 				if (PK11_HasRootCerts (slot)) {
515 					RootsModule = module;
516 					break;
517 				}
518 			}
519 		}
520 
521 		list = list->next;
522 	}
523 	SECMOD_ReleaseReadLock (lock);
524 
525 	if (RootsModule) {
526 		/* Check version, and unload module if it is too old */
527 		CK_INFO info;
528 
529 		if (PK11_GetModInfo (RootsModule, &info) != SECSuccess) {
530 			/* Do not use this module */
531 			RootsModule = NULL;
532 		} else {
533 			/* NSS_BUILTINS_LIBRARY_VERSION_MAJOR and NSS_BUILTINS_LIBRARY_VERSION_MINOR
534 			 * define the version we expect to have.
535 			 * Later version are fine.
536 			 * Older versions are not ok, and we will replace with our own version.
537 			 */
538 			if ((info.libraryVersion.major < NSS_BUILTINS_LIBRARY_VERSION_MAJOR)
539 			    || (info.libraryVersion.major == NSS_BUILTINS_LIBRARY_VERSION_MAJOR
540 				&& info.libraryVersion.minor < NSS_BUILTINS_LIBRARY_VERSION_MINOR)) {
541 				PRInt32 modType;
542 
543 				SECMOD_DeleteModule (RootsModule->commonName, &modType);
544 
545 				RootsModule = NULL;
546 			}
547 		}
548 	}
549 
550 	if (!RootsModule) {
551 #ifndef G_OS_WIN32
552 		/* grovel in various places for mozilla's built-in
553 		 * cert module.
554 		 *
555 		 * XXX yes this is gross.  *sigh *
556 		*/
557 		const gchar *paths_to_check[] = {
558 #ifdef MOZILLA_NSS_LIB_DIR
559 			MOZILLA_NSS_LIB_DIR,
560 #endif
561 			"/usr/lib",
562 			"/usr/lib/mozilla",
563 			"/opt/mozilla/lib",
564 			"/opt/mozilla/lib/mozilla"
565 		};
566 
567 		for (i = 0; i < G_N_ELEMENTS (paths_to_check); i++) {
568 			gchar *dll_path = g_module_build_path (paths_to_check[i], "nssckbi");
569 
570 			if (g_file_test (dll_path, G_FILE_TEST_EXISTS)) {
571 				PRInt32 modType;
572 
573 				/* Delete the existing module */
574 				SECMOD_DeleteModule ("Mozilla Root Certs", &modType);
575 
576 				SECMOD_AddNewModule ("Mozilla Root Certs",dll_path, 0, 0);
577 				g_free (dll_path);
578 				break;
579 			}
580 
581 			g_free (dll_path);
582 		}
583 #else
584 		/* FIXME: Might be useful to look up if there is a
585 		 * Mozilla installation on the machine and use the
586 		 * nssckbi.dll from there.
587 		 */
588 #endif
589 	}
590 }
591 
592 static void
e_cert_db_class_init(ECertDBClass * class)593 e_cert_db_class_init (ECertDBClass *class)
594 {
595 	GObjectClass *object_class;
596 
597 	object_class = G_OBJECT_CLASS (class);
598 
599 	initialize_nss ();
600 	/* check to see if you have a rootcert module installed */
601 	install_loadable_roots ();
602 
603 	e_cert_db_signals[PK11_PASSWD] = g_signal_new (
604 		"pk11_passwd",
605 		G_OBJECT_CLASS_TYPE (object_class),
606 		G_SIGNAL_RUN_LAST,
607 		G_STRUCT_OFFSET (ECertDBClass, pk11_passwd),
608 		NULL, NULL,
609 		e_marshal_BOOLEAN__POINTER_BOOLEAN_POINTER,
610 		G_TYPE_BOOLEAN, 3,
611 		G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_POINTER);
612 
613 	e_cert_db_signals[PK11_CHANGE_PASSWD] = g_signal_new (
614 		"pk11_change_passwd",
615 		G_OBJECT_CLASS_TYPE (object_class),
616 		G_SIGNAL_RUN_LAST,
617 		G_STRUCT_OFFSET (ECertDBClass, pk11_change_passwd),
618 		NULL, NULL,
619 		e_marshal_BOOLEAN__POINTER_POINTER,
620 		G_TYPE_BOOLEAN, 2,
621 		G_TYPE_POINTER, G_TYPE_POINTER);
622 
623 	e_cert_db_signals[CONFIRM_CA_CERT_IMPORT] = g_signal_new (
624 		"confirm_ca_cert_import",
625 		G_OBJECT_CLASS_TYPE (object_class),
626 		G_SIGNAL_RUN_LAST,
627 		G_STRUCT_OFFSET (ECertDBClass, confirm_ca_cert_import),
628 		NULL, NULL,
629 		e_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
630 		G_TYPE_BOOLEAN, 4,
631 		G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
632 }
633 
634 static void
e_cert_db_init(ECertDB * ec)635 e_cert_db_init (ECertDB *ec)
636 {
637 }
638 
639 GMutex init_mutex;
640 static ECertDB *cert_db = NULL;
641 
642 ECertDB *
e_cert_db_peek(void)643 e_cert_db_peek (void)
644 {
645 	g_mutex_lock (&init_mutex);
646 	if (!cert_db)
647 		cert_db = g_object_new (E_TYPE_CERT_DB, NULL);
648 	g_mutex_unlock (&init_mutex);
649 
650 	return cert_db;
651 }
652 
653 void
e_cert_db_shutdown(void)654 e_cert_db_shutdown (void)
655 {
656 	/* XXX */
657 }
658 
659 static gboolean
confirm_download_ca_cert(ECertDB * cert_db,ECert * cert,gboolean * trust_ssl,gboolean * trust_email,gboolean * trust_objsign)660 confirm_download_ca_cert (ECertDB *cert_db,
661                           ECert *cert,
662                           gboolean *trust_ssl,
663                           gboolean *trust_email,
664                           gboolean *trust_objsign)
665 {
666 	gboolean rv = FALSE;
667 
668 	*trust_ssl =
669 		*trust_email =
670 		*trust_objsign = FALSE;
671 
672 	g_signal_emit (
673 		e_cert_db_peek (),
674 		e_cert_db_signals[CONFIRM_CA_CERT_IMPORT], 0,
675 		cert,
676 		trust_ssl,
677 		trust_email,
678 		trust_objsign,
679 		&rv);
680 
681 	return rv;
682 }
683 
684 static gboolean
handle_ca_cert_download(ECertDB * cert_db,GList * certs,GError ** error)685 handle_ca_cert_download (ECertDB *cert_db,
686                          GList *certs,
687                          GError **error)
688 {
689 	ECert *certToShow;
690 	SECItem der;
691 	gchar *raw_der = NULL;
692 	CERTCertificate *tmpCert;
693 
694 	/* First thing we have to do is figure out which certificate
695 	 * we're gonna present to the user.  The CA may have sent down
696 	 * a list of certs which may or may not be a chained list of
697 	 * certs.  Until the day we can design some solid UI for the
698 	 * general case, we'll code to the > 90% case.  That case is
699 	 * where a CA sends down a list that is a chain up to its root
700 	 * in either ascending or descending order.  What we're gonna
701 	 * do is compare the first 2 entries, if the first was signed
702 	 * by the second, we assume the leaf cert is the first cert
703 	 * and display it.  If the second cert was signed by the first
704 	 * cert, then we assume the first cert is the root and the
705 	 * last cert in the array is the leaf.  In this case we
706 	 * display the last cert.
707 	*/
708 
709 	/*  nsNSSShutDownPreventionLock locker;*/
710 
711 	if (certs == NULL) {
712 		g_warning ("Didn't get any certs to import.");
713 		return TRUE;
714 	}
715 	else if (certs->next == NULL) {
716 		/* there's 1 cert */
717 		certToShow = E_CERT (certs->data);
718 	}
719 	else {
720 		/* there are multiple certs */
721 		ECert *cert0;
722 		ECert *cert1;
723 		const gchar * cert0SubjectName;
724 		const gchar * cert0IssuerName;
725 		const gchar * cert1SubjectName;
726 		const gchar * cert1IssuerName;
727 
728 		cert0 = E_CERT (certs->data);
729 		cert1 = E_CERT (certs->next->data);
730 
731 		cert0IssuerName = e_cert_get_issuer_name (cert0);
732 		cert0SubjectName = e_cert_get_subject_name (cert0);
733 
734 		cert1IssuerName = e_cert_get_issuer_name (cert1);
735 		cert1SubjectName = e_cert_get_subject_name (cert1);
736 
737 		if (!strcmp (cert1IssuerName, cert0SubjectName)) {
738 			/* In this case, the first cert in the list signed the second,
739 			 * so the first cert is the root.  Let's display the last cert
740 			 * in the list. */
741 			certToShow = E_CERT (g_list_last (certs)->data);
742 		}
743 		else if (!strcmp (cert0IssuerName, cert1SubjectName)) {
744 			/* In this case the second cert has signed the first cert.  The
745 			 * first cert is the leaf, so let's display it. */
746 			certToShow = cert0;
747 		} else {
748 			/* It's not a chain, so let's just show the first one in the
749 			 * downloaded list. */
750 			certToShow = cert0;
751 		}
752 	}
753 
754 	if (!certToShow) {
755 		set_nss_error (error);
756 		return FALSE;
757 	}
758 
759 	if (!e_cert_get_raw_der (certToShow, &raw_der, &der.len)) {
760 		set_nss_error (error);
761 		return FALSE;
762 	}
763 
764 	der.data = (guchar *) raw_der;
765 
766 	{
767 		/*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Creating temp cert\n"));*/
768 		CERTCertDBHandle *certdb = CERT_GetDefaultCertDB ();
769 		tmpCert = CERT_FindCertByDERCert (certdb, &der);
770 		if (!tmpCert) {
771 			tmpCert = CERT_NewTempCertificate (
772 				certdb, &der,
773 				NULL, PR_FALSE, PR_TRUE);
774 		}
775 		if (!tmpCert) {
776 			g_warning ("Couldn't create cert from DER blob");
777 			set_nss_error (error);
778 			return FALSE;
779 		}
780 	}
781 
782 #if 0
783 	CERTCertificateCleaner tmpCertCleaner (tmpCert);
784 #endif
785 
786 	if (tmpCert->isperm) {
787 		if (error && !*error)
788 			*error = g_error_new_literal (E_CERTDB_ERROR, 0, _("Certificate already exists"));
789 		return FALSE;
790 	}
791 	else {
792 		gboolean trust_ssl, trust_email, trust_objsign;
793 		gchar *nickname;
794 		SECStatus srv;
795 		CERTCertTrust trust;
796 
797 		if (!confirm_download_ca_cert (
798 			cert_db, certToShow, &trust_ssl,
799 			&trust_email, &trust_objsign)) {
800 			set_nss_error (error);
801 			return FALSE;
802 		}
803 
804 		/*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("trust is %d\n", trustBits));*/
805 
806 		nickname = CERT_MakeCANickname (tmpCert);
807 
808 		/*PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Created nick \"%s\"\n", nickname.get()));*/
809 
810 		e_cert_trust_init (&trust);
811 		e_cert_trust_set_valid_ca (&trust);
812 		e_cert_trust_add_ca_trust (
813 			&trust,
814 			trust_ssl,
815 			trust_email,
816 			trust_objsign);
817 
818 		srv = CERT_AddTempCertToPerm (
819 			tmpCert,
820 			nickname,
821 			&trust);
822 
823 		/* If we aren't logged into the token, then what *should*
824 		 * happen is the above call should fail, and we should
825 		 * authenticate and then try again. But see NSS bug #595861.
826 		 * With NSS 3.12.6 at least, the above call will fail, but
827 		 * it *will* have added the cert to the database, with
828 		 * random trust bits. We have to authenticate and then set
829 		 * the trust bits correctly. And calling
830 		 * CERT_AddTempCertToPerm() again doesn't work either -- it'll
831 		 * fail even though it arguably ought to succeed (which is
832 		 * probably another NSS bug).
833 		 * So if we get SEC_ERROR_TOKEN_NOT_LOGGED_IN, we first try
834 		 * CERT_ChangeCertTrust(), and if that doesn't work we hope
835 		 * we're on a fixed version of NSS and we try calling
836 		 * CERT_AddTempCertToPerm() again instead. */
837 		if (srv != SECSuccess &&
838 		    PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
839 		    e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ())) {
840 			srv = CERT_ChangeCertTrust (
841 				CERT_GetDefaultCertDB (),
842 				tmpCert, &trust);
843 			if (srv != SECSuccess)
844 				srv = CERT_AddTempCertToPerm (
845 					tmpCert,
846 					nickname,
847 					&trust);
848 		}
849 		if (srv != SECSuccess) {
850 			set_nss_error (error);
851 			return FALSE;
852 		}
853 
854 #if 0
855 		/* Now it's time to add the rest of the certs we just downloaded.
856 		 * Since we didn't prompt the user about any of these certs, we
857 		 * won't set any trust bits for them. */
858 		e_cert_trust_init (&trust);
859 		e_cert_trust_set_valid_ca (&trust);
860 		e_cert_trusts_add_ca_trust (&trust, 0, 0, 0);
861 		for (PRUint32 i = 0; i < numCerts; i++) {
862 			if (i == selCertIndex)
863 				continue;
864 
865 			certToShow = do_QueryElementAt (x509Certs, i);
866 			certToShow->GetRawDER (&der.len, (PRUint8 **) &der.data);
867 
868 			CERTCertificate *tmpCert2 =
869 				CERT_NewTempCertificate (certdb, &der, nsnull, PR_FALSE, PR_TRUE);
870 
871 			if (!tmpCert2) {
872 				NS_ASSERTION (0, "Couldn't create temp cert from DER blob\n");
873 				continue;  /* Let's try to import the rest of 'em */
874 			}
875 			nickname.Adopt (CERT_MakeCANickname (tmpCert2));
876 			CERT_AddTempCertToPerm (
877 				tmpCert2, NS_CONST_CAST (gchar *,nickname.get ()),
878 				defaultTrust.GetTrust ());
879 			CERT_DestroyCertificate (tmpCert2);
880 		}
881 #endif
882 		return TRUE;
883 	}
884 }
e_cert_db_change_cert_trust(CERTCertificate * cert,CERTCertTrust * trust)885 gboolean e_cert_db_change_cert_trust (CERTCertificate *cert, CERTCertTrust *trust)
886 {
887 	SECStatus srv;
888 
889 	srv = CERT_ChangeCertTrust (
890 		CERT_GetDefaultCertDB (),
891 		cert, trust);
892 	if (srv != SECSuccess &&
893 	    PORT_GetError () == SEC_ERROR_TOKEN_NOT_LOGGED_IN &&
894 	    e_cert_db_login_to_slot (NULL, PK11_GetInternalKeySlot ()))
895 		srv = CERT_ChangeCertTrust (
896 			CERT_GetDefaultCertDB (),
897 			cert, trust);
898 
899 	if (srv != SECSuccess) {
900 		gint err = PORT_GetError ();
901 		g_warning (
902 			"CERT_ChangeCertTrust() failed: %s\n",
903 			e_cert_db_nss_error_to_string (err));
904 		return FALSE;
905 	}
906 	return TRUE;
907 }
908 
909 /* deleting certificates */
910 gboolean
e_cert_db_delete_cert(ECertDB * certdb,ECert * ecert)911 e_cert_db_delete_cert (ECertDB *certdb,
912                        ECert *ecert)
913 {
914 	/*  nsNSSShutDownPreventionLock locker;
915 	 *  nsNSSCertificate *nssCert = NS_STATIC_CAST (nsNSSCertificate *, aCert); */
916 
917 	CERTCertificate *cert;
918 
919 	cert = e_cert_get_internal_cert (ecert);
920 	if (!cert)
921 		return FALSE;
922 
923 	if (cert->slot && !e_cert_db_login_to_slot (certdb, cert->slot))
924 		return FALSE;
925 
926 	if (!e_cert_mark_for_deletion (ecert)) {
927 		return FALSE;
928 	}
929 
930 	if (cert->slot && e_cert_get_cert_type (ecert) != E_CERT_USER) {
931 		/* To delete a cert of a slot (builtin, most likely), mark it as
932 		 * completely untrusted.  This way we keep a copy cached in the
933 		 * local database, and next time we try to load it off of the
934 		 * external token/slot, we'll know not to trust it.  We don't
935 		 * want to do that with user certs, because a user may  re-store
936 		 * the cert onto the card again at which point we *will* want to
937 		 * trust that cert if it chains up properly. */
938 		CERTCertTrust trust;
939 
940 		e_cert_trust_init_with_values (&trust, 0, 0, 0);
941 		return e_cert_db_change_cert_trust (cert, &trust);
942 	}
943 
944 	return TRUE;
945 }
946 
947 /* importing certificates */
948 gboolean
e_cert_db_import_certs(ECertDB * certdb,gchar * data,guint32 length,ECertType cert_type,GSList ** imported_certs,GError ** error)949 e_cert_db_import_certs (ECertDB *certdb,
950                         gchar *data,
951                         guint32 length,
952                         ECertType cert_type,
953                         GSList **imported_certs,
954                         GError **error)
955 {
956 	/*nsNSSShutDownPreventionLock locker;*/
957 	PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
958 	GList *certs = NULL;
959 	CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
960 	gint i;
961 	gboolean rv;
962 
963 	if (!certCollection) {
964 		set_nss_error (error);
965 		PORT_FreeArena (arena, PR_FALSE);
966 		return FALSE;
967 	}
968 
969 	/* Now let's create some certs to work with */
970 	for (i = 0; i < certCollection->numcerts; i++) {
971 		SECItem *currItem = &certCollection->rawCerts[i];
972 		ECert *cert;
973 
974 		cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
975 		if (!cert) {
976 			set_nss_error (error);
977 			g_list_foreach (certs, (GFunc) g_object_unref, NULL);
978 			g_list_free (certs);
979 			PORT_FreeArena (arena, PR_FALSE);
980 			return FALSE;
981 		}
982 		certs = g_list_append (certs, cert);
983 	}
984 	switch (cert_type) {
985 	case E_CERT_CA:
986 		rv = handle_ca_cert_download (certdb, certs, error);
987 		if (rv && imported_certs) {
988 			GList *l;
989 
990 			/* copy certificates to the caller */
991 			*imported_certs = NULL;
992 			for (l = certs; l; l = l->next) {
993 				ECert *cert = l->data;
994 
995 				if (cert)
996 					*imported_certs = g_slist_prepend (*imported_certs, g_object_ref (cert));
997 			}
998 
999 			*imported_certs = g_slist_reverse (*imported_certs);
1000 		}
1001 		break;
1002 	default:
1003 		/* We only deal with import CA certs in this method currently.*/
1004 		set_nss_error (error);
1005 		PORT_FreeArena (arena, PR_FALSE);
1006 		rv = FALSE;
1007 	}
1008 
1009 	g_list_foreach (certs, (GFunc) g_object_unref, NULL);
1010 	g_list_free (certs);
1011 	PORT_FreeArena (arena, PR_FALSE);
1012 	return rv;
1013 }
1014 
1015 gboolean
e_cert_db_import_email_cert(ECertDB * certdb,gchar * data,guint32 length,GSList ** imported_certs,GError ** error)1016 e_cert_db_import_email_cert (ECertDB *certdb,
1017                              gchar *data,
1018                              guint32 length,
1019                              GSList **imported_certs,
1020                              GError **error)
1021 {
1022 	/*nsNSSShutDownPreventionLock locker;*/
1023 	SECStatus srv = SECFailure;
1024 	gboolean rv = TRUE;
1025 	CERTCertificate * cert;
1026 	SECItem **rawCerts;
1027 	gint numcerts;
1028 	gint i;
1029 	PRArenaPool *arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE);
1030 	CERTDERCerts *certCollection = e_cert_db_get_certs_from_package (arena, data, length);
1031 
1032 	if (!certCollection) {
1033 		set_nss_error (error);
1034 		PORT_FreeArena (arena, PR_FALSE);
1035 		return FALSE;
1036 	}
1037 
1038 	cert = CERT_NewTempCertificate (
1039 		CERT_GetDefaultCertDB (), certCollection->rawCerts,
1040 		(gchar *) NULL, PR_FALSE, PR_TRUE);
1041 	if (!cert) {
1042 		set_nss_error (error);
1043 		rv = FALSE;
1044 		goto loser;
1045 	}
1046 	numcerts = certCollection->numcerts;
1047 	rawCerts = (SECItem **) PORT_Alloc (sizeof (SECItem *) * numcerts);
1048 	if (!rawCerts) {
1049 		set_nss_error (error);
1050 		rv = FALSE;
1051 		goto loser;
1052 	}
1053 
1054 	for (i = 0; i < numcerts; i++) {
1055 		rawCerts[i] = &certCollection->rawCerts[i];
1056 	}
1057 
1058 	srv = CERT_ImportCerts (
1059 		CERT_GetDefaultCertDB (), certUsageEmailSigner,
1060 		numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
1061 		NULL);
1062 	if (srv != SECSuccess) {
1063 		set_nss_error (error);
1064 		rv = FALSE;
1065 		goto loser;
1066 	}
1067 	CERT_SaveSMimeProfile (cert, NULL, NULL);
1068 
1069 	if (imported_certs) {
1070 		*imported_certs = NULL;
1071 		for (i = 0; i < certCollection->numcerts; i++) {
1072 			SECItem *currItem = &certCollection->rawCerts[i];
1073 			ECert *cert;
1074 
1075 			cert = e_cert_new_from_der ((gchar *) currItem->data, currItem->len);
1076 			if (cert)
1077 				*imported_certs = g_slist_prepend (*imported_certs, cert);
1078 		}
1079 
1080 		*imported_certs = g_slist_reverse (*imported_certs);
1081 	}
1082 
1083 	PORT_Free (rawCerts);
1084  loser:
1085 	if (cert)
1086 		CERT_DestroyCertificate (cert);
1087 	if (arena)
1088 		PORT_FreeArena (arena, PR_TRUE);
1089 	return rv;
1090 }
1091 
1092 gboolean
e_cert_db_import_server_cert(ECertDB * certdb,gchar * data,guint32 length,GSList ** imported_certs,GError ** error)1093 e_cert_db_import_server_cert (ECertDB *certdb,
1094                               gchar *data,
1095                               guint32 length,
1096                               GSList **imported_certs,
1097                               GError **error)
1098 {
1099 	/* not c&p'ing this over at the moment, as we don't have a UI
1100 	 * for server certs anyway */
1101 	return FALSE;
1102 }
1103 
1104 gboolean
e_cert_db_import_certs_from_file(ECertDB * cert_db,const gchar * file_path,ECertType cert_type,GSList ** imported_certs,GError ** error)1105 e_cert_db_import_certs_from_file (ECertDB *cert_db,
1106                                   const gchar *file_path,
1107                                   ECertType cert_type,
1108                                   GSList **imported_certs,
1109                                   GError **error)
1110 {
1111 	gboolean rv;
1112 	gint fd;
1113 	struct stat sb;
1114 	gchar *buf;
1115 	gint bytes_read;
1116 
1117 	switch (cert_type) {
1118 	case E_CERT_CA:
1119 	case E_CERT_CONTACT:
1120 	case E_CERT_SITE:
1121 		/* good */
1122 		break;
1123 
1124 	default:
1125 		/* not supported (yet) */
1126 		set_nss_error (error);
1127 		return FALSE;
1128 	}
1129 
1130 	fd = g_open (file_path, O_RDONLY | O_BINARY, 0);
1131 	if (fd == -1) {
1132 		set_nss_error (error);
1133 		return FALSE;
1134 	}
1135 
1136 	if (-1 == fstat (fd, &sb)) {
1137 		set_nss_error (error);
1138 		close (fd);
1139 		return FALSE;
1140 	}
1141 
1142 	buf = g_malloc (sb.st_size);
1143 	if (!buf) {
1144 		set_nss_error (error);
1145 		close (fd);
1146 		return FALSE;
1147 	}
1148 
1149 	bytes_read = read (fd, buf, sb.st_size);
1150 
1151 	close (fd);
1152 
1153 	if (bytes_read != sb.st_size) {
1154 		set_nss_error (error);
1155 		rv = FALSE;
1156 	}
1157 	else {
1158 		printf ("importing %d bytes from '%s'\n", bytes_read, file_path);
1159 
1160 		switch (cert_type) {
1161 		case E_CERT_CA:
1162 			rv = e_cert_db_import_certs (cert_db, buf, bytes_read, cert_type, imported_certs, error);
1163 			break;
1164 
1165 		case E_CERT_SITE:
1166 			rv = e_cert_db_import_server_cert (cert_db, buf, bytes_read, imported_certs, error);
1167 			break;
1168 
1169 		case E_CERT_CONTACT:
1170 			rv = e_cert_db_import_email_cert (cert_db, buf, bytes_read, imported_certs, error);
1171 			break;
1172 
1173 		/* coverity[dead_error_begin] */
1174 		default:
1175 			rv = FALSE;
1176 			break;
1177 		}
1178 	}
1179 
1180 	g_free (buf);
1181 	return rv;
1182 }
1183 
1184 gboolean
e_cert_db_import_pkcs12_file(ECertDB * cert_db,const gchar * file_path,GError ** error)1185 e_cert_db_import_pkcs12_file (ECertDB *cert_db,
1186                               const gchar *file_path,
1187                               GError **error)
1188 {
1189 	EPKCS12 *pkcs12 = e_pkcs12_new ();
1190 	GError *e = NULL;
1191 
1192 	if (!e_pkcs12_import_from_file (pkcs12, file_path, &e)) {
1193 		g_propagate_error (error, e);
1194 		return FALSE;
1195 	}
1196 
1197 	return TRUE;
1198 }
1199 
1200 gboolean
e_cert_db_export_pkcs12_file(ECert * cert,GFile * file,const gchar * password,gboolean save_chain,GError ** error)1201 e_cert_db_export_pkcs12_file (ECert *cert,
1202                               GFile *file,
1203                               const gchar *password,
1204                               gboolean save_chain,
1205                               GError **error)
1206 {
1207 	GError *e = NULL;
1208 	GList *list = NULL;
1209 
1210 	g_return_val_if_fail (cert != NULL, FALSE);
1211 	list = g_list_append (list, cert);
1212 
1213 	if (!e_pkcs12_export_to_file (list, file, password, save_chain, &e)) {
1214 		g_list_free (list);
1215 		g_propagate_error (error, e);
1216 		return FALSE;
1217 	}
1218 
1219 	g_list_free (list);
1220 
1221 	return TRUE;
1222 }
1223 
1224 gboolean
e_cert_db_login_to_slot(ECertDB * cert_db,PK11SlotInfo * slot)1225 e_cert_db_login_to_slot (ECertDB *cert_db,
1226                          PK11SlotInfo *slot)
1227 {
1228 	if (PK11_NeedLogin (slot)) {
1229 		PK11_Logout (slot);
1230 
1231 		if (PK11_NeedUserInit (slot)) {
1232 			gchar *pwd;
1233 			gboolean rv = FALSE;
1234 
1235 			printf ("initializing slot password\n");
1236 
1237 			g_signal_emit (
1238 				e_cert_db_peek (),
1239 				e_cert_db_signals[PK11_CHANGE_PASSWD], 0,
1240 				NULL,
1241 				&pwd,
1242 				&rv);
1243 
1244 			if (!rv)
1245 				return FALSE;
1246 
1247 			/* the user needs to specify the initial password */
1248 			PK11_InitPin (slot, "", pwd);
1249 		}
1250 
1251 		PK11_SetPasswordFunc (pk11_password);
1252 		if (PK11_Authenticate (slot, PR_TRUE, NULL) != SECSuccess) {
1253 			printf (
1254 				"PK11_Authenticate failed (err = %d/%d)\n",
1255 				PORT_GetError (), PORT_GetError () + 0x2000);
1256 			return FALSE;
1257 		}
1258 	}
1259 
1260 	return TRUE;
1261 }
1262