[Mew-dist 16893] S/MIME improvements

Ryutaroh Matsumoto ryutaroh at example.com
2001年 3月 19日 (月) 20:39:20 JST


S/MIME機能の不足部分でEmacs LispだけではどうにもならずOpenSSLを使った
外部プログラムを書かないと埋められない部分を、外部プログラムを作ること
によって埋めたので報告します。使えるようなら使って下さい。

現在のS/MIME機能の不足している点は深刻な順に、

(1) application/x-pkcs7-mime型のデータが来た場合それが電子署名なのか暗
    号文なのかわからない。そのため署名だと思って検証して失敗したら暗号
    文だと思って解読しようとしている。そのため検証に失敗した署名は内容
    を読めない。([Mew-dist 16675]付近で書いた問題)。

(2) RFC2634の電子署名付き受信確認を送信者が要求していてもそのことがわ
    からない。

(3) 現在外されている暗号化の部分では暗号アルゴリズムが3DES決め打ちだが、
    Winbiff [Version 2.31PL6]やNetscape 4.5など3DESに対応していないメー
    ルリーダは結構多い(ことに最近気がついた)。少なくとも送信者のメール
    リーダーが3DESに対応していない場合にMewのユーザーにそのことを通知
    したほうがいい。

(4) 電子署名のPKCS7構造の中に複数のcertificateが含まれているとき、複数
    のcertificateが単一のファイルに保存される(これはopensslコマンドの
    問題)。PKCS7構造の中に複数のcertificateが入っているときにユーザー
    に通知したほうがいいと思う。

以上の問題に対し以下のような方針で対処してみました。

(1) 署名か暗号文か判別する mew-smime-tell-type という外部コマンドを作っ
    てMewから呼び出すようにした。

(2--4) mew-smime-analyze-signatureという外部コマンドを作って(2--4)の状
    態が起きているかどうか検査し、起きている場合はX-Mewに表示するよう
    にした。

以下tarファイルとパッチが添付されていますが、tarファイルの中に入ってい
るCのプログラムを適当にコンパイルしてパスの通ったところに置いて下さい。

パッチのほうは無修正のMew 1.95b114に対するもので、[Mew-dist 16875],
[Mew-dist 16884]のパッチを含んでいます。

--
松本  隆太郎
-------------- next part --------------
diff -ru mew-1.95b114/mew-encode.el mew-1.95b114-smime/mew-encode.el
--- mew-1.95b114/mew-encode.el	Fri Mar  9 11:07:58 2001
+++ mew-1.95b114-smime/mew-encode.el	Mon Mar 19 18:48:27 2001
@@ -749,7 +749,7 @@
   (let* ((boundary (mew-security-multipart-boundary depth))
 	 (switch mew-encode-multipart-signed-switch) ;; save length
 	 (func (mew-encode-get-security-func proto switch))
-	 file1 file2 micalg cte2 fmc errmsg ct2 cd2)
+	 file1 file2 micalg cte2 fmc errmsg ct2 cdp2)
     (setq file1 (mew-save-transfer-form (point-min) (point-max) 'retain))
     ;; The narrowed region still the ORIGINAL part (i.e. line breaks are LF)
     ;; Call the protocol function
@@ -762,7 +762,7 @@
 		mew-ct-mls mew-temp-dir))))
     (setq file2 (nth 0 fmc) cte2 (nth 1 fmc) micalg (nth 2 fmc))
     (setq errmsg (nth 3 fmc))
