]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/tls2.c
ITS#7313 MozNSS: store certificate object instead of nickname in in ctx
[openldap] / libraries / libldap / tls2.c
index baadb1375d3901a2f7753a576ddd4924f4605eff..3809e9d8862f19a4df8bb346ccc2e0655c2f169a 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2009 The OpenLDAP Foundation.
+ * Copyright 1998-2012 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
 #include "ldap-tls.h"
 
-#ifdef LDAP_R_COMPILE
-#include <ldap_pvt_thread.h>
-#endif
-
 static tls_impl *tls_imp = &ldap_int_tls_impl;
 #define HAS_TLS( sb )  ber_sockbuf_ctrl( sb, LBER_SB_OPT_HAS_IO, \
                                (void *)tls_imp->ti_sbio )
@@ -143,7 +139,6 @@ void
 ldap_pvt_tls_destroy( void )
 {
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
-       int i;
 
        ldap_int_tls_destroy( lo );
 
@@ -179,8 +174,6 @@ tls_init(tls_impl *impl )
 int
 ldap_pvt_tls_init( void )
 {
-       struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
-
        return tls_init( tls_imp );
 }
 
@@ -190,7 +183,7 @@ ldap_pvt_tls_init( void )
 static int
 ldap_int_tls_init_ctx( struct ldapoptions *lo, int is_server )
 {
-       int i, rc = 0;
+       int rc = 0;
        tls_impl *ti = tls_imp;
        struct ldaptls lts = lo->ldo_tls_info;
 
@@ -272,13 +265,9 @@ ldap_pvt_tls_init_def_ctx( int is_server )
 {
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
        int rc;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_lock( &tls_def_ctx_mutex );
-#endif
+       LDAP_MUTEX_LOCK( &tls_def_ctx_mutex );
        rc = ldap_int_tls_init_ctx( lo, is_server );
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &tls_def_ctx_mutex );
-#endif
+       LDAP_MUTEX_UNLOCK( &tls_def_ctx_mutex );
        return rc;
 }
 
@@ -379,7 +368,7 @@ ldap_int_tls_connect( LDAP *ld, LDAPConn *conn )
                        return 1;
                }
 
-               msg = tls_imp->ti_session_errmsg( err, buf, sizeof(buf) );
+               msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
                if ( msg ) {
                        if ( ld->ld_error ) {
                                LDAP_FREE( ld->ld_error );
@@ -437,11 +426,14 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg )
 
        if ( err < 0 )
        {
-               char buf[256];
                if ( update_flags( sb, ssl, err )) return 1;
 
-               Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
-                       tls_imp->ti_session_errmsg( err, buf, sizeof(buf) ),0,0 );
+               if ( DebugTest( LDAP_DEBUG_ANY ) ) {
+                       char buf[256], *msg;
+                       msg = tls_imp->ti_session_errmsg( ssl, err, buf, sizeof(buf) );
+                       Debug( LDAP_DEBUG_ANY,"TLS: can't accept: %s.\n",
+                               msg ? msg : "(unknown)", 0, 0 );
+               }
 
                ber_sockbuf_remove_io( sb, tls_imp->ti_sbio,
                        LBER_SBIOD_LEVEL_TRANSPORT );
@@ -562,6 +554,7 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg )
                }
                return ldap_pvt_tls_set_option( ld, option, &i );
                }
+#ifdef HAVE_OPENSSL_CRL
        case LDAP_OPT_X_TLS_CRLCHECK:   /* OpenSSL only */
                i = -1;
                if ( strcasecmp( arg, "none" ) == 0 ) {
@@ -575,6 +568,7 @@ ldap_int_tls_config( LDAP *ld, int option, const char *arg )
                        return ldap_pvt_tls_set_option( ld, option, &i );
                }
                return -1;
+#endif
        }
        return -1;
 }
