Check-in [b9557ba691]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Updated to return soft errors on during SSL negotiation retries on reads and hard errors on SSL negotiation during writes or handshake commands
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:b9557ba6915d78e12d5674fbd2ad3076183e1344
User & Date: rkeene 2016-12-13 16:00:41
Context
2016-12-13
16:11
Fixed weird asymmetry in build of tls.tcl.h, which was required for out-of-tree builds check-in: 05099e9a1e user: rkeene tags: trunk
16:05
Merged in trunk check-in: 53bd8f71ad user: rkeene tags: tls-1-7
16:00
Updated to return soft errors on during SSL negotiation retries on reads and hard errors on SSL negotiation during writes or handshake commands check-in: b9557ba691 user: rkeene tags: trunk
15:43
Made repeated failures to handshake return fatal errors and made handshake code use the same logic as the rest of the OpenSSL read error checking check-in: 1b7959d27a user: rkeene tags: trunk
Changes

Changes to tls.c.

   632    632       Tcl_Interp *interp;
   633    633       int objc;
   634    634       Tcl_Obj *CONST objv[];
   635    635   {
   636    636       Tcl_Channel chan;		/* The channel to set a mode on. */
   637    637       State *statePtr;		/* client state for ssl socket */
   638    638       int ret = 1;
          639  +    int err = 0;
   639    640   
   640    641       dprintf("Called");
   641    642   
   642    643       if (objc != 2) {
   643    644   	Tcl_WrongNumArgs(interp, 1, objv, "channel");
   644    645   	return TCL_ERROR;
   645    646       }
................................................................................
   656    657       if (Tcl_GetChannelType(chan) != Tls_ChannelType()) {
   657    658   	Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan),
   658    659   		"\": not a TLS channel", NULL);
   659    660   	return TCL_ERROR;
   660    661       }
   661    662       statePtr = (State *)Tcl_GetChannelInstanceData(chan);
   662    663   
   663         -    if (!SSL_is_init_finished(statePtr->ssl)) {
   664         -	int err = 0;
   665    664           dprintf("Calling Tls_WaitForConnect");
   666         -	ret = Tls_WaitForConnect(statePtr, &err);
          665  +	ret = Tls_WaitForConnect(statePtr, &err, 1);
   667    666           dprintf("Tls_WaitForConnect returned: %i", ret);
   668    667   
          668  +     if (ret < 0) {
   669    669   	if ((statePtr->flags & TLS_TCL_ASYNC) && err == EAGAIN) {
   670    670               dprintf("Async set and err = EAGAIN");
   671    671   	    ret = 0;
   672    672   	}
          673  +     }
   673    674   
   674    675   	if (ret < 0) {
   675    676   	    CONST char *errStr = statePtr->err;
   676    677   	    Tcl_ResetResult(interp);
   677    678   	    Tcl_SetErrno(err);
   678    679   
   679    680   	    if (!errStr || *errStr == 0) {
   680    681   		errStr = Tcl_PosixError(interp);
   681    682   	    }
   682    683   
   683    684   	    Tcl_AppendResult(interp, "handshake failed: ", errStr, (char *) NULL);
   684    685               dprintf("Returning TCL_ERROR with handshake failed: %s", errStr);
   685    686   	    return TCL_ERROR;
   686         -	}
   687         -    }
          687  +	} else {
          688  +          ret = 1;
          689  +        }
   688    690   
          691  +    dprintf("Returning TCL_OK with data \"%i\"", ret);
   689    692       Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
   690    693       return TCL_OK;
   691    694       	clientData = clientData;
   692    695   }
   693    696   
   694    697   /*
   695    698    *-------------------------------------------------------------------

Changes to tlsIO.c.

   171    171   	dprintf("Returning TCL_OK");
   172    172   
   173    173   	return(TCL_OK);
   174    174   
   175    175   	/* Interp is unused. */
   176    176   	interp = interp;
   177    177   }
          178  +
          179  +/*
          180  + *------------------------------------------------------*
          181  + *
          182  + *	Tls_WaitForConnect --
          183  + *
          184  + *	Sideeffects:
          185  + *		Issues SSL_accept or SSL_connect
          186  + *
          187  + *	Result:
          188  + *		None.
          189  + *
          190  + *------------------------------------------------------*
          191  + */
          192  +int Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent) {
          193  +	unsigned long backingError;
          194  +	int err, rc;
          195  +	int bioShouldRetry;
          196  +
          197  +	dprintf("WaitForConnect(%p)", (void *) statePtr);
          198  +	dprintFlags(statePtr);
          199  +
          200  +	if (!(statePtr->flags & TLS_TCL_INIT)) {
          201  +		dprintf("Tls_WaitForConnect called on already initialized channel -- returning with immediate success");
          202  +		*errorCodePtr = 0;
          203  +		return(0);
          204  +	}
          205  +
          206  +	if (statePtr->flags & TLS_TCL_HANDSHAKE_FAILED) {
          207  +		/*
          208  +		 * Different types of operations have different requirements
          209  +		 * SSL being established
          210  +		 */
          211  +		if (handshakeFailureIsPermanent) {
          212  +			dprintf("Asked to wait for a TLS handshake that has already failed.  Returning fatal error");
          213  +			*errorCodePtr = ECONNABORTED;
          214  +		} else {
          215  +			dprintf("Asked to wait for a TLS handshake that has already failed.  Returning soft error");
          216  +			*errorCodePtr = ECONNRESET;
          217  +		}
          218  +		return(-1);
          219  +	}
          220  +
          221  +	for (;;) {
          222  +		/* Not initialized yet! */
          223  +		if (statePtr->flags & TLS_TCL_SERVER) {
          224  +			dprintf("Calling SSL_accept()");
          225  +
          226  +			err = SSL_accept(statePtr->ssl);
          227  +		} else {
          228  +			dprintf("Calling SSL_connect()");
          229  +
          230  +			err = SSL_connect(statePtr->ssl);
          231  +		}
          232  +
          233  +		if (err > 0) {
          234  +			dprintf("That seems to have gone okay");
          235  +
          236  +			err = BIO_flush(statePtr->bio);
          237  +
          238  +			if (err <= 0) {
          239  +				dprintf("Flushing the lower layers failed, this will probably terminate this session");
          240  +			}
          241  +		}
          242  +
          243  +		rc = SSL_get_error(statePtr->ssl, err);
          244  +
          245  +		dprintf("Got error: %i (rc = %i)", err, rc);
          246  +
          247  +		bioShouldRetry = 0;
          248  +		if (err <= 0) {
          249  +			if (rc == SSL_ERROR_WANT_CONNECT || rc == SSL_ERROR_WANT_ACCEPT || rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE) {
          250  +				bioShouldRetry = 1;
          251  +			} else if (BIO_should_retry(statePtr->bio)) {
          252  +				bioShouldRetry = 1;
          253  +			} else if (rc == SSL_ERROR_SYSCALL && Tcl_GetErrno() == EAGAIN) {
          254  +				bioShouldRetry = 1;
          255  +			}
          256  +		} else {
          257  +			if (!SSL_is_init_finished(statePtr->ssl)) {
          258  +				bioShouldRetry = 1;
          259  +			}
          260  +		}
          261  +
          262  +		if (bioShouldRetry) {
          263  +			dprintf("The I/O did not complete -- but we should try it again");
          264  +
          265  +			if (statePtr->flags & TLS_TCL_ASYNC) {
          266  +				dprintf("Returning EAGAIN so that it can be retried later");
          267  +
          268  +				*errorCodePtr = EAGAIN;
          269  +
          270  +				return(-1);
          271  +			} else {
          272  +				dprintf("Doing so now");
          273  +
          274  +				continue;
          275  +			}
          276  +		}
          277  +
          278  +		dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though");
          279  +		break;
          280  +	}
          281  +
          282  +
          283  +	*errorCodePtr = EINVAL;
          284  +
          285  +	switch (rc) {
          286  +		case SSL_ERROR_NONE:
          287  +			/* The connection is up, we are done here */
          288  +			dprintf("The connection is up");
          289  +			break;
          290  +		case SSL_ERROR_ZERO_RETURN:
          291  +			dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value...")
          292  +			return(-1);
          293  +		case SSL_ERROR_SYSCALL:
          294  +			backingError = ERR_get_error();
          295  +
          296  +			if (backingError == 0 && err == 0) {
          297  +				dprintf("EOF reached")
          298  +				*errorCodePtr = ECONNRESET;
          299  +			} else if (backingError == 0 && err == -1) {
          300  +				dprintf("I/O error occured (errno = %lu)", (unsigned long) Tcl_GetErrno());
          301  +				*errorCodePtr = Tcl_GetErrno();
          302  +				if (*errorCodePtr == ECONNRESET) {
          303  +					*errorCodePtr = ECONNABORTED;
          304  +				}
          305  +			} else {
          306  +				dprintf("I/O error occured (backingError = %lu)", backingError);
          307  +				*errorCodePtr = backingError;
          308  +				if (*errorCodePtr == ECONNRESET) {
          309  +					*errorCodePtr = ECONNABORTED;
          310  +				}
          311  +			}
          312  +
          313  +			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
          314  +
          315  +			return(-1);
          316  +		case SSL_ERROR_SSL:
          317  +			dprintf("Got permanent fatal SSL error, aborting immediately");
          318  +			Tls_Error(statePtr, (char *)ERR_reason_error_string(ERR_get_error()));
          319  +			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
          320  +			*errorCodePtr = ECONNABORTED;
          321  +			return(-1);
          322  +		case SSL_ERROR_WANT_CONNECT:
          323  +		case SSL_ERROR_WANT_ACCEPT:
          324  +		case SSL_ERROR_WANT_X509_LOOKUP:
          325  +		default:
          326  +			dprintf("We got a confusing reply: %i", rc);
          327  +			*errorCodePtr = Tcl_GetErrno();
          328  +			dprintf("ERR(%d, %d) ", rc, *errorCodePtr);
          329  +			return(-1);
          330  +	}
          331  +
          332  +#if 0
          333  +	if (statePtr->flags & TLS_TCL_SERVER) {
          334  +		dprintf("This is an TLS server, checking the certificate for the peer");
          335  +
          336  +		err = SSL_get_verify_result(statePtr->ssl);
          337  +		if (err != X509_V_OK) {
          338  +			dprintf("Invalid certificate, returning in failure");
          339  +
          340  +			Tls_Error(statePtr, (char *)X509_verify_cert_error_string(err));
          341  +			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
          342  +			*errorCodePtr = ECONNABORTED;
          343  +			return(-1);
          344  +		}
          345  +	}
          346  +#endif
          347  +
          348  +	dprintf("Removing the \"TLS_TCL_INIT\" flag since we have completed the handshake");
          349  +	statePtr->flags &= ~TLS_TCL_INIT;
          350  +
          351  +	dprintf("Returning in success");
          352  +	*errorCodePtr = 0;
          353  +
          354  +	return(0);
          355  +}
   178    356   
   179    357   /*
   180    358    *-------------------------------------------------------------------
   181    359    *
   182    360    * TlsInputProc --
   183    361    *
   184    362    *	This procedure is invoked by the generic IO level
................................................................................
   209    387   	if (statePtr->flags & TLS_TCL_CALLBACK) {
   210    388   		/* don't process any bytes while verify callback is running */
   211    389   		dprintf("Callback is running, reading 0 bytes");
   212    390   		return(0);
   213    391   	}
   214    392   
   215    393   	dprintf("Calling Tls_WaitForConnect");
   216         -	tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr);
          394  +	tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 0);
   217    395   	if (tlsConnect < 0) {
   218    396   		dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr);
   219    397   
   220    398   		bytesRead = -1;
   221    399   		if (*errorCodePtr == ECONNRESET) {
   222    400   			dprintf("Got connection reset");
   223    401   			/* Soft EOF */
................................................................................
   333    511   		dprintf("Don't process output while callbacks are running")
   334    512   		written = -1;
   335    513   		*errorCodePtr = EAGAIN;
   336    514   		return(-1);
   337    515   	}
   338    516   
   339    517   	dprintf("Calling Tls_WaitForConnect");
   340         -	tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr);
          518  +	tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 1);
   341    519   	if (tlsConnect < 0) {
   342    520   		dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr);
   343    521   
   344    522   		written = -1;
   345    523   		if (*errorCodePtr == ECONNRESET) {
   346    524   			dprintf("Got connection reset");
   347    525   			/* Soft EOF */
................................................................................
   634    812   	if (statePtr->flags & TLS_TCL_CALLBACK) {
   635    813   		dprintf("Returning 0 due to callback");
   636    814   		return 0;
   637    815   	}
   638    816   
   639    817   	dprintf("Calling Tls_WaitForConnect");
   640    818   	errorCode = 0;
   641         -	if (Tls_WaitForConnect(statePtr, &errorCode) < 0) {
          819  +	if (Tls_WaitForConnect(statePtr, &errorCode, 1) < 0) {
   642    820   		if (errorCode == EAGAIN) {
   643    821   			dprintf("Async flag could be set (didn't check) and errorCode == EAGAIN:  Returning 0");
   644    822   
   645    823   			return 0;
   646    824   		}
   647    825   
   648    826   		dprintf("Tls_WaitForConnect returned an error");
................................................................................
   778    956   	Tcl_NotifyChannel(statePtr->self, mask);
   779    957   
   780    958   	dprintf("Returning");
   781    959   
   782    960   	return;
   783    961   }
   784    962   
   785         -/*
   786         - *------------------------------------------------------*
   787         - *
   788         - *	Tls_WaitForConnect --
   789         - *
   790         - *	Sideeffects:
   791         - *		Issues SSL_accept or SSL_connect
   792         - *
   793         - *	Result:
   794         - *		None.
   795         - *
   796         - *------------------------------------------------------*
   797         - */
   798         -int Tls_WaitForConnect(State *statePtr, int *errorCodePtr) {
   799         -	unsigned long backingError;
   800         -	int err, rc;
   801         -	int bioShouldRetry;
   802         -
   803         -	dprintf("WaitForConnect(%p)", (void *) statePtr);
   804         -	dprintFlags(statePtr);
   805         -
   806         -	if (!(statePtr->flags & TLS_TCL_INIT)) {
   807         -		dprintf("Tls_WaitForConnect called on already initialized channel -- returning with immediate success");
   808         -		*errorCodePtr = 0;
   809         -		return(0);
   810         -	}
   811         -
   812         -	if (statePtr->flags & TLS_TCL_HANDSHAKE_FAILED) {
   813         -		dprintf("Asked to wait for a TLS handshake that has already failed.  Returning fatal error");
   814         -		/*
   815         -		 * If we get here, we've already returned a soft-failure once.
   816         -		 * Return a hard failure now.
   817         -		 */
   818         -		*errorCodePtr = ECONNABORTED;
   819         -		return(-1);
   820         -	}
   821         -
   822         -	for (;;) {
   823         -		/* Not initialized yet! */
   824         -		if (statePtr->flags & TLS_TCL_SERVER) {
   825         -			dprintf("Calling SSL_accept()");
   826         -
   827         -			err = SSL_accept(statePtr->ssl);
   828         -		} else {
   829         -			dprintf("Calling SSL_connect()");
   830         -
   831         -			err = SSL_connect(statePtr->ssl);
   832         -		}
   833         -
   834         -		if (err > 0) {
   835         -			dprintf("That seems to have gone okay");
   836         -
   837         -			err = BIO_flush(statePtr->bio);
   838         -
   839         -			if (err <= 0) {
   840         -				dprintf("Flushing the lower layers failed, this will probably terminate this session");
   841         -			}
   842         -		}
   843         -
   844         -		rc = SSL_get_error(statePtr->ssl, err);
   845         -
   846         -		dprintf("Got error: %i (rc = %i)", err, rc);
   847         -
   848         -		bioShouldRetry = 0;
   849         -		if (err <= 0) {
   850         -			if (rc == SSL_ERROR_WANT_CONNECT || rc == SSL_ERROR_WANT_ACCEPT || rc == SSL_ERROR_WANT_READ || rc == SSL_ERROR_WANT_WRITE) {
   851         -				bioShouldRetry = 1;
   852         -			} else if (BIO_should_retry(statePtr->bio)) {
   853         -				bioShouldRetry = 1;
   854         -			} else if (rc == SSL_ERROR_SYSCALL && Tcl_GetErrno() == EAGAIN) {
   855         -				bioShouldRetry = 1;
   856         -			}
   857         -		} else {
   858         -			if (!SSL_is_init_finished(statePtr->ssl)) {
   859         -				bioShouldRetry = 1;
   860         -			}
   861         -		}
   862         -
   863         -		if (bioShouldRetry) {
   864         -			dprintf("The I/O did not complete -- but we should try it again");
   865         -
   866         -			if (statePtr->flags & TLS_TCL_ASYNC) {
   867         -				dprintf("Returning EAGAIN so that it can be retried later");
   868         -
   869         -				*errorCodePtr = EAGAIN;
   870         -
   871         -				return(-1);
   872         -			} else {
   873         -				dprintf("Doing so now");
   874         -
   875         -				continue;
   876         -			}
   877         -		}
   878         -
   879         -		dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though");
   880         -		break;
   881         -	}
   882         -
   883         -
   884         -	*errorCodePtr = EINVAL;
   885         -
   886         -	switch (rc) {
   887         -		case SSL_ERROR_NONE:
   888         -			/* The connection is up, we are done here */
   889         -			dprintf("The connection is up");
   890         -			break;
   891         -		case SSL_ERROR_ZERO_RETURN:
   892         -			dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value...")
   893         -			return(-1);
   894         -		case SSL_ERROR_SYSCALL:
   895         -			backingError = ERR_get_error();
   896         -
   897         -			if (backingError == 0 && err == 0) {
   898         -				dprintf("EOF reached")
   899         -				*errorCodePtr = ECONNRESET;
   900         -			} else if (backingError == 0 && err == -1) {
   901         -				dprintf("I/O error occured (errno = %lu)", (unsigned long) Tcl_GetErrno());
   902         -				*errorCodePtr = Tcl_GetErrno();
   903         -				if (*errorCodePtr == ECONNRESET) {
   904         -					*errorCodePtr = ECONNABORTED;
   905         -				}
   906         -			} else {
   907         -				dprintf("I/O error occured (backingError = %lu)", backingError);
   908         -				*errorCodePtr = backingError;
   909         -				if (*errorCodePtr == ECONNRESET) {
   910         -					*errorCodePtr = ECONNABORTED;
   911         -				}
   912         -			}
   913         -
   914         -			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
   915         -
   916         -			return(-1);
   917         -		case SSL_ERROR_SSL:
   918         -			dprintf("Got permanent fatal SSL error, aborting immediately");
   919         -			Tls_Error(statePtr, (char *)ERR_reason_error_string(ERR_get_error()));
   920         -			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
   921         -			*errorCodePtr = ECONNABORTED;
   922         -			return(-1);
   923         -		case SSL_ERROR_WANT_CONNECT:
   924         -		case SSL_ERROR_WANT_ACCEPT:
   925         -		case SSL_ERROR_WANT_X509_LOOKUP:
   926         -		default:
   927         -			dprintf("We got a confusing reply: %i", rc);
   928         -			*errorCodePtr = Tcl_GetErrno();
   929         -			dprintf("ERR(%d, %d) ", rc, *errorCodePtr);
   930         -			return(-1);
   931         -	}
   932         -
   933         -#if 0
   934         -	if (statePtr->flags & TLS_TCL_SERVER) {
   935         -		dprintf("This is an TLS server, checking the certificate for the peer");
   936         -
   937         -		err = SSL_get_verify_result(statePtr->ssl);
   938         -		if (err != X509_V_OK) {
   939         -			dprintf("Invalid certificate, returning in failure");
   940         -
   941         -			Tls_Error(statePtr, (char *)X509_verify_cert_error_string(err));
   942         -			statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
   943         -			*errorCodePtr = ECONNABORTED;
   944         -			return(-1);
   945         -		}
   946         -	}
   947         -#endif
   948         -
   949         -	dprintf("Removing the \"TLS_TCL_INIT\" flag since we have completed the handshake");
   950         -	statePtr->flags &= ~TLS_TCL_INIT;
   951         -
   952         -	dprintf("Returning in success");
   953         -	*errorCodePtr = 0;
   954         -
   955         -	return(0);
   956         -}
   957         -
   958    963   Tcl_Channel Tls_GetParent(State *statePtr, int maskFlags) {
   959    964   	dprintf("Requested to get parent of channel %p", statePtr->self);
   960    965   
   961    966   	if ((statePtr->flags & ~maskFlags) & TLS_TCL_FASTPATH) {
   962    967   		dprintf("Asked to get the parent channel while we are using FastPath -- returning NULL");
   963    968   		return(NULL);
   964    969   	}
   965    970   
   966    971   	return(Tcl_GetStackedChannel(statePtr->self));
   967    972   }

Changes to tlsInt.h.

   167    167   Tcl_ChannelType *Tls_ChannelType(void);
   168    168   Tcl_Channel     Tls_GetParent(State *statePtr, int maskFlags);
   169    169   
   170    170   Tcl_Obj         *Tls_NewX509Obj(Tcl_Interp *interp, X509 *cert);
   171    171   void            Tls_Error(State *statePtr, char *msg);
   172    172   void            Tls_Free(char *blockPtr);
   173    173   void            Tls_Clean(State *statePtr);
   174         -int             Tls_WaitForConnect(State *statePtr, int *errorCodePtr);
          174  +int             Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent);
   175    175   
   176    176   BIO             *BIO_new_tcl(State* statePtr, int flags);
   177    177   
   178    178   #define PTR2INT(x) ((int) ((intptr_t) (x)))
   179    179   
   180    180   #endif /* _TLSINT_H */