From 7d03aa8b353ac5ea3ecb72bb3c0b11f30abec347 Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Thu, 5 Mar 2009 21:03:29 +0000 Subject: [PATCH] ITS#5991,ITS#5992 --- CHANGES | 2 + libraries/libldap/tls_g.c | 86 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index b2ea10b35f..a99543802b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ OpenLDAP 2.4 Change Log OpenLDAP 2.4.16 Engineering + Fixed libldap GnuTLS with x509v1 CA certs (ITS#5992) + Fixed libldap GnuTLS with CA chains (ITS#5991) Fixed libldap GnuTLS TLSVerifyCilent try (ITS#5981) Fixed libldap segfault in checking cert/DN (ITS#5976) Fixed libldap peer cert memory leak again (ITS#5849) diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c index 57731673b3..738fb36fc3 100644 --- a/libraries/libldap/tls_g.c +++ b/libraries/libldap/tls_g.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include "ldap-int.h" #include "ldap-tls.h" @@ -290,6 +292,31 @@ tlsg_ctx_free ( tls_ctx *ctx ) ber_memfree ( c ); } +static int +tlsg_getfile( const char *path, gnutls_datum_t *buf ) +{ + int rc = -1, fd; + struct stat st; + + fd = open( path, O_RDONLY ); + if ( fd >= 0 && fstat( fd, &st ) == 0 ) { + buf->size = st.st_size; + buf->data = LDAP_MALLOC( st.st_size + 1 ); + if ( buf->data ) { + rc = read( fd, buf->data, st.st_size ); + close( fd ); + if ( rc < st.st_size ) + rc = -1; + else + rc = 0; + } + } + return rc; +} + +/* This is the GnuTLS default */ +#define VERIFY_DEPTH 6 + /* * initialize a new TLS context */ @@ -322,11 +349,55 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) } if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) { - rc = gnutls_certificate_set_x509_key_file( - ctx->cred, - lt->lt_certfile, - lt->lt_keyfile, + gnutls_x509_privkey_t key; + gnutls_datum_t buf; + gnutls_x509_crt_t certs[VERIFY_DEPTH]; + unsigned int max = VERIFY_DEPTH; + + /* OpenSSL builds the cert chain for us, but GnuTLS + * expects it to be present in the certfile. If it's + * not, we have to build it ourselves. So we have to + * do some special checks here... + */ + rc = tlsg_getfile( lt->lt_keyfile, &buf ); + if ( rc ) return -1; + rc = gnutls_x509_privkey_import( key, &buf, GNUTLS_X509_FMT_PEM ); + LDAP_FREE( buf.data ); + if ( rc < 0 ) return rc; + + rc = tlsg_getfile( lt->lt_certfile, &buf ); + if ( rc ) return -1; + rc = gnutls_x509_crt_list_import( certs, &max, &buf, + GNUTLS_X509_FMT_PEM, 0 ); + LDAP_FREE( buf.data ); + if ( rc < 0 ) return rc; + + /* If there's only one cert and it's not self-signed, + * then we have to build the cert chain. + */ + if ( max == 1 && !gnutls_x509_crt_check_issuer( certs[0], certs[0] )) { + gnutls_x509_crt_t *cas; + unsigned int i, j, ncas; + + gnutls_certificate_get_x509_cas( ctx->cred, &cas, &ncas ); + for ( i = 1; icred, certs, max, key ); if ( rc ) return -1; } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) { Debug( LDAP_DEBUG_ANY, @@ -349,6 +420,13 @@ tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) if ( rc < 0 ) return -1; rc = 0; } + + /* FIXME: ITS#5992 - this should go be configurable, + * and V1 CA certs should be phased out ASAP. + */ + gnutls_certificate_set_verify_flags( ctx->cred, + GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); + if ( is_server ) { gnutls_dh_params_init(&ctx->dh_params); gnutls_dh_params_generate2(ctx->dh_params, DH_BITS); -- 2.39.5