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