Index: generic/tlsDigest.c
==================================================================
--- generic/tlsDigest.c
+++ generic/tlsDigest.c
@@ -32,14 +32,10 @@
 #define TYPE_MD		0x10
 #define TYPE_HMAC	0x20
 #define TYPE_CMAC	0x40
 #define TYPE_MAC	0x80
 
-#if OPENSSL_VERSION_NUMBER <= 0x30000000L
-#define EVP_MAC void
-#endif
-
 /*******************************************************************/
 
 /*
  * This structure defines the per-instance state of a digest operation.
  */
@@ -149,19 +145,22 @@
  * Side effects:
  *	No result or error message
  *
  *-------------------------------------------------------------------
  */
-int DigestInitialize(Tcl_Interp *interp, DigestState *statePtr, const EVP_MD *md,
-	const EVP_CIPHER *cipher, Tcl_Obj *keyObj, EVP_MAC *mac) {
-    int key_len = 0, res = 0;
+int DigestInitialize(Tcl_Interp *interp, DigestState *statePtr, Tcl_Obj *digestObj,
+	Tcl_Obj *cipherObj, Tcl_Obj *keyObj, Tcl_Obj *macObj) {
+    int key_len = 0, type = statePtr->format & 0xFF0;
+    const char *digestName = NULL, *cipherName = NULL, *macName = NULL;
+    const EVP_MD *md = NULL;
+    const EVP_CIPHER *cipher = NULL;
     const unsigned char *key = NULL;
 
     dprintf("Called");
 
     /* Create contexts */
-    switch(statePtr->format & 0xFF0) {
+    switch(type) {
     case TYPE_MD:
 	statePtr->ctx = EVP_MD_CTX_new();
 	res = (statePtr->ctx != NULL);
 	break;
     case TYPE_HMAC:
@@ -173,21 +172,68 @@
 	res = (statePtr->cctx != NULL);
 	break;
     }
 
     if (!res) {
-	Tcl_AppendResult(interp, "Create context failed: ", REASON(), NULL);
+	Tcl_AppendResult(interp, "Create context failed", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Get MAC */
+    if (macObj != NULL) {
+	macName = Tcl_GetStringFromObj(macObj, NULL);
+	if (strcmp(macName, "cmac") == 0) {
+	    type = TYPE_CMAC;
+	} else if (strcmp(macName, "hmac") == 0) {
+	    type = TYPE_HMAC;
+	} else {
+	    Tcl_AppendResult(interp, "Invalid MAC \"", macName, "\"", NULL);
+	    return TCL_ERROR;
+	}
+    } else if (type == TYPE_MAC) {
+	Tcl_AppendResult(interp, "No MAC specified", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Get digest */
+    if (digestObj != NULL) {
+	digestName = Tcl_GetStringFromObj(digestObj, NULL);
+	md = EVP_get_digestbyname(digestName);
+	if (md == NULL) {
+	    Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL);
+	    return TCL_ERROR;
+	} else if (md == EVP_shake128() || md == EVP_shake256()) {
+	    statePtr->format |= IS_XOF;
+	}
+    } else if (type != TYPE_CMAC) {
+	Tcl_AppendResult(interp, "No digest specified", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Get cipher */
+    if (cipherObj != NULL) {
+	cipherName = Tcl_GetStringFromObj(cipherObj, NULL);
+	cipher = EVP_get_cipherbyname(cipherName);
+	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;
     }
 
     /* Get key */
     if (keyObj != NULL) {
 	key = Tcl_GetByteArrayFromObj(keyObj, &key_len);
+    } else if (type != TYPE_MD) {
+	Tcl_AppendResult(interp, "No key specified", NULL);
+	return TCL_ERROR;
     }
 
     /* Initialize cryptography function */
-    switch(statePtr->format & 0xFF0) {
+    switch(type) {
     case TYPE_MD:
 	res = EVP_DigestInit_ex(statePtr->ctx, md, NULL);
 	break;
     case TYPE_HMAC:
 	res = HMAC_Init_ex(statePtr->hctx, (const void *) key, key_len, md, NULL);
@@ -762,12 +808,12 @@
  * Side effects:
  *	Adds transform to channel and sets result to channel id or error message.
  *
  *----------------------------------------------------------------------
  */
-static int DigestChannelHandler(Tcl_Interp *interp, const char *channel, const EVP_MD *md,
-	const EVP_CIPHER *cipher, int format, Tcl_Obj *keyObj, EVP_MAC *mac) {
+static int DigestChannelHandler(Tcl_Interp *interp, const char *channel, Tcl_Obj *digestObj,
+	Tcl_Obj *cipherObj, int format, Tcl_Obj *keyObj, Tcl_Obj *macObj) {
     int mode; /* OR-ed combination of TCL_READABLE and TCL_WRITABLE */
     Tcl_Channel chan;
     DigestState *statePtr;
 
     dprintf("Called");
@@ -799,11 +845,12 @@
     }
     statePtr->self = chan;
     statePtr->mode = mode;
 
     /* Initialize hash function */
-    if (DigestInitialize(interp, statePtr, md, cipher, keyObj, mac) != TCL_OK) {
+    if (DigestInitialize(interp, statePtr, digestObj, cipherObj, keyObj, macObj) != TCL_OK) {
+	DigestStateFree(statePtr);
 	return TCL_ERROR;
     }
 
     /* Stack channel */
     statePtr->self = Tcl_StackChannel(interp, &digestChannelType, (ClientData) statePtr, mode, chan);
@@ -965,12 +1012,12 @@
  * Side effects:
  *	Creates command or error message
  *
  *-------------------------------------------------------------------
  */
-int DigestCommandHandler(Tcl_Interp *interp, Tcl_Obj *cmdObj, const EVP_MD *md,
-	const EVP_CIPHER *cipher, int format, Tcl_Obj *keyObj, EVP_MAC *mac) {
+int DigestCommandHandler(Tcl_Interp *interp, Tcl_Obj *cmdObj, Tcl_Obj *digestObj,
+	Tcl_Obj *cipherObj, int format, Tcl_Obj *keyObj, Tcl_Obj *macObj) {
     DigestState *statePtr;
     char *cmdName = Tcl_GetStringFromObj(cmdObj, NULL);
 
     dprintf("Called");
 
@@ -979,17 +1026,21 @@
 	Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL);
 	return TCL_ERROR;
     }
 
     /* Initialize hash function */
-    if (DigestInitialize(interp, statePtr, md, cipher, keyObj, mac) != TCL_OK) {
+    if (DigestInitialize(interp, statePtr, digestObj, cipherObj, keyObj, macObj) != TCL_OK) {
 	return TCL_ERROR;
     }
 
     /* Create instance command */
     statePtr->token = Tcl_CreateObjCommand(interp, cmdName, DigestInstanceObjCmd,
 	(ClientData) statePtr, DigestCommandDeleteHandler);
+    if (statePtr->token == NULL) {
+	DigestStateFree(statePtr);
+	return TCL_ERROR;
+    }
 
     /* Return command name */
     Tcl_SetObjResult(interp, cmdObj);
     return TCL_OK;
 }
@@ -1010,12 +1061,12 @@
  * Side effects:
  *	Sets result to message digest or error message
  *
  *-------------------------------------------------------------------
  */
-int DigestDataHandler(Tcl_Interp *interp, Tcl_Obj *dataObj, const EVP_MD *md,
-	const EVP_CIPHER *cipher, int format, Tcl_Obj *keyObj, EVP_MAC *mac) {
+int DigestDataHandler(Tcl_Interp *interp, Tcl_Obj *dataObj, Tcl_Obj *digestObj,
+	Tcl_Obj *cipherObj, int format, Tcl_Obj *keyObj, Tcl_Obj *macObj) {
     char *data;
     int data_len;
     DigestState *statePtr;
 
     dprintf("Called");
@@ -1032,11 +1083,11 @@
 	Tcl_AppendResult(interp, "Memory allocation error", (char *) NULL);
 	return TCL_ERROR;
     }
 
     /* Calc Digest */
-    if (DigestInitialize(interp, statePtr, md, cipher, keyObj, mac) != TCL_OK ||
+    if (DigestInitialize(interp, statePtr, digestObj, cipherObj, keyObj, macObj) != TCL_OK ||
 	DigestUpdate(statePtr, data, (size_t) data_len, 1) != TCL_OK ||
 	DigestFinalize(interp, statePtr, NULL) != TCL_OK) {
 	DigestStateFree(statePtr);
 	return TCL_ERROR;
     }
@@ -1061,12 +1112,12 @@
  * Side effects:
  *	Result is message digest or error message
  *
  *-------------------------------------------------------------------
  */
-int DigestFileHandler(Tcl_Interp *interp, Tcl_Obj *inFileObj, const EVP_MD *md,
-	const EVP_CIPHER *cipher, int format, Tcl_Obj *keyObj, EVP_MAC *mac) {
+int DigestFileHandler(Tcl_Interp *interp, Tcl_Obj *inFileObj, Tcl_Obj *digestObj,
+	Tcl_Obj *cipherObj, int format, Tcl_Obj *keyObj, Tcl_Obj *macObj) {
     DigestState *statePtr;
     Tcl_Channel chan = NULL;
     unsigned char buf[BUFFER_SIZE];
     int res = TCL_OK, len;
 
@@ -1090,20 +1141,19 @@
 	goto done;
     }
     Tcl_SetChannelBufferSize(chan, BUFFER_SIZE);
 
     /* Initialize hash function */
-    if ((res = DigestInitialize(interp, statePtr, md, cipher, keyObj, mac)) != TCL_OK) {
+    if ((res = DigestInitialize(interp, statePtr, digestObj, cipherObj, keyObj, macObj)) != TCL_OK) {
 	goto done;
     }
 
     /* Read file data and update hash function */
     while (!Tcl_Eof(chan)) {
 	len = Tcl_ReadRaw(chan, (char *) buf, BUFFER_SIZE);
 	if (len > 0) {
-	    if (DigestUpdate(statePtr, &buf[0], (size_t) len, 1) != TCL_OK) {
-		res = TCL_ERROR;
+	    if ((res = DigestUpdate(statePtr, &buf[0], (size_t) len, 1)) != TCL_OK) {
 		goto done;
 	    }
 	}
     }
 
@@ -1119,123 +1169,10 @@
     /* Clean-up */
     DigestStateFree(statePtr);
     return res;
 }
 
-/*******************************************************************/
-
-/*
- *-------------------------------------------------------------------
- *
- * GetDigest -- Get message digest
- *
- * Returns:
- *	EVP_MD * or NULL
- *
- *-------------------------------------------------------------------
- */
-EVP_MD *GetDigest(Tcl_Interp *interp, Tcl_Obj *objPtr, int *format) {
-    const EVP_MD *md = NULL;
-    char *digestName = Tcl_GetStringFromObj(objPtr, NULL);
-
-    if (digestName != NULL) {
-	md = EVP_get_digestbyname(digestName);
-	if (md == NULL) {
-	    Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL);
-	    return NULL;
-	} else if (md == EVP_shake128() || md == EVP_shake256()) {
-	    *format |= IS_XOF;
-	}
-    } else {
-	Tcl_AppendResult(interp, "No digest specified", NULL);
-	return NULL;
-    }
-    return md;
-}
-
-/*
- *-------------------------------------------------------------------
- *
- * GetCipher -- Get cipher
- *
- * Returns:
- *	EVP_CIPHER * or NULL
- *
- *-------------------------------------------------------------------
- */
-EVP_CIPHER *GetCipher(Tcl_Interp *interp, Tcl_Obj *objPtr, int *type) {
-    const EVP_CIPHER *cipher = NULL;
-    char *cipherName = Tcl_GetStringFromObj(objPtr, NULL);
-
-    if (cipherName != NULL) {
-	cipher = EVP_get_cipherbyname(cipherName);
-	*type = TYPE_CMAC;
-	if (cipher == NULL) {
-	    Tcl_AppendResult(interp, "Invalid cipher \"", cipherName, "\"", NULL);
-	    return NULL;
-	}
-    } else {
-	Tcl_AppendResult(interp, "No cipher specified", NULL);
-	return NULL;
-    }
-    return cipher;
-}
-
-/*
- *-------------------------------------------------------------------
- *
- * GetKey -- Get key
- *
- * Returns:
- *	unsigned char * or NULL
- *
- *-------------------------------------------------------------------
- */
-unsigned char *GetKey(Tcl_Interp *interp, Tcl_Obj *objPtr, int *type) {
-    unsigned char *key = Tcl_GetByteArrayFromObj(objPtr, NULL);
-
-    if (key == NULL) {
-	Tcl_AppendResult(interp, "No key specified", NULL);
-	return NULL;
-    }
-    if (*type == TYPE_MD) {
-	*type = TYPE_HMAC;
-    }
-    return key;
-}
-
-/*
- *-------------------------------------------------------------------
- *
- * GetMAC -- Get MAC
- *
- * Returns:
- *	EVP_MAC * or NULL
- *
- *-------------------------------------------------------------------
- */
-EVP_MAC *GetMAC(Tcl_Interp *interp, Tcl_Obj *objPtr, int *type) {
-    EVP_MAC *mac = NULL;
-    char *macName = Tcl_GetStringFromObj(objPtr, NULL);
-
-    if (macName != NULL) {
-	if (strcmp(macName, "cmac") == 0) {
-	    *type = TYPE_CMAC;
-	} else if (strcmp(macName, "hmac") == 0) {
-	    *type = TYPE_HMAC;
-	} else {
-	    Tcl_AppendResult(interp, "Invalid MAC \"", macName, "\"", NULL);
-	    return NULL;
-	}
-	mac = (void *) macName;
-    } else {
-	Tcl_AppendResult(interp, "No MAC specified", NULL);
-	return NULL;
-    }
-    return mac;
-}
-
 /*******************************************************************/
 
 /*
  *-------------------------------------------------------------------
  *
@@ -1255,13 +1192,10 @@
 static int DigestMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
     int idx, start = 1, format = HEX_FORMAT, res = TCL_OK;
     Tcl_Obj *cipherObj = NULL, *cmdObj = NULL, *dataObj = NULL, *digestObj = NULL;
     Tcl_Obj *fileObj = NULL, *keyObj = NULL, *macObj = NULL;
     const char *channel = NULL, *opt;
-    const EVP_MD *md = NULL;
-    const EVP_CIPHER *cipher = NULL;
-    EVP_MAC *mac = NULL;
 
     dprintf("Called");
 
     /* Clear interp result */
     Tcl_ResetResult(interp);
@@ -1317,59 +1251,26 @@
     /* If only 1 arg left, it's the data */
     if (idx < objc && dataObj == NULL) {
 	dataObj = objv[idx];
     }
 
-    /* Get cipher */
-    if (cipherObj != NULL) {
-	if ((cipher = GetCipher(interp, cipherObj, &type)) == NULL) {
-	    return TCL_ERROR;
-	}
-    } else if (type == TYPE_CMAC) {
-	Tcl_AppendResult(interp, "No cipher specified", NULL);
-	return TCL_ERROR;
-    }
-
-    /* Get message digest */
-    if (digestObj != NULL) {
-	if ((md = GetDigest(interp, digestObj, &format)) == NULL) {
-	    return TCL_ERROR;
-	}
-    } else if (type == TYPE_MD || type == TYPE_HMAC) {
-	Tcl_AppendResult(interp, "No digest specified", NULL);
-	return TCL_ERROR;
-    }
-
-    /* Get key */
-    if (keyObj != NULL) {
-	if (GetKey(interp, keyObj, &type) == NULL) {
-	    return TCL_ERROR;	
-	}
-    } else if (type != TYPE_MD) {
-	Tcl_AppendResult(interp, "No key specified", NULL);
-	return TCL_ERROR;
-    }
-
-    /* Get MAC */
-    if (macObj != NULL) {
-	if ((mac = GetMAC(interp, macObj, &type)) == NULL) {
-	    return TCL_ERROR;
-	}
-    } else if (type == TYPE_MAC) {
-	Tcl_AppendResult(interp, "No MAC specified", NULL);
-	return TCL_ERROR;
+    /* Check types */
+    if (type == TYPE_MD && cipherObj != NULL) {
+	type = TYPE_CMAC;
+    } else if (type == TYPE_MD && keyObj != NULL) {
+	type = TYPE_HMAC;
     }
 
     /* Calc digest on file, stacked channel, using instance command, or data blob */
     if (fileObj != NULL) {
-	res = DigestFileHandler(interp, fileObj, md, cipher, format | type, keyObj, mac);
+	res = DigestFileHandler(interp, fileObj, digestObj, cipherObj, format | type, keyObj, macObj);
     } else if (channel != NULL) {
-	res = DigestChannelHandler(interp, channel, md, cipher, format | type, keyObj, mac);
+	res = DigestChannelHandler(interp, channel, digestObj, cipherObj, format | type, keyObj, macObj);
     } else if (cmdObj != NULL) {
-	res = DigestCommandHandler(interp, cmdObj, md, cipher, format | type, keyObj, mac);
+	res = DigestCommandHandler(interp, cmdObj, digestObj, cipherObj, format | type, keyObj, macObj);
     } else if (dataObj != NULL) {
-	res = DigestDataHandler(interp, dataObj, md, cipher, format | type, keyObj, mac);
+	res = DigestDataHandler(interp, dataObj, digestObj, cipherObj, format | type, keyObj, macObj);
     } else {
 	Tcl_AppendResult(interp, "No operation specified: Use -channel, -command, -data, or -file option", NULL);
 	res = TCL_ERROR;
     }
     return res;

Index: generic/tlsInfo.c
==================================================================
--- generic/tlsInfo.c
+++ generic/tlsInfo.c
@@ -393,14 +393,17 @@
  *	None.
  *
  *-------------------------------------------------------------------
  */
 int DigestInfo(Tcl_Interp *interp, char *digestName) {
+    EVP_MD *md;
     Tcl_Obj *objPtr, *listPtr;
-    EVP_MD *md = EVP_get_digestbyname(digestName);
     unsigned long flags;
 
+    /* Get message digest */
+    md = EVP_get_digestbyname(digestName);
+
     if (md == NULL) {
 	Tcl_AppendResult(interp, "Invalid digest \"", digestName, "\"", NULL);
 	return TCL_ERROR;
     }
 
@@ -507,11 +510,26 @@
  *	None.
  *
  *-------------------------------------------------------------------
  */
 int MacInfo(Tcl_Interp *interp, char *macName) {
-     return TCL_OK;
+    if (strcmp(macName, "cmac") != 0 && strcmp(macName, "hmac") != 0) {
+	Tcl_AppendResult(interp, "Invalid MAC \"", macName, "\"", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Get properties */
+    objPtr = Tcl_NewListObj(0, NULL);
+    if (objPtr == NULL) {
+	return TCL_ERROR;
+    }
+    LAPPEND_STR(interp, objPtr, "name", macName, -1);
+    LAPPEND_STR(interp, objPtr, "description", "", -1);
+    LAPPEND_STR(interp, objPtr, "provider", "", -1);
+
+    Tcl_SetObjResult(interp, objPtr);
+    return TCL_OK;
 }
 
 /*
  *-------------------------------------------------------------------
  *
@@ -592,11 +610,36 @@
  *	None.
  *
  *-------------------------------------------------------------------
  */
 int PkeyInfo(Tcl_Interp *interp, char *pkeyName) {
-     return TCL_OK;
+    Tcl_Obj *objPtr;
+    EVP_PKEY *pkey = NULL;
+
+/* In work */
+    if (pkey == NULL) {
+	Tcl_AppendResult(interp, "Invalid public key method \"", pkeyName, "\"", NULL);
+	return TCL_ERROR;
+    }
+
+    /* Get properties */
+    objPtr = Tcl_NewListObj(0, NULL);
+    if (objPtr == NULL) {
+	return TCL_ERROR;
+    }
+    LAPPEND_STR(interp, objPtr, "name", OBJ_nid2ln(EVP_PKEY_id(pkey)), -1);
+    LAPPEND_STR(interp, objPtr, "description", "", -1);
+    LAPPEND_STR(interp, objPtr, "baseId", OBJ_nid2ln(EVP_PKEY_base_id(pkey)), -1);
+    LAPPEND_STR(interp, objPtr, "provider", "", -1);
+    LAPPEND_STR(interp, objPtr, "type", OBJ_nid2ln(EVP_PKEY_type(EVP_PKEY_id(pkey))), -1);
+
+    LAPPEND_INT(interp, objPtr, "size", EVP_PKEY_size(pkey));
+    LAPPEND_INT(interp, objPtr, "bits", EVP_PKEY_bits(pkey));
+    LAPPEND_INT(interp, objPtr, "security_bits", EVP_PKEY_security_bits(pkey));
+
+    Tcl_SetObjResult(interp, objPtr);
+    return TCL_OK;
 }
 
 /*
  *-------------------------------------------------------------------
  *