Check-in [603eb0c0ba]
Overview
Comment:Merged in changes from master
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | crypto
Files: files | file ages | folders
SHA3-256: 603eb0c0badbf270e777960348d8bf9443f2d12fc2adfee9de088e3df266721b
User & Date: bohagan on 2024-02-24 03:57:03
Other Links: branch diff | manifest | tags
Context
2024-02-24
04:18
Applied optimized get string and cast nulls to char pointers to branch files check-in: aefb94a730 user: bohagan tags: crypto
03:57
Merged in changes from master check-in: 603eb0c0ba user: bohagan tags: crypto
03:26
Added back initialize dynamic strings since Tcl_TranslateFileName doesn't initialize them check-in: ccb3824e44 user: bohagan tags: trunk
2024-02-11
21:24
Updated test cases for OpenSSL 3.0. Added load legacy provider for obsolete algorithms. check-in: 8440f589be user: bohagan tags: crypto
Changes
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
18










-
+







Tool Command Language (TCL) Transport Layer Security (TLS) Extension

Intro
=====

This package provides an extension which implements Secure Socket Layer (SSL)
and Transport Layer Security (TLS) over Transmission Control Protocol (TCP)
network communication channels. It utilizes either the OpenSSL or LibreSSL
software library.
 
Version 2.0 also provides a cryptography library providing TCL scripts access
Version 1.9 also provides a cryptography library providing TCL scripts access
to the crypto capabilities of the OpenSSL library.


Description
===========

This extension works by creating a layered TCL Channel on top of an existing
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
58
59
60
61
62
63
64

65
66
67

68
69
70
71
72
73
74







-



-







The supported configure options include all of the standard TEA configure script
options, plus:

  --disable-tls1          disable TLS1 protocol
  --disable-tls1_1        disable TLS1.1 protocol
  --disable-tls1_2        disable TLS1.2 protocol
  --disable-tls1_3        disable TLS1.3 protocol
  --enable-deterministic  enable deterministic DH parameters
  --enable-ssl-fastpath   enable using the underlying file descriptor for talking directly to the SSL library
  --enable-hardening      enable hardening attempts
  --enable-static-ssl     enable static linking to the SSL library
  --with-builtin-dh-params-size=<bits>	specify the size of the built-in, precomputed, DH params

If either TCL or OpenSSL are installed in non-standard locations, the following
configure options are available. For all options, see ./configure --help.

  --with-tcl=<dir>			path to where tclCondig.sh file resides
  --with-tclinclude=<dir>		directory containing the public Tcl header files
  --with-openssl-dir=<dir>		path to root directory of OpenSSL or LibreSSL installation
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116







-
+







==========

Original TLS Copyright (C) 1997-2000 Matt Newman <matt@novadigm.com>
TLS 1.4.1    Copyright (C) 2000 Ajuba Solutions
TLS 1.6      Copyright (C) 2008 ActiveState Software Inc.
TLS 1.7      Copyright (C) 2016 Matt Newman, Ajuba Solutions, ActiveState
                                Software Inc, Roy Keene <tcltls@rkeene.org>
TLS 1.9-2.0  Copyright (C) 2023 Brian O'Hagan
TLS 1.8      Copyright (C) 2023 Brian O'Hagan

Acknowledgments
===============

Non-exclusive credits for TLS are:
   Original work: Matt Newman @ Novadigm
   Updates: Jeff Hobbs @ ActiveState
Modified configure from [db3c76f46d] to [11f1598819].
9324
9325
9326
9327
9328
9329
9330
9331

9332
9333
9334
9335
9336
9337
9338
9324
9325
9326
9327
9328
9329
9330

9331
9332
9333
9334
9335
9336
9337
9338







-
+







# For the OpenSSL version, I chose to use the same library names that
# OpenSSL uses as its default names.
#--------------------------------------------------------------------

if test "${TEA_PLATFORM}" = "windows" ; then
    if test "$GCC" = "yes"; then

    PKG_CFLAGS="$PKG_CFLAGS ${TCLTLS_SSL_CFLAGS}"
    PKG_CFLAGS="$PKG_CFLAGS ${TCLTLS_SSL_CFLAGS} -Wno-deprecated-declarations"



    vars="${TCLTLS_SSL_INCLUDES}"
    for i in $vars; do
	PKG_INCLUDES="$PKG_INCLUDES $i"
    done
9348
9349
9350
9351
9352
9353
9354
9355

9356
9357
9358
9359
9360
9361
9362
9348
9349
9350
9351
9352
9353
9354

9355
9356
9357
9358
9359
9360
9361
9362







-
+







	PKG_LIBS="$PKG_LIBS $i"
    done


    fi
else

    PKG_CFLAGS="$PKG_CFLAGS ${TCLTLS_SSL_CFLAGS}"
    PKG_CFLAGS="$PKG_CFLAGS ${TCLTLS_SSL_CFLAGS} -Wno-deprecated-declarations"



    vars="${TCLTLS_SSL_INCLUDES}"
    for i in $vars; do
	PKG_INCLUDES="$PKG_INCLUDES $i"
    done
173
174
175
176
177
178
179
180

181
182
183
184
185

186
187
188
189
190
191
192
173
174
175
176
177
178
179

180
181
182
183
184

185
186
187
188
189
190
191
192







-
+




-
+







# Also, windows libraries and unix libraries have different names.
# For the OpenSSL version, I chose to use the same library names that
# OpenSSL uses as its default names.
#--------------------------------------------------------------------

if test "${TEA_PLATFORM}" = "windows" ; then
    if test "$GCC" = "yes"; then
	TEA_ADD_CFLAGS([${TCLTLS_SSL_CFLAGS}])
	TEA_ADD_CFLAGS([${TCLTLS_SSL_CFLAGS} -Wno-deprecated-declarations])
	TEA_ADD_INCLUDES([${TCLTLS_SSL_INCLUDES}])
	TEA_ADD_LIBS([${TCLTLS_SSL_LIBS}])
    fi
