Changes On Branch 952ef184e63a5bc4

Changes In Branch mjanssen-asn1-certs Through [952ef184e6] Excluding Merge-Ins

This is equivalent to a diff from 2c8d3629bc to 952ef184e6

2020-05-04
15:09
Only load private key if we loaded a non-default certificate Closed-Leaf check-in: 51a2b1ec9a user: rkeene tags: mjanssen-asn1-certs
15:02
Updated to support cert/certfile independantly of key/keyfile check-in: 952ef184e6 user: rkeene tags: mjanssen-asn1-certs
14:57
Corrected wrong use of "key" check-in: f3a497fc67 user: rkeene tags: mjanssen-asn1-certs
2019-06-19
17:45
Make hardening optional, disabled by default when statically linking because it requires the linking program to fully participate check-in: 25024a31b0 user: rkeene tags: trunk
2019-06-17
12:05
Add support for ASN1 blobs for certificates and keys check-in: 49278969f2 user: mjanssen tags: mjanssen-asn1-certs
2019-04-25
16:51
Merged in changes from trunk check-in: a64e691ada user: rkeene tags: tls-1-7
2019-04-12
16:58
Better handling of shared/static naming issues check-in: 2c8d3629bc user: rkeene tags: trunk
2019-04-09
18:47
Make extension filename more centralized check-in: 8e730964e5 user: rkeene tags: trunk

Modified tclOpts.h from [aff9aa3b9c] to [1a6cf1121d].

40
41
42
43
44
45
46





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







+
+
+
+
+







#define OPTBOOL(option, var)			\
    OPT_PROLOG(option)				\
    if (Tcl_GetBooleanFromObj(interp, objv[idx],\
	    &(var)) != TCL_OK) {		\
	    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 tls.c from [c565bf20f1] to [e32cfd6f1e].

58
59
60
61
62
63
64

65
66


67
68
69
70
71
72
73
58
59
60
61
62
63
64
65


66
67
68
69
70
71
72
73
74







+
-
-
+
+







static int	MiscObjCmd(ClientData clientData,
			Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);

static int	UnimportObjCmd(ClientData clientData,
			Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);

static SSL_CTX *CTX_Init(State *statePtr, int isServer, int proto, char *key,
			char *certfile, unsigned char *key_asn1, unsigned char *cert_asn1,
			char *cert, char *CAdir, char *CAfile, char *ciphers,
			char *DHparams);
			int key_asn1_len, int cert_asn1_len, char *CAdir, char *CAfile,
      char *ciphers, char *DHparams);

static int	TlsLibInit(int uninitialize);

#define TLS_PROTO_SSL2		0x01
#define TLS_PROTO_SSL3		0x02
#define TLS_PROTO_TLS1		0x04
#define TLS_PROTO_TLS1_1	0x08
725
726
727
728
729
730
731
732
733
734



735
736
737
738
739
740
741
742
743
744
745













746
747

748
749
750
751
752
753
754
726
727
728
729
730
731
732



733
734
735
736
737









738
739
740
741
742
743
744
745
746
747
748
749
750
751

752
753
754
755
756
757
758
759







-
-
-
+
+
+


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

-
+







    ClientData clientData;	/* Not used. */
    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;
    SSL_CTX *ctx	        = NULL;
    Tcl_Obj *script	        = NULL;
    Tcl_Obj *password	        = NULL;
    Tcl_DString upperChannelTranslation, upperChannelBlocking, upperChannelEncoding, upperChannelEOFChar;
    int idx, len;
    int flags		= TLS_TCL_INIT;
    int server		= 0;	/* is connection incoming or outgoing? */
    char *key		= NULL;
    char *cert		= NULL;
    char *ciphers	= NULL;
    char *CAfile	= NULL;
    char *CAdir		= NULL;
    char *DHparams	= NULL;
    char *model		= NULL;
    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 *CAfile	        = NULL;
    char *CAdir		        = NULL;
    char *DHparams	        = NULL;
    char *model		        = NULL;
#ifndef OPENSSL_NO_TLSEXT
    char *servername	= NULL;	/* hostname for Server Name Indication */
    char *servername	        = NULL;	/* hostname for Server Name Indication */
