imap-send: the subject of SSL certificate must match the host
We did not check a valid certificate's subject at all, and would have happily talked with a wrong host after connecting to an incorrect address and getting a valid certificate that does not belong to the host we intended to talk to. Signed-off-by: Oswald Buddenhagen <ossi@kde.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Oswald Buddenhagen committed
Feb 15, 2013 at 12:50 UTC
b62fb077d5504deadea931fd16075729f39b8f47
1 file changed
+39
imap-send.c
+39
@@ -275,6 +275,35 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
275
276
#else
277
278
+static int host_matches(const char *host, const char *pattern)
279
+{
280
+ if (pattern[0] == '*' && pattern[1] == '.') {
281
+ pattern += 2;
282
+ if (!(host = strchr(host, '.')))
283
+ return 0;
284
+ host++;
285
+ }
286
+
287
+ return *host && *pattern && !strcasecmp(host, pattern);
288
+}
289
+
290
+static int verify_hostname(X509 *cert, const char *hostname)
291
+{
292
+ int len;
293
+ X509_NAME *subj;
294
+ char cname[1000];
295
+
296
+ /* try the common name */
297
+ if (!(subj = X509_get_subject_name(cert)))
298
+ return error("cannot get certificate subject");
299
+ if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
300
+ return error("cannot get certificate common name");
301
+ if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
302
+ return 0;
303
+ return error("certificate owner '%s' does not match hostname '%s'",
304
+ cname, hostname);
305
+}
306
+
307
static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
308
{
309
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
@@ -284,6 +313,7 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
313
#endif
314
SSL_CTX *ctx;
315
int ret;
316
+ X509 *cert;
317
318
SSL_library_init();
319
SSL_load_error_strings();
@@ -327,6 +357,15 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
357
return -1;
358
}
359
360
+ if (verify) {
361
+ /* make sure the hostname matches that of the certificate */
362
+ cert = SSL_get_peer_certificate(sock->ssl);
363
+ if (!cert)
364
+ return error("unable to get peer certificate.");
365
+ if (verify_hostname(cert, server.host) < 0)
366
+ return -1;
367
+ }
368
+
369
return 0;
370
}
371
#endif