Check-in [c7540ccbf1]
Overview
Comment:Changed options processing from using string compares in macros to using Tcl_GetIndexFromObj and switch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | crypto
Files: files | file ages | folders
SHA3-256: c7540ccbf12c037619fa2280ecd2139dcb39a9cd135794b6c3641f9b5cb1f701
User & Date: bohagan on 2023-12-16 04:56:30
Other Links: branch diff | manifest | tags
Context
2023-12-19
05:53
Added test vectors files for hash functions. Added test files and make script to generate TCL test cases from test vector files. These files come from NIST, IETC, etc. documents, examples, etc. check-in: 25db067636 user: bohagan tags: crypto
2023-12-16
04:56
Changed options processing from using string compares in macros to using Tcl_GetIndexFromObj and switch. check-in: c7540ccbf1 user: bohagan tags: crypto
2023-12-11
05:24
Added KDF module to derive keys and ivs from passwords and salts. Added -hash option as alias for -digest. check-in: d4c2159faf user: bohagan tags: crypto
Changes

Modified generic/tclOpts.h from [c197957f96] to [e342c63c26].

1
2
3
4

5
6
7
8
9
10
11

12
13
14
15
16

17
18
19
20
21
22
23
24
25


26
27
28



29
30
31
32
33
34
35

36
37
38

39
40
41
42
43
44
45
46


47
48
49

50
51

52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
1



2

3
4
5
6
7

8





9









10
11
12


13
14
15
16
17





18



19








20
21

22

23


24



25
26











27
28

-
-
-
+
-





-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+

-
-
+
+
+


-
-
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
+
+
-

-
+
-
-
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-


/*
 *  Copyright (C) 1997-2000 Matt Newman <[email protected]>
 *
 * Stylized option processing - requires consistent
 * Convenient option processing
 * external vars: opt, idx, objc, objv
 */

#ifndef _TCL_OPTS_H
#define _TCL_OPTS_H

#define OPTFLAG(option, var, val)		\
#define GET_OPT_BOOL(objPtr, varPtr) \
    if (strcmp(opt, (option)) == 0) {		\
	var = val;				\
	continue;				\
    }

    if (Tcl_GetBooleanFromObj(interp, objPtr, varPtr) != TCL_OK) {	\
#define OPT_PROLOG(option)			\
    if (strcmp(opt, (option)) == 0) {		\
	if (++idx >= objc) {			\
	    Tcl_AppendResult(interp,		\
		"no argument given for ",	\
		(option), " option",		\
		(char *) NULL);			\
	    return TCL_ERROR;			\
	}
	return TCL_ERROR;					\
    }

#define OPT_POSTLOG()				\
	continue;				\
#define GET_OPT_INT(objPtr, varPtr) \
    if (Tcl_GetIntFromObj(interp, objPtr, varPtr) != TCL_OK) {	\
	return TCL_ERROR;					\
    }

#define OPTOBJ(option, var)			\
    OPT_PROLOG(option)				\
    var = objv[idx];				\
    OPT_POSTLOG()

#define GET_OPT_STRING(objPtr, var, lenPtr) \
#define OPTSTR(option, var)			\
    OPT_PROLOG(option)				\
    var = Tcl_GetStringFromObj(objv[idx], (Tcl_Size *)NULL);\
    if ((var = Tcl_GetStringFromObj(objPtr, lenPtr)) == NULL) {	\
    OPT_POSTLOG()

#define OPTINT(option, var)			\
    OPT_PROLOG(option)				\
    if (Tcl_GetIntFromObj(interp, objv[idx],	\
	    &(var)) != TCL_OK) {		\
	    return TCL_ERROR;			\
    }						\
	return TCL_ERROR;					\
    }								\
    OPT_POSTLOG()

#define OPTBOOL(option, var)			\
#define GET_OPT_BYTE_ARRAY(objPtr, var, lenPtr) \
    OPT_PROLOG(option)				\
    if (Tcl_GetBooleanFromObj(interp, objv[idx],\
    if ((var = Tcl_GetByteArrayFromObj(objPtr, lenPtr)) == NULL) {	\
	    &(var)) != TCL_OK) {		\
	    return TCL_ERROR;			\
    }						\
	return TCL_ERROR;					\
    }								\
    OPT_POSTLOG()

#define OPTBYTE(option, var, lvar)		\
    OPT_PROLOG(option)				\
    var = Tcl_GetByteArrayFromObj(objv[idx], &(lvar));\
    OPT_POSTLOG()

#define OPTBAD(type, list)			\
    Tcl_AppendResult(interp, "bad ", (type),	\
		" \"", opt, "\": must be ",	\
		(list), (char *) NULL)

#endif /* _TCL_OPTS_H */

Modified generic/tls.c from [4273abe6e0] to [5f4251e5e6].

1008
1009
1010
1011
1012
1013
1014














1015
1016
1017
1018
1019
1020
1021
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035







+
+
+
+
+
+
+
+
+
+
+
+
+
+








    dprintf("Returning TCL_OK with data \"%i\"", ret);
    Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
    return(TCL_OK);
	clientData = clientData;
}

static const char *command_opts [] = {
    "-alpn", "-cadir", "-cafile", "-cert", "-certfile", "-cipher", "-ciphers", "-ciphersuites",
    "-command", "-dhparams", "-key", "-keyfile", "-model", "-password", "-post_handshake",
    "-request", "-require", "-security_level", "-server", "-servername", "-session_id", "-ssl2",
    "-ssl3", "-tls1", "-tls1.1", "-tls1.2", "-tls1.3", "-validatecommand", "-vcmd", NULL};

enum _command_opts {
    _opt_alpn, _opt_cadir, _opt_cafile, _opt_cert, _opt_certfile, _opt_cipher, _opt_ciphers,
    _opt_ciphersuite, _opt_cmd, _opt_dhparams, _opt_key, _opt_keyfile, _opt_model, _opt_password,
    _opt_handshake, _opt_request, _opt_require, _opt_security_level, _opt_server, _opt_servername,
    _opt_session_id, _opt_ssl2, _opt_ssl3, _opt_tls1, _opt_tls11, _opt_tls12, _opt_tls13,
    _opt_validate, _opt_vcmd
};

