Index: generic/tlsDigest.c ================================================================== --- generic/tlsDigest.c +++ generic/tlsDigest.c @@ -19,16 +19,18 @@ /* Constants */ const char *hex = "0123456789ABCDEF"; /* Macros */ #define BUFFER_SIZE 65536 -#define BIN_FORMAT 0 -#define HEX_FORMAT 1 #define CHAN_EOF 0x10 -#define TYPE_MD 0x20 -#define TYPE_HMAC 0x40 -#define TYPE_CMAC 0x80 + +/* Digest format and operation */ +#define BIN_FORMAT 0x01 +#define HEX_FORMAT 0x02 +#define TYPE_MD 0x10 +#define TYPE_HMAC 0x20 +#define TYPE_CMAC 0x40 /* * This structure defines the per-instance state of a digest operation. */ typedef struct DigestState { @@ -1041,20 +1043,37 @@ Tcl_SetResult(interp, "No data", NULL); return TCL_ERROR; } /* Calculate digest based on hash function */ - if (keyObj == (Tcl_Obj *) NULL) { + if (format & TYPE_MD) { res = EVP_Digest(data, (size_t) len, md_buf, &md_len, md, NULL); - } else { + + } else if (format & TYPE_HMAC) { unsigned char *key, *hmac = NULL; int key_len; key = Tcl_GetByteArrayFromObj(keyObj, &key_len); hmac = HMAC(md, (const void *) key, key_len, (const unsigned char *) data, (size_t) len, md_buf, &md_len); res = (hmac != NULL); + + } else if (format & TYPE_CMAC) { + DigestState *statePtr; + + if ((statePtr = Tls_DigestNew(interp, format)) == NULL) { + Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL); + return TCL_ERROR; + } + if (Tls_DigestInit(interp, statePtr, md, cipher, keyObj) != TCL_OK || + Tls_DigestUpdate(statePtr, data, (size_t) len) == 0 || + Tls_DigestFinialize(interp, statePtr) != TCL_OK) { + Tls_DigestFree(statePtr); + return TCL_ERROR; + } + Tls_DigestFree(statePtr); + return TCL_OK; } /* Output digest to result per format (bin or hex) */ if (res) { if (format & BIN_FORMAT) { @@ -1094,18 +1113,17 @@ * Side effects: * Sets result to message digest or error message * *------------------------------------------------------------------- */ -static int -DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { +static int DigestMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { int idx, len, format = HEX_FORMAT, res = TCL_OK, flags = 0; - const char *digestname, *channel = NULL; + const char *digestName, *channel = NULL; Tcl_Obj *cmdObj = NULL, *dataObj = NULL, *fileObj = NULL, *keyObj = NULL; unsigned char *cipherName = NULL; const EVP_MD *md; - const EVP_CIPHER *cipher; + const EVP_CIPHER *cipher = NULL; /* Clear interp result */ Tcl_ResetResult(interp); /* Validate arg count */ @@ -1113,13 +1131,13 @@ Tcl_WrongNumArgs(interp, 1, objv, "digest ?-bin|-hex? ?-cipher name? ?-key hmac_key? [-channel chan | -command cmdName | -file filename | ?-data? data]"); return TCL_ERROR; } /* Get digest */ - digestname = Tcl_GetStringFromObj(objv[1], &len); - if (digestname == NULL || (md = EVP_get_digestbyname(digestname)) == NULL) { - Tcl_AppendResult(interp, "Invalid digest \"", digestname, "\"", NULL); + digestName = Tcl_GetStringFromObj(objv[1], &len); + if (digestName == NULL || (md = EVP_get_digestbyname(digestName)) == NULL) { + Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL); return TCL_ERROR; } /* Optimal case for blob of data */ if (objc == 3 && type == TYPE_MD) { @@ -1157,55 +1175,80 @@ } /* Get cipher */ if (cipherName != NULL) { cipher = EVP_get_cipherbyname(cipherName); + type = TYPE_CMAC; if (cipher == NULL) { Tcl_AppendResult(interp, "Invalid cipher \"", cipherName, "\"", NULL); return TCL_ERROR; } + + } else if (type == TYPE_CMAC) { + Tcl_AppendResult(interp, "No cipher specified", NULL); + return TCL_ERROR; } - /* Define operation to perform */ - if (cipher != NULL) { - format |= TYPE_CMAC; - } else if (keyObj != NULL) { - format |= TYPE_HMAC; - } else { - format |= TYPE_MD; + /* Get key */ + if (keyObj != NULL) { + if (type == TYPE_MD) { + type = TYPE_HMAC; + } + } else if (type != TYPE_MD) { + Tcl_AppendResult(interp, "No key specified", NULL); + return TCL_ERROR; } /* Calc digest on file, stacked channel, using instance command, or data blob */ if (fileObj != NULL) { - res = Tls_DigestFile(interp, fileObj, md, cipher, format, keyObj); + res = Tls_DigestFile(interp, fileObj, md, cipher, format | type, keyObj); } else if (channel != NULL) { - res = Tls_DigestChannel(interp, channel, md, cipher, format, keyObj); + res = Tls_DigestChannel(interp, channel, md, cipher, format | type, keyObj); } else if (cmdObj != NULL) { - res = Tls_DigestInstance(interp, cmdObj, md, cipher, format, keyObj); + res = Tls_DigestInstance(interp, cmdObj, md, cipher, format | type, keyObj); } else if (dataObj != NULL) { Tcl_Obj *objs[2]; objs[0] = NULL; objs[1] = dataObj; - res = Tls_DigestData(interp, 2, objs, md, cipher, format, keyObj); + res = Tls_DigestData(interp, 2, objs, md, cipher, format | type, keyObj); } return res; } -int CMACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return DigestObjCmd(clientData, interp, objc, objv); +/* + *------------------------------------------------------------------- + * + * Message Digest and Message Authentication Code Commands -- + * + * Return Message Digest (MD) or Message Authentication Code (MAC). + * + * Returns: + * TCL_OK or TCL_ERROR + * + * Side effects: + * Sets result to message digest or error message + * + *------------------------------------------------------------------- + */ +static int DigestObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return DigestMain(TYPE_MD, interp, objc, objv); +} + +static int CMACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return DigestMain(TYPE_CMAC, interp, objc, objv); } -int HMACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return DigestObjCmd(clientData, interp, objc, objv); +static int HMACObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { + return DigestMain(TYPE_HMAC, interp, objc, objv); } /* *------------------------------------------------------------------- * * Message Digest Convenience Commands -- * - * Convenience commands for message digests. + * Convenience commands for select message digests. * * Returns: * TCL_OK or TCL_ERROR * * Side effects: @@ -1212,27 +1255,27 @@ * Sets result to message digest or error message * *------------------------------------------------------------------- */ int DigestMD4Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return Tls_DigestData(interp, objc, objv, EVP_md4(), NULL, HEX_FORMAT, NULL); + return Tls_DigestData(interp, objc, objv, EVP_md4(), NULL, HEX_FORMAT | TYPE_MD, NULL); } int DigestMD5Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return Tls_DigestData(interp, objc, objv, EVP_md5(), NULL, HEX_FORMAT, NULL); + return Tls_DigestData(interp, objc, objv, EVP_md5(), NULL, HEX_FORMAT | TYPE_MD, NULL); } int DigestSHA1Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return Tls_DigestData(interp, objc, objv, EVP_sha1(), NULL, HEX_FORMAT, NULL); + return Tls_DigestData(interp, objc, objv, EVP_sha1(), NULL, HEX_FORMAT | TYPE_MD, NULL); } int DigestSHA256Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return Tls_DigestData(interp, objc, objv, EVP_sha256(), NULL, HEX_FORMAT, NULL); + return Tls_DigestData(interp, objc, objv, EVP_sha256(), NULL, HEX_FORMAT | TYPE_MD, NULL); } int DigestSHA512Cmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - return Tls_DigestData(interp, objc, objv, EVP_sha512(), NULL, HEX_FORMAT, NULL); + return Tls_DigestData(interp, objc, objv, EVP_sha512(), NULL, HEX_FORMAT | TYPE_MD, NULL); } /* *------------------------------------------------------------------- *