~ubuntu-branches/ubuntu/lucid/openldap/lucid-proposed

« back to all changes in this revision

Viewing changes to libraries/libldap/tls_o.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug, Steve Langasek, Mathias Gug
  • Date: 2009-02-18 18:44:00 UTC
  • mfrom: (1.1.2 upstream) (0.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20090218184400-zw4mjse9eywt5566
Tags: 2.4.14-0ubuntu1
[ Steve Langasek ]
* New upstream version
  - Fixes a bug with the pcache overlay not returning cached entries
    (closes: #497697)
  - Update evolution-ntlm patch to apply to current Makefiles.
  - (tentatively) drop gnutls-ciphers, since this bug was reported to be
    fixed upstream in 2.4.8.  The fix applied in 2.4.8 didn't match the
    patch from the bug report, so this should be watched for regressions.
* Build against db4.7 instead of db4.2 at last!  Closes: #421946.
* Build with --disable-ndb, to avoid a misbuild when libmysqlclient is
  installed in the build environment.
* New patch, no-crlcheck-for-gnutls, to fix a build failure when using
  --with-tls=gnutls.

[ Mathias Gug ]
* Merge from debian unstable, remaining changes:
  - debian/apparmor-profile: add AppArmor profile
  - debian/slapd.postinst: Reload AA profile on configuration
  - updated debian/slapd.README.Debian for note on AppArmor
  - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6
  - debian/control: Conflicts with apparmor-profiles << 2.1+1075-0ubuntu4
    to make sure that if earlier version of apparmour-profiles gets
    installed it won't overwrite our profile.
  - Modify Maintainer value to match the DebianMaintainerField
    speficication.
  - follow ApparmorProfileMigration and force apparmor compalin mode on 
    some upgrades (LP: #203529)
  - debian/slapd.dirs: add etc/apparmor.d/force-complain
  - debian/slapd.preinst: create symlink for force-complain on pre-feisty
    upgrades, upgrades where apparmor-profiles profile is unchanged (ie
    non-enforcing) and upgrades where apparmor profile does not exist.
  - debian/slapd.postrm: remove symlink in force-complain/ on purge
  - debian/patches/fix-ucred-libc due to changes how newer glibc handle
    the ucred struct now.
  - debian/control:
    - Build-depend on libltdl7-dev rather then libltdl3-dev.
  - debian/patches/autogen.sh:
    - Call libtoolize with the --install option to install config.{guess,sub}
      files.
  - Don't use local statement in config script as it fails if /bin/sh
    points to bash (LP: #286063).
  - Disable the testsuite on hppa. Allows building of packages on this
    architecture again, once this package is in the archive.
    LP: #288908.
  - debian/slapd.postinst, debian/slapd.script-common: set correct ownership
    and permissions on /var/lib/ldap, /etc/ldap/slapd.d (group readable) and
    /var/run/slapd (world readable). (LP: #257667).
  - debian/patches/nssov-build, debian/rules: 
    Build and package the nss overlay.
    debian/schema/misc.ldif: add ldif file for the misc schema, which defines
    rfc822MailMember (required by the nss overlay).
  - debian/{control,rules}: enable PIE hardening
  - Use cn=config as the default configuration backend instead of 
    slapd.conf. Migrate slapd.conf  file to /etc/ldap/slapd.d/ on upgrade
    asking the end user to enter a new password to control the access to the
    cn=config tree.
* debian/patches/corrupt-contextCSN: The contextCSN can get corrupted at
  times. (ITS: #5947)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* tls_o.c - Handle tls/ssl using SSLeay or OpenSSL */
 
2
/* $OpenLDAP: pkg/ldap/libraries/libldap/tls_o.c,v 1.5.2.2 2009/02/10 16:41:01 quanah Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 2008-2009 The OpenLDAP Foundation.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted only as authorized by the OpenLDAP
 
10
 * Public License.
 
11
 *
 
12
 * A copy of this license is available in the file LICENSE in the
 
13
 * top-level directory of the distribution or, alternatively, at
 
14
 * <http://www.OpenLDAP.org/license.html>.
 
15
 */
 
16
/* ACKNOWLEDGEMENTS: Rewritten by Howard Chu
 
17
 */
 
18
 
 
19
#include "portable.h"
 
20
 
 
21
#ifdef HAVE_OPENSSL
 
22
 
 
23
#include "ldap_config.h"
 
24
 
 
25
#include <stdio.h>
 
26
 
 
27
#include <ac/stdlib.h>
 
28
#include <ac/errno.h>
 
29
#include <ac/socket.h>
 
30
#include <ac/string.h>
 
31
#include <ac/ctype.h>
 
32
#include <ac/time.h>
 
33
#include <ac/unistd.h>
 
34
#include <ac/param.h>
 
35
#include <ac/dirent.h>
 
36
 
 
37
#include "ldap-int.h"
 
38
#include "ldap-tls.h"
 
39
 
 
40
#ifdef LDAP_R_COMPILE
 
41
#include <ldap_pvt_thread.h>
 
42
#endif
 
43
 
 
44
#ifdef HAVE_OPENSSL_SSL_H
 
45
#include <openssl/ssl.h>
 
46
#include <openssl/x509v3.h>
 
47
#include <openssl/err.h>
 
48
#include <openssl/rand.h>
 
49
#include <openssl/safestack.h>
 
50
#elif defined( HAVE_SSL_H )
 
51
#include <ssl.h>
 
52
#endif
 
53
 
 
54
typedef SSL_CTX tlso_ctx;
 
55
typedef SSL tlso_session;
 
56
 
 
57
static int  tlso_opt_trace = 1;
 
58
 
 
59
static void tlso_report_error( void );
 
60
 
 
61
static void tlso_info_cb( const SSL *ssl, int where, int ret );
 
62
static int tlso_verify_cb( int ok, X509_STORE_CTX *ctx );
 
63
static int tlso_verify_ok( int ok, X509_STORE_CTX *ctx );
 
64
static RSA * tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length );
 
65
 
 
66
static DH * tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length );
 
67
 
 
68
typedef struct dhplist {
 
69
        struct dhplist *next;
 
70
        int keylength;
 
71
        DH *param;
 
72
} dhplist;
 
73
 
 
74
static dhplist *tlso_dhparams;
 
75
 
 
76
static int tlso_seed_PRNG( const char *randfile );
 
77
 
 
78
#ifdef LDAP_R_COMPILE
 
79
/*
 
80
 * provide mutexes for the SSLeay library.
 
81
 */
 
82
static ldap_pvt_thread_mutex_t  tlso_mutexes[CRYPTO_NUM_LOCKS];
 
83
static ldap_pvt_thread_mutex_t  tlso_dh_mutex;
 
84
 
 
85
static void tlso_locking_cb( int mode, int type, const char *file, int line )
 
86
{
 
87
        if ( mode & CRYPTO_LOCK ) {
 
88
                ldap_pvt_thread_mutex_lock( &tlso_mutexes[type] );
 
89
        } else {
 
90
                ldap_pvt_thread_mutex_unlock( &tlso_mutexes[type] );
 
91
        }
 
92
}
 
93
 
 
94
static unsigned long tlso_thread_self( void )
 
95
{
 
96
        /* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t
 
97
         * is an integral type that fits in an unsigned long
 
98
         */
 
99
 
 
100
        /* force an error if the ldap_pvt_thread_t type is too large */
 
101
        enum { ok = sizeof( ldap_pvt_thread_t ) <= sizeof( unsigned long ) };
 
102
        typedef struct { int dummy: ok ? 1 : -1; } Check[ok ? 1 : -1];
 
103
 
 
104
        return (unsigned long) ldap_pvt_thread_self();
 
105
}
 
106
 
 
107
static void tlso_thr_init( void )
 
108
{
 
109
        int i;
 
110
 
 
111
        for( i=0; i< CRYPTO_NUM_LOCKS ; i++ ) {
 
112
                ldap_pvt_thread_mutex_init( &tlso_mutexes[i] );
 
113
        }
 
114
        ldap_pvt_thread_mutex_init( &tlso_dh_mutex );
 
115
        CRYPTO_set_locking_callback( tlso_locking_cb );
 
116
        CRYPTO_set_id_callback( tlso_thread_self );
 
117
}
 
118
#endif /* LDAP_R_COMPILE */
 
119
 
 
120
static STACK_OF(X509_NAME) *
 
121
tlso_ca_list( char * bundle, char * dir )
 
122
{
 
123
        STACK_OF(X509_NAME) *ca_list = NULL;
 
124
 
 
125
        if ( bundle ) {
 
126
                ca_list = SSL_load_client_CA_file( bundle );
 
127
        }
 
128
#if defined(HAVE_DIRENT_H) || defined(dirent)
 
129
        if ( dir ) {
 
130
                int freeit = 0;
 
131
 
 
132
                if ( !ca_list ) {
 
133
                        ca_list = sk_X509_NAME_new_null();
 
134
                        freeit = 1;
 
135
                }
 
136
                if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) &&
 
137
                        freeit ) {
 
138
                        sk_X509_NAME_free( ca_list );
 
139
                        ca_list = NULL;
 
140
                }
 
141
        }
 
142
#endif
 
143
        return ca_list;
 
144
}
 
145
 
 
146
/*
 
147
 * Initialize TLS subsystem. Should be called only once.
 
148
 */
 
149
static int
 
150
tlso_init( void )
 
151
{
 
152
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
 
153
#ifdef HAVE_EBCDIC
 
154
        {
 
155
                char *file = LDAP_STRDUP( lo->ldo_tls_randfile );
 
156
                if ( file ) __atoe( file );
 
157
                (void) tlso_seed_PRNG( file );
 
158
                LDAP_FREE( file );
 
159
        }
 
160
#else
 
161
        (void) tlso_seed_PRNG( lo->ldo_tls_randfile );
 
162
#endif
 
163
 
 
164
        SSL_load_error_strings();
 
165
        SSLeay_add_ssl_algorithms();
 
166
 
 
167
        /* FIXME: mod_ssl does this */
 
168
        X509V3_add_standard_extensions();
 
169
 
 
170
        return 0;
 
171
}
 
172
 
 
173
/*
 
174
 * Tear down the TLS subsystem. Should only be called once.
 
175
 */
 
176
static void
 
177
tlso_destroy( void )
 
178
{
 
179
        struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT();   
 
180
 
 
181
        EVP_cleanup();
 
182
        ERR_remove_state(0);
 
183
        ERR_free_strings();
 
184
 
 
185
        if ( lo->ldo_tls_randfile ) {
 
186
                LDAP_FREE( lo->ldo_tls_randfile );
 
187
                lo->ldo_tls_randfile = NULL;
 
188
        }
 
189
}
 
190
 
 
191
static tls_ctx *
 
192
tlso_ctx_new( struct ldapoptions *lo )
 
193
{
 
194
        return (tls_ctx *) SSL_CTX_new( SSLv23_method() );
 
195
}
 
196
 
 
197
static void
 
198
tlso_ctx_ref( tls_ctx *ctx )
 
199
{
 
200
        tlso_ctx *c = (tlso_ctx *)ctx;
 
201
        CRYPTO_add( &c->references, 1, CRYPTO_LOCK_SSL_CTX );
 
202
}
 
203
 
 
204
static void
 
205
tlso_ctx_free ( tls_ctx *ctx )
 
206
{
 
207
        tlso_ctx *c = (tlso_ctx *)ctx;
 
208
        SSL_CTX_free( c );
 
209
}
 
210
 
 
211
/*
 
212
 * initialize a new TLS context
 
213
 */
 
214
static int
 
215
tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server )
 
216
{
 
217
        tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx;
 
218
        int i;
 
219
 
 
220
        if ( is_server ) {
 
221
                SSL_CTX_set_session_id_context( ctx,
 
222
                        (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 );
 
223
        }
 
224
 
 
225
        if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 )
 
226
                SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 );
 
227
        else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 )
 