/*
 *-------------------------------------------------------------------
 *
 * ImportObjCmd --
 *
 *	This procedure is invoked to process the "ssl" command
 *
1030
1031
1032
1033
1034
1035
1036
1037
1038


1039
1040
1041

1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057

1058

1059
1060
1061
1062
1063
1064
1065
1044
1045
1046
1047
1048
1049
1050


1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072

1073
1074
1075
1076
1077
1078
1079
1080







-
-
+
+


-
+
















+
-
+







 *-------------------------------------------------------------------
 */
static int
ImportObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    Tcl_Channel chan;		/* The channel to set a mode on. */
    State *statePtr;		/* client state for ssl socket */
    SSL_CTX *ctx	        = NULL;
    Tcl_Obj *script	        = NULL;
    Tcl_Obj *password	        = NULL;
    Tcl_Obj *cmdObj	        = NULL;
    Tcl_Obj *passwdObj	        = NULL;
    Tcl_Obj *vcmd	        = NULL;
    Tcl_DString upperChannelTranslation, upperChannelBlocking, upperChannelEncoding, upperChannelEOFChar;
    int idx, len;
    int idx, len, fn;
    int flags		        = TLS_TCL_INIT;
    int server		        = 0;	/* is connection incoming or outgoing? */
    char *keyfile	        = NULL;
    char *certfile	        = NULL;
    unsigned char *key  	= NULL;
    int key_len                 = 0;
    unsigned char *cert         = NULL;
    int cert_len                = 0;
    char *ciphers	        = NULL;
    char *ciphersuites	        = NULL;
    char *CAfile	        = NULL;
    char *CAdir		        = NULL;
    char *DHparams	        = NULL;
    char *model		        = NULL;
    char *servername	        = NULL;	/* hostname for Server Name Indication */
    const unsigned char *session_id = NULL;
    int sess_len                = 0;
    Tcl_Obj *alpn		= NULL;
    Tcl_Obj *alpnObj		= NULL;
    int ssl2 = 0, ssl3 = 0;
    int tls1 = 1, tls1_1 = 1, tls1_2 = 1, tls1_3 = 1;
    int proto = 0, level = -1;
    int verify = 0, require = 0, request = 1, post_handshake = 0;

    dprintf("Called");

1088
1089
1090
1091
1092
1093
1094



1095
1096
1097


























































































1098
1099

1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129

1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112



1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203

1204






























1205

1206


1207
1208
1209
1210
1211
1212
1213







+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-

-
-







	return TCL_ERROR;
    }

    /* Make sure to operate on the topmost channel */
    chan = Tcl_GetTopChannel(chan);

    for (idx = 2; idx < objc; idx++) {
	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
	    return TCL_ERROR;
	}
	char *opt = Tcl_GetStringFromObj(objv[idx], NULL);

	if (opt[0] != '-')

	/* Validate arg has value */
	if (++idx >= objc) {
	    Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
	    return TCL_ERROR;
	}

	switch(fn) {
	case _opt_alpn:
	    alpnObj = objv[idx];
	    break;
	case _opt_cadir:
	    GET_OPT_STRING(objv[idx], CAdir, NULL);
	    break;
	case _opt_cafile:
	    GET_OPT_STRING(objv[idx], CAfile, NULL);
	    break;
	case _opt_cert:
	    GET_OPT_BYTE_ARRAY(objv[idx], cert, &cert_len);
	    break;
	case _opt_certfile:
	    GET_OPT_STRING(objv[idx], certfile, NULL);
	    break;
	case _opt_cipher:
	case _opt_ciphers:
	    GET_OPT_STRING(objv[idx], ciphers, NULL);
	    break;
	case _opt_ciphersuite:
	    GET_OPT_STRING(objv[idx], ciphersuites, NULL);
	    break;
	case _opt_cmd:
	    cmdObj = objv[idx];
	    break;
	case _opt_dhparams:
	    GET_OPT_STRING(objv[idx], DHparams, NULL);
	    break;
	case _opt_key:
	    GET_OPT_BYTE_ARRAY(objv[idx], key, &key_len);
	    break;
	case _opt_keyfile:
	    GET_OPT_STRING(objv[idx], keyfile, NULL);
	    break;
	case _opt_model:
	    GET_OPT_STRING(objv[idx], model, NULL);
	    break;
	case _opt_password:
	    passwdObj = objv[idx];
	    break;
	case _opt_handshake:
	    GET_OPT_BOOL(objv[idx], &post_handshake);
	    break;
	case _opt_request:
	    GET_OPT_BOOL(objv[idx], &request);
	    break;
	case _opt_require:
	    GET_OPT_BOOL(objv[idx], &require);
	    break;
	case _opt_security_level:
	    GET_OPT_INT(objv[idx], &level);
	    break;
	case _opt_server:
	    GET_OPT_BOOL(objv[idx], &server);
	    break;
	case _opt_servername:
	    GET_OPT_STRING(objv[idx], servername, NULL);
	    break;
	case _opt_session_id:
	    GET_OPT_BYTE_ARRAY(objv[idx], session_id, &sess_len);
	    break;
	case _opt_ssl2:
	    GET_OPT_INT(objv[idx], &ssl2);
	    break;
	case _opt_ssl3:
	    GET_OPT_INT(objv[idx], &ssl3);
	    break;
	case _opt_tls1:
	    GET_OPT_INT(objv[idx], &tls1);
	    break;
	case _opt_tls11:
	    GET_OPT_INT(objv[idx], &tls1_1);
	    break;
	case _opt_tls12:
	    GET_OPT_INT(objv[idx], &tls1_2);
	    break;
	case _opt_tls13:
	    GET_OPT_INT(objv[idx], &tls1_3);
	    break;
	case _opt_validate:
	case _opt_vcmd:
	    vcmd = objv[idx];
	    break;

	}
	OPTOBJ("-alpn", alpn);
	OPTSTR("-cadir", CAdir);
	OPTSTR("-cafile", CAfile);
	OPTBYTE("-cert", cert, cert_len);
	OPTSTR("-certfile", certfile);
	OPTSTR("-cipher", ciphers);
	OPTSTR("-ciphers", ciphers);
	OPTSTR("-ciphersuites", ciphersuites);
	OPTOBJ("-command", script);
	OPTSTR("-dhparams", DHparams);
	OPTBYTE("-key", key, key_len);
	OPTSTR("-keyfile", keyfile);
	OPTSTR("-model", model);
	OPTOBJ("-password", password);
	OPTBOOL("-post_handshake", post_handshake);
	OPTBOOL("-request", request);
	OPTBOOL("-require", require);
	OPTINT("-security_level", level);
	OPTBOOL("-server", server);
	OPTSTR("-servername", servername);
	OPTSTR("-session_id", session_id);
	OPTBOOL("-ssl2", ssl2);
	OPTBOOL("-ssl3", ssl3);
	OPTBOOL("-tls1", tls1);
	OPTBOOL("-tls1.1", tls1_1);
	OPTBOOL("-tls1.2", tls1_2);
	OPTBOOL("-tls1.3", tls1_3);
	OPTOBJ("-validatecommand", vcmd);
	OPTOBJ("-vcmd", vcmd);

    }
	OPTBAD("option", "-alpn, -cadir, -cafile, -cert, -certfile, -cipher, -ciphersuites, -command, -dhparams, -key, -keyfile, -model, -password, -post_handshake, -request, -require, -security_level, -server, -servername, -session_id, -ssl2, -ssl3, -tls1, -tls1.1, -tls1.2, -tls1.3, or -validatecommand");

	return TCL_ERROR;
    }
    if (request)		verify |= SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_PEER;
    if (request && require)	verify |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
    if (request && post_handshake)	verify |= SSL_VERIFY_POST_HANDSHAKE;
    if (verify == 0)		verify = SSL_VERIFY_NONE;

    proto |= (ssl2 ? TLS_PROTO_SSL2 : 0);
    proto |= (ssl3 ? TLS_PROTO_SSL3 : 0);
