1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
4 * Michael Zucchi <notzed@ximian.com>
6 * The Initial Developer of the Original Code is Netscape
7 * Communications Corporation. Portions created by Netscape are
8 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
11 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
48 #include <glib/gi18n-lib.h>
50 #include "camel-data-wrapper.h"
51 #include "camel-mime-filter-basic.h"
52 #include "camel-mime-filter-canon.h"
53 #include "camel-mime-part.h"
54 #include "camel-multipart-signed.h"
55 #include "camel-operation.h"
56 #include "camel-session.h"
57 #include "camel-smime-context.h"
58 #include "camel-stream-filter.h"
59 #include "camel-stream-fs.h"
60 #include "camel-stream-mem.h"
64 #define CAMEL_SMIME_CONTEXT_GET_PRIVATE(obj) \
65 (G_TYPE_INSTANCE_GET_PRIVATE \
66 ((obj), CAMEL_TYPE_SMIME_CONTEXT, CamelSMIMEContextPrivate))
68 struct _CamelSMIMEContextPrivate {
69 CERTCertDBHandle *certdb;
72 camel_smime_sign_t sign_mode;
75 guint send_encrypt_key_prefs : 1;
78 G_DEFINE_TYPE (CamelSMIMEContext, camel_smime_context, CAMEL_TYPE_CIPHER_CONTEXT)
81 smime_cert_data_free (gpointer cert_data)
83 g_return_if_fail (cert_data != NULL);
85 CERT_DestroyCertificate (cert_data);
89 smime_cert_data_clone (gpointer cert_data)
91 g_return_val_if_fail (cert_data != NULL, NULL);
93 return CERT_DupCertificate (cert_data);
96 /* used for decode content callback, for streaming decode */
98 sm_write_stream (gpointer arg,
102 camel_stream_write ((CamelStream *) arg, buf, len, NULL, NULL);
106 sm_decrypt_key (gpointer arg,
107 SECAlgorithmID *algid)
109 printf ("Decrypt key called\n");
110 return (PK11SymKey *) arg;
114 nss_error_to_string (glong errorcode)
116 #define cs(a,b) case a: return b;
119 cs (SEC_ERROR_IO, "An I/O error occurred during security authorization.")
120 cs (SEC_ERROR_LIBRARY_FAILURE, "security library failure.")
121 cs (SEC_ERROR_BAD_DATA, "security library: received bad data.")
122 cs (SEC_ERROR_OUTPUT_LEN, "security library: output length error.")
123 cs (SEC_ERROR_INPUT_LEN, "security library has experienced an input length error.")
124 cs (SEC_ERROR_INVALID_ARGS, "security library: invalid arguments.")
125 cs (SEC_ERROR_INVALID_ALGORITHM, "security library: invalid algorithm.")
126 cs (SEC_ERROR_INVALID_AVA, "security library: invalid AVA.")
127 cs (SEC_ERROR_INVALID_TIME, "Improperly formatted time string.")
128 cs (SEC_ERROR_BAD_DER, "security library: improperly formatted DER-encoded message.")
129 cs (SEC_ERROR_BAD_SIGNATURE, "Peer's certificate has an invalid signature.")
130 cs (SEC_ERROR_EXPIRED_CERTIFICATE, "Peer's Certificate has expired.")
131 cs (SEC_ERROR_REVOKED_CERTIFICATE, "Peer's Certificate has been revoked.")
132 cs (SEC_ERROR_UNKNOWN_ISSUER, "Peer's Certificate issuer is not recognized.")
133 cs (SEC_ERROR_BAD_KEY, "Peer's public key is invalid.")
134 cs (SEC_ERROR_BAD_PASSWORD, "The security password entered is incorrect.")
135 cs (SEC_ERROR_RETRY_PASSWORD, "New password entered incorrectly. Please try again.")
136 cs (SEC_ERROR_NO_NODELOCK, "security library: no nodelock.")
137 cs (SEC_ERROR_BAD_DATABASE, "security library: bad database.")
138 cs (SEC_ERROR_NO_MEMORY, "security library: memory allocation failure.")
139 cs (SEC_ERROR_UNTRUSTED_ISSUER, "Peer's certificate issuer has been marked as not trusted by the user.")
140 cs (SEC_ERROR_UNTRUSTED_CERT, "Peer's certificate has been marked as not trusted by the user.")
141 cs (SEC_ERROR_DUPLICATE_CERT, "Certificate already exists in your database.")
142 cs (SEC_ERROR_DUPLICATE_CERT_NAME, "Downloaded certificate's name duplicates one already in your database.")
143 cs (SEC_ERROR_ADDING_CERT, "Error adding certificate to database.")
144 cs (SEC_ERROR_FILING_KEY, "Error refiling the key for this certificate.")
145 cs (SEC_ERROR_NO_KEY, "The private key for this certificate cannot be found in key database")
146 cs (SEC_ERROR_CERT_VALID, "This certificate is valid.")
147 cs (SEC_ERROR_CERT_NOT_VALID, "This certificate is not valid.")
148 cs (SEC_ERROR_CERT_NO_RESPONSE, "Cert Library: No Response")
149 cs (SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, "The certificate issuer's certificate has expired. Check your system date and time.")
150 cs (SEC_ERROR_CRL_EXPIRED, "The CRL for the certificate's issuer has expired. Update it or check your system date and time.")
151 cs (SEC_ERROR_CRL_BAD_SIGNATURE, "The CRL for the certificate's issuer has an invalid signature.")
152 cs (SEC_ERROR_CRL_INVALID, "New CRL has an invalid format.")
153 cs (SEC_ERROR_EXTENSION_VALUE_INVALID, "Certificate extension value is invalid.")
154 cs (SEC_ERROR_EXTENSION_NOT_FOUND, "Certificate extension not found.")
155 cs (SEC_ERROR_CA_CERT_INVALID, "Issuer certificate is invalid.")
156 cs (SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, "Certificate path length constraint is invalid.")
157 cs (SEC_ERROR_CERT_USAGES_INVALID, "Certificate usages field is invalid.")
158 cs (SEC_INTERNAL_ONLY, "**Internal ONLY module**")
159 cs (SEC_ERROR_INVALID_KEY, "The key does not support the requested operation.")
160 cs (SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, "Certificate contains unknown critical extension.")
161 cs (SEC_ERROR_OLD_CRL, "New CRL is not later than the current one.")
162 cs (SEC_ERROR_NO_EMAIL_CERT, "Not encrypted or signed: you do not yet have an email certificate.")
163 cs (SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, "Not encrypted: you do not have certificates for each of the recipients.")
164 cs (SEC_ERROR_NOT_A_RECIPIENT, "Cannot decrypt: you are not a recipient, or matching certificate and private key not found.")
165 cs (SEC_ERROR_PKCS7_KEYALG_MISMATCH, "Cannot decrypt: key encryption algorithm does not match your certificate.")
166 cs (SEC_ERROR_PKCS7_BAD_SIGNATURE, "Signature verification failed: no signer found, too many signers found, or improper or corrupted data.")
167 cs (SEC_ERROR_UNSUPPORTED_KEYALG, "Unsupported or unknown key algorithm.")
168 cs (SEC_ERROR_DECRYPTION_DISALLOWED, "Cannot decrypt: encrypted using a disallowed algorithm or key size.")
169 cs (XP_SEC_FORTEZZA_BAD_CARD, "Fortezza card has not been properly initialized. Please remove it and return it to your issuer.")
170 cs (XP_SEC_FORTEZZA_NO_CARD, "No Fortezza cards Found")
171 cs (XP_SEC_FORTEZZA_NONE_SELECTED, "No Fortezza card selected")
172 cs (XP_SEC_FORTEZZA_MORE_INFO, "Please select a personality to get more info on")
173 cs (XP_SEC_FORTEZZA_PERSON_NOT_FOUND, "Personality not found")
174 cs (XP_SEC_FORTEZZA_NO_MORE_INFO, "No more information on that Personality")
175 cs (XP_SEC_FORTEZZA_BAD_PIN, "Invalid Pin")
176 cs (XP_SEC_FORTEZZA_PERSON_ERROR, "Couldn't initialize Fortezza personalities.")
177 cs (SEC_ERROR_NO_KRL, "No KRL for this site's certificate has been found.")
178 cs (SEC_ERROR_KRL_EXPIRED, "The KRL for this site's certificate has expired.")
179 cs (SEC_ERROR_KRL_BAD_SIGNATURE, "The KRL for this site's certificate has an invalid signature.")
180 cs (SEC_ERROR_REVOKED_KEY, "The key for this site's certificate has been revoked.")
181 cs (SEC_ERROR_KRL_INVALID, "New KRL has an invalid format.")
182 cs (SEC_ERROR_NEED_RANDOM, "security library: need random data.")
183 cs (SEC_ERROR_NO_MODULE, "security library: no security module can perform the requested operation.")
184 cs (SEC_ERROR_NO_TOKEN, "The security card or token does not exist, needs to be initialized, or has been removed.")
185 cs (SEC_ERROR_READ_ONLY, "security library: read-only database.")
186 cs (SEC_ERROR_NO_SLOT_SELECTED, "No slot or token was selected.")
187 cs (SEC_ERROR_CERT_NICKNAME_COLLISION, "A certificate with the same nickname already exists.")
188 cs (SEC_ERROR_KEY_NICKNAME_COLLISION, "A key with the same nickname already exists.")
189 cs (SEC_ERROR_SAFE_NOT_CREATED, "error while creating safe object")
190 cs (SEC_ERROR_BAGGAGE_NOT_CREATED, "error while creating baggage object")
191 cs (XP_JAVA_REMOVE_PRINCIPAL_ERROR, "Couldn't remove the principal")
192 cs (XP_JAVA_DELETE_PRIVILEGE_ERROR, "Couldn't delete the privilege")
193 cs (XP_JAVA_CERT_NOT_EXISTS_ERROR, "This principal doesn't have a certificate")
194 cs (SEC_ERROR_BAD_EXPORT_ALGORITHM, "Required algorithm is not allowed.")
195 cs (SEC_ERROR_EXPORTING_CERTIFICATES, "Error attempting to export certificates.")
196 cs (SEC_ERROR_IMPORTING_CERTIFICATES, "Error attempting to import certificates.")
197 cs (SEC_ERROR_PKCS12_DECODING_PFX, "Unable to import. Decoding error. File not valid.")
198 cs (SEC_ERROR_PKCS12_INVALID_MAC, "Unable to import. Invalid MAC. Incorrect password or corrupt file.")
199 cs (SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, "Unable to import. MAC algorithm not supported.")
200 cs (SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE, "Unable to import. Only password integrity and privacy modes supported.")
201 cs (SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, "Unable to import. File structure is corrupt.")
202 cs (SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, "Unable to import. Encryption algorithm not supported.")
203 cs (SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, "Unable to import. File version not supported.")
204 cs (SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT, "Unable to import. Incorrect privacy password.")
205 cs (SEC_ERROR_PKCS12_CERT_COLLISION, "Unable to import. Same nickname already exists in database.")
206 cs (SEC_ERROR_USER_CANCELLED, "The user pressed cancel.")
207 cs (SEC_ERROR_PKCS12_DUPLICATE_DATA, "Not imported, already in database.")
208 cs (SEC_ERROR_MESSAGE_SEND_ABORTED, "Message not sent.")
209 cs (SEC_ERROR_INADEQUATE_KEY_USAGE, "Certificate key usage inadequate for attempted operation.")
210 cs (SEC_ERROR_INADEQUATE_CERT_TYPE, "Certificate type not approved for application.")
211 cs (SEC_ERROR_CERT_ADDR_MISMATCH, "Address in signing certificate does not match address in message headers.")
212 cs (SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, "Unable to import. Error attempting to import private key.")
213 cs (SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, "Unable to import. Error attempting to import certificate chain.")
214 cs (SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, "Unable to export. Unable to locate certificate or key by nickname.")
215 cs (SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, "Unable to export. Private Key could not be located and exported.")
216 cs (SEC_ERROR_PKCS12_UNABLE_TO_WRITE, "Unable to export. Unable to write the export file.")
217 cs (SEC_ERROR_PKCS12_UNABLE_TO_READ, "Unable to import. Unable to read the import file.")
218 cs (SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, "Unable to export. Key database corrupt or deleted.")
219 cs (SEC_ERROR_KEYGEN_FAIL, "Unable to generate public/private key pair.")
220 cs (SEC_ERROR_INVALID_PASSWORD, "Password entered is invalid. Please pick a different one.")
221 cs (SEC_ERROR_RETRY_OLD_PASSWORD, "Old password entered incorrectly. Please try again.")
222 cs (SEC_ERROR_BAD_NICKNAME, "Certificate nickname already in use.")
223 cs (SEC_ERROR_NOT_FORTEZZA_ISSUER, "Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
224 cs (SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, "A sensitive key cannot be moved to the slot where it is needed.")
225 cs (SEC_ERROR_JS_INVALID_MODULE_NAME, "Invalid module name.")
226 cs (SEC_ERROR_JS_INVALID_DLL, "Invalid module path/filename")
227 cs (SEC_ERROR_JS_ADD_MOD_FAILURE, "Unable to add module")
228 cs (SEC_ERROR_JS_DEL_MOD_FAILURE, "Unable to delete module")
229 cs (SEC_ERROR_OLD_KRL, "New KRL is not later than the current one.")
230 cs (SEC_ERROR_CKL_CONFLICT, "New CKL has different issuer than current CKL. Delete current CKL.")
231 cs (SEC_ERROR_CERT_NOT_IN_NAME_SPACE, "The Certifying Authority for this certificate is not permitted to issue a certificate with this name.")
232 cs (SEC_ERROR_KRL_NOT_YET_VALID, "The key revocation list for this certificate is not yet valid.")
233 cs (SEC_ERROR_CRL_NOT_YET_VALID, "The certificate revocation list for this certificate is not yet valid.")
234 cs (SEC_ERROR_UNKNOWN_CERT, "The requested certificate could not be found.")
235 cs (SEC_ERROR_UNKNOWN_SIGNER, "The signer's certificate could not be found.")
236 cs (SEC_ERROR_CERT_BAD_ACCESS_LOCATION, "The location for the certificate status server has invalid format.")
237 cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, "The OCSP response cannot be fully decoded; it is of an unknown type.")
238 cs (SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, "The OCSP server returned unexpected/invalid HTTP data.")
239 cs (SEC_ERROR_OCSP_MALFORMED_REQUEST, "The OCSP server found the request to be corrupted or improperly formed.")
240 cs (SEC_ERROR_OCSP_SERVER_ERROR, "The OCSP server experienced an internal error.")
241 cs (SEC_ERROR_OCSP_TRY_SERVER_LATER, "The OCSP server suggests trying again later.")
242 cs (SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, "The OCSP server requires a signature on this request.")
243 cs (SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, "The OCSP server has refused this request as unauthorized.")
244 cs (SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, "The OCSP server returned an unrecognizable status.")
245 cs (SEC_ERROR_OCSP_UNKNOWN_CERT, "The OCSP server has no status for the certificate.")
246 cs (SEC_ERROR_OCSP_NOT_ENABLED, "You must enable OCSP before performing this operation.")
247 cs (SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, "You must set the OCSP default responder before performing this operation.")
248 cs (SEC_ERROR_OCSP_MALFORMED_RESPONSE, "The response from the OCSP server was corrupted or improperly formed.")
249 cs (SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, "The signer of the OCSP response is not authorized to give status for this certificate.")
250 cs (SEC_ERROR_OCSP_FUTURE_RESPONSE, "The OCSP response is not yet valid (contains a date in the future).")
251 cs (SEC_ERROR_OCSP_OLD_RESPONSE, "The OCSP response contains out-of-date information.")
252 cs (SEC_ERROR_DIGEST_NOT_FOUND, "The CMS or PKCS #7 Digest was not found in signed message.")
253 cs (SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, "The CMS or PKCS #7 Message type is unsupported.")
254 cs (SEC_ERROR_MODULE_STUCK, "PKCS #11 module could not be removed because it is still in use.")
255 cs (SEC_ERROR_BAD_TEMPLATE, "Could not decode ASN.1 data. Specified template was invalid.")
256 cs (SEC_ERROR_CRL_NOT_FOUND, "No matching CRL was found.")
257 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.")
258 cs (SEC_ERROR_BUSY, "NSS could not shutdown. Objects are still in use.")
259 cs (SEC_ERROR_EXTRA_INPUT, "DER-encoded message contained extra unused data.")
260 cs (SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, "Unsupported elliptic curve.")
261 cs (SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, "Unsupported elliptic curve point form.")
262 cs (SEC_ERROR_UNRECOGNIZED_OID, "Unrecognized Object Identifier.")
263 cs (SEC_ERROR_OCSP_INVALID_SIGNING_CERT, "Invalid OCSP signing certificate in OCSP response.")
264 cs (SEC_ERROR_REVOKED_CERTIFICATE_CRL, "Certificate is revoked in issuer's certificate revocation list.")
265 cs (SEC_ERROR_REVOKED_CERTIFICATE_OCSP, "Issuer's OCSP responder reports certificate is revoked.")
266 cs (SEC_ERROR_CRL_INVALID_VERSION, "Issuer's Certificate Revocation List has an unknown version number.")
267 cs (SEC_ERROR_CRL_V1_CRITICAL_EXTENSION, "Issuer's V1 Certificate Revocation List has a critical extension.")
268 cs (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION, "Issuer's V2 Certificate Revocation List has an unknown critical extension.")
269 cs (SEC_ERROR_UNKNOWN_OBJECT_TYPE, "Unknown object type specified.")
270 cs (SEC_ERROR_INCOMPATIBLE_PKCS11, "PKCS #11 driver violates the spec in an incompatible way.")
271 cs (SEC_ERROR_NO_EVENT, "No new slot event is available at this time.")
272 cs (SEC_ERROR_CRL_ALREADY_EXISTS, "CRL already exists.")
273 cs (SEC_ERROR_NOT_INITIALIZED, "NSS is not initialized.")
274 cs (SEC_ERROR_TOKEN_NOT_LOGGED_IN, "The operation failed because the PKCS#11 token is not logged in.")
275 cs (SEC_ERROR_OCSP_RESPONDER_CERT_INVALID, "Configured OCSP responder's certificate is invalid.")
276 cs (SEC_ERROR_OCSP_BAD_SIGNATURE, "OCSP response has an invalid signature.")
278 #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))
279 cs (SEC_ERROR_OUT_OF_SEARCH_LIMITS, "Cert validation search is out of search limits")
280 cs (SEC_ERROR_INVALID_POLICY_MAPPING, "Policy mapping contains anypolicy")
281 cs (SEC_ERROR_POLICY_VALIDATION_FAILED, "Cert chain fails policy validation")
282 cs (SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE, "Unknown location type in cert AIA extension")
283 cs (SEC_ERROR_BAD_HTTP_RESPONSE, "Server returned bad HTTP response")
284 cs (SEC_ERROR_BAD_LDAP_RESPONSE, "Server returned bad LDAP response")
285 cs (SEC_ERROR_FAILED_TO_ENCODE_DATA, "Failed to encode data with ASN1 encoder")
286 cs (SEC_ERROR_BAD_INFO_ACCESS_LOCATION, "Bad information access location in cert extension")
287 cs (SEC_ERROR_LIBPKIX_INTERNAL, "Libpkix internal error occurred during cert validation.")
288 cs (SEC_ERROR_PKCS11_GENERAL_ERROR, "A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.")
289 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.")
290 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.")
300 set_nss_error (GError **error,
301 const gchar *def_error)
305 g_return_if_fail (def_error != NULL);
307 err_code = PORT_GetError ();
311 error, CAMEL_SERVICE_ERROR,
312 CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
315 const gchar *err_str;
317 err_str = nss_error_to_string (err_code);
319 err_str = "Uknown error.";
322 error, CAMEL_SERVICE_ERROR,
323 CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
324 "%s (%d) - %s", err_str, (gint) err_code, def_error);
328 static NSSCMSMessage *
329 sm_signing_cmsmessage (CamelSMIMEContext *context,
335 CamelSMIMEContextPrivate *p = context->priv;
336 NSSCMSMessage *cmsg = NULL;
337 NSSCMSContentInfo *cinfo;
338 NSSCMSSignedData *sigd;
339 NSSCMSSignerInfo *signerinfo;
340 CERTCertificate *cert= NULL, *ekpcert = NULL;
342 g_return_val_if_fail (hash != NULL, NULL);
344 if ((cert = CERT_FindUserCertByUsage (p->certdb,
346 certUsageEmailSigner,
350 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
351 _("Cannot find certificate for '%s'"), nick);
355 if (*hash == SEC_OID_UNKNOWN) {
356 /* use signature algorithm from the certificate */
357 switch (SECOID_GetAlgorithmTag (&cert->signature)) {
358 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
359 *hash = SEC_OID_SHA256;
361 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
362 *hash = SEC_OID_SHA384;
364 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
365 *hash = SEC_OID_SHA512;
367 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
370 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
372 *hash = SEC_OID_SHA1;
377 cmsg = NSS_CMSMessage_Create (NULL); /* create a message on its own pool */
379 set_nss_error (error, _("Cannot create CMS message"));
383 if ((sigd = NSS_CMSSignedData_Create (cmsg)) == NULL) {
384 set_nss_error (error, _("Cannot create CMS signed data"));
388 cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
389 if (NSS_CMSContentInfo_SetContent_SignedData (cmsg, cinfo, sigd) != SECSuccess) {
390 set_nss_error (error, _("Cannot attach CMS signed data"));
394 /* if !detatched, the contentinfo will alloc a data item for us */
395 cinfo = NSS_CMSSignedData_GetContentInfo (sigd);
396 if (NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, detached) != SECSuccess) {
397 set_nss_error (error, _("Cannot attach CMS data"));
401 signerinfo = NSS_CMSSignerInfo_Create (cmsg, cert, *hash);
402 if (signerinfo == NULL) {
403 set_nss_error (error, _("Cannot create CMS Signer information"));
407 /* we want the cert chain included for this one */
408 if (NSS_CMSSignerInfo_IncludeCerts (signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) {
409 set_nss_error (error, _("Cannot find certificate chain"));
413 /* SMIME RFC says signing time should always be added */
414 if (NSS_CMSSignerInfo_AddSigningTime (signerinfo, PR_Now ()) != SECSuccess) {
415 set_nss_error (error, _("Cannot add CMS Signing time"));
420 /* this can but needn't be added. not sure what general usage is */
421 if (NSS_CMSSignerInfo_AddSMIMECaps (signerinfo) != SECSuccess) {
422 fprintf (stderr, "ERROR: cannot add SMIMECaps attribute.\n");
427 /* Check if we need to send along our return encrypt cert, rfc2633 2.5.3 */
428 if (p->send_encrypt_key_prefs) {
429 CERTCertificate *enccert = NULL;
431 if (p->encrypt_key) {
432 /* encrypt key has its own nick */
433 if ((ekpcert = CERT_FindUserCertByUsage (
436 certUsageEmailRecipient, PR_TRUE, NULL)) == NULL) {
438 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
439 _("Encryption certificate for '%s' does not exist"),
444 } else if (CERT_CheckCertUsage (cert, certUsageEmailRecipient) == SECSuccess) {
445 /* encrypt key is signing key */
448 /* encrypt key uses same nick */
449 if ((ekpcert = CERT_FindUserCertByUsage (
450 p->certdb, (gchar *) nick,
451 certUsageEmailRecipient, PR_TRUE, NULL)) == NULL) {
453 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
454 _("Encryption certificate for '%s' does not exist"), nick);
460 if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs (signerinfo, enccert, p->certdb) != SECSuccess) {
461 set_nss_error (error, _("Cannot add SMIMEEncKeyPrefs attribute"));
465 if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs (signerinfo, enccert, p->certdb) != SECSuccess) {
466 set_nss_error (error, _("Cannot add MS SMIMEEncKeyPrefs attribute"));
470 if (ekpcert != NULL && NSS_CMSSignedData_AddCertificate (sigd, ekpcert) != SECSuccess) {
471 set_nss_error (error, _("Cannot add encryption certificate"));
476 if (NSS_CMSSignedData_AddSignerInfo (sigd, signerinfo) != SECSuccess) {
477 set_nss_error (error, _("Cannot add CMS Signer information"));
482 CERT_DestroyCertificate (ekpcert);
485 CERT_DestroyCertificate (cert);
490 CERT_DestroyCertificate (ekpcert);
493 CERT_DestroyCertificate (cert);
495 NSS_CMSMessage_Destroy (cmsg);
501 sm_status_description (NSSCMSVerificationStatus status)
503 /* could use this but then we can't control i18n? */
504 /*NSS_CMSUtil_VerificationStatusToString (status));*/
507 case NSSCMSVS_Unverified:
509 /* Translators: A fallback message when couldn't verify an SMIME signature */
510 return _("Unverified");
511 case NSSCMSVS_GoodSignature:
512 return _("Good signature");
513 case NSSCMSVS_BadSignature:
514 return _("Bad signature");
515 case NSSCMSVS_DigestMismatch:
516 return _("Content tampered with or altered in transit");
517 case NSSCMSVS_SigningCertNotFound:
518 return _("Signing certificate not found");
519 case NSSCMSVS_SigningCertNotTrusted:
520 return _("Signing certificate not trusted");
521 case NSSCMSVS_SignatureAlgorithmUnknown:
522 return _("Signature algorithm unknown");
523 case NSSCMSVS_SignatureAlgorithmUnsupported:
524 return _("Signature algorithm unsupported");
525 case NSSCMSVS_MalformedSignature:
526 return _("Malformed signature");
527 case NSSCMSVS_ProcessingError:
528 return _("Processing error");
532 static CamelCipherValidity *
533 sm_verify_cmsg (CamelCipherContext *context,
535 CamelStream *extstream,
536 GCancellable *cancellable,
539 CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *) context)->priv;
540 NSSCMSSignedData *sigd = NULL;
542 NSSCMSEnvelopedData *envd;
543 NSSCMSEncryptedData *encd;
545 SECAlgorithmID **digestalgs;
546 NSSCMSDigestContext *digcx;
547 gint count, i, nsigners, j;
549 PLArenaPool *poolp = NULL;
551 NSSCMSVerificationStatus status;
552 CamelCipherValidity *valid;
553 GString *description;
555 description = g_string_new ("");
556 valid = camel_cipher_validity_new ();
557 camel_cipher_validity_set_valid (valid, TRUE);
558 status = NSSCMSVS_Unverified;
560 /* NB: this probably needs to go into a decoding routine that can be used for processing
561 * enveloped data too */
562 count = NSS_CMSMessage_ContentLevelCount (cmsg);
563 for (i = 0; i < count; i++) {
564 NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel (cmsg, i);
565 SECOidTag typetag = NSS_CMSContentInfo_GetContentTypeTag (cinfo);
570 case SEC_OID_PKCS7_SIGNED_DATA:
571 sigd = (NSSCMSSignedData *) NSS_CMSContentInfo_GetContent (cinfo);
573 set_nss_error (error, _("No signed data in signature"));
577 if (extstream == NULL) {
578 set_nss_error (error, _("Digests missing from enveloped data"));
582 if ((poolp = PORT_NewArena (1024)) == NULL) {
583 set_nss_error (error, g_strerror (ENOMEM));
587 digestalgs = NSS_CMSSignedData_GetDigestAlgs (sigd);
589 digcx = NSS_CMSDigestContext_StartMultiple (digestalgs);
591 set_nss_error (error, _("Cannot calculate digests"));
595 buffer = g_byte_array_new ();
596 mem = camel_stream_mem_new_with_byte_array (buffer);
597 camel_stream_write_to_stream (extstream, mem, cancellable, NULL);
598 NSS_CMSDigestContext_Update (digcx, buffer->data, buffer->len);
599 g_object_unref (mem);
601 if (NSS_CMSDigestContext_FinishMultiple (digcx, poolp, &digests) != SECSuccess) {
602 set_nss_error (error, _("Cannot calculate digests"));
606 for (which_digest = 0; digests[which_digest] != NULL; which_digest++) {
607 SECOidData *digest_alg = SECOID_FindOID (&digestalgs[which_digest]->algorithm);
608 if (digest_alg == NULL) {
609 set_nss_error (error, _("Cannot set message digests"));
612 if (NSS_CMSSignedData_SetDigestValue (sigd, digest_alg->offset, digests[which_digest]) != SECSuccess) {
613 set_nss_error (error, _("Cannot set message digests"));
618 PORT_FreeArena (poolp, PR_FALSE);
621 /* import all certificates present */
622 if (NSS_CMSSignedData_ImportCerts (sigd, p->certdb, certUsageEmailSigner, PR_TRUE) != SECSuccess) {
623 set_nss_error (error, _("Certificate import failed"));
627 if (NSS_CMSSignedData_ImportCerts (sigd, p->certdb, certUsageEmailRecipient, PR_TRUE) != SECSuccess) {
628 set_nss_error (error, _("Certificate import failed"));
632 /* check for certs-only message */
633 nsigners = NSS_CMSSignedData_SignerInfoCount (sigd);
636 /* already imported certs above, not sure what usage we should use here or if this isn't handled above */
637 if (NSS_CMSSignedData_VerifyCertsOnly (sigd, p->certdb, certUsageEmailSigner) != SECSuccess) {
638 g_string_printf (description, _("Certificate is the only message, cannot verify certificates"));
640 status = NSSCMSVS_GoodSignature;
641 g_string_printf (description, _("Certificate is the only message, certificates imported and verified"));
644 if (!NSS_CMSSignedData_HasDigests (sigd)) {
645 set_nss_error (error, _("Cannot find signature digests"));
649 for (j = 0; j < nsigners; j++) {
650 NSSCMSSignerInfo *si;
653 si = NSS_CMSSignedData_GetSignerInfo (sigd, j);
654 NSS_CMSSignedData_VerifySignerInfo (sigd, j, p->certdb, certUsageEmailSigner);
656 status = NSS_CMSSignerInfo_GetVerificationStatus (si);
658 cn = NSS_CMSSignerInfo_GetSignerCommonName (si);
659 em = NSS_CMSSignerInfo_GetSignerEmailAddress (si);
661 g_string_append_printf (
662 description, _("Signer: %s <%s>: %s\n"),
663 cn ? cn:"<unknown>", em ? em:"<unknown>",
664 sm_status_description (status));
666 camel_cipher_validity_add_certinfo_ex (
667 valid, CAMEL_CIPHER_VALIDITY_SIGN, cn, em,
668 smime_cert_data_clone (NSS_CMSSignerInfo_GetSigningCertificate (si, p->certdb)),
669 smime_cert_data_free, smime_cert_data_clone);
676 if (status != NSSCMSVS_GoodSignature)
677 camel_cipher_validity_set_valid (valid, FALSE);
681 case SEC_OID_PKCS7_ENVELOPED_DATA:
682 /* FIXME Do something with this? */
683 /*envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent (cinfo);*/
685 case SEC_OID_PKCS7_ENCRYPTED_DATA:
686 /* FIXME Do something with this? */
687 /*encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent (cinfo);*/
689 case SEC_OID_PKCS7_DATA:
696 camel_cipher_validity_set_valid (valid, status == NSSCMSVS_GoodSignature);
697 camel_cipher_validity_set_description (valid, description->str);
698 g_string_free (description, TRUE);
703 camel_cipher_validity_free (valid);
704 g_string_free (description, TRUE);
710 smime_context_hash_to_id (CamelCipherContext *context,
711 CamelCipherHash hash)
714 case CAMEL_CIPHER_HASH_MD5:
716 case CAMEL_CIPHER_HASH_SHA1:
717 case CAMEL_CIPHER_HASH_DEFAULT:
719 case CAMEL_CIPHER_HASH_SHA256:
721 case CAMEL_CIPHER_HASH_SHA384:
723 case CAMEL_CIPHER_HASH_SHA512:
730 static CamelCipherHash
731 smime_context_id_to_hash (CamelCipherContext *context,
735 if (!strcmp (id, "md5"))
736 return CAMEL_CIPHER_HASH_MD5;
737 else if (!strcmp (id, "sha1"))
738 return CAMEL_CIPHER_HASH_SHA1;
739 else if (!strcmp (id, "sha256"))
740 return CAMEL_CIPHER_HASH_SHA256;
741 else if (!strcmp (id, "sha384"))
742 return CAMEL_CIPHER_HASH_SHA384;
743 else if (!strcmp (id, "sha512"))
744 return CAMEL_CIPHER_HASH_SHA512;
747 return CAMEL_CIPHER_HASH_DEFAULT;
750 static CamelCipherHash
751 get_hash_from_oid (SECOidTag oidTag)
755 return CAMEL_CIPHER_HASH_SHA1;
757 return CAMEL_CIPHER_HASH_SHA256;
759 return CAMEL_CIPHER_HASH_SHA384;
761 return CAMEL_CIPHER_HASH_SHA512;
763 return CAMEL_CIPHER_HASH_MD5;
768 return CAMEL_CIPHER_HASH_DEFAULT;
772 smime_context_sign_sync (CamelCipherContext *context,
774 CamelCipherHash hash,
775 CamelMimePart *ipart,
776 CamelMimePart *opart,
777 GCancellable *cancellable,
780 CamelCipherContextClass *class;
782 CamelStream *ostream, *istream;
785 NSSCMSEncoderContext *enc;
786 CamelDataWrapper *dw;
787 CamelContentType *ct;
788 gboolean success = FALSE;
790 class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
793 case CAMEL_CIPHER_HASH_DEFAULT:
795 sechash = SEC_OID_UNKNOWN;
797 case CAMEL_CIPHER_HASH_SHA1:
798 sechash = SEC_OID_SHA1;
800 case CAMEL_CIPHER_HASH_SHA256:
801 sechash = SEC_OID_SHA256;
803 case CAMEL_CIPHER_HASH_SHA384:
804 sechash = SEC_OID_SHA384;
806 case CAMEL_CIPHER_HASH_SHA512:
807 sechash = SEC_OID_SHA512;
809 case CAMEL_CIPHER_HASH_MD5:
810 sechash = SEC_OID_MD5;
814 cmsg = sm_signing_cmsmessage (
815 (CamelSMIMEContext *) context, userid, &sechash,
816 ((CamelSMIMEContext *) context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, error);
820 ostream = camel_stream_mem_new ();
822 /* FIXME: stream this, we stream output at least */
823 buffer = g_byte_array_new ();
824 istream = camel_stream_mem_new_with_byte_array (buffer);
826 if (camel_cipher_canonical_to_stream (
827 ipart, CAMEL_MIME_FILTER_CANON_STRIP |
828 CAMEL_MIME_FILTER_CANON_CRLF |
829 CAMEL_MIME_FILTER_CANON_FROM,
830 istream, cancellable, error) == -1) {
832 error, _("Could not generate signing data: "));
836 enc = NSS_CMSEncoder_Start (
838 sm_write_stream, ostream, /* DER output callback */
839 NULL, NULL, /* destination storage */
840 NULL, NULL, /* password callback */
841 NULL, NULL, /* decrypt key callback */
842 NULL, NULL ); /* detached digests */
844 set_nss_error (error, _("Cannot create encoder context"));
848 if (NSS_CMSEncoder_Update (enc, (gchar *) buffer->data, buffer->len) != SECSuccess) {
849 NSS_CMSEncoder_Cancel (enc);
850 set_nss_error (error, _("Failed to add data to CMS encoder"));
854 if (NSS_CMSEncoder_Finish (enc) != SECSuccess) {
855 set_nss_error (error, _("Failed to encode data"));
861 dw = camel_data_wrapper_new ();
862 g_seekable_seek (G_SEEKABLE (ostream), 0, G_SEEK_SET, NULL, NULL);
863 camel_data_wrapper_construct_from_stream_sync (
864 dw, ostream, cancellable, NULL);
865 dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
867 if (((CamelSMIMEContext *) context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) {
868 CamelMultipartSigned *mps;
869 CamelMimePart *sigpart;
871 sigpart = camel_mime_part_new ();
872 ct = camel_content_type_new ("application", "x-pkcs7-signature");
873 camel_content_type_set_param (ct, "name", "smime.p7s");
874 camel_data_wrapper_set_mime_type_field (dw, ct);
875 camel_content_type_unref (ct);
877 camel_medium_set_content ((CamelMedium *) sigpart, dw);
879 camel_mime_part_set_filename (sigpart, "smime.p7s");
880 camel_mime_part_set_disposition (sigpart, "attachment");
881 camel_mime_part_set_encoding (sigpart, CAMEL_TRANSFER_ENCODING_BASE64);
883 mps = camel_multipart_signed_new ();
884 ct = camel_content_type_new ("multipart", "signed");
885 camel_content_type_set_param (ct, "micalg", camel_cipher_context_hash_to_id (context, get_hash_from_oid (sechash)));
886 camel_content_type_set_param (ct, "protocol", class->sign_protocol);
887 camel_data_wrapper_set_mime_type_field ((CamelDataWrapper *) mps, ct);
888 camel_content_type_unref (ct);
889 camel_multipart_set_boundary ((CamelMultipart *) mps, NULL);
891 mps->signature = sigpart;
892 mps->contentraw = g_object_ref (istream);
895 G_SEEKABLE (istream), 0,
896 G_SEEK_SET, NULL, NULL);
898 camel_medium_set_content ((CamelMedium *) opart, (CamelDataWrapper *) mps);
900 ct = camel_content_type_new ("application", "x-pkcs7-mime");
901 camel_content_type_set_param (ct, "name", "smime.p7m");
902 camel_content_type_set_param (ct, "smime-type", "signed-data");
903 camel_data_wrapper_set_mime_type_field (dw, ct);
904 camel_content_type_unref (ct);
906 camel_medium_set_content ((CamelMedium *) opart, dw);
908 camel_mime_part_set_filename (opart, "smime.p7m");
909 camel_mime_part_set_description (opart, "S/MIME Signed Message");
910 camel_mime_part_set_disposition (opart, "attachment");
911 camel_mime_part_set_encoding (opart, CAMEL_TRANSFER_ENCODING_BASE64);
916 g_object_unref (ostream);
917 g_object_unref (istream);
922 static CamelCipherValidity *
923 smime_context_verify_sync (CamelCipherContext *context,
924 CamelMimePart *ipart,
925 GCancellable *cancellable,
928 CamelCipherContextClass *class;
929 NSSCMSDecoderContext *dec;
932 CamelStream *constream = NULL;
933 CamelCipherValidity *valid = NULL;
934 CamelContentType *ct;
936 CamelMimePart *sigpart;
937 CamelDataWrapper *dw;
940 class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
942 dw = camel_medium_get_content ((CamelMedium *) ipart);
945 /* FIXME: we should stream this to the decoder */
946 buffer = g_byte_array_new ();
947 mem = camel_stream_mem_new_with_byte_array (buffer);
949 if (camel_content_type_is (ct, "multipart", "signed")) {
950 CamelMultipart *mps = (CamelMultipart *) dw;
952 tmp = camel_content_type_param (ct, "protocol");
953 if (!CAMEL_IS_MULTIPART_SIGNED (mps)
955 || (g_ascii_strcasecmp (tmp, class->sign_protocol) != 0
956 && g_ascii_strcasecmp (tmp, "application/pkcs7-signature") != 0)) {
958 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
959 _("Cannot verify message signature: "
960 "Incorrect message format"));
964 constream = camel_multipart_signed_get_content_stream (
965 (CamelMultipartSigned *) mps, error);
966 if (constream == NULL)
969 sigpart = camel_multipart_get_part (mps, CAMEL_MULTIPART_SIGNED_SIGNATURE);
970 if (sigpart == NULL) {
972 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
973 _("Cannot verify message signature: "
974 "Incorrect message format"));
977 } else if (camel_content_type_is (ct, "application", "x-pkcs7-mime")) {
981 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
982 _("Cannot verify message signature: "
983 "Incorrect message format"));
987 dec = NSS_CMSDecoder_Start (
989 NULL, NULL, /* content callback */
990 NULL, NULL, /* password callback */
991 NULL, NULL); /* decrypt key callback */
993 camel_data_wrapper_decode_to_stream_sync (
994 camel_medium_get_content (
995 CAMEL_MEDIUM (sigpart)), mem, cancellable, NULL);
996 (void) NSS_CMSDecoder_Update (dec, (gchar *) buffer->data, buffer->len);
997 cmsg = NSS_CMSDecoder_Finish (dec);
999 set_nss_error (error, _("Decoder failed"));
1003 valid = sm_verify_cmsg (context, cmsg, constream, cancellable, error);
1005 NSS_CMSMessage_Destroy (cmsg);
1007 g_object_unref (mem);
1009 g_object_unref (constream);
1015 smime_context_encrypt_sync (CamelCipherContext *context,
1016 const gchar *userid,
1017 GPtrArray *recipients,
1018 CamelMimePart *ipart,
1019 CamelMimePart *opart,
1020 GCancellable *cancellable,
1023 CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *) context)->priv;
1024 /*NSSCMSRecipientInfo **recipient_infos;*/
1025 CERTCertificate **recipient_certs = NULL;
1026 NSSCMSContentInfo *cinfo;
1027 PK11SymKey *bulkkey = NULL;
1028 SECOidTag bulkalgtag;
1029 gint bulkkeysize, i;
1030 CK_MECHANISM_TYPE type;
1033 NSSCMSMessage *cmsg = NULL;
1034 NSSCMSEnvelopedData *envd;
1035 NSSCMSEncoderContext *enc = NULL;
1037 CamelStream *ostream = NULL;
1038 CamelDataWrapper *dw;
1039 CamelContentType *ct;
1042 poolp = PORT_NewArena (1024);
1043 if (poolp == NULL) {
1044 set_nss_error (error, g_strerror (ENOMEM));
1048 /* Lookup all recipients certs, for later working */
1049 recipient_certs = (CERTCertificate **) PORT_ArenaZAlloc (poolp, sizeof (*recipient_certs[0]) * (recipients->len + 1));
1050 if (recipient_certs == NULL) {
1051 set_nss_error (error, g_strerror (ENOMEM));
1055 for (i = 0; i < recipients->len; i++) {
1056 recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr (p->certdb, recipients->pdata[i]);
1057 if (recipient_certs[i] == NULL) {
1059 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
1060 _("Cannot find certificate for '%s'"),
1061 (gchar *) recipients->pdata[i]);
1066 /* Find a common algorithm, probably 3DES anyway ... */
1067 if (NSS_SMIMEUtil_FindBulkAlgForRecipients (recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) {
1068 set_nss_error (error, _("Cannot find common bulk encryption algorithm"));
1072 /* Generate a new bulk key based on the common algorithm - expensive */
1073 type = PK11_AlgtagToMechanism (bulkalgtag);
1074 slot = PK11_GetBestSlot (type, context);
1076 set_nss_error (error, _("Cannot allocate slot for encryption bulk key"));
1080 bulkkey = PK11_KeyGen (slot, type, NULL, bulkkeysize / 8, context);
1081 PK11_FreeSlot (slot);
1083 /* Now we can start building the message */
1084 /* msg->envelopedData->data */
1085 cmsg = NSS_CMSMessage_Create (NULL);
1087 set_nss_error (error, _("Cannot create CMS Message"));
1091 envd = NSS_CMSEnvelopedData_Create (cmsg, bulkalgtag, bulkkeysize);
1093 set_nss_error (error, _("Cannot create CMS Enveloped data"));
1097 cinfo = NSS_CMSMessage_GetContentInfo (cmsg);
1098 if (NSS_CMSContentInfo_SetContent_EnvelopedData (cmsg, cinfo, envd) != SECSuccess) {
1099 set_nss_error (error, _("Cannot attach CMS Enveloped data"));
1103 cinfo = NSS_CMSEnvelopedData_GetContentInfo (envd);
1104 if (NSS_CMSContentInfo_SetContent_Data (cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) {
1105 set_nss_error (error, _("Cannot attach CMS data object"));
1109 /* add recipient certs */
1110 for (i = 0; recipient_certs[i]; i++) {
1111 NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create (cmsg, recipient_certs[i]);
1114 set_nss_error (error, _("Cannot create CMS Recipient information"));
1118 if (NSS_CMSEnvelopedData_AddRecipient (envd, ri) != SECSuccess) {
1119 set_nss_error (error, _("Cannot add CMS Recipient information"));
1125 ostream = camel_stream_mem_new ();
1126 enc = NSS_CMSEncoder_Start (
1128 sm_write_stream, ostream,
1131 sm_decrypt_key, bulkkey,
1134 set_nss_error (error, _("Cannot create encoder context"));
1138 /* FIXME: Stream the input */
1139 buffer = g_byte_array_new ();
1140 mem = camel_stream_mem_new_with_byte_array (buffer);
1141 camel_cipher_canonical_to_stream (ipart, CAMEL_MIME_FILTER_CANON_CRLF, mem, NULL, NULL);
1142 if (NSS_CMSEncoder_Update (enc, (gchar *) buffer->data, buffer->len) != SECSuccess) {
1143 NSS_CMSEncoder_Cancel (enc);
1144 g_object_unref (mem);
1145 set_nss_error (error, _("Failed to add data to encoder"));
1148 g_object_unref (mem);
1150 if (NSS_CMSEncoder_Finish (enc) != SECSuccess) {
1151 set_nss_error (error, _("Failed to encode data"));
1155 PK11_FreeSymKey (bulkkey);
1156 NSS_CMSMessage_Destroy (cmsg);
1157 for (i = 0; recipient_certs[i]; i++)
1158 CERT_DestroyCertificate (recipient_certs[i]);
1159 PORT_FreeArena (poolp, PR_FALSE);
1161 dw = camel_data_wrapper_new ();
1162 camel_data_wrapper_construct_from_stream_sync (
1163 dw, ostream, NULL, NULL);
1164 g_object_unref (ostream);
1165 dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;
1167 ct = camel_content_type_new ("application", "x-pkcs7-mime");
1168 camel_content_type_set_param (ct, "name", "smime.p7m");
1169 camel_content_type_set_param (ct, "smime-type", "enveloped-data");
1170 camel_data_wrapper_set_mime_type_field (dw, ct);
1171 camel_content_type_unref (ct);
1173 camel_medium_set_content ((CamelMedium *) opart, dw);
1174 g_object_unref (dw);
1176 camel_mime_part_set_disposition (opart, "attachment");
1177 camel_mime_part_set_filename (opart, "smime.p7m");
1178 camel_mime_part_set_description (opart, "S/MIME Encrypted Message");
1179 camel_mime_part_set_encoding (opart, CAMEL_TRANSFER_ENCODING_BASE64);
1185 g_object_unref (ostream);
1187 NSS_CMSMessage_Destroy (cmsg);
1189 PK11_FreeSymKey (bulkkey);
1191 if (recipient_certs) {
1192 for (i = 0; recipient_certs[i]; i++)
1193 CERT_DestroyCertificate (recipient_certs[i]);
1196 PORT_FreeArena (poolp, PR_FALSE);
1201 static CamelCipherValidity *
1202 smime_context_decrypt_sync (CamelCipherContext *context,
1203 CamelMimePart *ipart,
1204 CamelMimePart *opart,
1205 GCancellable *cancellable,
1208 NSSCMSDecoderContext *dec;
1209 NSSCMSMessage *cmsg;
1210 CamelStream *istream;
1211 CamelStream *ostream;
1212 CamelCipherValidity *valid = NULL;
1215 /* FIXME: This assumes the content is only encrypted. Perhaps its ok for
1216 * this api to do this ... */
1218 ostream = camel_stream_mem_new ();
1219 camel_stream_mem_set_secure (CAMEL_STREAM_MEM (ostream));
1221 /* FIXME: stream this to the decoder incrementally */
1222 buffer = g_byte_array_new ();
1223 istream = camel_stream_mem_new_with_byte_array (buffer);
1224 if (!camel_data_wrapper_decode_to_stream_sync (
1225 camel_medium_get_content (CAMEL_MEDIUM (ipart)),
1226 istream, cancellable, error)) {
1227 g_object_unref (istream);
1231 g_seekable_seek (G_SEEKABLE (istream), 0, G_SEEK_SET, NULL, NULL);
1233 dec = NSS_CMSDecoder_Start (
1235 sm_write_stream, ostream, /* content callback */
1237 NULL, NULL); /* decrypt key callback */
1239 if (NSS_CMSDecoder_Update (dec, (gchar *) buffer->data, buffer->len) != SECSuccess) {
1242 cmsg = NSS_CMSDecoder_Finish (dec);
1245 g_object_unref (istream);
1248 set_nss_error (error, _("Decoder failed"));
1253 /* not sure if we really care about this? */
1254 if (!NSS_CMSMessage_IsEncrypted (cmsg)) {
1255 set_nss_error (ex, _("S/MIME Decrypt: No encrypted content found"));
1256 NSS_CMSMessage_Destroy (cmsg);
1261 g_seekable_seek (G_SEEKABLE (ostream), 0, G_SEEK_SET, NULL, NULL);
1263 camel_data_wrapper_construct_from_stream_sync (
1264 CAMEL_DATA_WRAPPER (opart), ostream, NULL, NULL);
1266 if (NSS_CMSMessage_IsSigned (cmsg)) {
1268 G_SEEKABLE (ostream), 0, G_SEEK_SET, NULL, NULL);
1269 valid = sm_verify_cmsg (
1270 context, cmsg, ostream, cancellable, error);
1272 valid = camel_cipher_validity_new ();
1273 valid->encrypt.description = g_strdup (_("Encrypted content"));
1274 valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED;
1277 NSS_CMSMessage_Destroy (cmsg);
1279 g_object_unref (ostream);
1285 camel_smime_context_class_init (CamelSMIMEContextClass *class)
1287 CamelCipherContextClass *cipher_context_class;
1289 g_type_class_add_private (class, sizeof (CamelSMIMEContextPrivate));
1291 cipher_context_class = CAMEL_CIPHER_CONTEXT_CLASS (class);
1292 cipher_context_class->sign_protocol = "application/x-pkcs7-signature";
1293 cipher_context_class->encrypt_protocol = "application/x-pkcs7-mime";
1294 cipher_context_class->key_protocol = "application/x-pkcs7-signature";
1295 cipher_context_class->hash_to_id = smime_context_hash_to_id;
1296 cipher_context_class->id_to_hash = smime_context_id_to_hash;
1297 cipher_context_class->sign_sync = smime_context_sign_sync;
1298 cipher_context_class->verify_sync = smime_context_verify_sync;
1299 cipher_context_class->encrypt_sync = smime_context_encrypt_sync;
1300 cipher_context_class->decrypt_sync = smime_context_decrypt_sync;
1304 camel_smime_context_init (CamelSMIMEContext *smime_context)
1306 smime_context->priv = CAMEL_SMIME_CONTEXT_GET_PRIVATE (smime_context);
1307 smime_context->priv->certdb = CERT_GetDefaultCertDB ();
1308 smime_context->priv->sign_mode = CAMEL_SMIME_SIGN_CLEARSIGN;
1309 smime_context->priv->password_tries = 0;
1313 * camel_smime_context_new:
1316 * Creates a new sm cipher context object.
1318 * Returns: a new sm cipher context object.
1320 CamelCipherContext *
1321 camel_smime_context_new (CamelSession *session)
1323 g_return_val_if_fail (CAMEL_IS_SESSION (session), NULL);
1325 return g_object_new (
1326 CAMEL_TYPE_SMIME_CONTEXT,
1327 "session", session, NULL);
1331 camel_smime_context_set_encrypt_key (CamelSMIMEContext *context,
1335 context->priv->send_encrypt_key_prefs = use;
1336 g_free (context->priv->encrypt_key);
1337 context->priv->encrypt_key = g_strdup (key);
1340 /* set signing mode, clearsigned multipart/signed or enveloped */
1342 camel_smime_context_set_sign_mode (CamelSMIMEContext *context,
1343 camel_smime_sign_t type)
1345 context->priv->sign_mode = type;
1348 /* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */
1350 camel_smime_context_describe_part (CamelSMIMEContext *context,
1351 CamelMimePart *part)
1353 CamelCipherContextClass *class;
1355 CamelContentType *ct;
1361 class = CAMEL_CIPHER_CONTEXT_GET_CLASS (context);
1363 ct = camel_mime_part_get_content_type (part);
1365 if (camel_content_type_is (ct, "multipart", "signed")) {
1366 tmp = camel_content_type_param (ct, "protocol");
1368 (g_ascii_strcasecmp (tmp, class->sign_protocol) == 0
1369 || g_ascii_strcasecmp (tmp, "application/pkcs7-signature") == 0))
1370 flags = CAMEL_SMIME_SIGNED;
1371 } else if (camel_content_type_is (ct, "application", "x-pkcs7-mime")) {
1372 CamelStream *istream;
1373 NSSCMSMessage *cmsg;
1374 NSSCMSDecoderContext *dec;
1377 /* FIXME: stream this to the decoder incrementally */
1378 buffer = g_byte_array_new ();
1379 istream = camel_stream_mem_new_with_byte_array (buffer);
1381 /* FIXME Pass a GCancellable and GError here. */
1382 camel_data_wrapper_decode_to_stream_sync (
1383 camel_medium_get_content ((CamelMedium *) part),
1384 istream, NULL, NULL);
1387 G_SEEKABLE (istream), 0, G_SEEK_SET, NULL, NULL);
1389 dec = NSS_CMSDecoder_Start (
1392 NULL, NULL, /* password callback */
1393 NULL, NULL); /* decrypt key callback */
1395 NSS_CMSDecoder_Update (dec, (gchar *) buffer->data, buffer->len);
1396 g_object_unref (istream);
1398 cmsg = NSS_CMSDecoder_Finish (dec);
1400 if (NSS_CMSMessage_IsSigned (cmsg)) {
1401 printf ("message is signed\n");
1402 flags |= CAMEL_SMIME_SIGNED;
1405 if (NSS_CMSMessage_IsEncrypted (cmsg)) {
1406 printf ("message is encrypted\n");
1407 flags |= CAMEL_SMIME_ENCRYPTED;
1410 if (NSS_CMSMessage_ContainsCertsOrCrls (cmsg)) {
1411 printf ("message contains certs or crls\n");
1412 flags |= CAMEL_SMIME_CERTS;
1415 NSS_CMSMessage_Destroy (cmsg);
1417 printf ("Message could not be parsed\n");
1424 #endif /* ENABLE_SMIME */