Diff

Differences From Artifact [6525346f21]:

To Artifact [f4a59d7949]:


268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283
284
285

286
287
288

289
290
291

292
293
294

295
296
297

298
299
300

301
302
303

304
305
306
307
308
309
310
311
312
313
314
315
316

317
318
319
320
321
322
323
268
269
270
271
272
273
274

275
276
277
278
279
280
281
282
283
284

285
286
287

288
289
290

291
292
293

294
295
296

297
298
299

300
301
302

303
304
305
306
307
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323







-
+









-
+


-
+


-
+


-
+


-
+


-
+


-
+












-
+







    case TLS1_2_VERSION:
	ver = "TLSv1.2";
	break;
    case TLS1_3_VERSION:
	ver = "TLSv1.3";
	break;
    case 0:
        ver = "none";
	ver = "none";
	break;
    default:
	ver = "unknown";
	break;
    }

    switch (content_type) {
    case SSL3_RT_HEADER:
	type = "Header";
        break;
	break;
    case SSL3_RT_INNER_CONTENT_TYPE:
	type = "Inner Content Type";
        break;
	break;
    case SSL3_RT_CHANGE_CIPHER_SPEC:
	type = "Change Cipher";
        break;
	break;
    case SSL3_RT_ALERT:
	type = "Alert";
        break;
	break;
    case SSL3_RT_HANDSHAKE:
	type = "Handshake";
        break;
	break;
    case SSL3_RT_APPLICATION_DATA:
	type = "App Data";
        break;
	break;
    case DTLS1_RT_HEARTBEAT:
	type = "Heartbeat";
        break;
	break;
    default:
	type = "unknown";
    }

    /* Needs compile time option "enable-ssl-trace". */
    if ((bio = BIO_new(BIO_s_mem())) != NULL) {
	int n;
	SSL_trace(write_p, version, content_type, buf, len, ssl, (void *)bio);
	n = BIO_read(bio, buffer, min(BIO_pending(bio), 14999));
	n = (n<0) ? 0 : n;
	buffer[n] = 0;
	(void)BIO_flush(bio);
 	BIO_free(bio);
	BIO_free(bio);
   }

    /* Create command to eval */
    cmdPtr = Tcl_DuplicateObj(statePtr->callback);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("message", -1));
    Tcl_ListObjAppendElement(interp, cmdPtr,
	    Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1));
1502
1503
1504
1505
1506
1507
1508
1509
1510


1511
1512
1513
1514
1515
1516
1517
1502
1503
1504
1505
1506
1507
1508


1509
1510
1511
1512
1513
1514
1515
1516
1517







