From 9bc829dbefd2b4450be724ca85bd65042193504d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 5 Mar 2009 08:04:49 +0000 Subject: [PATCH] ITS#5991 build cert chain, GnuTLS doesn't do it for us --- libraries/libldap/tls_g.c | 77 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/libraries/libldap/tls_g.c b/libraries/libldap/tls_g.c index 759c9b7621..6283db2ad7 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,53 @@ 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 = 0, 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, -- 2.39.5