228
                SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 );
 
229
 
 
230
        if ( lo->ldo_tls_ciphersuite &&
 
231
                !SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) )
 
232
        {
 
233
                Debug( LDAP_DEBUG_ANY,
 
234
                           "TLS: could not set cipher list %s.\n",
 
235
                           lo->ldo_tls_ciphersuite, 0, 0 );
 
236
                tlso_report_error();
 
237
                return -1;
 
238
        }
 
239
 
 
240
        if (lo->ldo_tls_cacertfile != NULL || lo->ldo_tls_cacertdir != NULL) {
 
241
                if ( !SSL_CTX_load_verify_locations( ctx,
 
242
                                lt->lt_cacertfile, lt->lt_cacertdir ) ||
 
243
                        !SSL_CTX_set_default_verify_paths( ctx ) )
 
244
                {
 
245
                        Debug( LDAP_DEBUG_ANY, "TLS: "
 
246
                                "could not load verify locations (file:`%s',dir:`%s').\n",
 
247
                                lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
 
248
                                lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
 
249
                                0 );
 
250
                        tlso_report_error();
 
251
                        return -1;
 
252
                }
 
253
 
 
254
                if ( is_server ) {
 
255
                        STACK_OF(X509_NAME) *calist;
 
256
                        /* List of CA names to send to a client */
 
257
                        calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir );
 
258
                        if ( !calist ) {
 
259
                                Debug( LDAP_DEBUG_ANY, "TLS: "
 
260
                                        "could not load client CA list (file:`%s',dir:`%s').\n",
 
261
                                        lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "",
 
262
                                        lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "",
 
263
                                        0 );
 
264
                                tlso_report_error();
 
265
                                return -1;
 
266
                        }
 
267
 
 
268
                        SSL_CTX_set_client_CA_list( ctx, calist );
 
269
                }
 
