]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_g.c
4ee683c4365bf63277cec57739a55d1b9a192813
[openldap] / libraries / libldap / tls_g.c
1 /* tls_g.c - Handle tls/ssl using GNUTLS. */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2008-2014 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and
17  * Emily Backes; sponsored by The Written Word (thewrittenword.com)
18  * and Stanford University (stanford.edu).
19  */
20
21 #include "portable.h"
22
23 #ifdef HAVE_GNUTLS
24
25 #include "ldap_config.h"
26
27 #include <stdio.h>
28
29 #include <ac/stdlib.h>
30 #include <ac/errno.h>
31 #include <ac/socket.h>
32 #include <ac/string.h>
33 #include <ac/ctype.h>
34 #include <ac/time.h>
35 #include <ac/unistd.h>
36 #include <ac/param.h>
37 #include <ac/dirent.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40
41 #include "ldap-int.h"
42 #include "ldap-tls.h"
43
44 #include <gnutls/gnutls.h>
45 #include <gnutls/x509.h>
46
47 #if LIBGNUTLS_VERSION_NUMBER >= 0x020200
48 #define HAVE_CIPHERSUITES       1
49 #else
50 #undef HAVE_CIPHERSUITES
51 #endif
52
53 #ifndef HAVE_CIPHERSUITES
54 /* Versions prior to 2.2.0 didn't handle cipher suites, so we had to
55  * kludge them ourselves.
56  */
57 typedef struct tls_cipher_suite {
58         const char *name;
59         gnutls_kx_algorithm_t kx;
60         gnutls_cipher_algorithm_t cipher;
61         gnutls_mac_algorithm_t mac;
62         gnutls_protocol_t version;
63 } tls_cipher_suite;
64 #endif
65
66 typedef struct tlsg_ctx {
67         struct ldapoptions *lo;
68         gnutls_certificate_credentials_t cred;
69         gnutls_dh_params_t dh_params;
70         unsigned long verify_depth;
71         int refcount;
72 #ifdef HAVE_CIPHERSUITES
73         gnutls_priority_t prios;
74 #else
75         int *kx_list;
76         int *cipher_list;
77         int *mac_list;
78 #endif
79 #ifdef LDAP_R_COMPILE
80         ldap_pvt_thread_mutex_t ref_mutex;
81 #endif
82 } tlsg_ctx;
83
84 typedef struct tlsg_session {
85         gnutls_session_t session;
86         tlsg_ctx *ctx;
87         struct berval peer_der_dn;
88 } tlsg_session;
89
90 #ifndef HAVE_CIPHERSUITES
91 static tls_cipher_suite *tlsg_ciphers;
92 static int tlsg_n_ciphers;
93 #endif
94
95 static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites );
96 static int tlsg_cert_verify( tlsg_session *s );
97
98 #ifdef LDAP_R_COMPILE
99
100 static int
101 tlsg_mutex_init( void **priv )
102 {
103         int err = 0;
104         ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t ));
105
106         if ( !lock )
107                 err = ENOMEM;
108         if ( !err ) {
109                 err = ldap_pvt_thread_mutex_init( lock );
110                 if ( err )
111                         LDAP_FREE( lock );
112                 else
113                         *priv = lock;
114         }
115         return err;
116 }
117
118 static int
119 tlsg_mutex_destroy( void **lock )
120 {
121         int err = ldap_pvt_thread_mutex_destroy( *lock );
122         LDAP_FREE( *lock );
123         return err;
124 }
125
126 static int
127 tlsg_mutex_lock( void **lock )
128 {
129         return ldap_pvt_thread_mutex_lock( *lock );
130 }
131
132 static int
133 tlsg_mutex_unlock( void **lock )
134 {
135         return ldap_pvt_thread_mutex_unlock( *lock );
136 }
137
138 static void
139 tlsg_thr_init( void )
140 {
141         gnutls_global_set_mutex (tlsg_mutex_init,
142                 tlsg_mutex_destroy,
143                 tlsg_mutex_lock,
144                 tlsg_mutex_unlock);
145 }
146 #endif /* LDAP_R_COMPILE */
147
148 /*
149  * Initialize TLS subsystem. Should be called only once.
150  */
151 static int
152 tlsg_init( void )
153 {
154         gnutls_global_init();
155
156 #ifndef HAVE_CIPHERSUITES
157         /* GNUtls cipher suite handling: The library ought to parse suite
158          * names for us, but it doesn't. It will return a list of suite names
159          * that it supports, so we can do parsing ourselves. It ought to tell
160          * us how long the list is, but it doesn't do that either, so we just
161          * have to count it manually...
162          */
163         {
164                 int i = 0;
165                 tls_cipher_suite *ptr, tmp;
166                 char cs_id[2];
167
168                 while ( gnutls_cipher_suite_info( i, cs_id, &tmp.kx, &tmp.cipher,
169                         &tmp.mac, &tmp.version ))
170                         i++;
171                 tlsg_n_ciphers = i;
172
173                 /* Store a copy */
174                 tlsg_ciphers = LDAP_MALLOC(tlsg_n_ciphers * sizeof(tls_cipher_suite));
175                 if ( !tlsg_ciphers )
176                         return -1;
177                 for ( i=0; i<tlsg_n_ciphers; i++ ) {
178                         tlsg_ciphers[i].name = gnutls_cipher_suite_info( i, cs_id,
179                                 &tlsg_ciphers[i].kx, &tlsg_ciphers[i].cipher, &tlsg_ciphers[i].mac,
180                                 &tlsg_ciphers[i].version );
181                 }
182         }
183 #endif
184         return 0;
185 }
186
187 /*
188  * Tear down the TLS subsystem. Should only be called once.
189  */
190 static void
191 tlsg_destroy( void )
192 {
193 #ifndef HAVE_CIPHERSUITES
194         LDAP_FREE( tlsg_ciphers );
195         tlsg_ciphers = NULL;
196         tlsg_n_ciphers = 0;
197 #endif
198         gnutls_global_deinit();
199 }
200
201 static tls_ctx *
202 tlsg_ctx_new ( struct ldapoptions *lo )
203 {
204         tlsg_ctx *ctx;
205
206         ctx = ber_memcalloc ( 1, sizeof (*ctx) );
207         if ( ctx ) {
208                 ctx->lo = lo;
209                 if ( gnutls_certificate_allocate_credentials( &ctx->cred )) {
210                         ber_memfree( ctx );
211                         return NULL;
212                 }
213                 ctx->refcount = 1;
214 #ifdef HAVE_CIPHERSUITES
215                 gnutls_priority_init( &ctx->prios, "NORMAL", NULL );
216 #endif
217 #ifdef LDAP_R_COMPILE
218                 ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
219 #endif
220         }
221         return (tls_ctx *)ctx;
222 }
223
224 static void
225 tlsg_ctx_ref( tls_ctx *ctx )
226 {
227         tlsg_ctx *c = (tlsg_ctx *)ctx;
228         LDAP_MUTEX_LOCK( &c->ref_mutex );
229         c->refcount++;
230         LDAP_MUTEX_UNLOCK( &c->ref_mutex );
231 }
232
233 static void
234 tlsg_ctx_free ( tls_ctx *ctx )
235 {
236         tlsg_ctx *c = (tlsg_ctx *)ctx;
237         int refcount;
238
239         if ( !c ) return;
240
241         LDAP_MUTEX_LOCK( &c->ref_mutex );
242         refcount = --c->refcount;
243         LDAP_MUTEX_UNLOCK( &c->ref_mutex );
244         if ( refcount )
245                 return;
246 #ifdef HAVE_CIPHERSUITES
247         gnutls_priority_deinit( c->prios );
248 #else
249         LDAP_FREE( c->kx_list );
250 #endif
251         gnutls_certificate_free_credentials( c->cred );
252         if ( c->dh_params )
253                 gnutls_dh_params_deinit( c->dh_params );
254         ber_memfree ( c );
255 }
256
257 static int
258 tlsg_getfile( const char *path, gnutls_datum_t *buf )
259 {
260         int rc = -1, fd;
261         struct stat st;
262
263         fd = open( path, O_RDONLY );
264         if ( fd >= 0 && fstat( fd, &st ) == 0 ) {
265                 buf->size = st.st_size;
266                 buf->data = LDAP_MALLOC( st.st_size + 1 );
267                 if ( buf->data ) {
268                         rc = read( fd, buf->data, st.st_size );
269                         close( fd );
270                         if ( rc < st.st_size )
271                                 rc = -1;
272                         else
273                                 rc = 0;
274                 }
275         }
276         return rc;
277 }
278
279 /* This is the GnuTLS default */
280 #define VERIFY_DEPTH    6
281
282 /*
283  * initialize a new TLS context
284  */
285 static int
286 tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
287 {
288         tlsg_ctx *ctx = lo->ldo_tls_ctx;
289         int rc;
290
291         if ( lo->ldo_tls_ciphersuite &&
292                 tlsg_parse_ciphers( ctx, lt->lt_ciphersuite )) {
293                 Debug( LDAP_DEBUG_ANY,
294                            "TLS: could not set cipher list %s.\n",
295                            lo->ldo_tls_ciphersuite, 0, 0 );
296                 return -1;
297         }
298
299         if (lo->ldo_tls_cacertdir != NULL) {
300                 Debug( LDAP_DEBUG_ANY, 
301                        "TLS: warning: cacertdir not implemented for gnutls\n",
302                        NULL, NULL, NULL );
303         }
304
305         if (lo->ldo_tls_cacertfile != NULL) {
306                 rc = gnutls_certificate_set_x509_trust_file( 
307                         ctx->cred,
308                         lt->lt_cacertfile,
309                         GNUTLS_X509_FMT_PEM );
310                 if ( rc < 0 ) return -1;
311         }
312
313         if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) {
314                 gnutls_x509_privkey_t key;
315                 gnutls_datum_t buf;
316                 gnutls_x509_crt_t certs[VERIFY_DEPTH];
317                 unsigned int max = VERIFY_DEPTH;
318
319                 rc = gnutls_x509_privkey_init( &key );
320                 if ( rc ) return -1;
321
322                 /* OpenSSL builds the cert chain for us, but GnuTLS
323                  * expects it to be present in the certfile. If it's
324                  * not, we have to build it ourselves. So we have to
325                  * do some special checks here...
326                  */
327                 rc = tlsg_getfile( lt->lt_keyfile, &buf );
328                 if ( rc ) return -1;
329                 rc = gnutls_x509_privkey_import( key, &buf,
330                         GNUTLS_X509_FMT_PEM );
331                 LDAP_FREE( buf.data );
332                 if ( rc < 0 ) return rc;
333
334                 rc = tlsg_getfile( lt->lt_certfile, &buf );
335                 if ( rc ) return -1;
336                 rc = gnutls_x509_crt_list_import( certs, &max, &buf,
337                         GNUTLS_X509_FMT_PEM, 0 );
338                 LDAP_FREE( buf.data );
339                 if ( rc < 0 ) return rc;
340
341                 /* If there's only one cert and it's not self-signed,
342                  * then we have to build the cert chain.
343                  */
344                 if ( max == 1 && !gnutls_x509_crt_check_issuer( certs[0], certs[0] )) {
345 #if GNUTLS_VERSION_NUMBER >= 0x020c00
346                         unsigned int i;
347                         for ( i = 1; i<VERIFY_DEPTH; i++ ) {
348                                 if ( gnutls_certificate_get_issuer( ctx->cred, certs[i-1], &certs[i], 0 ))
349                                         break;
350                                 max++;
351                                 /* If this CA is self-signed, we're done */
352                                 if ( gnutls_x509_crt_check_issuer( certs[i], certs[i] ))
353                                         break;
354                         }
355 #else
356                         gnutls_x509_crt_t *cas;
357                         unsigned int i, j, ncas;
358
359                         gnutls_certificate_get_x509_cas( ctx->cred, &cas, &ncas );
360                         for ( i = 1; i<VERIFY_DEPTH; i++ ) {
361                                 for ( j = 0; j<ncas; j++ ) {
362                                         if ( gnutls_x509_crt_check_issuer( certs[i-1], cas[j] )) {
363                                                 certs[i] = cas[j];
364                                                 max++;
365                                                 /* If this CA is self-signed, we're done */
366                                                 if ( gnutls_x509_crt_check_issuer( cas[j], cas[j] ))
367                                                         j = ncas;
368                                                 break;
369                                         }
370                                 }
371                                 /* only continue if we found a CA and it was not self-signed */
372                                 if ( j == ncas )
373                                         break;
374                         }
375 #endif
376                 }
377                 rc = gnutls_certificate_set_x509_key( ctx->cred, certs, max, key );
378                 if ( rc ) return -1;
379         } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) {
380                 Debug( LDAP_DEBUG_ANY, 
381                        "TLS: only one of certfile and keyfile specified\n",
382                        NULL, NULL, NULL );
383                 return -1;
384         }
385
386         if ( lo->ldo_tls_crlfile ) {
387                 rc = gnutls_certificate_set_x509_crl_file( 
388                         ctx->cred,
389                         lt->lt_crlfile,
390                         GNUTLS_X509_FMT_PEM );
391                 if ( rc < 0 ) return -1;
392                 rc = 0;
393         }
394
395         /* FIXME: ITS#5992 - this should be configurable,
396          * and V1 CA certs should be phased out ASAP.
397          */
398         gnutls_certificate_set_verify_flags( ctx->cred,
399                 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
400
401         if ( is_server && lo->ldo_tls_dhfile ) {
402                 gnutls_datum_t buf;
403                 rc = tlsg_getfile( lo->ldo_tls_dhfile, &buf );
404                 if ( rc ) return -1;
405                 rc = gnutls_dh_params_init( &ctx->dh_params );
406                 if ( rc == 0 )
407                         rc = gnutls_dh_params_import_pkcs3( ctx->dh_params, &buf,
408                                 GNUTLS_X509_FMT_PEM );
409                 LDAP_FREE( buf.data );
410                 if ( rc ) return -1;
411                 gnutls_certificate_set_dh_params( ctx->cred, ctx->dh_params );
412         }
413         return 0;
414 }
415
416 static tls_session *
417 tlsg_session_new ( tls_ctx * ctx, int is_server )
418 {
419         tlsg_ctx *c = (tlsg_ctx *)ctx;
420         tlsg_session *session;
421
422         session = ber_memcalloc ( 1, sizeof (*session) );
423         if ( !session )
424                 return NULL;
425
426         session->ctx = c;
427         gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT );
428 #ifdef HAVE_CIPHERSUITES
429         gnutls_priority_set( session->session, c->prios );
430 #else
431         gnutls_set_default_priority( session->session );
432         if ( c->kx_list ) {
433                 gnutls_kx_set_priority( session->session, c->kx_list );
434                 gnutls_cipher_set_priority( session->session, c->cipher_list );
435                 gnutls_mac_set_priority( session->session, c->mac_list );
436         }
437 #endif
438         if ( c->cred )
439                 gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, c->cred );
440         
441         if ( is_server ) {
442                 int flag = 0;
443                 if ( c->lo->ldo_tls_require_cert ) {
444                         flag = GNUTLS_CERT_REQUEST;
445                         if ( c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
446                                 c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD )
447                                 flag = GNUTLS_CERT_REQUIRE;
448                         gnutls_certificate_server_set_request( session->session, flag );
449                 }
450         }
451         return (tls_session *)session;
452
453
454 static int
455 tlsg_session_accept( tls_session *session )
456 {
457         tlsg_session *s = (tlsg_session *)session;
458         int rc;
459
460         rc = gnutls_handshake( s->session );
461         if ( rc == 0 && s->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) {
462                 const gnutls_datum_t *peer_cert_list;
463                 unsigned int list_size;
464
465                 peer_cert_list = gnutls_certificate_get_peers( s->session, 
466                                                 &list_size );
467                 if ( !peer_cert_list && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_TRY ) 
468                         rc = 0;
469                 else {
470                         rc = tlsg_cert_verify( s );
471                         if ( rc && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW )
472                                 rc = 0;
473                 }
474         }
475         return rc;
476 }
477
478 static int
479 tlsg_session_connect( LDAP *ld, tls_session *session )
480 {
481         return tlsg_session_accept( session);
482 }
483
484 static int
485 tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc )
486 {
487         tlsg_session *s = (tlsg_session *)session;
488
489         if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
490                 return 0;
491
492         switch (gnutls_record_get_direction (s->session)) {
493         case 0: 
494                 sb->sb_trans_needs_read = 1;
495                 return 1;
496         case 1:
497                 sb->sb_trans_needs_write = 1;
498                 return 1;
499         }
500         return 0;
501 }
502
503 static char *
504 tlsg_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
505 {
506         return (char *)gnutls_strerror( rc );
507 }
508
509 static void
510 tlsg_x509_cert_dn( struct berval *cert, struct berval *dn, int get_subject )
511 {
512         BerElementBuffer berbuf;
513         BerElement *ber = (BerElement *)&berbuf;
514         ber_tag_t tag;
515         ber_len_t len;
516         ber_int_t i;
517
518         ber_init2( ber, cert, LBER_USE_DER );
519         tag = ber_skip_tag( ber, &len );        /* Sequence */
520         tag = ber_skip_tag( ber, &len );        /* Sequence */
521         tag = ber_peek_tag( ber, &len );        /* Context + Constructed (version) */
522         if ( tag == 0xa0 ) {    /* Version is optional */
523                 tag = ber_skip_tag( ber, &len );
524                 tag = ber_get_int( ber, &i );   /* Int: Version */
525         }
526         tag = ber_skip_tag( ber, &len );        /* Int: Serial (can be longer than ber_int_t) */
527         ber_skip_data( ber, len );
528         tag = ber_skip_tag( ber, &len );        /* Sequence: Signature */
529         ber_skip_data( ber, len );
530         if ( !get_subject ) {
531                 tag = ber_peek_tag( ber, &len );        /* Sequence: Issuer DN */
532         } else {
533                 tag = ber_skip_tag( ber, &len );
534                 ber_skip_data( ber, len );
535                 tag = ber_skip_tag( ber, &len );        /* Sequence: Validity */
536                 ber_skip_data( ber, len );
537                 tag = ber_peek_tag( ber, &len );        /* Sequence: Subject DN */
538         }
539         len = ber_ptrlen( ber );
540         dn->bv_val = cert->bv_val + len;
541         dn->bv_len = cert->bv_len - len;
542 }
543
544 static int
545 tlsg_session_my_dn( tls_session *session, struct berval *der_dn )
546 {
547         tlsg_session *s = (tlsg_session *)session;
548         const gnutls_datum_t *x;
549         struct berval bv;
550
551         x = gnutls_certificate_get_ours( s->session );
552
553         if (!x) return LDAP_INVALID_CREDENTIALS;
554         
555         bv.bv_val = (char *) x->data;
556         bv.bv_len = x->size;
557
558         tlsg_x509_cert_dn( &bv, der_dn, 1 );
559         return 0;
560 }
561
562 static int
563 tlsg_session_peer_dn( tls_session *session, struct berval *der_dn )
564 {
565         tlsg_session *s = (tlsg_session *)session;
566         if ( !s->peer_der_dn.bv_val ) {
567                 const gnutls_datum_t *peer_cert_list;
568                 unsigned int list_size;
569                 struct berval bv;
570
571                 peer_cert_list = gnutls_certificate_get_peers( s->session, 
572                                                         &list_size );
573                 if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS;
574
575                 bv.bv_len = peer_cert_list->size;
576                 bv.bv_val = (char *) peer_cert_list->data;
577
578                 tlsg_x509_cert_dn( &bv, &s->peer_der_dn, 1 );
579         }
580         *der_dn = s->peer_der_dn;
581         return 0;
582 }
583
584 /* what kind of hostname were we given? */
585 #define IS_DNS  0
586 #define IS_IP4  1
587 #define IS_IP6  2
588
589 #define CN_OID  "2.5.4.3"
590
591 static int
592 tlsg_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
593 {
594         tlsg_session *s = (tlsg_session *)session;
595         int i, ret;
596         const gnutls_datum_t *peer_cert_list;
597         unsigned int list_size;
598         char altname[NI_MAXHOST];
599         size_t altnamesize;
600
601         gnutls_x509_crt_t cert;
602         const char *name;
603         char *ptr;
604         char *domain = NULL;
605 #ifdef LDAP_PF_INET6
606         struct in6_addr addr;
607 #else
608         struct in_addr addr;
609 #endif
610         int len1 = 0, len2 = 0;
611         int ntype = IS_DNS;
612
613         if( ldap_int_hostname &&
614                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
615         {
616                 name = ldap_int_hostname;
617         } else {
618                 name = name_in;
619         }
620
621         peer_cert_list = gnutls_certificate_get_peers( s->session, 
622                                                 &list_size );
623         if ( !peer_cert_list ) {
624                 Debug( LDAP_DEBUG_ANY,
625                         "TLS: unable to get peer certificate.\n",
626                         0, 0, 0 );
627                 /* If this was a fatal condition, things would have
628                  * aborted long before now.
629                  */
630                 return LDAP_SUCCESS;
631         }
632         ret = gnutls_x509_crt_init( &cert );
633         if ( ret < 0 )
634                 return LDAP_LOCAL_ERROR;
635         ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER );
636         if ( ret ) {
637                 gnutls_x509_crt_deinit( cert );
638                 return LDAP_LOCAL_ERROR;
639         }
640
641 #ifdef LDAP_PF_INET6
642         if (inet_pton(AF_INET6, name, &addr)) {
643                 ntype = IS_IP6;
644         } else 
645 #endif
646         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
647                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
648         }
649         
650         if (ntype == IS_DNS) {
651                 len1 = strlen(name);
652                 domain = strchr(name, '.');
653                 if (domain) {
654                         len2 = len1 - (domain-name);
655                 }
656         }
657
658         for ( i=0, ret=0; ret >= 0; i++ ) {
659                 altnamesize = sizeof(altname);
660                 ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 
661                         altname, &altnamesize, NULL );
662                 if ( ret < 0 ) break;
663
664                 /* ignore empty */
665                 if ( altnamesize == 0 ) continue;
666
667                 if ( ret == GNUTLS_SAN_DNSNAME ) {
668                         if (ntype != IS_DNS) continue;
669         
670                         /* Is this an exact match? */
671                         if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) {
672                                 break;
673                         }
674
675                         /* Is this a wildcard match? */
676                         if (domain && (altname[0] == '*') && (altname[1] == '.') &&
677                                 (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2))
678                         {
679                                 break;
680                         }
681                 } else if ( ret == GNUTLS_SAN_IPADDRESS ) {
682                         if (ntype == IS_DNS) continue;
683
684 #ifdef LDAP_PF_INET6
685                         if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) {
686                                 continue;
687                         } else
688 #endif
689                         if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) {
690                                 continue;
691                         }
692                         if (!memcmp(altname, &addr, altnamesize)) {
693                                 break;
694                         }
695                 }
696         }
697         if ( ret >= 0 ) {
698                 ret = LDAP_SUCCESS;
699         } else {
700                 /* find the last CN */
701                 i=0;
702                 do {
703                         altnamesize = 0;
704                         ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
705                                 i, 1, altname, &altnamesize );
706                         if ( ret == GNUTLS_E_SHORT_MEMORY_BUFFER )
707                                 i++;
708                         else
709                                 break;
710                 } while ( 1 );
711
712                 if ( i ) {
713                         altnamesize = sizeof(altname);
714                         ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
715                                 i-1, 0, altname, &altnamesize );
716                 }
717
718                 if ( ret < 0 ) {
719                         Debug( LDAP_DEBUG_ANY,
720                                 "TLS: unable to get common name from peer certificate.\n",
721                                 0, 0, 0 );
722                         ret = LDAP_CONNECT_ERROR;
723                         if ( ld->ld_error ) {
724                                 LDAP_FREE( ld->ld_error );
725                         }
726                         ld->ld_error = LDAP_STRDUP(
727                                 _("TLS: unable to get CN from peer certificate"));
728
729                 } else {
730                         ret = LDAP_LOCAL_ERROR;
731                         if ( !len1 ) len1 = strlen( name );
732                         if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) {
733                                 ret = LDAP_SUCCESS;
734
735                         } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) {
736                                         /* Is this a wildcard match? */
737                                 if( domain &&
738                                         (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) {
739                                         ret = LDAP_SUCCESS;
740                                 }
741                         }
742                 }
743
744                 if( ret == LDAP_LOCAL_ERROR ) {
745                         altname[altnamesize] = '\0';
746                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
747                                 "common name in certificate (%s).\n", 
748                                 name, altname, 0 );
749                         ret = LDAP_CONNECT_ERROR;
750                         if ( ld->ld_error ) {
751                                 LDAP_FREE( ld->ld_error );
752                         }
753                         ld->ld_error = LDAP_STRDUP(
754                                 _("TLS: hostname does not match CN in peer certificate"));
755                 }
756         }
757         gnutls_x509_crt_deinit( cert );
758         return ret;
759 }
760
761 static int
762 tlsg_session_strength( tls_session *session )
763 {
764         tlsg_session *s = (tlsg_session *)session;
765         gnutls_cipher_algorithm_t c;
766
767         c = gnutls_cipher_get( s->session );
768         return gnutls_cipher_get_key_size( c ) * 8;
769 }
770
771 static int
772 tlsg_session_unique( tls_session *sess, struct berval *buf, int is_server)
773 {
774 /* channel bindings added in 2.12.0 */
775 #if GNUTLS_VERSION_NUMBER >= 0x020c00
776         tlsg_session *s = (tlsg_session *)sess;
777         gnutls_datum_t cb;
778         int rc;
779
780         rc = gnutls_session_channel_binding( s->session, GNUTLS_CB_TLS_UNIQUE, &cb );
781         if ( rc == 0 ) {
782                 int len = cb.size;
783                 if ( len > buf->bv_len )
784                         len = buf->bv_len;
785                 buf->bv_len = len;
786                 memcpy( buf->bv_val, cb.data, len );
787                 return len;
788         }
789 #endif
790         return 0;
791 }
792
793 static const char *
794 tlsg_session_version( tls_session *sess )
795 {
796         tlsg_session *s = (tlsg_session *)sess;
797         return gnutls_protocol_get_name(gnutls_protocol_get_version( s->session ));
798 }
799
800 static const char *
801 tlsg_session_cipher( tls_session *sess )
802 {
803         tlsg_session *s = (tlsg_session *)sess;
804         return gnutls_cipher_get_name(gnutls_cipher_get( s->session ));
805 }
806
807 static int
808 tlsg_session_peercert( tls_session *sess, struct berval *der )
809 {
810         tlsg_session *s = (tlsg_session *)sess;
811         const gnutls_datum_t *peer_cert_list;
812         unsigned int list_size;
813
814         peer_cert_list = gnutls_certificate_get_peers( s->session, &list_size );
815         if (!peer_cert_list)
816                 return -1;
817         der->bv_len = peer_cert_list[0].size;
818         der->bv_val = LDAP_MALLOC( der->bv_len );
819         if (!der->bv_val)
820                 return -1;
821         memcpy(der->bv_val, peer_cert_list[0].data, der->bv_len);
822         return 0;
823 }
824
825 /* suites is a string of colon-separated cipher suite names. */
826 static int
827 tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites )
828 {
829 #ifdef HAVE_CIPHERSUITES
830         const char *err;
831         int rc = gnutls_priority_init( &ctx->prios, suites, &err );
832         if ( rc )
833                 ctx->prios = NULL;
834         return rc;
835 #else
836         char *ptr, *end;
837         int i, j, len, num;
838         int *list, nkx = 0, ncipher = 0, nmac = 0;
839         int *kx, *cipher, *mac;
840
841         num = 0;
842         ptr = suites;
843         do {
844                 end = strchr(ptr, ':');
845                 if ( end )
846                         len = end - ptr;
847                 else
848                         len = strlen(ptr);
849                 for (i=0; i<tlsg_n_ciphers; i++) {
850                         if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
851                                 num++;
852                                 break;
853                         }
854                 }
855                 if ( i == tlsg_n_ciphers ) {
856                         /* unrecognized cipher suite */
857                         return -1;
858                 }
859                 ptr += len + 1;
860         } while (end);
861
862         /* Space for all 3 lists */
863         list = LDAP_MALLOC( (num+1) * sizeof(int) * 3 );
864         if ( !list )
865                 return -1;
866         kx = list;
867         cipher = kx+num+1;
868         mac = cipher+num+1;
869
870         ptr = suites;
871         do {
872                 end = strchr(ptr, ':');
873                 if ( end )
874                         len = end - ptr;
875                 else
876                         len = strlen(ptr);
877                 for (i=0; i<tlsg_n_ciphers; i++) {
878                         /* For each cipher suite, insert its algorithms into
879                          * their respective priority lists. Make sure they
880                          * only appear once in each list.
881                          */
882                         if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
883                                 for (j=0; j<nkx; j++)
884                                         if ( kx[j] == tlsg_ciphers[i].kx )
885                                                 break;
886                                 if ( j == nkx )
887                                         kx[nkx++] = tlsg_ciphers[i].kx;
888                                 for (j=0; j<ncipher; j++)
889                                         if ( cipher[j] == tlsg_ciphers[i].cipher )
890                                                 break;
891                                 if ( j == ncipher ) 
892                                         cipher[ncipher++] = tlsg_ciphers[i].cipher;
893                                 for (j=0; j<nmac; j++)
894                                         if ( mac[j] == tlsg_ciphers[i].mac )
895                                                 break;
896                                 if ( j == nmac )
897                                         mac[nmac++] = tlsg_ciphers[i].mac;
898                                 break;
899                         }
900                 }
901                 ptr += len + 1;
902         } while (end);
903         kx[nkx] = 0;
904         cipher[ncipher] = 0;
905         mac[nmac] = 0;
906         ctx->kx_list = kx;
907         ctx->cipher_list = cipher;
908         ctx->mac_list = mac;
909         return 0;
910 #endif
911 }
912
913 /*
914  * TLS support for LBER Sockbufs
915  */
916
917 struct tls_data {
918         tlsg_session            *session;
919         Sockbuf_IO_Desc         *sbiod;
920 };
921
922 static ssize_t
923 tlsg_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len )
924 {
925         struct tls_data         *p;
926
927         if ( buf == NULL || len <= 0 ) return 0;
928
929         p = (struct tls_data *)ptr;
930
931         if ( p == NULL || p->sbiod == NULL ) {
932                 return 0;
933         }
934
935         return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
936 }
937
938 static ssize_t
939 tlsg_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len )
940 {
941         struct tls_data         *p;
942         
943         if ( buf == NULL || len <= 0 ) return 0;
944         
945         p = (struct tls_data *)ptr;
946
947         if ( p == NULL || p->sbiod == NULL ) {
948                 return 0;
949         }
950
951         return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
952 }
953
954 static int
955 tlsg_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
956 {
957         struct tls_data         *p;
958         tlsg_session    *session = arg;
959
960         assert( sbiod != NULL );
961
962         p = LBER_MALLOC( sizeof( *p ) );
963         if ( p == NULL ) {
964                 return -1;
965         }
966         
967         gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p );
968         gnutls_transport_set_pull_function( session->session, tlsg_recv );
969         gnutls_transport_set_push_function( session->session, tlsg_send );
970         p->session = session;
971         p->sbiod = sbiod;
972         sbiod->sbiod_pvt = p;
973         return 0;
974 }
975
976 static int
977 tlsg_sb_remove( Sockbuf_IO_Desc *sbiod )
978 {
979         struct tls_data         *p;
980         
981         assert( sbiod != NULL );
982         assert( sbiod->sbiod_pvt != NULL );
983
984         p = (struct tls_data *)sbiod->sbiod_pvt;
985         gnutls_deinit ( p->session->session );
986         LBER_FREE( p->session );
987         LBER_FREE( sbiod->sbiod_pvt );
988         sbiod->sbiod_pvt = NULL;
989         return 0;
990 }
991
992 static int
993 tlsg_sb_close( Sockbuf_IO_Desc *sbiod )
994 {
995         struct tls_data         *p;
996         
997         assert( sbiod != NULL );
998         assert( sbiod->sbiod_pvt != NULL );
999
1000         p = (struct tls_data *)sbiod->sbiod_pvt;
1001         gnutls_bye ( p->session->session, GNUTLS_SHUT_WR );
1002         return 0;
1003 }
1004
1005 static int
1006 tlsg_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
1007 {
1008         struct tls_data         *p;
1009         
1010         assert( sbiod != NULL );
1011         assert( sbiod->sbiod_pvt != NULL );
1012
1013         p = (struct tls_data *)sbiod->sbiod_pvt;
1014         
1015         if ( opt == LBER_SB_OPT_GET_SSL ) {
1016                 *((tlsg_session **)arg) = p->session;
1017                 return 1;
1018                 
1019         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
1020                 if( gnutls_record_check_pending( p->session->session ) > 0 ) {
1021                         return 1;
1022                 }
1023         }
1024         
1025         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
1026 }
1027
1028 static ber_slen_t
1029 tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1030 {
1031         struct tls_data         *p;
1032         ber_slen_t              ret;
1033
1034         assert( sbiod != NULL );
1035         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
1036
1037         p = (struct tls_data *)sbiod->sbiod_pvt;
1038
1039         ret = gnutls_record_recv ( p->session->session, buf, len );
1040         switch (ret) {
1041         case GNUTLS_E_INTERRUPTED:
1042         case GNUTLS_E_AGAIN:
1043                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
1044                 sock_errset(EWOULDBLOCK);
1045                 ret = 0;
1046                 break;
1047         case GNUTLS_E_REHANDSHAKE:
1048                 for ( ret = gnutls_handshake ( p->session->session );
1049                       ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN;
1050                       ret = gnutls_handshake ( p->session->session ) );
1051                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
1052                 ret = 0;
1053                 break;
1054         default:
1055                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
1056         }
1057         return ret;
1058 }
1059
1060 static ber_slen_t
1061 tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1062 {
1063         struct tls_data         *p;
1064         ber_slen_t              ret;
1065
1066         assert( sbiod != NULL );
1067         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
1068
1069         p = (struct tls_data *)sbiod->sbiod_pvt;
1070
1071         ret = gnutls_record_send ( p->session->session, (char *)buf, len );
1072
1073         if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) {
1074                 sbiod->sbiod_sb->sb_trans_needs_write = 1;
1075                 sock_errset(EWOULDBLOCK);
1076                 ret = 0;
1077         } else {
1078                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
1079         }
1080         return ret;
1081 }
1082
1083 static Sockbuf_IO tlsg_sbio =
1084 {
1085         tlsg_sb_setup,          /* sbi_setup */
1086         tlsg_sb_remove,         /* sbi_remove */
1087         tlsg_sb_ctrl,           /* sbi_ctrl */
1088         tlsg_sb_read,           /* sbi_read */
1089         tlsg_sb_write,          /* sbi_write */
1090         tlsg_sb_close           /* sbi_close */
1091 };
1092
1093 /* Certs are not automatically varified during the handshake */
1094 static int
1095 tlsg_cert_verify( tlsg_session *ssl )
1096 {
1097         unsigned int status = 0;
1098         int err;
1099         time_t now = time(0);
1100         time_t peertime;
1101
1102         err = gnutls_certificate_verify_peers2( ssl->session, &status );
1103         if ( err < 0 ) {
1104                 Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n",
1105                         err,0,0 );
1106                 return -1;
1107         }
1108         if ( status ) {
1109                 Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n",
1110                         status, 0,0 );
1111                 return -1;
1112         }
1113         peertime = gnutls_certificate_expiration_time_peers( ssl->session );
1114         if ( peertime == (time_t) -1 ) {
1115                 Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_expiration_time_peers failed\n",
1116                         0, 0, 0 );
1117                 return -1;
1118         }
1119         if ( peertime < now ) {
1120                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n",
1121                         0, 0, 0 );
1122                 return -1;
1123         }
1124         peertime = gnutls_certificate_activation_time_peers( ssl->session );
1125         if ( peertime == (time_t) -1 ) {
1126                 Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_activation_time_peers failed\n",
1127                         0, 0, 0 );
1128                 return -1;
1129         }
1130         if ( peertime > now ) {
1131                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n",
1132                         0, 0, 0 );
1133                 return -1;
1134         }
1135         return 0;
1136 }
1137
1138 tls_impl ldap_int_tls_impl = {
1139         "GnuTLS",
1140
1141         tlsg_init,
1142         tlsg_destroy,
1143
1144         tlsg_ctx_new,
1145         tlsg_ctx_ref,
1146         tlsg_ctx_free,
1147         tlsg_ctx_init,
1148
1149         tlsg_session_new,
1150         tlsg_session_connect,
1151         tlsg_session_accept,
1152         tlsg_session_upflags,
1153         tlsg_session_errmsg,
1154         tlsg_session_my_dn,
1155         tlsg_session_peer_dn,
1156         tlsg_session_chkhost,
1157         tlsg_session_strength,
1158         tlsg_session_unique,
1159         tlsg_session_version,
1160         tlsg_session_cipher,
1161         tlsg_session_peercert,
1162
1163         &tlsg_sbio,
1164
1165 #ifdef LDAP_R_COMPILE
1166         tlsg_thr_init,
1167 #else
1168         NULL,
1169 #endif
1170
1171         0
1172 };
1173
1174 #endif /* HAVE_GNUTLS */