Check-in [1cabc3b8f2]
Overview
Comment:Added support for setting the certificate store
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tls-1.8
Files: files | file ages | folders
SHA3-256: 1cabc3b8f294cb700cbb4cebf586e88932df197804f9a0a054520767f80c8a1d
User & Date: bohagan on 2024-06-20 01:01:25
Other Links: branch diff | manifest | tags
Context
2024-06-23
00:51
Added more notes to doc file. check-in: 369965b608 user: bohagan tags: tls-1.8
2024-06-20
01:01
Added support for setting the certificate store check-in: 1cabc3b8f2 user: bohagan tags: tls-1.8
2024-06-19
20:40
Added more connection status check-in: ab1aa551c0 user: bohagan tags: tls-1.8
Changes
129
130
131
132
133
134
135





136
137
138
139
140
141
142
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147







+
+
+
+
+







	    certificates are stored. The default is platform specific and can be
	    set at compile time. This can be overridden via the <b>SSL_CERT_DIR</b>
	    environment variable.</dd>
	<dt><strong>-cafile </strong><em>filename</em></dt>
	<dd>Specifies the file with the Certificate Authority (CA) certificates
	    to use. The default is <b>cert.pem</b>, in the OpenSSL directory. This can
	    also be overridden via the <b>SSL_CERT_FILE</b> environment variable.</dd>
	<dt><strong>-castore</strong> <em>URI</em></dt>
	<dd>URI for a store, which may be a single container or a catalog of
	    containers. On Windows, set to "org.openssl.winstore://" to use the
	    built-in Windows Cert Store. The Windows cert store only supports
	    root certificate stores.</dd>
	<dt><strong>-certfile</strong> <em>filename</em></dt>
	<dd>Specifies the file with the certificate to use in PEM format.
	    This also contains the public key.</dd>
	<dt><strong>-cert</strong> <em>binary_string</em></dt>
	<dd>Specifies the certificate to use as a DER encoded string (X.509 DER).</dd>
	<dt><strong>-cipher</strong> <em>string</em></dt>
	<dd>Specifies the list of ciphers to use for TLS 1.2 and earlier. String is a
45
46
47
48
49
50
51
52
53


54
55
56
57
58
59
60
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60







-
-
+
+








#define F2N(key, dsp) \
	(((key) == NULL) ? (char *) NULL : \
		Tcl_TranslateFileName(interp, (key), (dsp)))

static SSL_CTX *CTX_Init(State *statePtr, int isServer, int proto, char *key,
		char *certfile, unsigned char *key_asn1, unsigned char *cert_asn1,
		Tcl_Size key_asn1_len, Tcl_Size cert_asn1_len, char *CApath, char *CAfile,
		char *ciphers, char *ciphersuites, int level, char *DHparams);
		Tcl_Size key_asn1_len, Tcl_Size cert_asn1_len, char *CApath, char *CAstore,
		char *CAfile, char *ciphers, char *ciphersuites, int level, char *DHparams);

#define TLS_PROTO_SSL2		0x01
#define TLS_PROTO_SSL3		0x02
#define TLS_PROTO_TLS1		0x04
#define TLS_PROTO_TLS1_1	0x08
#define TLS_PROTO_TLS1_2	0x10
#define TLS_PROTO_TLS1_3	0x20
1253
1254
1255
1256
1257
1258
1259

1260
1261
1262
1263
1264
1265
1266
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267







+







    Tcl_Size key_len		= 0;
    unsigned char *cert		= NULL;
    Tcl_Size cert_len		= 0;
    char *ciphers		= NULL;
    char *ciphersuites		= NULL;
    char *CAfile		= NULL;
    char *CApath		= NULL;
    char *CAstore		= NULL;
    char *DHparams		= NULL;
    char *model			= NULL;
    char *servername		= NULL;	/* hostname for Server Name Indication */
    char *session_id		= NULL;
    Tcl_Obj *alpn		= NULL;
    int ssl2 = 0, ssl3 = 0;
    int tls1 = 1, tls1_1 = 1, tls1_2 = 1, tls1_3 = 1;
1303
1304
1305
1306
1307
1308
1309

1310
1311
1312
1313
1314
1315
1316
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318