270
        }
 
271
 
 
272
        if ( lo->ldo_tls_certfile &&
 
273
                !SSL_CTX_use_certificate_file( ctx,
 
274
                        lt->lt_certfile, SSL_FILETYPE_PEM ) )
 
275
        {
 
276
                Debug( LDAP_DEBUG_ANY,
 
277
                        "TLS: could not use certificate `%s'.\n",
 
278
                        lo->ldo_tls_certfile,0,0);
 
279
                tlso_report_error();
 
280
                return -1;
 
281
        }
 
282
 
 
283
        /* Key validity is checked automatically if cert has already been set */
 
284
        if ( lo->ldo_tls_keyfile &&
 
285
                !SSL_CTX_use_PrivateKey_file( ctx,
 
286
                        lt->lt_keyfile, SSL_FILETYPE_PEM ) )
 
287
        {
 
288
                Debug( LDAP_DEBUG_ANY,
 
289
                        "TLS: could not use key file `%s'.\n",
 
290
                        lo->ldo_tls_keyfile,0,0);
 
291
                tlso_report_error();
 
292
                return -1;
 
293
        }
 
294
 
 
295
        if ( lo->ldo_tls_dhfile ) {
 
296
                DH *dh = NULL;
 
297
                BIO *bio;
 
298
                dhplist *p;
 
299
 
 
300
                if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) {
 
301
                        Debug( LDAP_DEBUG_ANY,
 
302
                                "TLS: could not use DH parameters file `%s'.\n",
 
303
                                lo->ldo_tls_dhfile,0,0);
 
304
                        tlso_report_error();
 
305
                        return -1;
 
306
                }
 
307
                while (( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) {
 
308
                        p = LDAP_MALLOC( sizeof(dhplist) );
 
309
                        if ( p != NULL ) {
 
310
                                p->keylength = DH_size( dh ) * 8;
 
311
                                p->param = dh;
 
312
                                p->next = tlso_dhparams;
 
313
                                tlso_dhparams = p;
 
314
                        }
 
315
                }
 
316
                BIO_free( bio );
 
317
        }
 
318
 
 
319
        if ( tlso_opt_trace ) {
 
320
                SSL_CTX_set_info_callback( ctx, tlso_info_cb );
 
321
        }
 
322
 
 
323
        i = SSL_VERIFY_NONE;
 
324
        if ( lo->ldo_tls_require_cert ) {
 
325
                i = SSL_VERIFY_PEER;
 
326
                if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND ||
 
327
                         lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) {
 
328
                        i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 
329
                }
 
330
        }
 
331
 
 
332
        SSL_CTX_set_verify( ctx, i,
 
333
                lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ?
 
334
                tlso_verify_ok : tlso_verify_cb );
 
335
        SSL_CTX_set_tmp_rsa_callback( ctx, tlso_tmp_rsa_cb );
 
336
        if ( lo->ldo_tls_dhfile ) {
 
337
                SSL_CTX_set_tmp_dh_callback( ctx, tlso_tmp_dh_cb );
 
338
        }
 
339
#ifdef HAVE_OPENSSL_CRL
 
340
        if ( lo->ldo_tls_crlcheck ) {
 
341
                X509_STORE *x509_s = SSL_CTX_get_cert_store( ctx );
 
342
                if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) {
 
343
                        X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK );
 
344
                } else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) {
 
345
                        X509_STORE_set_flags( x509_s, 
 
346
                                        X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL  );
 
347
                }
 
348
        }
 
349
#endif
 
350
        return 0;
 
351
}
 
352
 
 
353
static tls_session *
 
354
tlso_session_new( tls_ctx *ctx, int is_server )
 
355
{
 
356
        tlso_ctx *c = (tlso_ctx *)ctx;
 
357
        return (tls_session *)SSL_new( c );
 
358
}
 
359
 
 
360
static int
 
361
tlso_session_connect( LDAP *ld, tls_session *sess )
 
362
{
 
363
        tlso_session *s = (tlso_session *)sess;
 
364
 
 
365
        /* Caller expects 0 = success, OpenSSL returns 1 = success */
 
366
        return SSL_connect( s ) - 1;
 
367
}
 
368
 
 
369
static int
 
370
tlso_session_accept( tls_session *sess )
 
371
{
 
372
        tlso_session *s = (tlso_session *)sess;
 
373
 
 
374
        /* Caller expects 0 = success, OpenSSL returns 1 = success */
 
375
        return SSL_accept( s ) - 1;
 
376
}
 
377
 
 
378
static int
 
379
tlso_session_upflags( Sockbuf *sb, tls_session *sess, int rc )
 
380
{
 
381
        tlso_session *s = (tlso_session *)sess;
 
382
 
 
383
        /* 1 was subtracted above, offset it back now */
 
384
        rc = SSL_get_error(s, rc+1);
 
385
        if (rc == SSL_ERROR_WANT_READ) {
 
386
                sb->sb_trans_needs_read  = 1;
 
387
                return 1;
 
388
 
 
389
        } else if (rc == SSL_ERROR_WANT_WRITE) {
 
390
                sb->sb_trans_needs_write = 1;
 
391
                return 1;
 
392
 
 
393
        } else if (rc == SSL_ERROR_WANT_CONNECT) {
 
394
                return 1;
 
395
        }
 
396
        return 0;
 
397
}
 
398
 
 
399
static char *
 
400
tlso_session_errmsg( int rc, char *buf, size_t len )
 
401
{
 
402
        rc = ERR_peek_error();
 
403
        if ( rc ) {
 
404
                ERR_error_string_n( rc, buf, len );
 
405
                return buf;
 
406
        }
 
407
        return NULL;
 
408
}
 
409
 
 
410
static int
 
411
tlso_session_my_dn( tls_session *sess, struct berval *der_dn )
 
412
{
 
413
        tlso_session *s = (tlso_session *)sess;
 
414
        X509 *x;
 
415
        X509_NAME *xn;
 
416
 
 
417
        x = SSL_get_certificate( s );
 
418
 
 
419
        if (!x) return LDAP_INVALID_CREDENTIALS;
 
420
        
 
421
        xn = X509_get_subject_name(x);
 
422
        der_dn->bv_len = i2d_X509_NAME( xn, NULL );
 
423
        der_dn->bv_val = xn->bytes->data;
 
424
        X509_free(x);
 
425
        return 0;
 
426
}
 
427
 
 
428
static X509 *
 
429
tlso_get_cert( SSL *s )
 
430
{
 
431
        /* If peer cert was bad, treat as if no cert was given */
 
432
        if (SSL_get_verify_result(s)) {
 
433
                return NULL;
 
434
        }
 
435
        return SSL_get_peer_certificate(s);
 
436
}
 
437
 
 
438
static int
 
439
tlso_session_peer_dn( tls_session *sess, struct berval *der_dn )
 