else
	TEA_ADD_CFLAGS([${TCLTLS_SSL_CFLAGS}])
	TEA_ADD_CFLAGS([${TCLTLS_SSL_CFLAGS} -Wno-deprecated-declarations])
	TEA_ADD_INCLUDES([${TCLTLS_SSL_INCLUDES}])
	TEA_ADD_LIBS([${TCLTLS_SSL_LIBS}])
fi

#--------------------------------------------------------------------
# Determine the name of the tclsh and/or wish executables in the
# Tcl and Tk build directories or the location they were installed
1
2
3
4

5
6
7
8
9
10
11
12
1
2
3

4

5
6
7
8
9
10
11



-
+
-







<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type"
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
content="text/html; charset=iso-8859-1">
<meta name="Copyright" content="1999 Matt Newman / 2004 Starfish Systems">
<title>TLS (SSL) TCL Commands</title>
<link rel="stylesheet" href="docs.css" type="text/css" media="all">
</head>

<body class="vsc-initialized">

414
415
416
417
418
419
420
421

422
423
424
425
426
427
428
414
415
416
417
418
419
420

421
422
423
424
425
426
427
428







-
+







    Tcl_IncrRefCount(cmdPtr);
    ok = EvalCallback(interp, statePtr, cmdPtr);
    Tcl_DecrRefCount(cmdPtr);

    dprintf("VerifyCallback: command result = %d", ok);

    /* statePtr->flags &= ~(TLS_TCL_CALLBACK); */
    return(ok);	/* By default, leave verification unchanged. */
    return ok;	/* By default, leave verification unchanged. */
}

