1 /* tls_w.c - Handle tls/ssl using Windows SSPI SChannel provider. */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2008-2022 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 #include "ldap_config.h"
22 #include <ac/stdlib.h>
24 #include <ac/socket.h>
25 #include <ac/string.h>
28 #include <ac/unistd.h>
30 #include <ac/dirent.h>
40 typedef struct tlsw_ctx
{
44 ldap_pvt_thread_mutex_t ref_mutex
;
48 typedef struct tlsw_session
{
49 CredHandle cred_handle
;
50 CtxtHandle ctxt_handle
;
51 Sockbuf_IO_Desc
*sbiod
;
52 struct berval peer_der_dn
;
62 #endif /* LDAP_R_COMPILE */
65 * Initialize TLS subsystem. Should be called only once.
70 struct ldapoptions
*lo
= LDAP_INT_GLOBAL_OPT();
77 * Tear down the TLS subsystem. Should only be called once.
86 tlsw_ctx_new( struct ldapoptions
*lo
)
90 ctx
= ber_memcalloc ( 1, sizeof (*ctx
) );
94 ldap_pvt_thread_mutex_init( &ctx
->ref_mutex
);
97 return (tls_ctx
*)ctx
;
101 tlsw_ctx_ref( tls_ctx
*ctx
)
103 tlsw_ctx
*c
= (tlsw_ctx
*)ctx
;
104 LDAP_MUTEX_LOCK( &c
->ref_mutex
);
106 LDAP_MUTEX_UNLOCK( &c
->ref_mutex
);
110 tlsw_ctx_free( tls_ctx
*ctx
)
112 tlsw_ctx
*c
= (tlsw_ctx
*)ctx
;
117 LDAP_MUTEX_LOCK( &c
->ref_mutex
);
118 refcount
= --c
->refcount
;
119 LDAP_MUTEX_UNLOCK( &c
->ref_mutex
);
126 * initialize a new TLS context
129 tlsw_ctx_init( struct ldapoptions
*lo
, struct ldaptls
*lt
, int is_server
)
131 tlsw_ctx
*ctx
= lo
->ldo_tls_ctx
;
133 ctx
->reqcert
= lo
->ldo_tls_require_cert
;
138 tlsw_session_new( tls_ctx
* ctx
, int is_server
)
140 tlsw_session
*session
;
143 session
= ber_memcalloc ( 1, sizeof (*session
) );
147 memset( &cred
, 0, sizeof(cred
) );
148 cred
.dwVersion
= SCHANNEL_CRED_VERSION
; /* FIXME set other fields */
149 if ( AcquireCredentialsHandleA( NULL
, (SEC_CHAR
*)UNISP_NAME_A
,
150 is_server
? SECPKG_CRED_INBOUND
: SECPKG_CRED_OUTBOUND
, NULL
,
151 &cred
, NULL
, NULL
, &session
->cred_handle
, NULL
)) {
152 ber_memfree( session
);
155 return (tls_session
*)session
;
159 tlsw_session_accept( tls_session
*session
)
165 tlsw_recv( Sockbuf_IO_Desc
*sbiod
, void *buf
, size_t len
)
167 tlsw_session
*session
;
169 if ( sbiod
== NULL
|| buf
== NULL
|| len
<= 0 ) return 0;
171 return LBER_SBIOD_READ_NEXT( sbiod
, buf
, len
);
175 tlsw_send( Sockbuf_IO_Desc
*sbiod
, const void *buf
, size_t len
)
177 tlsw_session
*session
;
179 if ( sbiod
== NULL
|| buf
== NULL
|| len
<= 0 ) return 0;
181 return LBER_SBIOD_WRITE_NEXT( sbiod
, (char *)buf
, len
);
184 #define TLS_HEADER_SIZE 5
186 tlsw_session_connect( LDAP
*ld
, tls_session
*session
, const char *name_in
)
188 tlsw_session
*s
= (tlsw_session
*)session
;
189 SecBuffer in_bufs
[] = { { 0, SECBUFFER_TOKEN
, NULL
}, { 0, SECBUFFER_EMPTY
, NULL
} };
190 SecBuffer out_bufs
[] = { { 0, SECBUFFER_TOKEN
, NULL
}, { 0, SECBUFFER_ALERT
, NULL
} };
191 SecBufferDesc in_buf_desc
= { SECBUFFER_VERSION
, ARRAYSIZE(in_bufs
), in_bufs
};
192 SecBufferDesc out_buf_desc
= { SECBUFFER_VERSION
, ARRAYSIZE(out_bufs
), out_bufs
};
193 ULONG attrs
, flags
= ISC_REQ_CONFIDENTIALITY
| ISC_REQ_STREAM
|
194 ISC_REQ_USE_SUPPLIED_CREDS
| ISC_REQ_ALLOCATE_MEMORY
;
195 SECURITY_STATUS status
;
196 ssize_t size
, max_token
, recv_offset
= 0, expected
= TLS_HEADER_SIZE
;
199 status
= QuerySecurityPackageInfoA( UNISP_NAME_A
, &info
);
200 if ( status
!= SEC_E_OK
)
202 expected
= max_token
= info
->cbMaxToken
;
203 FreeContextBuffer( info
);
205 in_bufs
[0].cbBuffer
= max_token
;
206 in_bufs
[0].pvBuffer
= ber_memalloc( in_bufs
[0].cbBuffer
);
207 if ( !in_bufs
[0].pvBuffer
)
210 status
= InitializeSecurityContextA( &s
->cred_handle
, NULL
, (SEC_CHAR
*)name_in
,
211 flags
, 0, 0, NULL
, 0, &s
->ctxt_handle
, &out_buf_desc
, &attrs
, NULL
);
212 while ( status
== SEC_I_CONTINUE_NEEDED
|| status
== SEC_E_INCOMPLETE_MESSAGE
)
214 if ( status
== SEC_I_CONTINUE_NEEDED
) {
215 size
= tlsw_send( s
->sbiod
, out_bufs
[0].pvBuffer
, out_bufs
[0].cbBuffer
);
218 expected
= TLS_HEADER_SIZE
;
219 in_bufs
[0].cbBuffer
= recv_offset
= 0;
222 while ( expected
> 0 ) {
223 size
= tlsw_recv( s
->sbiod
, (char *)in_bufs
[0].pvBuffer
+ recv_offset
, expected
);
226 in_bufs
[0].cbBuffer
+= size
;
231 out_bufs
[0].cbBuffer
= max_token
;
232 status
= InitializeSecurityContextA( &s
->cred_handle
, &s
->ctxt_handle
, (SEC_CHAR
*)name_in
,
233 flags
, 0, 0, &in_buf_desc
, 0, NULL
, &out_buf_desc
, &attrs
, NULL
);
234 if ( status
== SEC_E_INCOMPLETE_MESSAGE
) {
235 assert( in_bufs
[1].BufferType
== SECBUFFER_MISSING
);
236 expected
= in_bufs
[1].cbBuffer
;
237 in_bufs
[1].BufferType
= SECBUFFER_EMPTY
;
238 in_bufs
[1].cbBuffer
= 0;
242 ber_memfree( in_bufs
[0].pvBuffer
);
243 FreeContextBuffer( out_bufs
[0].pvBuffer
);
244 return status
== SEC_E_OK
? 0 : -1;
248 tlsw_session_upflags( Sockbuf
*sb
, tls_session
*session
, int rc
)
254 tlsw_session_errmsg( tls_session
*session
, int rc
, char *buf
, size_t len
)
260 tlsw_x509_cert_dn( struct berval
*cert
, struct berval
*dn
, int get_subject
)
262 BerElementBuffer berbuf
;
263 BerElement
*ber
= (BerElement
*)&berbuf
;
268 ber_init2( ber
, cert
, LBER_USE_DER
);
269 tag
= ber_skip_tag( ber
, &len
); /* Sequence */
270 tag
= ber_skip_tag( ber
, &len
); /* Sequence */
271 tag
= ber_peek_tag( ber
, &len
); /* Context + Constructed (version) */
272 if ( tag
== 0xa0 ) { /* Version is optional */
273 tag
= ber_skip_tag( ber
, &len
);
274 tag
= ber_get_int( ber
, &i
); /* Int: Version */
276 tag
= ber_skip_tag( ber
, &len
); /* Int: Serial (can be longer than ber_int_t) */
277 ber_skip_data( ber
, len
);
278 tag
= ber_skip_tag( ber
, &len
); /* Sequence: Signature */
279 ber_skip_data( ber
, len
);
280 if ( !get_subject
) {
281 tag
= ber_peek_tag( ber
, &len
); /* Sequence: Issuer DN */
283 tag
= ber_skip_tag( ber
, &len
);
284 ber_skip_data( ber
, len
);
285 tag
= ber_skip_tag( ber
, &len
); /* Sequence: Validity */
286 ber_skip_data( ber
, len
);
287 tag
= ber_peek_tag( ber
, &len
); /* Sequence: Subject DN */
289 len
= ber_ptrlen( ber
);
290 dn
->bv_val
= cert
->bv_val
+ len
;
291 dn
->bv_len
= cert
->bv_len
- len
;
295 tlsw_session_my_dn( tls_session
*session
, struct berval
*der_dn
)
301 tlsw_session_peer_dn( tls_session
*session
, struct berval
*der_dn
)
307 tlsw_session_chkhost( LDAP
*ld
, tls_session
*session
, const char *name_in
)
313 tlsw_session_strength( tls_session
*session
)
319 tlsw_session_unique( tls_session
*session
, struct berval
*buf
, int is_server
)
325 tlsw_session_endpoint( tls_session
*session
, struct berval
*buf
, int is_server
)
331 tlsw_session_version( tls_session
*session
)
337 tlsw_session_cipher( tls_session
*session
)
343 tlsw_session_peercert( tls_session
*session
, struct berval
*der
)
349 tlsw_session_pinning( LDAP
*ld
, tls_session
*session
, char *hashalg
, struct berval
*hash
)
355 * TLS support for LBER Sockbufs
366 tlsw_session
*session
;
367 struct buffer header
;
369 struct buffer trailer
;
374 tlsw_sb_setup( Sockbuf_IO_Desc
*sbiod
, void *arg
)
376 struct tls_data
*tls
;
377 tlsw_session
*session
= arg
;
378 SECURITY_STATUS status
;
380 assert( sbiod
!= NULL
);
382 tls
= ber_memcalloc( 1, sizeof( *tls
) );
387 tls
->session
= session
;
388 sbiod
->sbiod_pvt
= tls
;
389 session
->sbiod
= sbiod
;
394 tlsw_sb_remove( Sockbuf_IO_Desc
*sbiod
)
396 struct tls_data
*tls
;
398 assert( sbiod
!= NULL
);
399 assert( sbiod
->sbiod_pvt
!= NULL
);
401 tls
= (struct tls_data
*)sbiod
->sbiod_pvt
;
402 ber_memfree( tls
->header
.buf
);
403 ber_memfree( tls
->data
.buf
);
404 ber_memfree( tls
->trailer
.buf
);
405 ber_memfree( tls
->recv
.buf
);
406 DeleteSecurityContext( &tls
->session
->ctxt_handle
);
407 FreeCredentialsHandle( &tls
->session
->cred_handle
);
408 ber_memfree( tls
->session
);
409 ber_memfree( sbiod
->sbiod_pvt
);
410 sbiod
->sbiod_pvt
= NULL
;
415 tlsw_sb_close( Sockbuf_IO_Desc
*sbiod
)
417 /* FIXME: send close_notify message */
422 tlsw_sb_ctrl( Sockbuf_IO_Desc
*sbiod
, int opt
, void *arg
)
424 struct tls_data
*tls
;
426 assert( sbiod
!= NULL
);
427 assert( sbiod
->sbiod_pvt
!= NULL
);
429 tls
= (struct tls_data
*)sbiod
->sbiod_pvt
;
431 if ( opt
== LBER_SB_OPT_GET_SSL
) {
432 *((tlsw_session
**)arg
) = tls
->session
;
435 else if ( opt
== LBER_SB_OPT_DATA_READY
) {
436 if ( tls
->data
.offset
> 0 || tls
->recv
.offset
> 0 ) {
441 return LBER_SBIOD_CTRL_NEXT( sbiod
, opt
, arg
);
444 static int alloc_buffer( struct buffer
*buf
, size_t size
)
448 buf
->buf
= ber_memalloc( buf
->size
);
449 return buf
->buf
!= NULL
;
452 static int setup_buffers( struct tls_data
*tls
)
454 SecPkgContext_StreamSizes sizes
;
455 SECURITY_STATUS status
;
457 if ( tls
->header
.buf
)
460 status
= QueryContextAttributesA( &tls
->session
->ctxt_handle
, SECPKG_ATTR_STREAM_SIZES
, &sizes
);
461 if ( status
!= SEC_E_OK
)
464 if ( !alloc_buffer( &tls
->header
, sizes
.cbHeader
) )
467 if ( !alloc_buffer( &tls
->data
, sizes
.cbMaximumMessage
) ) {
468 ber_memfree( tls
->header
.buf
);
472 if ( !alloc_buffer( &tls
->trailer
, sizes
.cbTrailer
) ) {
473 ber_memfree( tls
->header
.buf
);
474 ber_memfree( tls
->data
.buf
);
478 if ( !alloc_buffer( &tls
->recv
, sizes
.cbMaximumMessage
) ) {
479 ber_memfree( tls
->header
.buf
);
480 ber_memfree( tls
->data
.buf
);
481 ber_memfree( tls
->trailer
.buf
);
488 static void init_secbuf( SecBuffer
*secbuf
, DWORD type
, void *buf
, DWORD size
) {
489 secbuf
->BufferType
= type
;
490 secbuf
->cbBuffer
= size
;
491 secbuf
->pvBuffer
= buf
;
494 static ber_len_t
remove_data( struct tls_data
*tls
, ber_len_t len
)
496 tls
->data
.offset
-= len
;
497 memmove( tls
->data
.buf
, tls
->data
.buf
+ len
, tls
->data
.offset
);
501 static int grow_buffer( struct buffer
*buf
, size_t min_size
)
503 size_t size
= max( min_size
, buf
->size
* 2 );
506 if ( buf
->size
>= min_size
)
509 tmp
= ber_memrealloc( buf
->buf
, size
);
518 tlsw_sb_read( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
520 struct tls_data
*tls
= sbiod
->sbiod_pvt
;
522 SecBufferDesc buf_desc
= { SECBUFFER_VERSION
, 4, bufs
};
523 SECURITY_STATUS status
= SEC_E_OK
;
524 ssize_t size
, expected
= max( len
, tls
->header
.size
), ret
= -1;
528 if ( setup_buffers( tls
) < 0 )
531 if ( tls
->data
.offset
>= len
) {
532 memcpy( buf
, tls
->data
.buf
, len
);
533 return remove_data( tls
, len
);
537 if ( grow_buffer( &tls
->recv
, expected
) < 0 )
539 while ( tls
->recv
.offset
< expected
) {
540 size
= tlsw_recv( sbiod
, tls
->recv
.buf
+ tls
->recv
.offset
, expected
- tls
->recv
.offset
);
543 tls
->recv
.offset
+= size
;
546 if ( grow_buffer( &tls
->data
, tls
->data
.offset
+ tls
->recv
.offset
) < 0 )
548 memcpy( tls
->data
.buf
+ tls
->data
.offset
, tls
->recv
.buf
, tls
->recv
.offset
);
550 init_secbuf( &bufs
[0], SECBUFFER_DATA
, tls
->data
.buf
+ tls
->data
.offset
, tls
->recv
.offset
);
551 init_secbuf( &bufs
[1], SECBUFFER_EMPTY
, NULL
, 0 );
552 init_secbuf( &bufs
[2], SECBUFFER_EMPTY
, NULL
, 0 );
553 init_secbuf( &bufs
[3], SECBUFFER_EMPTY
, NULL
, 0 );
555 status
= DecryptMessage( &tls
->session
->ctxt_handle
, &buf_desc
, 0, NULL
);
556 if ( status
== SEC_E_OK
) {
557 assert( bufs
[0].BufferType
== SECBUFFER_STREAM_HEADER
);
558 assert( bufs
[1].BufferType
== SECBUFFER_DATA
);
559 assert( (char *)bufs
[1].pvBuffer
== (char *)bufs
[0].pvBuffer
+ tls
->header
.size
);
561 tls
->recv
.offset
= 0;
562 memmove( tls
->data
.buf
, tls
->data
.buf
+ tls
->header
.size
, bufs
[1].cbBuffer
);
563 tls
->data
.offset
+= bufs
[1].cbBuffer
;
564 if ( tls
->data
.offset
>= len
) {
565 memcpy( buf
, tls
->data
.buf
, len
);
566 ret
= remove_data( tls
, len
);
569 else if ( status
== SEC_E_INCOMPLETE_MESSAGE
) {
570 assert( bufs
[1].BufferType
== SECBUFFER_MISSING
);
571 expected
= bufs
[1].cbBuffer
;
579 tlsw_sb_write( Sockbuf_IO_Desc
*sbiod
, void *buf
, ber_len_t len
)
581 struct tls_data
*tls
= sbiod
->sbiod_pvt
;
583 SecBufferDesc buf_desc
= { SECBUFFER_VERSION
, 3, bufs
};
584 SECURITY_STATUS status
;
585 ssize_t size
, ret
= len
;
590 if ( setup_buffers( tls
) < 0 )
593 init_secbuf( &bufs
[0], SECBUFFER_STREAM_HEADER
, tls
->header
.buf
, tls
->header
.size
);
594 init_secbuf( &bufs
[1], SECBUFFER_DATA
, buf
, len
);
595 init_secbuf( &bufs
[2], SECBUFFER_STREAM_TRAILER
, tls
->trailer
.buf
, tls
->trailer
.size
);
597 status
= EncryptMessage( &tls
->session
->ctxt_handle
, 0, &buf_desc
, 0 );
598 if ( status
!= SEC_E_OK
)
601 for ( i
= 0; i
< 3; i
++ ) {
602 size
= tlsw_send( sbiod
, bufs
[i
].pvBuffer
, bufs
[i
].cbBuffer
);
613 static Sockbuf_IO tlsw_sbio
=
615 tlsw_sb_setup
, /* sbi_setup */
616 tlsw_sb_remove
, /* sbi_remove */
617 tlsw_sb_ctrl
, /* sbi_ctrl */
618 tlsw_sb_read
, /* sbi_read */
619 tlsw_sb_write
, /* sbi_write */
620 tlsw_sb_close
/* sbi_close */
623 tls_impl ldap_int_tls_impl
= {
624 "Windows SSPI SChannel",
635 tlsw_session_connect
,
637 tlsw_session_upflags
,
640 tlsw_session_peer_dn
,
641 tlsw_session_chkhost
,
642 tlsw_session_strength
,
644 tlsw_session_endpoint
,
645 tlsw_session_version
,
647 tlsw_session_peercert
,
648 tlsw_session_pinning
,
652 #ifdef LDAP_R_COMPILE