@@ -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
static 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)
200
201
}
201
202
}
202
203
204
+ #ifdef NO_OPENSSL
203
205
static int ssl_socket_connect (struct imap_socket * sock , int use_tls_only , int verify )
204
206
{
205
- #ifdef NO_OPENSSL
206
207
fprintf (stderr , "SSL requested but SSL support not compiled in\n" );
207
208
return -1 ;
209
+ }
210
+
208
211
#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
+ {
209
262
#if (OPENSSL_VERSION_NUMBER >= 0x10000000L )
210
263
const SSL_METHOD * meth ;
211
264
#else
212
265
SSL_METHOD * meth ;
213
266
#endif
214
267
SSL_CTX * ctx ;
215
268
int ret ;
269
+ X509 * cert ;
216
270
217
271
SSL_library_init ();
218
272
SSL_load_error_strings ();
@@ -256,9 +310,18 @@ static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int ve
256
310
return -1 ;
257
311
}
258
312
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
+
259
322
return 0 ;
260
- #endif
261
323
}
324
+ #endif
262
325
263
326
static int socket_read (struct imap_socket * sock , char * buf , int len )
264
327
{
0 commit comments