Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -43,20 +43,10 @@ #define F2N(key, dsp) \ (((key) == NULL) ? (char *)NULL : \ Tcl_TranslateFileName(interp, (key), (dsp))) -static void InfoCallback(const SSL *ssl, int where, int ret); - -static Tcl_ObjCmdProc CiphersObjCmd; -static Tcl_ObjCmdProc HandshakeObjCmd; -static Tcl_ObjCmdProc ImportObjCmd; -static Tcl_ObjCmdProc StatusObjCmd; -static Tcl_ObjCmdProc VersionObjCmd; -static Tcl_ObjCmdProc MiscObjCmd; -static Tcl_ObjCmdProc UnimportObjCmd; - static SSL_CTX *CTX_Init(State *statePtr, int isServer, int proto, char *key, char *certfile, unsigned char *key_asn1, unsigned char *cert_asn1, int key_asn1_len, int cert_asn1_len, char *CAdir, char *CAfile, char *ciphers, char *DHparams); @@ -161,10 +151,11 @@ */ static void InfoCallback(const SSL *ssl, int where, int ret) { State *statePtr = (State*)SSL_get_app_data((SSL *)ssl); + Tcl_Interp *interp = statePtr->interp; Tcl_Obj *cmdPtr; const char *major, *minor; dprintf("Called"); @@ -199,43 +190,43 @@ else if (where & SSL_CB_LOOP) minor = "loop"; else if (where & SSL_CB_EXIT) minor = "exit"; else minor = "unknown"; } - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, + Tcl_ListObjAppendElement( interp, cmdPtr, Tcl_NewStringObj( "info", -1)); - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, + Tcl_ListObjAppendElement( interp, cmdPtr, Tcl_NewStringObj( Tcl_GetChannelName(statePtr->self), -1) ); - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, + Tcl_ListObjAppendElement( interp, cmdPtr, Tcl_NewStringObj( major, -1) ); - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, + Tcl_ListObjAppendElement( interp, cmdPtr, Tcl_NewStringObj( minor, -1) ); if (where & (SSL_CB_LOOP|SSL_CB_EXIT)) { - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, - Tcl_NewStringObj( SSL_state_string_long(ssl), -1) ); - } else if (where & SSL_CB_ALERT) { - const char *cp = (char *) SSL_alert_desc_string_long(ret); - - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, - Tcl_NewStringObj( cp, -1) ); - } else { - Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, - Tcl_NewStringObj( SSL_state_string_long(ssl), -1) ); - } - Tcl_Preserve( (ClientData) statePtr->interp); - Tcl_Preserve( (ClientData) statePtr); - - Tcl_IncrRefCount( cmdPtr); - (void) Tcl_EvalObjEx(statePtr->interp, cmdPtr, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount( cmdPtr); - - Tcl_Release( (ClientData) statePtr); - Tcl_Release( (ClientData) statePtr->interp); + Tcl_ListObjAppendElement( interp, cmdPtr, + Tcl_NewStringObj( SSL_state_string_long(ssl), -1) ); + } else if (where & SSL_CB_ALERT) { + const char *cp = (char *)SSL_alert_desc_string_long(ret); + + Tcl_ListObjAppendElement( interp, cmdPtr, + Tcl_NewStringObj( cp, -1) ); + } else { + Tcl_ListObjAppendElement( interp, cmdPtr, + Tcl_NewStringObj( SSL_state_string_long(ssl), -1) ); + } + Tcl_Preserve((void *) interp); + Tcl_Preserve((void *) statePtr); + + Tcl_IncrRefCount( cmdPtr); + (void) Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount( cmdPtr); + + Tcl_Release((void *) statePtr); + Tcl_Release((void *) interp); } /* *------------------------------------------------------------------- @@ -303,12 +294,12 @@ Tcl_NewIntObj( ok) ); Tcl_ListObjAppendElement( statePtr->interp, cmdPtr, Tcl_NewStringObj( errStr ? errStr : "", -1) ); - Tcl_Preserve( (ClientData) statePtr->interp); - Tcl_Preserve( (ClientData) statePtr); + Tcl_Preserve((void *) statePtr->interp); + Tcl_Preserve((void *) statePtr); statePtr->flags |= TLS_TCL_CALLBACK; Tcl_IncrRefCount( cmdPtr); if (Tcl_EvalObjEx(statePtr->interp, cmdPtr, TCL_EVAL_GLOBAL) != TCL_OK) { @@ -328,12 +319,12 @@ } Tcl_DecrRefCount( cmdPtr); statePtr->flags &= ~(TLS_TCL_CALLBACK); - Tcl_Release( (ClientData) statePtr); - Tcl_Release( (ClientData) statePtr->interp); + Tcl_Release((void *) statePtr); + Tcl_Release((void *) statePtr->interp); return(ok); /* By default, leave verification unchanged. */ } /* @@ -380,21 +371,21 @@ Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1)); Tcl_ListObjAppendElement(statePtr->interp, cmdPtr, Tcl_NewStringObj(msg, -1)); - Tcl_Preserve((ClientData) statePtr->interp); - Tcl_Preserve((ClientData) statePtr); + Tcl_Preserve((void *) statePtr->interp); + Tcl_Preserve((void *) statePtr); Tcl_IncrRefCount(cmdPtr); if (Tcl_EvalObjEx(statePtr->interp, cmdPtr, TCL_EVAL_GLOBAL) != TCL_OK) { Tcl_BackgroundError(statePtr->interp); } Tcl_DecrRefCount(cmdPtr); - Tcl_Release((ClientData) statePtr); - Tcl_Release((ClientData) statePtr->interp); + Tcl_Release((void *) statePtr); + Tcl_Release((void *) statePtr->interp); } /* *------------------------------------------------------------------- * @@ -444,22 +435,22 @@ } } cmdPtr = Tcl_DuplicateObj(statePtr->password); - Tcl_Preserve((ClientData) statePtr->interp); - Tcl_Preserve((ClientData) statePtr); + Tcl_Preserve((void *) statePtr->interp); + Tcl_Preserve((void *) statePtr); Tcl_IncrRefCount(cmdPtr); result = Tcl_EvalObjEx(interp, cmdPtr, TCL_EVAL_GLOBAL); if (result != TCL_OK) { Tcl_BackgroundError(statePtr->interp); } Tcl_DecrRefCount(cmdPtr); - Tcl_Release((ClientData) statePtr); - Tcl_Release((ClientData) statePtr->interp); + Tcl_Release((void *) statePtr); + Tcl_Release((void *) statePtr->interp); if (result == TCL_OK) { const char *ret = Tcl_GetStringResult(interp); strncpy(buf, ret, (size_t) size); return (int)strlen(ret); @@ -650,10 +641,11 @@ /* Make sure to operate on the topmost channel */ chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "HANDSHAKE", "CHANNEL", "INVALID", (char *)NULL); return(TCL_ERROR); } statePtr = (State *)Tcl_GetChannelInstanceData(chan); dprintf("Calling Tls_WaitForConnect"); @@ -662,19 +654,24 @@ 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); if (!errStr || (*errStr == 0)) { errStr = Tcl_PosixError(interp); } Tcl_AppendResult(interp, "handshake failed: ", errStr, (char *)NULL); + if ((result = SSL_get_verify_result(statePtr->ssl)) != X509_V_OK) { + Tcl_AppendResult(interp, " due to \"", X509_verify_cert_error_string(result), "\"", (char *)NULL); + } + Tcl_SetErrorCode(interp, "TLS", "HANDSHAKE", "FAILED", (char *)NULL); dprintf("Returning TCL_ERROR with handshake failed: %s", errStr); return(TCL_ERROR); } else { if (err != 0) { dprintf("Got an error with a completed handshake: err = %i", err); @@ -871,10 +868,11 @@ */ chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "IMPORT", "CHANNEL", "INVALID", (char *)NULL); Tls_Free((void *)statePtr); return TCL_ERROR; } ctx = ((State *)Tcl_GetChannelInstanceData(chan))->ctx; } else { @@ -926,18 +924,20 @@ statePtr->ssl = SSL_new(statePtr->ctx); if (!statePtr->ssl) { /* SSL library error */ Tcl_AppendResult(interp, "couldn't construct ssl session: ", GET_ERR_REASON(), (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "IMPORT", "INIT", "FAILED", (char *)NULL); Tls_Free((void *)statePtr); return TCL_ERROR; } #ifndef OPENSSL_NO_TLSEXT if (servername) { if (!SSL_set_tlsext_host_name(statePtr->ssl, servername) && require) { Tcl_AppendResult(interp, "setting TLS host name extension failed", (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "IMPORT", "HOSTNAME", "FAILED", (char *)NULL); Tls_Free((void *)statePtr); return TCL_ERROR; } } #endif @@ -964,11 +964,11 @@ /* * End of SSL Init */ dprintf("Returning %s", Tcl_GetChannelName(statePtr->self)); - Tcl_SetResult(interp, (char *) Tcl_GetChannelName(statePtr->self), TCL_VOLATILE); + Tcl_SetResult(interp, (char *)Tcl_GetChannelName(statePtr->self), TCL_VOLATILE); return TCL_OK; } /* *------------------------------------------------------------------- @@ -1013,10 +1013,11 @@ chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "UNIMPORT", "CHANNEL", "INVALID", (char *)NULL); return TCL_ERROR; } if (Tcl_UnstackChannel(interp, chan) == TCL_ERROR) { return TCL_ERROR; @@ -1391,10 +1392,11 @@ */ chan = Tcl_GetTopChannel(chan); if (Tcl_GetChannelType(chan) != Tls_ChannelType()) { Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan), "\": not a TLS channel", (char *)NULL); + Tcl_SetErrorCode(interp, "TLS", "STATUS", "CHANNEL", "INVALID", (char *)NULL); return TCL_ERROR; } statePtr = (State *) Tcl_GetChannelInstanceData(chan); /* Get certificate for peer or self */