+








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

	OPTOBJ("-alpn", alpn);
	OPTSTR("-cadir", CApath);
	OPTSTR("-cafile", CAfile);
	OPTSTR("-castore", CAstore);
	OPTBYTE("-cert", cert, cert_len);
	OPTSTR("-certfile", certfile);
	OPTSTR("-cipher", ciphers);
	OPTSTR("-ciphers", ciphers);
	OPTSTR("-ciphersuites", ciphersuites);
	OPTOBJ("-command", script);
	OPTSTR("-dhparams", DHparams);
1330
1331
1332
1333
1334
1335
1336
1337

1338
1339
1340
1341
1342
1343
1344
1332
1333
1334
1335
1336
1337
1338

1339
1340
1341
1342
1343
1344
1345
1346







-
+







	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");
	OPTBAD("option", "-alpn, -cadir, -cafile, -castore, -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;
1355
1356
1357
1358
1359
1360
1361

1362
1363
1364
1365
1366
1367
1368
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371







+







    if (key && !*key)		        key	        = NULL;
    if (certfile && !*certfile)         certfile	= NULL;
    if (keyfile && !*keyfile)		keyfile	        = NULL;
    if (ciphers && !*ciphers)	        ciphers	        = NULL;
    if (ciphersuites && !*ciphersuites) ciphersuites    = NULL;
    if (CAfile && !*CAfile)	        CAfile	        = NULL;
    if (CApath && !*CApath)	        CApath	        = NULL;
    if (CAstore && !*CAstore)	        CAstore	        = NULL;
    if (DHparams && !*DHparams)	        DHparams        = NULL;

    /* new SSL state */
    statePtr		= (State *) ckalloc((unsigned) sizeof(State));
    memset(statePtr, 0, sizeof(State));

    statePtr->flags	= flags;
1416
1417
1418
1419
1420
1421
1422
1423

1424
1425
1426
1427
1428
1429
1430
1419
1420
1421
1422
1423
1424
1425

1426
1427
1428
1429
1430
1431
1432
1433







-
+







	    Tcl_SetErrorCode(interp, "TLS", "IMPORT", "CHANNEL", "INVALID", (char *) NULL);
	    Tls_Free((tls_free_type *) statePtr);
	    return TCL_ERROR;
	}
	ctx = ((State *)Tcl_GetChannelInstanceData(chan))->ctx;
    } else {
	if ((ctx = CTX_Init(statePtr, server, proto, keyfile, certfile, key, cert, key_len,
	    cert_len, CApath, CAfile, ciphers, ciphersuites, level, DHparams)) == NULL) {
	    cert_len, CApath, CAstore, CAfile, ciphers, ciphersuites, level, DHparams)) == NULL) {
	    Tls_Free((tls_free_type *) statePtr);
	    return TCL_ERROR;
	}
    }

    statePtr->ctx = ctx;

1568
1569
1570
1571
1572
1573
1574

1575
1576
1577
1578
1579
1580
1581
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585







+







    }

    /*
     * SSL Callbacks
     */
    SSL_set_app_data(statePtr->ssl, (void *)statePtr);	/* point back to us */
    SSL_set_verify(statePtr->ssl, verify, VerifyCallback);
    /*SSL_set_verify_depth(SSL_set_verify_depth, 0);*/
    SSL_set_info_callback(statePtr->ssl, InfoCallback);

    /* Callback for observing protocol messages */
#ifndef OPENSSL_NO_SSL_TRACE
    /* void SSL_CTX_set_msg_callback_arg(statePtr->ctx, (void *)statePtr);
    void SSL_CTX_set_msg_callback(statePtr->ctx, MessageCallback); */
    SSL_set_msg_callback_arg(statePtr->ssl, (void *)statePtr);
1738
1739
1740
1741
1742
1743
1744
1745

1746
1747
1748
1749
1750
1751
1752
1742
1743
1744
1745
1746
1747
1748

1749
1750
1751
1752
1753
1754
1755
1756







-
+







 *	constructs SSL context (CTX)
 *
 *-------------------------------------------------------------------
 */