440
{
 
441
        tlso_session *s = (tlso_session *)sess;
 
442
        X509 *x = tlso_get_cert( s );
 
443
        X509_NAME *xn;
 
444
 
 
445
        if ( !x )
 
446
                return LDAP_INVALID_CREDENTIALS;
 
447
 
 
448
        xn = X509_get_subject_name(x);
 
449
        der_dn->bv_len = i2d_X509_NAME( xn, NULL );
 
450
        der_dn->bv_val = xn->bytes->data;
 
451
        X509_free(x);
 
452
        return 0;
 
453
}
 
454
 
 
455
/* what kind of hostname were we given? */
 
456
#define IS_DNS  0
 
457
#define IS_IP4  1
 
458
#define IS_IP6  2
 
459
 
 
460
static int
 
461
tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in )
 
462
{
 
463
        tlso_session *s = (tlso_session *)sess;
 
464
        int i, ret = LDAP_LOCAL_ERROR;
 
465
        X509 *x;
 
466
        const char *name;
 
467
        char *ptr;
 
468
        int ntype = IS_DNS;
 
469
#ifdef LDAP_PF_INET6
 
470
        struct in6_addr addr;
 
471
#else
 
472
        struct in_addr addr;
 
473
#endif
 
474
 
 
475
        if( ldap_int_hostname &&
 
476
                ( !name_in || !strcasecmp( name_in, "localhost" ) ) )
 
477
        {
 
478
                name = ldap_int_hostname;
 
479
        } else {
 
480
                name = name_in;
 
481
        }
 
482
 
 
483
        x = tlso_get_cert(s);
 
484
        if (!x) {
 
485
                Debug( LDAP_DEBUG_ANY,
 
486
                        "TLS: unable to get peer certificate.\n",
 
487
                        0, 0, 0 );
 
488
                /* If this was a fatal condition, things would have
 
489
                 * aborted long before now.
 
490
                 */
 
491
                return LDAP_SUCCESS;
 
492
        }
 
493
 
 
494
#ifdef LDAP_PF_INET6
 
495
        if (name[0] == '[' && strchr(name, ']')) {
 
496
                char *n2 = ldap_strdup(name+1);
 
497
                *strchr(n2, ']') = 0;
 
498
                if (inet_pton(AF_INET6, n2, &addr))
 
499
                        ntype = IS_IP6;
 
500
                LDAP_FREE(n2);
 
501
        } else 
 
502
#endif
 
503
        if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) {
 
504
                if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4;
 
505
        }
 
506
        
 
507
        i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1);
 
508
        if (i >= 0) {
 
509
                X509_EXTENSION *ex;
 
510
                STACK_OF(GENERAL_NAME) *alt;
 
511
 
 
512
                ex = X509_get_ext(x, i);
 
513
                alt = X509V3_EXT_d2i(ex);
 
514
                if (alt) {
 
515
                        int n, len1 = 0, len2 = 0;
 
516
                        char *domain = NULL;
 
517
                        GENERAL_NAME *gn;
 
518
 
 
519
                        if (ntype == IS_DNS) {
 
520
                                len1 = strlen(name);
 
521
                                domain = strchr(name, '.');
 
522
                                if (domain) {
 
523
                                        len2 = len1 - (domain-name);
 
524
                                }
 
525
                        }
 
526
                        n = sk_GENERAL_NAME_num(alt);
 
527
                        for (i=0; i<n; i++) {
 
528
                                char *sn;
 
529
                                int sl;
 
530
                                gn = sk_GENERAL_NAME_value(alt, i);
 
531
                                if (gn->type == GEN_DNS) {
 
532
                                        if (ntype != IS_DNS) continue;
 
533
 
 
534
                                        sn = (char *) ASN1_STRING_data(gn->d.ia5);
 
535
                                        sl = ASN1_STRING_length(gn->d.ia5);
 
536
 
 
537
                                        /* ignore empty */
 
538
                                        if (sl == 0) continue;
 
539
 
 
540
                                        /* Is this an exact match? */
 
541
                                        if ((len1 == sl) && !strncasecmp(name, sn, len1)) {
 
542
                                                break;
 
543
                                        }
 
544
 
 
545
                                        /* Is this a wildcard match? */
 
546
                                        if (domain && (sn[0] == '*') && (sn[1] == '.') &&
 
547
                                                (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2))
 
548
                                        {
 
549
                                                break;
 
550
                                        }
 
551
 
 
552
                                } else if (gn->type == GEN_IPADD) {
 
553
                                        if (ntype == IS_DNS) continue;
 
554
 
 
555
                                        sn = (char *) ASN1_STRING_data(gn->d.ia5);
 
556
                                        sl = ASN1_STRING_length(gn->d.ia5);
 
557
 
 
558
#ifdef LDAP_PF_INET6
 
559
                                        if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) {
 
560
                                                continue;
 
561
                                        } else
 
562
#endif
 
563
                                        if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) {
 
564
                                                continue;
 
565
                                        }
 
566
                                        if (!memcmp(sn, &addr, sl)) {
 
567
                                                break;
 
568
                                        }
 
569
                                }
 
570
                        }
 
571
 
 
572
                        GENERAL_NAMES_free(alt);
 
573
                        if (i < n) {    /* Found a match */
 
574
                                ret = LDAP_SUCCESS;
 
575
                        }
 
576
                }
 
577
        }
 
578
 
 
579
        if (ret != LDAP_SUCCESS) {
 
580
                X509_NAME *xn;
 
581
                char buf[2048];
 
582
                buf[0] = '\0';
 
583
 
 
584
                xn = X509_get_subject_name(x);
 
585
                if( X509_NAME_get_text_by_NID( xn, NID_commonName,
 
586
                        buf, sizeof(buf)) == -1)
 
587
                {
 
588
                        Debug( LDAP_DEBUG_ANY,
 
589
                                "TLS: unable to get common name from peer certificate.\n",
 
590
                                0, 0, 0 );
 
591
                        ret = LDAP_CONNECT_ERROR;
 
592
                        if ( ld->ld_error ) {
 
593
                                LDAP_FREE( ld->ld_error );
 
594
                        }
 
595
                        ld->ld_error = LDAP_STRDUP(
 
596
                                _("TLS: unable to get CN from peer certificate"));
 
597
 
 
598
                } else if (strcasecmp(name, buf) == 0 ) {
 
599
                        ret = LDAP_SUCCESS;
 
600
 
 
601
                } else if (( buf[0] == '*' ) && ( buf[1] == '.' )) {
 
602
                        char *domain = strchr(name, '.');
 
603
                        if( domain ) {
 
604
                                size_t dlen = 0;
 
605
                                size_t sl;
 
606
 
 
607
                                sl = strlen(name);
 
608
                                dlen = sl - (domain-name);
 
609
                                sl = strlen(buf);
 
610
 
 
611
                                /* Is this a wildcard match? */
 
612
                                if ((dlen == sl-1) && !strncasecmp(domain, &buf[1], dlen)) {
 
613
                                        ret = LDAP_SUCCESS;
 
614
                                }
 
615
                        }
 
616
                }
 
617
 
 
618
                if( ret == LDAP_LOCAL_ERROR ) {
 
619
                        Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match "
 
620
                                "common name in certificate (%s).\n", 
 
621
                                name, buf, 0 );
 
622
                        ret = LDAP_CONNECT_ERROR;
 
623
                        if ( ld->ld_error ) {
 
624
                                LDAP_FREE( ld->ld_error );
 
625
                        }
 
626
                        ld->ld_error = LDAP_STRDUP(
 
627
                                _("TLS: hostname does not match CN in peer certificate"));
 
628
                }
 
