1 /* $NetBSD: tls_g.c,v 1.1.1.4 2017/02/09 01:46:47 christos Exp $ */ 2 3 /* tls_g.c - Handle tls/ssl using GNUTLS. */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2008-2016 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* ACKNOWLEDGEMENTS: GNUTLS support written by Howard Chu and 19 * Emily Backes; sponsored by The Written Word (thewrittenword.com) 20 * and Stanford University (stanford.edu). 21 */ 22 23 #include <sys/cdefs.h> 24 __RCSID("$NetBSD: tls_g.c,v 1.1.1.4 2017/02/09 01:46:47 christos Exp $"); 25 26 #include "portable.h" 27 28 #ifdef HAVE_GNUTLS 29 30 #include "ldap_config.h" 31 32 #include <stdio.h> 33 34 #include <ac/stdlib.h> 35 #include <ac/errno.h> 36 #include <ac/socket.h> 37 #include <ac/string.h> 38 #include <ac/ctype.h> 39 #include <ac/time.h> 40 #include <ac/unistd.h> 41 #include <ac/param.h> 42 #include <ac/dirent.h> 43 #include <sys/stat.h> 44 #include <fcntl.h> 45 46 #include "ldap-int.h" 47 #include "ldap-tls.h" 48 49 #include <gnutls/gnutls.h> 50 #include <gnutls/x509.h> 51 52 #define DH_BITS (1024) 53 54 typedef struct tlsg_ctx { 55 struct ldapoptions *lo; 56 gnutls_certificate_credentials_t cred; 57 gnutls_dh_params_t dh_params; 58 unsigned long verify_depth; 59 int refcount; 60 gnutls_priority_t prios; 61 #ifdef LDAP_R_COMPILE 62 ldap_pvt_thread_mutex_t ref_mutex; 63 #endif 64 } tlsg_ctx; 65 66 typedef struct tlsg_session { 67 gnutls_session_t session; 68 tlsg_ctx *ctx; 69 struct berval peer_der_dn; 70 } tlsg_session; 71 72 static int tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites ); 73 static int tlsg_cert_verify( tlsg_session *s ); 74 75 #ifdef LDAP_R_COMPILE 76 77 static int 78 tlsg_mutex_init( void **priv ) 79 { 80 int err = 0; 81 ldap_pvt_thread_mutex_t *lock = LDAP_MALLOC( sizeof( ldap_pvt_thread_mutex_t )); 82 83 if ( !lock ) 84 err = ENOMEM; 85 if ( !err ) { 86 err = ldap_pvt_thread_mutex_init( lock ); 87 if ( err ) 88 LDAP_FREE( lock ); 89 else 90 *priv = lock; 91 } 92 return err; 93 } 94 95 static int 96 tlsg_mutex_destroy( void **lock ) 97 { 98 int err = ldap_pvt_thread_mutex_destroy( *lock ); 99 LDAP_FREE( *lock ); 100 return err; 101 } 102 103 static int 104 tlsg_mutex_lock( void **lock ) 105 { 106 return ldap_pvt_thread_mutex_lock( *lock ); 107 } 108 109 static int 110 tlsg_mutex_unlock( void **lock ) 111 { 112 return ldap_pvt_thread_mutex_unlock( *lock ); 113 } 114 115 static void 116 tlsg_thr_init( void ) 117 { 118 gnutls_global_set_mutex (tlsg_mutex_init, 119 tlsg_mutex_destroy, 120 tlsg_mutex_lock, 121 tlsg_mutex_unlock); 122 } 123 #endif /* LDAP_R_COMPILE */ 124 125 /* 126 * Initialize TLS subsystem. Should be called only once. 127 */ 128 static int 129 tlsg_init( void ) 130 { 131 gnutls_global_init(); 132 return 0; 133 } 134 135 /* 136 * Tear down the TLS subsystem. Should only be called once. 137 */ 138 static void 139 tlsg_destroy( void ) 140 { 141 gnutls_global_deinit(); 142 } 143 144 static tls_ctx * 145 tlsg_ctx_new ( struct ldapoptions *lo ) 146 { 147 tlsg_ctx *ctx; 148 149 ctx = ber_memcalloc ( 1, sizeof (*ctx) ); 150 if ( ctx ) { 151 ctx->lo = lo; 152 if ( gnutls_certificate_allocate_credentials( &ctx->cred )) { 153 ber_memfree( ctx ); 154 return NULL; 155 } 156 ctx->refcount = 1; 157 gnutls_priority_init( &ctx->prios, "NORMAL", NULL ); 158 #ifdef LDAP_R_COMPILE 159 ldap_pvt_thread_mutex_init( &ctx->ref_mutex ); 160 #endif 161 } 162 return (tls_ctx *)ctx; 163 } 164 165 static void 166 tlsg_ctx_ref( tls_ctx *ctx ) 167 { 168 tlsg_ctx *c = (tlsg_ctx *)ctx; 169 LDAP_MUTEX_LOCK( &c->ref_mutex ); 170 c->refcount++; 171 LDAP_MUTEX_UNLOCK( &c->ref_mutex ); 172 } 173 174 static void 175 tlsg_ctx_free ( tls_ctx *ctx ) 176 { 177 tlsg_ctx *c = (tlsg_ctx *)ctx; 178 int refcount; 179 180 if ( !c ) return; 181 182 LDAP_MUTEX_LOCK( &c->ref_mutex ); 183 refcount = --c->refcount; 184 LDAP_MUTEX_UNLOCK( &c->ref_mutex ); 185 if ( refcount ) 186 return; 187 gnutls_priority_deinit( c->prios ); 188 gnutls_certificate_free_credentials( c->cred ); 189 ber_memfree ( c ); 190 } 191 192 static int 193 tlsg_getfile( const char *path, gnutls_datum_t *buf ) 194 { 195 int rc = -1, fd; 196 struct stat st; 197 198 fd = open( path, O_RDONLY ); 199 if ( fd >= 0 && fstat( fd, &st ) == 0 ) { 200 buf->size = st.st_size; 201 buf->data = LDAP_MALLOC( st.st_size + 1 ); 202 if ( buf->data ) { 203 rc = read( fd, buf->data, st.st_size ); 204 close( fd ); 205 if ( rc < st.st_size ) 206 rc = -1; 207 else 208 rc = 0; 209 } 210 } 211 return rc; 212 } 213 214 /* This is the GnuTLS default */ 215 #define VERIFY_DEPTH 6 216 217 /* 218 * initialize a new TLS context 219 */ 220 static int 221 tlsg_ctx_init( struct ldapoptions *lo, struct ldaptls *lt, int is_server ) 222 { 223 tlsg_ctx *ctx = lo->ldo_tls_ctx; 224 int rc; 225 226 if ( lo->ldo_tls_ciphersuite && 227 tlsg_parse_ciphers( ctx, lt->lt_ciphersuite )) { 228 Debug( LDAP_DEBUG_ANY, 229 "TLS: could not set cipher list %s.\n", 230 lo->ldo_tls_ciphersuite, 0, 0 ); 231 return -1; 232 } 233 234 if (lo->ldo_tls_cacertdir != NULL) { 235 Debug( LDAP_DEBUG_ANY, 236 "TLS: warning: cacertdir not implemented for gnutls\n", 237 NULL, NULL, NULL ); 238 } 239 240 if (lo->ldo_tls_cacertfile != NULL) { 241 rc = gnutls_certificate_set_x509_trust_file( 242 ctx->cred, 243 lt->lt_cacertfile, 244 GNUTLS_X509_FMT_PEM ); 245 if ( rc < 0 ) return -1; 246 } 247 248 if ( lo->ldo_tls_certfile && lo->ldo_tls_keyfile ) { 249 gnutls_x509_privkey_t key; 250 gnutls_datum_t buf; 251 gnutls_x509_crt_t certs[VERIFY_DEPTH]; 252 unsigned int max = VERIFY_DEPTH; 253 254 rc = gnutls_x509_privkey_init( &key ); 255 if ( rc ) return -1; 256 257 /* OpenSSL builds the cert chain for us, but GnuTLS 258 * expects it to be present in the certfile. If it's 259 * not, we have to build it ourselves. So we have to 260 * do some special checks here... 261 */ 262 rc = tlsg_getfile( lt->lt_keyfile, &buf ); 263 if ( rc ) return -1; 264 rc = gnutls_x509_privkey_import( key, &buf, 265 GNUTLS_X509_FMT_PEM ); 266 LDAP_FREE( buf.data ); 267 if ( rc < 0 ) return rc; 268 269 rc = tlsg_getfile( lt->lt_certfile, &buf ); 270 if ( rc ) return -1; 271 rc = gnutls_x509_crt_list_import( certs, &max, &buf, 272 GNUTLS_X509_FMT_PEM, 0 ); 273 LDAP_FREE( buf.data ); 274 if ( rc < 0 ) return rc; 275 276 /* If there's only one cert and it's not self-signed, 277 * then we have to build the cert chain. 278 */ 279 if ( max == 1 && !gnutls_x509_crt_check_issuer( certs[0], certs[0] )) { 280 unsigned int i; 281 for ( i = 1; i<VERIFY_DEPTH; i++ ) { 282 if ( gnutls_certificate_get_issuer( ctx->cred, certs[i-1], &certs[i], 0 )) 283 break; 284 max++; 285 /* If this CA is self-signed, we're done */ 286 if ( gnutls_x509_crt_check_issuer( certs[i], certs[i] )) 287 break; 288 } 289 } 290 rc = gnutls_certificate_set_x509_key( ctx->cred, certs, max, key ); 291 if ( rc ) return -1; 292 } else if ( lo->ldo_tls_certfile || lo->ldo_tls_keyfile ) { 293 Debug( LDAP_DEBUG_ANY, 294 "TLS: only one of certfile and keyfile specified\n", 295 NULL, NULL, NULL ); 296 return -1; 297 } 298 299 if ( lo->ldo_tls_dhfile ) { 300 Debug( LDAP_DEBUG_ANY, 301 "TLS: warning: ignoring dhfile\n", 302 NULL, NULL, NULL ); 303 } 304 305 if ( lo->ldo_tls_crlfile ) { 306 rc = gnutls_certificate_set_x509_crl_file( 307 ctx->cred, 308 lt->lt_crlfile, 309 GNUTLS_X509_FMT_PEM ); 310 if ( rc < 0 ) return -1; 311 rc = 0; 312 } 313 314 /* FIXME: ITS#5992 - this should go be configurable, 315 * and V1 CA certs should be phased out ASAP. 316 */ 317 gnutls_certificate_set_verify_flags( ctx->cred, 318 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT ); 319 320 if ( is_server ) { 321 gnutls_dh_params_init(&ctx->dh_params); 322 gnutls_dh_params_generate2(ctx->dh_params, DH_BITS); 323 } 324 return 0; 325 } 326 327 static tls_session * 328 tlsg_session_new ( tls_ctx * ctx, int is_server ) 329 { 330 tlsg_ctx *c = (tlsg_ctx *)ctx; 331 tlsg_session *session; 332 333 session = ber_memcalloc ( 1, sizeof (*session) ); 334 if ( !session ) 335 return NULL; 336 337 session->ctx = c; 338 gnutls_init( &session->session, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT ); 339 gnutls_priority_set( session->session, c->prios ); 340 if ( c->cred ) 341 gnutls_credentials_set( session->session, GNUTLS_CRD_CERTIFICATE, c->cred ); 342 343 if ( is_server ) { 344 int flag = 0; 345 if ( c->lo->ldo_tls_require_cert ) { 346 flag = GNUTLS_CERT_REQUEST; 347 if ( c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_DEMAND || 348 c->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_HARD ) 349 flag = GNUTLS_CERT_REQUIRE; 350 gnutls_certificate_server_set_request( session->session, flag ); 351 } 352 } 353 return (tls_session *)session; 354 } 355 356 static int 357 tlsg_session_accept( tls_session *session ) 358 { 359 tlsg_session *s = (tlsg_session *)session; 360 int rc; 361 362 rc = gnutls_handshake( s->session ); 363 if ( rc == 0 && s->ctx->lo->ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER ) { 364 const gnutls_datum_t *peer_cert_list; 365 unsigned int list_size; 366 367 peer_cert_list = gnutls_certificate_get_peers( s->session, 368 &list_size ); 369 if ( !peer_cert_list && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_TRY ) 370 rc = 0; 371 else { 372 rc = tlsg_cert_verify( s ); 373 if ( rc && s->ctx->lo->ldo_tls_require_cert == LDAP_OPT_X_TLS_ALLOW ) 374 rc = 0; 375 } 376 } 377 return rc; 378 } 379 380 static int 381 tlsg_session_connect( LDAP *ld, tls_session *session ) 382 { 383 return tlsg_session_accept( session); 384 } 385 386 static int 387 tlsg_session_upflags( Sockbuf *sb, tls_session *session, int rc ) 388 { 389 tlsg_session *s = (tlsg_session *)session; 390 391 if ( rc != GNUTLS_E_INTERRUPTED && rc != GNUTLS_E_AGAIN ) 392 return 0; 393 394 switch (gnutls_record_get_direction (s->session)) { 395 case 0: 396 sb->sb_trans_needs_read = 1; 397 return 1; 398 case 1: 399 sb->sb_trans_needs_write = 1; 400 return 1; 401 } 402 return 0; 403 } 404 405 static char * 406 tlsg_session_errmsg( tls_session *sess, int rc, char *buf, size_t len ) 407 { 408 return (char *)gnutls_strerror( rc ); 409 } 410 411 static void 412 tlsg_x509_cert_dn( struct berval *cert, struct berval *dn, int get_subject ) 413 { 414 BerElementBuffer berbuf; 415 BerElement *ber = (BerElement *)&berbuf; 416 ber_tag_t tag; 417 ber_len_t len; 418 ber_int_t i; 419 420 ber_init2( ber, cert, LBER_USE_DER ); 421 tag = ber_skip_tag( ber, &len ); /* Sequence */ 422 tag = ber_skip_tag( ber, &len ); /* Sequence */ 423 tag = ber_peek_tag( ber, &len ); /* Context + Constructed (version) */ 424 if ( tag == 0xa0 ) { /* Version is optional */ 425 tag = ber_skip_tag( ber, &len ); 426 tag = ber_get_int( ber, &i ); /* Int: Version */ 427 } 428 tag = ber_skip_tag( ber, &len ); /* Int: Serial (can be longer than ber_int_t) */ 429 ber_skip_data( ber, len ); 430 tag = ber_skip_tag( ber, &len ); /* Sequence: Signature */ 431 ber_skip_data( ber, len ); 432 if ( !get_subject ) { 433 tag = ber_peek_tag( ber, &len ); /* Sequence: Issuer DN */ 434 } else { 435 tag = ber_skip_tag( ber, &len ); 436 ber_skip_data( ber, len ); 437 tag = ber_skip_tag( ber, &len ); /* Sequence: Validity */ 438 ber_skip_data( ber, len ); 439 tag = ber_peek_tag( ber, &len ); /* Sequence: Subject DN */ 440 } 441 len = ber_ptrlen( ber ); 442 dn->bv_val = cert->bv_val + len; 443 dn->bv_len = cert->bv_len - len; 444 } 445 446 static int 447 tlsg_session_my_dn( tls_session *session, struct berval *der_dn ) 448 { 449 tlsg_session *s = (tlsg_session *)session; 450 const gnutls_datum_t *x; 451 struct berval bv; 452 453 x = gnutls_certificate_get_ours( s->session ); 454 455 if (!x) return LDAP_INVALID_CREDENTIALS; 456 457 bv.bv_val = (char *) x->data; 458 bv.bv_len = x->size; 459 460 tlsg_x509_cert_dn( &bv, der_dn, 1 ); 461 return 0; 462 } 463 464 static int 465 tlsg_session_peer_dn( tls_session *session, struct berval *der_dn ) 466 { 467 tlsg_session *s = (tlsg_session *)session; 468 if ( !s->peer_der_dn.bv_val ) { 469 const gnutls_datum_t *peer_cert_list; 470 unsigned int list_size; 471 struct berval bv; 472 473 peer_cert_list = gnutls_certificate_get_peers( s->session, 474 &list_size ); 475 if ( !peer_cert_list ) return LDAP_INVALID_CREDENTIALS; 476 477 bv.bv_len = peer_cert_list->size; 478 bv.bv_val = (char *) peer_cert_list->data; 479 480 tlsg_x509_cert_dn( &bv, &s->peer_der_dn, 1 ); 481 } 482 *der_dn = s->peer_der_dn; 483 return 0; 484 } 485 486 /* what kind of hostname were we given? */ 487 #define IS_DNS 0 488 #define IS_IP4 1 489 #define IS_IP6 2 490 491 #define CN_OID "2.5.4.3" 492 493 static int 494 tlsg_session_chkhost( LDAP *ld, tls_session *session, const char *name_in ) 495 { 496 tlsg_session *s = (tlsg_session *)session; 497 int i, ret; 498 const gnutls_datum_t *peer_cert_list; 499 unsigned int list_size; 500 char altname[NI_MAXHOST]; 501 size_t altnamesize; 502 503 gnutls_x509_crt_t cert; 504 const char *name; 505 char *ptr; 506 char *domain = NULL; 507 #ifdef LDAP_PF_INET6 508 struct in6_addr addr; 509 #else 510 struct in_addr addr; 511 #endif 512 int len1 = 0, len2 = 0; 513 int ntype = IS_DNS; 514 515 if( ldap_int_hostname && 516 ( !name_in || !strcasecmp( name_in, "localhost" ) ) ) 517 { 518 name = ldap_int_hostname; 519 } else { 520 name = name_in; 521 } 522 523 peer_cert_list = gnutls_certificate_get_peers( s->session, 524 &list_size ); 525 if ( !peer_cert_list ) { 526 Debug( LDAP_DEBUG_ANY, 527 "TLS: unable to get peer certificate.\n", 528 0, 0, 0 ); 529 /* If this was a fatal condition, things would have 530 * aborted long before now. 531 */ 532 return LDAP_SUCCESS; 533 } 534 ret = gnutls_x509_crt_init( &cert ); 535 if ( ret < 0 ) 536 return LDAP_LOCAL_ERROR; 537 ret = gnutls_x509_crt_import( cert, peer_cert_list, GNUTLS_X509_FMT_DER ); 538 if ( ret ) { 539 gnutls_x509_crt_deinit( cert ); 540 return LDAP_LOCAL_ERROR; 541 } 542 543 #ifdef LDAP_PF_INET6 544 if (inet_pton(AF_INET6, name, &addr)) { 545 ntype = IS_IP6; 546 } else 547 #endif 548 if ((ptr = strrchr(name, '.')) && isdigit((unsigned char)ptr[1])) { 549 if (inet_aton(name, (struct in_addr *)&addr)) ntype = IS_IP4; 550 } 551 552 if (ntype == IS_DNS) { 553 len1 = strlen(name); 554 domain = strchr(name, '.'); 555 if (domain) { 556 len2 = len1 - (domain-name); 557 } 558 } 559 560 for ( i=0, ret=0; ret >= 0; i++ ) { 561 altnamesize = sizeof(altname); 562 ret = gnutls_x509_crt_get_subject_alt_name( cert, i, 563 altname, &altnamesize, NULL ); 564 if ( ret < 0 ) break; 565 566 /* ignore empty */ 567 if ( altnamesize == 0 ) continue; 568 569 if ( ret == GNUTLS_SAN_DNSNAME ) { 570 if (ntype != IS_DNS) continue; 571 572 /* Is this an exact match? */ 573 if ((len1 == altnamesize) && !strncasecmp(name, altname, len1)) { 574 break; 575 } 576 577 /* Is this a wildcard match? */ 578 if (domain && (altname[0] == '*') && (altname[1] == '.') && 579 (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) 580 { 581 break; 582 } 583 } else if ( ret == GNUTLS_SAN_IPADDRESS ) { 584 if (ntype == IS_DNS) continue; 585 586 #ifdef LDAP_PF_INET6 587 if (ntype == IS_IP6 && altnamesize != sizeof(struct in6_addr)) { 588 continue; 589 } else 590 #endif 591 if (ntype == IS_IP4 && altnamesize != sizeof(struct in_addr)) { 592 continue; 593 } 594 if (!memcmp(altname, &addr, altnamesize)) { 595 break; 596 } 597 } 598 } 599 if ( ret >= 0 ) { 600 ret = LDAP_SUCCESS; 601 } else { 602 /* find the last CN */ 603 i=0; 604 do { 605 altnamesize = 0; 606 ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID, 607 i, 1, altname, &altnamesize ); 608 if ( ret == GNUTLS_E_SHORT_MEMORY_BUFFER ) 609 i++; 610 else 611 break; 612 } while ( 1 ); 613 614 if ( i ) { 615 altnamesize = sizeof(altname); 616 ret = gnutls_x509_crt_get_dn_by_oid( cert, CN_OID, 617 i-1, 0, altname, &altnamesize ); 618 } 619 620 if ( ret < 0 ) { 621 Debug( LDAP_DEBUG_ANY, 622 "TLS: unable to get common name from peer certificate.\n", 623 0, 0, 0 ); 624 ret = LDAP_CONNECT_ERROR; 625 if ( ld->ld_error ) { 626 LDAP_FREE( ld->ld_error ); 627 } 628 ld->ld_error = LDAP_STRDUP( 629 _("TLS: unable to get CN from peer certificate")); 630 631 } else { 632 ret = LDAP_LOCAL_ERROR; 633 if ( !len1 ) len1 = strlen( name ); 634 if ( len1 == altnamesize && strncasecmp(name, altname, altnamesize) == 0 ) { 635 ret = LDAP_SUCCESS; 636 637 } else if (( altname[0] == '*' ) && ( altname[1] == '.' )) { 638 /* Is this a wildcard match? */ 639 if( domain && 640 (len2 == altnamesize-1) && !strncasecmp(domain, &altname[1], len2)) { 641 ret = LDAP_SUCCESS; 642 } 643 } 644 } 645 646 if( ret == LDAP_LOCAL_ERROR ) { 647 altname[altnamesize] = '\0'; 648 Debug( LDAP_DEBUG_ANY, "TLS: hostname (%s) does not match " 649 "common name in certificate (%s).\n", 650 name, altname, 0 ); 651 ret = LDAP_CONNECT_ERROR; 652 if ( ld->ld_error ) { 653 LDAP_FREE( ld->ld_error ); 654 } 655 ld->ld_error = LDAP_STRDUP( 656 _("TLS: hostname does not match CN in peer certificate")); 657 } 658 } 659 gnutls_x509_crt_deinit( cert ); 660 return ret; 661 } 662 663 static int 664 tlsg_session_strength( tls_session *session ) 665 { 666 tlsg_session *s = (tlsg_session *)session; 667 gnutls_cipher_algorithm_t c; 668 669 c = gnutls_cipher_get( s->session ); 670 return gnutls_cipher_get_key_size( c ) * 8; 671 } 672 673 /* suites is a string of colon-separated cipher suite names. */ 674 static int 675 tlsg_parse_ciphers( tlsg_ctx *ctx, char *suites ) 676 { 677 const char *err; 678 int rc = gnutls_priority_init( &ctx->prios, suites, &err ); 679 if ( rc ) 680 ctx->prios = NULL; 681 return rc; 682 } 683 684 /* 685 * TLS support for LBER Sockbufs 686 */ 687 688 struct tls_data { 689 tlsg_session *session; 690 Sockbuf_IO_Desc *sbiod; 691 }; 692 693 static ssize_t 694 tlsg_recv( gnutls_transport_ptr_t ptr, void *buf, size_t len ) 695 { 696 struct tls_data *p; 697 698 if ( buf == NULL || len <= 0 ) return 0; 699 700 p = (struct tls_data *)ptr; 701 702 if ( p == NULL || p->sbiod == NULL ) { 703 return 0; 704 } 705 706 return LBER_SBIOD_READ_NEXT( p->sbiod, buf, len ); 707 } 708 709 static ssize_t 710 tlsg_send( gnutls_transport_ptr_t ptr, const void *buf, size_t len ) 711 { 712 struct tls_data *p; 713 714 if ( buf == NULL || len <= 0 ) return 0; 715 716 p = (struct tls_data *)ptr; 717 718 if ( p == NULL || p->sbiod == NULL ) { 719 return 0; 720 } 721 722 return LBER_SBIOD_WRITE_NEXT( p->sbiod, (char *)buf, len ); 723 } 724 725 static int 726 tlsg_sb_setup( Sockbuf_IO_Desc *sbiod, void *arg ) 727 { 728 struct tls_data *p; 729 tlsg_session *session = arg; 730 731 assert( sbiod != NULL ); 732 733 p = LBER_MALLOC( sizeof( *p ) ); 734 if ( p == NULL ) { 735 return -1; 736 } 737 738 gnutls_transport_set_ptr( session->session, (gnutls_transport_ptr)p ); 739 gnutls_transport_set_pull_function( session->session, tlsg_recv ); 740 gnutls_transport_set_push_function( session->session, tlsg_send ); 741 p->session = session; 742 p->sbiod = sbiod; 743 sbiod->sbiod_pvt = p; 744 return 0; 745 } 746 747 static int 748 tlsg_sb_remove( Sockbuf_IO_Desc *sbiod ) 749 { 750 struct tls_data *p; 751 752 assert( sbiod != NULL ); 753 assert( sbiod->sbiod_pvt != NULL ); 754 755 p = (struct tls_data *)sbiod->sbiod_pvt; 756 gnutls_deinit ( p->session->session ); 757 LBER_FREE( p->session ); 758 LBER_FREE( sbiod->sbiod_pvt ); 759 sbiod->sbiod_pvt = NULL; 760 return 0; 761 } 762 763 static int 764 tlsg_sb_close( Sockbuf_IO_Desc *sbiod ) 765 { 766 struct tls_data *p; 767 768 assert( sbiod != NULL ); 769 assert( sbiod->sbiod_pvt != NULL ); 770 771 p = (struct tls_data *)sbiod->sbiod_pvt; 772 gnutls_bye ( p->session->session, GNUTLS_SHUT_WR ); 773 return 0; 774 } 775 776 static int 777 tlsg_sb_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) 778 { 779 struct tls_data *p; 780 781 assert( sbiod != NULL ); 782 assert( sbiod->sbiod_pvt != NULL ); 783 784 p = (struct tls_data *)sbiod->sbiod_pvt; 785 786 if ( opt == LBER_SB_OPT_GET_SSL ) { 787 *((tlsg_session **)arg) = p->session; 788 return 1; 789 790 } else if ( opt == LBER_SB_OPT_DATA_READY ) { 791 if( gnutls_record_check_pending( p->session->session ) > 0 ) { 792 return 1; 793 } 794 } 795 796 return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); 797 } 798 799 static ber_slen_t 800 tlsg_sb_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 801 { 802 struct tls_data *p; 803 ber_slen_t ret; 804 805 assert( sbiod != NULL ); 806 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 807 808 p = (struct tls_data *)sbiod->sbiod_pvt; 809 810 ret = gnutls_record_recv ( p->session->session, buf, len ); 811 switch (ret) { 812 case GNUTLS_E_INTERRUPTED: 813 case GNUTLS_E_AGAIN: 814 sbiod->sbiod_sb->sb_trans_needs_read = 1; 815 sock_errset(EWOULDBLOCK); 816 ret = 0; 817 break; 818 case GNUTLS_E_REHANDSHAKE: 819 for ( ret = gnutls_handshake ( p->session->session ); 820 ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN; 821 ret = gnutls_handshake ( p->session->session ) ); 822 sbiod->sbiod_sb->sb_trans_needs_read = 1; 823 ret = 0; 824 break; 825 default: 826 sbiod->sbiod_sb->sb_trans_needs_read = 0; 827 } 828 return ret; 829 } 830 831 static ber_slen_t 832 tlsg_sb_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) 833 { 834 struct tls_data *p; 835 ber_slen_t ret; 836 837 assert( sbiod != NULL ); 838 assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); 839 840 p = (struct tls_data *)sbiod->sbiod_pvt; 841 842 ret = gnutls_record_send ( p->session->session, (char *)buf, len ); 843 844 if ( ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN ) { 845 sbiod->sbiod_sb->sb_trans_needs_write = 1; 846 sock_errset(EWOULDBLOCK); 847 ret = 0; 848 } else { 849 sbiod->sbiod_sb->sb_trans_needs_write = 0; 850 } 851 return ret; 852 } 853 854 static Sockbuf_IO tlsg_sbio = 855 { 856 tlsg_sb_setup, /* sbi_setup */ 857 tlsg_sb_remove, /* sbi_remove */ 858 tlsg_sb_ctrl, /* sbi_ctrl */ 859 tlsg_sb_read, /* sbi_read */ 860 tlsg_sb_write, /* sbi_write */ 861 tlsg_sb_close /* sbi_close */ 862 }; 863 864 /* Certs are not automatically varified during the handshake */ 865 static int 866 tlsg_cert_verify( tlsg_session *ssl ) 867 { 868 unsigned int status = 0; 869 int err; 870 time_t now = time(0); 871 time_t peertime; 872 873 err = gnutls_certificate_verify_peers2( ssl->session, &status ); 874 if ( err < 0 ) { 875 Debug( LDAP_DEBUG_ANY,"TLS: gnutls_certificate_verify_peers2 failed %d\n", 876 err,0,0 ); 877 return -1; 878 } 879 if ( status ) { 880 Debug( LDAP_DEBUG_TRACE,"TLS: peer cert untrusted or revoked (0x%x)\n", 881 status, 0,0 ); 882 return -1; 883 } 884 peertime = gnutls_certificate_expiration_time_peers( ssl->session ); 885 if ( peertime == (time_t) -1 ) { 886 Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_expiration_time_peers failed\n", 887 0, 0, 0 ); 888 return -1; 889 } 890 if ( peertime < now ) { 891 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate is expired\n", 892 0, 0, 0 ); 893 return -1; 894 } 895 peertime = gnutls_certificate_activation_time_peers( ssl->session ); 896 if ( peertime == (time_t) -1 ) { 897 Debug( LDAP_DEBUG_ANY, "TLS: gnutls_certificate_activation_time_peers failed\n", 898 0, 0, 0 ); 899 return -1; 900 } 901 if ( peertime > now ) { 902 Debug( LDAP_DEBUG_ANY, "TLS: peer certificate not yet active\n", 903 0, 0, 0 ); 904 return -1; 905 } 906 return 0; 907 } 908 909 tls_impl ldap_int_tls_impl = { 910 "GnuTLS", 911 912 tlsg_init, 913 tlsg_destroy, 914 915 tlsg_ctx_new, 916 tlsg_ctx_ref, 917 tlsg_ctx_free, 918 tlsg_ctx_init, 919 920 tlsg_session_new, 921 tlsg_session_connect, 922 tlsg_session_accept, 923 tlsg_session_upflags, 924 tlsg_session_errmsg, 925 tlsg_session_my_dn, 926 tlsg_session_peer_dn, 927 tlsg_session_chkhost, 928 tlsg_session_strength, 929 930 &tlsg_sbio, 931 932 #ifdef LDAP_R_COMPILE 933 tlsg_thr_init, 934 #else 935 NULL, 936 #endif 937 938 0 939 }; 940 941 #endif /* HAVE_GNUTLS */ 942