From: Howard Chu Date: Sat, 8 Apr 2017 23:13:42 +0000 (+0100) Subject: Add options to use DER format cert+keys directly X-Git-Url: https://git.sur5r.net/?p=openldap;a=commitdiff_plain;h=b402a2805f8b96d2751a7315ea5e70e5082965ed Add options to use DER format cert+keys directly Instead of loading from files. --- diff --git a/include/ldap.h b/include/ldap.h index 4caacb15b3..588e9066dc 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -162,6 +162,9 @@ LDAP_BEGIN_DECL #define LDAP_OPT_X_TLS_VERSION 0x6013 /* read-only */ #define LDAP_OPT_X_TLS_CIPHER 0x6014 /* read-only */ #define LDAP_OPT_X_TLS_PEERCERT 0x6015 /* read-only */ +#define LDAP_OPT_X_TLS_CACERT 0x6016 +#define LDAP_OPT_X_TLS_CERT 0x6017 +#define LDAP_OPT_X_TLS_KEY 0x6018 #define LDAP_OPT_X_TLS_NEVER 0 #define LDAP_OPT_X_TLS_HARD 1 diff --git a/libraries/libldap/ldap-int.h b/libraries/libldap/ldap-int.h index db100c8058..bcd6118b5f 100644 --- a/libraries/libldap/ldap-int.h +++ b/libraries/libldap/ldap-int.h @@ -167,6 +167,9 @@ struct ldaptls { char *lt_randfile; /* OpenSSL only */ char *lt_ecname; /* OpenSSL only */ int lt_protocol_min; + struct berval lt_cacert; + struct berval lt_cert; + struct berval lt_key; }; #endif @@ -258,6 +261,9 @@ struct ldapoptions { #define ldo_tls_protocol_min ldo_tls_info.lt_protocol_min #define ldo_tls_crlfile ldo_tls_info.lt_crlfile #define ldo_tls_randfile ldo_tls_info.lt_randfile +#define ldo_tls_cacert ldo_tls_info.lt_cacert +#define ldo_tls_cert ldo_tls_info.lt_cert +#define ldo_tls_key ldo_tls_info.lt_key int ldo_tls_mode; int ldo_tls_require_cert; int ldo_tls_impl; diff --git a/libraries/libldap/tls2.c b/libraries/libldap/tls2.c index d6b36bbd36..732826b2e0 100644 --- a/libraries/libldap/tls2.c +++ b/libraries/libldap/tls2.c @@ -199,7 +199,9 @@ ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server ) tls_init( ti ); if ( is_server && !lts.lt_certfile && !lts.lt_keyfile && - !lts.lt_cacertfile && !lts.lt_cacertdir ) { + !lts.lt_cacertfile && !lts.lt_cacertdir && + !lts.lt_cacert.bv_val && !lts.lt_cert.bv_val && + !lts.lt_key.bv_val ) { /* minimum configuration not provided */ return LDAP_NOT_SUPPORTED; } @@ -864,6 +866,36 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg ) ldap_pvt_tls_ctx_free( lo->ldo_tls_ctx ); lo->ldo_tls_ctx = NULL; return ldap_int_tls_init_ctx( lo, *(int *)arg ); + case LDAP_OPT_X_TLS_CACERT: + if ( !arg ) return -1; + if ( lo->ldo_tls_cacert.bv_val ) + LDAP_FREE( lo->ldo_tls_cacert.bv_val ); + lo->ldo_tls_cacert.bv_len = ((struct berval *)arg)->bv_len; + lo->ldo_tls_cacert.bv_val = LDAP_MALLOC( lo->ldo_tls_cacert.bv_len ); + if ( !lo->ldo_tls_cacert.bv_val ) + return -1; + AC_MEMCPY( lo->ldo_tls_cacert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cacert.bv_len ); + break; + case LDAP_OPT_X_TLS_CERT: + if ( !arg ) return -1; + if ( lo->ldo_tls_cert.bv_val ) + LDAP_FREE( lo->ldo_tls_cert.bv_val ); + lo->ldo_tls_cert.bv_len = ((struct berval *)arg)->bv_len; + lo->ldo_tls_cert.bv_val = LDAP_MALLOC( lo->ldo_tls_cert.bv_len ); + if ( !lo->ldo_tls_cert.bv_val ) + return -1; + AC_MEMCPY( lo->ldo_tls_cert.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_cert.bv_len ); + break; + case LDAP_OPT_X_TLS_KEY: + if ( !arg ) return -1; + if ( lo->ldo_tls_key.bv_val ) + LDAP_FREE( lo->ldo_tls_key.bv_val ); + lo->ldo_tls_key.bv_len = ((struct berval *)arg)->bv_len; + lo->ldo_tls_key.bv_val = LDAP_MALLOC( lo->ldo_tls_key.bv_len ); + if ( !lo->ldo_tls_key.bv_val ) + return -1; + AC_MEMCPY( lo->ldo_tls_key.bv_val, ((struct berval *)arg)->bv_val, lo->ldo_tls_key.bv_len ); + break; default: return -1; } diff --git a/libraries/libldap/tls_o.c b/libraries/libldap/tls_o.c index 795278d30d..ce0663b66b 100644 --- a/libraries/libldap/tls_o.c +++ b/libraries/libldap/tls_o.c @@ -114,7 +114,7 @@ static void tlso_thr_init( void ) {} #endif /* OpenSSL 1.1 */ static STACK_OF(X509_NAME) * -tlso_ca_list( char * bundle, char * dir ) +tlso_ca_list( char * bundle, char * dir, X509 *cert ) { STACK_OF(X509_NAME) *ca_list = NULL; @@ -136,6 +136,12 @@ tlso_ca_list( char * bundle, char * dir ) } } #endif + if ( cert ) { + X509_NAME *xn = X509_get_subject_name( cert ); + xn = X509_NAME_dup( xn ); + if ( xn ) + sk_X509_NAME_push( ca_list, xn ); + } return ca_list; } @@ -266,7 +272,8 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) return -1; } - if ( lo->ldo_tls_cacertfile == NULL && lo->ldo_tls_cacertdir == NULL ) { + if ( lo->ldo_tls_cacertfile == NULL && lo->ldo_tls_cacertdir == NULL && + lo->ldo_tls_cacert.bv_val == NULL ) { if ( !SSL_CTX_set_default_verify_paths( ctx ) ) { Debug( LDAP_DEBUG_ANY, "TLS: " "could not use default certificate paths", 0, 0, 0 ); @@ -274,7 +281,19 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) return -1; } } else { - if ( !SSL_CTX_load_verify_locations( ctx, + X509 *cert = NULL; + if ( lo->ldo_tls_cacert.bv_val ) { + const unsigned char *pp = lo->ldo_tls_cacert.bv_val; + cert = d2i_X509( NULL, &pp, lo->ldo_tls_cacert.bv_len ); + X509_STORE *store = SSL_CTX_get_cert_store( ctx ); + if ( !X509_STORE_add_cert( store, cert )) { + Debug( LDAP_DEBUG_ANY, "TLS: " + "could not use CA certificate", 0, 0, 0 ); + tlso_report_error(); + return -1; + } + } + if (( lt->lt_cacertfile || lt->lt_cacertdir ) && !SSL_CTX_load_verify_locations( ctx, lt->lt_cacertfile, lt->lt_cacertdir ) ) { Debug( LDAP_DEBUG_ANY, "TLS: " @@ -289,7 +308,7 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) if ( is_server ) { STACK_OF(X509_NAME) *calist; /* List of CA names to send to a client */ - calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir ); + calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir, cert ); if ( !calist ) { Debug( LDAP_DEBUG_ANY, "TLS: " "could not load client CA list (file:`%s',dir:`%s').\n", @@ -302,20 +321,47 @@ tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) SSL_CTX_set_client_CA_list( ctx, calist ); } + if ( cert ) + X509_free( cert ); } + if ( lo->ldo_tls_cert.bv_val ) + { + const unsigned char *pp = lo->ldo_tls_cert.bv_val; + X509 *cert = d2i_X509( NULL, &pp, lo->ldo_tls_cert.bv_len ); + if ( !SSL_CTX_use_certificate( ctx, cert )) { + Debug( LDAP_DEBUG_ANY, + "TLS: could not use certificate.\n", 0,0,0); + tlso_report_error(); + return -1; + } + X509_free( cert ); + } else if ( lo->ldo_tls_certfile && !SSL_CTX_use_certificate_file( ctx, lt->lt_certfile, SSL_FILETYPE_PEM ) ) { Debug( LDAP_DEBUG_ANY, - "TLS: could not use certificate `%s'.\n", + "TLS: could not use certificate file `%s'.\n", lo->ldo_tls_certfile,0,0); tlso_report_error(); return -1; } /* Key validity is checked automatically if cert has already been set */ + if ( lo->ldo_tls_key.bv_val ) + { + const unsigned char *pp = lo->ldo_tls_key.bv_val; + EVP_PKEY *pkey = d2i_AutoPrivateKey( NULL, &pp, lo->ldo_tls_key.bv_len ); + if ( !SSL_CTX_use_PrivateKey( ctx, pkey )) + { + Debug( LDAP_DEBUG_ANY, + "TLS: could not use private key.\n", 0,0,0); + tlso_report_error(); + return -1; + } + EVP_PKEY_free( pkey ); + } else if ( lo->ldo_tls_keyfile && !SSL_CTX_use_PrivateKey_file( ctx, lt->lt_keyfile, SSL_FILETYPE_PEM ) )