static SSL_CTX *
CTX_Init(State *statePtr, int isServer, int proto, char *keyfile, char *certfile,
    unsigned char *key, unsigned char *cert, Tcl_Size key_len, Tcl_Size cert_len, char *CApath,
    char *CAfile, char *ciphers, char *ciphersuites, int level, char *DHparams) {
    char *CAstore, char *CAfile, char *ciphers, char *ciphersuites, int level, char *DHparams) {
    Tcl_Interp *interp = statePtr->interp;
    SSL_CTX *ctx = NULL;
    Tcl_DString ds;
    int off = 0, abort = 0;
    int load_private_key;
    const SSL_METHOD *method;

2031
2032
2033
2034
2035
2036
2037
2038
2039
2040






2041
2042
2043
2044
2045
2046
2047
2035
2036
2037
2038
2039
2040
2041



2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054







-
-
-
+
+
+
+
+
+







	    Tcl_AppendResult(interp, "private key does not match the certificate public key",
			     (char *) NULL);
	    SSL_CTX_free(ctx);
	    return NULL;
	}
    }

    /* Set to use default location and file for Certificate Authority (CA) certificates. The
     * verify path and store can be overridden by the SSL_CERT_DIR env var. The verify file can
     * be overridden by the SSL_CERT_FILE env var. */
    /* Set to use the default location and file for Certificate Authority (CA) certificates.
     * The default CA certificates directory is called certs in the default OpenSSL
     * directory. It contains the CA certificates in PEM format, with one certificate per
     * file. The verify path and store can be overridden by the SSL_CERT_DIR env var. The
     * default CA certificates file is called cert.pem in the default OpenSSL directory.
     * The verify file can be overridden by the SSL_CERT_FILE env var. */
    if (!SSL_CTX_set_default_verify_paths(ctx)) {
	abort++;
    }

    /* Overrides for the CA verify path and file */
    {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
2062
2063
2064
2065
2066
2067
2068

2069
2070
2071
2072
2073
2074










2075
2076
2077
2078
2079
2080
2081
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099







+






+
+
+
+
+
+
+
+
+
+







	    if (certNames != NULL) {
		SSL_CTX_set_client_CA_list(ctx, certNames);
	    }
	    Tcl_DStringFree(&ds);
	}

#else
	/* Directory containing CA certificates in PEM format. */
	if (CApath != NULL) {
	    if (!SSL_CTX_load_verify_dir(ctx, F2N(CApath, &ds))) {
		abort++;
	    }
	    Tcl_DStringFree(&ds);
	}
	
	/* URI for to a store, which may be a single container or a catalog of containers. */
	if (CAstore != NULL) {
	    if (!SSL_CTX_load_verify_store(ctx, F2N(CAstore, &ds))) {
		abort++;
	    }
	    Tcl_DStringFree(&ds);
	}
	
	/* File of CA certificates in PEM format.  */
	if (CAfile != NULL) {
	    if (!SSL_CTX_load_verify_file(ctx, F2N(CAfile, &ds))) {
		abort++;
	    }
	    Tcl_DStringFree(&ds);

	    /* Set list of CAs to send to client when requesting a client certificate */
2780
2781
2782
2783
2784
2785
2786



2787
2788
2789
2790
2791
2792
2793
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814







+
+
+







 */
void Tls_Clean(State *statePtr) {
    dprintf("Called");

    if (statePtr->ssl) {
	/* Send close_notify message */
	dprintf("SSL_shutdown(%p)", statePtr->ssl);
	/* Will return return 0 while shutdown in process, then 1 when complete */
	/* closes the write direction of the connection; the read direction is closed by the peer. */
	/* Does not affect socket */
	SSL_shutdown(statePtr->ssl);
    }

    /*
     * we're assuming here that we're single-threaded
     */
    if (statePtr->timer != (Tcl_TimerToken) NULL) {
31
32
33
34
35
36
37

38
39
40
41
42
43
44
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45







+







        {0 -async sopts 0}
        {* -myaddr sopts 1}
        {0 -myport sopts 1}
        {* -type sopts 1}
        {* -alpn iopts 1}
        {* -cadir iopts 1}
        {* -cafile iopts 1}
        {* -castore iopts 1}
        {* -cert iopts 1}
        {* -certfile iopts 1}
        {* -cipher iopts 1}
        {* -ciphersuites iopts 1}
        {* -command iopts 1}
        {* -dhparams iopts 1}
        {* -key iopts 1}