2009-12-01 (Tue) [長年日記]

_ Sylpheed で S/MIME 復号

できた。ちょっとパッチ。テストするのが面倒だからなぁ、投稿するかどうかは不明。

Index: libsylph/procheader.c
===================================================================
--- libsylph/procheader.c	(revision 2362)
+++ libsylph/procheader.c	(working copy)
@@ -690,7 +690,7 @@
 				MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME);
 			} else if (!charset) {
 				procmime_scan_content_type_str
-					(hp, NULL, &charset, NULL, NULL);
+					(hp, NULL, &charset, NULL, NULL, NULL);
 			}
 			break;
 		case H_SEEN:
Index: libsylph/procmime.c
===================================================================
--- libsylph/procmime.c	(revision 2362)
+++ libsylph/procmime.c	(working copy)
@@ -69,6 +69,7 @@
 		g_free(mimeinfo->boundary);
 		g_free(mimeinfo->content_disposition);
 		g_free(mimeinfo->filename);
+		g_free(mimeinfo->smime_type);

 		g_free(mimeinfo->sigstatus);
 		g_free(mimeinfo->sigstatus_full);
@@ -379,14 +380,17 @@
 	g_free(mimeinfo->charset);
 	g_free(mimeinfo->name);
 	g_free(mimeinfo->boundary);
+	g_free(mimeinfo->smime_type);
 	mimeinfo->content_type = NULL;
 	mimeinfo->charset      = NULL;
 	mimeinfo->name         = NULL;
 	mimeinfo->boundary     = NULL;
+	mimeinfo->smime_type   = NULL;

 	procmime_scan_content_type_str(content_type, &mimeinfo->content_type,
 				       &mimeinfo->charset, &mimeinfo->name,
-				       &mimeinfo->boundary);
+				       &mimeinfo->boundary,
+				       &mimeinfo->smime_type);

 	mimeinfo->mime_type = procmime_scan_mime_type(mimeinfo->content_type);
 	if (mimeinfo->mime_type == MIME_MULTIPART && !mimeinfo->boundary)
@@ -706,7 +710,8 @@

 void procmime_scan_content_type_str(const gchar *content_type,
 				    gchar **mime_type, gchar **charset,
-				    gchar **name, gchar **boundary)
+				    gchar **name, gchar **boundary,
+				    gchar **smime_type)
 {
 	MimeParams *mparams;
 	GSList *cur;
@@ -730,6 +735,10 @@
 			   !g_ascii_strcasecmp(param->name, "boundary")) {
 			*boundary = g_strdup(param->value);
 			boundary = NULL;
+		} else if (smime_type &&
+			   !g_ascii_strcasecmp(param->name, "smime-type")) {
+			*smime_type = g_strdup(param->value);
+			smime_type = NULL;
 		}
 	}

Index: libsylph/procmime.h
===================================================================
--- libsylph/procmime.h	(revision 2362)
+++ libsylph/procmime.h	(working copy)
@@ -102,6 +102,7 @@
 	gchar *charset;
 	gchar *name;
 	gchar *boundary;
+	gchar *smime_type;

 	gchar *content_disposition;
 	gchar *filename;
@@ -155,7 +156,8 @@
 					 gchar	       **mime_type,
 					 gchar	       **charset,
 					 gchar	       **name,
-					 gchar	       **boundary);
+					 gchar	       **boundary,
+					 gchar	       **smime_type);
 void procmime_scan_content_disposition	(MimeInfo	*mimeinfo,
 					 const gchar	*content_disposition);
 MimeInfo *procmime_scan_mime_header	(FILE		*fp);
Index: src/compose.c
===================================================================
--- src/compose.c	(revision 2362)
+++ src/compose.c	(working copy)
@@ -1410,7 +1410,8 @@

 	if (hentry[H_CONTENT_TYPE].body != NULL) {
 		procmime_scan_content_type_str(hentry[H_CONTENT_TYPE].body,
-					       NULL, &charset, NULL, NULL);
+					       NULL, &charset, NULL, NULL,
+					       NULL);
 		g_free(hentry[H_CONTENT_TYPE].body);
 		hentry[H_CONTENT_TYPE].body = NULL;
 	}
Index: src/rfc2015.c
===================================================================
--- src/rfc2015.c	(revision 2362)
+++ src/rfc2015.c	(working copy)
@@ -364,7 +364,8 @@
 }
 #endif

-static gpgme_data_t pgp_decrypt(MsgInfo *msginfo, MimeInfo *partinfo, FILE *fp)
+static gpgme_data_t pgp_decrypt(MsgInfo *msginfo, MimeInfo *partinfo, FILE *fp,
+				gboolean pgp)
 {
 	gpgme_ctx_t ctx = NULL;
 	gpgme_error_t err;
@@ -372,6 +373,7 @@
 	struct passphrase_cb_info_s info;
 	gpgme_verify_result_t verifyresult = NULL;
 	const gchar *result = NULL;
+	const gchar *filename;

 	memset(&info, 0, sizeof info);

@@ -380,13 +382,37 @@
 		debug_print("gpgme_new failed: %s\n", gpgme_strerror(err));
 		goto leave;
 	}
+	if (!pgp) {
+		err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
+		if (err) {
+			debug_print("gpgme_set_protocol failed: %s\n",
+			            gpgme_strerror(err));
+			goto leave;
+		}
+	}