/*
 *-------------------------------------------------------------------
 *
 * Tls_Error --
 *
450
451
452
453
454
455
456
457

458
459
460
461
462
463
464
450
451
452
453
454
455
456

457
458
459
460
461
462
463
464







-
+







    cmdPtr = Tcl_DuplicateObj(statePtr->callback);
    Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj("error", -1));
    Tcl_ListObjAppendElement(interp, cmdPtr,
	    Tcl_NewStringObj(Tcl_GetChannelName(statePtr->self), -1));
    if (msg != NULL) {
	Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(msg, -1));

    } else if ((msg = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), (Tcl_Size *) NULL)) != NULL) {
    } else if ((msg = Tcl_GetString(Tcl_GetObjResult(interp))) != NULL) {
	Tcl_ListObjAppendElement(interp, cmdPtr, Tcl_NewStringObj(msg, -1));

    } else {
	listPtr = Tcl_NewListObj(0, NULL);
	while ((err = ERR_get_error()) != 0) {
	    Tcl_ListObjAppendElement(interp, listPtr, Tcl_NewStringObj(ERR_reason_error_string(err), -1));
	}
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
565
566
567
568
569
570
571

572
573
574
575
576
577
578
579







-
+







	char *ret = (char *) Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &len);
	if (len > (Tcl_Size) size-1) {
	    len = (Tcl_Size) size-1;
	}
	strncpy(buf, ret, (size_t) len);
	buf[len] = '\0';
	Tcl_Release((ClientData) interp);
	return((int) len);
	return (int) len;
    }
    Tcl_Release((ClientData) interp);
    return -1;
}

/*
 *-------------------------------------------------------------------
957
958
959
960
961
962
963
964

965
966
967
968
969

970
971

972
973
974
975
976
977
978

979
980

981
982
983
984
985
986
987
957
958
959
960
961
962
963

964
965
966
967
968

969
970

971
972
973
974
975
976
977

978
979

980
981
982
983
984
985
986
987







-
+




-
+

-
+






-
+

-
+







    int err = 0;
    (void) clientData;

    dprintf("Called");

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

    ERR_clear_error();

    chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], (Tcl_Size *) NULL), NULL);
    chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
    if (chan == (Tcl_Channel) NULL) {
	return(TCL_ERROR);
	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);
	    "\": not a TLS channel", (char *) NULL);
	Tcl_SetErrorCode(interp, "TLS", "HANDSHAKE", "CHANNEL", "INVALID", (char *) NULL);
	return(TCL_ERROR);
	return TCL_ERROR;
    }
    statePtr = (State *)Tcl_GetChannelInstanceData(chan);

    dprintf("Calling Tls_WaitForConnect");
    ret = Tls_WaitForConnect(statePtr, &err, 1);
    dprintf("Tls_WaitForConnect returned: %i", ret);

1000
1001
1002
1003
1004
1005
1006
1007

1008
1009
1010
1011
1012
1013
1014
1015
1016
1017

1018
1019
1020
1021
1022
1023
1024
1000
1001
1002
1003
1004
1005
1006

1007
1008
1009
1010
1011
1012
1013
1014
1015
1016

1017
1018
1019
1020
1021
1022
1023
1024







-
+









-
+








	Tcl_AppendResult(interp, "handshake failed: ", errStr, (char *) NULL);
	if ((result = SSL_get_verify_result(statePtr->ssl)) != X509_V_OK) {
	    Tcl_AppendResult(interp, " due to \"", X509_verify_cert_error_string(result), "\"", (char *) NULL);
	}
	Tcl_SetErrorCode(interp, "TLS", "HANDSHAKE", "FAILED", (char *) NULL);
	dprintf("Returning TCL_ERROR with handshake failed: %s", errStr);
	return(TCL_ERROR);
	return TCL_ERROR;
    } else {
	if (err != 0) {
	    dprintf("Got an error with a completed handshake: err = %i", err);
	}
	ret = 1;
    }

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

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};
1101
1102
1103
1104
1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
1101
1102
1103
1104
1105
1106
1107

1108
1109
1110
1111
1112
1113
1114
1115







-
+







    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "channel ?options?");
	return TCL_ERROR;
    }

    ERR_clear_error();

    chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], (Tcl_Size *) NULL), NULL);
    chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
    if (chan == (Tcl_Channel) NULL) {
	return TCL_ERROR;
    }

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

1281
1282
1283
1284
1285
1286
1287
1288

1289
1290
1291
1292
1293
1294
1295
1281
1282
1283
1284
1285
1286
1287

1288
1289
1290
1291
1292
1293
1294
1295







-
+








	/*
	 * 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);
		"\": not a TLS channel", (char *) NULL);
	    Tcl_SetErrorCode(interp, "TLS", "IMPORT", "CHANNEL", "INVALID", (char *) NULL);
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}
	ctx = ((State *)Tcl_GetChannelInstanceData(chan))->ctx;
    } else {
	if ((ctx = CTX_Init(statePtr, server, proto, keyfile, certfile, key, cert, (int) key_len,
1549
1550
1551
1552
1553
1554
1555
1556

1557
1558
1559
1560
1561
1562
1563
1549
1550
1551
1552
1553
1554
1555

1556
1557
1558
1559
1560
1561
1562
1563







-
+







    }

    /* 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);
		"\": not a TLS channel", (char *) NULL);
	    Tcl_SetErrorCode(interp, "TLS", "UNIMPORT", "CHANNEL", "INVALID", (char *) NULL);
	return TCL_ERROR;
    }

    if (Tcl_UnstackChannel(interp, chan) == TCL_ERROR) {
	return TCL_ERROR;
    }
1695
1696
1697
1698
1699
1700
1701
1702

1703
1704
1705
1706
1707
1708
1709
1695
1696
1697
1698
1699
1700
1701

1702
1703
1704
1705
1706
1707
1708
1709







-
+







	break;
    }

    ERR_clear_error();

    ctx = SSL_CTX_new(method);
    if (!ctx) {
	return(NULL);
	return NULL;
    }

    if (getenv(SSLKEYLOGFILE)) {
	SSL_CTX_set_keylog_callback(ctx, KeyLogCallback);
    }

#if !defined(NO_TLS1_3) && !defined(OPENSSL_NO_TLS1_3)
1761
1762
1763
1764
1765
1766
1767


1768
1769
1770
1771
1772
1773
1774
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776







+
+







	return NULL;
    }
#else
    {
	DH* dh;
	if (DHparams != NULL) {
	    BIO *bio;

	    Tcl_DStringInit(&ds);
	    bio = BIO_new_file(F2N(DHparams, &ds), "r");
	    if (!bio) {
		Tcl_DStringFree(&ds);
		Tcl_AppendResult(interp, "Could not find DH parameters file", (char *) NULL);
		SSL_CTX_free(ctx);
		return NULL;
	    }
1796
1797
1798
1799
1800
1801
1802

1803
1804
1805
1806
1807
1808
1809
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812







+







#endif

    /* set our certificate */
    load_private_key = 0;
    if (certfile != NULL) {
	load_private_key = 1;

	Tcl_DStringInit(&ds);
	if (SSL_CTX_use_certificate_file(ctx, F2N(certfile, &ds), SSL_FILETYPE_PEM) <= 0) {
	    Tcl_DStringFree(&ds);
	    Tcl_AppendResult(interp, "unable to set certificate file ", certfile, ": ",
		GET_ERR_REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return NULL;
	}
1839
1840
1841
1842
1843
1844
1845

1846
1847
1848
1849
1850
1851
1852
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856







+








	if (keyfile != NULL) {
	    /* get the private key associated with this certificate */
	    if (keyfile == NULL) {
		keyfile = certfile;
	    }

	    Tcl_DStringInit(&ds);
	    if (SSL_CTX_use_PrivateKey_file(ctx, F2N(keyfile, &ds), SSL_FILETYPE_PEM) <= 0) {
		Tcl_DStringFree(&ds);
		/* flush the passphrase which might be left in the result */
		Tcl_SetResult(interp, NULL, TCL_STATIC);
		Tcl_AppendResult(interp, "unable to set public key file ", keyfile, " ",
		    GET_ERR_REASON(), (char *) NULL);
		SSL_CTX_free(ctx);
1881
1882
1883
1884
1885
1886
1887



1888
1889
1890
1891
1892
1893
1894
1895
1896

1897
1898
1899
1900
1901
1902
1903
1904
1905

1906
1907
1908
1909
1910
1911

1912
1913
1914
1915
1916
1917

1918
1919
1920
1921
1922
1923
1924
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935







+
+
+









+









+






+






+







    }

    /* Overrides for the CA verify path and file */
    {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
	if (CApath != NULL || CAfile != NULL) {
	    Tcl_DString ds1;
	    Tcl_DStringInit(&ds);
	    Tcl_DStringInit(&ds1);

	    if (!SSL_CTX_load_verify_locations(ctx, F2N(CAfile, &ds), F2N(CApath, &ds1))) {
		abort++;
	    }
	    Tcl_DStringFree(&ds);
	    Tcl_DStringFree(&ds1);

	    /* Set list of CAs to send to client when requesting a client certificate */
	    /* https://sourceforge.net/p/tls/bugs/57/ */
	    /* XXX:TODO: Let the user supply values here instead of something that exists on the filesystem */
	    Tcl_DStringInit(&ds);
	    STACK_OF(X509_NAME) *certNames = SSL_load_client_CA_file(F2N(CAfile, &ds));
	    if (certNames != NULL) {
		SSL_CTX_set_client_CA_list(ctx, certNames);
	    }
	    Tcl_DStringFree(&ds);
	}

#else
	if (CApath != NULL) {
	    Tcl_DStringInit(&ds);
	    if (!SSL_CTX_load_verify_dir(ctx, F2N(CApath, &ds))) {
		abort++;
	    }
	    Tcl_DStringFree(&ds);
	}
	if (CAfile != NULL) {
	    Tcl_DStringInit(&ds);
	    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 */
	    Tcl_DStringInit(&ds);
	    STACK_OF(X509_NAME) *certNames = SSL_load_client_CA_file(F2N(CAfile, &ds));
	    if (certNames != NULL) {
		SSL_CTX_set_client_CA_list(ctx, certNames);
	    }
	    Tcl_DStringFree(&ds);
	}
#endif
1957
1958
1959
1960
1961
1962
1963
1964

1965
1966
1967
1968
1969
1970
1971
1972
1973
1974

1975
1976
1977
1978
1979
1980
1981
1968
1969
1970
1971
1972
1973
1974

1975
1976
1977
1978
1979
1980
1981
1982
1983
1984

1985
1986
1987
1988
1989
1990
1991
1992







-
+









-
+








    if (objc < 2 || objc > 3 || (objc == 3 && !strcmp(Tcl_GetString(objv[1]), "-local"))) {
	Tcl_WrongNumArgs(interp, 1, objv, "?-local? channel");
	return TCL_ERROR;
    }

    /* Get channel Id */
    channelName = Tcl_GetStringFromObj(objv[(objc == 2 ? 1 : 2)], (Tcl_Size *) NULL);
    channelName = Tcl_GetString(objv[(objc == 2 ? 1 : 2)]);
    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);
		"\": not a TLS channel", (char *) NULL);
	Tcl_SetErrorCode(interp, "TLS", "STATUS", "CHANNEL", "INVALID", (char *) NULL);
	return TCL_ERROR;
    }
    statePtr = (State *) Tcl_GetChannelInstanceData(chan);

    /* Get certificate for peer or self */
    if (objc == 2) {
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
2100
2101
2102
2103
2086
2087
2088
2089
2090
2091
2092

2093
2094
2095

2096
2097

2098
2099
2100
2101
2102
2103
2104

2105
2106

2107
2108
2109
2110
2111
2112
2113
2114







-
+


-
+

-
+






-
+

-
+







    const SSL_CIPHER *cipher;
    const SSL_SESSION *session;
    const EVP_MD *md;
    (void) clientData;

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

    chan = Tcl_GetChannel(interp, Tcl_GetStringFromObj(objv[1], (Tcl_Size *) NULL), NULL);
    chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL);
    if (chan == (Tcl_Channel) NULL) {
	return(TCL_ERROR);
	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);
	    "\": not a TLS channel", (char *) NULL);
	Tcl_SetErrorCode(interp, "TLS", "CONNECTION", "CHANNEL", "INVALID", (char *) NULL);
	return(TCL_ERROR);
	return TCL_ERROR;
    }

    objPtr = Tcl_NewListObj(0, NULL);

    /* Connection info */
    statePtr = (State *)Tcl_GetChannelInstanceData(chan);
    ssl = statePtr->ssl;
