@@ -31,6 +31,7 @@ typedef void *SSL;
3131#else
3232#include <openssl/evp.h>
3333#include <openssl/hmac.h>
34+ #include <openssl/x509v3.h>
3435#endif
3536
3637struct store_conf {
@@ -266,19 +267,72 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
266267 }
267268}
268269
270+ #ifdef NO_OPENSSL
269271static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
270272{
271- #ifdef NO_OPENSSL
272273 fprintf (stderr , "SSL requested but SSL support not compiled in\n" );
273274 return -1 ;
275+ }
276+
274277#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+ {
275328#if (OPENSSL_VERSION_NUMBER >= 0x10000000L )
276329 const SSL_METHOD * meth ;
277330#else
278331 SSL_METHOD * meth ;
279332#endif
280333 SSL_CTX * ctx ;
281334 int ret ;
335+ X509 * cert ;
282336
283337 SSL_library_init ();
284338 SSL_load_error_strings ();
@@ -322,9 +376,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
322376 return -1 ;
323377 }
324378
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+
325388 return 0 ;
326- #endif
327389}
390+ #endif
328391
329392static int socket_read (struct imap_socket * sock , char * buf , int len )
330393{
0 commit comments