Index: generic/tlsDigest.c
==================================================================
--- generic/tlsDigest.c
+++ generic/tlsDigest.c
@@ -1247,11 +1247,11 @@
 	/* Get option */
 	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
 	    return TCL_ERROR;
 	}
 
-	/* Validate arg has value */
+	/* Validate arg has a value */
 	if (fn > _opt_hexadecimal) {
 	    if (++idx >= objc) {
 		Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
 		return TCL_ERROR;
 	    }

Index: generic/tlsEncrypt.c
==================================================================
--- generic/tlsEncrypt.c
+++ generic/tlsEncrypt.c
@@ -1262,11 +1262,11 @@
 	/* Get option */
 	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
 	    return TCL_ERROR;
 	}
 
-	/* Validate arg has value */
+	/* Validate arg has a value */
 	if (++idx >= objc) {
 	    Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
 	return TCL_ERROR;
     }
 

Index: generic/tlsInfo.c
==================================================================
--- generic/tlsInfo.c
+++ generic/tlsInfo.c
@@ -6,11 +6,10 @@
  * Copyright (C) 2023 Brian O'Hagan
  *
  */
 
 #include "tlsInt.h"
-#include "tclOpts.h"
 #include <openssl/crypto.h>
 #include <openssl/ssl.h>
 #include <openssl/safestack.h>
 
 /*
@@ -147,10 +146,36 @@
     LAPPEND_BOOL(interp, listObj, "Custom Cipher", flags & EVP_CIPH_FLAG_CUSTOM_CIPHER);
     LAPPEND_BOOL(interp, listObj, "AEAD Cipher", flags & EVP_CIPH_FLAG_AEAD_CIPHER);
     LAPPEND_BOOL(interp, listObj, "Custom Copy", flags & EVP_CIPH_CUSTOM_COPY);
     LAPPEND_BOOL(interp, listObj, "Non FIPS Allow", flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW);
     LAPPEND_OBJ(interp, resultObj, "flags", listObj);
+
+    /* CTX only properties */
+    {
+	EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+	int tag_len = 0;
+
+	EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL);
+	if (mode == EVP_CIPH_GCM_MODE || mode == EVP_CIPH_OCB_MODE) {
+	    tag_len = EVP_GCM_TLS_TAG_LEN; /* EVP_MAX_AEAD_TAG_LENGTH */
+	} else if (mode == EVP_CIPH_CCM_MODE) {
+	    tag_len = EVP_CCM_TLS_TAG_LEN;
+	} else if (cipher == EVP_get_cipherbyname("chacha20-poly1305")) {
+	    tag_len = EVP_CHACHAPOLY_TLS_TAG_LEN; /* POLY1305_BLOCK_SIZE */
+	}
+	EVP_CIPHER_CTX_free(ctx);
+	LAPPEND_INT(interp, resultObj, "tag_length", tag_len);
+    }
+    
+    /* AEAD properties */
+    {
+	int aad_len = 0;
+	if (flags & EVP_CIPH_FLAG_AEAD_CIPHER) {
+	    aad_len = EVP_AEAD_TLS1_AAD_LEN;
+	}
+	LAPPEND_INT(interp, resultObj, "aad_length", aad_len);
+    }
 
     Tcl_SetObjResult(interp, resultObj);
     return TCL_OK;
 }
 
@@ -532,10 +557,78 @@
 /*******************************************************************/
 
 /*
  *-------------------------------------------------------------------
  *
+ * KdfList --
+ *
+ *	Return a list of all KDF algorithms
+ *
+ * Results:
+ *	A standard Tcl list.
+ *
+ * Side effects:
+ *	None.
+ *
+ *-------------------------------------------------------------------
+ */
+int KdfList(Tcl_Interp *interp, char *select_name) {
+    Tcl_Obj *resultObj = Tcl_NewListObj(0, NULL);
+    if (resultObj == NULL) {
+	return TCL_ERROR;
+    }
+
+    Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("hkdf", -1));
+    Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("pbkdf2", -1));
+    Tcl_ListObjAppendElement(interp, resultObj, Tcl_NewStringObj("scrypt", -1));
+    Tcl_SetObjResult(interp, resultObj);
+    return TCL_OK;
+}
+
+/*
+ *-------------------------------------------------------------------
+ *
+ * KdfsObjCmd --
+ *
+ *	Return a list of all valid Key Derivation Function (KDF).
+ *
+ * Results:
+ *	A standard Tcl list.
+ *
+ * Side effects:
+ *	None.
+ *
+ *-------------------------------------------------------------------
+ */
+int KdfsObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
+    dprintf("Called");
+
+    /* Clear errors */
+    Tcl_ResetResult(interp);
+    ERR_clear_error();
+
+
+    /* Validate arg count */
+    if (objc == 1) {
+	return KdfList(interp, NULL);
+
+    } else if (objc == 2) {
+
+
+    } else {
+	Tcl_WrongNumArgs(interp, 1, objv, "?name?");
+	return TCL_ERROR;
+    }
+    return TCL_OK;
+	clientData = clientData;
+}
+
+/*******************************************************************/
+
+/*
+ *-------------------------------------------------------------------
+ *
  * MacInfo --
  *
  *	Return a list of properties and values for macName.
  *
  * Results:
@@ -880,12 +973,13 @@
 #endif
 
     Tcl_CreateObjCommand(interp, "tls::cipher", CipherObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::ciphers", CiphersObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::digests", DigestsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
+    Tcl_CreateObjCommand(interp, "tls::kdfs", KdfsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::macs", MacsObjCmd, (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
     Tcl_CreateObjCommand(interp, "tls::pkeys", PkeysObjCmd, (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);
     return TCL_OK;
 }