2444
2445
2446
2447
2448
2449
2450
2451

2452
2453
2454
2455
2456
2457
2458
2455
2456
2457
2458
2459
2460
2461

2462
2463
2464
2465
2466
2467
2468
2469







-
+








		if ((cert=X509_new())==NULL) {
		    Tcl_SetResult(interp,"Error generating certificate request",NULL);
		    EVP_PKEY_free(pkey);
#if OPENSSL_VERSION_NUMBER < 0x30000000L
		    BN_free(bne);
#endif
		    return(TCL_ERROR);
		    return TCL_ERROR;
		}

		X509_set_version(cert,2);
		ASN1_INTEGER_set(X509_get_serialNumber(cert),serial);
		X509_gmtime_adj(X509_getm_notBefore(cert),0);
		X509_gmtime_adj(X509_getm_notAfter(cert),(long)60*60*24*days);
		X509_set_pubkey(cert,pkey);
2682
2683
2684
2685
2686
2687
2688
2689

2690
2691
2692
2693
2694
2695
2696
2693
2694
2695
2696
2697
2698
2699

2700
2701
2702
2703
2704
2705
2706
2707







-
+







 *	Result:
 *		A standard Tcl error code.
 *
 *------------------------------------------------------*
 */
DLLEXPORT int Tls_SafeInit(Tcl_Interp *interp) {
    dprintf("Called");
    return(Tls_Init(interp));
    return Tls_Init(interp);
}

/*
 *------------------------------------------------------*
 *
 *	TlsLibInit --
 *
2713
2714
2715
2716
2717
2718
2719
2720

2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740

2741
2742
2743
2744
2745

2746
2747
2748
2749
2750
2751
2752
2724
2725
2726
2727
2728
2729
2730

2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750

2751
2752
2753
2754
2755

2756
2757
2758
2759
2760
2761
2762
2763







-
+



















-
+




-
+







    size_t num_locks;
#endif

    if (uninitialize) {
	if (!initialized) {
	    dprintf("Asked to uninitialize, but we are not initialized");

	    return(TCL_OK);
	    return TCL_OK;
	}

	dprintf("Asked to uninitialize");

#if defined(OPENSSL_THREADS) && defined(TCL_THREADS)
	Tcl_MutexLock(&init_mx);

	if (locks) {
	    free(locks);
	    locks = NULL;
	    locksCount = 0;
	}
#endif
	initialized = 0;

#if defined(OPENSSL_THREADS) && defined(TCL_THREADS)
	Tcl_MutexUnlock(&init_mx);
#endif

	return(TCL_OK);
	return TCL_OK;
    }

    if (initialized) {
	dprintf("Called, but using cached value");
	return(status);
	return status;
    }

    dprintf("Called");

#if defined(OPENSSL_THREADS) && defined(TCL_THREADS)
    Tcl_MutexLock(&init_mx);
#endif
2790
2791
2792
2793
2794
2795
2796
2797

2798
2801
2802
2803
2804
2805
2806
2807

2808
2809







-
+

    } while (RAND_status() != 1);
#endif

#if defined(OPENSSL_THREADS) && defined(TCL_THREADS)
    Tcl_MutexUnlock(&init_mx);
#endif

    return(status);
    return status;
}
52
53
54
55
56
57
58
59

60
61
62
63
64
65
66
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66







-
+







    if (ret != -1 || (ret == -1 && tclErrno == EAGAIN)) {
	if (BIO_should_read(bio)) {
	    dprintf("Setting should retry read flag");

	    BIO_set_retry_read(bio);
	}
    }
    return((int) ret);
    return (int) ret;
}

/* Called by SSL_read()*/
static int BioRead(BIO *bio, char *buf, int bufLen) {
    Tcl_Channel chan;
    Tcl_Size ret = 0;
    int tclEofChan, tclErrno;
113
114
115
116
117
118
119
120

121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
113
114
115
116
117
118
119

120
121
122
123
124
125

126
127
128
129
130
131
132
133
134
135
136
137
138
139

140
141
142
143
144
145
146







-
+





-
+













-







	    BIO_set_retry_write(bio);
	}
    }

    dprintf("BioRead(%p, <buf>, %d) [%p] returning %" TCL_SIZE_MODIFIER "d", (void *) bio,
	bufLen, (void *) chan, ret);

    return((int) ret);
    return (int) ret;
}

