~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to debian/patches/CVE-2011-4318.patch

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2011-12-08 14:34:36 UTC
  • Revision ID: package-import@ubuntu.com-20111208143436-9scnmh9l46vo9opk
Tags: 1:2.0.15-1ubuntu5
* SECURITY UPDATE: Incorrect cert Common Name verification when proxying
  - debian/patches/CVE-2011-4318.patch: correctly validate Common Name
    when a hostname is specified in src/login-common/{login-proxy.c,
    ssl-proxy.*,ssl-proxy-openssl.c}.
  - CVE-2011-4318

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Description: Perform cert Common Name verification when proxying
 
2
Origin: upstream, http://hg.dovecot.org/dovecot-2.0/rev/5e9eaf63a6b1
 
3
Origin: upstream, http://hg.dovecot.org/dovecot-2.0/rev/de8715e4d793
 
4
Origin: upstream, http://hg.dovecot.org/dovecot-2.0/rev/4294e9136cd6
 
5
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=649511
 
6
 
 
7
Index: dovecot-2.0.15/src/login-common/login-proxy.c
 
8
===================================================================
 
9
--- dovecot-2.0.15.orig/src/login-common/login-proxy.c  2011-08-02 06:29:37.000000000 -0400
 
10
+++ dovecot-2.0.15/src/login-common/login-proxy.c       2011-12-08 14:34:15.302942940 -0500
 
11
@@ -504,19 +504,29 @@
 
12
 static int login_proxy_ssl_handshaked(void *context)
 
13
 {
 
14
        struct login_proxy *proxy = context;
 
15
+       struct ip_addr ip;
 
16
 
 
17
-       if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0 ||
 
18
-           ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy))
 
19
+       if ((proxy->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0)
 
20
                return 0;
 
21
 
 
22
-       if (!ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
 
23
+       if (ssl_proxy_has_broken_client_cert(proxy->ssl_server_proxy)) {
 
24
+               client_log_err(proxy->client, t_strdup_printf(
 
25
+                       "proxy: Received invalid SSL certificate from %s:%u",
 
26
+                       proxy->host, proxy->port));
 
27
+       } else if (!ssl_proxy_has_valid_client_cert(proxy->ssl_server_proxy)) {
 
28
                client_log_err(proxy->client, t_strdup_printf(
 
29
                        "proxy: SSL certificate not received from %s:%u",
 
30
                        proxy->host, proxy->port));
 
31
-       } else {
 
32
+       } else if (net_addr2ip(proxy->host, &ip) == 0 ||
 
33
+                  /* NOTE: allow IP address for backwards compatibility,
 
34
+                     v2.1 no longer accepts it */
 
35
+                  ssl_proxy_cert_match_name(proxy->ssl_server_proxy,
 
36
+                                            proxy->host) < 0) {
 
37
                client_log_err(proxy->client, t_strdup_printf(
 
38
-                       "proxy: Received invalid SSL certificate from %s:%u",
 
39
+                       "proxy: hostname doesn't match SSL certificate at %s:%u",
 
40
                        proxy->host, proxy->port));
 
41
+       } else {
 
42
+               return 0;
 
43
        }
 
44
        proxy->disconnecting = TRUE;
 
45
        return -1;
 
46
Index: dovecot-2.0.15/src/login-common/ssl-proxy.c
 
47
===================================================================
 
48
--- dovecot-2.0.15.orig/src/login-common/ssl-proxy.c    2011-03-04 13:53:01.000000000 -0500
 
49
+++ dovecot-2.0.15/src/login-common/ssl-proxy.c 2011-12-08 14:34:15.302942940 -0500
 
50
@@ -46,6 +46,12 @@
 
51
        return FALSE;
 
52
 }
 
53
 
 
54
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy ATTR_UNUSED,
 
55
+                             const char *verify_name ATTR_UNUSED)
 
56
+{
 
57
+       return -1;
 
58
+}
 
59
+
 
60
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy ATTR_UNUSED)
 
61
 {
 
62
        return NULL;
 
63
Index: dovecot-2.0.15/src/login-common/ssl-proxy.h
 
64
===================================================================
 
65
--- dovecot-2.0.15.orig/src/login-common/ssl-proxy.h    2011-03-04 13:53:01.000000000 -0500
 
66
+++ dovecot-2.0.15/src/login-common/ssl-proxy.h 2011-12-08 14:34:15.302942940 -0500
 
67
@@ -24,6 +24,7 @@
 
68
 void ssl_proxy_set_client(struct ssl_proxy *proxy, struct client *client);
 
69
 bool ssl_proxy_has_valid_client_cert(const struct ssl_proxy *proxy) ATTR_PURE;
 
70
 bool ssl_proxy_has_broken_client_cert(struct ssl_proxy *proxy);
 
71
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name);
 
72
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy);
 
73
 bool ssl_proxy_is_handshaked(const struct ssl_proxy *proxy) ATTR_PURE;
 
