~ubuntu-branches/ubuntu/saucy/irssi/saucy-proposed

« back to all changes in this revision

Viewing changes to debian/patches/91_CVE-2010-1155.patch

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2010-04-14 13:36:33 UTC
  • Revision ID: james.westby@ubuntu.com-20100414133633-qn4xagdn8am0kqk2
Tags: 0.8.14-1ubuntu3
* SECURITY UPDATE: perform certificate host validation
  - debian/patches/91_CVE-2010-1155.patch: adjust to verify hostname against
    CN. Also use one SSL_CTX per connection and use default trusted CAs if
    nothing specified. This can be dropped in 0.8.15.
  - CVE-2010-1155
* SECURITY UPDATE: fix crash when checking for fuzzy nick match when not on
  the channel
  - debian/patches/91_CVE-2010-1156.patch: verify channel is non-NULL in
    src/core/nicklist.c. This can be dropped in 0.8.15.
  - CVE-2010-1156
* Do not use SSLv2 protocol. This can be dropped in 0.8.16.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Origin: r5104, r5107, r5108 and r5116
 
2
Description: perform certificate host validation (CVE-2010-1155). CVE-2010-1154
 
3
 was also assigned to this issue for checking /0 in CN, but it never checked
 
4
 the hostname until these commits. From the upstream svn log:
 
5
 r5104:
 
6
  Check if an SSL certificate matches the hostname of the server we are
 
7
  connecting to
 
8
 r5107:
 
9
  Use one SSL_CTX per connection, use default trusted CAs if nothing specified.
 
10
  This allows useful use of -ssl_verify without -ssl_cafile/-ssl_capath, using
 
11
  OpenSSL's default trusted CAs.
 
12
 r5108:
 
13
  Call OpenSSL_add_all_algorithms(), may be needed to verify SHA256 certs with
 
14
  certain versions of OpenSSL.
 
15
 r5116:
 
16
  network-openssl: Show why a certificate failed validation.
 
17
 
 
18
diff -Nur irssi-0.8.14/src/core/network.h irssi-0.8.14.new/src/core/network.h
 
19
--- irssi-0.8.14/src/core/network.h     2009-07-21 13:48:05.000000000 -0500
 
20
+++ irssi-0.8.14.new/src/core/network.h 2010-04-14 13:25:51.050161002 -0500
 
21
@@ -47,7 +47,7 @@
 
22
 /* Connect to socket */
 
23
 GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
 
24
 /* Connect to socket with ip address and SSL*/
 
25
-GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
 
26
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, const char* hostname, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
 
27
 int irssi_ssl_handshake(GIOChannel *handle);
 
28
 /* Connect to socket with ip address */
 
29
 GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
 
30
diff -Nur irssi-0.8.14/src/core/network-openssl.c irssi-0.8.14.new/src/core/network-openssl.c
 
31
--- irssi-0.8.14/src/core/network-openssl.c     2009-07-21 13:48:05.000000000 -0500
 
32
+++ irssi-0.8.14.new/src/core/network-openssl.c 2010-04-14 13:26:18.761443736 -0500
 
33
@@ -26,6 +26,7 @@
 
34
 
 
35
 #include <openssl/crypto.h>
 
36
 #include <openssl/x509.h>
 
37
+#include <openssl/x509v3.h>
 
38
 #include <openssl/pem.h>
 
39
 #include <openssl/ssl.h>
 
40
 #include <openssl/err.h>
 
41
@@ -39,28 +40,174 @@
 
42
        SSL *ssl;
 
43
        SSL_CTX *ctx;
 
44
        unsigned int verify:1;
 
45
+       const char *hostname;
 
46
 } GIOSSLChannel;
 
47
 
 
48
-static SSL_CTX *ssl_ctx = NULL;
 
49
+static int ssl_inited = FALSE;
 
50
 
 
51
 static void irssi_ssl_free(GIOChannel *handle)
 
52
 {
 
53
        GIOSSLChannel *chan = (GIOSSLChannel *)handle;
 
54
        g_io_channel_unref(chan->giochan);
 
55
        SSL_free(chan->ssl);
 
56
-       if (chan->ctx != ssl_ctx)
 
57
-               SSL_CTX_free(chan->ctx);
 
58
+       SSL_CTX_free(chan->ctx);
 
59
        g_free(chan);
 
60
 }
 
61
 
 
62
-static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, X509 *cert)
 