static int BioPuts(BIO *bio, const char *str) {
    dprintf("BioPuts(%p, <string:%p>) called", bio, str);

    return(BioWrite(bio, str, (int) strlen(str)));
    return BioWrite(bio, str, (int) strlen(str));
}

static long BioCtrl(BIO *bio, int cmd, long num, void *ptr) {
    Tcl_Channel chan;
    long ret = 1;

    chan = Tls_GetParent((State *) BIO_get_data(bio), 0);

    dprintf("BioCtrl(%p, 0x%x, 0x%lx, %p)", (void *) bio, cmd, num, ptr);

    switch (cmd) {
	case BIO_CTRL_RESET:
		dprintf("Got BIO_CTRL_RESET");
		num = 0;
		ret = 0;
		break;
	case BIO_C_FILE_SEEK:
		dprintf("Got BIO_C_FILE_SEEK");
		ret = 0;
		break;
	case BIO_C_FILE_TELL:
218
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233
234

235
236
237
238
239

240
241
242
243
244
245
246
247
248
249
250
251
252
253

254
255
256
257
258
259
260
217
218
219
220
221
222
223

224
225
226
227
228
229
230
231
232

233
234
235
236
237

238
239
240
241
242
243
244
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259







-
+








-
+




-
+













-
+







		break;
#endif
	default:
		dprintf("Got unknown control command (%i)", cmd);
		ret = 0;
		break;
    }
    return(ret);
    return ret;
}

static int BioNew(BIO *bio) {
    dprintf("BioNew(%p) called", bio);

    BIO_set_init(bio, 0);
    BIO_set_data(bio, NULL);
    BIO_clear_flags(bio, -1);
    return(1);
    return 1;
}

static int BioFree(BIO *bio) {
    if (bio == NULL) {
	return(0);
	return 0;
    }

    dprintf("BioFree(%p) called", bio);

    if (BIO_get_shutdown(bio)) {
	if (BIO_get_init(bio)) {
	    /*shutdown(bio->num, 2) */
	    /*closesocket(bio->num) */
	}

	BIO_set_init(bio, 0);
	BIO_clear_flags(bio, -1);
    }
    return(1);
    return 1;
}

BIO *BIO_new_tcl(State *statePtr, int flags) {
    BIO *bio;
    static BIO_METHOD *BioMethods = NULL;
#ifdef TCLTLS_SSL_USE_FASTPATH
    Tcl_Channel parentChannel;
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
275
276
277
278
279
280
281

282
283
284
285
286
287
288
289







-
+







	BIO_meth_set_create(BioMethods, BioNew);
	BIO_meth_set_destroy(BioMethods, BioFree);
    }

    if (statePtr == NULL) {
	dprintf("Asked to setup a NULL state, just creating the initial configuration");

	return(NULL);
	return NULL;
    }

#ifdef TCLTLS_SSL_USE_FASTPATH
    /*
     * If the channel can be mapped back to a file descriptor, just use the file descriptor
     * with the SSL library since it will likely be optimized for this.
     */
307
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322
323
324

325
306
307
308
309
310
311
312

313
314
315
316
317
318
319
320
321
322

323
324







-
+









-
+

	}
    }

    if (validParentChannelFd) {
	dprintf("We found a shortcut, this channel is backed by a socket: %i", parentChannelFdIn);
	bio = BIO_new_socket(parentChannelFd, flags);
	statePtr->flags |= TLS_TCL_FASTPATH;
	return(bio);
	return bio;
    }

    dprintf("Falling back to Tcl I/O for this channel");
#endif

    bio = BIO_new(BioMethods);
    BIO_set_data(bio, statePtr);
    BIO_set_shutdown(bio, flags);
    BIO_set_init(bio, 1);
    return(bio);
    return bio;
}
45
46
47
48
49
50
51
52

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

52
53
54
55
56
57
58
59







-
+







    State *statePtr = (State *) instanceData;

    if (mode == TCL_MODE_NONBLOCKING) {
	statePtr->flags |= TLS_TCL_ASYNC;
    } else {
	statePtr->flags &= ~(TLS_TCL_ASYNC);
    }
    return(0);
    return 0;
}