629
        }
 
630
        X509_free(x);
 
631
        return ret;
 
632
}
 
633
 
 
634
static int
 
635
tlso_session_strength( tls_session *sess )
 
636
{
 
637
        tlso_session *s = (tlso_session *)sess;
 
638
        SSL_CIPHER *c;
 
639
 
 
640
        c = SSL_get_current_cipher(s);
 
641
        return SSL_CIPHER_get_bits(c, NULL);
 
642
}
 
643
 
 
644
/*
 
645
 * TLS support for LBER Sockbufs
 
646
 */
 
647
 
 
648
struct tls_data {
 
649
        tlso_session            *session;
 
650
        Sockbuf_IO_Desc         *sbiod;
 
651
};
 
652
 
 
653
static int
 
654
tlso_bio_create( BIO *b ) {
 
655
        b->init = 1;
 
656
        b->num = 0;
 
657
        b->ptr = NULL;
 
658
        b->flags = 0;
 
659
        return 1;
 
660
}
 
661
 
 
662
static int
 
663
tlso_bio_destroy( BIO *b )
 
664
{
 
665
        if ( b == NULL ) return 0;
 
666
 
 
667
        b->ptr = NULL;          /* sb_tls_remove() will free it */
 
668
        b->init = 0;
 
669
        b->flags = 0;
 
670
        return 1;
 
671
}
 
672
 
 
673
static int
 
674
tlso_bio_read( BIO *b, char *buf, int len )
 
675
{
 
676
        struct tls_data         *p;
 
677
        int                     ret;
 
678
                
 
679
        if ( buf == NULL || len <= 0 ) return 0;
 
680
 
 
681
        p = (struct tls_data *)b->ptr;
 
682
 
 
683
        if ( p == NULL || p->sbiod == NULL ) {
 
684
                return 0;
 
685
        }
 
686
 
 
687
        ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len );
 
688
 
 
689
        BIO_clear_retry_flags( b );
 
690
        if ( ret < 0 ) {
 
691
                int err = sock_errno();
 
692
                if ( err == EAGAIN || err == EWOULDBLOCK ) {
 
693
                        BIO_set_retry_read( b );
 
694
                }
 
695
        }
 
696
 
 
697
        return ret;
 
698
}
 
699
 
 
700
static int
 
701
tlso_bio_write( BIO *b, const char *buf, int len )
 
702
{
 
703
        struct tls_data         *p;
 
704
        int                     ret;
 
705
        
 
706
        if ( buf == NULL || len <= 0 ) return 0;
 
707
        
 
708
        p = (struct tls_data *)b->ptr;
 
709
 
 
710
        if ( p == NULL || p->sbiod == NULL ) {
 
711
                return 0;
 
712
        }
 
713
 
 
714
        ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len );
 
715
 
 
716
        BIO_clear_retry_flags( b );
 
717
        if ( ret < 0 ) {
 
718
                int err = sock_errno();
 
719
                if ( err == EAGAIN || err == EWOULDBLOCK ) {
 
720
                        BIO_set_retry_write( b );
 
721
                }
 
722
        }
 
723
 
 
724
        return ret;
 
725
}
 
726
 
 
727
static long
 
728
tlso_bio_ctrl( BIO *b, int cmd, long num, void *ptr )
 
729
{
 
730
        if ( cmd == BIO_CTRL_FLUSH ) {
 
731
                /* The OpenSSL library needs this */
 
732
                return 1;
 
733
        }
 
734
        return 0;
 
735
}
 
736
 
 
737
static int
 
738
tlso_bio_gets( BIO *b, char *buf, int len )
 
739
{
 
740
        return -1;
 
741
}
 
742
 
 
743
static int
 
744
tlso_bio_puts( BIO *b, const char *str )
 
745
{
 
746
        return tlso_bio_write( b, str, strlen( str ) );
 
747
}
 
748
        
 
749
static BIO_METHOD tlso_bio_method =
 
750
{
 
751
        ( 100 | 0x400 ),                /* it's a source/sink BIO */
 
752
        "sockbuf glue",
 
753
        tlso_bio_write,
 
754
        tlso_bio_read,
 
755
        tlso_bio_puts,
 
756
        tlso_bio_gets,
 
757
        tlso_bio_ctrl,
 
758
        tlso_bio_create,
 
759
        tlso_bio_destroy
 
760
};
 
761
 
 
762
static int
 
763
tlso_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg )
 
764
{
 
765
        struct tls_data         *p;
 
766
        BIO                     *bio;
 
767
 
 
768
        assert( sbiod != NULL );
 
769
 
 
770
        p = LBER_MALLOC( sizeof( *p ) );
 
771
        if ( p == NULL ) {
 
772
                return -1;
 
773
        }
 
774
        
 
775
        p->session = arg;
 
776
        p->sbiod = sbiod;
 
777
        bio = BIO_new( &tlso_bio_method );
 
778
        bio->ptr = (void *)p;
 
779
        SSL_set_bio( p->session, bio, bio );
 
780
        sbiod->sbiod_pvt = p;
 
781
        return 0;
 
782
}
 
783
 
 
784
static int
 
785
tlso_sb_remove( Sockbuf_IO_Desc *sbiod )
 
786
{
 
787
        struct tls_data         *p;
 
788
        
 
789
        assert( sbiod != NULL );
 
790
        assert( sbiod->sbiod_pvt != NULL );
 
791
 
 
792
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
793
        SSL_free( p->session );
 
794
        LBER_FREE( sbiod->sbiod_pvt );
 
795
        sbiod->sbiod_pvt = NULL;
 
796
        return 0;
 
797
}
 
798
 
 
799
static int
 
800
tlso_sb_close( Sockbuf_IO_Desc *sbiod )
 
801
{
 
802
        struct tls_data         *p;
 
803
        
 
804
        assert( sbiod != NULL );
 
805
        assert( sbiod->sbiod_pvt != NULL );
 
806
 
 
807
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
808
        SSL_shutdown( p->session );
 
809
        return 0;
 
810
}
 
811
 
 
812
static int
 
813
tlso_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
 
