Hi there, I'm now using the attached patch to handle this. It seems to work (it's only been in production for 24 hours or so). If it looks OK to you all, would you mind seeing if it can go upstream?
Thanks, -- ----------------------------------------------------------------- | ,''`. Stephen Gran | | : :' : [EMAIL PROTECTED] | | `. `' Debian user, admin, and developer | | `- http://www.debian.org | -----------------------------------------------------------------
diff -u dovecot-1.0.5/debian/changelog dovecot-1.0.5/debian/changelog --- dovecot-1.0.5/debian/changelog +++ dovecot-1.0.5/debian/changelog @@ -1,3 +1,9 @@ +dovecot (1:1.0.5-1.1) unstable; urgency=low + + * Test SSL patch + + -- Mark Hymers <[EMAIL PROTECTED]> Sat, 27 Oct 2007 01:08:22 +0100 + dovecot (1:1.0.5-1) unstable; urgency=low * New upstream release. --- dovecot-1.0.5.orig/src/login-common/ssl-proxy.c +++ dovecot-1.0.5/src/login-common/ssl-proxy.c @@ -33,6 +33,11 @@ void ssl_proxy_free(struct ssl_proxy *proxy __attr_unused__) {} +const char *ssl_proxy_get_fingerprint(struct ssl_proxy *proxy __attr_unused__) +{ + return NULL; +} + unsigned int ssl_proxy_get_count(void) { return 0; only in patch2: unchanged: --- dovecot-1.0.5.orig/src/login-common/sasl-server.c +++ dovecot-1.0.5/src/login-common/sasl-server.c @@ -147,6 +147,8 @@ info.service = service; info.cert_username = client->proxy == NULL ? NULL : ssl_proxy_get_peer_name(client->proxy); + info.cert_fingerprint = client->proxy == NULL ? NULL : + ssl_proxy_get_fingerprint(client->proxy); info.flags = client_get_auth_flags(client); info.local_ip = client->local_ip; info.remote_ip = client->ip; only in patch2: unchanged: --- dovecot-1.0.5.orig/src/login-common/ssl-proxy.h +++ dovecot-1.0.5/src/login-common/ssl-proxy.h @@ -14,6 +14,7 @@ const char *ssl_proxy_get_peer_name(struct ssl_proxy *proxy); bool ssl_proxy_is_handshaked(struct ssl_proxy *proxy); void ssl_proxy_free(struct ssl_proxy *proxy); +const char *ssl_proxy_get_fingerprint(struct ssl_proxy *proxy); /* Return number of active SSL proxies */ unsigned int ssl_proxy_get_count(void); only in patch2: unchanged: --- dovecot-1.0.5.orig/src/login-common/ssl-proxy-openssl.c +++ dovecot-1.0.5/src/login-common/ssl-proxy-openssl.c @@ -26,6 +26,8 @@ /* Check every 30 minutes if parameters file has been updated */ #define SSL_PARAMFILE_CHECK_INTERVAL (60*30) +static const char hexcodes[] = "0123456789ABCDEF"; + enum ssl_io_action { SSL_ADD_INPUT, SSL_REMOVE_INPUT, @@ -535,6 +537,35 @@ return *name == '\0' ? NULL : name; } +const char *ssl_proxy_get_fingerprint(struct ssl_proxy *proxy) { + X509 *x509; + char *peer_fingerprint = NULL; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n; + int j; + + if (!ssl_proxy_has_valid_client_cert(proxy)) + return NULL; + + x509 = SSL_get_peer_certificate(proxy->ssl); + if (x509 == NULL) + return NULL; /* we should have had it.. */ + + if (X509_digest(x509, EVP_md5(), md, &n) && n > 0) { + peer_fingerprint = i_malloc(n * 3); + for (j = 0; j < (int) n; j++) { + peer_fingerprint[j * 3] = hexcodes[(md[j] & 0xf0) >> 4U]; + peer_fingerprint[(j * 3) + 1] = hexcodes[(md[j] & 0x0f)]; + if (j + 1 != (int) n) + peer_fingerprint[(j * 3) + 2] = ':'; + else + peer_fingerprint[(j * 3) + 2] = '\0'; + } + i_info("fingerprint: %s", peer_fingerprint); + } + return (const char *)peer_fingerprint; +} + bool ssl_proxy_is_handshaked(struct ssl_proxy *proxy) { return proxy->handshaked; only in patch2: unchanged: --- dovecot-1.0.5.orig/src/lib-auth/auth-server-request.c +++ dovecot-1.0.5/src/lib-auth/auth-server-request.c @@ -15,7 +15,7 @@ unsigned int id; - char *mech, *service, *cert_username; + char *mech, *service, *cert_username, *cert_fingerprint; enum auth_request_flags flags; struct ip_addr local_ip, remote_ip; @@ -108,6 +108,15 @@ } str_printfa(str, "\tcert_username=%s", request->cert_username); } + if (request->cert_fingerprint != NULL) { + if (!is_valid_string(request->cert_fingerprint)) { + t_pop(); + *error_r = "Invalid fingerprint in SSL certificate"; + return -1; + } + str_printfa(str, "\tcert_fingerprint=%s", request->cert_fingerprint); + } + if (request->local_ip.family != 0) str_printfa(str, "\tlip=%s", net_ip2addr(&request->local_ip)); if (request->remote_ip.family != 0) @@ -345,6 +354,7 @@ request->mech = i_strdup(request_info->mech); request->service = i_strdup(request_info->service); request->cert_username = i_strdup(request_info->cert_username); + request->cert_fingerprint = i_strdup(request_info->cert_fingerprint); request->flags = request_info->flags; request->local_ip = request_info->local_ip; request->remote_ip = request_info->remote_ip; @@ -385,6 +395,7 @@ i_free(request->mech); i_free(request->service); i_free(request->cert_username); + i_free(request->cert_fingerprint); i_free(request); } only in patch2: unchanged: --- dovecot-1.0.5.orig/src/lib-auth/auth-client.h +++ dovecot-1.0.5/src/lib-auth/auth-client.h @@ -26,6 +26,7 @@ const char *mech; const char *service; const char *cert_username; + const char *cert_fingerprint; enum auth_request_flags flags; struct ip_addr local_ip, remote_ip; only in patch2: unchanged: --- dovecot-1.0.5.orig/src/auth/auth-request.c +++ dovecot-1.0.5/src/auth/auth-request.c @@ -146,6 +146,8 @@ request->user = p_strdup(request->pool, value); else if (strcmp(key, "master_user") == 0) request->master_user = p_strdup(request->pool, value); + else if (strcmp(key, "cert_fingerprint") == 0) + request->cert_fingerprint = p_strdup(request->pool, value); else if (strcmp(key, "cert_username") == 0) { if (request->auth->ssl_username_from_cert) { /* get username from SSL certificate. it overrides only in patch2: unchanged: --- dovecot-1.0.5.orig/src/auth/passdb-checkpassword.c +++ dovecot-1.0.5/src/auth/passdb-checkpassword.c @@ -250,6 +250,10 @@ env_put(t_strconcat("MASTER_USER=", request->master_user, NULL)); } + if (request->cert_fingerprint != NULL) { + env_put(t_strconcat("SSL_FINGERPRINT=", + request->cert_fingerprint, NULL)); + } if (request->extra_fields != NULL) { const char *fields = auth_stream_reply_export(request->extra_fields); only in patch2: unchanged: --- dovecot-1.0.5.orig/src/auth/auth-request.h +++ dovecot-1.0.5/src/auth/auth-request.h @@ -38,6 +38,7 @@ const char *original_username; char *mech_password; /* set if verify_plain() is called */ char *passdb_password; /* set after password lookup if successful */ + char *cert_fingerprint; /* extra_fields are returned in authentication reply. Fields prefixed with "userdb_" are skipped. If prefetch userdb is used, it uses the "userdb_" prefixed fields. */ only in patch2: unchanged: --- dovecot-1.0.5.orig/src/login-common/ssl-proxy-gnutls.c +++ dovecot-1.0.5/src/login-common/ssl-proxy-gnutls.c @@ -61,6 +61,11 @@ return gnutls_alert_get_name(gnutls_alert_get(proxy->session)); } +const char *ssl_proxy_get_fingerprint(struct ssl_proxy *proxy __attr_unused__) +{ + return NULL; +} + static int handle_ssl_error(struct ssl_proxy *proxy, int error) { if (!gnutls_error_is_fatal(error)) {