Check-in [6866efe8ea]
Overview
Comment:Disabled skip channel IO during verify callback processing. Call Tcl_Error for connect/handshake errors.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | errors_and_callbacks
Files: files | file ages | folders
SHA3-256: 6866efe8eac051282531eefa05935b9df9a24aad5fdc7c112a4fecf959715fa2
User & Date: bohagan on 2023-07-28 17:01:07
Other Links: branch diff | manifest | tags
Context
2023-07-28
18:41
Set/get invalid channel option now calls Tcl_BadChannelOption. check-in: 106dba31ae user: bohagan tags: errors_and_callbacks
17:01
Disabled skip channel IO during verify callback processing. Call Tcl_Error for connect/handshake errors. check-in: 6866efe8ea user: bohagan tags: errors_and_callbacks
16:07
Refactored Tls_Error handler to not set errorCode. Use error message, return result, or if none, fall-back to OpenSSL error queue. Added clear OpenSSL errors to start of each command function to remove old error messages. check-in: e85a439068 user: bohagan tags: errors_and_callbacks
Changes
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
316
317
318
319
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
316
317
318
319
320







+
-
+






-
+



















-
+







	Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1));
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(depth));
    Tcl_ListObjAppendElement(interp, cmdPtr, Tls_NewX509Obj(interp, cert));
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewIntObj(ok));
    Tcl_ListObjAppendElement(interp, cmdPtr,
	Tcl_NewStringObj((char*)X509_verify_cert_error_string(err), -1));

    /* Prevent I/O while callback is in progress */
    statePtr->flags |= TLS_TCL_CALLBACK;
    /* statePtr->flags |= TLS_TCL_CALLBACK; */

    /* Eval callback command */
    Tcl_IncrRefCount(cmdPtr);
    ok = EvalCallback(interp, statePtr, cmdPtr);
    Tcl_DecrRefCount(cmdPtr);

    statePtr->flags &= ~(TLS_TCL_CALLBACK);
    /* statePtr->flags &= ~(TLS_TCL_CALLBACK); */
    return(ok);	/* By default, leave verification unchanged. */
}

/*
 *-------------------------------------------------------------------
 *
 * Tls_Error --
 *
 *	Calls callback with list of errors.
 *
 * 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, char *msg) {
    Tcl_Interp *interp	= statePtr->interp;
    Tcl_Obj *cmdPtr, listPtr;
    Tcl_Obj *cmdPtr, *listPtr;
    unsigned long err;
    statePtr->err = msg;

    dprintf("Called");

    if (statePtr->callback == (Tcl_Obj*)NULL)
	return;
329
330
331
332
333
334
335
336

337
338
339
340
341
342
343
330
331
332
333
334
335
336

337
338
339
340
341
342
343
344







-
+








    } else if ((msg = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), NULL)) != NULL) {
	Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(msg, -1));

    } else {
	listPtr = Tcl_NewListObj(0, NULL);
	while ((err = ERR_get_error()) != 0) {
	    Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(ERR_reason_error_string(err, -1));
	    Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(ERR_reason_error_string(err), -1));
	}
	Tcl_ListObjAppendElement(interp, cmdPtr, listPtr);
    }

    /* Eval callback command */
    Tcl_IncrRefCount(cmdPtr);
    EvalCallback(interp, statePtr, cmdPtr);
355
356
357
358
359
360
361



362
363
364
365
366
367
368
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372







+
+
+







 *	none
 *
 *-------------------------------------------------------------------
 */
void KeyLogCallback(const SSL *ssl, const char *line) {
    char *str = getenv(SSLKEYLOGFILE);
    FILE *fd;

    dprintf("Called");

    if (str) {
	fd = fopen(str, "a");
	fprintf(fd, "%s\n",line);
	fclose(fd);
    }
}

382
383
384
385
386
387
388

389
390
391
392
393
394
395
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400