#endif
    int ssl2 = 0, ssl3 = 0;
    int tls1 = 1, tls1_1 = 1, tls1_2 = 1, tls1_3 = 1;
    int proto = 0;
    int verify = 0, require = 0, request = 1;

    dprintf("Called");
791
792
793
794
795
796
797
798

799
800
801
802

803
804
805
806
807
808
809
810
811
812
813
814
815
816
817


818
819

820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840








841
842
843
844
845
846
847
796
797
798
799
800
801
802

803
804
805
806

807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825

826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841






842
843
844
845
846
847
848
849
850
851
852
853
854
855
856







-
+



-
+















+
+

-
+















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







	char *opt = Tcl_GetStringFromObj(objv[idx], NULL);

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

	OPTSTR( "-cadir", CAdir);
	OPTSTR( "-cafile", CAfile);
	OPTSTR( "-certfile", cert);
	OPTSTR( "-certfile", certfile);
	OPTSTR( "-cipher", ciphers);
	OPTOBJ( "-command", script);
	OPTSTR( "-dhparams", DHparams);
	OPTSTR( "-keyfile", key);
	OPTSTR( "-keyfile", keyfile);
	OPTSTR( "-model", model);
	OPTOBJ( "-password", password);
	OPTBOOL( "-require", require);
	OPTBOOL( "-request", request);
	OPTBOOL( "-server", server);
#ifndef OPENSSL_NO_TLSEXT
        OPTSTR( "-servername", servername);
#endif

	OPTBOOL( "-ssl2", ssl2);
	OPTBOOL( "-ssl3", ssl3);
	OPTBOOL( "-tls1", tls1);
	OPTBOOL( "-tls1.1", tls1_1);
	OPTBOOL( "-tls1.2", tls1_2);
	OPTBOOL( "-tls1.3", tls1_3);
  OPTBYTE("-cert", cert, cert_len);
  OPTBYTE("-key", key, key_len);

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

	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 (verify == 0)	verify = SSL_VERIFY_NONE;

    proto |= (ssl2 ? TLS_PROTO_SSL2 : 0);
    proto |= (ssl3 ? TLS_PROTO_SSL3 : 0);
    proto |= (tls1 ? TLS_PROTO_TLS1 : 0);
    proto |= (tls1_1 ? TLS_PROTO_TLS1_1 : 0);
    proto |= (tls1_2 ? TLS_PROTO_TLS1_2 : 0);
    proto |= (tls1_3 ? TLS_PROTO_TLS1_3 : 0);

    /* reset to NULL if blank string provided */
    if (cert && !*cert)		cert	 = NULL;
    if (key && !*key)		key	 = NULL;
    if (ciphers && !*ciphers)	ciphers	 = NULL;
    if (CAfile && !*CAfile)	CAfile	 = NULL;
    if (CAdir && !*CAdir)	CAdir	 = NULL;
    if (DHparams && !*DHparams)	DHparams = NULL;
    if (cert && !*cert)		        cert	        = NULL;
    if (key && !*key)		        key	        = NULL;
    if (certfile && !*certfile)         certfile	= NULL;
    if (keyfile && !*keyfile)		keyfile	        = NULL;
    if (ciphers && !*ciphers)	        ciphers	        = NULL;
    if (CAfile && !*CAfile)	        CAfile	        = NULL;
    if (CAdir && !*CAdir)	        CAdir	        = NULL;
    if (DHparams && !*DHparams)	        DHparams        = NULL;

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

    statePtr->flags	= flags;
    statePtr->interp	= interp;
883
884
885
886
887
888
889
890
891



892
893
894
895
896
897
898
892
893
894
895
896
897
898


899
900
901
902
903
904
905
906
907
908







