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