diff options
| author | Ted Zlatanov | 2013-12-14 13:04:09 -0500 |
|---|---|---|
| committer | Ted Zlatanov | 2013-12-14 13:04:09 -0500 |
| commit | 31b4827ea9ba8d22deb17c0593f0f555a33e1fa4 (patch) | |
| tree | dbfcb55f9fa3edc10623b34d5cf964a9a1167f7d | |
| parent | f93cc74f04312c1b27bfcc870c1782083525fc61 (diff) | |
| download | emacs-31b4827ea9ba8d22deb17c0593f0f555a33e1fa4.tar.gz emacs-31b4827ea9ba8d22deb17c0593f0f555a33e1fa4.zip | |
New verify-error GnuTLS interface for certificate validation
* net/gnutls.el (gnutls-verify-error): New defcustom to control
the behavior when a certificate fails validation. Defaults to
old behavior: never abort, just warn.
(gnutls-negotiate): Use it.
* gnutls.c: Replace `:verify_hostname_error' with `:verify_error',
now a list of certificate validation checks that will abort a
connection with an error.
(Fgnutls_boot): Document it and use it.
| -rw-r--r-- | lisp/ChangeLog | 7 | ||||
| -rw-r--r-- | lisp/net/gnutls.el | 67 | ||||
| -rw-r--r-- | src/ChangeLog | 7 | ||||
| -rw-r--r-- | src/gnutls.c | 48 |
4 files changed, 96 insertions, 33 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f1f1f45df91..246b7ae5b5f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2013-12-14 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 2 | |||
| 3 | * net/gnutls.el (gnutls-verify-error): New defcustom to control | ||
| 4 | the behavior when a certificate fails validation. Defaults to | ||
| 5 | old behavior: never abort, just warn. | ||
| 6 | (gnutls-negotiate): Use it. | ||
| 7 | |||
| 1 | 2013-12-14 Martin Rudalics <rudalics@gmx.at> | 8 | 2013-12-14 Martin Rudalics <rudalics@gmx.at> |
| 2 | 9 | ||
| 3 | * window.el (display-buffer-below-selected): Never split window | 10 | * window.el (display-buffer-below-selected): Never split window |
diff --git a/lisp/net/gnutls.el b/lisp/net/gnutls.el index 923b108c708..5bf9adc2b53 100644 --- a/lisp/net/gnutls.el +++ b/lisp/net/gnutls.el | |||
| @@ -51,6 +51,19 @@ set this variable to \"normal:-dhe-rsa\"." | |||
| 51 | :type '(choice (const nil) | 51 | :type '(choice (const nil) |
| 52 | string)) | 52 | string)) |
| 53 | 53 | ||
| 54 | (defcustom gnutls-verify-error nil | ||
| 55 | "If non-nil, this should be a list of checks per hostname regex or t." | ||
| 56 | :group 'gnutls | ||
| 57 | :type '(choice | ||
| 58 | (const t) | ||
| 59 | (repeat :tag "List of hostname regexps with flags for each" | ||
| 60 | (list | ||
| 61 | (choice :tag "Hostname" | ||
| 62 | (const ".*" :tag "Any hostname") | ||
| 63 | regexp) | ||
| 64 | (set (const :trustfiles) | ||
| 65 | (const :hostname)))))) | ||
| 66 | |||
| 54 | (defcustom gnutls-trustfiles | 67 | (defcustom gnutls-trustfiles |
| 55 | '( | 68 | '( |
| 56 | "/etc/ssl/certs/ca-certificates.crt" ; Debian, Ubuntu, Gentoo and Arch Linux | 69 | "/etc/ssl/certs/ca-certificates.crt" ; Debian, Ubuntu, Gentoo and Arch Linux |
| @@ -138,19 +151,25 @@ MIN-PRIME-BITS is the minimum acceptable size of Diffie-Hellman keys | |||
| 138 | \(see `gnutls-min-prime-bits' for more information). Use nil for the | 151 | \(see `gnutls-min-prime-bits' for more information). Use nil for the |
| 139 | default. | 152 | default. |
| 140 | 153 | ||
| 141 | When VERIFY-HOSTNAME-ERROR is not nil, an error will be raised | 154 | VERIFY-HOSTNAME-ERROR is a backwards compatibility option for |
| 142 | when the hostname does not match the presented certificate's host | 155 | putting `:hostname' in VERIFY-ERROR. |
| 143 | name. The exact verification algorithm is a basic implementation | 156 | |
| 144 | of the matching described in RFC2818 (HTTPS), which takes into | 157 | When VERIFY-ERROR is t or a list containing `:trustfiles', an |
| 145 | account wildcards, and the DNSName/IPAddress subject alternative | 158 | error will be raised when the peer certificate verification fails |
| 146 | name PKIX extension. See GnuTLS' gnutls_x509_crt_check_hostname | 159 | as per GnuTLS' gnutls_certificate_verify_peers2. Otherwise, only |
| 147 | for details. When VERIFY-HOSTNAME-ERROR is nil, only a warning | 160 | warnings will be shown about the verification failure. |
| 148 | will be issued. | ||
| 149 | 161 | ||
| 150 | When VERIFY-ERROR is not nil, an error will be raised when the | 162 | When VERIFY-ERROR is t or a list containing `:hostname', an error |
| 151 | peer certificate verification fails as per GnuTLS' | 163 | will be raised when the hostname does not match the presented |
| 152 | gnutls_certificate_verify_peers2. Otherwise, only warnings will | 164 | certificate's host name. The exact verification algorithm is a |
| 153 | be shown about the verification failure. | 165 | basic implementation of the matching described in |
| 166 | RFC2818 (HTTPS), which takes into account wildcards, and the | ||
| 167 | DNSName/IPAddress subject alternative name PKIX extension. See | ||
| 168 | GnuTLS' gnutls_x509_crt_check_hostname for details. Otherwise, | ||
| 169 | only a warning will be issued. | ||
| 170 | |||
| 171 | Note that the list in `gnutls-verify-error', matched against the | ||
| 172 | HOSTNAME, is the default VERIFY-ERROR. | ||
| 154 | 173 | ||
| 155 | VERIFY-FLAGS is a numeric OR of verification flags only for | 174 | VERIFY-FLAGS is a numeric OR of verification flags only for |
| 156 | `gnutls-x509pki' connections. See GnuTLS' x509.h for details; | 175 | `gnutls-x509pki' connections. See GnuTLS' x509.h for details; |
| @@ -183,8 +202,28 @@ defaults to GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT." | |||
| 183 | (if gnutls-algorithm-priority | 202 | (if gnutls-algorithm-priority |
| 184 | (upcase gnutls-algorithm-priority) | 203 | (upcase gnutls-algorithm-priority) |
| 185 | "NORMAL"))))) | 204 | "NORMAL"))))) |
| 205 | (verify-error (or verify-error | ||
| 206 | ;; this uses the value of `gnutls-verify-error' | ||
| 207 | (cond | ||
| 208 | ;; if t, pass it on | ||
| 209 | ((eq gnutls-verify-error t) | ||
| 210 | t) | ||
| 211 | ;; if a list, look for hostname matches | ||
| 212 | ((listp gnutls-verify-error) | ||
| 213 | (mapcan | ||
| 214 | (lambda (check) | ||
| 215 | (when (string-match (car check) hostname) | ||
| 216 | (cdr check))) | ||
| 217 | gnutls-verify-error)) | ||
| 218 | ;; else it's nil | ||
| 219 | (t nil)))) | ||
| 186 | (min-prime-bits (or min-prime-bits gnutls-min-prime-bits)) | 220 | (min-prime-bits (or min-prime-bits gnutls-min-prime-bits)) |
| 187 | (params `(:priority ,priority-string | 221 | params ret) |
| 222 | |||
| 223 | (when verify-hostname-error | ||
| 224 | (push :hostname verify-error)) | ||
| 225 | |||
| 226 | (setq params `(:priority ,priority-string | ||
| 188 | :hostname ,hostname | 227 | :hostname ,hostname |
| 189 | :loglevel ,gnutls-log-level | 228 | :loglevel ,gnutls-log-level |
| 190 | :min-prime-bits ,min-prime-bits | 229 | :min-prime-bits ,min-prime-bits |
| @@ -193,9 +232,7 @@ defaults to GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT." | |||
| 193 | :keylist ,keylist | 232 | :keylist ,keylist |
| 194 | :verify-flags ,verify-flags | 233 | :verify-flags ,verify-flags |
| 195 | :verify-error ,verify-error | 234 | :verify-error ,verify-error |
| 196 | :verify-hostname-error ,verify-hostname-error | ||
| 197 | :callbacks nil)) | 235 | :callbacks nil)) |
| 198 | ret) | ||
| 199 | 236 | ||
| 200 | (gnutls-message-maybe | 237 | (gnutls-message-maybe |
| 201 | (setq ret (gnutls-boot process type params)) | 238 | (setq ret (gnutls-boot process type params)) |
diff --git a/src/ChangeLog b/src/ChangeLog index 80367c81166..081a6b8631c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,10 @@ | |||
| 1 | 2013-12-14 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 2 | |||
| 3 | * gnutls.c: Replace `:verify_hostname_error' with `:verify_error', | ||
| 4 | now a list of certificate validation checks that will abort a | ||
| 5 | connection with an error. | ||
| 6 | (Fgnutls_boot): Document it and use it. | ||
| 7 | |||
| 1 | 2013-12-14 Martin Rudalics <rudalics@gmx.at> | 8 | 2013-12-14 Martin Rudalics <rudalics@gmx.at> |
| 2 | 9 | ||
| 3 | * w32term.c (w32_enable_frame_resize_hack): New variable. | 10 | * w32term.c (w32_enable_frame_resize_hack): New variable. |
diff --git a/src/gnutls.c b/src/gnutls.c index 105e5071ed7..a14d3ef31c5 100644 --- a/src/gnutls.c +++ b/src/gnutls.c | |||
| @@ -50,7 +50,7 @@ static Lisp_Object QCgnutls_bootprop_loglevel; | |||
| 50 | static Lisp_Object QCgnutls_bootprop_hostname; | 50 | static Lisp_Object QCgnutls_bootprop_hostname; |
| 51 | static Lisp_Object QCgnutls_bootprop_min_prime_bits; | 51 | static Lisp_Object QCgnutls_bootprop_min_prime_bits; |
| 52 | static Lisp_Object QCgnutls_bootprop_verify_flags; | 52 | static Lisp_Object QCgnutls_bootprop_verify_flags; |
| 53 | static Lisp_Object QCgnutls_bootprop_verify_hostname_error; | 53 | static Lisp_Object QCgnutls_bootprop_verify_error; |
| 54 | 54 | ||
| 55 | /* Callback keys for `gnutls-boot'. Unused currently. */ | 55 | /* Callback keys for `gnutls-boot'. Unused currently. */ |
| 56 | static Lisp_Object QCgnutls_bootprop_callbacks_verify; | 56 | static Lisp_Object QCgnutls_bootprop_callbacks_verify; |
| @@ -754,8 +754,12 @@ certificates for `gnutls-x509pki'. | |||
| 754 | :verify-flags is a bitset as per GnuTLS' | 754 | :verify-flags is a bitset as per GnuTLS' |
| 755 | gnutls_certificate_set_verify_flags. | 755 | gnutls_certificate_set_verify_flags. |
| 756 | 756 | ||
| 757 | :verify-hostname-error, if non-nil, makes a hostname mismatch an | 757 | :verify-hostname-error is ignored. Pass :hostname in :verify-error |
| 758 | error. Otherwise it will be just a warning. | 758 | instead. |
| 759 | |||
| 760 | :verify-error is a list of symbols to express verification checks or | ||
| 761 | `t' to do all checks. Currently it can contain `:trustfiles' and | ||
| 762 | `:hostname' to verify the certificate or the hostname respectively. | ||
| 759 | 763 | ||
| 760 | :min-prime-bits is the minimum accepted number of bits the client will | 764 | :min-prime-bits is the minimum accepted number of bits the client will |
| 761 | accept in Diffie-Hellman key exchange. | 765 | accept in Diffie-Hellman key exchange. |
| @@ -799,8 +803,7 @@ one trustfile (usually a CA bundle). */) | |||
| 799 | /* Lisp_Object callbacks; */ | 803 | /* Lisp_Object callbacks; */ |
| 800 | Lisp_Object loglevel; | 804 | Lisp_Object loglevel; |
| 801 | Lisp_Object hostname; | 805 | Lisp_Object hostname; |
| 802 | /* Lisp_Object verify_error; */ | 806 | Lisp_Object verify_error; |
| 803 | Lisp_Object verify_hostname_error; | ||
| 804 | Lisp_Object prime_bits; | 807 | Lisp_Object prime_bits; |
| 805 | 808 | ||
| 806 | CHECK_PROCESS (proc); | 809 | CHECK_PROCESS (proc); |
| @@ -819,11 +822,14 @@ one trustfile (usually a CA bundle). */) | |||
| 819 | keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist); | 822 | keylist = Fplist_get (proplist, QCgnutls_bootprop_keylist); |
| 820 | crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles); | 823 | crlfiles = Fplist_get (proplist, QCgnutls_bootprop_crlfiles); |
| 821 | loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel); | 824 | loglevel = Fplist_get (proplist, QCgnutls_bootprop_loglevel); |
| 822 | verify_hostname_error = Fplist_get (proplist, QCgnutls_bootprop_verify_hostname_error); | 825 | verify_error = Fplist_get (proplist, QCgnutls_bootprop_verify_error); |
| 823 | prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits); | 826 | prime_bits = Fplist_get (proplist, QCgnutls_bootprop_min_prime_bits); |
| 824 | 827 | ||
| 828 | if (!Flistp (verify_error)) | ||
| 829 | error ("gnutls-boot: invalid :verify_error parameter (not a list)"); | ||
| 830 | |||
| 825 | if (!STRINGP (hostname)) | 831 | if (!STRINGP (hostname)) |
| 826 | error ("gnutls-boot: invalid :hostname parameter"); | 832 | error ("gnutls-boot: invalid :hostname parameter (not a string)"); |
| 827 | c_hostname = SSDATA (hostname); | 833 | c_hostname = SSDATA (hostname); |
| 828 | 834 | ||
| 829 | state = XPROCESS (proc)->gnutls_state; | 835 | state = XPROCESS (proc)->gnutls_state; |
| @@ -1065,14 +1071,17 @@ one trustfile (usually a CA bundle). */) | |||
| 1065 | 1071 | ||
| 1066 | if (peer_verification != 0) | 1072 | if (peer_verification != 0) |
| 1067 | { | 1073 | { |
| 1068 | if (NILP (verify_hostname_error)) | 1074 | if (EQ (verify_error, Qt) |
| 1069 | GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:", | 1075 | || !NILP (Fmember (QCgnutls_bootprop_trustfiles, verify_error))) |
| 1070 | c_hostname); | 1076 | { |
| 1071 | else | ||
| 1072 | { | ||
| 1073 | emacs_gnutls_deinit (proc); | 1077 | emacs_gnutls_deinit (proc); |
| 1074 | error ("Certificate validation failed %s, verification code %d", | 1078 | error ("Certificate validation failed %s, verification code %d", |
| 1075 | c_hostname, peer_verification); | 1079 | c_hostname, peer_verification); |
| 1080 | } | ||
| 1081 | else | ||
| 1082 | { | ||
| 1083 | GNUTLS_LOG2 (1, max_log_level, "certificate validation failed:", | ||
| 1084 | c_hostname); | ||
| 1076 | } | 1085 | } |
| 1077 | } | 1086 | } |
| 1078 | 1087 | ||
| @@ -1112,14 +1121,17 @@ one trustfile (usually a CA bundle). */) | |||
| 1112 | 1121 | ||
| 1113 | if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname)) | 1122 | if (!fn_gnutls_x509_crt_check_hostname (gnutls_verify_cert, c_hostname)) |
| 1114 | { | 1123 | { |
| 1115 | if (NILP (verify_hostname_error)) | 1124 | if (EQ (verify_error, Qt) |
| 1116 | GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:", | 1125 | || !NILP (Fmember (QCgnutls_bootprop_hostname, verify_error))) |
| 1117 | c_hostname); | 1126 | { |
| 1118 | else | ||
| 1119 | { | ||
| 1120 | fn_gnutls_x509_crt_deinit (gnutls_verify_cert); | 1127 | fn_gnutls_x509_crt_deinit (gnutls_verify_cert); |
| 1121 | emacs_gnutls_deinit (proc); | 1128 | emacs_gnutls_deinit (proc); |
| 1122 | error ("The x509 certificate does not match \"%s\"", c_hostname); | 1129 | error ("The x509 certificate does not match \"%s\"", c_hostname); |
| 1130 | } | ||
| 1131 | else | ||
| 1132 | { | ||
| 1133 | GNUTLS_LOG2 (1, max_log_level, "x509 certificate does not match:", | ||
| 1134 | c_hostname); | ||
| 1123 | } | 1135 | } |
| 1124 | } | 1136 | } |
| 1125 | fn_gnutls_x509_crt_deinit (gnutls_verify_cert); | 1137 | fn_gnutls_x509_crt_deinit (gnutls_verify_cert); |
| @@ -1179,7 +1191,7 @@ syms_of_gnutls (void) | |||
| 1179 | DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits"); | 1191 | DEFSYM (QCgnutls_bootprop_min_prime_bits, ":min-prime-bits"); |
| 1180 | DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel"); | 1192 | DEFSYM (QCgnutls_bootprop_loglevel, ":loglevel"); |
| 1181 | DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags"); | 1193 | DEFSYM (QCgnutls_bootprop_verify_flags, ":verify-flags"); |
| 1182 | DEFSYM (QCgnutls_bootprop_verify_hostname_error, ":verify-hostname-error"); | 1194 | DEFSYM (QCgnutls_bootprop_verify_error, ":verify-error"); |
| 1183 | 1195 | ||
| 1184 | DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted"); | 1196 | DEFSYM (Qgnutls_e_interrupted, "gnutls-e-interrupted"); |
| 1185 | Fput (Qgnutls_e_interrupted, Qgnutls_code, | 1197 | Fput (Qgnutls_e_interrupted, Qgnutls_code, |