-
-
+
+








    /* Resume session id */
    if (session_id && strlen(session_id) <= 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))) {
	    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;
	    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) {
	/* Convert a TCL list into a protocol-list in wire-format */
2050
2051
2052
2053
2054
2055
2056
2057

2058
2059
2060
2061
2062
2063
2064
2065

2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077


2078
2079


2080
2081
2082
2083

2084
2085
2086
2087
2088
2089
2090
2050
2051
2052
2053
2054
2055
2056

2057
2058
2059
2060





2061












2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079







-
+



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


+
+




+







    X509 *peer;
    Tcl_Obj *objPtr;
    Tcl_Channel chan;
    char *channelName, *ciphers;
    int mode;
    const unsigned char *proto;
    unsigned int len;
    int nid;
    int nid, res;

    dprintf("Called");

    switch (objc) {
	case 2:
	    channelName = Tcl_GetStringFromObj(objv[1], (Tcl_Size *)NULL);
	    break;

    if (objc < 2 || objc > 3 || (objc == 3 && !strcmp(Tcl_GetString(objv[1]), "-local"))) {
	case 3:
	    if (!strcmp (Tcl_GetString (objv[1]), "-local")) {
		channelName = Tcl_GetStringFromObj(objv[2], (Tcl_Size *)NULL);
		break;
	    }
	    /* else fall-through ... */
#if defined(__GNUC__)
	    __attribute__((fallthrough));
#endif
	default:
	    Tcl_WrongNumArgs(interp, 1, objv, "?-local? channel");
	    return TCL_ERROR;
	Tcl_WrongNumArgs(interp, 1, objv, "?-local? channel");
	return TCL_ERROR;
    }

    /* Get channel Id */
    channelName = Tcl_GetStringFromObj(objv[(objc == 2 ? 1 : 2)], (Tcl_Size *) NULL);
    chan = Tcl_GetChannel(interp, channelName, &mode);
    if (chan == (Tcl_Channel) NULL) {
	return TCL_ERROR;
    }

    /* Make sure to operate on the topmost channel */
    chan = Tcl_GetTopChannel(chan);
    if (Tcl_GetChannelType(chan) != Tls_ChannelType()) {
	Tcl_AppendResult(interp, "bad channel \"", Tcl_GetChannelName(chan),
		"\": not a TLS channel", NULL);
	Tcl_SetErrorCode(interp, "TLS", "STATUS", "CHANNEL", "INVALID", (char *) NULL);
	return TCL_ERROR;
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122

2123
2124
2125

2126
2127
2128
2129

2130
2131

2132
2133
2134
2135
2136


2137
2138
2139
2140
2141
2142
2143

2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158

2159
2160
2161
2162
2163
2164

2165
2166
2167
2168

2169
2170
2171

2172
2173
2174
2175


2176
2177
2178

2179


2180
2181



2182
2183
2184

2185


2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204

2205
2206
2207
2208
2209
2210

2211
2212
2213
2214
2215
2216
2217
2093
2094
2095
2096
2097
2098
2099









2100


2101



2102
2103
2104


2105


2106

2107



2108
2109
2110
2111


2112
2113

2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128

2129
2130
2131
2132



2133
2134
2135
2136

2137



2138
2139
2140


2141
2142

2143

2144
2145
2146
2147


2148
2149
2150

2151

2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173

2174
2175
2176
2177
2178
2179

2180
2181
2182
2183
2184
2185
2186
2187







-
-
-
-
-
-
-
-
-

-
-
+
-
-
-
+


-
-
+
-
-
+
-

-
-
-
+
+


-
-


-
+














-
+



-
-
-
+



-
+
-
-
-
+


-
-
+
+
-

-
+

+
+
-
-
+
+
+
-

-
+

+
+


















-
+





-
+







	    X509_free(peer);
	    peer = NULL;
	}
    } else {
	objPtr = Tcl_NewListObj(0, NULL);
    }

    /* Peer cert chain (client only) */
    STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(statePtr->ssl);
    if (ssl_certs == NULL || sk_X509_num(ssl_certs) == 0) {
	Tcl_SetErrorCode(interp, "TLS", "STATUS", "CERTIFICATE", (char *) NULL);
	Tcl_IncrRefCount(objPtr);
	Tcl_DecrRefCount(objPtr);
	return TCL_ERROR;
    }

    /* Peer name */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("peername", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get0_peername(statePtr->ssl), -1));
    LAPPEND_STR(interp, objPtr, "peername", SSL_get0_peername(statePtr->ssl), -1);

    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("sbits", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_get_cipher_bits(statePtr->ssl, NULL)));
    LAPPEND_INT(interp, objPtr, "sbits", SSL_get_cipher_bits(statePtr->ssl, NULL));

    ciphers = (char*)SSL_get_cipher(statePtr->ssl);
    if ((ciphers != NULL) && (strcmp(ciphers, "(NONE)") != 0)) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1));
    LAPPEND_STR(interp, objPtr, "cipher", ciphers, -1);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(ciphers, -1));
    }


    /* Verify the X509 certificate presented by the peer */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyResult", -1));
    Tcl_ListObjAppendElement(interp, objPtr,
	Tcl_NewStringObj(X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl)), -1));
    LAPPEND_STR(interp, objPtr, "verifyResult",
	X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl)), -1);

    /* Verify mode */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyMode", -1));
    /* SSL_CTX_get_verify_mode(ctx) */
    mode = SSL_get_verify_mode(statePtr->ssl);
    if (mode && SSL_VERIFY_NONE) {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("none", -1));
	LAPPEND_STR(interp, objPtr, "verifyMode", "none", -1);
    } else {
	Tcl_Obj *listObjPtr = Tcl_NewListObj(0, NULL);
	if (mode && SSL_VERIFY_PEER) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("peer", -1));
	}
	if (mode && SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("fail if no peer cert", -1));
	}
	if (mode && SSL_VERIFY_CLIENT_ONCE) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("client once", -1));
	}
	if (mode && SSL_VERIFY_POST_HANDSHAKE) {
	    Tcl_ListObjAppendElement(interp, listObjPtr, Tcl_NewStringObj("post handshake", -1));
	}
	Tcl_ListObjAppendElement(interp, objPtr, listObjPtr);
	LAPPEND_OBJ(interp, objPtr, "verifyMode", listObjPtr)
    }

    /* Verify mode depth */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("verifyDepth", -1));
    /* SSL_CTX_get_verify_depth(ctx) */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_get_verify_depth(statePtr->ssl)));
    LAPPEND_INT(interp, objPtr, "verifyDepth", SSL_get_verify_depth(statePtr->ssl));

    /* Report the selected protocol as a result of the negotiation */
    SSL_get0_alpn_selected(statePtr->ssl, &proto, &len);
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
    LAPPEND_STR(interp, objPtr, "alpn", (char *)proto, (Tcl_Size) len);
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("protocol", -1));
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(statePtr->ssl), -1));
    LAPPEND_STR(interp, objPtr, "protocol", SSL_get_version(statePtr->ssl), -1);

    /* Valid for non-RSA signature and TLS 1.3 */
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signatureHashAlgorithm", -1));
    if (objc == 2 ? SSL_get_peer_signature_nid(statePtr->ssl, &nid) : SSL_get_signature_nid(statePtr->ssl, &nid)) {
    if (objc == 2) {
	res = SSL_get_peer_signature_nid(statePtr->ssl, &nid);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
	res = SSL_get_signature_nid(statePtr->ssl, &nid);
    }
    if (!res) {nid = 0;}
    LAPPEND_STR(interp, objPtr, "signatureHashAlgorithm", OBJ_nid2ln(nid), -1);
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("signatureType", -1));
    if (objc == 2 ? SSL_get_peer_signature_type_nid(statePtr->ssl, &nid) : SSL_get_signature_type_nid(statePtr->ssl, &nid)) {

    if (objc == 2) {
	res = SSL_get_peer_signature_type_nid(statePtr->ssl, &nid);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(OBJ_nid2ln(nid), -1));
    } else {
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("", -1));
	res = SSL_get_signature_type_nid(statePtr->ssl, &nid);
    }
    if (!res) {nid = 0;}
    LAPPEND_STR(interp, objPtr, "signatureType", OBJ_nid2ln(nid), -1);

    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
	clientData = clientData;
}