/*
 *-------------------------------------------------------------------
 *
 * TlsCloseProc --
 *
74
75
76
77
78
79
80
81

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

81
82
83
84
85
86
87
88







-
+







static int TlsCloseProc(ClientData instanceData, Tcl_Interp *interp) {
    State *statePtr = (State *) instanceData;

    dprintf("TlsCloseProc(%p)", (void *) statePtr);

    Tls_Clean(statePtr);
    Tcl_EventuallyFree((ClientData)statePtr, Tls_Free);
    return(0);
    return 0;
}

static int TlsClose2Proc(ClientData instanceData,    /* The socket state. */
    Tcl_Interp *interp,		/* For errors - can be NULL. */
    int flags)			/* Flags to close read and/or write side of channel */
{
    State *statePtr = (State *) instanceData;
115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
115
116
117
118
119
120
121

122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137

138
139
140
141
142
143
144
145







-
+















-
+







    *errorCodePtr = 0;

    dprintf("WaitForConnect(%p)", (void *) statePtr);
    dprintFlags(statePtr);

    if (!(statePtr->flags & TLS_TCL_INIT)) {
	dprintf("Tls_WaitForConnect called on already initialized channel -- returning with immediate success");
	return(0);
	return 0;
    }

    if (statePtr->flags & TLS_TCL_HANDSHAKE_FAILED) {
	/*
	 * Different types of operations have different requirements
	 * SSL being established
	 */
	if (handshakeFailureIsPermanent) {
	    dprintf("Asked to wait for a TLS handshake that has already failed.  Returning fatal error");
	    *errorCodePtr = ECONNABORTED;
	} else {
	    dprintf("Asked to wait for a TLS handshake that has already failed.  Returning soft error");
	    *errorCodePtr = ECONNRESET;
	}
	Tls_Error(statePtr, "Wait for failed handshake");
	return(-1);
	return -1;
    }

    for (;;) {
	ERR_clear_error();

	/* Not initialized yet! Also calls SSL_do_handshake. */
	if (statePtr->flags & TLS_TCL_SERVER) {
186
187
188
189
190
191
192
193

194
195
196
197
198
199
200
186
187
188
189
190
191
192

193
194
195
196
197
198
199
200







-
+







	if (bioShouldRetry) {
	    dprintf("The I/O did not complete -- but we should try it again");

	    if (statePtr->flags & TLS_TCL_ASYNC) {
		dprintf("Returning EAGAIN so that it can be retried later");
		*errorCodePtr = EAGAIN;
		Tls_Error(statePtr, "Handshake not complete, will retry later");
		return(-1);
		return -1;
	    } else {
		dprintf("Doing so now");
		continue;
	    }
	}

	dprintf("We have either completely established the session or completely failed it -- there is no more need to ever retry it though");
209
210
211
212
213
214
215
216

217
218
219
220
221
222
223
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223







-
+







	    break;

	case SSL_ERROR_ZERO_RETURN:
	    /* The TLS/SSL peer has closed the connection for writing by sending the close_notify alert */
	    dprintf("SSL_ERROR_ZERO_RETURN: Connect returned an invalid value...");
	    *errorCodePtr = EINVAL;
	    Tls_Error(statePtr, "Peer has closed the connection for writing by sending the close_notify alert");
	    return(-1);
	    return -1;

	case SSL_ERROR_SYSCALL:
	    /* Some non-recoverable, fatal I/O error occurred */
	    dprintf("SSL_ERROR_SYSCALL");
	    if (backingError == 0 && err == 0) {
		dprintf("EOF reached")
		*errorCodePtr = ECONNRESET;
237
238
239
240
241
242
243
244

245
246
247
248
249
250
251
252
253
254
255
256
257

258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
281

282
283
284
285
286
287
288
237
238
239
240
241
242
243

244
245
246
247
248
249
250
251
252
253
254
255
256

257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280

281
282
283
284
285
286
287
288







-
+












-
+















-
+







-
+







		if (*errorCodePtr == ECONNRESET) {
		    *errorCodePtr = ECONNABORTED;
		}
		Tls_Error(statePtr, (char *) ERR_reason_error_string(backingError));
	    }

	    statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
	    return(-1);
	    return -1;

	case SSL_ERROR_SSL:
	    /* A non-recoverable, fatal error in the SSL library occurred, usually a protocol error */
	    dprintf("SSL_ERROR_SSL: Got permanent fatal SSL error, aborting immediately");
	    if (SSL_get_verify_result(statePtr->ssl) != X509_V_OK) {
		Tls_Error(statePtr, (char *) X509_verify_cert_error_string(SSL_get_verify_result(statePtr->ssl)));
	    }
	    if (backingError != 0) {
		Tls_Error(statePtr, (char *) ERR_reason_error_string(backingError));
	    }
	    statePtr->flags |= TLS_TCL_HANDSHAKE_FAILED;
	    *errorCodePtr = ECONNABORTED;
	    return(-1);
	    return -1;

	case SSL_ERROR_WANT_READ:
	case SSL_ERROR_WANT_WRITE:
	case SSL_ERROR_WANT_X509_LOOKUP:
	case SSL_ERROR_WANT_CONNECT:
	case SSL_ERROR_WANT_ACCEPT:
	case SSL_ERROR_WANT_ASYNC:
	case SSL_ERROR_WANT_ASYNC_JOB:
	case SSL_ERROR_WANT_CLIENT_HELLO_CB:
	default:
	    /* The operation did not complete and should be retried later. */
	    dprintf("Operation did not complete, call function again later: %i", rc);
	    *errorCodePtr = EAGAIN;
	    dprintf("ERR(%d, %d) ", rc, *errorCodePtr);
	    Tls_Error(statePtr, "Operation did not complete, call function again later");
	    return(-1);
	    return -1;
    }

    dprintf("Removing the \"TLS_TCL_INIT\" flag since we have completed the handshake");
    statePtr->flags &= ~TLS_TCL_INIT;

    dprintf("Returning in success");
    *errorCodePtr = 0;
    return(0);
    return 0;
}

/*
 *-------------------------------------------------------------------
 *
 * TlsInputProc --
 *
308
309
310
311
312
313
314
315

316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

332
333
334
335
336
337
338
308
309
310
311
312
313
314

315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338







-
+















-
+







    *errorCodePtr = 0;

    dprintf("BIO_read(%d)", bufSize);

    if (statePtr->flags & TLS_TCL_CALLBACK) {
	/* don't process any bytes while verify callback is running */
	dprintf("Callback is running, reading 0 bytes");
	return(0);
	return 0;
    }

    dprintf("Calling Tls_WaitForConnect");
    tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 0);
    if (tlsConnect < 0) {
	dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr);
	Tls_Error(statePtr, strerror(*errorCodePtr));

	bytesRead = -1;
	if (*errorCodePtr == ECONNRESET) {
	    dprintf("Got connection reset");
	    /* Soft EOF */
	    *errorCodePtr = 0;
	    bytesRead = 0;
	}
	return(bytesRead);
	return bytesRead;
    }

    /*
     * We need to clear the SSL error stack now because we sometimes reach
     * this function with leftover errors in the stack.  If BIO_read
     * returns -1 and intends EAGAIN, there is a leftover error, it will be
     * misconstrued as an error, not EAGAIN.
429
430
431
432
433
434
435
436

437
438
439
440
441
442
443
429
430
431
432
433
434
435

436
437
438
439
440
441
442
443







-
+







	    *errorCodePtr = 0;
	    bytesRead = 0;
	    Tls_Error(statePtr, "Unknown error");
	    break;
    }

    dprintf("Input(%d) -> %d [%d]", bufSize, bytesRead, *errorCodePtr);
    return(bytesRead);
    return bytesRead;
}

/*
 *-------------------------------------------------------------------
 *
 * TlsOutputProc --
 *
464
465
466
467
468
469
470
471

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

488
489
490
491
492
493
494
495
496
497
498
499
500

501
502
503
504
505

506
507
508
509
510
511
512
464
465
466
467
468
469
470

471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486

487
488
489
490
491
492
493
494
495
496
497
498
499

500
501
502
503
504

505
506
507
508
509
510
511
512







-
+















-
+












-
+




-
+







    dprintf("BIO_write(%p, %d)", (void *) statePtr, toWrite);
    dprintBuffer(buf, toWrite);

    if (statePtr->flags & TLS_TCL_CALLBACK) {
	dprintf("Don't process output while callbacks are running");
	written = -1;
	*errorCodePtr = EAGAIN;
	return(-1);
	return -1;
    }

    dprintf("Calling Tls_WaitForConnect");
    tlsConnect = Tls_WaitForConnect(statePtr, errorCodePtr, 1);
    if (tlsConnect < 0) {
	dprintf("Got an error waiting to connect (tlsConnect = %i, *errorCodePtr = %i)", tlsConnect, *errorCodePtr);
	Tls_Error(statePtr, strerror(*errorCodePtr));

	written = -1;
	if (*errorCodePtr == ECONNRESET) {
	    dprintf("Got connection reset");
	    /* Soft EOF */
	    *errorCodePtr = 0;
	    written = 0;
	}
	return(written);
	return written;
    }

    if (toWrite == 0) {
	dprintf("zero-write");
	err = BIO_flush(statePtr->bio);

	if (err <= 0) {
	    dprintf("Flushing failed");
	    Tls_Error(statePtr, "Flush failed");

	    *errorCodePtr = EIO;
	    written = 0;
	    return(-1);
	    return -1;
	}

	written = 0;
	*errorCodePtr = 0;
	return(0);
	return 0;
    }

    /*
     * We need to clear the SSL error stack now because we sometimes reach
     * this function with leftover errors in the stack.  If BIO_write
     * returns -1 and intends EAGAIN, there is a leftover error, it will be
     * misconstrued as an error, not EAGAIN.
593
594
595
596
597
598
599
600

601
602
603
604
605
606
607
593
594
595
596
597
598
599

600
601
602
603
604
605
606
607







-
+







	default:
	    dprintf("unknown error: %d", err);
	    Tls_Error(statePtr, "Unknown error");
	    break;
    }

    dprintf("Output(%d) -> %d", toWrite, written);
    return(written);
    return written;
}

/*
 *-------------------------------------------------------------------
 *
 * TlsSetOptionProc --
 *
788
789
790
791
792
793
794
795

796
797
798
799
800
801
802
788
789
790
791
792
793
794

795
796
797
798
799
800
801
802







-
+







 */
