1/* tls_o.c - Handle tls/ssl using OpenSSL */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2008-2011 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 HAVE_OPENSSL_SSL_H 41#include <openssl/ssl.h> 42#include <openssl/x509v3.h> 43#include <openssl/err.h> 44#include <openssl/rand.h> 45#include <openssl/safestack.h> 46#elif defined( HAVE_SSL_H ) 47#include <ssl.h> 48#endif 49 50#ifdef __APPLE__ 51#include <Security/Security.h> 52#include <syslog.h> 53 54static int tlso_use_cert_from_keychain( struct ldapoptions *lo ); 55static X509 *tslo_copy_cert_to_x509(SecCertificateRef inRef); 56static OSStatus tslo_create_ca_chain(SSL_CTX* ctx, SecCertificateRef sslCertRef); 57static EVP_PKEY *tslo_copy_key_to_evpkey(SecKeyRef inKey); 58#endif 59 60typedef SSL_CTX tlso_ctx; 61typedef SSL tlso_session; 62 63static int tlso_opt_trace = 1; 64 65static void tlso_report_error( void ); 66 67static void tlso_info_cb( const SSL *ssl, int where, int ret ); 68static int tlso_verify_cb( int ok, X509_STORE_CTX *ctx ); 69static int tlso_pphrase_cb( char *buf, int bufsize, int verify ); 70static int tlso_verify_ok( int ok, X509_STORE_CTX *ctx ); 71static RSA * tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); 72EVP_PKEY *SSL_read_PrivateKey(FILE *fp, EVP_PKEY **key, int (*cb)()); 73static DH * tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length ); 74 75typedef struct dhplist { 76 struct dhplist *next; 77 int keylength; 78 DH *param; 79} dhplist; 80 81static dhplist *tlso_dhparams; 82 83static int tlso_seed_PRNG( const char *randfile ); 84 85#ifdef LDAP_R_COMPILE 86/* 87 * provide mutexes for the OpenSSL library. 88 */ 89static ldap_pvt_thread_mutex_t tlso_mutexes[CRYPTO_NUM_LOCKS]; 90static ldap_pvt_thread_mutex_t tlso_dh_mutex; 91 92static void tlso_locking_cb( int mode, int type, const char *file, int line ) 93{ 94 if ( mode & CRYPTO_LOCK ) { 95 ldap_pvt_thread_mutex_lock( &tlso_mutexes[type] ); 96 } else { 97 ldap_pvt_thread_mutex_unlock( &tlso_mutexes[type] ); 98 } 99} 100 101static unsigned long tlso_thread_self( void ) 102{ 103 /* FIXME: CRYPTO_set_id_callback only works when ldap_pvt_thread_t 104 * is an integral type that fits in an unsigned long 105 */ 106 107 /* force an error if the ldap_pvt_thread_t type is too large */ 108 enum { ok = sizeof( ldap_pvt_thread_t ) <= sizeof( unsigned long ) }; 109 typedef struct { int dummy: ok ? 1 : -1; } Check[ok ? 1 : -1]; 110 111 return (unsigned long) ldap_pvt_thread_self(); 112} 113 114static void tlso_thr_init( void ) 115{ 116 int i; 117 118 for( i=0; i< CRYPTO_NUM_LOCKS ; i++ ) { 119 ldap_pvt_thread_mutex_init( &tlso_mutexes[i] ); 120 } 121 ldap_pvt_thread_mutex_init( &tlso_dh_mutex ); 122 CRYPTO_set_locking_callback( tlso_locking_cb ); 123 CRYPTO_set_id_callback( tlso_thread_self ); 124} 125#endif /* LDAP_R_COMPILE */ 126 127/*Apple Specific code*/ 128 129EVP_PKEY *SSL_read_PrivateKey(FILE *fp, EVP_PKEY **key, int (*cb)()) 130{ 131 EVP_PKEY *rc; 132 BIO *bioS; 133 BIO *bioF; 134 135 /* 1. try PEM (= DER+Base64+headers) */ 136 rc = PEM_read_PrivateKey(fp, key, cb, NULL); 137 if (rc == NULL) { 138 /* 2. try DER+Base64 */ 139 fseek(fp, 0L, SEEK_SET); 140 if ((bioS = BIO_new(BIO_s_fd())) == NULL) 141 return NULL; 142 BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); 143 if ((bioF = BIO_new(BIO_f_base64())) == NULL) { 144 BIO_free(bioS); 145 return NULL; 146 } 147 bioS = BIO_push(bioF, bioS); 148 rc = d2i_PrivateKey_bio(bioS, NULL); 149 BIO_free_all(bioS); 150 if (rc == NULL) { 151 /* 3. try plain DER */ 152 fseek(fp, 0L, SEEK_SET); 153 if ((bioS = BIO_new(BIO_s_fd())) == NULL) 154 return NULL; 155 BIO_set_fd(bioS, fileno(fp), BIO_NOCLOSE); 156 rc = d2i_PrivateKey_bio(bioS, NULL); 157 BIO_free(bioS); 158 } 159 } 160 if (rc != NULL && key != NULL) { 161 if (*key != NULL) 162 EVP_PKEY_free(*key); 163 *key = rc; 164 } 165 return rc; 166} 167 168#define SYSTEM_KEYCHAIN_PATH "/Library/Keychains/System.keychain" 169int tlso_pphrase_cb( char *buf, int bufsize, int verify ) 170{ 171 int len = -1; 172 struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); 173 /* 174 * When a remembered passphrase is available, use it 175 */ 176 if (lo->ldo_tls_passphrase != NULL) { 177 178 SecKeychainRef keychainRef = NULL; 179 OSStatus status = SecKeychainOpen( SYSTEM_KEYCHAIN_PATH, &keychainRef ); 180 if ( status != errSecSuccess ) { 181 Debug( LDAP_DEBUG_ANY, "TLS: SecKeychainOpen failed for keychain %s: %d", 182 SYSTEM_KEYCHAIN_PATH, (int)status, 0 ); 183 syslog( LOG_ERR, "TLS: SecKeychainOpen failed for keychain %s: %d", 184 SYSTEM_KEYCHAIN_PATH, (int)status, 0 ); 185 cssmPerror( "SecKeychainOpen", status ); 186 return len; 187 } 188 char *keychain_identifier = LDAP_STRDUP(lo->ldo_tls_passphrase); 189 CFStringRef keychainCFName = CFStringCreateWithCString(NULL, keychain_identifier, kCFStringEncodingUTF8); 190 if(keychainCFName) 191 { 192 CFRange foundRange; 193 if(CFStringFindWithOptions(keychainCFName, CFSTR("."), CFRangeMake(0, CFStringGetLength(keychainCFName)), kCFCompareCaseInsensitive, &foundRange) == true) 194 { 195 CFStringRef itemName = CFStringCreateWithSubstring(NULL, keychainCFName, CFRangeMake(0, foundRange.location)); 196 CFStringRef accountName = CFStringCreateWithSubstring(NULL, keychainCFName, CFRangeMake(foundRange.location + 1, CFStringGetLength(keychainCFName) - foundRange.location)); 197 char *item_name, *account_name; 198 void *passphraseBytes = nil; 199 UInt32 passphraseLength = 0; 200 201 if(itemName) 202 { 203 int length = CFStringGetLength(itemName); 204 item_name = (char*)calloc(1, length + 1); 205 CFStringGetCString(itemName, item_name, length +1, kCFStringEncodingUTF8); 206 } 207 if(accountName) 208 { 209 int length = CFStringGetLength(accountName); 210 account_name = (char*)calloc(1, length + 1); 211 CFStringGetCString(accountName, account_name, length +1, kCFStringEncodingUTF8); 212 } 213 status = SecKeychainFindGenericPassword(keychainRef, 214 strlen(item_name),item_name , 215 strlen(account_name), account_name, 216 &passphraseLength, &passphraseBytes, nil); 217 if(status == 0) 218 { 219 if(passphraseLength < bufsize) 220 { 221 memcpy(buf, passphraseBytes, passphraseLength); 222 buf[passphraseLength] ='\0'; 223 len = strlen( buf ); 224 } 225 SecKeychainItemFreeContent(nil, passphraseBytes); 226 } 227 if(item_name) 228 free(item_name); 229 if(account_name) 230 free(account_name); 231 if(keychain_identifier) 232 LDAP_FREE(keychain_identifier); 233 } 234 } 235 } 236 /* 237 * Ok, we now have the pass phrase 238 * so return its length to OpenSSL... 239 */ 240 return len; 241} 242/* Apple Specific code end*/ 243 244static STACK_OF(X509_NAME) * 245tlso_ca_list( char * bundle, char * dir ) 246{ 247 STACK_OF(X509_NAME) *ca_list = NULL; 248 249 if ( bundle ) { 250 ca_list = SSL_load_client_CA_file( bundle ); 251 } 252#if defined(HAVE_DIRENT_H) || defined(dirent) 253 if ( dir ) { 254 int freeit = 0; 255 256 if ( !ca_list ) { 257 ca_list = sk_X509_NAME_new_null(); 258 freeit = 1; 259 } 260 if ( !SSL_add_dir_cert_subjects_to_stack( ca_list, dir ) && 261 freeit ) { 262 sk_X509_NAME_free( ca_list ); 263 ca_list = NULL; 264 } 265 } 266#endif 267 return ca_list; 268} 269 270/* 271 * Initialize TLS subsystem. Should be called only once. 272 */ 273static int 274tlso_init( void ) 275{ 276 struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); 277#ifdef HAVE_EBCDIC 278 { 279 char *file = LDAP_STRDUP( lo->ldo_tls_randfile ); 280 if ( file ) __atoe( file ); 281 (void) tlso_seed_PRNG( file ); 282 LDAP_FREE( file ); 283 } 284#else 285 (void) tlso_seed_PRNG( lo->ldo_tls_randfile ); 286#endif 287 288 SSL_load_error_strings(); 289 SSL_library_init(); 290 OpenSSL_add_all_algorithms(); 291 OpenSSL_add_all_digests(); 292 293 /* FIXME: mod_ssl does this */ 294 X509V3_add_standard_extensions(); 295 296 return 0; 297} 298 299/* 300 * Tear down the TLS subsystem. Should only be called once. 301 */ 302static void 303tlso_destroy( void ) 304{ 305 struct ldapoptions *lo = LDAP_INT_GLOBAL_OPT(); 306 307 EVP_cleanup(); 308 ERR_remove_state(0); 309 ERR_free_strings(); 310 311 if ( lo->ldo_tls_randfile ) { 312 LDAP_FREE( lo->ldo_tls_randfile ); 313 lo->ldo_tls_randfile = NULL; 314 } 315 if ( lo->ldo_tls_passphrase ) { 316 memset( lo->ldo_tls_passphrase, 0, strlen(lo->ldo_tls_passphrase)); 317 LDAP_FREE( lo->ldo_tls_passphrase ); 318 lo->ldo_tls_passphrase = NULL; 319 } 320 321} 322 323static tls_ctx * 324tlso_ctx_new( struct ldapoptions *lo ) 325{ 326 return (tls_ctx *) SSL_CTX_new( SSLv23_method() ); 327} 328 329static void 330tlso_ctx_ref( tls_ctx *ctx ) 331{ 332 tlso_ctx *c = (tlso_ctx *)ctx; 333 CRYPTO_add( &c->references, 1, CRYPTO_LOCK_SSL_CTX ); 334} 335 336static void 337tlso_ctx_free ( tls_ctx *ctx ) 338{ 339 tlso_ctx *c = (tlso_ctx *)ctx; 340 SSL_CTX_free( c ); 341} 342 343/* 344 * initialize a new TLS context 345 */ 346static int 347tlso_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) 348{ 349 tlso_ctx *ctx = (tlso_ctx *)lo->ldo_tls_ctx; 350 int i; 351 352 if ( is_server ) { 353 SSL_CTX_set_session_id_context( ctx, 354 (const unsigned char *) "OpenLDAP", sizeof("OpenLDAP")-1 ); 355 } 356 357 if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL3 ) 358 SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 ); 359 else if ( lo->ldo_tls_protocol_min > LDAP_OPT_X_TLS_PROTOCOL_SSL2 ) 360 SSL_CTX_set_options( ctx, SSL_OP_NO_SSLv2 ); 361 362 if ( lo->ldo_tls_ciphersuite && 363 !SSL_CTX_set_cipher_list( ctx, lt->lt_ciphersuite ) ) 364 { 365 Debug( LDAP_DEBUG_ANY, 366 "TLS: could not set cipher list %s.\n", 367 lo->ldo_tls_ciphersuite, 0, 0 ); 368 tlso_report_error(); 369 return -1; 370 } 371#ifdef __APPLE__ 372 /* ldo_tls_server_ident_ref_name should only be set for servers. */ 373 /* Since this is server-only, using syslog() instead of Debug(). */ 374 if(lo->ldo_tls_server_ident_ref_name != NULL) 375 { 376 OSStatus status = errSecSuccess; 377 SecIdentityRef sslIdentityRef = NULL; 378 X509 *x509_cert = NULL; 379 SecCertificateRef certRef = NULL; 380 SecKeyRef keyRef = NULL; 381 EVP_PKEY *pvtKey = NULL; 382 383 SecKeychainSetUserInteractionAllowed(false); 384 SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem); 385 386 sslIdentityRef = SecIdentityCopyPreferred(CFSTR("OPENDIRECTORY_SSL_IDENTITY"), 0, NULL); 387 if (sslIdentityRef) { 388 syslog(LOG_DEBUG, "TLS: found identity in keychain using identity preference."); 389 } 390 else { 391 syslog(LOG_DEBUG, 392 "TLS: failed to find identity in keychain using identity preference. Trying to find identity by name '%s'.", 393 lo->ldo_tls_server_ident_ref_name); 394 395 /* The identity name may be preceeded by "APPLE:". If so, strip that part. */ 396 char *sep = strchr(lo->ldo_tls_server_ident_ref_name, ':'); 397 char *cIdentityName = sep ? sep + 1 : lo->ldo_tls_server_ident_ref_name; 398 CFStringRef identityName = CFStringCreateWithCString(NULL, cIdentityName, kCFStringEncodingUTF8); 399 if (!identityName) { 400 syslog(LOG_NOTICE, 401 "TLS: failed to create CFString version of identity name %s.", 402 lo->ldo_tls_server_ident_ref_name); 403 } 404 else { 405 CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 406 CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); 407 CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); 408 CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); 409 CFDictionaryAddValue(query, kSecMatchSubjectContains, identityName); 410 411 /* Always want to specify the system keychain to protect ourselves from 412 * damage done to the keychain search list by Server.app & friends. 413 */ 414 SecKeychainRef keychainRef = NULL; 415 status = SecKeychainOpen(SYSTEM_KEYCHAIN_PATH, &keychainRef); 416 if (status == errSecSuccess) { 417 CFArrayRef searchList = CFArrayCreate(kCFAllocatorDefault, (const void**)&keychainRef, 1, &kCFTypeArrayCallBacks); 418 if (searchList) { 419 CFDictionaryAddValue(query, kSecMatchSearchList, searchList); 420 CFRelease(searchList); 421 } 422 } 423 424 CFTypeRef results = NULL; 425 status = SecItemCopyMatching(query, &results); 426 if(status != noErr) { 427 syslog(LOG_NOTICE, 428 "TLS: SecItemCopyMatching returned error %d when searching for identity %s.", 429 status, lo->ldo_tls_server_ident_ref_name); 430 } 431 else if (!results) { 432 syslog(LOG_NOTICE, 433 "TLS: failed to find identity using name %s: no results returned.", 434 lo->ldo_tls_server_ident_ref_name); 435 } 436 else { 437 if (CFGetTypeID(results) == SecIdentityGetTypeID()) { 438 sslIdentityRef = (SecIdentityRef)results; 439 CFRetain(sslIdentityRef); 440 } 441 else if (CFGetTypeID(results) == CFArrayGetTypeID()) { 442 if (CFArrayGetCount(results) != 0) { 443 sslIdentityRef = (SecIdentityRef)CFArrayGetValueAtIndex(results, 0); 444 CFRetain(sslIdentityRef); 445 } 446 else { 447 syslog(LOG_NOTICE, 448 "TLS: failed to find identity using name %s: empty array returned.", 449 lo->ldo_tls_server_ident_ref_name); 450 } 451 } 452 else { 453 syslog(LOG_DEBUG, "TLS: SecItemCopyMatching returned unhandled type."); 454 } 455 } 456 457 CFRelease(identityName); 458 CFRelease(query); 459 } 460 461 if (sslIdentityRef) { 462 syslog(LOG_DEBUG, 463 "TLS: found identity in keychain by name '%s'.", 464 lo->ldo_tls_server_ident_ref_name); 465 } 466 else { 467 syslog(LOG_NOTICE, "TLS: failed to find ssl identity in keychain."); 468 return LDAP_TLS_KEYCHAIN_CERT_NOTFOUND; 469 } 470 } 471 472 status = SecIdentityCopyCertificate(sslIdentityRef, &certRef); 473 if(status) 474 { 475 syslog(LOG_NOTICE, 476 "TLS: could not copy certificate from keychain identity '%s'.", 477 lo->ldo_tls_server_ident_ref_name); 478 goto done; 479 } 480 x509_cert = tslo_copy_cert_to_x509(certRef); 481 482 status = tslo_create_ca_chain(ctx, certRef); 483 if(status != noErr) { 484 syslog(LOG_NOTICE, 485 "TLS: failed to create ca chain for '%s'.", 486 lo->ldo_tls_server_ident_ref_name); 487 goto done; 488 } 489 490 if(!SSL_CTX_use_certificate(ctx, x509_cert)) 491 { 492 syslog(LOG_NOTICE, 493 "TLS: could not use certificate '%s'.", 494 lo->ldo_tls_server_ident_ref_name); 495 tlso_report_error(); 496 status = -1; 497 goto done; 498 } 499 status = SecIdentityCopyPrivateKey(sslIdentityRef, &keyRef); 500 if(status != noErr) 501 { 502 syslog(LOG_NOTICE, 503 "TLS: could not retrieve pvt key for '%s' from system keychain.", 504 lo->ldo_tls_server_ident_ref_name); 505 goto done; 506 } 507 pvtKey = tslo_copy_key_to_evpkey(keyRef); 508 if(!pvtKey) 509 { 510 syslog(LOG_NOTICE, 511 "TLS: could not convert keychain item '%s' to EVP_PKEY.", 512 lo->ldo_tls_server_ident_ref_name); 513 tlso_report_error(); 514 status = -1; 515 goto done; 516 } 517 if (!SSL_CTX_use_PrivateKey( lo->ldo_tls_ctx, pvtKey ) ) 518 { 519 syslog(LOG_NOTICE, 520 "TLS: could not use pvt key '%s'.", 521 lo->ldo_tls_server_ident_ref_name); 522 tlso_report_error(); 523 status = -1; 524 goto done; 525 } 526 if (!SSL_CTX_check_private_key(lo->ldo_tls_ctx) ) 527 { 528 syslog(LOG_NOTICE, 529 "TLS: pvt key doesn't match public key '%s'.", 530 lo->ldo_tls_server_ident_ref_name); 531 tlso_report_error(); 532 status = -1; 533 } 534done: 535 if(pvtKey) 536 EVP_PKEY_free(pvtKey); 537 if(keyRef) 538 CFRelease(keyRef); 539 if(x509_cert) 540 X509_free(x509_cert); 541 if(certRef) 542 CFRelease(certRef); 543 if(sslIdentityRef) 544 CFRelease(sslIdentityRef); 545 if(status != noErr) 546 return -1; 547 } 548 else 549 { 550#endif 551 if (lo->ldo_tls_cacertfile != NULL || lo->ldo_tls_cacertdir != NULL) { 552 if ( !SSL_CTX_load_verify_locations( ctx, 553 lt->lt_cacertfile, lt->lt_cacertdir ) || 554 !SSL_CTX_set_default_verify_paths( ctx ) ) 555 { 556 Debug( LDAP_DEBUG_ANY, "TLS: " 557 "could not load verify locations (file:`%s',dir:`%s').\n", 558 lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", 559 lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", 560 0 ); 561 tlso_report_error(); 562 return -1; 563 } 564 565 if ( is_server ) { 566 STACK_OF(X509_NAME) *calist; 567 /* List of CA names to send to a client */ 568 calist = tlso_ca_list( lt->lt_cacertfile, lt->lt_cacertdir ); 569 if ( !calist ) { 570 Debug( LDAP_DEBUG_ANY, "TLS: " 571 "could not load client CA list (file:`%s',dir:`%s').\n", 572 lo->ldo_tls_cacertfile ? lo->ldo_tls_cacertfile : "", 573 lo->ldo_tls_cacertdir ? lo->ldo_tls_cacertdir : "", 574 0 ); 575 tlso_report_error(); 576 return -1; 577 } 578 579 SSL_CTX_set_client_CA_list( ctx, calist ); 580 } 581 } 582 583 if ( lo->ldo_tls_certfile && 584 !SSL_CTX_use_certificate_file( ctx, 585 lt->lt_certfile, SSL_FILETYPE_PEM ) ) 586 { 587 Debug( LDAP_DEBUG_ANY, 588 "TLS: could not use certificate `%s'.\n", 589 lo->ldo_tls_certfile,0,0); 590 tlso_report_error(); 591 return -1; 592 } 593 594 /* Key validity is checked automatically if cert has already been set */ 595 if ( lo->ldo_tls_keyfile ) 596 { 597 FILE *fp; 598 EVP_PKEY *privatekey; 599 int success; 600 601 Debug( LDAP_DEBUG_ANY, 602 "TLS: attempting to read `%s'.\n", 603 lo->ldo_tls_keyfile,0,0); 604 /* 605 * Try to read the private key file with the help of 606 * the callback function which serves the pass 607 * phrases to OpenSSL 608 */ 609 if ((fp = fopen(lo->ldo_tls_keyfile, "r")) == NULL) { 610 success = 0; 611 } else { 612 privatekey = SSL_read_PrivateKey(fp, NULL, 613 tlso_pphrase_cb); 614 success = (privatekey != NULL ? 1 : 0); 615 fclose(fp); 616 } 617 618 if (!success || !SSL_CTX_use_PrivateKey( lo->ldo_tls_ctx, privatekey ) ) 619 { 620 Debug( LDAP_DEBUG_ANY, 621 "TLS: could not use key file `%s'.\n", 622 lo->ldo_tls_keyfile,0,0); 623 tlso_report_error(); 624 return -1; 625 } 626 } 627#ifdef __APPLE__ 628 } 629 630 /* Client path only. If the server's certificate was previously found 631 * in the keychain, try to use. 632 */ 633 if ( lo->ldo_tls_cert_ref ) { 634 if ( !tlso_use_cert_from_keychain( lo ) ) { 635 return -1; 636 } 637 } 638#endif 639 640 if ( lo->ldo_tls_dhfile ) { 641 DH *dh = NULL; 642 BIO *bio; 643 dhplist *p; 644 645 if (( bio=BIO_new_file( lt->lt_dhfile,"r" )) == NULL ) { 646 Debug( LDAP_DEBUG_ANY, 647 "TLS: could not use DH parameters file `%s'.\n", 648 lo->ldo_tls_dhfile,0,0); 649 tlso_report_error(); 650 return -1; 651 } 652 while (( dh=PEM_read_bio_DHparams( bio, NULL, NULL, NULL ))) { 653 p = LDAP_MALLOC( sizeof(dhplist) ); 654 if ( p != NULL ) { 655 p->keylength = DH_size( dh ) * 8; 656 p->param = dh; 657 p->next = tlso_dhparams; 658 tlso_dhparams = p; 659 } 660 } 661 BIO_free( bio ); 662 } 663 664 if ( tlso_opt_trace ) { 665 SSL_CTX_set_info_callback( ctx, tlso_info_cb ); 666 } 667 668 i = SSL_VERIFY_NONE; 669 if ( lo->ldo_tls_require_cert ) { 670 i = SSL_VERIFY_PEER; 671 if ( lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || 672 lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) { 673 i |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; 674 } 675 } 676 677 SSL_CTX_set_verify( ctx, i, 678 lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ? 679 tlso_verify_ok : tlso_verify_cb ); 680 SSL_CTX_set_tmp_rsa_callback( ctx, tlso_tmp_rsa_cb ); 681 if ( lo->ldo_tls_dhfile ) { 682 SSL_CTX_set_tmp_dh_callback( ctx, tlso_tmp_dh_cb ); 683 } 684#ifdef HAVE_OPENSSL_CRL 685 if ( lo->ldo_tls_crlcheck ) { 686 X509_STORE *x509_s = SSL_CTX_get_cert_store( ctx ); 687 if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_PEER ) { 688 X509_STORE_set_flags( x509_s, X509_V_FLAG_CRL_CHECK ); 689 } else if ( lo->ldo_tls_crlcheck == LDAP_OPT_X_TLS_CRL_ALL ) { 690 X509_STORE_set_flags( x509_s, 691 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); 692 } 693 } 694#endif 695 return 0; 696} 697 698static tls_session * 699tlso_session_new( tls_ctx *ctx, int is_server ) 700{ 701 tlso_ctx *c = (tlso_ctx *)ctx; 702 return (tls_session *)SSL_new( c ); 703} 704 705static int 706tlso_session_connect( LDAP *ld, tls_session *sess ) 707{ 708 tlso_session *s = (tlso_session *)sess; 709 710 /* Caller expects 0 = success, OpenSSL returns 1 = success */ 711 return SSL_connect( s ) - 1; 712} 713 714static int 715tlso_session_accept( tls_session *sess ) 716{ 717 tlso_session *s = (tlso_session *)sess; 718 719 /* Caller expects 0 = success, OpenSSL returns 1 = success */ 720 return SSL_accept( s ) - 1; 721} 722 723static int 724tlso_session_upflags( Sockbuf *sb, tls_session *sess, int rc ) 725{ 726 tlso_session *s = (tlso_session *)sess; 727 728 /* 1 was subtracted above, offset it back now */ 729 rc = SSL_get_error(s, rc+1); 730 if (rc == SSL_ERROR_WANT_READ) { 731 sb->sb_trans_needs_read = 1; 732 return 1; 733 734 } else if (rc == SSL_ERROR_WANT_WRITE) { 735 sb->sb_trans_needs_write = 1; 736 return 1; 737 738 } else if (rc == SSL_ERROR_WANT_CONNECT) { 739 return 1; 740 } 741 return 0; 742} 743 744static char * 745tlso_session_errmsg( tls_session *sess, int rc, char *buf, size_t len ) 746{ 747 char err[256] = ""; 748 const char *certerr=NULL; 749 tlso_session *s = (tlso_session *)sess; 750 751 rc = ERR_peek_error(); 752 if ( rc ) { 753 ERR_error_string_n( rc, err, sizeof(err) ); 754 if ( ( ERR_GET_LIB(rc) == ERR_LIB_SSL ) && 755 ( ERR_GET_REASON(rc) == SSL_R_CERTIFICATE_VERIFY_FAILED ) ) { 756 int certrc = SSL_get_verify_result(s); 757 certerr = (char *)X509_verify_cert_error_string(certrc); 758 } 759 snprintf(buf, len, "%s%s%s%s", err, certerr ? " (" :"", 760 certerr ? certerr : "", certerr ? ")" : "" ); 761 return buf; 762 } 763 return NULL; 764} 765 766static int 767tlso_session_my_dn( tls_session *sess, struct berval *der_dn ) 768{ 769 tlso_session *s = (tlso_session *)sess; 770 X509 *x; 771 X509_NAME *xn; 772 773 x = SSL_get_certificate( s ); 774 775 if (!x) return LDAP_INVALID_CREDENTIALS; 776 777 xn = X509_get_subject_name(x); 778 der_dn->bv_len = i2d_X509_NAME( xn, NULL ); 779 der_dn->bv_val = xn->bytes->data; 780 /* Don't X509_free, the session is still using it */ 781 return 0; 782} 783 784static X509 * 785tlso_get_cert( SSL *s ) 786{ 787 /* If peer cert was bad, treat as if no cert was given */ 788 if (SSL_get_verify_result(s)) { 789 return NULL; 790 } 791 return SSL_get_peer_certificate(s); 792} 793 794static int 795tlso_session_peer_dn( tls_session *sess, struct berval *der_dn ) 796{ 797 tlso_session *s = (tlso_session *)sess; 798 X509 *x = tlso_get_cert( s ); 799 X509_NAME *xn; 800 801 if ( !x ) 802 return LDAP_INVALID_CREDENTIALS; 803 804 xn = X509_get_subject_name(x); 805 der_dn->bv_len = i2d_X509_NAME( xn, NULL ); 806 der_dn->bv_val = xn->bytes->data; 807 X509_free(x); 808 return 0; 809} 810 811/* what kind of hostname were we given? */ 812#define IS_DNS 0 813#define IS_IP4 1 814#define IS_IP6 2 815 816static int 817tlso_session_chkhost( LDAP *ld, tls_session *sess, const char *name_in ) 818{ 819 tlso_session *s = (tlso_session *)sess; 820 int i, ret = LDAP_LOCAL_ERROR; 821 X509 *x; 822 const char *name; 823 char *ptr; 824 int ntype = IS_DNS, nlen; 825#ifdef LDAP_PF_INET6 826 struct in6_addr addr; 827#else 828 struct in_addr addr; 829#endif 830 831 if( ldap_int_hostname && 832 ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) 833 { 834 name = ldap_int_hostname; 835 } else { 836 name = name_in; 837 } 838 nlen = strlen(name); 839 840 x = tlso_get_cert(s); 841 if (!x) { 842 Debug( LDAP_DEBUG_ANY, 843 "TLS: unable to get peer certificate.\n", 844 0, 0, 0 ); 845 /* If this was a fatal condition, things would have 846 * aborted long before now. 847 */ 848 return LDAP_SUCCESS; 849 } 850 851#ifdef LDAP_PF_INET6 852 if (name[0] == '[' && strchr(name, ']')) { 853 char *n2 = ldap_strdup(name+1); 854 *strchr(n2, ']') = 0; 855 if (inet_pton(AF_INET6, n2, &addr)) 856 ntype = IS_IP6; 857 LDAP_FREE(n2); 858 } else 859#endif 860 if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { 861 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; 862 } 863 864 i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); 865 if (i >= 0) { 866 X509_EXTENSION *ex; 867 STACK_OF(GENERAL_NAME) *alt; 868 869 ex = X509_get_ext(x, i); 870 alt = X509V3_EXT_d2i(ex); 871 if (alt) { 872 int n, len2 = 0; 873 char *domain = NULL; 874 GENERAL_NAME *gn; 875 876 if (ntype == IS_DNS) { 877 domain = strchr(name, '.'); 878 if (domain) { 879 len2 = nlen - (domain-name); 880 } 881 } 882 n = sk_GENERAL_NAME_num(alt); 883 for (i=0; i<n; i++) { 884 char *sn; 885 int sl; 886 gn = sk_GENERAL_NAME_value(alt, i); 887 if (gn->type == GEN_DNS) { 888 if (ntype != IS_DNS) continue; 889 890 sn = (char *) ASN1_STRING_data(gn->d.ia5); 891 sl = ASN1_STRING_length(gn->d.ia5); 892 893 /* ignore empty */ 894 if (sl == 0) continue; 895 896 /* Is this an exact match? */ 897 if ((nlen == sl) && !strncasecmp(name, sn, nlen)) { 898 break; 899 } 900 901 /* Is this a wildcard match? */ 902 if (domain && (sn[0] == '*') && (sn[1] == '.') && 903 (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) 904 { 905 break; 906 } 907 908 } else if (gn->type == GEN_IPADD) { 909 if (ntype == IS_DNS) continue; 910 911 sn = (char *) ASN1_STRING_data(gn->d.ia5); 912 sl = ASN1_STRING_length(gn->d.ia5); 913 914#ifdef LDAP_PF_INET6 915 if (ntype == IS_IP6 && sl != sizeof(struct in6_addr)) { 916 continue; 917 } else 918#endif 919 if (ntype == IS_IP4 && sl != sizeof(struct in_addr)) { 920 continue; 921 } 922 if (!memcmp(sn, &addr, sl)) { 923 break; 924 } 925 } 926 } 927 928 GENERAL_NAMES_free(alt); 929 if (i < n) { /* Found a match */ 930 ret = LDAP_SUCCESS; 931 } 932 } 933 } 934 935 if (ret != LDAP_SUCCESS) { 936 X509_NAME *xn; 937 X509_NAME_ENTRY *ne; 938 ASN1_OBJECT *obj; 939 ASN1_STRING *cn = NULL; 940 int navas; 941 942 /* find the last CN */ 943 obj = OBJ_nid2obj( NID_commonName ); 944 if ( !obj ) goto no_cn; /* should never happen */ 945 946 xn = X509_get_subject_name(x); 947 navas = X509_NAME_entry_count( xn ); 948 for ( i=navas-1; i>=0; i-- ) { 949 ne = X509_NAME_get_entry( xn, i ); 950 if ( !OBJ_cmp( ne->object, obj )) { 951 cn = X509_NAME_ENTRY_get_data( ne ); 952 break; 953 } 954 } 955 956 if( !cn ) 957 { 958no_cn: 959 Debug( LDAP_DEBUG_ANY, 960 "TLS: unable to get common name from peer certificate.\n", 961 0, 0, 0 ); 962 ret = LDAP_CONNECT_ERROR; 963 if ( ld->ld_error ) { 964 LDAP_FREE( ld->ld_error ); 965 } 966 ld->ld_error = LDAP_STRDUP( 967 _("TLS: unable to get CN from peer certificate")); 968 969 } else if ( cn->length == nlen && 970 strncasecmp( name, (char *) cn->data, nlen ) == 0 ) { 971 ret = LDAP_SUCCESS; 972 973 } else if (( cn->data[0] == '*' ) && ( cn->data[1] == '.' )) { 974 char *domain = strchr(name, '.'); 975 if( domain ) { 976 int dlen; 977 978 dlen = nlen - (domain-name); 979 980 /* Is this a wildcard match? */ 981 if ((dlen == cn->length-1) && 982 !strncasecmp(domain, (char *) &cn->data[1], dlen)) { 983 ret = LDAP_SUCCESS; 984 } 985 } 986 } 987 988 if( ret == LDAP_LOCAL_ERROR ) { 989 Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " 990 "common name in certificate (%.*s).\n", 991 name, cn->length, cn->data ); 992 ret = LDAP_CONNECT_ERROR; 993 if ( ld->ld_error ) { 994 LDAP_FREE( ld->ld_error ); 995 } 996 ld->ld_error = LDAP_STRDUP( 997 _("TLS: hostname does not match CN in peer certificate")); 998 } 999 } 1000 X509_free(x); 1001 return ret; 1002} 1003 1004static int 1005tlso_session_strength( tls_session *sess ) 1006{ 1007 tlso_session *s = (tlso_session *)sess; 1008 SSL_CIPHER *c; 1009 1010 c = SSL_get_current_cipher(s); 1011 return SSL_CIPHER_get_bits(c, NULL); 1012} 1013 1014/* 1015 * TLS support for LBER Sockbufs 1016 */ 1017 1018struct tls_data { 1019 tlso_session *session; 1020 Sockbuf_IO_Desc *sbiod; 1021}; 1022 1023static int 1024tlso_bio_create( BIO *b ) { 1025 b->init = 1; 1026 b->num = 0; 1027 b->ptr = NULL; 1028 b->flags = 0; 1029 return 1; 1030} 1031 1032static int 1033tlso_bio_destroy( BIO *b ) 1034{ 1035 if ( b == NULL ) return 0; 1036 1037 b->ptr = NULL; /* sb_tls_remove() will free it */ 1038 b->init = 0; 1039 b->flags = 0; 1040 return 1; 1041} 1042 1043static int 1044tlso_bio_read( BIO *b, char *buf, int len ) 1045{ 1046 struct tls_data *p; 1047 int ret; 1048 1049 if ( buf == NULL || len <= 0 ) return 0; 1050 1051 p = (struct tls_data *)b->ptr; 1052 1053 if ( p == NULL || p->sbiod == NULL ) { 1054 return 0; 1055 } 1056 1057 ret = LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); 1058 1059 BIO_clear_retry_flags( b ); 1060 if ( ret < 0 ) { 1061 int err = sock_errno(); 1062 if ( err == EAGAIN || err == EWOULDBLOCK ) { 1063 BIO_set_retry_read( b ); 1064 } 1065 } 1066 1067 return ret; 1068} 1069 1070static int 1071tlso_bio_write( BIO *b, const char *buf, int len ) 1072{ 1073 struct tls_data *p; 1074 int ret; 1075 1076 if ( buf == NULL || len <= 0 ) return 0; 1077 1078 p = (struct tls_data *)b->ptr; 1079 1080 if ( p == NULL || p->sbiod == NULL ) { 1081 return 0; 1082 } 1083 1084 ret = LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); 1085 1086 BIO_clear_retry_flags( b ); 1087 if ( ret < 0 ) { 1088 int err = sock_errno(); 1089 if ( err == EAGAIN || err == EWOULDBLOCK ) { 1090 BIO_set_retry_write( b ); 1091 } 1092 } 1093 1094 return ret; 1095} 1096 1097static long 1098tlso_bio_ctrl( BIO *b, int cmd, long num, void *ptr ) 1099{ 1100 if ( cmd == BIO_CTRL_FLUSH ) { 1101 /* The OpenSSL library needs this */ 1102 return 1; 1103 } 1104 return 0; 1105} 1106 1107static int 1108tlso_bio_gets( BIO *b, char *buf, int len ) 1109{ 1110 return -1; 1111} 1112 1113static int 1114tlso_bio_puts( BIO *b, const char *str ) 1115{ 1116 return tlso_bio_write( b, str, strlen( str ) ); 1117} 1118 1119static BIO_METHOD tlso_bio_method = 1120{ 1121 ( 100 | 0x400 ), /* it's a source/sink BIO */ 1122 "sockbuf glue", 1123 tlso_bio_write, 1124 tlso_bio_read, 1125 tlso_bio_puts, 1126 tlso_bio_gets, 1127 tlso_bio_ctrl, 1128 tlso_bio_create, 1129 tlso_bio_destroy 1130}; 1131 1132static int 1133tlso_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 1134{ 1135 struct tls_data *p; 1136 BIO *bio; 1137 1138 assert( sbiod != NULL ); 1139 1140 p = LBER_MALLOC( sizeof( *p ) ); 1141 if ( p == NULL ) { 1142 return -1; 1143 } 1144 1145 p->session = arg; 1146 p->sbiod = sbiod; 1147 bio = BIO_new( &tlso_bio_method ); 1148 bio->ptr = (void *)p; 1149 SSL_set_bio( p->session, bio, bio ); 1150 sbiod->sbiod_pvt = p; 1151 return 0; 1152} 1153 1154static int 1155tlso_sb_remove( Sockbuf_IO_Desc *sbiod ) 1156{ 1157 struct tls_data *p; 1158 1159 assert( sbiod != NULL ); 1160 assert( sbiod->sbiod_pvt != NULL ); 1161 1162 p = (struct tls_data *)sbiod->sbiod_pvt; 1163 SSL_free( p->session ); 1164 LBER_FREE( sbiod->sbiod_pvt ); 1165 sbiod->sbiod_pvt = NULL; 1166 return 0; 1167} 1168 1169static int 1170tlso_sb_close( Sockbuf_IO_Desc *sbiod ) 1171{ 1172 struct tls_data *p; 1173 1174 assert( sbiod != NULL ); 1175 assert( sbiod->sbiod_pvt != NULL ); 1176 1177 p = (struct tls_data *)sbiod->sbiod_pvt; 1178 SSL_shutdown( p->session ); 1179 return 0; 1180} 1181 1182static int 1183tlso_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 1184{ 1185 struct tls_data *p; 1186 1187 assert( sbiod != NULL ); 1188 assert( sbiod->sbiod_pvt != NULL ); 1189 1190 p = (struct tls_data *)sbiod->sbiod_pvt; 1191 1192 if ( opt == LBER_SB_OPT_GET_SSL ) { 1193 *((tlso_session **)arg) = p->session; 1194 return 1; 1195 1196 } else if ( opt == LBER_SB_OPT_DATA_READY ) { 1197 if( SSL_pending( p->session ) > 0 ) { 1198 return 1; 1199 } 1200 } 1201 1202 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); 1203} 1204 1205static ber_slen_t 1206tlso_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 1207{ 1208 struct tls_data *p; 1209 ber_slen_t ret; 1210 int err; 1211 1212 assert( sbiod != NULL ); 1213 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 1214 1215 p = (struct tls_data *)sbiod->sbiod_pvt; 1216 1217 ret = SSL_read( p->session, (char *)buf, len ); 1218#ifdef HAVE_WINSOCK 1219 errno = WSAGetLastError(); 1220#endif 1221 err = SSL_get_error( p->session, ret ); 1222 if (err == SSL_ERROR_WANT_READ ) { 1223 sbiod->sbiod_sb->sb_trans_needs_read = 1; 1224 sock_errset(EWOULDBLOCK); 1225 } 1226 else 1227 sbiod->sbiod_sb->sb_trans_needs_read = 0; 1228 return ret; 1229} 1230 1231static ber_slen_t 1232tlso_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 1233{ 1234 struct tls_data *p; 1235 ber_slen_t ret; 1236 int err; 1237 1238 assert( sbiod != NULL ); 1239 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 1240 1241 p = (struct tls_data *)sbiod->sbiod_pvt; 1242 1243 ret = SSL_write( p->session, (char *)buf, len ); 1244#ifdef HAVE_WINSOCK 1245 errno = WSAGetLastError(); 1246#endif 1247 err = SSL_get_error( p->session, ret ); 1248 if (err == SSL_ERROR_WANT_WRITE ) { 1249 sbiod->sbiod_sb->sb_trans_needs_write = 1; 1250 sock_errset(EWOULDBLOCK); 1251 1252 } else { 1253 sbiod->sbiod_sb->sb_trans_needs_write = 0; 1254 } 1255 return ret; 1256} 1257 1258static Sockbuf_IO tlso_sbio = 1259{ 1260 tlso_sb_setup, /* sbi_setup */ 1261 tlso_sb_remove, /* sbi_remove */ 1262 tlso_sb_ctrl, /* sbi_ctrl */ 1263 tlso_sb_read, /* sbi_read */ 1264 tlso_sb_write, /* sbi_write */ 1265 tlso_sb_close /* sbi_close */ 1266}; 1267 1268/* Derived from openssl/apps/s_cb.c */ 1269static void 1270tlso_info_cb( const SSL *ssl, int where, int ret ) 1271{ 1272 int w; 1273 char *op; 1274 char *state = (char *) SSL_state_string_long( (SSL *)ssl ); 1275 1276 w = where & ~SSL_ST_MASK; 1277 if ( w & SSL_ST_CONNECT ) { 1278 op = "SSL_connect"; 1279 } else if ( w & SSL_ST_ACCEPT ) { 1280 op = "SSL_accept"; 1281 } else { 1282 op = "undefined"; 1283 } 1284 1285#ifdef HAVE_EBCDIC 1286 if ( state ) { 1287 state = LDAP_STRDUP( state ); 1288 __etoa( state ); 1289 } 1290#endif 1291 if ( where & SSL_CB_LOOP ) { 1292 Debug( LDAP_DEBUG_TRACE, 1293 "TLS trace: %s:%s\n", 1294 op, state, 0 ); 1295 1296 } else if ( where & SSL_CB_ALERT ) { 1297 char *atype = (char *) SSL_alert_type_string_long( ret ); 1298 char *adesc = (char *) SSL_alert_desc_string_long( ret ); 1299 op = ( where & SSL_CB_READ ) ? "read" : "write"; 1300#ifdef HAVE_EBCDIC 1301 if ( atype ) { 1302 atype = LDAP_STRDUP( atype ); 1303 __etoa( atype ); 1304 } 1305 if ( adesc ) { 1306 adesc = LDAP_STRDUP( adesc ); 1307 __etoa( adesc ); 1308 } 1309#endif 1310 Debug( LDAP_DEBUG_TRACE, 1311 "TLS trace: SSL3 alert %s:%s:%s\n", 1312 op, atype, adesc ); 1313#ifdef HAVE_EBCDIC 1314 if ( atype ) LDAP_FREE( atype ); 1315 if ( adesc ) LDAP_FREE( adesc ); 1316#endif 1317 } else if ( where & SSL_CB_EXIT ) { 1318 if ( ret == 0 ) { 1319 Debug( LDAP_DEBUG_TRACE, 1320 "TLS trace: %s:failed in %s\n", 1321 op, state, 0 ); 1322 } else if ( ret < 0 ) { 1323 Debug( LDAP_DEBUG_TRACE, 1324 "TLS trace: %s:error in %s\n", 1325 op, state, 0 ); 1326 } 1327 } 1328#ifdef HAVE_EBCDIC 1329 if ( state ) LDAP_FREE( state ); 1330#endif 1331} 1332 1333static int 1334tlso_verify_cb( int ok, X509_STORE_CTX *ctx ) 1335{ 1336 X509 *cert; 1337 int errnum; 1338 int errdepth; 1339 X509_NAME *subject; 1340 X509_NAME *issuer; 1341 char *sname; 1342 char *iname; 1343 char *certerr = NULL; 1344 1345 cert = X509_STORE_CTX_get_current_cert( ctx ); 1346 errnum = X509_STORE_CTX_get_error( ctx ); 1347 errdepth = X509_STORE_CTX_get_error_depth( ctx ); 1348 1349 /* 1350 * X509_get_*_name return pointers to the internal copies of 1351 * those things requested. So do not free them. 1352 */ 1353 subject = X509_get_subject_name( cert ); 1354 issuer = X509_get_issuer_name( cert ); 1355 /* X509_NAME_oneline, if passed a NULL buf, allocate memomry */ 1356 sname = X509_NAME_oneline( subject, NULL, 0 ); 1357 iname = X509_NAME_oneline( issuer, NULL, 0 ); 1358 if ( !ok ) certerr = (char *)X509_verify_cert_error_string( errnum ); 1359#ifdef HAVE_EBCDIC 1360 if ( sname ) __etoa( sname ); 1361 if ( iname ) __etoa( iname ); 1362 if ( certerr ) { 1363 certerr = LDAP_STRDUP( certerr ); 1364 __etoa( certerr ); 1365 } 1366#endif 1367 Debug( LDAP_DEBUG_TRACE, 1368 "TLS certificate verification: depth: %d, err: %d, subject: %s,", 1369 errdepth, errnum, 1370 sname ? sname : "-unknown-" ); 1371 Debug( LDAP_DEBUG_TRACE, " issuer: %s\n", iname ? iname : "-unknown-", 0, 0 ); 1372 if ( !ok ) { 1373 Debug( LDAP_DEBUG_ANY, 1374 "TLS certificate verification: Error, %s\n", 1375 certerr, 0, 0 ); 1376 } 1377 if ( sname ) 1378 CRYPTO_free ( sname ); 1379 if ( iname ) 1380 CRYPTO_free ( iname ); 1381#ifdef HAVE_EBCDIC 1382 if ( certerr ) LDAP_FREE( certerr ); 1383#endif 1384 return ok; 1385} 1386 1387static int 1388tlso_verify_ok( int ok, X509_STORE_CTX *ctx ) 1389{ 1390 (void) tlso_verify_cb( ok, ctx ); 1391 return 1; 1392} 1393 1394/* Inspired by ERR_print_errors in OpenSSL */ 1395static void 1396tlso_report_error( void ) 1397{ 1398 unsigned long l; 1399 char buf[200]; 1400 const char *file; 1401 int line; 1402 1403 while ( ( l = ERR_get_error_line( &file, &line ) ) != 0 ) { 1404 ERR_error_string_n( l, buf, sizeof( buf ) ); 1405#ifdef HAVE_EBCDIC 1406 if ( file ) { 1407 file = LDAP_STRDUP( file ); 1408 __etoa( (char *)file ); 1409 } 1410 __etoa( buf ); 1411#endif 1412 Debug( LDAP_DEBUG_ANY, "TLS: %s %s:%d\n", 1413 buf, file, line ); 1414#ifdef HAVE_EBCDIC 1415 if ( file ) LDAP_FREE( (void *)file ); 1416#endif 1417 } 1418} 1419 1420static RSA * 1421tlso_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ) 1422{ 1423 RSA *tmp_rsa; 1424 /* FIXME: Pregenerate the key on startup */ 1425 /* FIXME: Who frees the key? */ 1426#if OPENSSL_VERSION_NUMBER >= 0x00908000 1427 BIGNUM *bn = BN_new(); 1428 tmp_rsa = NULL; 1429 if ( bn ) { 1430 if ( BN_set_word( bn, RSA_F4 )) { 1431 tmp_rsa = RSA_new(); 1432 if ( tmp_rsa && !RSA_generate_key_ex( tmp_rsa, key_length, bn, NULL )) { 1433 RSA_free( tmp_rsa ); 1434 tmp_rsa = NULL; 1435 } 1436 } 1437 BN_free( bn ); 1438 } 1439#else 1440 tmp_rsa = RSA_generate_key( key_length, RSA_F4, NULL, NULL ); 1441#endif 1442 1443 if ( !tmp_rsa ) { 1444 Debug( LDAP_DEBUG_ANY, 1445 "TLS: Failed to generate temporary %d-bit %s RSA key\n", 1446 key_length, is_export ? "export" : "domestic", 0 ); 1447 } 1448 return tmp_rsa; 1449} 1450 1451static int 1452tlso_seed_PRNG( const char *randfile ) 1453{ 1454#ifndef URANDOM_DEVICE 1455 /* no /dev/urandom (or equiv) */ 1456 long total=0; 1457 char buffer[MAXPATHLEN]; 1458 1459 if (randfile == NULL) { 1460 /* The seed file is $RANDFILE if defined, otherwise $HOME/.rnd. 1461 * If $HOME is not set or buffer too small to hold the pathname, 1462 * an error occurs. - From RAND_file_name() man page. 1463 * The fact is that when $HOME is NULL, .rnd is used. 1464 */ 1465 randfile = RAND_file_name( buffer, sizeof( buffer ) ); 1466 1467 } else if (RAND_egd(randfile) > 0) { 1468 /* EGD socket */ 1469 return 0; 1470 } 1471 1472 if (randfile == NULL) { 1473 Debug( LDAP_DEBUG_ANY, 1474 "TLS: Use configuration file or $RANDFILE to define seed PRNG\n", 1475 0, 0, 0); 1476 return -1; 1477 } 1478 1479 total = RAND_load_file(randfile, -1); 1480 1481 if (RAND_status() == 0) { 1482 Debug( LDAP_DEBUG_ANY, 1483 "TLS: PRNG not been seeded with enough data\n", 1484 0, 0, 0); 1485 return -1; 1486 } 1487 1488 /* assume if there was enough bits to seed that it's okay 1489 * to write derived bits to the file 1490 */ 1491 RAND_write_file(randfile); 1492 1493#endif 1494 1495 return 0; 1496} 1497 1498struct dhinfo { 1499 int keylength; 1500 const char *pem; 1501 size_t size; 1502}; 1503 1504 1505/* From the OpenSSL 0.9.7 distro */ 1506static const char tlso_dhpem512[] = 1507"-----BEGIN DH PARAMETERS-----\n\ 1508MEYCQQDaWDwW2YUiidDkr3VvTMqS3UvlM7gE+w/tlO+cikQD7VdGUNNpmdsp13Yn\n\ 1509a6LT1BLiGPTdHghM9tgAPnxHdOgzAgEC\n\ 1510-----END DH PARAMETERS-----\n"; 1511 1512static const char tlso_dhpem1024[] = 1513"-----BEGIN DH PARAMETERS-----\n\ 1514MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq\n\ 1515/Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx\n\ 1516/mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC\n\ 1517-----END DH PARAMETERS-----\n"; 1518 1519static const char tlso_dhpem2048[] = 1520"-----BEGIN DH PARAMETERS-----\n\ 1521MIIBCAKCAQEA7ZKJNYJFVcs7+6J2WmkEYb8h86tT0s0h2v94GRFS8Q7B4lW9aG9o\n\ 1522AFO5Imov5Jo0H2XMWTKKvbHbSe3fpxJmw/0hBHAY8H/W91hRGXKCeyKpNBgdL8sh\n\ 1523z22SrkO2qCnHJ6PLAMXy5fsKpFmFor2tRfCzrfnggTXu2YOzzK7q62bmqVdmufEo\n\ 1524pT8igNcLpvZxk5uBDvhakObMym9mX3rAEBoe8PwttggMYiiw7NuJKO4MqD1llGkW\n\ 1525aVM8U2ATsCun1IKHrRxynkE1/MJ86VHeYYX8GZt2YA8z+GuzylIOKcMH6JAWzMwA\n\ 1526Gbatw6QwizOhr9iMjZ0B26TE3X8LvW84wwIBAg==\n\ 1527-----END DH PARAMETERS-----\n"; 1528 1529static const char tlso_dhpem4096[] = 1530"-----BEGIN DH PARAMETERS-----\n\ 1531MIICCAKCAgEA/urRnb6vkPYc/KEGXWnbCIOaKitq7ySIq9dTH7s+Ri59zs77zty7\n\ 1532vfVlSe6VFTBWgYjD2XKUFmtqq6CqXMhVX5ElUDoYDpAyTH85xqNFLzFC7nKrff/H\n\ 1533TFKNttp22cZE9V0IPpzedPfnQkE7aUdmF9JnDyv21Z/818O93u1B4r0szdnmEvEF\n\ 1534bKuIxEHX+bp0ZR7RqE1AeifXGJX3d6tsd2PMAObxwwsv55RGkn50vHO4QxtTARr1\n\ 1535rRUV5j3B3oPMgC7Offxx+98Xn45B1/G0Prp11anDsR1PGwtaCYipqsvMwQUSJtyE\n\ 1536EOQWk+yFkeMe4vWv367eEi0Sd/wnC+TSXBE3pYvpYerJ8n1MceI5GQTdarJ77OW9\n\ 1537bGTHmxRsLSCM1jpLdPja5jjb4siAa6EHc4qN9c/iFKS3PQPJEnX7pXKBRs5f7AF3\n\ 1538W3RIGt+G9IVNZfXaS7Z/iCpgzgvKCs0VeqN38QsJGtC1aIkwOeyjPNy2G6jJ4yqH\n\ 1539ovXYt/0mc00vCWeSNS1wren0pR2EiLxX0ypjjgsU1mk/Z3b/+zVf7fZSIB+nDLjb\n\ 1540NPtUlJCVGnAeBK1J1nG3TQicqowOXoM6ISkdaXj5GPJdXHab2+S7cqhKGv5qC7rR\n\ 1541jT6sx7RUr0CNTxzLI7muV2/a4tGmj0PSdXQdsZ7tw7gbXlaWT1+MM2MCAQI=\n\ 1542-----END DH PARAMETERS-----\n"; 1543 1544static const struct dhinfo tlso_dhpem[] = { 1545 { 512, tlso_dhpem512, sizeof(tlso_dhpem512) }, 1546 { 1024, tlso_dhpem1024, sizeof(tlso_dhpem1024) }, 1547 { 2048, tlso_dhpem2048, sizeof(tlso_dhpem2048) }, 1548 { 4096, tlso_dhpem4096, sizeof(tlso_dhpem4096) }, 1549 { 0, NULL, 0 } 1550}; 1551 1552static DH * 1553tlso_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) 1554{ 1555 struct dhplist *p = NULL; 1556 BIO *b = NULL; 1557 DH *dh = NULL; 1558 int i; 1559 1560 /* Do we have params of this length already? */ 1561 LDAP_MUTEX_LOCK( &tlso_dh_mutex ); 1562 for ( p = tlso_dhparams; p; p=p->next ) { 1563 if ( p->keylength == key_length ) { 1564 LDAP_MUTEX_UNLOCK( &tlso_dh_mutex ); 1565 return p->param; 1566 } 1567 } 1568 1569 /* No - check for hardcoded params */ 1570 1571 for (i=0; tlso_dhpem[i].keylength; i++) { 1572 if ( tlso_dhpem[i].keylength == key_length ) { 1573 b = BIO_new_mem_buf( (char *)tlso_dhpem[i].pem, tlso_dhpem[i].size ); 1574 break; 1575 } 1576 } 1577 1578 if ( b ) { 1579 dh = PEM_read_bio_DHparams( b, NULL, NULL, NULL ); 1580 BIO_free( b ); 1581 } 1582 1583 /* Generating on the fly is expensive/slow... */ 1584 if ( !dh ) { 1585 dh = DH_generate_parameters( key_length, DH_GENERATOR_2, NULL, NULL ); 1586 } 1587 if ( dh ) { 1588 p = LDAP_MALLOC( sizeof(struct dhplist) ); 1589 if ( p != NULL ) { 1590 p->keylength = key_length; 1591 p->param = dh; 1592 p->next = tlso_dhparams; 1593 tlso_dhparams = p; 1594 } 1595 } 1596 1597 LDAP_MUTEX_UNLOCK( &tlso_dh_mutex ); 1598 return dh; 1599} 1600 1601tls_impl ldap_int_tls_impl = { 1602 "OpenSSL", 1603 1604 tlso_init, 1605 tlso_destroy, 1606 1607 tlso_ctx_new, 1608 tlso_ctx_ref, 1609 tlso_ctx_free, 1610 tlso_ctx_init, 1611 1612 tlso_session_new, 1613 tlso_session_connect, 1614 tlso_session_accept, 1615 tlso_session_upflags, 1616 tlso_session_errmsg, 1617 tlso_session_my_dn, 1618 tlso_session_peer_dn, 1619 tlso_session_chkhost, 1620 tlso_session_strength, 1621 1622 &tlso_sbio, 1623 1624#ifdef LDAP_R_COMPILE 1625 tlso_thr_init, 1626#else 1627 NULL, 1628#endif 1629 1630 0 1631}; 1632 1633#ifdef __APPLE__ 1634static int 1635tlso_use_cert_from_keychain( struct ldapoptions *lo ) 1636{ 1637 if ( lo == NULL || lo->ldo_tls_cert_ref == NULL ) { 1638 return 0; 1639 } 1640 1641 CFDataRef certificateCFData = NULL; 1642 OSStatus status = SecKeychainItemExport( lo->ldo_tls_cert_ref, 1643 kSecFormatX509Cert, 1644 0, 1645 NULL, 1646 &certificateCFData ); 1647 if ( status != noErr ) { 1648 Debug( LDAP_DEBUG_ANY, 1649 "%s: SecKeychainItemExport(certificateRef) failed: %d\n", 1650 __PRETTY_FUNCTION__, (int)status, 0 ); 1651 syslog( LOG_ERR, "%s: SecKeychainItemExport(certificateRef): %d", 1652 __PRETTY_FUNCTION__, (int)status, 0 ); 1653 cssmPerror( "SecKeychainItemExport(certificateRef)", status ); 1654 return 0; 1655 } 1656 1657 /* Put the data into a C array so openssl can use it. */ 1658 int rc = 0; 1659 unsigned char *certificateData = NULL; 1660 int certificateDataLen = CFDataGetLength( certificateCFData ); 1661 if ( certificateDataLen ) { 1662 certificateData = LDAP_MALLOC( certificateDataLen * sizeof(*certificateData) ); 1663 if ( certificateData ) { 1664 CFDataGetBytes( certificateCFData, 1665 CFRangeMake(0, certificateDataLen), 1666 certificateData ); 1667 1668 rc = SSL_CTX_use_certificate_ASN1( lo->ldo_tls_ctx, 1669 certificateDataLen, 1670 certificateData ); 1671 if ( !rc ) { 1672 Debug( LDAP_DEBUG_ANY, 1673 "TLS: could not use keychain certificate data in SSL_CTX_use_certificate_ASN1\n", 1674 0,0,0); 1675 tlso_report_error(); 1676 } 1677 else { 1678 Debug( LDAP_DEBUG_ANY, 1679 "TLS: using keychain certificate data\n", 1680 0, 0, 0); 1681 } 1682 LDAP_FREE( certificateData ); 1683 } 1684 } 1685 CFRelease( certificateCFData ); 1686 1687 return rc; 1688} 1689 1690static X509 *tslo_copy_cert_to_x509(SecCertificateRef inRef) 1691{ 1692 X509 *result = NULL; 1693 const unsigned char *buf = NULL; 1694 CFDataRef DERCertData = SecCertificateCopyData(inRef); 1695 CFIndex len = 0; 1696 if(DERCertData == NULL) return NULL; 1697 1698 len = CFDataGetLength(DERCertData); 1699 buf = (const unsigned char *)CFDataGetBytePtr(DERCertData); 1700 1701 result = d2i_X509(NULL, &buf, len); 1702 CFRelease(DERCertData); 1703 return result; 1704} 1705 1706static EVP_PKEY *tslo_copy_key_to_evpkey(SecKeyRef inKey) 1707{ 1708 OSStatus ortn = 0; 1709 EVP_PKEY *result = NULL; 1710 SecItemImportExportKeyParameters params; 1711 CFDataRef intermediateData = NULL; 1712 BIO *intermediateBIO = NULL; 1713 char* cExportPass = ";aweCrugf99;uvPvh8229fliaYnx``1"; 1714 CFStringRef cfExportPass = NULL; 1715 1716 cfExportPass = CFStringCreateWithCString(NULL, cExportPass, kCFStringEncodingUTF8); 1717 if (!cfExportPass) { 1718 syslog(LOG_DEBUG, "TLS: Unable to create CFString private key passphrase."); 1719 return NULL; 1720 } 1721 1722 memset(¶ms, 0, sizeof(params)); 1723 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 1724 params.flags = 0; 1725 params.passphrase = cfExportPass; 1726 1727 ortn = SecItemExport(inKey, kSecFormatWrappedPKCS8, 0, ¶ms, (CFDataRef*)&intermediateData); 1728 if(ortn != 0) { 1729 syslog( LOG_DEBUG, "TLS: Unable to export private key."); 1730 CFRelease(cfExportPass); 1731 return NULL; 1732 } 1733 1734 intermediateBIO = BIO_new_mem_buf((void *)CFDataGetBytePtr(intermediateData), CFDataGetLength(intermediateData)); 1735 if(intermediateBIO == NULL) 1736 { 1737 syslog( LOG_DEBUG, "TLS: Unable to create BIO buffer for private key data."); 1738 CFRelease(cfExportPass); 1739 CFRelease(intermediateData); 1740 return NULL; 1741 } 1742 1743 result = d2i_PKCS8PrivateKey_bio(intermediateBIO, NULL, NULL, cExportPass); 1744 if(result == NULL) 1745 { 1746 char errbuf[512]; 1747 ERR_error_string(ERR_get_error(), errbuf); 1748 syslog( LOG_DEBUG, "TLS: Unable to use passphrase for private key: %s.", errbuf); 1749 } 1750 1751 BIO_free_all(intermediateBIO); 1752 CFRelease(intermediateData); 1753 CFRelease(cfExportPass); 1754 1755 return result; 1756} 1757 1758static OSStatus tslo_create_ca_chain(SSL_CTX* ctx, SecCertificateRef sslCertRef) 1759{ 1760 OSStatus status = noErr; 1761 CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 1762 SecPolicyRef policy = SecPolicyCreateBasicX509(); 1763 SecTrustRef trustRef = NULL; 1764 SecTrustResultType trustResult = NULL; 1765 X509* x509_cert = NULL; 1766 SSL_CTX_set_mode(ctx, SSL_MODE_NO_AUTO_CHAIN); 1767 1768 do { 1769 if (sslCertRef) { 1770 CFArrayAppendValue(certChain, sslCertRef); 1771 status = SecTrustCreateWithCertificates(certChain, policy, &trustRef); 1772 if (status == noErr) { 1773 status = SecTrustEvaluate(trustRef, &trustResult); 1774 if (status == noErr) { 1775 CFIndex count = SecTrustGetCertificateCount(trustRef); 1776 if (count) { 1777 int i; 1778 for (i = 0; i < count; i++) { 1779 SecCertificateRef certInChainRef = SecTrustGetCertificateAtIndex(trustRef, i); 1780 if (certInChainRef) { 1781 x509_cert = tslo_copy_cert_to_x509(certInChainRef); 1782 if(SSL_CTX_add_client_CA(ctx, x509_cert) < 1) { 1783 syslog( LOG_DEBUG, "[%s] TLS: could not load client CA name using SSL_CTX_add_client_CA ", __func__); 1784 tlso_report_error(); 1785 status = -1; 1786 X509_free(x509_cert); 1787 break; 1788 } 1789 if(SSL_CTX_add_extra_chain_cert(ctx, x509_cert) < 1) { 1790 syslog( LOG_DEBUG, "[%s] TLS: could not load client CA name using SSL_CTX_add_extra_chain_cert ", __func__); 1791 tlso_report_error(); 1792 status = -1; 1793 X509_free(x509_cert); 1794 break; 1795 } 1796 } 1797 } 1798 } else { 1799 syslog( LOG_DEBUG, "[%s] SecTrustGetCertificateCount - No Certificates returned", __func__); 1800 status = -1; 1801 break; 1802 } 1803 } else { 1804 syslog( LOG_DEBUG, "[%s] SecTrustEvaluate (ssl) err (%d) trustResult(%d)", __func__, status, trustResult); 1805 status = -1; 1806 break; 1807 } 1808 } else { 1809 syslog( LOG_DEBUG, "[%s] SecTrustCreateWithCertificates (ssl) err (%d)", __func__, status); 1810 status = -1; 1811 break; 1812 } 1813 } 1814 } while (0); 1815 1816 if (certChain) 1817 CFRelease(certChain); 1818 if (policy) 1819 CFRelease(policy); 1820 if (trustRef) 1821 CFRelease(trustRef); 1822 1823 return status; 1824} 1825 1826#endif /*__APPLE__*/ 1827 1828#endif /* HAVE_OPENSSL */ 1829