/*
 *-------------------------------------------------------------------
 *
 * ConnectionInfoObjCmd -- return connection info from OpenSSL.
 *
 * Results:
 *	A list of connection info
  *
 *-------------------------------------------------------------------
 */

static int ConnectionInfoObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
    Tcl_Channel chan;		/* The channel to set a mode on. */
    Tcl_Channel chan;		/* The channel to set a mode on */
    State *statePtr;		/* client state for ssl socket */
    Tcl_Obj *objPtr, *listPtr;
    const SSL *ssl;
    const SSL_CIPHER *cipher;
    const SSL_SESSION *session;
    long mode;
    const EVP_MD *md;

    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel");
	return(TCL_ERROR);
    }

    chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], (Tcl_Size *)NULL), NULL);
2231
2232
2233
2234
2235
2236
2237
2238

2239
2240
2241
2242
2243

2244
2245
2246
2247

2248
2249
2250
2251
2252

2253
2254
2255
2256

2257
2258
2259
2260

2261
2262
2263
2264




2265
2266
2267
2268
2269
2270
2271
2272

2273
2274
2275
2276







2277

2278
2279
2280

2281
2282

2283
2284
2285
2286



2287














2288
2289
2290




2291

2292
2293
2294

2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309

2310
2311
2312
2313
2314
2315

2316
2317
2318
2319
2320
2321

2322
2323
2324
2325

2326
2327
2328
2329

2330
2331
2332
2333
2334
2335
2336
2337

2338
2339
2340
2341
2342

2343
2344
2345
2346
2347
2348




2349
2350
2351
2352

2353
2354
2355
2356
2357
2358





2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369

2370
2371

2372
2373
2374

2375
2376

2377
2378
2379
2380
2381
2382

2383
2384

2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396

2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415


2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2201
2202
2203
2204
2205
2206
2207

2208

2209
2210


2211
2212
2213


2214
2215
2216



2217
2218
2219


2220
2221
2222


2223
2224
2225


2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238




2239
2240
2241
2242
2243
2244
2245
2246
2247
2248


2249


2250
2251
2252


2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271


2272
2273
2274
2275
2276
2277
2278


2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293

2294

2295
2296
2297
2298

2299