static int TlsGetHandleProc(ClientData instanceData,    /* Socket state. */
    int direction,		/* TCL_READABLE or TCL_WRITABLE */
    ClientData *handlePtr)	/* Handle associated with the channel */
{
    State *statePtr = (State *) instanceData;

    return(Tcl_GetChannelHandle(Tls_GetParent(statePtr, TLS_TCL_FASTPATH), direction, handlePtr));
    return Tcl_GetChannelHandle(Tls_GetParent(statePtr, TLS_TCL_FASTPATH), direction, handlePtr);
}

/*
 *-------------------------------------------------------------------
 *
 * TlsNotifyProc --
 *
851
852
853
854
855
856
857
858

859
860
861
862
863
864
865
851
852
853
854
855
856
857

858
859
860
861
862
863
864
865







-
+







	}

	dprintf("Tls_WaitForConnect returned an error");
    }

    dprintf("Returning %i", mask);

    return(mask);
    return mask;
}

/*
 *------------------------------------------------------*
 *
 *    TlsChannelHandlerTimer --
 *
905
906
907
908
909
910
911
912

913
914

915
916
917
918
919
920
921
905
906
907
908
909
910
911

912
913

914
915
916
917
918
919
920
921







-
+

-
+







}

Tcl_Channel Tls_GetParent(State *statePtr, int maskFlags) {
    dprintf("Requested to get parent of channel %p", statePtr->self);

    if ((statePtr->flags & ~maskFlags) & TLS_TCL_FASTPATH) {
	dprintf("Asked to get the parent channel while we are using FastPath -- returning NULL");
	return(NULL);
	return NULL;
    }
    return(Tcl_GetStackedChannel(statePtr->self));
    return Tcl_GetStackedChannel(statePtr->self);
}

/*
 *-------------------------------------------------------------------
 *
 * Tls_ChannelType --
 *
1
2
3
4
5
6
7
8
9
10
11
12
13
14


15
16

17
18
19
20
21
22
23
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













-
+
+


+







# -*- tcl -*-
# Tcl package index file, version 1.1
#
if {[package vsatisfies [package provide Tcl] 9.0-]} {
    package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \
	    [list load [file join $dir @PKG_LIB_FILE9@] [string totitle @PACKAGE_NAME@]]
    set initScript [file join $dir @PACKAGE_NAME@.tcl]
    if {[file exists $initScript]} {
	source -encoding utf-8 $initScript
    }
} else {
    if {![package vsatisfies [package provide Tcl] 8.5]} {return}
    package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ [list apply {{dir} {
	if {[string tolower [file extension @PKG_LIB_FILE8@]] in [list ".dll" ".so"]} {
	if {[string tolower [file extension @PKG_LIB_FILE8@]] in [list .dll .dylib .so]} {
	    # Load dynamic library
	    load [file join $dir @PKG_LIB_FILE8@] [string totitle @PACKAGE_NAME@]
	} else {
	    # Static library
	    load {} [string totitle @PACKAGE_NAME@]
	}
	set initScript [file join $dir @PACKAGE_NAME@.tcl]
	if {[file exists $initScript]} {
	    source -encoding utf-8 $initScript
	}
    }} $dir]
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
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







-
+

-
+





+
+
+
+
+
+
+
+
-
+









-
-
+
+





-
-
-
-
+
+
+
+



+
+
-
+

-
-
+
+







  Install to C:\Strawberry\perl

(1c) Install NASM Assembler from https://www.nasm.us/

  https://www.nasm.us/pub/nasm/releasebuilds/2.16.01/win64/nasm-2.16.01-installer-x64.exe
  Install to: C:\Program Files\NASM

(1d) Configure
(1d) Configure Open SSL 1.1.1

  At Visual Studio x86 native prompt:
  At Visual Studio x64 native prompt:

  set Path=%PATH%;C:\Program Files\NASM;C:\Strawberry\perl\bin
  perl ..\Configure VC-WIN64A no-shared no-filenames threads no-ssl2 no-ssl3 --api=1.1.0 --prefix="%SSLINSTALL%" --openssldir="%SSLCOMMON%" -DOPENSSL_NO_DEPRECATED
  # Not used options: no-asm no-zlib no-comp no-ui-console no-autoload-config

(1e) Configure Open SSL 3.0+

  At Visual Studio x64 native prompt:

  set Path=%PATH%;C:\Program Files\NASM;C:\Strawberry\perl\bin
  perl ..\Configure VC-WIN64A no-shared no-filenames threads no-ssl2 no-ssl3 --prefix="%SSLINSTALL%" --openssldir="%SSLCOMMON%"
  # Not used options: no-asm no-zlib no-comp no-ui-console no-autoload-config

(1e) Build OpenSSL
(1f) Build OpenSSL

  nmake
  nmake test
  nmake install

-----------------------------

2) Build TclTLS

set BUILDDIR=\path\to\build\dir
set TCLINSTALL=\path\to\tcl\dir
  set BUILDDIR=\path\to\build\dir
  set TCLINSTALL=\path\to\tcl\dir

2a) Unzip distribution to %BUILDDIR%

2b) Start BASH shell (MinGW62 Git shell)

cd %BUILDDIR%
od -A n -v -t xC < 'library/tls.tcl' > tls.tcl.h.new.1
sed 's@[^0-9A-Fa-f]@@g;s@..@0x&, @g' < tls.tcl.h.new.1 > generic/tls.tcl.h
rm -f tls.tcl.h.new.1
  cd %BUILDDIR%
  od -A n -v -t xC < 'library/tls.tcl' > tls.tcl.h.new.1
  sed 's@[^0-9A-Fa-f]@@g;s@..@0x&, @g' < tls.tcl.h.new.1 > generic/tls.tcl.h
  rm -f tls.tcl.h.new.1

2c) Start Visual Studio shell

  At Visual Studio x64 native prompt:

cd %BUILDDIR%\win
  cd %BUILDDIR%\win

nmake -f makefile.vc TCLDIR=%TCLINSTALL% SSL_INSTALL_FOLDER=%SSLINSTALL%
nmake -f makefile.vc install TCLDIR=c:\test\tcl8610 INSTALLDIR=%TCLINSTALL% SSL_INSTALL_FOLDER=%SSLINSTALL%
  nmake -f makefile.vc TCLDIR=%TCLINSTALL% SSL_INSTALL_FOLDER=%SSLINSTALL%
  nmake -f makefile.vc install TCLDIR=c:\test\tcl8610 INSTALLDIR=%TCLINSTALL% SSL_INSTALL_FOLDER=%SSLINSTALL%

-----------------------------

3) Test

Start tclsh or wish

72
73
74
75
76
77
78






79
80
81
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87







+
+
+
+
+
+



pkgindex: default-pkgindex

# The default install target only installs binaries and scripts so add
# an additional target for our documentation. Note this *adds* a target
# since no commands are listed after it. The original targets for
# install (from targets.vc) will remain.
install: default-pkgindex-tea default-install default-install-docs-html
    if exist "$(SSL_INSTALL_FOLDER)\bin\libcrypto-*-x64.dll" (
        xcopy /c /y "$(SSL_INSTALL_FOLDER)\bin\libcrypto-*-x64.dll" "$(PRJ_INSTALL_DIR)"
    )
    if exist "$(SSL_INSTALL_FOLDER)\bin\libssl-*-x64.dll" (
        xcopy /c /y "$(SSL_INSTALL_FOLDER)\bin\libssl-*-x64.dll" "$(PRJ_INSTALL_DIR)"
    )

# Test package
test: default-test