63
+/* Checks if the given string has internal NUL characters. */
 
64
+static gboolean has_internal_nul(const char* str, int len) {
 
65
+       /* Remove trailing nul characters. They would give false alarms */
 
66
+       while (len > 0 && str[len-1] == 0)
 
67
+               len--;
 
68
+       return strlen(str) != len;
 
69
+}
 
70
+
 
71
+/* tls_dns_name - Extract valid DNS name from subjectAltName value */
 
72
+static const char *tls_dns_name(const GENERAL_NAME * gn)
 
73
+{
 
74
+       const char *dnsname;
 
75
+
 
76
+       /* We expect the OpenSSL library to construct GEN_DNS extension objects as
 
77
+          ASN1_IA5STRING values. Check we got the right union member. */
 
78
+       if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
 
79
+               g_warning("Invalid ASN1 value type in subjectAltName");
 
80
+               return NULL;
 
81
+       }
 
82
+
 
83
+       /* Safe to treat as an ASCII string possibly holding a DNS name */
 
84
+       dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
 
85
+
 
86
+       if (has_internal_nul(dnsname, ASN1_STRING_length(gn->d.ia5))) {
 
87
+               g_warning("Internal NUL in subjectAltName");
 
88
+               return NULL;
 
89
+       }
 
90
+
 
91
+       return dnsname;
 
92
+}
 
93
+
 
94
+/* tls_text_name - extract certificate property value by name */
 
95
+static char *tls_text_name(X509_NAME *name, int nid)
 
96
+{
 
97
+       int     pos;
 
98
+       X509_NAME_ENTRY *entry;
 
99
+       ASN1_STRING *entry_str;
 
100
+       int     utf8_length;
 
101
+       unsigned char *utf8_value;
 
102
+       char *result;
 
103
+
 
104
+       if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
 
105
+               return NULL;
 
106
+    }
 
107
+
 
108
+    entry = X509_NAME_get_entry(name, pos);
 
109
+    g_return_val_if_fail(entry != NULL, NULL);
 
110
+    entry_str = X509_NAME_ENTRY_get_data(entry);
 
111
+    g_return_val_if_fail(entry_str != NULL, NULL);
 
112
+
 
113
+    /* Convert everything into UTF-8. It's up to OpenSSL to do something
 
114
+          reasonable when converting ASCII formats that contain non-ASCII
 
115
+          content. */
 
116
+    if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
 
117
+       g_warning("Error decoding ASN.1 type=%d", ASN1_STRING_type(entry_str));
 
118
+       return NULL;
 
119
+    }
 
120
+
 
121
+    if (has_internal_nul((char *)utf8_value, utf8_length)) {
 
122
+       g_warning("NUL character in hostname in certificate");
 
123
+       OPENSSL_free(utf8_value);
 
124
+       return NULL;
 
125
+    }
 
126
+
 
127
+    result = g_strdup((char *) utf8_value);
 
128
+       OPENSSL_free(utf8_value);
 
129
+       return result;
 
130
+}
 
131
+
 
132
+
 
133
+/** check if a hostname in the certificate matches the hostname we used for the connection */
 
134
+static gboolean match_hostname(const char *cert_hostname, const char *hostname)
 
135
+{
 
136
+       const char *hostname_left;
 
137
+
 
138
+       if (!strcasecmp(cert_hostname, hostname)) { /* exact match */
 
139
+               return TRUE;
 
140
+       } else if (cert_hostname[0] == '*' && cert_hostname[1] == '.' && cert_hostname[2] != 0) { /* wildcard match */
 
141
+               /* The initial '*' matches exactly one hostname component */
 
142
+               hostname_left = strchr(hostname, '.');
 
143
+               if (hostname_left != NULL && ! strcasecmp(hostname_left + 1, cert_hostname + 2)) {
 
144
+                       return TRUE;
 
145
+               }
 
146
+       }
 
147
+       return FALSE;
 
148
+}
 
149
+
 
150
+/* based on verify_extract_name from tls_client.c in postfix */
 
151
+static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname)
 