-
-
+
+
+







	    Tcl_AppendResult(interp, "bad channel \"",
		    Tcl_GetChannelName(chan), "\": not a TLS channel", NULL);
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}
	ctx = ((State *)Tcl_GetChannelInstanceData(chan))->ctx;
    } else {
	if ((ctx = CTX_Init(statePtr, server, proto, key, cert, CAdir, CAfile, ciphers,
		DHparams)) == (SSL_CTX*)0) {
	if ((ctx = CTX_Init(statePtr, server, proto, keyfile, certfile, key,
    cert, key_len, cert_len, CAdir, CAfile, ciphers,
    DHparams)) == (SSL_CTX*)0) {
	    Tls_Free((char *) statePtr);
	    return TCL_ERROR;
	}
    }

    statePtr->ctx = ctx;

1052
1053
1054
1055
1056
1057
1058
1059


1060
1061
1062
1063
1064






1065
1066
1067
1068
1069
1070
1071
1062
1063
1064
1065
1066
1067
1068

1069
1070
1071
1072
1073


1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086







-
+
+



-
-
+
+
+
+
+
+







 * Side effects:
 *	constructs SSL context (CTX)
 *
 *-------------------------------------------------------------------
 */

static SSL_CTX *
CTX_Init(statePtr, isServer, proto, key, cert, CAdir, CAfile, ciphers, DHparams)
CTX_Init(statePtr, isServer, proto, keyfile, certfile, key, cert,
         key_len, cert_len, CAdir, CAfile, ciphers, DHparams)
    State *statePtr;
    int isServer;
    int proto;
    char *key;
    char *cert;
    char *keyfile;
    char *certfile;
    unsigned char *key;
    unsigned char *cert;
    int key_len;
    int cert_len;
    char *CAdir;
    char *CAfile;
    char *ciphers;
    char *DHparams;
{
    Tcl_Interp *interp = statePtr->interp;
    SSL_CTX *ctx = NULL;
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
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
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
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375







-
+


-
+



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



+

-
+
+
+
+
+
+
+
+

-
-
-
+
+
+
+
+





-
+














-
+
-
-
+
-
-
-

+
+

-
+



-


-
+
+
















+







	}
	SSL_CTX_set_tmp_dh(ctx, dh);
	DH_free(dh);
    }