-	err = gpgme_data_new_from_filepart(&cipher, NULL, fp,
-	                                   partinfo->fpos, partinfo->size);
-	if (err) {
-		debug_print("gpgme_data_new_from_filepart failed: %s\n",
-		            gpgme_strerror(err));
-		goto leave;
+	if (pgp) {
+		err = gpgme_data_new_from_filepart(&cipher, NULL, fp,
+		                                   partinfo->fpos, partinfo->size);
+		if (err) {
+			debug_print("gpgme_data_new_from_filepart failed: %s\n",
+			            gpgme_strerror(err));
+			goto leave;
+		}
+	} else {
+		filename = procmime_get_tmp_file_name(partinfo);
+		if (procmime_get_part_fp(filename, fp, partinfo) < 0) {
+			g_warning("Can't get the S/MIME data file.");
+			g_free(filename);
+			goto leave;
+		}
+		err = gpgme_data_new_from_file(&cipher, filename, 1);
+		g_free(filename);
+		if (err) {
+			debug_print("gpgme_data_new_from_file failed: %s\n",
+			            gpgme_strerror(err));
+			goto leave;
+		}
 	}

 	err = gpgme_data_new(&plain);
@@ -538,12 +564,23 @@

 gint rfc2015_is_encrypted(MimeInfo *mimeinfo)
 {
-	if (!mimeinfo || mimeinfo->mime_type != MIME_MULTIPART)
+	if (!mimeinfo)
 		return 0;
-	if (g_ascii_strcasecmp(mimeinfo->content_type, "multipart/encrypted"))
-		return 0;
-	/* fixme: we should check the protocol parameter */
-	return 1;
+
+	/* PGP */
+	if (mimeinfo->mime_type == MIME_MULTIPART &&
+	    !g_ascii_strcasecmp(mimeinfo->content_type, "multipart/encrypted")) {
+		/* fixme: we should check the protocol parameter */
+		return 1;
+	}
+
+	/* S/MIME */
+	if (!g_ascii_strcasecmp(mimeinfo->content_type, "application/pkcs7-mime") &&
+	      !g_ascii_strcasecmp(mimeinfo->smime_type, "enveloped-data")) {
+		return 1;
+	}
+
+	return 0;
 }

 gboolean rfc2015_msg_is_encrypted(const gchar *file)
@@ -625,47 +662,72 @@
 	gchar buf[BUFFSIZE];
 	gint in_cline;
 	gpgme_error_t err;
+	gboolean multi = FALSE;

 	g_return_if_fail(msginfo != NULL);
 	g_return_if_fail(mimeinfo != NULL);
 	g_return_if_fail(fp != NULL);
-	g_return_if_fail(mimeinfo->mime_type == MIME_MULTIPART);
+	multi = (mimeinfo->mime_type == MIME_MULTIPART);

-	debug_print("** decrypting multipart/encrypted message\n");
+	debug_print("** decrypting multipart/encrypted or application/pkcs7-mime message\n");

 	/* skip headers */
 	if (fseek(fp, mimeinfo->fpos, SEEK_SET) < 0)
 		perror("fseek");
 	tmpinfo = procmime_scan_mime_header(fp);
-	if (!tmpinfo || tmpinfo->mime_type != MIME_MULTIPART) {
+	if (!tmpinfo) {
 		DECRYPTION_ABORT();
 	}

-	procmime_scan_multipart_message(tmpinfo, fp);
+	if (multi) {
+		if (tmpinfo->mime_type == MIME_MULTIPART) {
+			procmime_scan_multipart_message(tmpinfo, fp);
+			partinfo = tmpinfo->children;
+		} else {
+			DECRYPTION_ABORT();
+		}
+	} else {
+		partinfo = tmpinfo;
+	}

-	/* check that we have the 2 parts */
-	partinfo = tmpinfo->children;
-	if (!partinfo || !partinfo->next) {
+	if (!partinfo) {
 		DECRYPTION_ABORT();
 	}
-	if (!g_ascii_strcasecmp(partinfo->content_type,
+	if (multi && !g_ascii_strcasecmp(partinfo->content_type,
 	                        "application/pgp-encrypted")) {
+		/* check that we have the 2 parts */
+		if (!partinfo->next) {
+			DECRYPTION_ABORT();
+		}
 		/* Fixme: check that the version is 1 */
 		ver_ok = 1;
+
+		partinfo = partinfo->next;
+		if (ver_ok &&
+		    !g_ascii_strcasecmp(partinfo->content_type,
+					"application/octet-stream")) {
+			if (partinfo->next) {
+				g_warning("oops: pgp_encrypted with more than 2 parts");
+			}
+		} else {
+			DECRYPTION_ABORT();
+		}
+
+		debug_print("** yep, it is pgp encrypted\n");
 	}
-	partinfo = partinfo->next;
-	if (ver_ok &&
-	    !g_ascii_strcasecmp(partinfo->content_type,
-	                        "application/octet-stream")) {
-		if (partinfo->next)
-			g_warning("oops: pgp_encrypted with more than 2 parts");
-	} else {
-		DECRYPTION_ABORT();
+
+	if (!g_ascii_strcasecmp(partinfo->content_type,
+				"application/pkcs7-mime")) {
+		if (!g_ascii_strcasecmp(partinfo->smime_type,
+		    "enveloped-data")) {
+			ver_ok = 1; /*???*/
+		} else {
+			DECRYPTION_ABORT();
+		}
+		debug_print("** yep, it is smime encrypted\n");
 	}

-	debug_print("** yep, it is pgp encrypted\n");
-
-	plain = pgp_decrypt(msginfo, partinfo, fp);
+	plain = pgp_decrypt(msginfo, partinfo, fp, multi);
 	if (!plain) {
 		DECRYPTION_ABORT();
 	}

RFC も何も見てないので、 偶然うちの (mutt から送った) S/MIME メッセージを見ることができただけかもしれないし、 セキュリティについても知らない。保証はしないよ。

とくに outlook とのやりとりなんかのバッドノウハウはまったく知らない。

[]

«前の日記(2009-11-30 (Mon)) 最新