814
{
 
815
        struct tls_data         *p;
 
816
        
 
817
        assert( sbiod != NULL );
 
818
        assert( sbiod->sbiod_pvt != NULL );
 
819
 
 
820
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
821
        
 
822
        if ( opt == LBER_SB_OPT_GET_SSL ) {
 
823
                *((tlso_session **)arg) = p->session;
 
824
                return 1;
 
825
 
 
826
        } else if ( opt == LBER_SB_OPT_DATA_READY ) {
 
827
                if( SSL_pending( p->session ) > 0 ) {
 
828
                        return 1;
 
829
                }
 
830
        }
 
831
        
 
832
        return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg );
 
833
}
 
834
 
 
835
static ber_slen_t
 
836
tlso_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 
837
{
 
838
        struct tls_data         *p;
 
839
        ber_slen_t              ret;
 
840
        int                     err;
 
841
 
 
842
        assert( sbiod != NULL );
 
843
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
844
 
 
845
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
846
 
 
847
        ret = SSL_read( p->session, (char *)buf, len );
 
848
#ifdef HAVE_WINSOCK
 
849
        errno = WSAGetLastError();
 
850
#endif
 
851
        err = SSL_get_error( p->session, ret );
 
852
        if (err == SSL_ERROR_WANT_READ ) {
 
853
                sbiod->sbiod_sb->sb_trans_needs_read = 1;
 
854
                sock_errset(EWOULDBLOCK);
 
855
        }
 
856
        else
 
857
                sbiod->sbiod_sb->sb_trans_needs_read = 0;
 
858
        return ret;
 
859
}
 
860
 
 
861
static ber_slen_t
 
862
tlso_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 
863
{
 
864
        struct tls_data         *p;
 
865
        ber_slen_t              ret;
 
866
        int                     err;
 
867
 
 
868
        assert( sbiod != NULL );
 
869
        assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
 
870
 
 
871
        p = (struct tls_data *)sbiod->sbiod_pvt;
 
872
 
 
873
        ret = SSL_write( p->session, (char *)buf, len );
 
874
#ifdef HAVE_WINSOCK
 
875
        errno = WSAGetLastError();
 
876
#endif
 
877
        err = SSL_get_error( p->session, ret );
 
878
        if (err == SSL_ERROR_WANT_WRITE ) {
 
879
                sbiod->sbiod_sb->sb_trans_needs_write = 1;
 
880
                sock_errset(EWOULDBLOCK);
 
881
 
 
882
        } else {
 
883
                sbiod->sbiod_sb->sb_trans_needs_write = 0;
 
884
        }
 
885
        return ret;
 
886
}
 
887
 
 
888
static Sockbuf_IO tlso_sbio =
 
889
{
 
890
        tlso_sb_setup,          /* sbi_setup */
 
891
        tlso_sb_remove,         /* sbi_remove */
 
892
        tlso_sb_ctrl,           /* sbi_ctrl */
 
893
        tlso_sb_read,           /* sbi_read */
 
894
        tlso_sb_write,          /* sbi_write */
 
895
        tlso_sb_close           /* sbi_close */
 
896
};
 
897
 
 
898
/* Derived from openssl/apps/s_cb.c */
 
899
static void
 
900
tlso_info_cb( const SSL *ssl, int where, int ret )
 
901
{
 
902
        int w;
 
903
        char *op;
 
904
        char *state = (char *) SSL_state_string_long( (SSL *)ssl );
 
905
 
 
906
        w = where & ~SSL_ST_MASK;
 
907
        if ( w & SSL_ST_CONNECT ) {
 
908
                op = "SSL_connect";
 
909
        } else if ( w & SSL_ST_ACCEPT ) {
 
910
                op = "SSL_accept";
 
911
        } else {
 
912
                op = "undefined";
 
913
        }
 
914
 
 
915
#ifdef HAVE_EBCDIC
 
916
        if ( state ) {
 
917
                state = LDAP_STRDUP( state );
 
918
                __etoa( state );
 
919
        }
 
920
#endif
 
921
        if ( where & SSL_CB_LOOP ) {
 
922
                Debug( LDAP_DEBUG_TRACE,
 
923
                           "TLS trace: %s:%s\n",
 
924
                           op, state, 0 );
 
925
 
 
926
        } else if ( where & SSL_CB_ALERT ) {
 
927
                char *atype = (char *) SSL_alert_type_string_long( ret );
 
928
                char *adesc = (char *) SSL_alert_desc_string_long( ret );
 
929
                op = ( where & SSL_CB_READ ) ? "read" : "write";
 
930
#ifdef HAVE_EBCDIC
 
931
                if ( atype ) {
 
932
                        atype = LDAP_STRDUP( atype );
 
933
                        __etoa( atype );
 
934
                }
 
935
                if ( adesc ) {
 
936
                        adesc = LDAP_STRDUP( adesc );
 
937
                        __etoa( adesc );
 
938
                }
 
939
#endif
 
940
                Debug( LDAP_DEBUG_TRACE,
 
941
                           "TLS trace: SSL3 alert %s:%s:%s\n",
 
942
                           op, atype, adesc );
 
943
#ifdef HAVE_EBCDIC
 
944
                if ( atype ) LDAP_FREE( atype );
 
945
                if ( adesc ) LDAP_FREE( adesc );
 
946
#endif
 
947
        } else if ( where & SSL_CB_EXIT ) {
 
948
                if ( ret == 0 ) {
 
949
                        Debug( LDAP_DEBUG_TRACE,
 
950
                                   "TLS trace: %s:failed in %s\n",
 
951
                                   op, state, 0 );
 
952
                } else if ( ret < 0 ) {
 
953
                        Debug( LDAP_DEBUG_TRACE,
 
954
                                   "TLS trace: %s:error in %s\n",
 
955
                                   op, state, 0 );
 
956
                }
 
957
        }
 
958
#ifdef HAVE_EBCDIC
 
959
        if ( state ) LDAP_FREE( state );
 
960
#endif
 
961
}
 
962
 
 
963
static int
 
964
tlso_verify_cb( int ok, X509_STORE_CTX *ctx )
 
