From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Ted Zlatanov Newsgroups: gmane.emacs.devel Subject: Re: client certs and CRL lists for GnuTLS Date: Tue, 03 May 2011 10:47:24 -0500 Organization: =?utf-8?B?0KLQtdC+0LTQvtGAINCX0LvQsNGC0LDQvdC+0LI=?= @ Cienfuegos Message-ID: <87pqnzair7.fsf@lifelogs.com> References: <87d3kal0za.fsf@lifelogs.com> <874o5mky4o.fsf@lifelogs.com> <8762ptue8r.fsf@lifelogs.com> <87k4e8ucw3.fsf@lifelogs.com> <87y62nak0m.fsf_-_@lifelogs.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: dough.gmane.org 1304437674 22567 80.91.229.12 (3 May 2011 15:47:54 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Tue, 3 May 2011 15:47:54 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue May 03 17:47:48 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QHHpE-0003Rf-8n for ged-emacs-devel@m.gmane.org; Tue, 03 May 2011 17:47:48 +0200 Original-Received: from localhost ([::1]:52441 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QHHpD-0006D1-S8 for ged-emacs-devel@m.gmane.org; Tue, 03 May 2011 11:47:47 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:47634) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QHHp9-0006Cl-PZ for emacs-devel@gnu.org; Tue, 03 May 2011 11:47:46 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QHHp4-0003bv-CX for emacs-devel@gnu.org; Tue, 03 May 2011 11:47:43 -0400 Original-Received: from lo.gmane.org ([80.91.229.12]:59636) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QHHp3-0003bk-UV for emacs-devel@gnu.org; Tue, 03 May 2011 11:47:38 -0400 Original-Received: from list by lo.gmane.org with local (Exim 4.69) (envelope-from ) id 1QHHp2-0003Ks-6r for emacs-devel@gnu.org; Tue, 03 May 2011 17:47:36 +0200 Original-Received: from 38.98.147.130 ([38.98.147.130]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 03 May 2011 17:47:36 +0200 Original-Received: from tzz by 38.98.147.130 with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Tue, 03 May 2011 17:47:36 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 268 Original-X-Complaints-To: usenet@dough.gmane.org X-Gmane-NNTP-Posting-Host: 38.98.147.130 X-Face: bd.DQ~'29fIs`T_%O%C\g%6jW)yi[zuz6; d4V0`@y-~$#3P_Ng{@m+e4o<4P'#(_GJQ%TT= D}[Ep*b!\e,fBZ'j_+#"Ps?s2!4H2-Y"sx" User-Agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.50 (gnu/linux) Cancel-Lock: sha1:yMI/mN+9pef8s+2Ud9RYqvqaYP4= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 80.91.229.12 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:139055 Archived-At: --=-=-= Content-Type: text/plain On Tue, 03 May 2011 17:25:44 +0200 Lars Magne Ingebrigtsen wrote: LMI> Ted Zlatanov writes: >> The attached patch adds a :keylist parameter to `gnutls-boot' which is a >> list of (client key file, client cert file) pairs. It also renames the >> :keyfiles parameter to :crlfiles since it's for CRL lists. So now you >> can specify any number of client certs. If the key files require a >> passphrase, the decoding won't work because we don't set a callback. LMI> Right. Hm... if you specify a keyfile (that requires a password), does LMI> starttls.el allow prompting for that password? (I'm just wondering LMI> whether the gnutls.c situation would be totally equivalent or not...) I don't think so. gnutls.c will eventually allow it if people need it. >> (defun gnutls-negotiate (proc type hostname &optional priority-string >> - trustfiles keyfiles verify-flags >> + trustfiles crlfiles keylist verify-flags >> verify-error verify-hostname-error) LMI> Heh. Yes, I think it would be better to change this to a plist. :-) Done, see attached (same patch with the plist change). Ted --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=gnutls-crl-and-client-certs.patch Content-Description: second try, with plist for `gnutls-negotiate' params === modified file 'lisp/net/gnutls.el' --- lisp/net/gnutls.el 2011-04-25 13:47:23 +0000 +++ lisp/net/gnutls.el 2011-05-03 15:41:06 +0000 @@ -35,6 +35,8 @@ ;;; Code: +(eval-when-compile (require 'cl)) + (defgroup gnutls nil "Emacs interface to the GnuTLS library." :prefix "gnutls-" @@ -72,9 +74,9 @@ documentation for the specific parameters you can use to open a GnuTLS connection, including specifying the credential type, trust and key files, and priority string." - (gnutls-negotiate (open-network-stream name buffer host service) - 'gnutls-x509pki - host)) + (gnutls-negotiate :process (open-network-stream name buffer host service) + :type 'gnutls-x509pki + :hostname host)) (put 'gnutls-error 'error-conditions @@ -85,16 +87,23 @@ (declare-function gnutls-boot "gnutls.c" (proc type proplist)) (declare-function gnutls-errorp "gnutls.c" (error)) -(defun gnutls-negotiate (proc type hostname &optional priority-string - trustfiles keyfiles verify-flags - verify-error verify-hostname-error) +(defun* gnutls-negotiate + (&rest spec + &key process type hostname priority-string + trustfiles crlfiles keylist verify-flags + verify-error verify-hostname-error + &allow-other-keys) "Negotiate a SSL/TLS connection. Returns proc. Signals gnutls-error. + +Note arguments are passed CL style, :type TYPE instead of just TYPE. + TYPE is `gnutls-x509pki' (default) or `gnutls-anon'. Use nil for the default. -PROC is a process returned by `open-network-stream'. +PROCESS is a process returned by `open-network-stream'. HOSTNAME is the remote hostname. It must be a valid string. PRIORITY-STRING is as per the GnuTLS docs, default is \"NORMAL\". TRUSTFILES is a list of CA bundles. -KEYFILES is a list of client keys. +CRLFILES is a list of CRL files. +KEYLIST is an alist of (client key file, client cert file) pairs. When VERIFY-HOSTNAME-ERROR is not nil, an error will be raised when the hostname does not match the presented certificate's host @@ -141,7 +150,8 @@ :hostname ,hostname :loglevel ,gnutls-log-level :trustfiles ,trustfiles - :keyfiles ,keyfiles + :crlfiles ,crlfiles + :keylist ,keylist :verify-flags ,verify-flags :verify-error ,verify-error :verify-hostname-error ,verify-hostname-error @@ -149,14 +159,14 @@ ret) (gnutls-message-maybe - (setq ret (gnutls-boot proc type params)) + (setq ret (gnutls-boot process type params)) "boot: %s" params) (when (gnutls-errorp ret) ;; This is a error from the underlying C code. - (signal 'gnutls-error (list proc ret))) + (signal 'gnutls-error (list process ret))) - proc)) + process)) (declare-function gnutls-error-string "gnutls.c" (error)) === modified file 'lisp/net/network-stream.el' --- lisp/net/network-stream.el 2011-05-01 15:39:10 +0000 +++ lisp/net/network-stream.el 2011-05-03 15:41:58 +0000 @@ -45,9 +45,7 @@ (require 'tls) (require 'starttls) -(declare-function gnutls-negotiate "gnutls" - (proc type host &optional priority-string trustfiles keyfiles - verify-flags verify-error verify-hostname-error)) +(declare-function gnutls-negotiate "gnutls" (&rest spec)) ;;;###autoload (defun open-network-stream (name buffer host service &rest parameters) @@ -203,7 +201,7 @@ (network-stream-command stream starttls-command eoc)) ;; The server said it was OK to begin STARTTLS negotiations. (if (fboundp 'open-gnutls-stream) - (gnutls-negotiate stream nil host) + (gnutls-negotiate :process stream :hostname host) (unless (starttls-negotiate stream) (delete-process stream))) (if (memq (process-status stream) '(open run)) === modified file 'src/gnutls.c' --- src/gnutls.c 2011-05-02 02:49:06 +0000 +++ src/gnutls.c 2011-05-03 15:11:35 +0000 @@ -44,7 +44,8 @@ /* The following are for the property list of `gnutls-boot'. */ static Lisp_Object Qgnutls_bootprop_priority; static Lisp_Object Qgnutls_bootprop_trustfiles; -static Lisp_Object Qgnutls_bootprop_keyfiles; +static Lisp_Object Qgnutls_bootprop_keylist; +static Lisp_Object Qgnutls_bootprop_crlfiles; static Lisp_Object Qgnutls_bootprop_callbacks; static Lisp_Object Qgnutls_bootprop_loglevel; static Lisp_Object Qgnutls_bootprop_hostname; @@ -412,7 +413,10 @@ :trustfiles is a list of PEM-encoded trust files for `gnutls-x509pki'. -:keyfiles is a list of PEM-encoded key files for `gnutls-x509pki'. +:crlfiles is a list of PEM-encoded CRL lists for `gnutls-x509pki'. + +:keylist is an alist of PEM-encoded key files and PEM-encoded +certificates for `gnutls-x509pki'. :callbacks is an alist of callback functions, see below. @@ -471,7 +475,8 @@ /* Placeholders for the property list elements. */ Lisp_Object priority_string; Lisp_Object trustfiles; - Lisp_Object keyfiles; + Lisp_Object crlfiles; + Lisp_Object keylist; /* Lisp_Object callbacks; */ Lisp_Object loglevel; Lisp_Object hostname; @@ -486,7 +491,8 @@ hostname = Fplist_get (proplist, Qgnutls_bootprop_hostname); priority_string = Fplist_get (proplist, Qgnutls_bootprop_priority); trustfiles = Fplist_get (proplist, Qgnutls_bootprop_trustfiles); - keyfiles = Fplist_get (proplist, Qgnutls_bootprop_keyfiles); + keylist = Fplist_get (proplist, Qgnutls_bootprop_keylist); + crlfiles = Fplist_get (proplist, Qgnutls_bootprop_crlfiles); /* callbacks = Fplist_get (proplist, Qgnutls_bootprop_callbacks); */ loglevel = Fplist_get (proplist, Qgnutls_bootprop_loglevel); verify_flags = Fplist_get (proplist, Qgnutls_bootprop_verify_flags); @@ -614,15 +620,41 @@ } } - for (tail = keyfiles; !NILP (tail); tail = Fcdr (tail)) - { - Lisp_Object keyfile = Fcar (tail); - if (STRINGP (keyfile)) - { - GNUTLS_LOG2 (1, max_log_level, "setting the keyfile: ", + for (tail = crlfiles; !NILP (tail); tail = Fcdr (tail)) + { + Lisp_Object crlfile = Fcar (tail); + if (STRINGP (crlfile)) + { + GNUTLS_LOG2 (1, max_log_level, "setting the CRL file: ", + SSDATA (crlfile)); + ret = gnutls_certificate_set_x509_crl_file + (x509_cred, + SSDATA (crlfile), + file_format); + + if (ret < GNUTLS_E_SUCCESS) + return gnutls_make_error (ret); + } + else + { + error ("Sorry, GnuTLS can't use non-string CRL file %s", + SDATA (crlfile)); + } + } + + for (tail = keylist; !NILP (tail); tail = Fcdr (tail)) + { + Lisp_Object keyfile = Fcar (Fcar (tail)); + Lisp_Object certfile = Fcar (Fcdr (tail)); + if (STRINGP (keyfile) && STRINGP (certfile)) + { + GNUTLS_LOG2 (1, max_log_level, "setting the client key file: ", SSDATA (keyfile)); - ret = gnutls_certificate_set_x509_crl_file + GNUTLS_LOG2 (1, max_log_level, "setting the client cert file: ", + SSDATA (certfile)); + ret = gnutls_certificate_set_x509_key_file (x509_cred, + SSDATA (certfile), SSDATA (keyfile), file_format); @@ -631,8 +663,12 @@ } else { - error ("Sorry, GnuTLS can't use non-string keyfile %s", - SDATA (keyfile)); + if (STRINGP (keyfile)) + error ("Sorry, GnuTLS can't use non-string client cert file %s", + SDATA (certfile)); + else + error ("Sorry, GnuTLS can't use non-string client key file %s", + SDATA (keyfile)); } } } @@ -868,8 +904,11 @@ Qgnutls_bootprop_trustfiles = intern_c_string (":trustfiles"); staticpro (&Qgnutls_bootprop_trustfiles); - Qgnutls_bootprop_keyfiles = intern_c_string (":keyfiles"); - staticpro (&Qgnutls_bootprop_keyfiles); + Qgnutls_bootprop_keylist = intern_c_string (":keylist"); + staticpro (&Qgnutls_bootprop_keylist); + + Qgnutls_bootprop_crlfiles = intern_c_string (":crlfiles"); + staticpro (&Qgnutls_bootprop_crlfiles); Qgnutls_bootprop_callbacks = intern_c_string (":callbacks"); staticpro (&Qgnutls_bootprop_callbacks); --=-=-=--