+







    State *statePtr	= (State *) udata;
    Tcl_Interp *interp	= statePtr->interp;
    Tcl_Obj *cmdPtr;
    int code;

    dprintf("Called");

    /* If no callback, use default callback */
    if (statePtr->password == NULL) {
	if (Tcl_EvalEx(interp, "tls::password", -1, TCL_EVAL_GLOBAL) == TCL_OK) {
	    char *ret = (char *) Tcl_GetStringResult(interp);
	    strncpy(buf, ret, (size_t) size);
	    return (int)strlen(ret);
	} else {
	    return -1;
14
15
16
17
18
19
20

21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28







+







 * Also work done by the follow people provided the impetus to do this "right":
 *    tclSSL (Colin McCormack, Shared Technology)
 *    SSLtcl (Peter Antman)
 *
 */

#include "tlsInt.h"
#include <errno.h>

/*
 * Forward declarations
 */
static void TlsChannelHandlerTimer(ClientData clientData);

/*
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127
108
109
110
111
112
113
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128







+






-







 *
 *------------------------------------------------------*
 */
int Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent) {
    unsigned long backingError;
    int err, rc;
    int bioShouldRetry;
    *errorCodePtr = 0;

    dprintf("WaitForConnect(%p)", (void *) statePtr);
    dprintFlags(statePtr);

    if (!(statePtr->flags & TLS_TCL_INIT)) {
	dprintf("Tls_WaitForConnect called on already initialized channel -- returning with immediate success");
	*errorCodePtr = 0;
	return(0);
    }

    if (statePtr->flags & TLS_TCL_HANDSHAKE_FAILED) {
	/*
	 * Different types of operations have different requirements
	 * SSL being established
191
192
193
194
195
196
197
198
199
200
201
202
203

204
205
206


207
208
209
210
211
212
213
192
193
194
195
196
197
198


199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214







-
-




+


-
+
+







	    }
	}

	dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though");
	break;
    }

    *errorCodePtr = EINVAL;

    switch (rc) {
	case SSL_ERROR_NONE:
	    /* The connection is up, we are done here */
	    dprintf("The connection is up");
	    *errorCodePtr = 0;
	    break;
	case SSL_ERROR_ZERO_RETURN:
	    dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value...")
	    dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value...");
	    *errorCodePtr = EINVAL;
	    return(-1);
	case SSL_ERROR_SYSCALL:
	    backingError = ERR_get_error();

	    if (backingError == 0 && err == 0) {
		dprintf("EOF reached")
		*errorCodePtr = ECONNRESET;
304
305
306
307
308
309
310

311
312
313
314
315
316
317
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319







+







	return(0);
    }

    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);
	Tls_Error(statePtr, strerror(*errorCodePtr));

	bytesRead = -1;
	if (*errorCodePtr == ECONNRESET) {
	    dprintf("Got connection reset");
	    /* Soft EOF */
	    *errorCodePtr = 0;
	    bytesRead = 0;
391
392
393
394
395
396
397



398
399
400
401
402
403
404
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409







+
+
+







	default:
	    dprintf("Unknown error (err = %i), mapping to EOF", err);
	    *errorCodePtr = 0;
	    bytesRead = 0;
	    break;
    }

    if (*errorCodePtr < 0) {
	Tls_Error(statePtr, strerror(*errorCodePtr));
    }
    dprintf("Input(%d) -> %d [%d]", bufSize, bytesRead, *errorCodePtr);
    return(bytesRead);
}

/*
 *-------------------------------------------------------------------
 *
434
435
436
437
438
439
440

441
442
443
444
445
446
447
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453







+







	return(-1);
    }

    dprintf("Calling Tls_WaitForConnect");
    tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 1);
    if (tlsConnect < 0) {
	dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr);
	Tls_Error(statePtr, strerror(*errorCodePtr));

	written = -1;
	if (*errorCodePtr == ECONNRESET) {
	    dprintf("Got connection reset");
	    /* Soft EOF */
	    *errorCodePtr = 0;
	    written = 0;
534
535
536
537
538
539
540



541
542
543
544
545
546
547
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556







+
+
+







	    break;

	default:
	    dprintf(" unknown err: %d", err);
	    break;
    }

    if (*errorCodePtr < 0) {
	Tls_Error(statePtr, strerror(*errorCodePtr));
    }
    dprintf("Output(%d) -> %d", toWrite, written);
    return(written);
}

/*
 *-------------------------------------------------------------------
 *
773
774
775
776
777
778
779

780
781
782
783
784
785
786
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796







+







	dprintf("Returning 0 due to callback");
	return 0;
    }

    dprintf("Calling Tls_WaitForConnect");
    errorCode = 0;
    if (Tls_WaitForConnect(statePtr, &errorCode, 1) < 0) {
	Tls_Error(statePtr, strerror(errorCode));
	if (errorCode == EAGAIN) {
	    dprintf("Async flag could be set (didn't check) and errorCode == EAGAIN:  Returning 0");

	    return 0;
	}

	dprintf("Tls_WaitForConnect returned an error");