#endif

    /* set our certificate */
    if (cert != NULL) {
    if (certfile != NULL) {
	Tcl_DStringInit(&ds);

	if (SSL_CTX_use_certificate_file(ctx, F2N( cert, &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 ", cert, ": ",
			     "unable to set certificate file ", certfile, ": ",
			     REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
	}
    } else if (cert != NULL) {
	if (SSL_CTX_use_certificate_ASN1(ctx, cert_len, cert) <= 0) {
	    Tcl_DStringFree(&ds);
	    Tcl_AppendResult(interp,
			     "unable to set certificate: ",
			     REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
	}
    } else {
	certfile = (char*)X509_get_default_cert_file();

	if (SSL_CTX_use_certificate_file(ctx, certfile,
					SSL_FILETYPE_PEM) <= 0) {
#if 0
	    Tcl_DStringFree(&ds);
	    Tcl_AppendResult(interp,
			     "unable to use default certificate file ", certfile, ": ",
			     REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
#endif
	}

    }

    /* set our private key */
    if (keyfile == NULL && key == NULL) {
	keyfile = certfile;
    }

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

	if (SSL_CTX_use_PrivateKey_file(ctx, F2N( key, &ds),
	if (keyfile == NULL) {
	    keyfile = certfile;
	}

	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 ", key, " ",
			     "unable to set public key file ", keyfile, " ",
			     REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
	}
	Tcl_DStringFree(&ds);
	/* Now we know that a key and cert have been set against
	 * the SSL context */
	if (!SSL_CTX_check_private_key(ctx)) {
	    Tcl_AppendResult(interp,
			     "private key does not match the certificate public key",
			     (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
	}
    } else {
    } else if (key != NULL) {
	cert = (char*)X509_get_default_cert_file();

	if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, key,key_len) <= 0) {
	if (SSL_CTX_use_certificate_file(ctx, cert,
					SSL_FILETYPE_PEM) <= 0) {
#if 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 use default certificate file ", cert, ": ",
			     "unable to set public key: ",
			     REASON(), (char *) NULL);
	    SSL_CTX_free(ctx);
	    return (SSL_CTX *)0;
#endif
	}
    }
	

    /* Set verification CAs */
    Tcl_DStringInit(&ds);
    Tcl_DStringInit(&ds1);
    if (!SSL_CTX_load_verify_locations(ctx, F2N(CAfile, &ds), F2N(CAdir, &ds1)) ||
	!SSL_CTX_set_default_verify_paths(ctx)) {
#if 0
	Tcl_DStringFree(&ds);
	Tcl_DStringFree(&ds1);
	/* Don't currently care if this fails */
	Tcl_AppendResult(interp, "SSL default verify paths: ",
		REASON(), (char *) NULL);
	SSL_CTX_free(ctx);
	return (SSL_CTX *)0;
#endif
    }

    /* https://sourceforge.net/p/tls/bugs/57/ */
    /* XXX:TODO: Let the user supply values here instead of something that exists on the filesystem */
    if ( CAfile != NULL ) {
        STACK_OF(X509_NAME) *certNames = SSL_load_client_CA_file( F2N(CAfile, &ds) );
	if ( certNames != NULL ) { 
	    SSL_CTX_set_client_CA_list(ctx, certNames );
	}
    }

Modified tls.htm from [60845f0ae5] to [ef8070e9b1].

163
164
165
166
167
168
169
170



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187


188
189
190
191
192
193
194
163
164
165
166
167
168
169

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198







-
+
+
+

















+
+







<blockquote>
    <dl>
        <dt><strong>-cadir</strong> <em>dir</em></dt>
        <dd>Provide the directory containing the CA certificates.</dd>
        <dt><strong>-cafile </strong><em>filename</em></dt>
        <dd>Provide the CA file.</dd>
        <dt><strong>-certfile</strong> <em>filename</em></dt>
        <dd>Provide the certificate to use.</dd>
        <dd>Provide the name of a file containing certificate to use.</dd>
        <dt><strong>-cert</strong> <em>filename</em></dt>
        <dd>Provide the contents of a certificate to use, as a DER encoded binary value (X.509 DER).</dd>
        <dt><strong>-cipher </strong><em>string</em></dt>
        <dd>Provide the cipher suites to use. Syntax is as per
            OpenSSL.</dd>
        <dt><strong>-command</strong> <em>callback</em></dt>
        <dd>If specified, this callback will be invoked at several points
            during the OpenSSL handshake.  It can pass errors and tracing
            information, and it can allow Tcl scripts to perform
            their own validation of the certificate in place of the
            default validation provided by OpenSSL.
            <br>
            See <a href="#CALLBACK OPTIONS">CALLBACK OPTIONS</a> for
            further discussion.</dd>
        <dt><strong>-dhparams </strong><em>filename</em></dt>
        <dd>Provide a Diffie-Hellman parameters file.</dd>
        <dt><strong>-keyfile</strong> <em>filename</em></dt>
        <dd>Provide the private key file. (<strong>default</strong>:
            value of -certfile)</dd>
        <dt><strong>-key</strong> <em>filename</em></dt>
        <dd>Provide the private key to use as a DER encoded value (PKCS#1 DER)</dd>
        <dt><strong>-model</strong> <em>channel</em></dt>
        <dd>This will force this channel to share the same <em><strong>SSL_CTX</strong></em>
            structure as the specified <em>channel</em>, and
            therefore share callbacks etc.</dd>
        <dt><strong>-password</strong> <em>callback</em></dt>
        <dd>If supplied, this callback will be invoked when OpenSSL needs
            to obtain a password, typically to unlock the private key of

Modified tls.tcl from [75c0c2a68a] to [ae8c7a0664].

30
31
32
33
34
35
36

37
38
39
40

41
42
43
44
45
46
47
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49







+




+







    variable socketOptionRules {
        {0 -async sopts 0}
        {* -myaddr sopts 1}
        {0 -myport sopts 1}
        {* -type sopts 1}
        {* -cadir iopts 1}
        {* -cafile iopts 1}
        {* -cert iopts 1}
        {* -certfile iopts 1}
        {* -cipher iopts 1}
        {* -command iopts 1}
        {* -dhparams iopts 1}
        {* -key iopts 1}
        {* -keyfile iopts 1}
        {* -password iopts 1}
        {* -request iopts 1}
        {* -require iopts 1}
        {* -autoservername discardOpts 1}
        {* -servername iopts 1}
        {* -ssl2 iopts 1}