Back to index

openldap  2.4.31
tls_g.c
Go to the documentation of this file.
00001 /* tls_g.c - Handle tls/ssl using GNUTLS. */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2008-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and
00017  * Matt Backes; sponsored by The Written Word (thewrittenword.com)
00018  * and Stanford University (stanford.edu).
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #ifdef HAVE_GNUTLS
00024 
00025 #include "ldap_config.h"
00026 
00027 #include <stdio.h>
00028 
00029 #include <ac/stdlib.h>
00030 #include <ac/errno.h>
00031 #include <ac/socket.h>
00032 #include <ac/string.h>
00033 #include <ac/ctype.h>
00034 #include <ac/time.h>
00035 #include <ac/unistd.h>
00036 #include <ac/param.h>
00037 #include <ac/dirent.h>
00038 #include <sys/stat.h>
00039 #include <fcntl.h>
00040 
00041 #include "ldap-int.h"
00042 #include "ldap-tls.h"
00043 
00044 #include <gnutls/gnutls.h>
00045 #include <gnutls/x509.h>
00046 #include <gcrypt.h>
00047 
00048 #define DH_BITS      (1024)
00049 
00050 #if LIBGNUTLS_VERSION_NUMBER >= 0x020200
00051 #define       HAVE_CIPHERSUITES    1
00052 /* This is a kludge. gcrypt 1.4.x has support. Recent GnuTLS requires gcrypt 1.4.x
00053  * but that dependency isn't reflected in their configure script, resulting in
00054  * build errors on older gcrypt. So, if they have a working build environment,
00055  * assume gcrypt is new enough.
00056  */
00057 #define HAVE_GCRYPT_RAND    1
00058 #else
00059 #undef HAVE_CIPHERSUITES
00060 #undef HAVE_GCRYPT_RAND
00061 #endif
00062 
00063 #ifndef HAVE_CIPHERSUITES
00064 /* Versions prior to 2.2.0 didn't handle cipher suites, so we had to
00065  * kludge them ourselves.
00066  */
00067 typedef struct tls_cipher_suite {
00068        const char *name;
00069        gnutls_kx_algorithm_t kx;
00070        gnutls_cipher_algorithm_t cipher;
00071        gnutls_mac_algorithm_t mac;
00072        gnutls_protocol_t version;
00073 } tls_cipher_suite;
00074 #endif
00075 
00076 typedef struct tlsg_ctx {
00077        struct ldapoptions *lo;
00078        gnutls_certificate_credentials_t cred;
00079        gnutls_dh_params_t dh_params;
00080        unsigned long verify_depth;
00081        int refcount;
00082 #ifdef HAVE_CIPHERSUITES
00083        gnutls_priority_t prios;
00084 #else
00085        int *kx_list;
00086        int *cipher_list;
00087        int *mac_list;
00088 #endif
00089 #ifdef LDAP_R_COMPILE
00090        ldap_pvt_thread_mutex_t ref_mutex;
00091 #endif
00092 } tlsg_ctx;
00093 
00094 typedef struct tlsg_session {
00095        gnutls_session_t session;
00096        tlsg_ctx *ctx;
00097        struct berval peer_der_dn;
00098 } tlsg_session;
00099 
00100 #ifndef HAVE_CIPHERSUITES
00101 static tls_cipher_suite *tlsg_ciphers;
00102 static int tlsg_n_ciphers;
00103 #endif
00104 
00105 static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites );
00106 static int tlsg_cert_verify( tlsg_session *s );
00107 
00108 #ifdef LDAP_R_COMPILE
00109 
00110 static int
00111 tlsg_mutex_init( void **priv )
00112 {
00113        int err = 0;
00114        ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t ));
00115 
00116        if ( !lock )
00117               err = ENOMEM;
00118        if ( !err ) {
00119               err = ldap_pvt_thread_mutex_init( lock );
00120               if ( err )
00121                      LDAP_FREE( lock );
00122               else
00123                      *priv = lock;
00124        }
00125        return err;
00126 }
00127 
00128 static int
00129 tlsg_mutex_destroy( void **lock )
00130 {
00131        int err = ldap_pvt_thread_mutex_destroy( *lock );
00132        LDAP_FREE( *lock );
00133        return err;
00134 }
00135 
00136 static int
00137 tlsg_mutex_lock( void **lock )
00138 {
00139        return ldap_pvt_thread_mutex_lock( *lock );
00140 }
00141 
00142 static int
00143 tlsg_mutex_unlock( void **lock )
00144 {
00145        return ldap_pvt_thread_mutex_unlock( *lock );
00146 }
00147 
00148 static struct gcry_thread_cbs tlsg_thread_cbs = {
00149        GCRY_THREAD_OPTION_USER,
00150        NULL,
00151        tlsg_mutex_init,
00152        tlsg_mutex_destroy,
00153        tlsg_mutex_lock,
00154        tlsg_mutex_unlock,
00155        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
00156 };
00157 
00158 static void
00159 tlsg_thr_init( void )
00160 {
00161        gcry_control (GCRYCTL_SET_THREAD_CBS, &tlsg_thread_cbs);
00162 }
00163 #endif /* LDAP_R_COMPILE */
00164 
00165 /*
00166  * Initialize TLS subsystem. Should be called only once.
00167  */
00168 static int
00169 tlsg_init( void )
00170 {
00171 #ifdef HAVE_GCRYPT_RAND
00172        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();
00173        if ( lo->ldo_tls_randfile &&
00174               gcry_control( GCRYCTL_SET_RNDEGD_SOCKET, lo->ldo_tls_randfile )) {
00175               Debug( LDAP_DEBUG_ANY,
00176               "TLS: gcry_control GCRYCTL_SET_RNDEGD_SOCKET failed\n",
00177               0, 0, 0);
00178               return -1;
00179        }
00180 #endif
00181 
00182        gnutls_global_init();
00183 
00184 #ifndef HAVE_CIPHERSUITES
00185        /* GNUtls cipher suite handling: The library ought to parse suite
00186         * names for us, but it doesn't. It will return a list of suite names
00187         * that it supports, so we can do parsing ourselves. It ought to tell
00188         * us how long the list is, but it doesn't do that either, so we just
00189         * have to count it manually...
00190         */
00191        {
00192               int i = 0;
00193               tls_cipher_suite *ptr, tmp;
00194               char cs_id[2];
00195 
00196               while ( gnutls_cipher_suite_info( i, cs_id, &tmp.kx, &tmp.cipher,
00197                      &tmp.mac, &tmp.version ))
00198                      i++;
00199               tlsg_n_ciphers = i;
00200 
00201               /* Store a copy */
00202               tlsg_ciphers = LDAP_MALLOC(tlsg_n_ciphers * sizeof(tls_cipher_suite));
00203               if ( !tlsg_ciphers )
00204                      return -1;
00205               for ( i=0; i<tlsg_n_ciphers; i++ ) {
00206                      tlsg_ciphers[i].name = gnutls_cipher_suite_info( i, cs_id,
00207                             &tlsg_ciphers[i].kx, &tlsg_ciphers[i].cipher, &tlsg_ciphers[i].mac,
00208                             &tlsg_ciphers[i].version );
00209               }
00210        }
00211 #endif
00212        return 0;
00213 }
00214 
00215 /*
00216  * Tear down the TLS subsystem. Should only be called once.
00217  */
00218 static void
00219 tlsg_destroy( void )
00220 {
00221 #ifndef HAVE_CIPHERSUITES
00222        LDAP_FREE( tlsg_ciphers );
00223        tlsg_ciphers = NULL;
00224        tlsg_n_ciphers = 0;
00225 #endif
00226        gnutls_global_deinit();
00227 }
00228 
00229 static tls_ctx *
00230 tlsg_ctx_new ( struct ldapoptions *lo )
00231 {
00232        tlsg_ctx *ctx;
00233 
00234        ctx = ber_memcalloc ( 1, sizeof (*ctx) );
00235        if ( ctx ) {
00236               ctx->lo = lo;
00237               if ( gnutls_certificate_allocate_credentials( &ctx->cred )) {
00238                      ber_memfree( ctx );
00239                      return NULL;
00240               }
00241               ctx->refcount = 1;
00242 #ifdef HAVE_CIPHERSUITES
00243               gnutls_priority_init( &ctx->prios, "NORMAL", NULL );
00244 #endif
00245 #ifdef LDAP_R_COMPILE
00246               ldap_pvt_thread_mutex_init( &ctx->ref_mutex );
00247 #endif
00248        }
00249        return (tls_ctx *)ctx;
00250 }
00251 
00252 static void
00253 tlsg_ctx_ref( tls_ctx *ctx )
00254 {
00255        tlsg_ctx *c = (tlsg_ctx *)ctx;
00256        LDAP_MUTEX_LOCK( &c->ref_mutex );
00257        c->refcount++;
00258        LDAP_MUTEX_UNLOCK( &c->ref_mutex );
00259 }
00260 
00261 static void
00262 tlsg_ctx_free ( tls_ctx *ctx )
00263 {
00264        tlsg_ctx *c = (tlsg_ctx *)ctx;
00265        int refcount;
00266 
00267        if ( !c ) return;
00268 
00269        LDAP_MUTEX_LOCK( &c->ref_mutex );
00270        refcount = --c->refcount;
00271        LDAP_MUTEX_UNLOCK( &c->ref_mutex );
00272        if ( refcount )
00273               return;
00274 #ifdef HAVE_CIPHERSUITES
00275        gnutls_priority_deinit( c->prios );
00276 #else
00277        LDAP_FREE( c->kx_list );
00278 #endif
00279        gnutls_certificate_free_credentials( c->cred );
00280        ber_memfree ( c );
00281 }
00282 
00283 static int
00284 tlsg_getfile( const char *path, gnutls_datum_t *buf )
00285 {
00286        int rc = -1, fd;
00287        struct stat st;
00288 
00289        fd = open( path, O_RDONLY );
00290        if ( fd >= 0 && fstat( fd, &st ) == 0 ) {
00291               buf->size = st.st_size;
00292               buf->data = LDAP_MALLOC( st.st_size + 1 );
00293               if ( buf->data ) {
00294                      rc = read( fd, buf->data, st.st_size );
00295                      close( fd );
00296                      if ( rc < st.st_size )
00297                             rc = -1;
00298                      else
00299                             rc = 0;
00300               }
00301        }
00302        return rc;
00303 }
00304 
00305 /* This is the GnuTLS default */
00306 #define       VERIFY_DEPTH  6
00307 
00308 /*
00309  * initialize a new TLS context
00310  */
00311 static int
00312 tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
00313 {
00314        tlsg_ctx *ctx = lo->ldo_tls_ctx;
00315        int rc;
00316 
00317        if ( lo->ldo_tls_ciphersuite &&
00318               tlsg_parse_ciphers( ctx, lt->lt_ciphersuite )) {
00319               Debug( LDAP_DEBUG_ANY,
00320                         "TLS: could not set cipher list %s.\n",
00321                         lo->ldo_tls_ciphersuite, 0, 0 );
00322               return -1;
00323        }
00324 
00325        if (lo->ldo_tls_cacertdir != NULL) {
00326               Debug( LDAP_DEBUG_ANY, 
00327                      "TLS: warning: cacertdir not implemented for gnutls\n",
00328                      NULL, NULL, NULL );
00329        }
00330 
00331        if (lo->ldo_tls_cacertfile != NULL) {
00332               rc = gnutls_certificate_set_x509_trust_file( 
00333                      ctx->cred,
00334                      lt->lt_cacertfile,
00335                      GNUTLS_X509_FMT_PEM );
00336               if ( rc < 0 ) return -1;
00337        }
00338 
00339        if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) {
00340               gnutls_x509_privkey_t key;
00341               gnutls_datum_t buf;
00342               gnutls_x509_crt_t certs[VERIFY_DEPTH];
00343               unsigned int max = VERIFY_DEPTH;
00344 
00345               rc = gnutls_x509_privkey_init( &key );
00346               if ( rc ) return -1;
00347 
00348               /* OpenSSL builds the cert chain for us, but GnuTLS
00349                * expects it to be present in the certfile. If it's
00350                * not, we have to build it ourselves. So we have to
00351                * do some special checks here...
00352                */
00353               rc = tlsg_getfile( lt->lt_keyfile, &buf );
00354               if ( rc ) return -1;
00355               rc = gnutls_x509_privkey_import( key, &buf,
00356                      GNUTLS_X509_FMT_PEM );
00357               LDAP_FREE( buf.data );
00358               if ( rc < 0 ) return rc;
00359 
00360               rc = tlsg_getfile( lt->lt_certfile, &buf );
00361               if ( rc ) return -1;
00362               rc = gnutls_x509_crt_list_import( certs, &max, &buf,
00363                      GNUTLS_X509_FMT_PEM, 0 );
00364               LDAP_FREE( buf.data );
00365               if ( rc < 0 ) return rc;
00366 
00367               /* If there's only one cert and it's not self-signed,
00368                * then we have to build the cert chain.
00369                */
00370               if ( max == 1 && !gnutls_x509_crt_check_issuer( certs[0], certs[0] )) {
00371                      gnutls_x509_crt_t *cas;
00372                      unsigned int i, j, ncas;
00373 
00374                      gnutls_certificate_get_x509_cas( ctx->cred, &cas, &ncas );
00375                      for ( i = 1; i<VERIFY_DEPTH; i++ ) {
00376                             for ( j = 0; j<ncas; j++ ) {
00377                                    if ( gnutls_x509_crt_check_issuer( certs[i-1], cas[j] )) {
00378                                           certs[i] = cas[j];
00379                                           max++;
00380                                           /* If this CA is self-signed, we're done */
00381                                           if ( gnutls_x509_crt_check_issuer( cas[j], cas[j] ))
00382                                                  j = ncas;
00383                                           break;
00384                                    }
00385                             }
00386                             /* only continue if we found a CA and it was not self-signed */
00387                             if ( j == ncas )
00388                                    break;
00389                      }
00390               }
00391               rc = gnutls_certificate_set_x509_key( ctx->cred, certs, max, key );
00392               if ( rc ) return -1;
00393        } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) {
00394               Debug( LDAP_DEBUG_ANY, 
00395                      "TLS: only one of certfile and keyfile specified\n",
00396                      NULL, NULL, NULL );
00397               return -1;
00398        }
00399 
00400        if ( lo->ldo_tls_dhfile ) {
00401               Debug( LDAP_DEBUG_ANY, 
00402                      "TLS: warning: ignoring dhfile\n", 
00403                      NULL, NULL, NULL );
00404        }
00405 
00406        if ( lo->ldo_tls_crlfile ) {
00407               rc = gnutls_certificate_set_x509_crl_file( 
00408                      ctx->cred,
00409                      lt->lt_crlfile,
00410                      GNUTLS_X509_FMT_PEM );
00411               if ( rc < 0 ) return -1;
00412               rc = 0;
00413        }
00414 
00415        /* FIXME: ITS#5992 - this should go be configurable,
00416         * and V1 CA certs should be phased out ASAP.
00417         */
00418        gnutls_certificate_set_verify_flags( ctx->cred,
00419               GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
00420 
00421        if ( is_server ) {
00422               gnutls_dh_params_init(&ctx->dh_params);
00423               gnutls_dh_params_generate2(ctx->dh_params, DH_BITS);
00424        }
00425        return 0;
00426 }
00427 
00428 static tls_session *
00429 tlsg_session_new ( tls_ctx * ctx, int is_server )
00430 {
00431        tlsg_ctx *c = (tlsg_ctx *)ctx;
00432        tlsg_session *session;
00433 
00434        session = ber_memcalloc ( 1, sizeof (*session) );
00435        if ( !session )
00436               return NULL;
00437 
00438        session->ctx = c;
00439        gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT );
00440 #ifdef HAVE_CIPHERSUITES
00441        gnutls_priority_set( session->session, c->prios );
00442 #else
00443        gnutls_set_default_priority( session->session );
00444        if ( c->kx_list ) {
00445               gnutls_kx_set_priority( session->session, c->kx_list );
00446               gnutls_cipher_set_priority( session->session, c->cipher_list );
00447               gnutls_mac_set_priority( session->session, c->mac_list );
00448        }
00449 #endif
00450        if ( c->cred )
00451               gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, c->cred );
00452        
00453        if ( is_server ) {
00454               int flag = 0;
00455               if ( c->lo->ldo_tls_require_cert ) {
00456                      flag = GNUTLS_CERT_REQUEST;
00457                      if ( c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
00458                             c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD )
00459                             flag = GNUTLS_CERT_REQUIRE;
00460                      gnutls_certificate_server_set_request( session->session, flag );
00461               }
00462        }
00463        return (tls_session *)session;
00464 } 
00465 
00466 static int
00467 tlsg_session_accept( tls_session *session )
00468 {
00469        tlsg_session *s = (tlsg_session *)session;
00470        int rc;
00471 
00472        rc = gnutls_handshake( s->session );
00473        if ( rc == 0 && s->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) {
00474               const gnutls_datum_t *peer_cert_list;
00475               unsigned int list_size;
00476 
00477               peer_cert_list = gnutls_certificate_get_peers( s->session, 
00478                                           &list_size );
00479               if ( !peer_cert_list && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_TRY ) 
00480                      rc = 0;
00481               else {
00482                      rc = tlsg_cert_verify( s );
00483                      if ( rc && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW )
00484                             rc = 0;
00485               }
00486        }
00487        return rc;
00488 }
00489 
00490 static int
00491 tlsg_session_connect( LDAP *ld, tls_session *session )
00492 {
00493        return tlsg_session_accept( session);
00494 }
00495 
00496 static int
00497 tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc )
00498 {
00499        tlsg_session *s = (tlsg_session *)session;
00500 
00501        if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN )
00502               return 0;
00503 
00504        switch (gnutls_record_get_direction (s->session)) {
00505        case 0: 
00506               sb->sb_trans_needs_read = 1;
00507               return 1;
00508        case 1:
00509               sb->sb_trans_needs_write = 1;
00510               return 1;
00511        }
00512        return 0;
00513 }
00514 
00515 static char *
00516 tlsg_session_errmsg( tls_session *sess, int rc, char *buf, size_t len )
00517 {
00518        return (char *)gnutls_strerror( rc );
00519 }
00520 
00521 static void
00522 tlsg_x509_cert_dn( struct berval *cert, struct berval *dn, int get_subject )
00523 {
00524        BerElementBuffer berbuf;
00525        BerElement *ber = (BerElement *)&berbuf;
00526        ber_tag_t tag;
00527        ber_len_t len;
00528        ber_int_t i;
00529 
00530        ber_init2( ber, cert, LBER_USE_DER );
00531        tag = ber_skip_tag( ber, &len );   /* Sequence */
00532        tag = ber_skip_tag( ber, &len );   /* Sequence */
00533        tag = ber_peek_tag( ber, &len );   /* Context + Constructed (version) */
00534        if ( tag == 0xa0 ) { /* Version is optional */
00535               tag = ber_skip_tag( ber, &len );
00536               tag = ber_get_int( ber, &i );      /* Int: Version */
00537        }
00538        tag = ber_skip_tag( ber, &len );   /* Int: Serial (can be longer than ber_int_t) */
00539        ber_skip_data( ber, len );
00540        tag = ber_skip_tag( ber, &len );   /* Sequence: Signature */
00541        ber_skip_data( ber, len );
00542        if ( !get_subject ) {
00543               tag = ber_peek_tag( ber, &len );   /* Sequence: Issuer DN */
00544        } else {
00545               tag = ber_skip_tag( ber, &len );
00546               ber_skip_data( ber, len );
00547               tag = ber_skip_tag( ber, &len );   /* Sequence: Validity */
00548               ber_skip_data( ber, len );
00549               tag = ber_peek_tag( ber, &len );   /* Sequence: Subject DN */
00550        }
00551        len = ber_ptrlen( ber );
00552        dn->bv_val = cert->bv_val + len;
00553        dn->bv_len = cert->bv_len - len;
00554 }
00555 
00556 static int
00557 tlsg_session_my_dn( tls_session *session, struct berval *der_dn )
00558 {
00559        tlsg_session *s = (tlsg_session *)session;
00560        const gnutls_datum_t *x;
00561        struct berval bv;
00562 
00563        x = gnutls_certificate_get_ours( s->session );
00564 
00565        if (!x) return LDAP_INVALID_CREDENTIALS;
00566        
00567        bv.bv_val = (char *) x->data;
00568        bv.bv_len = x->size;
00569 
00570        tlsg_x509_cert_dn( &bv, der_dn, 1 );
00571        return 0;
00572 }
00573 
00574 static int
00575 tlsg_session_peer_dn( tls_session *session, struct berval *der_dn )
00576 {
00577        tlsg_session *s = (tlsg_session *)session;
00578        if ( !s->peer_der_dn.bv_val ) {
00579               const gnutls_datum_t *peer_cert_list;
00580               unsigned int list_size;
00581               struct berval bv;
00582 
00583               peer_cert_list = gnutls_certificate_get_peers( s->session, 
00584                                                  &list_size );
00585               if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS;
00586 
00587               bv.bv_len = peer_cert_list->size;
00588               bv.bv_val = (char *) peer_cert_list->data;
00589 
00590               tlsg_x509_cert_dn( &bv, &s->peer_der_dn, 1 );
00591        }
00592        *der_dn = s->peer_der_dn;
00593        return 0;
00594 }
00595 
00596 /* what kind of hostname were we given? */
00597 #define       IS_DNS 0
00598 #define       IS_IP4 1
00599 #define       IS_IP6 2
00600 
00601 #define       CN_OID "2.5.4.3"
00602 
00603 static int
00604 tlsg_session_chkhost( LDAP *ld, tls_session *session, const char *name_in )
00605 {
00606        tlsg_session *s = (tlsg_session *)session;
00607        int i, ret;
00608        const gnutls_datum_t *peer_cert_list;
00609        unsigned int list_size;
00610        char altname[NI_MAXHOST];
00611        size_t altnamesize;
00612 
00613        gnutls_x509_crt_t cert;
00614        const char *name;
00615        char *ptr;
00616        char *domain = NULL;
00617 #ifdef LDAP_PF_INET6
00618        struct in6_addr addr;
00619 #else
00620        struct in_addr addr;
00621 #endif
00622        int len1 = 0, len2 = 0;
00623        int ntype = IS_DNS;
00624 
00625        if( ldap_int_hostname &&
00626               ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
00627        {
00628               name = ldap_int_hostname;
00629        } else {
00630               name = name_in;
00631        }
00632 
00633        peer_cert_list = gnutls_certificate_get_peers( s->session, 
00634                                           &list_size );
00635        if ( !peer_cert_list ) {
00636               Debug( LDAP_DEBUG_ANY,
00637                      "TLS: unable to get peer certificate.\n",
00638                      0, 0, 0 );
00639               /* If this was a fatal condition, things would have
00640                * aborted long before now.
00641                */
00642               return LDAP_SUCCESS;
00643        }
00644        ret = gnutls_x509_crt_init( &cert );
00645        if ( ret < 0 )
00646               return LDAP_LOCAL_ERROR;
00647        ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER );
00648        if ( ret ) {
00649               gnutls_x509_crt_deinit( cert );
00650               return LDAP_LOCAL_ERROR;
00651        }
00652 
00653 #ifdef LDAP_PF_INET6
00654        if (inet_pton(AF_INET6, name, &addr)) {
00655               ntype = IS_IP6;
00656        } else 
00657 #endif
00658        if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
00659               if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
00660        }
00661        
00662        if (ntype == IS_DNS) {
00663               len1 = strlen(name);
00664               domain = strchr(name, '.');
00665               if (domain) {
00666                      len2 = len1 - (domain-name);
00667               }
00668        }
00669 
00670        for ( i=0, ret=0; ret >= 0; i++ ) {
00671               altnamesize = sizeof(altname);
00672               ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 
00673                      altname, &altnamesize, NULL );
00674               if ( ret < 0 ) break;
00675 
00676               /* ignore empty */
00677               if ( altnamesize == 0 ) continue;
00678 
00679               if ( ret == GNUTLS_SAN_DNSNAME ) {
00680                      if (ntype != IS_DNS) continue;
00681        
00682                      /* Is this an exact match? */
00683                      if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) {
00684                             break;
00685                      }
00686 
00687                      /* Is this a wildcard match? */
00688                      if (domain && (altname[0] == '*') && (altname[1] == '.') &&
00689                             (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2))
00690                      {
00691                             break;
00692                      }
00693               } else if ( ret == GNUTLS_SAN_IPADDRESS ) {
00694                      if (ntype == IS_DNS) continue;
00695 
00696 #ifdef LDAP_PF_INET6
00697                      if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) {
00698                             continue;
00699                      } else
00700 #endif
00701                      if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) {
00702                             continue;
00703                      }
00704                      if (!memcmp(altname, &addr, altnamesize)) {
00705                             break;
00706                      }
00707               }
00708        }
00709        if ( ret >= 0 ) {
00710               ret = LDAP_SUCCESS;
00711        } else {
00712               /* find the last CN */
00713               i=0;
00714               do {
00715                      altnamesize = 0;
00716                      ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
00717                             i, 1, altname, &altnamesize );
00718                      if ( ret == GNUTLS_E_SHORT_MEMORY_BUFFER )
00719                             i++;
00720                      else
00721                             break;
00722               } while ( 1 );
00723 
00724               if ( i ) {
00725                      altnamesize = sizeof(altname);
00726                      ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID,
00727                             i-1, 0, altname, &altnamesize );
00728               }
00729 
00730               if ( ret < 0 ) {
00731                      Debug( LDAP_DEBUG_ANY,
00732                             "TLS: unable to get common name from peer certificate.\n",
00733                             0, 0, 0 );
00734                      ret = LDAP_CONNECT_ERROR;
00735                      if ( ld->ld_error ) {
00736                             LDAP_FREE( ld->ld_error );
00737                      }
00738                      ld->ld_error = LDAP_STRDUP(
00739                             _("TLS: unable to get CN from peer certificate"));
00740 
00741               } else {
00742                      ret = LDAP_LOCAL_ERROR;
00743                      if ( !len1 ) len1 = strlen( name );
00744                      if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) {
00745                             ret = LDAP_SUCCESS;
00746 
00747                      } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) {
00748                                    /* Is this a wildcard match? */
00749                             if( domain &&
00750                                    (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) {
00751                                    ret = LDAP_SUCCESS;
00752                             }
00753                      }
00754               }
00755 
00756               if( ret == LDAP_LOCAL_ERROR ) {
00757                      altname[altnamesize] = '\0';
00758                      Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
00759                             "common name in certificate (%s).\n", 
00760                             name, altname, 0 );
00761                      ret = LDAP_CONNECT_ERROR;
00762                      if ( ld->ld_error ) {
00763                             LDAP_FREE( ld->ld_error );
00764                      }
00765                      ld->ld_error = LDAP_STRDUP(
00766                             _("TLS: hostname does not match CN in peer certificate"));
00767               }
00768        }
00769        gnutls_x509_crt_deinit( cert );
00770        return ret;
00771 }
00772 
00773 static int
00774 tlsg_session_strength( tls_session *session )
00775 {
00776        tlsg_session *s = (tlsg_session *)session;
00777        gnutls_cipher_algorithm_t c;
00778 
00779        c = gnutls_cipher_get( s->session );
00780        return gnutls_cipher_get_key_size( c ) * 8;
00781 }
00782 
00783 /* suites is a string of colon-separated cipher suite names. */
00784 static int
00785 tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites )
00786 {
00787 #ifdef HAVE_CIPHERSUITES
00788        const char *err;
00789        return gnutls_priority_init( &ctx->prios, suites, &err );
00790 #else
00791        char *ptr, *end;
00792        int i, j, len, num;
00793        int *list, nkx = 0, ncipher = 0, nmac = 0;
00794        int *kx, *cipher, *mac;
00795 
00796        num = 0;
00797        ptr = suites;
00798        do {
00799               end = strchr(ptr, ':');
00800               if ( end )
00801                      len = end - ptr;
00802               else
00803                      len = strlen(ptr);
00804               for (i=0; i<tlsg_n_ciphers; i++) {
00805                      if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
00806                             num++;
00807                             break;
00808                      }
00809               }
00810               if ( i == tlsg_n_ciphers ) {
00811                      /* unrecognized cipher suite */
00812                      return -1;
00813               }
00814               ptr += len + 1;
00815        } while (end);
00816 
00817        /* Space for all 3 lists */
00818        list = LDAP_MALLOC( (num+1) * sizeof(int) * 3 );
00819        if ( !list )
00820               return -1;
00821        kx = list;
00822        cipher = kx+num+1;
00823        mac = cipher+num+1;
00824 
00825        ptr = suites;
00826        do {
00827               end = strchr(ptr, ':');
00828               if ( end )
00829                      len = end - ptr;
00830               else
00831                      len = strlen(ptr);
00832               for (i=0; i<tlsg_n_ciphers; i++) {
00833                      /* For each cipher suite, insert its algorithms into
00834                       * their respective priority lists. Make sure they
00835                       * only appear once in each list.
00836                       */
00837                      if ( !strncasecmp( tlsg_ciphers[i].name, ptr, len )) {
00838                             for (j=0; j<nkx; j++)
00839                                    if ( kx[j] == tlsg_ciphers[i].kx )
00840                                           break;
00841                             if ( j == nkx )
00842                                    kx[nkx++] = tlsg_ciphers[i].kx;
00843                             for (j=0; j<ncipher; j++)
00844                                    if ( cipher[j] == tlsg_ciphers[i].cipher )
00845                                           break;
00846                             if ( j == ncipher ) 
00847                                    cipher[ncipher++] = tlsg_ciphers[i].cipher;
00848                             for (j=0; j<nmac; j++)
00849                                    if ( mac[j] == tlsg_ciphers[i].mac )
00850                                           break;
00851                             if ( j == nmac )
00852                                    mac[nmac++] = tlsg_ciphers[i].mac;
00853                             break;
00854                      }
00855               }
00856               ptr += len + 1;
00857        } while (end);
00858        kx[nkx] = 0;
00859        cipher[ncipher] = 0;
00860        mac[nmac] = 0;
00861        ctx->kx_list = kx;
00862        ctx->cipher_list = cipher;
00863        ctx->mac_list = mac;
00864        return 0;
00865 #endif
00866 }
00867 
00868 /*
00869  * TLS support for LBER Sockbufs
00870  */
00871 
00872 struct tls_data {
00873        tlsg_session         *session;
00874        Sockbuf_IO_Desc             *sbiod;
00875 };
00876 
00877 static ssize_t
00878 tlsg_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len )
00879 {
00880        struct tls_data             *p;
00881 
00882        if ( buf == NULL || len <= 0 ) return 0;
00883 
00884        p = (struct tls_data *)ptr;
00885 
00886        if ( p == NULL || p->sbiod == NULL ) {
00887               return 0;
00888        }
00889 
00890        return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
00891 }
00892 
00893 static ssize_t
00894 tlsg_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len )
00895 {
00896        struct tls_data             *p;
00897        
00898        if ( buf == NULL || len <= 0 ) return 0;
00899        
00900        p = (struct tls_data *)ptr;
00901 
00902        if ( p == NULL || p->sbiod == NULL ) {
00903               return 0;
00904        }
00905 
00906        return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
00907 }
00908 
00909 static int
00910 tlsg_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
00911 {
00912        struct tls_data             *p;
00913        tlsg_session  *session = arg;
00914 
00915        assert( sbiod != NULL );
00916 
00917        p = LBER_MALLOC( sizeof( *p ) );
00918        if ( p == NULL ) {
00919               return -1;
00920        }
00921        
00922        gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p );
00923        gnutls_transport_set_pull_function( session->session, tlsg_recv );
00924        gnutls_transport_set_push_function( session->session, tlsg_send );
00925        p->session = session;
00926        p->sbiod = sbiod;
00927        sbiod->sbiod_pvt = p;
00928        return 0;
00929 }
00930 
00931 static int
00932 tlsg_sb_remove( Sockbuf_IO_Desc *sbiod )
00933 {
00934        struct tls_data             *p;
00935        
00936        assert( sbiod != NULL );
00937        assert( sbiod->sbiod_pvt != NULL );
00938 
00939        p = (struct tls_data *)sbiod->sbiod_pvt;
00940        gnutls_deinit ( p->session->session );
00941        LBER_FREE( p->session );
00942        LBER_FREE( sbiod->sbiod_pvt );
00943        sbiod->sbiod_pvt = NULL;
00944        return 0;
00945 }
00946 
00947 static int
00948 tlsg_sb_close( Sockbuf_IO_Desc *sbiod )
00949 {
00950        struct tls_data             *p;
00951        
00952        assert( sbiod != NULL );
00953        assert( sbiod->sbiod_pvt != NULL );
00954 
00955        p = (struct tls_data *)sbiod->sbiod_pvt;
00956        gnutls_bye ( p->session->session, GNUTLS_SHUT_WR );
00957        return 0;
00958 }
00959 
00960 static int
00961 tlsg_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
00962 {
00963        struct tls_data             *p;
00964        
00965        assert( sbiod != NULL );
00966        assert( sbiod->sbiod_pvt != NULL );
00967 
00968        p = (struct tls_data *)sbiod->sbiod_pvt;
00969        
00970        if ( opt == LBER_SB_OPT_GET_SSL ) {
00971               *((tlsg_session **)arg) = p->session;
00972               return 1;
00973               
00974        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
00975               if( gnutls_record_check_pending( p->session->session ) > 0 ) {
00976                      return 1;
00977               }
00978        }
00979        
00980        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
00981 }
00982 
00983 static ber_slen_t
00984 tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
00985 {
00986        struct tls_data             *p;
00987        ber_slen_t           ret;
00988 
00989        assert( sbiod != NULL );
00990        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
00991 
00992        p = (struct tls_data *)sbiod->sbiod_pvt;
00993 
00994        ret = gnutls_record_recv ( p->session->session, buf, len );
00995        switch (ret) {
00996        case GNUTLS_E_INTERRUPTED:
00997        case GNUTLS_E_AGAIN:
00998               sbiod->sbiod_sb->sb_trans_needs_read = 1;
00999               sock_errset(EWOULDBLOCK);
01000               ret = 0;
01001               break;
01002        case GNUTLS_E_REHANDSHAKE:
01003               for ( ret = gnutls_handshake ( p->session->session );
01004                     ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN;
01005                     ret = gnutls_handshake ( p->session->session ) );
01006               sbiod->sbiod_sb->sb_trans_needs_read = 1;
01007               ret = 0;
01008               break;
01009        default:
01010               sbiod->sbiod_sb->sb_trans_needs_read = 0;
01011        }
01012        return ret;
01013 }
01014 
01015 static ber_slen_t
01016 tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
01017 {
01018        struct tls_data             *p;
01019        ber_slen_t           ret;
01020 
01021        assert( sbiod != NULL );
01022        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
01023 
01024        p = (struct tls_data *)sbiod->sbiod_pvt;
01025 
01026        ret = gnutls_record_send ( p->session->session, (char *)buf, len );
01027 
01028        if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) {
01029               sbiod->sbiod_sb->sb_trans_needs_write = 1;
01030               sock_errset(EWOULDBLOCK);
01031               ret = 0;
01032        } else {
01033               sbiod->sbiod_sb->sb_trans_needs_write = 0;
01034        }
01035        return ret;
01036 }
01037 
01038 static Sockbuf_IO tlsg_sbio =
01039 {
01040        tlsg_sb_setup,              /* sbi_setup */
01041        tlsg_sb_remove,             /* sbi_remove */
01042        tlsg_sb_ctrl,        /* sbi_ctrl */
01043        tlsg_sb_read,        /* sbi_read */
01044        tlsg_sb_write,              /* sbi_write */
01045        tlsg_sb_close        /* sbi_close */
01046 };
01047 
01048 /* Certs are not automatically varified during the handshake */
01049 static int
01050 tlsg_cert_verify( tlsg_session *ssl )
01051 {
01052        unsigned int status = 0;
01053        int err;
01054        time_t now = time(0);
01055        time_t peertime;
01056 
01057        err = gnutls_certificate_verify_peers2( ssl->session, &status );
01058        if ( err < 0 ) {
01059               Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n",
01060                      err,0,0 );
01061               return -1;
01062        }
01063        if ( status ) {
01064               Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n",
01065                      status, 0,0 );
01066               return -1;
01067        }
01068        peertime = gnutls_certificate_expiration_time_peers( ssl->session );
01069        if ( peertime == (time_t) -1 ) {
01070               Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_expiration_time_peers failed\n",
01071                      0, 0, 0 );
01072               return -1;
01073        }
01074        if ( peertime < now ) {
01075               Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n",
01076                      0, 0, 0 );
01077               return -1;
01078        }
01079        peertime = gnutls_certificate_activation_time_peers( ssl->session );
01080        if ( peertime == (time_t) -1 ) {
01081               Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_activation_time_peers failed\n",
01082                      0, 0, 0 );
01083               return -1;
01084        }
01085        if ( peertime > now ) {
01086               Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n",
01087                      0, 0, 0 );
01088               return -1;
01089        }
01090        return 0;
01091 }
01092 
01093 tls_impl ldap_int_tls_impl = {
01094        "GnuTLS",
01095 
01096        tlsg_init,
01097        tlsg_destroy,
01098 
01099        tlsg_ctx_new,
01100        tlsg_ctx_ref,
01101        tlsg_ctx_free,
01102        tlsg_ctx_init,
01103 
01104        tlsg_session_new,
01105        tlsg_session_connect,
01106        tlsg_session_accept,
01107        tlsg_session_upflags,
01108        tlsg_session_errmsg,
01109        tlsg_session_my_dn,
01110        tlsg_session_peer_dn,
01111        tlsg_session_chkhost,
01112        tlsg_session_strength,
01113 
01114        &tlsg_sbio,
01115 
01116 #ifdef LDAP_R_COMPILE
01117        tlsg_thr_init,
01118 #else
01119        NULL,
01120 #endif
01121 
01122        0
01123 };
01124 
01125 #endif /* HAVE_GNUTLS */