From: Junio C Hamano Date: Wed, 20 Feb 2013 05:54:15 +0000 (-0800) Subject: Merge branch 'ob/imap-send-ssl-verify' into maint X-Git-Tag: v1.8.1.4~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0ee7198f457c8ea031b09b528cfd88f0f0e630d8?ds=inline;hp=-c Merge branch 'ob/imap-send-ssl-verify' into maint * ob/imap-send-ssl-verify: imap-send: support subjectAltName as well imap-send: the subject of SSL certificate must match the host imap-send: move #ifdef around --- 0ee7198f457c8ea031b09b528cfd88f0f0e630d8 diff --combined imap-send.c index d42e471297,171c887076..ef500111ec --- a/imap-send.c +++ b/imap-send.c @@@ -25,12 -25,12 +25,13 @@@ #include "cache.h" #include "exec_cmd.h" #include "run-command.h" +#include "prompt.h" #ifdef NO_OPENSSL typedef void *SSL; #else #include #include + #include #endif struct store_conf { @@@ -139,6 -139,7 +140,6 @@@ static struct imap_server_conf server struct imap_store_conf { struct store_conf gen; struct imap_server_conf *server; - unsigned use_namespace:1; }; #define NIL (void *)0x1 @@@ -266,12 -267,64 +267,64 @@@ static void socket_perror(const char *f } } + #ifdef NO_OPENSSL static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) { - #ifdef NO_OPENSSL fprintf(stderr, "SSL requested but SSL support not compiled in\n"); return -1; + } + #else + + static int host_matches(const char *host, const char *pattern) + { + if (pattern[0] == '*' && pattern[1] == '.') { + pattern += 2; + if (!(host = strchr(host, '.'))) + return 0; + host++; + } + + return *host && *pattern && !strcasecmp(host, pattern); + } + + static int verify_hostname(X509 *cert, const char *hostname) + { + int len; + X509_NAME *subj; + char cname[1000]; + int i, found; + STACK_OF(GENERAL_NAME) *subj_alt_names; + + /* try the DNS subjectAltNames */ + found = 0; + if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) { + int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names); + for (i = 0; !found && i < num_subj_alt_names; i++) { + GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i); + if (subj_alt_name->type == GEN_DNS && + strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length && + host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data))) + found = 1; + } + sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free); + } + if (found) + return 0; + + /* try the common name */ + if (!(subj = X509_get_subject_name(cert))) + return error("cannot get certificate subject"); + if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0) + return error("cannot get certificate common name"); + if (strlen(cname) == (size_t)len && host_matches(hostname, cname)) + return 0; + return error("certificate owner '%s' does not match hostname '%s'", + cname, hostname); + } + + static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) + { #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) const SSL_METHOD *meth; #else @@@ -279,6 -332,7 +332,7 @@@ #endif SSL_CTX *ctx; int ret; + X509 *cert; SSL_library_init(); SSL_load_error_strings(); @@@ -322,9 -376,18 +376,18 @@@ return -1; } + if (verify) { + /* make sure the hostname matches that of the certificate */ + cert = SSL_get_peer_certificate(sock->ssl); + if (!cert) + return error("unable to get peer certificate."); + if (verify_hostname(cert, server.host) < 0) + return -1; + } + return 0; - #endif } + #endif static int socket_read(struct imap_socket *sock, char *buf, int len) { @@@ -1022,7 -1085,7 +1085,7 @@@ static int auth_cram_md5(struct imap_st ret = socket_write(&ctx->imap->buf.sock, response, strlen(response)); if (ret != strlen(response)) - return error("IMAP error: sending response failed\n"); + return error("IMAP error: sending response failed"); free(response); @@@ -1186,10 -1249,13 +1249,10 @@@ static struct store *imap_open_store(st goto bail; } if (!srvc->pass) { - char prompt[80]; - sprintf(prompt, "Password (%s@%s): ", srvc->user, srvc->host); - arg = git_getpass(prompt); - if (!arg) { - perror("getpass"); - exit(1); - } + struct strbuf prompt = STRBUF_INIT; + strbuf_addf(&prompt, "Password (%s@%s): ", srvc->user, srvc->host); + arg = git_getpass(prompt.buf); + strbuf_release(&prompt); if (!*arg) { fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host); goto bail; @@@ -1513,8 -1579,6 +1576,8 @@@ int main(int argc, char **argv git_extract_argv0_path(argv[0]); + git_setup_gettext(); + if (argc != 1) usage(imap_send_usage);