Overview
Comment: | More comment updates and changes for fast path option |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk | main |
Files: | files | file ages | folders |
SHA3-256: |
c61a46b561a527738084591912aee915 |
User & Date: | bohagan on 2024-12-31 04:12:42 |
Other Links: | branch diff | manifest | tags |
Context
2025-01-01
| ||
22:38 | Added demos directory with example scripts to download web pages and files using TLS. check-in: 0ebb44402a user: bohagan tags: trunk, main | |
2024-12-31
| ||
04:12 | More comment updates and changes for fast path option check-in: c61a46b561 user: bohagan tags: trunk, main | |
2024-12-29
| ||
04:36 | Added IO buffer checks to TlsChannelHandlerTimer mask function. Reordered TlsNotifyProc to check conditions prior to timer deletion. Pass buffer length in MessageCallback. check-in: 6252a3a1f5 user: bohagan tags: trunk, main | |
Changes
Modified generic/tls.c
from [1c80245128]
to [9f3b154f0e].
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 | * 1 = Command returned success or eval returned TCL_OK * * Side effects: * Evaluates callback command * *------------------------------------------------------------------- */ static int EvalCallback( Tcl_Interp *interp, /* Tcl interpreter */ State *statePtr, /* Client state for TLS socket */ Tcl_Obj *cmdPtr) /* Command to eval as a Tcl object */ { int code, ok = 0; | > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | * 1 = Command returned success or eval returned TCL_OK * * Side effects: * Evaluates callback command * *------------------------------------------------------------------- */ static int EvalCallback( Tcl_Interp *interp, /* Tcl interpreter */ State *statePtr, /* Client state for TLS socket */ Tcl_Obj *cmdPtr) /* Command to eval as a Tcl object */ { int code, ok = 0; |
︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 | * None * * Side effects: * Calls callback (if defined) * *------------------------------------------------------------------- */ static void InfoCallback( const SSL *ssl, /* SSL context */ int where, /* Source of info */ int ret) /* message enum */ { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); | > | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | * None * * Side effects: * Calls callback (if defined) * *------------------------------------------------------------------- */ static void InfoCallback( const SSL *ssl, /* SSL context */ int where, /* Source of info */ int ret) /* message enum */ { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); |
︙ | ︙ | |||
210 211 212 213 214 215 216 217 218 219 220 221 222 223 | * None * * Side effects: * Calls callback (if defined) * *------------------------------------------------------------------- */ #ifndef OPENSSL_NO_SSL_TRACE static void MessageCallback( int write_p, /* Message 0=received, 1=sent */ int version, /* TLS version */ int content_type, /* Protocol content type */ const void *buf, /* Protocol message */ | > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | * None * * Side effects: * Calls callback (if defined) * *------------------------------------------------------------------- */ #ifndef OPENSSL_NO_SSL_TRACE static void MessageCallback( int write_p, /* Message 0=received, 1=sent */ int version, /* TLS version */ int content_type, /* Protocol content type */ const void *buf, /* Protocol message */ |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 369 370 371 372 | * * Side effects: * The err field of the currently operative State is set * to a string describing the SSL negotiation failure reason * *------------------------------------------------------------------- */ static int VerifyCallback( int ok, /* Verify result */ X509_STORE_CTX *ctx) /* CTX context */ { Tcl_Obj *cmdPtr; SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); | > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 | * * Side effects: * The err field of the currently operative State is set * to a string describing the SSL negotiation failure reason * *------------------------------------------------------------------- */ static int VerifyCallback( int ok, /* Verify result */ X509_STORE_CTX *ctx) /* CTX context */ { Tcl_Obj *cmdPtr; SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
︙ | ︙ | |||
428 429 430 431 432 433 434 435 436 437 438 439 440 441 | * * Side effects: * The err field of the currently operative State is set to a * string describing the SSL negotiation failure reason * *------------------------------------------------------------------- */ void Tls_Error( State *statePtr, /* Client state for TLS socket */ const char *msg) /* Error message */ { Tcl_Interp *interp = statePtr->interp; Tcl_Obj *cmdPtr, *listPtr; | > | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | * * Side effects: * The err field of the currently operative State is set to a * string describing the SSL negotiation failure reason * *------------------------------------------------------------------- */ void Tls_Error( State *statePtr, /* Client state for TLS socket */ const char *msg) /* Error message */ { Tcl_Interp *interp = statePtr->interp; Tcl_Obj *cmdPtr, *listPtr; |
︙ | ︙ | |||
485 486 487 488 489 490 491 492 493 494 495 496 497 498 | * Write received key data to log file. * * Side effects: * none * *------------------------------------------------------------------- */ void KeyLogCallback( const SSL *ssl, /* Client state for TLS socket */ const char *line) /* Key data to be logged */ { char *str = getenv(SSLKEYLOGFILE); FILE *fd; | > | 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | * Write received key data to log file. * * Side effects: * none * *------------------------------------------------------------------- */ void KeyLogCallback( const SSL *ssl, /* Client state for TLS socket */ const char *line) /* Key data to be logged */ { char *str = getenv(SSLKEYLOGFILE); FILE *fd; |
︙ | ︙ | |||
521 522 523 524 525 526 527 528 529 530 531 532 533 534 | * Calls callback (if defined) * * Returns: * Password size in bytes or -1 for an error. * *------------------------------------------------------------------- */ static int PasswordCallback( char *buf, /* Pointer to buffer to store password in */ int size, /* Buffer length in bytes */ int rwflag, /* Whether password is needed for read or write */ void *udata) /* Client state for TLS socket */ { | > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 | * Calls callback (if defined) * * Returns: * Password size in bytes or -1 for an error. * *------------------------------------------------------------------- */ static int PasswordCallback( char *buf, /* Pointer to buffer to store password in */ int size, /* Buffer length in bytes */ int rwflag, /* Whether password is needed for read or write */ void *udata) /* Client state for TLS socket */ { |
︙ | ︙ | |||
605 606 607 608 609 610 611 612 613 614 615 616 617 618 | * * Return codes: * 0 = error where session will be immediately removed from the internal cache. * 1 = success where app retains session in session cache, and must call SSL_SESSION_free() when done. * *------------------------------------------------------------------- */ static int SessionCallback( SSL *ssl, /* SSL context */ SSL_SESSION *session) /* Session context */ { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); Tcl_Interp *interp = statePtr->interp; | > | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | * * Return codes: * 0 = error where session will be immediately removed from the internal cache. * 1 = success where app retains session in session cache, and must call SSL_SESSION_free() when done. * *------------------------------------------------------------------- */ static int SessionCallback( SSL *ssl, /* SSL context */ SSL_SESSION *session) /* Session context */ { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); Tcl_Interp *interp = statePtr->interp; |
︙ | ︙ | |||
677 678 679 680 681 682 683 684 685 686 687 688 689 690 | * SSL_TLSEXT_ERR_ALERT_FATAL: There was no overlap between the client's * supplied list and the server configuration. The connection will be aborted. * SSL_TLSEXT_ERR_NOACK: ALPN protocol not selected, e.g., because no ALPN * protocols are configured for this connection. The connection continues. * *------------------------------------------------------------------- */ static int ALPNCallback( SSL *ssl, /* SSL context */ const unsigned char **out, /* Return buffer to store selected protocol */ unsigned char *outlen, /* Return buffer size */ const unsigned char *in, /* Peer provided protocols */ unsigned int inlen, /* Peer buffer size */ | > | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | * SSL_TLSEXT_ERR_ALERT_FATAL: There was no overlap between the client's * supplied list and the server configuration. The connection will be aborted. * SSL_TLSEXT_ERR_NOACK: ALPN protocol not selected, e.g., because no ALPN * protocols are configured for this connection. The connection continues. * *------------------------------------------------------------------- */ static int ALPNCallback( SSL *ssl, /* SSL context */ const unsigned char **out, /* Return buffer to store selected protocol */ unsigned char *outlen, /* Return buffer size */ const unsigned char *in, /* Peer provided protocols */ unsigned int inlen, /* Peer buffer size */ |
︙ | ︙ | |||
751 752 753 754 755 756 757 758 759 760 761 762 763 764 | * * Return codes: * SSL_TLSEXT_ERR_OK: NPN protocol selected. The connection continues. * SSL_TLSEXT_ERR_NOACK: NPN protocol not selected. The connection continues. * *------------------------------------------------------------------- */ #ifdef USE_NPN static int NPNCallback( const SSL *ssl, /* SSL context */ const unsigned char **out, /* Return buffer to store selected protocol */ unsigned int *outlen, /* Return buffer size */ void *arg) /* Client state for TLS socket */ | > | 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 | * * Return codes: * SSL_TLSEXT_ERR_OK: NPN protocol selected. The connection continues. * SSL_TLSEXT_ERR_NOACK: NPN protocol not selected. The connection continues. * *------------------------------------------------------------------- */ #ifdef USE_NPN static int NPNCallback( const SSL *ssl, /* SSL context */ const unsigned char **out, /* Return buffer to store selected protocol */ unsigned int *outlen, /* Return buffer size */ void *arg) /* Client state for TLS socket */ |
︙ | ︙ | |||
805 806 807 808 809 810 811 812 813 814 815 816 817 818 | * SSL_TLSEXT_ERR_ALERT_WARNING: SNI hostname is not accepted, warning alert * sent (not supported in TLSv1.3). The connection continues. * SSL_TLSEXT_ERR_NOACK: SNI hostname is not accepted and not acknowledged, * e.g. if SNI has not been configured. The connection continues. * *------------------------------------------------------------------- */ static int SNICallback( const SSL *ssl, /* SSL context */ int *alert, /* Returned alert message */ void *arg) /* Client state for TLS socket */ { State *statePtr = (State*)arg; | > | 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 | * SSL_TLSEXT_ERR_ALERT_WARNING: SNI hostname is not accepted, warning alert * sent (not supported in TLSv1.3). The connection continues. * SSL_TLSEXT_ERR_NOACK: SNI hostname is not accepted and not acknowledged, * e.g. if SNI has not been configured. The connection continues. * *------------------------------------------------------------------- */ static int SNICallback( const SSL *ssl, /* SSL context */ int *alert, /* Returned alert message */ void *arg) /* Client state for TLS socket */ { State *statePtr = (State*)arg; |
︙ | ︙ | |||
881 882 883 884 885 886 887 888 889 890 891 892 893 894 | * Return codes: * SSL_CLIENT_HELLO_RETRY: suspend the handshake, and the handshake function will return immediately * SSL_CLIENT_HELLO_ERROR: failure, terminate connection. Set alert to error code. * SSL_CLIENT_HELLO_SUCCESS: success * *------------------------------------------------------------------- */ static int HelloCallback( SSL *ssl, /* SSL context */ int *alert, /* Returned alert message */ void *arg) /* Client state for TLS socket */ { State *statePtr = (State*)arg; | > | 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | * Return codes: * SSL_CLIENT_HELLO_RETRY: suspend the handshake, and the handshake function will return immediately * SSL_CLIENT_HELLO_ERROR: failure, terminate connection. Set alert to error code. * SSL_CLIENT_HELLO_SUCCESS: success * *------------------------------------------------------------------- */ static int HelloCallback( SSL *ssl, /* SSL context */ int *alert, /* Returned alert message */ void *arg) /* Client state for TLS socket */ { State *statePtr = (State*)arg; |
︙ | ︙ | |||
981 982 983 984 985 986 987 988 989 990 991 992 993 994 | * A standard Tcl result list. * * Side effects: * constructs and destroys SSL context (CTX) * *------------------------------------------------------------------- */ static const char *protocols[] = { "ssl2", "ssl3", "tls1", "tls1.1", "tls1.2", "tls1.3", NULL }; enum protocol { TLS_SSL2, TLS_SSL3, TLS_TLS1, TLS_TLS1_1, TLS_TLS1_2, TLS_TLS1_3, TLS_NONE }; | > | 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | * A standard Tcl result list. * * Side effects: * constructs and destroys SSL context (CTX) * *------------------------------------------------------------------- */ static const char *protocols[] = { "ssl2", "ssl3", "tls1", "tls1.1", "tls1.2", "tls1.3", NULL }; enum protocol { TLS_SSL2, TLS_SSL3, TLS_TLS1, TLS_TLS1_1, TLS_TLS1_2, TLS_TLS1_3, TLS_NONE }; |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | } statePtr = (State *)Tcl_GetChannelInstanceData(chan); dprintf("Calling Tls_WaitForConnect"); ret = Tls_WaitForConnect(statePtr, &err, 1); dprintf("Tls_WaitForConnect returned: %i", ret); | | | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | } statePtr = (State *)Tcl_GetChannelInstanceData(chan); dprintf("Calling Tls_WaitForConnect"); ret = Tls_WaitForConnect(statePtr, &err, 1); dprintf("Tls_WaitForConnect returned: %i", ret); if (ret <= 0 && ((statePtr->flags & TLS_TCL_ASYNC) && (err == EAGAIN))) { dprintf("Async set and err = EAGAIN"); ret = 0; } else if (ret < 0) { long result; errStr = statePtr->err; Tcl_ResetResult(interp); Tcl_SetErrno(err); |
︙ | ︙ | |||
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 | * Number of certificates loaded or 0 for none. * * Side effects: * Loads CA certificates * *------------------------------------------------------------------- */ static int TlsLoadClientCAFileFromMemory( Tcl_Interp *interp, /* Tcl interpreter */ SSL_CTX *ctx, /* CTX context */ Tcl_Obj *file) /* CA certificates filename */ { BIO *bio = NULL; | > | 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 | * Number of certificates loaded or 0 for none. * * Side effects: * Loads CA certificates * *------------------------------------------------------------------- */ static int TlsLoadClientCAFileFromMemory( Tcl_Interp *interp, /* Tcl interpreter */ SSL_CTX *ctx, /* CTX context */ Tcl_Obj *file) /* CA certificates filename */ { BIO *bio = NULL; |
︙ | ︙ | |||
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int StatusObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ int objc, /* Arg count */ Tcl_Obj *const objv[]) /* Arguments as Tcl objects */ { | > | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int StatusObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ int objc, /* Arg count */ Tcl_Obj *const objv[]) /* Arguments as Tcl objects */ { |
︙ | ︙ | |||
2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int VersionObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ TCL_UNUSED(int), /* objc - Arg count */ TCL_UNUSED(Tcl_Obj *const *)) /* objv - Arguments as Tcl objects */ { | > | 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int VersionObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ TCL_UNUSED(int), /* objc - Arg count */ TCL_UNUSED(Tcl_Obj *const *)) /* objv - Arguments as Tcl objects */ { |
︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int MiscObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ int objc, /* Arg count */ Tcl_Obj *const objv[]) /* Arguments as Tcl objects */ { | > | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 | * A standard Tcl result. * * Side effects: * None. * *------------------------------------------------------------------- */ static int MiscObjCmd( TCL_UNUSED(ClientData), /* Client data */ Tcl_Interp *interp, /* Tcl interpreter */ int objc, /* Arg count */ Tcl_Obj *const objv[]) /* Arguments as Tcl objects */ { |
︙ | ︙ | |||
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 | * none * * Side effects: * Frees all the state * *------------------------------------------------------------------- */ void Tls_Free( tls_free_type *blockPtr) /* Client state for TLS socket */ { State *statePtr = (State *)blockPtr; dprintf("Called"); | > | 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 | * none * * Side effects: * Frees all the state * *------------------------------------------------------------------- */ void Tls_Free( tls_free_type *blockPtr) /* Client state for TLS socket */ { State *statePtr = (State *)blockPtr; dprintf("Called"); |
︙ | ︙ | |||
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 | * none * * Side effects: * Frees all the state * *------------------------------------------------------------------- */ void Tls_Clean( State *statePtr) /* Client state for TLS socket */ { dprintf("Called"); /* * we're assuming here that we're single-threaded | > | 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 | * none * * Side effects: * Frees all the state * *------------------------------------------------------------------- */ void Tls_Clean( State *statePtr) /* Client state for TLS socket */ { dprintf("Called"); /* * we're assuming here that we're single-threaded |
︙ | ︙ | |||
3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 | * A standard TCL result * * Side effects: * Shutdown SSL library * *------------------------------------------------------* */ void TlsLibShutdown( ClientData clientData) /* Not used */ { dprintf("Called"); BIO_cleanup(); } | > | 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 | * A standard TCL result * * Side effects: * Shutdown SSL library * *------------------------------------------------------* */ void TlsLibShutdown( ClientData clientData) /* Not used */ { dprintf("Called"); BIO_cleanup(); } |
︙ | ︙ | |||
3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 | * A standard Tcl result * * Side effects: * Initializes SSL library * *------------------------------------------------------* */ static int TlsLibInit() { static int initialized = 0; dprintf("Called"); if (!initialized) { /* Initialize BOTH libcrypto and libssl. */ | > | 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 | * A standard Tcl result * * Side effects: * Initializes SSL library * *------------------------------------------------------* */ static int TlsLibInit() { static int initialized = 0; dprintf("Called"); if (!initialized) { /* Initialize BOTH libcrypto and libssl. */ |
︙ | ︙ | |||
3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 | * Same as of 'Tls_Init' * * Side effects: * Same as of 'Tls_Init' * *------------------------------------------------------------------- */ DLLEXPORT int Tls_SafeInit( Tcl_Interp *interp) /* Tcl interpreter */ { dprintf("Called"); return Tls_Init(interp); } | > | 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 | * Same as of 'Tls_Init' * * Side effects: * Same as of 'Tls_Init' * *------------------------------------------------------------------- */ DLLEXPORT int Tls_SafeInit( Tcl_Interp *interp) /* Tcl interpreter */ { dprintf("Called"); return Tls_Init(interp); } |
Modified generic/tlsBIO.c
from [201a06bc4e]
to [9efb936c9c].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* * Provides Custom BIO layer to interface OpenSSL with TCL. These functions * directly interface between the TCL IO channel and BIO buffers. * * Copyright (C) 1997-2000 Matt Newman <[email protected]> * Copyright (C) 2024 Brian O'Hagan * */ /* tlsBIO.c tlsIO.c +------+ +---+ +---+ | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | |socket| <encrypted> |BIO| <unencrypted> |App| | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | +------+ +---+ +---+ */ #include "tlsInt.h" #include <openssl/bio.h> /* Define BIO methods structure */ static BIO_METHOD *BioMethods = NULL; | > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /* * Provides Custom BIO layer to interface OpenSSL with TCL. These functions * directly interface between the TCL IO channel and BIO buffers. * * Copyright (C) 1997-2000 Matt Newman <[email protected]> * Copyright (C) 2024 Brian O'Hagan * */ /* Normal tlsBIO.c tlsIO.c +------+ +---+ +---+ | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | |socket| <encrypted> |BIO| <unencrypted> |App| | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | +------+ +---+ +---+ Fast Path tlsIO.c +------+ +-----+ +-----+ | |<-- write <--| SSL |BIO_write <-- TlsOutputProc <-- Write| | |socket| <encrypted> | BIO | <unencrypted> | App | | |<-- read <--| |BIO_Read --> TlsInputProc --> Read| | +------+ +-----+ +-----+ */ #include "tlsInt.h" #include <openssl/bio.h> /* Define BIO methods structure */ static BIO_METHOD *BioMethods = NULL; |
︙ | ︙ |
Modified generic/tlsIO.c
from [a3e847176e]
to [fc485d2835].
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | * Also work done by the follow people provided the impetus to do this "right": * tclSSL (Colin McCormack, Shared Technology) * SSLtcl (Peter Antman) * */ /* tlsBIO.c tlsIO.c +------+ +---+ +---+ | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | |socket| <encrypted> |BIO| <unencrypted> |App| | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | +------+ +---+ +---+ */ #include "tlsInt.h" #include <errno.h> /* *----------------------------------------------------------------------------- | > > > > > > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | * Also work done by the follow people provided the impetus to do this "right": * tclSSL (Colin McCormack, Shared Technology) * SSLtcl (Peter Antman) * */ /* Normal tlsBIO.c tlsIO.c +------+ +---+ +---+ | |Tcl_WriteRaw<--BioOutput|SSL|BIO_write<--TlsOutputProc<--Write| | |socket| <encrypted> |BIO| <unencrypted> |App| | |Tcl_ReadRaw --> BioInput| |BIO_Read -->TlsInputProc --> Read| | +------+ +---+ +---+ Fast Path tlsIO.c +------+ +-----+ +-----+ | |<-- write <--| SSL |BIO_write <-- TlsOutputProc <-- Write| | |socket| <encrypted> | BIO | <unencrypted> | App | | |<-- read <--| |BIO_Read --> TlsInputProc --> Read| | +------+ +-----+ +-----+ */ #include "tlsInt.h" #include <errno.h> /* *----------------------------------------------------------------------------- |
︙ | ︙ | |||
216 217 218 219 220 221 222 | bioShouldRetry = 1; } else if (rc == SSL_ERROR_WANT_READ) { bioShouldRetry = 1; statePtr->want |= TCL_READABLE; } else if (rc == SSL_ERROR_WANT_WRITE) { bioShouldRetry = 1; statePtr->want |= TCL_WRITABLE; | < < < < | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | bioShouldRetry = 1; } else if (rc == SSL_ERROR_WANT_READ) { bioShouldRetry = 1; statePtr->want |= TCL_READABLE; } else if (rc == SSL_ERROR_WANT_WRITE) { bioShouldRetry = 1; statePtr->want |= TCL_WRITABLE; } } if (bioShouldRetry) { dprintf("The I/O did not complete -- but we should try it again"); if (statePtr->flags & TLS_TCL_ASYNC) { |
︙ | ︙ | |||
243 244 245 246 247 248 249 | dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though"); break; } switch (rc) { case SSL_ERROR_NONE: /* The TLS/SSL I/O operation completed successfully */ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though"); break; } switch (rc) { case SSL_ERROR_NONE: /* The TLS/SSL I/O operation completed successfully */ dprintf("SSL_ERROR_NONE"); *errorCodePtr = 0; break; case SSL_ERROR_SSL: /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error. This includes certificate validation errors. */ dprintf("SSL_ERROR_SSL: Fatal SSL protocol error occurred"); if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED; *errorCodePtr = ECONNABORTED; return -1; case SSL_ERROR_WANT_READ: /* More data must be read from the underlying BIO layer in order to complete the actual SSL_*() operation. */ dprintf("SSL_ERROR_WANT_READ"); BIO_set_retry_read(statePtr->bio); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_READ, EAGAIN)"); statePtr->want |= TCL_READABLE; return 0; case SSL_ERROR_WANT_WRITE: /* There is data in the SSL buffer that must be written to the underlying BIO in order to complete the SSL_*() operation. */ dprintf("SSL_ERROR_WANT_WRITE"); BIO_set_retry_write(statePtr->bio); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_WRITE, EAGAIN)"); statePtr->want |= TCL_WRITABLE; return 0; case SSL_ERROR_WANT_X509_LOOKUP: /* The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again. */ dprintf("SSL_ERROR_WANT_X509_LOOKUP"); BIO_set_retry_special(statePtr->bio); BIO_set_retry_reason(statePtr->bio, BIO_RR_SSL_X509_LOOKUP); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_X509_LOOKUP, EAGAIN)"); return 0; case SSL_ERROR_SYSCALL: /* Some non-recoverable, fatal I/O error occurred */ dprintf("SSL_ERROR_SYSCALL: Fatal I/O error occurred"); if (backingError == 0 && err == 0) { dprintf("EOF reached") *errorCodePtr = ECONNRESET; Tls_Error(statePtr, "(unexpected) EOF reached"); } else if (backingError == 0 && err == -1) { |
︙ | ︙ | |||
293 294 295 296 297 298 299 | Tls_Error(statePtr, ERR_reason_error_string(backingError)); } statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED; return -1; case SSL_ERROR_ZERO_RETURN: | | | | | | < < < < < < < < | < < < < < < < < < | < < | | > | < < < < < < < < < < < < | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | Tls_Error(statePtr, ERR_reason_error_string(backingError)); } statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED; return -1; case SSL_ERROR_ZERO_RETURN: /* Peer has cleanly closed the connection by sending the close_notify alert. Can't read, but can write. Need to return an EOF, so the channel is closed which will send an SSL_shutdown(). */ dprintf("SSL_ERROR_ZERO_RETURN: Peer has closed the connection"); *errorCodePtr = ECONNRESET; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); return -1; case SSL_ERROR_WANT_CONNECT: /* The operation did not complete and connect would have blocked. Retry again after connection is established. */ dprintf("SSL_ERROR_WANT_CONNECT"); BIO_set_retry_special(statePtr->bio); BIO_set_retry_reason(statePtr->bio, BIO_RR_CONNECT); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_CONNECT, EAGAIN)"); return 0; case SSL_ERROR_WANT_ACCEPT: /* The operation did not complete and accept would have blocked. Retry again after connection is established. */ dprintf("SSL_ERROR_WANT_ACCEPT"); BIO_set_retry_special(statePtr->bio); BIO_set_retry_reason(statePtr->bio, BIO_RR_ACCEPT); *errorCodePtr = EAGAIN; dprintf("ERR(SSL_ERROR_WANT_ACCEPT, EAGAIN)"); return 0; case SSL_ERROR_WANT_ASYNC: /* Used with flag SSL_MODE_ASYNC, op didn't complete because an async engine is still processing data */ case SSL_ERROR_WANT_ASYNC_JOB: /* The asynchronous job could not be started because there were no async jobs available in the pool. */ case SSL_ERROR_WANT_CLIENT_HELLO_CB: /* The operation did not complete because an application callback set by SSL_CTX_set_client_hello_cb() has asked to be called again. */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L case SSL_ERROR_WANT_RETRY_VERIFY: /* The operation did not complete because a certificate verification callback has asked to be called again via SSL_set_retry_verify(3). */ #endif default: /* The operation did not complete and should be retried later. */ dprintf("Operation did not complete, call function again later"); *errorCodePtr = EAGAIN; dprintf("ERR(Other, EAGAIN)"); return 0; } dprintf("Removing the \"TLS_TCL_INIT\" flag since we have completed the handshake"); statePtr->flags &= ~TLS_TCL_INIT; dprintf("Returning success"); |
︙ | ︙ | |||
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | if (statePtr->flags & TLS_TCL_INIT) { int tlsConnect; dprintf("Calling Tls_WaitForConnect"); tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 0); if (tlsConnect < 0) { dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr); bytesRead = -1; if (*errorCodePtr == ECONNRESET) { dprintf("Got connection reset"); /* Soft EOF */ *errorCodePtr = 0; bytesRead = 0; } return bytesRead; } } /* * We need to clear the SSL error stack now because we sometimes reach * this function with leftover errors in the stack. If BIO_read | > > > > > | 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | if (statePtr->flags & TLS_TCL_INIT) { int tlsConnect; dprintf("Calling Tls_WaitForConnect"); tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 0); if (tlsConnect < 0) { /* Failure, so abort */ dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr); bytesRead = -1; if (*errorCodePtr == ECONNRESET) { dprintf("Got connection reset"); /* Soft EOF */ *errorCodePtr = 0; bytesRead = 0; } return bytesRead; } else if (tlsConnect == 0) { /* Try again */ bytesRead = -1; return bytesRead; } } /* * We need to clear the SSL error stack now because we sometimes reach * this function with leftover errors in the stack. If BIO_read |
︙ | ︙ | |||
489 490 491 492 493 494 495 | dprintf("BIO has pending data to write"); statePtr->want |= TCL_WRITABLE; } if (BIO_should_io_special(statePtr->bio)) { int reason = BIO_get_retry_reason(statePtr->bio); dprintf("BIO has some special condition other than read or write: code=%d", reason); } | < | | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | dprintf("BIO has pending data to write"); statePtr->want |= TCL_WRITABLE; } if (BIO_should_io_special(statePtr->bio)) { int reason = BIO_get_retry_reason(statePtr->bio); dprintf("BIO has some special condition other than read or write: code=%d", reason); } } switch (err) { case SSL_ERROR_NONE: /* I/O operation completed */ dprintf("SSL_ERROR_NONE"); dprintBuffer(buf, bytesRead); break; case SSL_ERROR_SSL: /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error. */ dprintf("SSL_ERROR_SSL: Fatal SSL protocol error occurred"); if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } else if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } else { Tls_Error(statePtr, "Unknown SSL error"); |
︙ | ︙ | |||
546 547 548 549 550 551 552 | *errorCodePtr = EAGAIN; bytesRead = -1; statePtr->want |= TCL_WRITABLE; BIO_set_retry_write(statePtr->bio); break; case SSL_ERROR_WANT_X509_LOOKUP: | | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | *errorCodePtr = EAGAIN; bytesRead = -1; statePtr->want |= TCL_WRITABLE; BIO_set_retry_write(statePtr->bio); break; case SSL_ERROR_WANT_X509_LOOKUP: /* The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again. */ dprintf("Got SSL_ERROR_WANT_X509_LOOKUP, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = -1; break; case SSL_ERROR_SYSCALL: /* Some non-recoverable, fatal I/O error occurred */ dprintf("SSL_ERROR_SYSCALL: Fatal I/O error occurred"); if (backingError == 0 && bytesRead == 0) { /* Unexpected EOF from the peer for OpenSSL 1.1 */ dprintf("(Unexpected) EOF reached") *errorCodePtr = 0; bytesRead = 0; Tls_Error(statePtr, "EOF reached"); |
︙ | ︙ | |||
580 581 582 583 584 585 586 | *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: | | | | | | | 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 | *errorCodePtr = Tcl_GetErrno(); bytesRead = -1; Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: /* Peer has cleanly closed the connection by sending the close_notify alert. Can't read, but can write. Need to return an EOF, so the channel is closed which will send an SSL_shutdown(). */ dprintf("SSL_ERROR_ZERO_RETURN: Peer has closed the connection"); bytesRead = 0; *errorCodePtr = 0; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); break; case SSL_ERROR_WANT_ASYNC: /* Used with flag SSL_MODE_ASYNC, operation didn't complete because an async engine is still processing data. */ dprintf("Got SSL_ERROR_WANT_ASYNC, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; bytesRead = 0; break; default: dprintf("Unknown error (err = %i), mapping to EOF", err); *errorCodePtr = 0; bytesRead = 0; Tls_Error(statePtr, "Unknown error"); |
︙ | ︙ | |||
670 671 672 673 674 675 676 677 678 679 680 681 682 683 | if (*errorCodePtr == ECONNRESET) { dprintf("Got connection reset"); /* Soft EOF */ *errorCodePtr = 0; written = 0; } return written; } } if (toWrite == 0) { dprintf("zero-write"); err = BIO_flush(statePtr->bio); | > > > > | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | if (*errorCodePtr == ECONNRESET) { dprintf("Got connection reset"); /* Soft EOF */ *errorCodePtr = 0; written = 0; } return written; } else if (tlsConnect == 0) { /* Try again */ written = -1; return written; } } if (toWrite == 0) { dprintf("zero-write"); err = BIO_flush(statePtr->bio); |
︙ | ︙ | |||
732 733 734 735 736 737 738 | if (BIO_should_write(statePtr->bio)) { dprintf("BIO has pending data to write"); } if (BIO_should_io_special(statePtr->bio)) { int reason = BIO_get_retry_reason(statePtr->bio); dprintf("BIO has some special condition other than read or write: code=%d", reason); } | < | | | | | | | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | if (BIO_should_write(statePtr->bio)) { dprintf("BIO has pending data to write"); } if (BIO_should_io_special(statePtr->bio)) { int reason = BIO_get_retry_reason(statePtr->bio); dprintf("BIO has some special condition other than read or write: code=%d", reason); } } else { BIO_flush(statePtr->bio); } switch (err) { case SSL_ERROR_NONE: /* I/O operation completed */ dprintf("SSL_ERROR_NONE"); if (written < 0) { written = 0; } break; case SSL_ERROR_SSL: /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error */ dprintf("SSL_ERROR_SSL: Fatal SSL protocol error occurred"); if (backingError != 0) { Tls_Error(statePtr, ERR_reason_error_string(backingError)); } else if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) { Tls_Error(statePtr, X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl))); } else { Tls_Error(statePtr, "Unknown SSL error"); } *errorCodePtr = ECONNABORTED; written = -1; break; case SSL_ERROR_WANT_READ: /* Operation did not complete due to not enough data was available. Retry again later with same data. */ dprintf("Got SSL_ERROR_WANT_READ, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; statePtr->want |= TCL_READABLE; BIO_set_retry_read(statePtr->bio); break; case SSL_ERROR_WANT_WRITE: /* Operation did not complete due to unable to send all data to the BIO. Retry later with same data. */ dprintf("Got SSL_ERROR_WANT_WRITE, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; statePtr->want |= TCL_WRITABLE; BIO_set_retry_write(statePtr->bio); break; case SSL_ERROR_WANT_X509_LOOKUP: /* The operation did not complete because an application callback set by SSL_CTX_set_client_cert_cb() has asked to be called again. */ dprintf("Got SSL_ERROR_WANT_X509_LOOKUP, mapping it to EAGAIN"); *errorCodePtr = EAGAIN; written = -1; break; case SSL_ERROR_SYSCALL: /* Some non-recoverable, fatal I/O error occurred */ dprintf("SSL_ERROR_SYSCALL: Fatal I/O error occurred"); if (backingError == 0 && written == 0) { dprintf("EOF reached") *errorCodePtr = 0; written = 0; Tls_Error(statePtr, "EOF reached"); |
︙ | ︙ | |||
816 817 818 819 820 821 822 | *errorCodePtr = Tcl_GetErrno(); written = -1; Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: | | | | | | | | | 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | *errorCodePtr = Tcl_GetErrno(); written = -1; Tls_Error(statePtr, ERR_reason_error_string(backingError)); } break; case SSL_ERROR_ZERO_RETURN: /* Peer has cleanly closed the connection by sending the close_notify alert. Can't read, but can write. Need to return an EOF, so the channel is closed which will send an SSL_shutdown(). */ dprintf("SSL_ERROR_ZERO_RETURN: Peer has closed the connection"); *errorCodePtr = 0; written = 0; Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert"); break; case SSL_ERROR_WANT_ASYNC: /* Used with flag SSL_MODE_ASYNC, operation didn't complete because an async engine is still processing data. */ dprintf("Got SSL_ERROR_WANT_ASYNC, mapping this to EAGAIN"); *errorCodePtr = EAGAIN; written = 0; break; default: dprintf("unknown error: %d", err); Tls_Error(statePtr, "Unknown error"); break; } |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 | */ static void TlsWatchProc( ClientData instanceData, /* Connection state info */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and TCL_EXCEPTION. */ { | | | 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 | */ static void TlsWatchProc( ClientData instanceData, /* Connection state info */ int mask) /* Events of interest; an OR-ed combination of * TCL_READABLE, TCL_WRITABLE and TCL_EXCEPTION. */ { Tcl_Channel parent; State *statePtr = (State *) instanceData; Tcl_DriverWatchProc *watchProc; int pending = 0; dprintf("Called with mask 0x%02x", mask); dprintFlags(statePtr); |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | watchProc(Tcl_GetChannelInstanceData(parent), 0); statePtr->watchMask = 0; return; } statePtr->watchMask = mask; | > | | > | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 | watchProc(Tcl_GetChannelInstanceData(parent), 0); statePtr->watchMask = 0; return; } statePtr->watchMask = mask; /* * No channel handlers any more. We will be notified automatically about * events on the channel below via a call to our 'TransformNotifyProc'. But * we have to pass the interest down now. We are allowed to add additional * 'interest' to the mask if we want to, but this transformation has no * such interest. It just passes the request down, unchanged. */ dprintf("Registering our interest in the lower channel (chan=%p)", (void *) parent); watchProc = Tcl_ChannelWatchProc(Tcl_GetChannelType(parent)); watchProc(Tcl_GetChannelInstanceData(parent), mask); /* Do we have any pending data */ pending = (statePtr->want || \ ((mask & TCL_READABLE) && ((Tcl_InputBuffered(statePtr->self) > 0) || (BIO_ctrl_pending(statePtr->bio) > 0))) || ((mask & TCL_WRITABLE) && ((Tcl_OutputBuffered(statePtr->self) > 0) || (BIO_ctrl_wpending(statePtr->bio) > 0)))); dprintf("IO Want=%d, input buffer=%d, output buffer=%d, BIO pending=%zd, BIO wpending=%zd, pending=%d", \ statePtr->want, Tcl_InputBuffered(statePtr->self), Tcl_OutputBuffered(statePtr->self), \ BIO_ctrl_pending(statePtr->bio), BIO_ctrl_wpending(statePtr->bio), pending); /* Schedule next event if data is pending, otherwise cease events for now */ if (!(mask & TCL_READABLE) || pending == 0) { /* Remove timer, if any */ if (statePtr->timer != (Tcl_TimerToken) NULL) { dprintf("A timer was found, deleting it"); Tcl_DeleteTimerHandler(statePtr->timer); statePtr->timer = (Tcl_TimerToken) NULL; } |
︙ | ︙ | |||
1182 1183 1184 1185 1186 1187 1188 | } } /* * Delete an existing timer. It was not fired, yet we are here, so the * channel below generated such an event and we don't have to. The renewal * of the interest after the execution of channel handlers will eventually | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | } } /* * Delete an existing timer. It was not fired, yet we are here, so the * channel below generated such an event and we don't have to. The renewal * of the interest after the execution of channel handlers will eventually * cause us to recreate the timer (in TlsWatchProc). */ if (statePtr->timer != (Tcl_TimerToken) NULL) { Tcl_DeleteTimerHandler(statePtr->timer); statePtr->timer = (Tcl_TimerToken) NULL; } /* |
︙ | ︙ |