74
 const char *ssl_proxy_get_last_error(const struct ssl_proxy *proxy) ATTR_PURE;
 
75
Index: dovecot-2.0.15/src/login-common/ssl-proxy-openssl.c
 
76
===================================================================
 
77
--- dovecot-2.0.15.orig/src/login-common/ssl-proxy-openssl.c    2011-03-04 13:53:01.000000000 -0500
 
78
+++ dovecot-2.0.15/src/login-common/ssl-proxy-openssl.c 2011-12-08 14:34:15.306942941 -0500
 
79
@@ -21,6 +21,7 @@
 
80
 
 
81
 #include <openssl/crypto.h>
 
82
 #include <openssl/x509.h>
 
83
+#include <openssl/x509v3.h>
 
84
 #include <openssl/pem.h>
 
85
 #include <openssl/ssl.h>
 
86
 #include <openssl/err.h>
 
87
@@ -661,6 +662,87 @@
 
88
        return proxy->cert_received && proxy->cert_broken;
 
89
 }
 
90
 
 
91
+static const char *asn1_string_to_c(ASN1_STRING *asn_str)
 
92
+{
 
93
+       const char *cstr;
 
94
+       unsigned int len;
 
95
+
 
96
+       len = ASN1_STRING_length(asn_str);
 
97
+       cstr = t_strndup(ASN1_STRING_data(asn_str), len);
 
98
+       if (strlen(cstr) != len) {
 
99
+               /* NULs in the name - could be some MITM attack.
 
100
+                  never allow. */
 
101
+               return "";
 
102
+       }
 
103
+       return cstr;
 
104
+}
 
105
+
 
106
+static const char *get_general_dns_name(const GENERAL_NAME *name)
 
107
+{
 
108
+       if (ASN1_STRING_type(name->d.ia5) != V_ASN1_IA5STRING)
 
109
+               return "";
 
110
+
 
111
+       return asn1_string_to_c(name->d.ia5);
 
112
+}
 
113
+
 
114
+static const char *get_cname(X509 *cert)
 
115
+{
 
116
+       X509_NAME *name;
 
117
+       X509_NAME_ENTRY *entry;
 
118
+       ASN1_STRING *str;
 
119
+       int cn_idx;
 
120
+
 
121
+       name = X509_get_subject_name(cert);
 
122
+       if (name == NULL)
 
123
+               return "";
 
124
+       cn_idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
 
125
+       if (cn_idx == -1)
 
126
+               return "";
 
127
+       entry = X509_NAME_get_entry(name, cn_idx);
 
128
+       i_assert(entry != NULL);
 
129
+       str = X509_NAME_ENTRY_get_data(entry);
 
130
+       i_assert(str != NULL);
 
131
+       return asn1_string_to_c(str);
 
132
+}
 
133
+
 
134
+static int openssl_cert_match_name(SSL *ssl, const char *verify_name)
 
135
+{
 
136
+       X509 *cert;
 
137
+       STACK_OF(GENERAL_NAME) *gnames;
 
138
+       const GENERAL_NAME *gn;
 
139
+       const char *dnsname;
 
140
+       bool dns_names = FALSE;
 
141
+       unsigned int i, count;
 
142
+
 
143
+       cert = SSL_get_peer_certificate(ssl);
 
144
+       i_assert(cert != NULL);
 
145
+
 
146
+       /* verify against SubjectAltNames */
 
147
+       gnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 
148
+       count = gnames == NULL ? 0 : sk_GENERAL_NAME_num(gnames);
 
149
+       for (i = 0; i < count; i++) {
 
150
+               gn = sk_GENERAL_NAME_value(gnames, i);
 
151
+               if (gn->type == GEN_DNS) {
 
152
+                       dns_names = TRUE;
 
153
+                       dnsname = get_general_dns_name(gn);
 
154
+                       if (strcmp(dnsname, verify_name) == 0)
 
155
+                               break;
 
156
+               }
 
157
+       }
 
158
+       sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);
 
159
+       /* verify against CommonName only when there wasn't any DNS
 
160
+          SubjectAltNames */
 
161
+       if (dns_names)
 
162
+               return i < count ? 0 : -1;
 
163
+
 
164
+       return strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
 
165
+}
 
166
+
 
167
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name)
 
168
+{
 
169
+       return openssl_cert_match_name(proxy->ssl, verify_name);
 
170
+}
 
171
+
 
172
 const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
 
173
 {
 
174
        X509 *x509;
 
175
@@ -847,6 +929,10 @@
 
176
                else
 
177
                        i_info("Valid certificate: %s", buf);
 
178
        }
 
179
+       if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL && proxy->client_proxy) {
 
180
+               /* no CRL given with the CA list. don't worry about it. */
 
181
+               preverify_ok = 1;
 
182
+       }
 
183
        if (!preverify_ok)
 
184
                proxy->cert_broken = TRUE;
 
185