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