965
{
 
966
        X509 *cert;
 
967
        int errnum;
 
968
        int errdepth;
 
969
        X509_NAME *subject;
 
970
        X509_NAME *issuer;
 
971
        char *sname;
 
972
        char *iname;
 
973
        char *certerr = NULL;
 
974
 
 
975
        cert = X509_STORE_CTX_get_current_cert( ctx );
 
976
        errnum = X509_STORE_CTX_get_error( ctx );
 
977
        errdepth = X509_STORE_CTX_get_error_depth( ctx );
 
978
 
 
979
        /*
 
980
         * X509_get_*_name return pointers to the internal copies of
 
981
         * those things requested.  So do not free them.
 
982
         */
 
983
        subject = X509_get_subject_name( cert );
 
984
        issuer = X509_get_issuer_name( cert );
 
985
        /* X509_NAME_oneline, if passed a NULL buf, allocate memomry */
 
986
        sname = X509_NAME_oneline( subject, NULL, 0 );
 
987
        iname = X509_NAME_oneline( issuer, NULL, 0 );
 
988
        if ( !ok ) certerr = (char *)X509_verify_cert_error_string( errnum );
 
989
#ifdef HAVE_EBCDIC
 
990
        if ( sname ) __etoa( sname );
 
991
        if ( iname ) __etoa( iname );
 
992
        if ( certerr ) {
 
993
                certerr = LDAP_STRDUP( certerr );
 
994
                __etoa( certerr );
 
995
        }
 
996
#endif
 
997
        Debug( LDAP_DEBUG_TRACE,
 
998
                   "TLS certificate verification: depth: %d, err: %d, subject: %s,",
 
999
                   errdepth, errnum,
 
1000
                   sname ? sname : "-unknown-" );
 
1001
        Debug( LDAP_DEBUG_TRACE, " issuer: %s\n", iname ? iname : "-unknown-", 0, 0 );
 
1002
        if ( !ok ) {
 
1003
                Debug( LDAP_DEBUG_ANY,
 
1004
                        "TLS certificate verification: Error, %s\n",
 
1005
                        certerr, 0, 0 );
 
1006
        }
 
1007
        if ( sname )
 
1008
                CRYPTO_free ( sname );
 
1009
        if ( iname )
 
1010
                CRYPTO_free ( iname );
 
1011
#ifdef HAVE_EBCDIC
 
1012
        if ( certerr ) LDAP_FREE( certerr );
 
1013
#endif
 
1014
        return ok;
 
1015
}
 
1016
 
 
1017
static int
 
1018
tlso_verify_ok( int ok, X509_STORE_CTX *ctx )
 
1019
{
 
1020
        (void) tlso_verify_cb( ok, ctx );
 
1021
        return 1;
 
1022
}
 
1023
 
 
1024
/* Inspired by ERR_print_errors in OpenSSL */
 
1025
static void
 
1026
tlso_report_error( void )
 
1027
{
 
1028
        unsigned long l;
 
1029
        char buf[200];
 
1030
        const char *file;
 
1031
        int line;
 
1032
 
 
1033
        while ( ( l = ERR_get_error_line( &file, &line ) ) != 0 ) {
 
1034
                ERR_error_string_n( l, buf, sizeof( buf ) );
 
1035
#ifdef HAVE_EBCDIC
 
1036
                if ( file ) {
 
1037
                        file = LDAP_STRDUP( file );
 
1038
                        __etoa( (char *)file );
 
1039
                }
 
1040
                __etoa( buf );
 
1041
#endif
 
1042
                Debug( LDAP_DEBUG_ANY, "TLS: %s %s:%d\n",
 
1043
                        buf, file, line );
 
1044
#ifdef HAVE_EBCDIC
 
1045
                if ( file ) LDAP_FREE( (void *)file );
 
1046
#endif
 
1047
        }
 
1048
}
 
1049
 
 
1050
static RSA *
 
1051
tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length )
 
1052
{
 
1053
        RSA *tmp_rsa;
 
1054
 
 
1055
        /* FIXME:  Pregenerate the key on startup */
 
1056
        /* FIXME:  Who frees the key? */
 
1057
        tmp_rsa = RSA_generate_key( key_length, RSA_F4, NULL, NULL );
 
1058
 
 
1059
        if ( !tmp_rsa ) {
 
1060
                Debug( LDAP_DEBUG_ANY,
 
1061
                        "TLS: Failed to generate temporary %d-bit %s RSA key\n",
 
1062
                        key_length, is_export ? "export" : "domestic", 0 );
 
1063
                return NULL;
 
1064
        }
 
1065
        return tmp_rsa;
 
1066
}
 
1067
 
 
1068
static int
 
1069
tlso_seed_PRNG( const char *randfile )
 
1070
{
 
1071
#ifndef URANDOM_DEVICE
 
1072
        /* no /dev/urandom (or equiv) */
 
1073
        long total=0;
 
1074
        char buffer[MAXPATHLEN];
 
1075
 
 
1076
        if (randfile == NULL) {
 
1077
                /* The seed file is $RANDFILE if defined, otherwise $HOME/.rnd.
 
1078
                 * If $HOME is not set or buffer too small to hold the pathname,
 
1079
                 * an error occurs.     - From RAND_file_name() man page.
 
1080
                 * The fact is that when $HOME is NULL, .rnd is used.
 
1081
                 */
 
1082
                randfile = RAND_file_name( buffer, sizeof( buffer ) );
 
1083
 
 
1084
        } else if (RAND_egd(randfile) > 0) {
 
1085
                /* EGD socket */
 
1086
                return 0;
 
1087
        }
 
1088
 
 
1089
        if (randfile == NULL) {
 
1090
                Debug( LDAP_DEBUG_ANY,
 
1091
                        "TLS: Use configuration file or $RANDFILE to define seed PRNG\n",
 
1092
                        0, 0, 0);
 
1093
                return -1;
 
1094
        }
 
1095
 
 
1096
        total = RAND_load_file(randfile, -1);
 
1097
 
 
1098
        if (RAND_status() == 0) {
 
1099
                Debug( LDAP_DEBUG_ANY,
 
1100
                        "TLS: PRNG not been seeded with enough data\n",
 
1101
                        0, 0, 0);
 
1102
                return -1;
 
1103
        }
 
1104
 
 
1105
        /* assume if there was enough bits to seed that it's okay
 
1106
         * to write derived bits to the file
 
1107
         */
 
1108
        RAND_write_file(randfile);
 
1109
 
 
1110
#endif
 
1111
 
 
1112
        return 0;
 
1113
}
 
1114
 
 
1115
struct dhinfo {
 
1116
        int keylength;
 
1117
        const char *pem;
 
1118
        size_t size;
 
1119
};
 
1120
 
 
1121
 
 
1122
/* From the OpenSSL 0.9.7 distro */
 
1123
static const char tlso_dhpem512[] =
 
1124
"-----BEGIN DH PARAMETERS-----\n\
 
1125
MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn\n\
 
1126
a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC\n\
 
1127
-----END DH PARAMETERS-----\n";
 
1128
 
 
1129
static const char tlso_dhpem1024[] =
 
1130
"-----BEGIN DH PARAMETERS-----\n\
 
1131
MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq\n\
 
1132
/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx\n\
 
1133
/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC\n\
 
1134
-----END DH PARAMETERS-----\n";
 
1135
 
 
1136
static const char tlso_dhpem2048[] =
 
1137
"-----BEGIN DH PARAMETERS-----\n\
 
1138
MIIBCAKCAQEA7ZKJNYJFVcs7+6J2WmkEYb8h86tT0s0h2v94GRFS8Q7B4lW9aG9o\n\
 
1139
AFO5Imov5Jo0H2XMWTKKvbHbSe3fpxJmw/0hBHAY8H/W91hRGXKCeyKpNBgdL8sh\n\
 
