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
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
12
static int login_proxy_ssl_handshaked(void *context)
14
struct login_proxy *proxy = context;
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)
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));
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,
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));
44
proxy->disconnecting = TRUE;
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
54
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy ATTR_UNUSED,
55
+ const char *verify_name ATTR_UNUSED)
60
const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy ATTR_UNUSED)
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
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
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>
88
return proxy->cert_received && proxy->cert_broken;
91
+static const char *asn1_string_to_c(ASN1_STRING *asn_str)
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.
106
+static const char *get_general_dns_name(const GENERAL_NAME *name)
108
+ if (ASN1_STRING_type(name->d.ia5) != V_ASN1_IA5STRING)
111
+ return asn1_string_to_c(name->d.ia5);
114
+static const char *get_cname(X509 *cert)
117
+ X509_NAME_ENTRY *entry;
121
+ name = X509_get_subject_name(cert);
124
+ cn_idx = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
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);
134
+static int openssl_cert_match_name(SSL *ssl, const char *verify_name)
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;
143
+ cert = SSL_get_peer_certificate(ssl);
144
+ i_assert(cert != NULL);
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) {
153
+ dnsname = get_general_dns_name(gn);
154
+ if (strcmp(dnsname, verify_name) == 0)
158
+ sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);
159
+ /* verify against CommonName only when there wasn't any DNS
162
+ return i < count ? 0 : -1;
164
+ return strcmp(get_cname(cert), verify_name) == 0 ? 0 : -1;
167
+int ssl_proxy_cert_match_name(struct ssl_proxy *proxy, const char *verify_name)
169
+ return openssl_cert_match_name(proxy->ssl, verify_name);
172
const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy)
177
i_info("Valid certificate: %s", buf);
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. */
184
proxy->cert_broken = TRUE;