Index: configure ================================================================== --- configure +++ configure @@ -5394,11 +5394,11 @@ # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- - vars="tls.c tlsBIO.c tlsIO.c tlsX509.c" + vars="tls.c tlsBIO.c tlsDigest.c tlsIO.c tlsX509.c" for i in $vars; do case $i in \$*) # allow $-var names PKG_SOURCES="$PKG_SOURCES $i" Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -69,11 +69,11 @@ # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- -TEA_ADD_SOURCES([tls.c tlsBIO.c tlsIO.c tlsX509.c]) +TEA_ADD_SOURCES([tls.c tlsBIO.c tlsDigest.c tlsIO.c tlsX509.c]) TEA_ADD_HEADERS([generic/tls.h]) TEA_ADD_INCLUDES([]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([]) TEA_ADD_STUB_SOURCES([]) Index: generic/tls.c ================================================================== --- generic/tls.c +++ generic/tls.c @@ -930,131 +930,10 @@ /********************/ /* *------------------------------------------------------------------- * - * Hash Calc -- - * - * Calculate message digest of data using type hash algorithm. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *------------------------------------------------------------------- - */ -int -HashCalc(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const EVP_MD *type) { - char *data; - int len; - unsigned int mdlen; - unsigned char mdbuf[EVP_MAX_MD_SIZE]; - const char *hex = "0123456789ABCDEF"; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "data"); - return TCL_ERROR; - } - - /* Get data */ - data = Tcl_GetByteArrayFromObj(objv[1], &len); - if (data == NULL || len == 0) { - Tcl_SetResult(interp, "No data", NULL); - return TCL_ERROR; - } - - /* Calc hash value, create hex representation, and write to result */ - if (EVP_Digest(data, (size_t) len, mdbuf, &mdlen, type, NULL)) { - Tcl_Obj *resultObj; - unsigned char *ptr; - resultObj = Tcl_NewObj(); - ptr = Tcl_SetByteArrayLength(resultObj, mdlen*2); - - for (unsigned int i = 0; i < mdlen; i++) { - *ptr++ = hex[(mdbuf[i] >> 4) & 0x0F]; - *ptr++ = hex[mdbuf[i] & 0x0F]; - } - Tcl_SetObjResult(interp, resultObj); - } else { - Tcl_SetResult(interp, "Hash calculation error", NULL); - return TCL_ERROR; - } - return TCL_OK; -} - -/* - *------------------------------------------------------------------- - * - * Hash Commands -- - * - * Return the digest as a hex string for data using type message digest. - * - * Results: - * A standard Tcl result. - * - * Side effects: - * None. - * - *------------------------------------------------------------------- - */ -DigestCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - int len; - const char *name; - const EVP_MD *type; - - if (objc != 3) { - Tcl_WrongNumArgs(interp, 1, objv, "type data"); - return TCL_ERROR; - } - - name = Tcl_GetStringFromObj(objv[1],&len); - if (name == NULL || (type = EVP_get_digestbyname(name)) == NULL) { - Tcl_AppendResult(interp, "Invalid digest type \"", name, "\"", NULL); - return TCL_ERROR; - } - objc--; - objv++; - return HashCalc(interp, objc, objv, type); -} - -/* - * Command to Calculate MD4 Message Digest - */ -int -DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return HashCalc(interp, objc, objv, EVP_md4()); -} - -/* - * Command to Calculate MD5 Message Digest - */ -int -DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return HashCalc(interp, objc, objv, EVP_md5()); -} - -/* - * Command to Calculate SHA-1 Hash - */ -int -DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return HashCalc(interp, objc, objv, EVP_sha1()); -} - -/* - * Command to Calculate SHA2 SHA-256 Hash - */ -int -DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return HashCalc(interp, objc, objv, EVP_sha256()); -} - -/* - *------------------------------------------------------------------- - * * Hash List Command -- * * Return a list of all valid hash algorithms or message digests. * * Results: @@ -2973,16 +2852,12 @@ Tcl_CreateObjCommand(interp, "tls::ciphers", CiphersObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::protocols", ProtocolsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); Tcl_CreateObjCommand(interp, "tls::version", VersionObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateObjCommand(interp, "tls::digest", DigestCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tls_DigestCommands(interp); Tcl_CreateObjCommand(interp, "tls::digests", DigestListCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateObjCommand(interp, "tls::md4", DigestMD4Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateObjCommand(interp, "tls::md5", DigestMD5Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateObjCommand(interp, "tls::sha1", DigestSHA1Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateObjCommand(interp, "tls::sha256", DigestSHA256Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); if (interp) { Tcl_Eval(interp, tlsTclInitScript); } ADDED generic/tlsDigest.c Index: generic/tlsDigest.c ================================================================== --- /dev/null +++ generic/tlsDigest.c @@ -0,0 +1,163 @@ +/* + * Digest Commands + * + * Copyright (C) 2023 Brian O'Hagan + * + */ + +#include "tlsInt.h" +#include +#include +#include +#include + +/* Constants */ +const char *hex = "0123456789ABCDEF"; + + +/*******************************************************************/ + +/* + *------------------------------------------------------------------- + * + * Hash Calc -- + * + * Calculate message digest of data using type hash algorithm. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *------------------------------------------------------------------- + */ +int +HashCalc(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const EVP_MD *type) { + char *data; + int len; + unsigned int mdlen; + unsigned char mdbuf[EVP_MAX_MD_SIZE]; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "data"); + return TCL_ERROR; + } + + /* Get data */ + data = Tcl_GetByteArrayFromObj(objv[1], &len); + if (data == NULL || len == 0) { + Tcl_SetResult(interp, "No data", NULL); + return TCL_ERROR; + } + + /* Calculate hash value, create hex representation, and write to result */ + if (EVP_Digest(data, (size_t) len, mdbuf, &mdlen, type, NULL)) { + Tcl_Obj *resultObj; + unsigned char *ptr; + resultObj = Tcl_NewObj(); + ptr = Tcl_SetByteArrayLength(resultObj, mdlen*2); + + for (unsigned int i = 0; i < mdlen; i++) { + *ptr++ = hex[(mdbuf[i] >> 4) & 0x0F]; + *ptr++ = hex[mdbuf[i] & 0x0F]; + } + Tcl_SetObjResult(interp, resultObj); + } else { + Tcl_SetResult(interp, "Hash calculation error", NULL); + return TCL_ERROR; + } + return TCL_OK; +} + +/* + *------------------------------------------------------------------- + * + * Hash Commands -- + * + * Return the digest as a hex string for data using type message digest. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *------------------------------------------------------------------- + */ +DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + int len; + const char *name; + const EVP_MD *type; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "type data"); + return TCL_ERROR; + } + + name = Tcl_GetStringFromObj(objv[1],&len); + if (name == NULL || (type = EVP_get_digestbyname(name)) == NULL) { + Tcl_AppendResult(interp, "Invalid digest type \"", name, "\"", NULL); + return TCL_ERROR; + } + objc--; + objv++; + return HashCalc(interp, objc, objv, type); +} + +/* + * Command to Calculate MD4 Message Digest + */ +int +DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return HashCalc(interp, objc, objv, EVP_md4()); +} + +/* + * Command to Calculate MD5 Message Digest + */ +int +DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return HashCalc(interp, objc, objv, EVP_md5()); +} + +/* + * Command to Calculate SHA-1 Hash + */ +int +DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return HashCalc(interp, objc, objv, EVP_sha1()); +} + +/* + * Command to Calculate SHA2 SHA-256 Hash + */ +int +DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return HashCalc(interp, objc, objv, EVP_sha256()); +} + +/* + *------------------------------------------------------------------- + * + * Tls_DigestCommands -- + * + * Create digest commands + * + * Returns: + * TCL_OK or TCL_ERROR + * + * Side effects: + * Creates commands + * + *------------------------------------------------------------------- + */ +int Tls_DigestCommands(Tcl_Interp *interp) { + Tcl_CreateObjCommand(interp, "tls::digest", DigestObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::md4", DigestMD4Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::md5", DigestMD5Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::sha1", DigestSHA1Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + Tcl_CreateObjCommand(interp, "tls::sha256", DigestSHA256Cmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL); + return TCL_OK; +} + Index: generic/tlsInt.h ================================================================== --- generic/tlsInt.h +++ generic/tlsInt.h @@ -192,10 +192,11 @@ Tcl_Obj *Tls_NewCAObj(Tcl_Interp *interp, const SSL *ssl, int peer); void Tls_Error(State *statePtr, char *msg); void Tls_Free(char *blockPtr); void Tls_Clean(State *statePtr); int Tls_WaitForConnect(State *statePtr, int *errorCodePtr, int handshakeFailureIsPermanent); +int Tls_DigestCommands(Tcl_Interp *interp); BIO *BIO_new_tcl(State* statePtr, int flags); #define PTR2INT(x) ((int) ((intptr_t) (x))) Index: win/makefile.vc ================================================================== --- win/makefile.vc +++ win/makefile.vc @@ -25,20 +25,22 @@ # Note the resource file does not makes sense if doing a static library build # hence it is under that condition. TMP_DIR is the output directory # defined by rules for object files. PRJ_OBJS = $(TMP_DIR)\tls.obj \ $(TMP_DIR)\tlsBIO.obj \ + $(TMP_DIR)\tlsDigest.obj \ $(TMP_DIR)\tlsIO.obj \ $(TMP_DIR)\tlsX509.obj # Define any additional project include flags # SSL_INSTALL_FOLDER = with the OpenSSL installation folder following. PRJ_INCLUDES = -I"$(SSL_INSTALL_FOLDER)\include" -I"$(OPENSSL_INSTALL_DIR)\include" # Define any additional compiler flags that might be required for the project PRJ_DEFINES = -D NO_SSL2 -D NO_SSL3 -D _CRT_SECURE_NO_WARNINGS - + +# # SSL Libs: # 1. ${LIBCRYPTO}.dll # 2. ${LIBSSL}.dll # Where LIBCRYPTO (#1.) and LIBSSL (#2.) are defined as follows: # v1.1: libcrypto-1.1-x64.dll and libssl-1.1-x64.dll @@ -53,10 +55,14 @@ # Define the standard targets !include "targets.vc" # Project specific targets +all: + +clean: default-clean + # We must define a pkgindex target that will create a pkgIndex.tcl # file in the $(OUT_DIR) directory. We can just redirect to the # default-pkgindex target for our sample extension. pkgindex: default-pkgindex