-    (setq ct2 (nth 4 fmc) cd2 (nth 5 fmc))
+    (setq ct2 (nth 4 fmc) cdp2 (nth 5 fmc))
     (if errmsg
 	(progn
 	  (if (file-exists-p file1) (delete-file file1))
@@ -782,7 +782,7 @@
       ;; After the sigend part
       (insert (format "\n--%s\n" boundary))
       (mew-encode-singlepart 
-       (mew-encode-syntax-single file2 (or ct2 (list proto)) cte2 cd2))
+       (mew-encode-syntax-single file2 (or ct2 (list proto)) cte2 nil nil cdp2))
       (insert (format "\n--%s--\n" boundary))
       ;; Throw away the garbage 
       (if (file-exists-p file1) (delete-file file1))
diff -ru mew-1.95b114/mew-smime.el mew-1.95b114-smime/mew-smime.el
--- mew-1.95b114/mew-smime.el	Sun Mar  4 21:35:07 2001
+++ mew-1.95b114-smime/mew-smime.el	Mon Mar 19 19:27:22 2001
@@ -29,6 +29,11 @@
   :group 'mew-privacy
   :type '(file :must-match t))
 
+(defconst mew-smime-tell-type-prog
+  "mew-smime-tell-type")
+(defconst mew-smime-analyze-signature-prog
+  "mew-smime-analyze-signature")
+
 (defun mew-smime-sign-configuration-check ()
   (cond
    ((or (not mew-smime-digital-id)
@@ -46,7 +51,11 @@
    ((or (not mew-smime-pubkey-dir)
 	(not (file-directory-p mew-smime-pubkey-dir)))
     "Please set mew-smime-pubkey-dir")
-   ((not (mew-which-exec "openssl")) "OpenSSL is not installed.")))
+   ((not (mew-which-exec "openssl")) "OpenSSL is not installed.")   
+   ((not (mew-which-exec mew-smime-tell-type-prog))
+    (concat mew-smime-tell-type-prog " is not installed."))   
+   ((not (mew-which-exec mew-smime-analyze-signature-prog))
+    (concat mew-smime-analyze-signature-prog " is not installed."))))
 
 ;; internal variables
 (defvar mew-smime-running nil)
@@ -61,6 +70,11 @@
 
 (defconst mew-smime-passtag "S/MIME")
 
+(defconst mew-smime-signature-filename "smime.p7s")
+
+(defconst mew-smime-type-signature 1)
+(defconst mew-smime-type-envelope 2)
+
 ;; The following variables are used only in the variable
 ;; mew-decode-multipart-signed-switch in mew-decode.el.
 (defvar mew-smime-ver 0)
@@ -96,7 +110,7 @@
     (setq mew-smime-running 'signing)
     (let ((process-connection-type mew-connection-type2)
 	  file2 process)
-      (setq file2 (mew-make-temp-name))
+      (setq file2 (mew-make-temp-name mew-smime-signature-filename))
       ;; not perfectly unique but OK
       (setq process
 	    (mew-start-process-lang
@@ -120,22 +134,31 @@
 	  (discard-input)))
       (message "S/MIME signing ... done")
       (list file2 mew-b64 "sha1" mew-smime-sign-error
-	    (list "application/x-pkcs7-signature" (list "name" "smime.p7s"))
-	    (list "attachment" (list "filename" "smime.p7s"))))));; return
+	    (list "application/x-pkcs7-signature" (list "name" mew-smime-signature-filename))
+	    t))));; return
+
+(defun mew-smime-analyze-signature (pkcs7-file)
+  (with-temp-buffer
+    (mew-call-process-lang
+     mew-smime-analyze-signature-prog
+     nil t nil pkcs7-file)
+    (buffer-substring (point-min) (point-max))))
 
 (defun mew-smime-verify (file1 file2)
   (message "S/MIME verifying ... ")
   (if (mew-smime-verify-configuration-check)
       (mew-smime-verify-configuration-check)
     (let ((pubkey-file (mew-make-temp-name)))
-      (if (equal 0 (mew-call-process-lang
-		    "openssl" nil nil nil
-		    "smime" "-verify" "-inform" "DER" "-in" file2
-		    "-content" file1
-		    "-CAfile" mew-smime-CA-file "-signer" pubkey-file))
-	  (concat "valid S/MIME digital signature by " 
-		  (mew-smime-move-pubkey-and-extract-email pubkey-file))
-	"S/MIME signature verification failed"))))
+      (concat
+       (if (equal 0 (mew-call-process-lang
+		     "openssl" nil nil nil
+		     "smime" "-verify" "-inform" "DER" "-in" file2
+		     "-content" file1
+		     "-CAfile" mew-smime-CA-file "-signer" pubkey-file))
+	   (concat "valid S/MIME digital signature by " 
+		   (mew-smime-move-pubkey-and-extract-email pubkey-file))
+	 "S/MIME signature verification failed")
+       (mew-smime-analyze-signature file2)))))
 
 (defun mew-smime-email-address-to-filename (addr)
   (let ((addr2 (copy-sequence addr)) i)
@@ -145,17 +168,13 @@
      (expand-file-name addr2 mew-smime-pubkey-dir))))
 
 (defun mew-smime-move-pubkey-and-extract-email (pubkey-file)
-  (let ((buf (generate-new-buffer mew-buffer-prefix))
-	email-addr pubkey-moved)
-    (save-excursion
-      (set-buffer buf)
-      (mew-erase-buffer)
+  (let (email-addr pubkey-moved)
+    (with-temp-buffer
       (mew-call-process-lang "openssl" nil t nil
 			     "x509" "-noout" "-email" "-in" pubkey-file)
       (goto-char (point-min))
       (replace-string "\n" "")
       (setq email-addr (mew-buffer-substring (point-min) (point-max))))
-    (mew-remove-buffer buf)
     (setq pubkey-moved (mew-smime-email-address-to-filename email-addr))
     (if (and (not (file-exists-p pubkey-moved))
 	     (file-writable-p pubkey-moved))
@@ -177,23 +196,42 @@
     (mew-decode-mime-body ctl cte)
     (let ((encrypted-file (mew-make-temp-name))
 	  (decrypted-file (mew-make-temp-name))
-	  process syntax3 proto
+	  process syntax3 proto smime-type
 	  result privacy (pubkey-file (mew-make-temp-name)))
       ;; XXX WHY DON'T YOU USE mew-save-decode-form!!!
       (mew-flet
        (write-region (mew-syntax-get-begin syntax)
 		     (point-max)
 		     encrypted-file nil 'no-msg))
-      ;; signature verification
-      (message "S/MIME verifying ... ")
-      (if (equal 0 (mew-call-process-lang
-		    "openssl" nil nil nil
-		    "smime" "-verify" "-inform" "DER"
-		    "-in" encrypted-file
-		    "-CAfile" mew-smime-CA-file
-		    "-signer" pubkey-file "-out" decrypted-file))
-	  (setq result (concat "valid S/MIME digital signature by " 
-			       (mew-smime-move-pubkey-and-extract-email pubkey-file)))
+      (setq smime-type
+	    (mew-call-process-lang mew-smime-tell-type-prog nil nil nil
+				   encrypted-file))
+      (cond
+       ((equal smime-type mew-smime-type-signature)
+	;; signature verification
+	(message "S/MIME verifying ... ")
+	(if (equal 0 (mew-call-process-lang
+		      "openssl" nil nil nil
+		      "smime" "-verify" "-inform" "DER"
+		      "-in" encrypted-file
+		      "-CAfile" mew-smime-CA-file
+		      "-signer" pubkey-file "-out" decrypted-file))
+	    (setq result (concat "valid S/MIME digital signature by " 
+				 (mew-smime-move-pubkey-and-extract-email pubkey-file)))
+	  (setq result "S/MIME signature verification failed")
+	  ;; openssl does not store the verified message
+	  ;; when signature verification fails.
+	  (mew-call-process-lang
+	   "openssl" nil nil nil
+	   "smime" "-verify" "-inform" "DER"
+	   "-in" encrypted-file
+	   "-noverify" "-nochain" "-nosigs"
+	   "-out" decrypted-file))
+	(setq result
+	      (concat result
+		      (mew-smime-analyze-signature encrypted-file)))
+	(message "S/MIME verifying ... done"))
+       ((equal smime-type mew-smime-type-envelope)
 	;; decryption
 	(message "S/MIME decrypting ...")
 	(setq mew-smime-running 'decrypt)
@@ -218,7 +256,7 @@
 	(message "S/MIME decrypting ... done")
 	(if (null mew-smime-sign-error)
 	    (setq result "S/MIME decrypted")
-	  (setq mew-decode-not-decrypted t)))
+	  (setq mew-decode-not-decrypted t))))
       (when result
 	(delete-region (point-min) (point-max))
 	(mew-flet 
diff -ru mew-1.95b114/mew-syntax.el mew-1.95b114-smime/mew-syntax.el
--- mew-1.95b114/mew-syntax.el	Sun Mar  4 13:30:37 2001
+++ mew-1.95b114-smime/mew-syntax.el	Mon Mar 19 18:48:27 2001
@@ -149,7 +149,7 @@
 
 (defun mew-syntax-cdp-format (file ct)
   (when file
-    (setq file (mew-header-sanity-check-string file))
+    (setq file (file-name-nondirectory (mew-header-sanity-check-string file)))
     (if (mew-member-case-equal ct mew-content-disposition-inline-list)
 	(list "inline" (list "filename" file))
       (list "attachment" (list "filename" file)))))
diff -ru mew-1.95b114/mew-vars2.el mew-1.95b114-smime/mew-vars2.el
--- mew-1.95b114/mew-vars2.el	Wed Mar 14 12:29:22 2001
+++ mew-1.95b114-smime/mew-vars2.el	Mon Mar 19 18:48:27 2001
@@ -326,6 +326,8 @@
      mew-prog-mspowerpoint           mew-icon-text)
     ("application/pgp-keys"          "\\.pka$"  nil
      mew-prog-pgp-keys               mew-icon-unknown)
+    ("application/x-pkcs7-signature" "\\.p7s$"  mew-b64
+     nil			     mew-icon-unknown)
     ("application/octet-stream"
      "\\.tar$\\|\\.tar\\.gz$\\|\\.tgz$\\|\\.gz$\\|\\.Z$\\|\\.taz$\\|\\.tar\\.bz2?$\\|\\.bz2?$\\|\\.lzh$\\|\\.zip$\\|\\.bin$\\|\\.pgp$|\\.gpg$"
       mew-b64 mew-prog-octet-stream mew-icon-application/octet-stream)
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: mew-smime-bin.tar.gz
型:         application/octet-stream
サイズ:     1252 バイト
説明:       無し
URL:        <http://www.mew.org/pipermail/mew-dist/attachments/20010319/dfac904d/attachment.obj>
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: smime.p7s
型:         application/x-pkcs7-signature
サイズ:     3207 バイト
説明:       無し
URL:        <http://www.mew.org/pipermail/mew-dist/attachments/20010319/dfac904d/attachment.bin>


Mew-dist メーリングリストの案内