@@ -31,6 +31,7 @@ typedef void *SSL;
31
31
#else
32
32
#include <openssl/evp.h>
33
33
#include <openssl/hmac.h>
34
+ #include <openssl/x509v3.h>
34
35
#endif
35
36
36
37
struct store_conf {
@@ -266,19 +267,72 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
266
267
}
267
268
}
268
269
270
+ #ifdef NO_OPENSSL
269
271
static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
270
272
{
271
- #ifdef NO_OPENSSL
272
273
fprintf (stderr , "SSL requested but SSL support not compiled in\n" );
273
274
return -1 ;
275
+ }
276
+
274
277
#else
278
+
279
+ static int host_matches (const char * host , const char * pattern )
280
+ {
281
+ if (pattern [0 ] == '*' && pattern [1 ] == '.' ) {
282
+ pattern += 2 ;
283
+ if (!(host = strchr (host , '.' )))
284
+ return 0 ;
285
+ host ++ ;
286
+ }
287
+
288
+ return * host && * pattern && !strcasecmp (host , pattern );
289
+ }
290
+
291
+ static int verify_hostname (X509 * cert , const char * hostname )
292
+ {
293
+ int len ;
294
+ X509_NAME * subj ;
295
+ char cname [1000 ];
296
+ int i , found ;
297
+ STACK_OF (GENERAL_NAME ) * subj_alt_names ;
298
+
299
+ /* try the DNS subjectAltNames */
300
+ found = 0 ;
301
+ if ((subj_alt_names = X509_get_ext_d2i (cert , NID_subject_alt_name , NULL , NULL ))) {
302
+ int num_subj_alt_names = sk_GENERAL_NAME_num (subj_alt_names );
303
+ for (i = 0 ; !found && i < num_subj_alt_names ; i ++ ) {
304
+ GENERAL_NAME * subj_alt_name = sk_GENERAL_NAME_value (subj_alt_names , i );
305
+ if (subj_alt_name -> type == GEN_DNS &&
306
+ strlen ((const char * )subj_alt_name -> d .ia5 -> data ) == (size_t )subj_alt_name -> d .ia5 -> length &&
307
+ host_matches (hostname , (const char * )(subj_alt_name -> d .ia5 -> data )))
308
+ found = 1 ;
309
+ }
310
+ sk_GENERAL_NAME_pop_free (subj_alt_names , GENERAL_NAME_free );
311
+ }
312
+ if (found )
313
+ return 0 ;
314
+
315
+ /* try the common name */
316
+ if (!(subj = X509_get_subject_name (cert )))
317
+ return error ("cannot get certificate subject" );
318
+ if ((len = X509_NAME_get_text_by_NID (subj , NID_commonName , cname , sizeof (cname ))) < 0 )
319
+ return error ("cannot get certificate common name" );
320
+ if (strlen (cname ) == (size_t )len && host_matches (hostname , cname ))
321
+ return 0 ;
322
+ return error ("certificate owner '%s' does not match hostname '%s'" ,
323
+ cname , hostname );
324
+ }
325
+
326
+ static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
327
+ {
275
328
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L )
276
329
const SSL_METHOD * meth ;
277
330
#else
278
331
SSL_METHOD * meth ;
279
332
#endif
280
333
SSL_CTX * ctx ;
281
334
int ret ;
335
+ X509 * cert ;
282
336
283
337
SSL_library_init ();
284
338
SSL_load_error_strings ();
@@ -322,9 +376,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
322
376
return -1 ;
323
377
}
324
378
379
+ if (verify ) {
380
+ /* make sure the hostname matches that of the certificate */
381
+ cert = SSL_get_peer_certificate (sock -> ssl );
382
+ if (!cert )
383
+ return error ("unable to get peer certificate." );
384
+ if (verify_hostname (cert , server .host ) < 0 )
385
+ return -1 ;
386
+ }
387
+
325
388
return 0 ;
326
- #endif
327
389
}
390
+ #endif
328
391
329
392
static int socket_read (struct imap_socket * sock , char * buf , int len )
330
393
{
0 commit comments