2300
2301
2302


2303
2304
2305


2306
2307
2308


2309




2310
2311
2312

2313

2314
2315
2316

2317

2318
2319
2320


2321
2322
2323
2324
2325
2326
2327

2328

2329
2330
2331


2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345


2346


2347
2348


2349


2350
2351
2352
2353
2354
2355

2356
2357

2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369

2370

2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386


2387
2388
2389
2390
2391
2392
2393

2394
2395
2396
2397
2398
2399
2400







-
+
-


-
-
+


-
-
+


-
-
-
+


-
-
+


-
-
+


-
-
+
+
+
+








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

+

-
-
+
-
-
+


-
-
+
+
+

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

-
-
+
+
+
+

+

-
-
+














-
+
-




-
+
-



-
-
+


-
-
+


-
-
+
-
-
-
-



-
+
-



-
+
-



-
-
+
+
+
+



-
+
-



-
-
+
+
+
+
+









-
-
+
-
-
+

-
-
+
-
-
+





-
+

-
+











-
+
-
















-
-
+
+





-







    objPtr = Tcl_NewListObj(0, NULL);

    /* Connection info */
    statePtr = (State *)Tcl_GetChannelInstanceData(chan);
    ssl = statePtr->ssl;
    if (ssl != NULL) {
	/* connection state */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("state", -1));
	LAPPEND_STR(interp, objPtr, "state", SSL_state_string_long(ssl), -1);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_state_string_long(ssl), -1));

	/* Get SNI requested server name */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("servername", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name), -1));
	LAPPEND_STR(interp, objPtr, "servername", SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name), -1);

	/* Get protocol */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("protocol", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(ssl), -1));
	LAPPEND_STR(interp, objPtr, "protocol", SSL_get_version(ssl), -1);

	/* Renegotiation allowed */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("renegotiation", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(
	    SSL_get_secure_renegotiation_support(ssl) ? "supported" : "not supported", -1));
	LAPPEND_BOOL(interp, objPtr, "renegotiation_allowed", SSL_get_secure_renegotiation_support(ssl));

	/* Get security level */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("securitylevel", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_get_security_level(ssl)));
	LAPPEND_INT(interp, objPtr, "securitylevel", SSL_get_security_level(ssl));

	/* Session info */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_reused", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewBooleanObj(SSL_session_reused(ssl)));
	LAPPEND_BOOL(interp, objPtr, "session_reused", SSL_session_reused(ssl));

	/* Is server info */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("is_server", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewBooleanObj(SSL_is_server(ssl)));
	LAPPEND_BOOL(interp, objPtr, "is_server", SSL_is_server(ssl));

	/* Is DTLS */
	LAPPEND_BOOL(interp, objPtr, "is_dtls", SSL_is_dtls(ssl));
    }

    /* Cipher info */
    cipher = SSL_get_current_cipher(ssl);
    if (cipher != NULL) {
	char buf[BUFSIZ] = {0};
	int bits, alg_bits;

	/* Cipher name */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_get_name(cipher), -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("standard_name", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_standard_name(cipher), -1));
	LAPPEND_STR(interp, objPtr, "cipher", SSL_CIPHER_get_name(cipher), -1);

	/* RFC name of cipher */
	LAPPEND_STR(interp, objPtr, "standard_name", SSL_CIPHER_standard_name(cipher), -1);

	/* OpenSSL name of cipher */
	LAPPEND_STR(interp, objPtr, "openssl_name", OPENSSL_cipher_name(SSL_CIPHER_standard_name(cipher)), -1);

	/* number of secret bits used for cipher */
	bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("secret_bits", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(bits));
	LAPPEND_INT(interp, objPtr, "secret_bits", bits);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("algorithm_bits", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(alg_bits));
	LAPPEND_INT(interp, objPtr, "algorithm_bits", alg_bits);
	/* alg_bits is actual key secret bits. If use bits and secret (algorithm) bits differ,
	   the rest of the bits are fixed, i.e. for limited export ciphers (bits < 56) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("min_version", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_CIPHER_get_version(cipher), -1));

	/* Indicates which SSL/TLS protocol version first defined the cipher */
	LAPPEND_STR(interp, objPtr, "min_version", SSL_CIPHER_get_version(cipher), -1);

	/* Cipher NID */
	LAPPEND_STR(interp, objPtr, "cipherNID", (char *)OBJ_nid2ln(SSL_CIPHER_get_cipher_nid(cipher)), -1);
	LAPPEND_STR(interp, objPtr, "digestNID", (char *)OBJ_nid2ln(SSL_CIPHER_get_digest_nid(cipher)), -1);
	LAPPEND_STR(interp, objPtr, "keyExchangeNID", (char *)OBJ_nid2ln(SSL_CIPHER_get_kx_nid(cipher)), -1);
	LAPPEND_STR(interp, objPtr, "authenticationNID", (char *)OBJ_nid2ln(SSL_CIPHER_get_auth_nid(cipher)), -1);

	/* message authentication code - Cipher is AEAD (e.g. GCM or ChaCha20/Poly1305) or not */
	/* Authenticated Encryption with associated data (AEAD) check */
	LAPPEND_BOOL(interp, objPtr, "cipher_is_aead", SSL_CIPHER_is_aead(cipher));

	/* Digest used during the SSL/TLS handshake when using the cipher. */
	md = SSL_CIPHER_get_handshake_digest(cipher);
	LAPPEND_STR(interp, objPtr, "handshake_digest", (char *)EVP_MD_name(md), -1);

	/* Get OpenSSL-specific ID, not IANA ID */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("id", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj((int) SSL_CIPHER_get_id(cipher)));
	LAPPEND_INT(interp, objPtr, "cipher_id", (int) SSL_CIPHER_get_id(cipher));

	/* Two-byte ID used in the TLS protocol of the given cipher */
	LAPPEND_INT(interp, objPtr, "protocol_id", (int) SSL_CIPHER_get_protocol_id(cipher));

	/* Textual description of the cipher */
	if (SSL_CIPHER_description(cipher, buf, sizeof(buf)) != NULL) {
	    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("description", -1));
	    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(buf, -1));
	    LAPPEND_STR(interp, objPtr, "description", buf, -1);
	}
    }

    /* Session info */
    session = SSL_get_session(ssl);
    if (session != NULL) {
	const unsigned char *ticket;
	size_t len2;
	unsigned int ulen;
	const unsigned char *session_id, *proto;
	char buffer[SSL_MAX_MASTER_KEY_LENGTH];

	/* Report the selected protocol as a result of the ALPN negotiation */
	SSL_SESSION_get0_alpn_selected(session, &proto, &len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("alpn", -1));
	LAPPEND_STR(interp, objPtr, "alpn", (char *) proto, (Tcl_Size) len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) len2));

	/* Report the selected protocol as a result of the NPN negotiation */
