@@ -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
3637static const char imap_send_usage [] = "git imap-send < <mbox>" ;
@@ -200,19 +201,72 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret)
200201 }
201202}
202203
204+ #ifdef NO_OPENSSL
203205static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
204206{
205- #ifdef NO_OPENSSL
206207 fprintf (stderr , "SSL requested but SSL support not compiled in\n" );
207208 return -1 ;
209+ }
210+
208211#else
212+
213+ static int host_matches (const char * host , const char * pattern )
214+ {
215+ if (pattern [0 ] == '*' && pattern [1 ] == '.' ) {
216+ pattern += 2 ;
217+ if (!(host = strchr (host , '.' )))
218+ return 0 ;
219+ host ++ ;
220+ }
221+
222+ return * host && * pattern && !strcasecmp (host , pattern );
223+ }
224+
225+ static int verify_hostname (X509 * cert , const char * hostname )
226+ {
227+ int len ;
228+ X509_NAME * subj ;
229+ char cname [1000 ];
230+ int i , found ;
231+ STACK_OF (GENERAL_NAME ) * subj_alt_names ;
232+
233+ /* try the DNS subjectAltNames */
234+ found = 0 ;
235+ if ((subj_alt_names = X509_get_ext_d2i (cert , NID_subject_alt_name , NULL , NULL ))) {
236+ int num_subj_alt_names = sk_GENERAL_NAME_num (subj_alt_names );
237+ for (i = 0 ; !found && i < num_subj_alt_names ; i ++ ) {
238+ GENERAL_NAME * subj_alt_name = sk_GENERAL_NAME_value (subj_alt_names , i );
239+ if (subj_alt_name -> type == GEN_DNS &&
240+ strlen ((const char * )subj_alt_name -> d .ia5 -> data ) == (size_t )subj_alt_name -> d .ia5 -> length &&
241+ host_matches (hostname , (const char * )(subj_alt_name -> d .ia5 -> data )))
242+ found = 1 ;
243+ }
244+ sk_GENERAL_NAME_pop_free (subj_alt_names , GENERAL_NAME_free );
245+ }
246+ if (found )
247+ return 0 ;
248+
249+ /* try the common name */
250+ if (!(subj = X509_get_subject_name (cert )))
251+ return error ("cannot get certificate subject" );
252+ if ((len = X509_NAME_get_text_by_NID (subj , NID_commonName , cname , sizeof (cname ))) < 0 )
253+ return error ("cannot get certificate common name" );
254+ if (strlen (cname ) == (size_t )len && host_matches (hostname , cname ))
255+ return 0 ;
256+ return error ("certificate owner '%s' does not match hostname '%s'" ,
257+ cname , hostname );
258+ }
259+
260+ static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
261+ {
209262#if (OPENSSL_VERSION_NUMBER >= 0x10000000L )
210263 const SSL_METHOD * meth ;
211264#else
212265 SSL_METHOD * meth ;
213266#endif
214267 SSL_CTX * ctx ;
215268 int ret ;
269+ X509 * cert ;
216270
217271 SSL_library_init ();
218272 SSL_load_error_strings ();
@@ -256,9 +310,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
256310 return -1 ;
257311 }
258312
313+ if (verify ) {
314+ /* make sure the hostname matches that of the certificate */
315+ cert = SSL_get_peer_certificate (sock -> ssl );
316+ if (!cert )
317+ return error ("unable to get peer certificate." );
318+ if (verify_hostname (cert , server .host ) < 0 )
319+ return -1 ;
320+ }
321+
259322 return 0 ;
260- #endif
261323}
324+ #endif
262325
263326static int socket_read (struct imap_socket * sock , char * buf , int len )
264327{
0 commit comments