]> git.sur5r.net Git - openldap/blob - libraries/libldap/tls_g.c
720b399475379da7bf82c6c97f04ec8187c8d201
[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                 rc = tlsg_cert_verify( s );
406                 if ( rc && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW )
407                         rc = 0;
408         }
409         return rc;
410 }
411
412 static int
413 tlsg_session_connect( LDAP *ld, tls_session *session )
414 {
415         return tlsg_session_accept( session);
416 }
417
418 static int
419 tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc )
420 {
421         tlsg_session *s = (tlsg_session *)session;
422
423         if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
424                 return 0;
425
426         switch (gnutls_record_get_direction (s->session)) {
427         case 0: 
428                 sb->sb_trans_needs_read = 1;
429                 return 1;
430         case 1:
431                 sb->sb_trans_needs_write = 1;
432                 return 1;
433         }
434         return 0;
435 }
436
437 static char *
438 tlsg_session_errmsg( int rc, char *buf, size_t len )
439 {
440         return (char *)gnutls_strerror( rc );
441 }
442
443 static void
444 tlsg_x509_cert_dn( struct berval *cert, struct berval *dn, int get_subject )
445 {
446         BerElementBuffer berbuf;
447         BerElement *ber = (BerElement *)&berbuf;
448         ber_tag_t tag;
449         ber_len_t len;
450         ber_int_t i;
451
452         ber_init2( ber, cert, LBER_USE_DER );
453         tag = ber_skip_tag( ber, &len );        /* Sequence */
454         tag = ber_skip_tag( ber, &len );        /* Sequence */
455         tag = ber_skip_tag( ber, &len );        /* Context + Constructed (version) */
456         if ( tag == 0xa0 )      /* Version is optional */
457                 tag = ber_get_int( ber, &i );   /* Int: Version */
458         tag = ber_get_int( ber, &i );   /* Int: Serial */
459         tag = ber_skip_tag( ber, &len );        /* Sequence: Signature */
460         ber_skip_data( ber, len );
461         if ( !get_subject ) {
462                 tag = ber_peek_tag( ber, &len );        /* Sequence: Issuer DN */
463         } else {
464                 tag = ber_skip_tag( ber, &len );
465                 ber_skip_data( ber, len );
466                 tag = ber_skip_tag( ber, &len );        /* Sequence: Validity */
467                 ber_skip_data( ber, len );
468                 tag = ber_peek_tag( ber, &len );        /* Sequence: Subject DN */
469         }
470         len = ber_ptrlen( ber );
471         dn->bv_val = cert->bv_val + len;
472         dn->bv_len = cert->bv_len - len;
473 }
474
475 static int
476 tlsg_session_my_dn( tls_session *session, struct berval *der_dn )
477 {
478         tlsg_session *s = (tlsg_session *)session;
479         const gnutls_datum_t *x;
480         struct berval bv;
481
482         x = gnutls_certificate_get_ours( s->session );
483
484         if (!x) return LDAP_INVALID_CREDENTIALS;
485         
486         bv.bv_val = x->data;
487         bv.bv_len = x->size;
488
489         tlsg_x509_cert_dn( &bv, der_dn, 1 );
490         return 0;
491 }
492
493 static int
494 tlsg_session_peer_dn( tls_session *session, struct berval *der_dn )
495 {
496         tlsg_session *s = (tlsg_session *)session;
497         if ( !s->peer_der_dn.bv_val ) {
498                 const gnutls_datum_t *peer_cert_list;
499                 int list_size;
500                 struct berval bv;
501
502                 peer_cert_list = gnutls_certificate_get_peers( s->session, 
503                                                         &list_size );
504                 if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS;
505
506                 bv.bv_len = peer_cert_list->size;
507                 bv.bv_val = peer_cert_list->data;
508
509                 tlsg_x509_cert_dn( &bv, &s->peer_der_dn, 1 );
510         }
511         *der_dn = s->peer_der_dn;
512         return 0;
513 }
514
515 /* what kind of hostname were we given? */
516 #define IS_DNS  0
517 #define IS_IP4  1
518 #define IS_IP6  2
519
520 #define CN_OID  "2.5.4.3"
521
522 static int
523 tlsg_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
524 {
525         tlsg_session *s = (tlsg_session *)session;
526         int i, ret;
527         const gnutls_datum_t *peer_cert_list;
528         int list_size;
529         struct berval bv;
530         char altname[NI_MAXHOST];
531         size_t altnamesize;
532
533         gnutls_x509_crt_t cert;
534         gnutls_datum_t *x;
535         const char *name;
536         char *ptr;
537         char *domain = NULL;
538 #ifdef LDAP_PF_INET6
539         struct in6_addr addr;
540 #else
541         struct in_addr addr;
542 #endif
543         int n, len1 = 0, len2 = 0;
544         int ntype = IS_DNS;
545         time_t now = time(0);
546
547         if( ldap_int_hostname &&
548                 ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
549         {
550                 name = ldap_int_hostname;
551         } else {
552                 name = name_in;
553         }
554
555         peer_cert_list = gnutls_certificate_get_peers( s->session, 
556                                                 &list_size );
557         if ( !peer_cert_list ) {
558                 Debug( LDAP_DEBUG_ANY,
559                         "TLS: unable to get peer certificate.\n",
560                         0, 0, 0 );
561                 /* If this was a fatal condition, things would have
562                  * aborted long before now.
563                  */
564                 return LDAP_SUCCESS;
565         }
566         ret = gnutls_x509_crt_init( &cert );
567         if ( ret < 0 )
568                 return LDAP_LOCAL_ERROR;
569         ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER );
570         if ( ret ) {
571                 gnutls_x509_crt_deinit( cert );
572                 return LDAP_LOCAL_ERROR;
573         }
574
575 #ifdef LDAP_PF_INET6
576         if (name[0] == '[' && strchr(name, ']')) {
577                 char *n2 = ldap_strdup(name+1);
578                 *strchr(n2, ']') = 0;
579                 if (inet_pton(AF_INET6, n2, &addr))
580                         ntype = IS_IP6;
581                 LDAP_FREE(n2);
582         } else 
583 #endif
584         if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
585                 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
586         }
587         
588         if (ntype == IS_DNS) {
589                 len1 = strlen(name);
590                 domain = strchr(name, '.');
591                 if (domain) {
592                         len2 = len1 - (domain-name);
593                 }
594         }
595
596         for ( i=0, ret=0; ret >= 0; i++ ) {
597                 altnamesize = sizeof(altname);
598                 ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 
599                         altname, &altnamesize, NULL );
600                 if ( ret < 0 ) break;
601
602                 /* ignore empty */
603                 if ( altnamesize == 0 ) continue;
604
605                 if ( ret == GNUTLS_SAN_DNSNAME ) {
606                         if (ntype != IS_DNS) continue;
607         
608                         /* Is this an exact match? */
609                         if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) {
610                                 break;
611                         }
612
613                         /* Is this a wildcard match? */
614                         if (domain && (altname[0] == '*') && (altname[1] == '.') &&
615                                 (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2))
616                         {
617                                 break;
618                         }
619                 } else if ( ret == GNUTLS_SAN_IPADDRESS ) {
620                         if (ntype == IS_DNS) continue;
621
622 #ifdef LDAP_PF_INET6
623                         if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) {
624                                 continue;
625                         } else
626 #endif
627                         if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) {
628                                 continue;
629                         }
630                         if (!memcmp(altname, &addr, altnamesize)) {
631                                 break;
632                         }
633                 }
634         }
635         if ( ret >= 0 ) {
636                 ret = LDAP_SUCCESS;
637         } else {
638                 altnamesize = sizeof(altname);
639                 ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
640                         0, 0, altname, &altnamesize );
641                 if ( ret < 0 ) {
642                         Debug( LDAP_DEBUG_ANY,
643                                 "TLS: unable to get common name from peer certificate.\n",
644                                 0, 0, 0 );
645                         ret = LDAP_CONNECT_ERROR;
646                         if ( ld->ld_error ) {
647                                 LDAP_FREE( ld->ld_error );
648                         }
649                         ld->ld_error = LDAP_STRDUP(
650                                 _("TLS: unable to get CN from peer certificate"));
651
652                 } else {
653                         ret = LDAP_LOCAL_ERROR;
654                         if ( !len1 ) len1 = strlen( name );
655                         if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) {
656                                 ret = LDAP_SUCCESS;
657
658                         } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) {
659                                         /* Is this a wildcard match? */
660                                 if( domain &&
661                                         (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) {
662                                         ret = LDAP_SUCCESS;
663                                 }
664                         }
665                 }
666
667                 if( ret == LDAP_LOCAL_ERROR ) {
668                         altname[altnamesize] = '\0';
669                         Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
670                                 "common name in certificate (%s).\n", 
671                                 name, altname, 0 );
672                         ret = LDAP_CONNECT_ERROR;
673                         if ( ld->ld_error ) {
674                                 LDAP_FREE( ld->ld_error );
675                         }
676                         ld->ld_error = LDAP_STRDUP(
677                                 _("TLS: hostname does not match CN in peer certificate"));
678                 }
679         }
680         gnutls_x509_crt_deinit( cert );
681         return ret;
682 }
683
684 static int
685 tlsg_session_strength( tls_session *session )
686 {
687         tlsg_session *s = (tlsg_session *)session;
688         gnutls_cipher_algorithm_t c;
689
690         c = gnutls_cipher_get( s->session );
691         return gnutls_cipher_get_key_size( c ) * 8;
692 }
693
694 /* suites is a string of colon-separated cipher suite names. */
695 static int
696 tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites )
697 {
698 #ifdef HAVE_CIPHERSUITES
699         const char *err;
700         return gnutls_priority_init( &ctx->prios, suites, &err );
701 #else
702         char *ptr, *end;
703         int i, j, len, num;
704         int *list, nkx = 0, ncipher = 0, nmac = 0;
705         int *kx, *cipher, *mac;
706
707         num = 0;
708         ptr = suites;
709         do {
710                 end = strchr(ptr, ':');
711                 if ( end )
712                         len = end - ptr;
713                 else
714                         len = strlen(ptr);
715                 for (i=0; i<tlsg_n_ciphers; i++) {
716                         if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
717                                 num++;
718                                 break;
719                         }
720                 }
721                 if ( i == tlsg_n_ciphers ) {
722                         /* unrecognized cipher suite */
723                         return -1;
724                 }
725                 ptr += len + 1;
726         } while (end);
727
728         /* Space for all 3 lists */
729         list = LDAP_MALLOC( (num+1) * sizeof(int) * 3 );
730         if ( !list )
731                 return -1;
732         kx = list;
733         cipher = kx+num+1;
734         mac = cipher+num+1;
735
736         ptr = suites;
737         do {
738                 end = strchr(ptr, ':');
739                 if ( end )
740                         len = end - ptr;
741                 else
742                         len = strlen(ptr);
743                 for (i=0; i<tlsg_n_ciphers; i++) {
744                         /* For each cipher suite, insert its algorithms into
745                          * their respective priority lists. Make sure they
746                          * only appear once in each list.
747                          */
748                         if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
749                                 for (j=0; j<nkx; j++)
750                                         if ( kx[j] == tlsg_ciphers[i].kx )
751                                                 break;
752                                 if ( j == nkx )
753                                         kx[nkx++] = tlsg_ciphers[i].kx;
754                                 for (j=0; j<ncipher; j++)
755                                         if ( cipher[j] == tlsg_ciphers[i].cipher )
756                                                 break;
757                                 if ( j == ncipher ) 
758                                         cipher[ncipher++] = tlsg_ciphers[i].cipher;
759                                 for (j=0; j<nmac; j++)
760                                         if ( mac[j] == tlsg_ciphers[i].mac )
761                                                 break;
762                                 if ( j == nmac )
763                                         mac[nmac++] = tlsg_ciphers[i].mac;
764                                 break;
765                         }
766                 }
767                 ptr += len + 1;
768         } while (end);
769         kx[nkx] = 0;
770         cipher[ncipher] = 0;
771         mac[nmac] = 0;
772         ctx->kx_list = kx;
773         ctx->cipher_list = cipher;
774         ctx->mac_list = mac;
775         return 0;
776 #endif
777 }
778
779 /*
780  * TLS support for LBER Sockbufs
781  */
782
783 struct tls_data {
784         tlsg_session            *session;
785         Sockbuf_IO_Desc         *sbiod;
786 };
787
788 static ssize_t
789 tlsg_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len )
790 {
791         struct tls_data         *p;
792
793         if ( buf == NULL || len <= 0 ) return 0;
794
795         p = (struct tls_data *)ptr;
796
797         if ( p == NULL || p->sbiod == NULL ) {
798                 return 0;
799         }
800
801         return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
802 }
803
804 static ssize_t
805 tlsg_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len )
806 {
807         struct tls_data         *p;
808         
809         if ( buf == NULL || len <= 0 ) return 0;
810         
811         p = (struct tls_data *)ptr;
812
813         if ( p == NULL || p->sbiod == NULL ) {
814                 return 0;
815         }
816
817         return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
818 }
819
820 static int
821 tlsg_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
822 {
823         struct tls_data         *p;
824         tlsg_session    *session = arg;
825
826         assert( sbiod != NULL );
827
828         p = LBER_MALLOC( sizeof( *p ) );
829         if ( p == NULL ) {
830                 return -1;
831         }
832         
833         gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p );
834         gnutls_transport_set_pull_function( session->session, tlsg_recv );
835         gnutls_transport_set_push_function( session->session, tlsg_send );
836         p->session = session;
837         p->sbiod = sbiod;
838         sbiod->sbiod_pvt = p;
839         return 0;
840 }
841
842 static int
843 tlsg_sb_remove( Sockbuf_IO_Desc *sbiod )
844 {
845         struct tls_data         *p;
846         
847         assert( sbiod != NULL );
848         assert( sbiod->sbiod_pvt != NULL );
849
850         p = (struct tls_data *)sbiod->sbiod_pvt;
851         gnutls_deinit ( p->session->session );
852         LBER_FREE( p->session );
853         LBER_FREE( sbiod->sbiod_pvt );
854         sbiod->sbiod_pvt = NULL;
855         return 0;
856 }
857
858 static int
859 tlsg_sb_close( Sockbuf_IO_Desc *sbiod )
860 {
861         struct tls_data         *p;
862         
863         assert( sbiod != NULL );
864         assert( sbiod->sbiod_pvt != NULL );
865
866         p = (struct tls_data *)sbiod->sbiod_pvt;
867         gnutls_bye ( p->session->session, GNUTLS_SHUT_RDWR );
868         return 0;
869 }
870
871 static int
872 tlsg_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
873 {
874         struct tls_data         *p;
875         
876         assert( sbiod != NULL );
877         assert( sbiod->sbiod_pvt != NULL );
878
879         p = (struct tls_data *)sbiod->sbiod_pvt;
880         
881         if ( opt == LBER_SB_OPT_GET_SSL ) {
882                 *((tlsg_session **)arg) = p->session;
883                 return 1;
884                 
885         } else if ( opt == LBER_SB_OPT_DATA_READY ) {
886                 if( gnutls_record_check_pending( p->session->session ) > 0 ) {
887                         return 1;
888                 }
889         }
890         
891         return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
892 }
893
894 static ber_slen_t
895 tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
896 {
897         struct tls_data         *p;
898         ber_slen_t              ret;
899         int                     err;
900
901         assert( sbiod != NULL );
902         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
903
904         p = (struct tls_data *)sbiod->sbiod_pvt;
905
906         ret = gnutls_record_recv ( p->session->session, buf, len );
907         switch (ret) {
908         case GNUTLS_E_INTERRUPTED:
909         case GNUTLS_E_AGAIN:
910                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
911                 sock_errset(EWOULDBLOCK);
912                 ret = 0;
913                 break;
914         case GNUTLS_E_REHANDSHAKE:
915                 for ( ret = gnutls_handshake ( p->session->session );
916                       ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN;
917                       ret = gnutls_handshake ( p->session->session ) );
918                 sbiod->sbiod_sb->sb_trans_needs_read = 1;
919                 ret = 0;
920                 break;
921         default:
922                 sbiod->sbiod_sb->sb_trans_needs_read = 0;
923         }
924         return ret;
925 }
926
927 static ber_slen_t
928 tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
929 {
930         struct tls_data         *p;
931         ber_slen_t              ret;
932         int                     err;
933
934         assert( sbiod != NULL );
935         assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
936
937         p = (struct tls_data *)sbiod->sbiod_pvt;
938
939         ret = gnutls_record_send ( p->session->session, (char *)buf, len );
940
941         if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) {
942                 sbiod->sbiod_sb->sb_trans_needs_write = 1;
943                 sock_errset(EWOULDBLOCK);
944                 ret = 0;
945         } else {
946                 sbiod->sbiod_sb->sb_trans_needs_write = 0;
947         }
948         return ret;
949 }
950
951 static Sockbuf_IO tlsg_sbio =
952 {
953         tlsg_sb_setup,          /* sbi_setup */
954         tlsg_sb_remove,         /* sbi_remove */
955         tlsg_sb_ctrl,           /* sbi_ctrl */
956         tlsg_sb_read,           /* sbi_read */
957         tlsg_sb_write,          /* sbi_write */
958         tlsg_sb_close           /* sbi_close */
959 };
960
961 /* Certs are not automatically varified during the handshake */
962 static int
963 tlsg_cert_verify( tlsg_session *ssl )
964 {
965         unsigned int status = 0;
966         int err;
967         time_t now = time(0);
968
969         err = gnutls_certificate_verify_peers2( ssl->session, &status );
970         if ( err < 0 ) {
971                 Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n",
972                         err,0,0 );
973                 return -1;
974         }
975         if ( status ) {
976                 Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n",
977                         status, 0,0 );
978                 return -1;
979         }
980         if ( gnutls_certificate_expiration_time_peers( ssl->session ) < now ) {
981                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n",
982                         0, 0, 0 );
983                 return -1;
984         }
985         if ( gnutls_certificate_activation_time_peers( ssl->session ) > now ) {
986                 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n",
987                         0, 0, 0 );
988                 return -1;
989         }
990         return 0;
991 }
992
993 tls_impl ldap_int_tls_impl = {
994         "GnuTLS",
995
996         tlsg_init,
997         tlsg_destroy,
998
999         tlsg_ctx_new,
1000         tlsg_ctx_ref,
1001         tlsg_ctx_free,
1002         tlsg_ctx_init,
1003
1004         tlsg_session_new,
1005         tlsg_session_connect,
1006         tlsg_session_accept,
1007         tlsg_session_upflags,
1008         tlsg_session_errmsg,
1009         tlsg_session_my_dn,
1010         tlsg_session_peer_dn,
1011         tlsg_session_chkhost,
1012         tlsg_session_strength,
1013
1014         &tlsg_sbio,
1015
1016 #ifdef LDAP_R_COMPILE
1017         tlsg_thr_init,
1018 #else
1019         NULL,
1020 #endif
1021
1022         0
1023 };
1024
1025 #endif /* HAVE_GNUTLS */