152
+{
 
153
+       int gen_index, gen_count;
 
154
+       gboolean matched = FALSE, has_dns_name = FALSE;
 
155
+       const char *cert_dns_name;
 
156
+       char *cert_subject_cn;
 
157
+       const GENERAL_NAME *gn;
 
158
+       STACK_OF(GENERAL_NAME) * gens;
 
159
+
 
160
+       /* Verify the dNSName(s) in the peer certificate against the hostname. */
 
161
+       gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
 
162
+       if (gens) {
 
163
+               gen_count = sk_GENERAL_NAME_num(gens);
 
164
+               for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) {
 
165
+                       gn = sk_GENERAL_NAME_value(gens, gen_index);
 
166
+                       if (gn->type != GEN_DNS)
 
167
+                               continue;
 
168
+
 
169
+                       /* Even if we have an invalid DNS name, we still ultimately
 
170
+                          ignore the CommonName, because subjectAltName:DNS is
 
171
+                          present (though malformed). */
 
172
+                       has_dns_name = TRUE;
 
173
+                       cert_dns_name = tls_dns_name(gn);
 
174
+                       if (cert_dns_name && *cert_dns_name) {
 
175
+                               matched = match_hostname(cert_dns_name, hostname);
 
176
+                       }
 
177
+       }
 
178
+
 
179
+           /* Free stack *and* member GENERAL_NAME objects */
 
180
+           sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
 
181
+       }
 
182
+
 
183
+       if (has_dns_name) {
 
184
+               if (! matched) {
 
185
+                       /* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */
 
186
+                       g_warning("None of the Subject Alt Names in the certificate match hostname '%s'", hostname);
 
187
+               }
 
188
+               return matched;
 
189
+       } else { /* No subjectAltNames, look at CommonName */
 
190
+               cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName);
 
191
+           if (cert_subject_cn && *cert_subject_cn) {
 
192
+               matched = match_hostname(cert_subject_cn, hostname);
 
193
+               if (! matched) {
 
194
+                               g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname);
 
195
+               }
 
196
+           } else {
 
197
+               g_warning("No subjectAltNames and no valid common name in certificate");
 
198
+           }
 
199
+           free(cert_subject_cn);
 
200
+       }
 
201
+
 
202
+       return matched;
 
203
+}
 
204
+
 
205
+static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, X509 *cert)
 
206
 {
 
207
-       if (SSL_get_verify_result(ssl) != X509_V_OK) {
 
208
+       long result;
 
209
+
 
210
+       result = SSL_get_verify_result(ssl);
 
211
+       if (result != X509_V_OK) {
 
212
                unsigned char md[EVP_MAX_MD_SIZE];
 
213
                unsigned int n;
 
214
                char *str;
 
215
 
 
216
-               g_warning("Could not verify SSL servers certificate:");
 
217
+               g_warning("Could not verify SSL servers certificate: %s",
 
218
+                               X509_verify_cert_error_string(result));
 
219
                if ((str = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0)) == NULL)
 
220
                        g_warning("  Could not get subject-name from peer certificate");
 
221
                else {
 
222
@@ -89,6 +236,8 @@
 
223
                        }
 
224
                }
 
225
                return FALSE;
 
226
+       } else if (! irssi_ssl_verify_hostname(cert, hostname)){
 
227
+               return FALSE;
 
228
        }
 
229
        return TRUE;
 
230
 }
 
231
@@ -229,19 +378,14 @@
 
232
 {
 
233
        SSL_library_init();
 
234
        SSL_load_error_strings();
 
235
-
 
236
-       ssl_ctx = SSL_CTX_new(SSLv23_client_method());
 
237
-       if(!ssl_ctx)
 
238
-       {
 
239
-               g_error("Initialization of the SSL library failed");
 
240
-               return FALSE;
 
241
-       }
 
242
+       OpenSSL_add_all_algorithms();
 
243
+       ssl_inited = TRUE;
 
244
 
 
245
        return TRUE;
 
246
 
 
247
 }
 
248
 
 
249
-static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify)
 
250
+static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *hostname, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify)
 