@@ -584,6 +578,11 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
 {
        struct ldapoptions *lo;
 
+       if( option == LDAP_OPT_X_TLS_PACKAGE ) {
+               *(char **)arg = LDAP_STRDUP( tls_imp->ti_name );
+               return 0;
+       }
+
        if( ld != NULL ) {
                assert( LDAP_VALID( ld ) );
 
@@ -638,9 +637,11 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
        case LDAP_OPT_X_TLS_REQUIRE_CERT:
                *(int *)arg = lo->ldo_tls_require_cert;
                break;
+#ifdef HAVE_OPENSSL_CRL
        case LDAP_OPT_X_TLS_CRLCHECK:   /* OpenSSL only */
                *(int *)arg = lo->ldo_tls_crlcheck;
                break;
+#endif
        case LDAP_OPT_X_TLS_CIPHER_SUITE:
                *(char **)arg = lo->ldo_tls_ciphersuite ?
                        LDAP_STRDUP( lo->ldo_tls_ciphersuite ) : NULL;
@@ -648,7 +649,7 @@ ldap_pvt_tls_get_option( LDAP *ld, int option, void *arg )
        case LDAP_OPT_X_TLS_PROTOCOL_MIN:
                *(int *)arg = lo->ldo_tls_protocol_min;
                break;
-       case LDAP_OPT_X_TLS_RANDOM_FILE:        /* OpenSSL only */
+       case LDAP_OPT_X_TLS_RANDOM_FILE:
                *(char **)arg = lo->ldo_tls_randfile ?
                        LDAP_STRDUP( lo->ldo_tls_randfile ) : NULL;
                break;
@@ -764,6 +765,7 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
                        return 0;
                }
                return -1;
+#ifdef HAVE_OPENSSL_CRL
        case LDAP_OPT_X_TLS_CRLCHECK:   /* OpenSSL only */
                if ( !arg ) return -1;
                switch( *(int *) arg ) {
@@ -774,6 +776,7 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
                        return 0;
                }
                return -1;
+#endif
        case LDAP_OPT_X_TLS_CIPHER_SUITE:
                if ( lo->ldo_tls_ciphersuite ) LDAP_FREE( lo->ldo_tls_ciphersuite );
                lo->ldo_tls_ciphersuite = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
@@ -783,14 +786,12 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
                if ( !arg ) return -1;
                lo->ldo_tls_protocol_min = *(int *)arg;
                return 0;
-
-       case LDAP_OPT_X_TLS_RANDOM_FILE:        /* OpenSSL only */
+       case LDAP_OPT_X_TLS_RANDOM_FILE:
                if ( ld != NULL )
                        return -1;
                if ( lo->ldo_tls_randfile ) LDAP_FREE (lo->ldo_tls_randfile );
                lo->ldo_tls_randfile = arg ? LDAP_STRDUP( (char *) arg ) : NULL;
                break;
-
        case LDAP_OPT_X_TLS_NEWCTX:
                if ( !arg ) return -1;
                if ( lo->ldo_tls_ctx )
@@ -806,10 +807,14 @@ ldap_pvt_tls_set_option( LDAP *ld, int option, void *arg )
 int
 ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
 {
-       Sockbuf *sb = conn->lconn_sb;
+       Sockbuf *sb;
        char *host;
        void *ssl;
 
+       if ( !conn )
+               return LDAP_PARAM_ERROR;
+
+       sb = conn->lconn_sb;
        if( srv ) {
                host = srv->lud_host;
        } else {
@@ -837,7 +842,8 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
        /* 
         * compare host with name(s) in certificate
         */
-       if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER) {
+       if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER &&
+           ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) {
                ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host );
                if (ld->ld_errno != LDAP_SUCCESS) {
                        return ld->ld_errno;
@@ -871,8 +877,9 @@ ldap_pvt_tls_get_my_dn( void *s, struct berval *dn, LDAPDN_rewrite_dummy *func,
        struct berval der_dn;
        int rc;
 
-       tls_imp->ti_session_my_dn( session, &der_dn );
-       rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
+       rc = tls_imp->ti_session_my_dn( session, &der_dn );
+       if ( rc == LDAP_SUCCESS )
+               rc = ldap_X509dn2bv(&der_dn, dn, (LDAPDN_rewrite_func *)func, flags );
        return rc;
 }
 #endif /* HAVE_TLS */
@@ -970,6 +977,93 @@ find_oid( struct berval *oid )
        return NULL;
 }
 
+/* Converts BER Bitstring value to LDAP BitString value (RFC4517)
+ *
+ * berValue    : IN
+ * rfc4517Value: OUT
+ *
+ * berValue and ldapValue should not be NULL
+ */
+
+#define BITS_PER_BYTE  8
+#define SQUOTE_LENGTH  1
+#define B_CHAR_LENGTH  1
+#define STR_OVERHEAD    (2*SQUOTE_LENGTH + B_CHAR_LENGTH)
+
+static int
+der_to_ldap_BitString (struct berval *berValue,
+                                   struct berval *ldapValue)
+{
+       ber_len_t bitPadding=0;
+       ber_len_t bits, maxBits;
+       char *tmpStr;
+       unsigned char byte;
+       ber_len_t bitLength;
+       ber_len_t valLen;
+       unsigned char* valPtr;
+
+       ldapValue->bv_len=0;
+       ldapValue->bv_val=NULL;
+
+       /* Gets padding and points to binary data */
+       valLen=berValue->bv_len;
+       valPtr=(unsigned char*)berValue->bv_val;
+       if (valLen) {
+               bitPadding=(ber_len_t)(valPtr[0]);
+               valLen--;
+               valPtr++;
+       }
+       /* If Block is non DER encoding fixes to DER encoding */
+       if (bitPadding >= BITS_PER_BYTE) {
+               if (valLen*BITS_PER_BYTE > bitPadding ) {
+                       valLen-=(bitPadding/BITS_PER_BYTE);
+                       bitPadding%=BITS_PER_BYTE;
+               } else {
+                       valLen=0;
+                       bitPadding=0;
+               }
+       }
+       /* Just in case bad encoding */
+       if (valLen*BITS_PER_BYTE < bitPadding ) {
+               bitPadding=0;
+               valLen=0;
+       }
+
+       /* Gets buffer to hold RFC4517 Bit String format */
+       bitLength=valLen*BITS_PER_BYTE-bitPadding;
+       tmpStr=LDAP_MALLOC(bitLength + STR_OVERHEAD + 1);
+
+       if (!tmpStr)
+               return LDAP_NO_MEMORY;
+
+       ldapValue->bv_val=tmpStr;
+       ldapValue->bv_len=bitLength + STR_OVERHEAD;
+
+       /* Formatting in '*binary-digit'B format */
+       maxBits=BITS_PER_BYTE;
+       *tmpStr++ ='\'';
+       while(valLen) {
+               byte=*valPtr;
+               if (valLen==1)
+                       maxBits-=bitPadding;
+               for (bits=0; bits<maxBits; bits++) {
+                       if (0x80 & byte)
+                               *tmpStr='1';
+                       else
+                               *tmpStr='0';
+                       tmpStr++;
+                       byte<<=1;
+               }
+               valPtr++;
+               valLen--;
+       }
+       *tmpStr++ ='\'';
+       *tmpStr++ ='B';
+       *tmpStr=0;
+
+       return LDAP_SUCCESS;
+}
+
 /* Convert a structured DN from an X.509 certificate into an LDAPV3 DN.
  * x509_name must be raw DER. If func is non-NULL, the
  * constructed DN will use numeric OIDs to identify attributeTypes,
@@ -1112,6 +1206,8 @@ ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func,
                                        newAVA->la_attr = oidname->name;
                                }
                        }
+                       newAVA->la_private = NULL;
+                       newAVA->la_flags = LDAP_AVA_STRING;
                        tag = ber_get_stringbv( ber, &Val, LBER_BV_NOTERM );
                        switch(tag) {
                        case LBER_TAG_UNIVERSAL:
@@ -1124,22 +1220,29 @@ ldap_X509dn2bv( void *x509_name, struct berval *bv, LDAPDN_rewrite_func *func,
                                /* This uses 8-bit, assume ISO 8859-1 */
                                csize = 1;
 to_utf8:               rc = ldap_ucs_to_utf8s( &Val, csize, &newAVA->la_value );
+                               newAVA->la_flags |= LDAP_AVA_NONPRINTABLE;
+allocd:
                                newAVA->la_flags |= LDAP_AVA_FREE_VALUE;
                                if (rc != LDAP_SUCCESS) goto nomem;
-                               newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
                                break;
                        case LBER_TAG_UTF8:
-                               newAVA->la_flags = LDAP_AVA_NONPRINTABLE;
+                               newAVA->la_flags |= LDAP_AVA_NONPRINTABLE;
                                /* This is already in UTF-8 encoding */
                        case LBER_TAG_IA5:
                        case LBER_TAG_PRINTABLE:
                                /* These are always 7-bit strings */
                                newAVA->la_value = Val;
+                               break;
+                       case LBER_BITSTRING:
+                               /* X.690 bitString value converted to RFC4517 Bit String */
+                               rc = der_to_ldap_BitString( &Val, &newAVA->la_value );
+                               goto allocd;
                        default:
-                               ;
+                               /* Not a string type at all */
+                               newAVA->la_flags = 0;
+                               newAVA->la_value = Val;
+                               break;
                        }
-                       newAVA->la_private = NULL;
-                       newAVA->la_flags = LDAP_AVA_STRING;
                        newAVA++;
                }
                *newRDN++ = NULL;