1160
1161
1162
1163
1164
1165
1166
1167
1168


1169
1170

1171
1172
1173
1174
1175
1176
1177


1178
1179

1180
1181
1182
1183
1184
1185
1186
1233
1234
1235
1236
1237
1238
1239


1240
1241
1242

1243
1244
1245
1246
1247
1248


1249
1250
1251

1252
1253
1254
1255
1256
1257
1258
1259







-
-
+
+

-
+





-
-
+
+

-
+








    statePtr->flags	= flags;
    statePtr->interp	= interp;
    statePtr->vflags	= verify;
    statePtr->err	= "";

    /* allocate script */
    if (script) {
	(void) Tcl_GetStringFromObj(script, &len);
    if (cmdObj != NULL) {
	(void) Tcl_GetStringFromObj(cmdObj, &len);
	if (len) {
	    statePtr->callback = script;
	    statePtr->callback = cmdObj;
	    Tcl_IncrRefCount(statePtr->callback);
	}
    }

    /* allocate password */
    if (password) {
	(void) Tcl_GetStringFromObj(password, &len);
    if (passwdObj != NULL) {
	(void) Tcl_GetStringFromObj(passwdObj, &len);
	if (len) {
	    statePtr->password = password;
	    statePtr->password = passwdObj;
	    Tcl_IncrRefCount(statePtr->password);
	}
    }

    /* allocate validate command */
    if (vcmd) {
	(void) Tcl_GetStringFromObj(vcmd, &len);
1283
1284
1285
1286
1287
1288
1289
1290

1291
1292

1293
1294
1295
1296
1297
1298
1299
1300
1301
1302

1303
1304
1305
1306
1307
1308
1309

1310
1311
1312
1313
1314
1315
1316
1356
1357
1358
1359
1360
1361
1362

1363
1364

1365
1366
1367
1368
1369
1370
1371
1372
1373
1374

1375
1376
1377
1378
1379
1380
1381

1382
1383
1384
1385
1386
1387
1388
1389







-
+

-
+









-
+






-
+







	    Tcl_SetErrorCode(interp, "TLS", "IMPORT", "HOSTNAME", "FAILED", (char *) NULL);
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}
    }

    /* Resume session id */
    if (session_id && strlen(session_id) <= SSL_MAX_SID_CTX_LENGTH) {
    if (session_id && sess_len <= SSL_MAX_SID_CTX_LENGTH) {
	/* SSL_set_session() */
	if (!SSL_SESSION_set1_id_context(SSL_get_session(statePtr->ssl), session_id, (unsigned int) strlen(session_id))) {
	if (!SSL_SESSION_set1_id_context(SSL_get_session(statePtr->ssl), session_id, (unsigned int) sess_len)) {
	    Tcl_AppendResult(interp, "Resume session id ", session_id, " failed", (char *) NULL);
	    Tcl_SetErrorCode(interp, "TLS", "IMPORT", "SESSION", "FAILED", (char *) NULL);
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}
    }

    /* Enable Application-Layer Protocol Negotiation. Examples are: http/1.0,
	http/1.1, h2, h3, ftp, imap, pop3, xmpp-client, xmpp-server, mqtt, irc, etc. */
    if (alpn) {
    if (alpnObj != NULL) {
	/* Convert a TCL list into a protocol-list in wire-format */
	unsigned char *protos, *p;
	unsigned int protos_len = 0;
	int i, len, cnt;
	Tcl_Obj **list;

	if (Tcl_ListObjGetElements(interp, alpn, &cnt, &list) != TCL_OK) {
	if (Tcl_ListObjGetElements(interp, alpnObj, &cnt, &list) != TCL_OK) {
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}

	/* Determine the memory required for the protocol-list */
	for (i = 0; i < cnt; i++) {
	    Tcl_GetStringFromObj(list[i], &len);

Modified generic/tlsDigest.c from [59f6eb5d91] to [188fdc0d84].

816
817
818
819
820
821
822

823
824
825
826
827
828
829
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830







+







    Tcl_Channel chan;
    DigestState *statePtr;

    dprintf("Called");

    /* Validate args */
    if (channel == (const char *) NULL) {
	Tcl_AppendResult(interp, "No channel", (char *) NULL);
	return TCL_ERROR;
    }

    /* Get channel Id */
    chan = Tcl_GetChannel(interp, channel, &mode);
    if (chan == (Tcl_Channel) NULL) {
	return TCL_ERROR;
1169
1170
1171
1172
1173
1174
1175









1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193

1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211


1212
1213
1214
1215
1216
1217
1218
1219
1220









1221
1222
1223
1224
1225
1226




1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247






















































1248
1249
1250


1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261

























1262
1263
1264
1265
1266
1267
1268
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202

1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223









1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236


1237
1238
1239
1240





















1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294



1295
1296




1297
1298
1299




1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331







+
+
+
+
+
+
+
+
+

















-
+


















+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+




-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-



-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    /* Clean-up */
    DigestStateFree(statePtr);
    return res;
}

/*******************************************************************/

static const char *command_opts [] = { "-bin", "-binary", "-hex", "-hexadecimal",
    "-chan", "-channel", "-cipher", "-command", "-data", "-digest", "-file", "-filename",
    "-hash", "-key", "-mac", NULL};

enum _command_opts {
    _opt_bin, _opt_binary, _opt_hex, _opt_hexadecimal, _opt_chan, _opt_channel, _opt_cipher,
    _opt_command, _opt_data, _opt_digest, _opt_file, _opt_filename, _opt_hash, _opt_key, _opt_mac
};

/*
 *-------------------------------------------------------------------
 *
 * DigestMain --
 *
 *	Return message digest or Message Authentication Code (MAC) of
 *	data using user specified hash function.
 *
 * Returns:
 *	TCL_OK or TCL_ERROR
 *
 * Side effects:
 *	Sets result to message digest or error message
 *
 *-------------------------------------------------------------------
 */
static int DigestMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    int idx, start = 1, format = HEX_FORMAT, res = TCL_OK;
    int start = 1, format = HEX_FORMAT, res = TCL_OK, fn;
    Tcl_Obj *cipherObj = NULL, *cmdObj = NULL, *dataObj = NULL, *digestObj = NULL;
    Tcl_Obj *fileObj = NULL, *keyObj = NULL, *macObj = NULL;
    const char *channel = NULL, *opt;

    dprintf("Called");

    /* Clear interp result */
    Tcl_ResetResult(interp);

    /* Validate arg count */
    if (objc < 3 || objc > 12) {
	Tcl_WrongNumArgs(interp, 1, objv, "?-bin|-hex? ?-cipher name? ?-digest name? ?-key key? ?-mac name? [-channel chan | -command cmdName | -file filename | ?-data? data]");
	return TCL_ERROR;
    }

    /* Special case of first arg is digest, cipher, or mac */
    opt = Tcl_GetStringFromObj(objv[start], NULL);
    if (opt[0] != '-') {
	switch(type) {
	case TYPE_MD:
	if (type == TYPE_MD || type == TYPE_HMAC) {
	    digestObj = objv[start];
	    start++;
	} else if (type == TYPE_CMAC) {
	    cipherObj = objv[start];
	    start++;
	} else if (type == TYPE_MAC) {
	    macObj = objv[start];
	    start++;
	case TYPE_HMAC:
	    digestObj = objv[start++];
	    break;
	case TYPE_CMAC:
	    cipherObj = objv[start++];
	    break;
	case TYPE_MAC:
	    macObj = objv[start++];
	    break;
	}
    }

    /* Get options */
    for (idx = start; idx < objc; idx++) {
	opt = Tcl_GetStringFromObj(objv[idx], NULL);
    for (int idx = start; idx < objc; idx++) {
	/* Special case for when last arg is data */
	if (idx == objc - 1) {
	    opt = Tcl_GetStringFromObj(objv[idx], NULL);

	if (opt[0] != '-') {
	    break;
	}

	OPTFLAG("-bin", format, BIN_FORMAT);
	OPTFLAG("-binary", format, BIN_FORMAT);
	OPTFLAG("-hex", format, HEX_FORMAT);
	OPTFLAG("-hexadecimal", format, HEX_FORMAT);
	OPTSTR("-chan", channel);
	OPTSTR("-channel", channel);
	OPTOBJ("-cipher", cipherObj);
	OPTOBJ("-command", cmdObj);
	OPTOBJ("-data", dataObj);
	OPTOBJ("-digest", digestObj);
	OPTOBJ("-file", fileObj);
	OPTOBJ("-filename", fileObj);
	OPTOBJ("-hash", digestObj);
	OPTOBJ("-key", keyObj);
	OPTOBJ("-mac", macObj);

	    if (opt[0] != '-' && dataObj == NULL) {
		dataObj = objv[idx];
		break;
	    }
	}

	/* Get option */
	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
	    return TCL_ERROR;
	}

	/* Validate arg has value */
	if (fn > _opt_hexadecimal) {
	    if (++idx >= objc) {
		Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
		return TCL_ERROR;
	    }
	}

	switch(fn) {
	case _opt_bin:
	case _opt_binary:
	    format = BIN_FORMAT;
	    break;
	case _opt_hex:
	case _opt_hexadecimal:
	    format = HEX_FORMAT;
	    break;
	case _opt_chan:
	case _opt_channel:
    	    GET_OPT_STRING(objv[idx], channel, NULL);
	    break;
	case _opt_cipher:
	    cipherObj = objv[idx];
	    break;
	case _opt_command:
	    cmdObj = objv[idx];
	    break;
	case _opt_data:
	    dataObj = objv[idx];
	    break;
	case _opt_digest:
	case _opt_hash:
	    digestObj = objv[idx];
	    break;
	case _opt_file:
	case _opt_filename:
	    fileObj = objv[idx];
	    break;
	case _opt_key:
	    keyObj = objv[idx];
	    break;
	case _opt_mac:
	    macObj = objv[idx];
	OPTBAD("option", "-bin, -channel, -cipher, -command, -data, -digest, -file, -filename, -hex, -key, or -mac");
	return TCL_ERROR;
    }
	    break;
	}

    /* If only 1 arg left, it's the data */
    if (idx < objc && dataObj == NULL) {
	dataObj = objv[idx];
    }

    /* Check types */
    if (type == TYPE_MD && cipherObj != NULL) {
	type = TYPE_CMAC;
    } else if (type == TYPE_MD && keyObj != NULL) {
	type = TYPE_HMAC;
    if (type == TYPE_MD) {
	 if (macObj != NULL) {
	    type = TYPE_MAC;
	} else if (cipherObj != NULL) {
	    type = TYPE_CMAC;
	} else if (keyObj != NULL) {
	    type = TYPE_HMAC;
	}
    }

    if (type == TYPE_MAC) {
	if (macObj != NULL) {
	    char *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 {
	    Tcl_AppendResult(interp, "No MAC specified", NULL);
	    return TCL_ERROR;
	}
    }

    /* Calc digest on file, stacked channel, using instance command, or data blob */
    if (fileObj != NULL) {
	res = DigestFileHandler(interp, fileObj, digestObj, cipherObj, format | type, keyObj, macObj);
    } else if (channel != NULL) {
	res = DigestChannelHandler(interp, channel, digestObj, cipherObj, format | type, keyObj, macObj);
1319
1320
1321
1322
1323
1324
1325



1326
1327
1328
1329
1330













1331
1332
1333
1334
1335

1336
1337
1338
1339
1340

1341
1342
1343
1344
1345

1346
1347
1348
1349
1350

1351
1352
1353
1354
1355

1356
1357
1358
1359
1360
1361
1362
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391





1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407


1408
1409
1410
1411


1412
1413
1414
1415


1416
1417
1418
1419


1420
1421
1422
1423


1424
1425
1426
1427
1428
1429
1430
1431







+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+



-
-
+



-
-
+



-
-
+



-
-
+



-
-
+







 *	TCL_OK or TCL_ERROR
 *
 * Side effects:
 *	Sets result to message digest or error message
 *
 *-------------------------------------------------------------------
 */
 int TemplateCmd(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], char *digestName, int format) {
    Tcl_Obj *dataObj, *digestObj;
    int res;
 #define VALIDATE_ARGC(objc, objv) { \
    if (objc != 2) { \
	Tcl_WrongNumArgs(interp, 1, objv, "data"); \
	return TCL_ERROR; \
    } \

    if (objc == 2) {
	dataObj = objv[1];
    } else {
	Tcl_WrongNumArgs(interp, 1, objv, "data");
	return TCL_ERROR;
    }

    digestObj = Tcl_NewStringObj(digestName, -1);
    Tcl_IncrRefCount(digestObj);
    res = DigestDataHandler(interp, dataObj, digestObj, NULL, format, NULL, NULL);
    Tcl_DecrRefCount(digestObj);
    return res;
}
 
int MD4ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    VALIDATE_ARGC(objc, objv);
    return DigestDataHandler(interp, objv[1], EVP_md4(), NULL, HEX_FORMAT | TYPE_MD, NULL, NULL);
    return TemplateCmd(interp, objc, objv, "md4", HEX_FORMAT | TYPE_MD);
}

int MD5ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    VALIDATE_ARGC(objc, objv);
    return DigestDataHandler(interp, objv[1], EVP_md5(), NULL, HEX_FORMAT | TYPE_MD, NULL, NULL);
    return TemplateCmd(interp, objc, objv, "md5", HEX_FORMAT | TYPE_MD);
}

int SHA1ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    VALIDATE_ARGC(objc, objv);
    return DigestDataHandler(interp, objv[1], EVP_sha1(), NULL, HEX_FORMAT | TYPE_MD, NULL, NULL);
    return TemplateCmd(interp, objc, objv, "sha1", HEX_FORMAT | TYPE_MD);
}

int SHA256ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    VALIDATE_ARGC(objc, objv);
    return DigestDataHandler(interp, objv[1], EVP_sha256(), NULL, HEX_FORMAT | TYPE_MD, NULL, NULL);
    return TemplateCmd(interp, objc, objv, "sha256", HEX_FORMAT | TYPE_MD);
}

int SHA512ObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    VALIDATE_ARGC(objc, objv);
    return DigestDataHandler(interp, objv[1], EVP_sha512(), NULL, HEX_FORMAT | TYPE_MD, NULL, NULL);
    return TemplateCmd(interp, objc, objv, "sha512", HEX_FORMAT | TYPE_MD);
}

/*
 *-------------------------------------------------------------------
 *
 * Tls_DigestCommands --
 *

Modified generic/tlsEncrypt.c from [6005ec3c3c] to [c0069dd5ac].

782
783
784
785
786
787
788

789
790
791
792
793
794
795
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796







+







    Tcl_Channel chan;
    EncryptState *statePtr;

    dprintf("Called");

    /* Validate args */
    if (channel == (const char *) NULL) {
	Tcl_AppendResult(interp, "No channel", (char *) NULL);
	return TCL_ERROR;
    }

    /* Get channel Id */
    chan = Tcl_GetChannel(interp, channel, &mode);
    if (chan == (Tcl_Channel) NULL) {
	return TCL_ERROR;
1191
1192
1193
1194
1195
1196
1197









1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217

1218
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232

1233
1234
1235




1236
1237
1238
1239
1240



1241
1242
1243
1244
1245
1246
1247






1248
1249
1250


1251
1252
1253
1254

1255
1256
1257
1258
1259
1260





1261
1262
1263
1264
1265
1266



































1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287

1288
1289
1290
1291
1292
1293
1294
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226

1227
1228
1229
1230
1231
1232
1233
1234
1235

1236
1237
1238
1239
1240
1241
1242
1243



1244
1245
1246
1247
1248
1249
1250
1251

1252
1253
1254
1255






1256
1257
1258
1259
1260
1261



1262
1263




1264






1265
1266
1267
1268
1269
1270
1271
1272



1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327

1328
1329
1330
1331
1332
1333
1334
1335







+
+
+
+
+
+
+
+
+



















-
+








-
+






+
-
-
-
+
+
+
+




-
+
+
+

-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+



-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




















-
+







	EVP_CIPHER_CTX_free(ctx);
    }
    return res;
}

/*******************************************************************/

static const char *command_opts [] = {
    "-chan", "-channel", "-cipher", "-command", "-data", "-digest", "-infile", "-filename",
    "-outfile", "-hash", "-iv", "-key", "-mac", NULL};

enum _command_opts {
    _opt_chan, _opt_channel, _opt_cipher, _opt_command, _opt_data, _opt_digest, _opt_infile,
    _opt_filename, _opt_outfile, _opt_hash, _opt_iv, _opt_key, _opt_mac
};

/*
 *-------------------------------------------------------------------
 *
 * EncryptMain --
 *
 *	Perform encryption function and return result.
 *
 * Returns:
 *	TCL_OK or TCL_ERROR
 *
 * Side effects:
 *	Sets result or error message
 *
 *-------------------------------------------------------------------
 */
static int EncryptMain(int type, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    Tcl_Obj *cipherObj = NULL, *cmdObj = NULL, *dataObj = NULL, *digestObj = NULL;
    Tcl_Obj *inFileObj = NULL, *outFileObj = NULL, *keyObj = NULL, *ivObj = NULL, *macObj = NULL;
    const char *channel = NULL, *opt;
    int idx, res, start = 1;
    int res, start = 1, fn;

    dprintf("Called");

    /* Clear interp result */
    Tcl_ResetResult(interp);

    /* Validate arg count */
    if (objc < 3 || objc > 12) {
	Tcl_WrongNumArgs(interp, 1, objv, "-cipher name ?-digest name? -key key ?-iv string? ?-mac name? [-channel chan | -command cmdName | -infile filename -outfile filename | -data data]");
	Tcl_WrongNumArgs(interp, 1, objv, "?-cipher? name ?-digest name? -key key ?-iv string? ?-mac name? [-channel chan | -command cmdName | -infile filename -outfile filename | ?-data? data]");
	return TCL_ERROR;
    }

    /* Special case of first arg is cipher */
    opt = Tcl_GetStringFromObj(objv[start], NULL);
    if (opt[0] != '-') {
	switch(type) {
	if (type == TYPE_ENCRYPT || type == TYPE_DECRYPT) {
	    cipherObj = objv[start];
	    start++;
	case TYPE_ENCRYPT:
	case TYPE_DECRYPT:
	    cipherObj = objv[start++];
	    break;
	}
    }

    /* Get options */
    for (idx = start; idx < objc; idx++) {
    for (int idx = start; idx < objc; idx++) {
	/* Special case for when last arg is data */
	if (idx == objc - 1) {
	opt = Tcl_GetStringFromObj(objv[idx], NULL);

	if (opt[0] != '-') {
	    break;
	}

	OPTSTR("-chan", channel);
	    if (opt[0] != '-' && dataObj == NULL) {
		dataObj = objv[idx];
		break;
	    }
	}

	OPTSTR("-channel", channel);
	OPTOBJ("-cipher", cipherObj);
	OPTOBJ("-command", cmdObj);
	/* Get option */
	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
	OPTOBJ("-data", dataObj);
	OPTOBJ("-digest", digestObj);
	OPTOBJ("-hash", digestObj);
	OPTOBJ("-infile", inFileObj);
	    return TCL_ERROR;
	OPTOBJ("-outfile", outFileObj);
	OPTOBJ("-key", keyObj);
	OPTOBJ("-iv", ivObj);
	OPTOBJ("-mac", macObj);

	OPTBAD("option", "-chan, -channel, -cipher, -command, -data, -digest, -infile, -key, -iv, -mac, -outfile");
	}

	/* Validate arg has value */
	if (++idx >= objc) {
	    Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
	return TCL_ERROR;
    }

    /* If only 1 arg left, it's the data */
    if (idx < objc && dataObj == NULL) {
	dataObj = objv[idx];
	switch(fn) {
	case _opt_chan:
	case _opt_channel:
    	    GET_OPT_STRING(objv[idx], channel, NULL);
	    break;
	case _opt_cipher:
	    cipherObj = objv[idx];
	    break;
	case _opt_command:
	    cmdObj = objv[idx];
	    break;
	case _opt_data:
	    dataObj = objv[idx];
	    break;
	case _opt_digest:
	case _opt_hash:
	    digestObj = objv[idx];
	    break;
	case _opt_infile:
	case _opt_filename:
	    inFileObj = objv[idx];
	    break;
	case _opt_outfile:
	    outFileObj = objv[idx];
	    break;
	case _opt_iv:
	    ivObj = objv[idx];
	    break;
	case _opt_key:
	    keyObj = objv[idx];
	    break;
	case _opt_mac:
	    macObj = objv[idx];
	    break;
	}
    }

    /* Check for required options */
    if (cipherObj == NULL) {
	Tcl_AppendResult(interp, "No cipher", NULL);
    } else if (keyObj == NULL) {
	Tcl_AppendResult(interp, "No key", NULL);
	return TCL_ERROR;
    }

    /* Perform encryption function on file, stacked channel, using instance command, or data blob */
    if (inFileObj != NULL && outFileObj != NULL) {
	res = EncryptFileHandler(interp, type, inFileObj, outFileObj, cipherObj, digestObj, keyObj, ivObj);
    } else if (channel != NULL) {
	res = EncryptChannelHandler(interp, type, channel, cipherObj, digestObj, keyObj, ivObj);
    } else if (cmdObj != NULL) {
	res = EncryptCommandHandler(interp, type, cmdObj, cipherObj, digestObj, keyObj, ivObj);
    } else if (dataObj != NULL) {
	res = EncryptDataHandler(interp, type, dataObj, cipherObj, digestObj, keyObj, ivObj);
    } else {
	Tcl_AppendResult(interp, "No operation specified: Use -channel, -command, -data, -infile, or -outfile option", NULL);
	Tcl_AppendResult(interp, "No operation specified: Use -channel, -command, -data, or -infile option", NULL);
	res = TCL_ERROR;
    }
    return res;
}

/*
 *-------------------------------------------------------------------

Modified generic/tlsKey.c from [9989291d21] to [8cdbc99261].

9
10
11
12
13
14
15







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34
35
36

37
38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63









64

65
66
67
68
69
70














71
72

73
74

75
76






77
78

79
80
81
82











83
84
85
86
87
88









89
90
91
92
93
94
95
96
97
98
99
100
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67





68
69
70
71
72
73
74
75
76
77
78






79
80
81
82
83
84
85
86
87
88
89
90
91
92


93


94


95
96
97
98
99
100
101

102




103
104
105
106
107
108
109
110
111
112
113






114
115
116
117
118
119
120
121
122





123
124
125
126
127
128
129







+
+
+
+
+
+
+

















-
+


-
+




+


















+
-
-
-
-
-
+
+
+
+
+
+
+
+
+

+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
+
-
-
+
+
+
+
+
+

-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-








#include "tlsInt.h"
#include "tclOpts.h"
#include <openssl/crypto.h>

/*******************************************************************/

static const char *command_opts [] = { 
    "-cipher", "-digest", "-hash", "-iterations", "-password", "-salt", "-size", NULL};

enum _command_opts {
    _opt_cipher, _opt_digest, _opt_hash, _opt_iter, _opt_password, _opt_salt, _opt_size
};

/*
 *-------------------------------------------------------------------
 *
 * DeriveKey --
 *
 *	PKCS5_PBKDF2_HMAC key derivation function (KDF) specified by PKCS #5.
 *	See RFC 6070.
 *
 * Returns:
 *	TCL_OK or TCL_ERROR
 *
 * Side effects:
 *	Sets result to a list of key and iv values, or an error message
 *
 *-------------------------------------------------------------------
 */
static int DeriveKey(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    int key_len = 0, md_len = 0, pass_len = 0, salt_len = 0;
    int key_len = 0, md_len = 0, pass_len = 0, salt_len = 0, fn;
    int iklen, ivlen, iter = PKCS5_DEFAULT_ITER;
    unsigned char *passwd = NULL, *salt = NULL;
    Tcl_Obj *cipherObj = NULL, *digestObj = NULL, *passwdObj = NULL, *saltObj = NULL, *resultObj;
    Tcl_Obj *resultObj;
    const EVP_MD *md = NULL;
    const EVP_CIPHER *cipher = NULL;
    int max = EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH, size = max;
    unsigned char tmpkeyiv[EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH];
    char *cipherName = NULL, *digestName = NULL;

    dprintf("Called");

    /* Clear errors */
    Tcl_ResetResult(interp);
    ERR_clear_error();

    /* Validate arg count */
    if (objc < 3 || objc > 11) {
	Tcl_WrongNumArgs(interp, 1, objv, "[-cipher cipher | -size length] -digest digest ?-iterations count? ?-password string? ?-salt string?");
	return TCL_ERROR;
    }

    /* Init buffers */
    memset(tmpkeyiv, 0, EVP_MAX_KEY_LENGTH + EVP_MAX_IV_LENGTH);

    /* Get options */
    for (int idx = 1; idx < objc; idx++) {
	/* Get option */
	char *opt = Tcl_GetStringFromObj(objv[idx], NULL);

	if (opt[0] != '-') {
	    break;
	}
	if (Tcl_GetIndexFromObj(interp, objv[idx], command_opts, "option", 0, &fn) != TCL_OK) {
	    return TCL_ERROR;
	}

	/* Validate arg has value */
	if (++idx >= objc) {
	    Tcl_AppendResult(interp, "No value for option \"", command_opts[fn], "\"", (char *) NULL);
	return TCL_ERROR;
    }

	switch(fn) {
	OPTOBJ("-cipher", cipherObj);
	OPTOBJ("-digest", digestObj);
	OPTOBJ("-hash", digestObj);
	OPTINT("-iterations", iter);
	OPTOBJ("-password", passwdObj);
	OPTOBJ("-salt", saltObj);
	case _opt_cipher:
	    GET_OPT_STRING(objv[idx], cipherName, NULL);
	    break;
	case _opt_digest:
	case _opt_hash:
	    GET_OPT_STRING(objv[idx], digestName, NULL);
	    break;
	case _opt_iter:
	    GET_OPT_INT(objv[idx], &iter);
	    break;
	case _opt_password:
	    GET_OPT_BYTE_ARRAY(objv[idx], passwd, &pass_len);
	    break;
	case _opt_salt:
	OPTINT("-size", size);

	    GET_OPT_BYTE_ARRAY(objv[idx], salt, &salt_len);
	OPTBAD("option", "-cipher, -digest, -iterations, -password, -salt, or -size option");
	return TCL_ERROR;
	    break;
    }

	case _opt_size:
	    GET_OPT_INT(objv[idx], &size);
	    break;
	}
    }

    /* Validate options */
    if (cipherObj != NULL) {
    if (cipherName != NULL) {
	char *name = Tcl_GetByteArrayFromObj(cipherObj, NULL);
	cipher = EVP_get_cipherbyname(name);
    }
    if (digestObj != NULL) {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
	cipher = EVP_get_cipherbyname(cipherName);
#else
	cipher = EVP_CIPHER_fetch(NULL, cipherName, NULL);
#endif
	if (cipher == NULL) {
	    Tcl_AppendResult(interp, "Invalid cipher: \"", cipherName, "\"", NULL);
	    return TCL_ERROR;
	}
    }
    if (digestName != NULL) {
	char *name = Tcl_GetStringFromObj(digestObj, &md_len);
	md = EVP_get_digestbyname(name);
    } else {
	Tcl_AppendResult(interp, "No digest specified", NULL);
	return TCL_ERROR;
    }
#if OPENSSL_VERSION_NUMBER < 0x30000000L
	md = EVP_get_digestbyname(digestName);
#else
	md = EVP_MD_fetch(NULL, digestName, NULL);
#endif
	if (md == NULL) {
	    Tcl_AppendResult(interp, "Invalid digest: \"", digestName, "\"", NULL);
	    return TCL_ERROR;
	}
    if (passwdObj != NULL) {
	passwd = Tcl_GetByteArrayFromObj(passwdObj, &pass_len);
    }
    if (saltObj != NULL) {
	salt = Tcl_GetByteArrayFromObj(saltObj, &salt_len);
    }
    if (iter < 1) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("Invalid iterations count %d: must be > 0", iter));
	return TCL_ERROR;
    }
    if (size < 1 || size > max) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("Invalid derived key length %d: must be 0 < size <= %d", size, max));

Modified tests/digest.csv from [f2a8b06d9d] to [2969f7b1ad].

77
78
79
80
81
82
83
84

85
86
87
88
89
90
91
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91







-
+







,,,,,,,,,,
command,# MD Error Cases,,,,,,,,,
MD Errors,Too few args,,,::tls::md,,,"wrong # args: should be ""::tls::md ?-bin|-hex? ?-cipher name? ?-digest name? ?-key key? ?-mac name? [-channel chan | -command cmdName | -file filename | ?-data? data]""",,,1
MD Errors,Too many args,,,::tls::md too many command line args to pass the test without an error or failing,,,"wrong # args: should be ""::tls::md ?-bin|-hex? ?-cipher name? ?-digest name? ?-key key? ?-mac name? [-channel chan | -command cmdName | -file filename | ?-data? data]""",,,1
MD Errors,Invalid digest,,,::tls::md bogus data,,,"Invalid digest ""bogus""",,,1
MD Errors,Invalid digest Arg,,,::tls::md -digest bogus -data data,,,"Invalid digest ""bogus""",,,1
MD Errors,No digest,,,::tls::md -hex -data value,,,No digest specified,,,1
MD Errors,Invalid option,,,::tls::md -digest sha256 -bogus value,,,"bad option ""-bogus"": must be -bin, -channel, -cipher, -command, -data, -digest, -file, -filename, -hex, -key, or -mac",,,1
MD Errors,Invalid option,,,::tls::md -digest sha256 -bogus value,,,"bad option ""-bogus"": must be -bin, -binary, -hex, -hexadecimal, -chan, -channel, -cipher, -command, -data, -digest, -file, -filename, -hash, -key, or -mac",,,1
MD Errors,Invalid file,,,::tls::md -digest sha256 -file bogus,,,"couldn't open ""bogus"": no such file or directory",,,1
MD Errors,Invalid channel,,,::tls::md -digest sha256 -channel bogus,,,"can not find channel named ""bogus""",,,1
MD Errors,No operation,,,::tls::md -digest sha256 -bin,,,"No operation specified: Use -channel, -command, -data, or -file option",,,1
,,,,,,,,,,
,,,,,,,,,,
command,# Test CMAC command,,,,,,,,,
command,"set test_cipher ""aes-128-cbc""",,,,,,,,,

Modified tests/digest.test from [fa6ff50353] to [c72f5245d1].

247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
247
248
249
250
251
252
253

254
255
256
257
258
259
260
261







-
+








test MD_Errors-8.5 {No digest} -body {
	::tls::md -hex -data value
    } -result {No digest specified} -returnCodes {1}

test MD_Errors-8.6 {Invalid option} -body {
	::tls::md -digest sha256 -bogus value
    } -result {bad option "-bogus": must be -bin, -channel, -cipher, -command, -data, -digest, -file, -filename, -hex, -key, or -mac} -returnCodes {1}
    } -result {bad option "-bogus": must be -bin, -binary, -hex, -hexadecimal, -chan, -channel, -cipher, -command, -data, -digest, -file, -filename, -hash, -key, or -mac} -returnCodes {1}

test MD_Errors-8.7 {Invalid file} -body {
	::tls::md -digest sha256 -file bogus
    } -result {couldn't open "bogus": no such file or directory} -returnCodes {1}

test MD_Errors-8.8 {Invalid channel} -body {
	::tls::md -digest sha256 -channel bogus

Modified tests/info.csv from [25591cb194] to [a605570f7c].

74
75
76
77
78
79
80
81
82


83
84
85
86
87
74
75
76
77
78
79
80


81
82
83
84
85
86
87







-
-
+
+





Protocols,All,,,lcompare $::protocols [::tls::protocols],,,missing {ssl2 ssl3} unexpected {},,,
,,,,,,,,,,
command,# Test show version,,,,,,,,,
Version,All,,,::tls::version,,glob,*,,,
Version,OpenSSL,OpenSSL,,::tls::version,,glob,OpenSSL*,,,
,,,,,,,,,,
command,# Error Cases,,,,,,,,,
Error Cases,Cipher Too few args,,,::tls::cipher,,,"wrong # args: should be ""::tls::cipher name""",,,1
Error Cases,Cipher Too many args,,,::tls::cipher too many args,,,"wrong # args: should be ""::tls::cipher name""",,,1
Error Cases,Cipher Too few args,,,::tls::cipher,,,"wrong # args: should be ""::tls::cipher ?name?""",,,1
Error Cases,Cipher Too many args,,,::tls::cipher too many args,,,"wrong # args: should be ""::tls::cipher ?name?""",,,1
Error Cases,Digests Too many args,,,::tls::digests too many args,,,"wrong # args: should be ""::tls::digests ?name?""",,,1
Error Cases,MACs Too many args,,,::tls::macs too many args,,,"wrong # args: should be ""::tls::macs ?name?""",,,1
Error Cases,Pkeys Too many args,,,::tls::pkeys too many args,,,"wrong # args: should be ""::tls::pkeys ?name?""",,,1
Error Cases,Protocols Too many args,,,::tls::protocols too many args,,,"wrong # args: should be ""::tls::protocols""",,,1
Error Cases,Version Too many args,,,::tls::version too many args,,,"wrong # args: should be ""::tls::version""",,,1

Modified tests/info.test from [3004379e81] to [421d0bdeb4].

210
211
212
213
214
215
216
217

218
219
220
221

222
223
224
225
226
227
228
210
211
212
213
214
215
216

217
218
219
220

221
222
223
224
225
226
227
228







-
+



-
+







    } -match {glob} -result {OpenSSL*}

# Error Cases


test Error_Cases-13.1 {Cipher Too few args} -body {
	::tls::cipher
    } -result {wrong # args: should be "::tls::cipher name"} -returnCodes {1}
    } -result {wrong # args: should be "::tls::cipher ?name?"} -returnCodes {1}

test Error_Cases-13.2 {Cipher Too many args} -body {
	::tls::cipher too many args
    } -result {wrong # args: should be "::tls::cipher name"} -returnCodes {1}
    } -result {wrong # args: should be "::tls::cipher ?name?"} -returnCodes {1}

test Error_Cases-13.3 {Digests Too many args} -body {
	::tls::digests too many args
    } -result {wrong # args: should be "::tls::digests ?name?"} -returnCodes {1}

test Error_Cases-13.4 {MACs Too many args} -body {
	::tls::macs too many args