251
 {
 
252
        GIOSSLChannel *chan;
 
253
        GIOChannel *gchan;
 
254
@@ -251,18 +395,20 @@
 
255
 
 
256
        g_return_val_if_fail(handle != NULL, NULL);
 
257
 
 
258
-       if(!ssl_ctx && !irssi_ssl_init())
 
259
+       if(!ssl_inited && !irssi_ssl_init())
 
260
                return NULL;
 
261
 
 
262
        if(!(fd = g_io_channel_unix_get_fd(handle)))
 
263
                return NULL;
 
264
 
 
265
+       ctx = SSL_CTX_new(SSLv23_client_method());
 
266
+       if (ctx == NULL) {
 
267
+               g_error("Could not allocate memory for SSL context");
 
268
+               return NULL;
 
269
+       }
 
270
+
 
271
        if (mycert && *mycert) {
 
272
                char *scert = NULL, *spkey = NULL;
 
273
-               if ((ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
 
274
-                       g_error("Could not allocate memory for SSL context");
 
275
-                       return NULL;
 
276
-               }
 
277
                scert = convert_home(mycert);
 
278
                if (mypkey && *mypkey)
 
279
                        spkey = convert_home(mypkey);
 
280
@@ -279,10 +425,6 @@
 
281
        if ((cafile && *cafile) || (capath && *capath)) {
 
282
                char *scafile = NULL;
 
283
                char *scapath = NULL;
 
284
-               if (! ctx && (ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
 
285
-                       g_error("Could not allocate memory for SSL context");
 
286
-                       return NULL;
 
287
-               }
 
288
                if (cafile && *cafile)
 
289
                        scafile = convert_home(cafile);
 
290
                if (capath && *capath)
 
291
@@ -297,14 +439,15 @@
 
292
                g_free(scafile);
 
293
                g_free(scapath);
 
294
                verify = TRUE;
 
295
+       } else {
 
296
+               if (!SSL_CTX_set_default_verify_paths(ctx))
 
297
+                       g_warning("Could not load default certificates");
 
298
        }
 
299
 
 
300
-       if (ctx == NULL)
 
301
-               ctx = ssl_ctx;
 
302
-
 
303
        if(!(ssl = SSL_new(ctx)))
 
304
        {
 
305
                g_warning("Failed to allocate SSL structure");
 
306
+               SSL_CTX_free(ctx);
 
307
                return NULL;
 
308
        }
 
309
 
 
310
@@ -312,8 +455,7 @@
 
311
        {
 
312
                g_warning("Failed to associate socket to SSL stream");
 
313
                SSL_free(ssl);
 
314
-               if (ctx != ssl_ctx)
 
315
-                       SSL_CTX_free(ctx);
 
316
+               SSL_CTX_free(ctx);
 
317
                return NULL;
 
318
        }
 
319
 
 
320
@@ -323,6 +465,7 @@
 
321
        chan->ssl = ssl;
 
322
        chan->ctx = ctx;
 
323
        chan->verify = verify;
 
324
+       chan->hostname = hostname;
 
325
 
 
326
        gchan = (GIOChannel *)chan;
 
327
        gchan->funcs = &irssi_ssl_channel_funcs;
 
328
@@ -333,14 +476,14 @@
 
329
        return gchan;
 
330
 }
 
331
 
 
332
-GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
 
333
+GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, const char* hostname, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
 
334
 {
 
335
        GIOChannel *handle, *ssl_handle;
 
336
 
 
337
        handle = net_connect_ip(ip, port, my_ip);
 
338
        if (handle == NULL)
 
339
                return NULL;
 
340
-       ssl_handle  = irssi_ssl_get_iochannel(handle, cert, pkey, cafile, capath, verify);
 
341
+       ssl_handle  = irssi_ssl_get_iochannel(handle, hostname, cert, pkey, cafile, capath, verify);
 
342
        if (ssl_handle == NULL)
 
343
                g_io_channel_unref(handle);
 
344
        return ssl_handle;
 
345
@@ -382,7 +525,7 @@
 
346
                g_warning("SSL server supplied no certificate");
 
347
                return -1;
 
348
        }
 
349
-       ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, cert);
 
350
+       ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, chan->hostname, cert);
 
351
        X509_free(cert);
 
352
        return ret ? 0 : -1;
 
353
 }
 
354
diff -Nur irssi-0.8.14/src/core/servers.c irssi-0.8.14.new/src/core/servers.c
 
355
--- irssi-0.8.14/src/core/servers.c     2009-07-21 13:48:05.000000000 -0500
 
356
+++ irssi-0.8.14.new/src/core/servers.c 2010-04-14 13:25:51.070161073 -0500
 
357
@@ -224,7 +224,7 @@
 
358
                port = server->connrec->proxy != NULL ?
 
359
                        server->connrec->proxy_port : server->connrec->port;
 
360
                handle = server->connrec->use_ssl ?
 
361
-                       net_connect_ip_ssl(ip, port, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey,
 
362
+                       net_connect_ip_ssl(ip, port, server->connrec->address, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey,
 
363
 server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_verify) :
 
364
                        net_connect_ip(ip, port, own_ip);
 
365
        } else {