#ifdef USE_NPN
	SSL_get0_next_proto_negotiated(ssl, &proto, &ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("npn", -1));
	LAPPEND_STR(interp, objPtr, "npn", (char *) proto, (Tcl_Size) ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj((char *)proto, (int) ulen));
#endif

	/* Resumable session */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("resumable", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewIntObj(SSL_SESSION_is_resumable(session)));
	LAPPEND_BOOL(interp, objPtr, "resumable", SSL_SESSION_is_resumable(session));

	/* Session start time (seconds since epoch) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("start_time", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_time(session)));
	LAPPEND_LONG(interp, objPtr, "start_time", SSL_SESSION_get_time(session));

	/* Timeout value - SSL_CTX_get_timeout (in seconds) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("timeout", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_timeout(session)));
	LAPPEND_LONG(interp, objPtr, "timeout", SSL_SESSION_get_timeout(session));

	/* Session ticket lifetime hint (in seconds) */
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("lifetime", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewLongObj(SSL_SESSION_get_ticket_lifetime_hint(session)));

	/* Session id - TLSv1.2 and below only */
	session_id = SSL_SESSION_get_id(session, &ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_id", -1));
	LAPPEND_BARRAY(interp, objPtr, "session_id", session_id, (Tcl_Size) ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));

	/* Session context */
	session_id = SSL_SESSION_get0_id_context(session, &ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_context", -1));
	LAPPEND_BARRAY(interp, objPtr, "session_context", session_id, (Tcl_Size) ulen);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(session_id, (int) ulen));

	/* Session ticket - client only */
	SSL_SESSION_get0_ticket(session, &ticket, &len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_ticket", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(ticket, (int) len2));
	LAPPEND_BARRAY(interp, objPtr, "session_ticket", ticket, (Tcl_Size) len2);

	/* Session ticket lifetime hint (in seconds) */
	LAPPEND_LONG(interp, objPtr, "lifetime", SSL_SESSION_get_ticket_lifetime_hint(session));

	/* Ticket app data */
	SSL_SESSION_get0_ticket_appdata(session, &ticket, &len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("ticket_app_data", -1));
	LAPPEND_BARRAY(interp, objPtr, "ticket_app_data", ticket, (Tcl_Size) len2);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(ticket, (int) len2));

	/* Get master key */
	len2 = SSL_SESSION_get_master_key(session, buffer, SSL_MAX_MASTER_KEY_LENGTH);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("master_key", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewByteArrayObj(buffer, (int) len2));
	LAPPEND_BARRAY(interp, objPtr, "master_key", buffer, (Tcl_Size) len2);

	/* Compression id */
	unsigned int id = SSL_SESSION_get_compress_id(session);
	LAPPEND_STR(interp, objPtr, "compression_id", id == 1 ? "zlib" : "none", -1);
    }

    /* Compression info */
    if (ssl != NULL) {
#ifdef HAVE_SSL_COMPRESSION
	const COMP_METHOD *comp, *expn;
	comp = SSL_get_current_compression(ssl);
	expn = SSL_get_current_expansion(ssl);

	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("compression", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(comp ? SSL_COMP_get_name(comp) : "NONE", -1));
	LAPPEND_STR(interp, objPtr, "compression", comp ? SSL_COMP_get_name(comp) : "none", -1);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("expansion", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(expn ? SSL_COMP_get_name(expn) : "NONE", -1));
	LAPPEND_STR(interp, objPtr, "expansion", expn ? SSL_COMP_get_name(expn) : "none", -1);
#else
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("compression", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("NONE", -1));
	LAPPEND_STR(interp, objPtr, "compression", "none", -1);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("expansion", -1));
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("NONE", -1));
	LAPPEND_STR(interp, objPtr, "expansion", "none", -1);