1140
z22SrkO2qCnHJ6PLAMXy5fsKpFmFor2tRfCzrfnggTXu2YOzzK7q62bmqVdmufEo\n\
 
1141
pT8igNcLpvZxk5uBDvhakObMym9mX3rAEBoe8PwttggMYiiw7NuJKO4MqD1llGkW\n\
 
1142
aVM8U2ATsCun1IKHrRxynkE1/MJ86VHeYYX8GZt2YA8z+GuzylIOKcMH6JAWzMwA\n\
 
1143
Gbatw6QwizOhr9iMjZ0B26TE3X8LvW84wwIBAg==\n\
 
1144
-----END DH PARAMETERS-----\n";
 
1145
 
 
1146
static const char tlso_dhpem4096[] =
 
1147
"-----BEGIN DH PARAMETERS-----\n\
 
1148
MIICCAKCAgEA/urRnb6vkPYc/KEGXWnbCIOaKitq7ySIq9dTH7s+Ri59zs77zty7\n\
 
1149
vfVlSe6VFTBWgYjD2XKUFmtqq6CqXMhVX5ElUDoYDpAyTH85xqNFLzFC7nKrff/H\n\
 
1150
TFKNttp22cZE9V0IPpzedPfnQkE7aUdmF9JnDyv21Z/818O93u1B4r0szdnmEvEF\n\
 
1151
bKuIxEHX+bp0ZR7RqE1AeifXGJX3d6tsd2PMAObxwwsv55RGkn50vHO4QxtTARr1\n\
 
1152
rRUV5j3B3oPMgC7Offxx+98Xn45B1/G0Prp11anDsR1PGwtaCYipqsvMwQUSJtyE\n\
 
1153
EOQWk+yFkeMe4vWv367eEi0Sd/wnC+TSXBE3pYvpYerJ8n1MceI5GQTdarJ77OW9\n\
 
1154
bGTHmxRsLSCM1jpLdPja5jjb4siAa6EHc4qN9c/iFKS3PQPJEnX7pXKBRs5f7AF3\n\
 
1155
W3RIGt+G9IVNZfXaS7Z/iCpgzgvKCs0VeqN38QsJGtC1aIkwOeyjPNy2G6jJ4yqH\n\
 
1156
ovXYt/0mc00vCWeSNS1wren0pR2EiLxX0ypjjgsU1mk/Z3b/+zVf7fZSIB+nDLjb\n\
 
1157
NPtUlJCVGnAeBK1J1nG3TQicqowOXoM6ISkdaXj5GPJdXHab2+S7cqhKGv5qC7rR\n\
 
1158
jT6sx7RUr0CNTxzLI7muV2/a4tGmj0PSdXQdsZ7tw7gbXlaWT1+MM2MCAQI=\n\
 
1159
-----END DH PARAMETERS-----\n";
 
1160
 
 
1161
static const struct dhinfo tlso_dhpem[] = {
 
1162
        { 512, tlso_dhpem512, sizeof(tlso_dhpem512) },
 
1163
        { 1024, tlso_dhpem1024, sizeof(tlso_dhpem1024) },
 
1164
        { 2048, tlso_dhpem2048, sizeof(tlso_dhpem2048) },
 
1165
        { 4096, tlso_dhpem4096, sizeof(tlso_dhpem4096) },
 
1166
        { 0, NULL, 0 }
 
1167
};
 
1168
 
 
1169
static DH *
 
1170
tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length )
 
1171
{
 
1172
        struct dhplist *p = NULL;
 
1173
        BIO *b = NULL;
 
1174
        DH *dh = NULL;
 
1175
        int i;
 
1176
 
 
1177
        /* Do we have params of this length already? */
 
1178
#ifdef LDAP_R_COMPILE
 
1179
        ldap_pvt_thread_mutex_lock( &tlso_dh_mutex );
 
1180
#endif
 
1181
        for ( p = tlso_dhparams; p; p=p->next ) {
 
1182
                if ( p->keylength == key_length ) {
 
1183
#ifdef LDAP_R_COMPILE
 
1184
                        ldap_pvt_thread_mutex_unlock( &tlso_dh_mutex );
 
1185
#endif
 
1186
                        return p->param;
 
1187
                }
 
1188
        }
 
1189
 
 
1190
        /* No - check for hardcoded params */
 
1191
 
 
1192
        for (i=0; tlso_dhpem[i].keylength; i++) {
 
1193
                if ( tlso_dhpem[i].keylength == key_length ) {
 
1194
                        b = BIO_new_mem_buf( (char *)tlso_dhpem[i].pem, tlso_dhpem[i].size );
 
1195
                        break;
 
1196
                }
 
1197
        }
 
1198
 
 
1199
        if ( b ) {
 
1200
                dh = PEM_read_bio_DHparams( b, NULL, NULL, NULL );
 
1201
                BIO_free( b );
 
1202
        }
 
1203
 
 
1204
        /* Generating on the fly is expensive/slow... */
 
1205
        if ( !dh ) {
 
1206
                dh = DH_generate_parameters( key_length, DH_GENERATOR_2, NULL, NULL );
 
1207
        }
 
1208
        if ( dh ) {
 
1209
                p = LDAP_MALLOC( sizeof(struct dhplist) );
 
1210
                if ( p != NULL ) {
 
1211
                        p->keylength = key_length;
 
1212
                        p->param = dh;
 
1213
                        p->next = tlso_dhparams;
 
1214
                        tlso_dhparams = p;
 
1215
                }
 
1216
        }
 
1217
 
 
1218
#ifdef LDAP_R_COMPILE
 
1219
        ldap_pvt_thread_mutex_unlock( &tlso_dh_mutex );
 
1220
#endif
 
1221
        return dh;
 
1222
}
 
1223
 
 
1224
tls_impl ldap_int_tls_impl = {
 
1225
        "OpenSSL",
 
1226
 
 
1227
        tlso_init,
 
1228
        tlso_destroy,
 
1229
 
 
1230
        tlso_ctx_new,
 
1231
        tlso_ctx_ref,
 
1232
        tlso_ctx_free,
 
1233
        tlso_ctx_init,
 
1234
 
 
1235
        tlso_session_new,
 
1236
        tlso_session_connect,
 
1237
        tlso_session_accept,
 
1238
        tlso_session_upflags,
 
1239
        tlso_session_errmsg,
 
1240
        tlso_session_my_dn,
 
1241
        tlso_session_peer_dn,
 
1242
        tlso_session_chkhost,
 
1243
        tlso_session_strength,
 
1244
 
 
1245
        &tlso_sbio,
 
1246
 
 
1247
#ifdef LDAP_R_COMPILE
 
1248
        tlso_thr_init,
 
1249
#else
 
1250
        NULL,
 
1251
#endif
 
1252
 
 
1253
        0
 
1254
};
 
1255
 
 
1256
#endif /* HAVE_OPENSSL */