#endif
    }

    /* Server info */
    {
	mode = SSL_CTX_get_session_cache_mode(statePtr->ctx);
	long mode = SSL_CTX_get_session_cache_mode(statePtr->ctx);
	char *msg;
	

	if (mode & SSL_SESS_CACHE_OFF) {
	    msg = "off";
	} else if (mode & SSL_SESS_CACHE_CLIENT) {
	    msg = "client";
	} else if (mode & SSL_SESS_CACHE_SERVER) {
	    msg = "server";
	} else if (mode & SSL_SESS_CACHE_BOTH) {
	    msg = "both";
	} else {
	    msg = "unknown";
	}
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("session_cache_mode", -1));
	LAPPEND_STR(interp, objPtr, "session_cache_mode", msg, -1);
	Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(msg, -1));
    }

    /* CA List */
    /* IF not a server, same as SSL_get0_peer_CA_list. If server same as SSL_CTX_get_client_CA_list */
    listPtr = Tcl_NewListObj(0, NULL);
    STACK_OF(X509_NAME) *ca_list;
    if ((ca_list = SSL_get_client_CA_list(ssl)) != NULL) {
	char buffer[BUFSIZ];
	for (int i = 0; i < sk_X509_NAME_num(ca_list); i++) {
	    X509_NAME *name = sk_X509_NAME_value(ca_list, i);
	    if (name) {
		X509_NAME_oneline(name, buffer, BUFSIZ);
		Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(buffer, -1));
	    }
	}
    }
    Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("caList", -1));
    Tcl_ListObjAppendElement(interp, objPtr, listPtr);
    LAPPEND_OBJ(interp, objPtr, "caList", listPtr);
    LAPPEND_INT(interp, objPtr, "caListCount", sk_X509_NAME_num(ca_list));

    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
	clientData = clientData;
}


/*
 *-------------------------------------------------------------------
 *
 * VersionObjCmd -- return version string from OpenSSL.
 *
 * Results:
2471
2472
2473
2474
2475
2476
2477
2478

2479
2480
2481
2482
2483
2484
2485
2443
2444
2445
2446
2447
2448
2449

2450
2451
2452
2453
2454
2455
2456
2457







-
+








    dprintf("Called");

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "subcommand ?args?");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], commands, "command", 0,&cmd) != TCL_OK) {
    if (Tcl_GetIndexFromObj(interp, objv[1], commands, "command", 0, &cmd) != TCL_OK) {
	return TCL_ERROR;
    }

    ERR_clear_error();

    isStr = (cmd == C_STRREQ);
    switch ((enum command) cmd) {