Changes On Branch mjanssen-asn1-certs
Bounty program for improvements to Tcl and certain Tcl packages.

Changes In Branch mjanssen-asn1-certs Excluding Merge-Ins

This is equivalent to a diff from 2c8d3629bc to 51a2b1ec9a

2020-05-04
15:10
Integrated mjanssen's work on loading certificates and keys as values check-in: b08bbeb9a1 user: rkeene tags: trunk
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
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     40   #define OPTBOOL(option, var)			\
    41     41       OPT_PROLOG(option)				\
    42     42       if (Tcl_GetBooleanFromObj(interp, objv[idx],\
    43     43   	    &(var)) != TCL_OK) {		\
    44     44   	    return TCL_ERROR;			\
    45     45       }						\
    46     46       OPT_POSTLOG()
           47  +
           48  +#define OPTBYTE(option, var, lvar)			\
           49  +    OPT_PROLOG(option)				\
           50  +    var = Tcl_GetByteArrayFromObj(objv[idx], &(lvar));\
           51  +    OPT_POSTLOG()
    47     52   
    48     53   #define OPTBAD(type, list)			\
    49     54       Tcl_AppendResult(interp, "bad ", (type),	\
    50     55   		" \"", opt, "\": must be ",	\
    51     56   		(list), (char *) NULL)
    52     57   
    53     58   #endif /* _TCL_OPTS_H */

Modified tls.c from [c565bf20f1] to [93c7ba9ac0].

    58     58   static int	MiscObjCmd(ClientData clientData,
    59     59   			Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
    60     60   
    61     61   static int	UnimportObjCmd(ClientData clientData,
    62     62   			Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]);
    63     63   
    64     64   static SSL_CTX *CTX_Init(State *statePtr, int isServer, int proto, char *key,
    65         -			char *cert, char *CAdir, char *CAfile, char *ciphers,
    66         -			char *DHparams);
           65  +			char *certfile, unsigned char *key_asn1, unsigned char *cert_asn1,
           66  +			int key_asn1_len, int cert_asn1_len, char *CAdir, char *CAfile,
           67  +      char *ciphers, char *DHparams);
    67     68   
    68     69   static int	TlsLibInit(int uninitialize);
    69     70   
    70     71   #define TLS_PROTO_SSL2		0x01
    71     72   #define TLS_PROTO_SSL3		0x02
    72     73   #define TLS_PROTO_TLS1		0x04
    73     74   #define TLS_PROTO_TLS1_1	0x08
................................................................................
   725    726       ClientData clientData;	/* Not used. */
   726    727       Tcl_Interp *interp;
   727    728       int objc;
   728    729       Tcl_Obj *CONST objv[];
   729    730   {
   730    731       Tcl_Channel chan;		/* The channel to set a mode on. */
   731    732       State *statePtr;		/* client state for ssl socket */
   732         -    SSL_CTX *ctx	= NULL;
   733         -    Tcl_Obj *script	= NULL;
   734         -    Tcl_Obj *password	= NULL;
          733  +    SSL_CTX *ctx	        = NULL;
          734  +    Tcl_Obj *script	        = NULL;
          735  +    Tcl_Obj *password	        = NULL;
   735    736       Tcl_DString upperChannelTranslation, upperChannelBlocking, upperChannelEncoding, upperChannelEOFChar;
   736    737       int idx, len;
   737         -    int flags		= TLS_TCL_INIT;
   738         -    int server		= 0;	/* is connection incoming or outgoing? */
   739         -    char *key		= NULL;
   740         -    char *cert		= NULL;
   741         -    char *ciphers	= NULL;
   742         -    char *CAfile	= NULL;
   743         -    char *CAdir		= NULL;
   744         -    char *DHparams	= NULL;
   745         -    char *model		= NULL;
          738  +    int flags		        = TLS_TCL_INIT;
          739  +    int server		        = 0;	/* is connection incoming or outgoing? */
          740  +    char *keyfile	        = NULL;
          741  +    char *certfile	        = NULL;
          742  +    unsigned char *key  	= NULL;
          743  +    int key_len                 = 0;
          744  +    unsigned char *cert         = NULL;
          745  +    int cert_len                = 0;
          746  +    char *ciphers	        = NULL;
          747  +    char *CAfile	        = NULL;
          748  +    char *CAdir		        = NULL;
          749  +    char *DHparams	        = NULL;
          750  +    char *model		        = NULL;
   746    751   #ifndef OPENSSL_NO_TLSEXT
   747         -    char *servername	= NULL;	/* hostname for Server Name Indication */
          752  +    char *servername	        = NULL;	/* hostname for Server Name Indication */
   748    753   #endif
   749    754       int ssl2 = 0, ssl3 = 0;
   750    755       int tls1 = 1, tls1_1 = 1, tls1_2 = 1, tls1_3 = 1;
   751    756       int proto = 0;
   752    757       int verify = 0, require = 0, request = 1;
   753    758   
   754    759       dprintf("Called");
................................................................................
   791    796   	char *opt = Tcl_GetStringFromObj(objv[idx], NULL);
   792    797   
   793    798   	if (opt[0] != '-')
   794    799   	    break;
   795    800   
   796    801   	OPTSTR( "-cadir", CAdir);
   797    802   	OPTSTR( "-cafile", CAfile);
   798         -	OPTSTR( "-certfile", cert);
          803  +	OPTSTR( "-certfile", certfile);
   799    804   	OPTSTR( "-cipher", ciphers);
   800    805   	OPTOBJ( "-command", script);
   801    806   	OPTSTR( "-dhparams", DHparams);
   802         -	OPTSTR( "-keyfile", key);
          807  +	OPTSTR( "-keyfile", keyfile);
   803    808   	OPTSTR( "-model", model);
   804    809   	OPTOBJ( "-password", password);
   805    810   	OPTBOOL( "-require", require);
   806    811   	OPTBOOL( "-request", request);
   807    812   	OPTBOOL( "-server", server);
   808    813   #ifndef OPENSSL_NO_TLSEXT
   809    814           OPTSTR( "-servername", servername);
................................................................................
   811    816   
   812    817   	OPTBOOL( "-ssl2", ssl2);
   813    818   	OPTBOOL( "-ssl3", ssl3);
   814    819   	OPTBOOL( "-tls1", tls1);
   815    820   	OPTBOOL( "-tls1.1", tls1_1);
   816    821   	OPTBOOL( "-tls1.2", tls1_2);
   817    822   	OPTBOOL( "-tls1.3", tls1_3);
          823  +  OPTBYTE("-cert", cert, cert_len);
          824  +  OPTBYTE("-key", key, key_len);
   818    825   
   819         -	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");
          826  +	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");
   820    827   
   821    828   	return TCL_ERROR;
   822    829       }
   823    830       if (request)	    verify |= SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_PEER;
   824    831       if (request && require) verify |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
   825    832       if (verify == 0)	verify = SSL_VERIFY_NONE;
   826    833   
................................................................................
   828    835       proto |= (ssl3 ? TLS_PROTO_SSL3 : 0);
   829    836       proto |= (tls1 ? TLS_PROTO_TLS1 : 0);
   830    837       proto |= (tls1_1 ? TLS_PROTO_TLS1_1 : 0);
   831    838       proto |= (tls1_2 ? TLS_PROTO_TLS1_2 : 0);
   832    839       proto |= (tls1_3 ? TLS_PROTO_TLS1_3 : 0);
   833    840   
   834    841       /* reset to NULL if blank string provided */
   835         -    if (cert && !*cert)		cert	 = NULL;
   836         -    if (key && !*key)		key	 = NULL;
   837         -    if (ciphers && !*ciphers)	ciphers	 = NULL;
   838         -    if (CAfile && !*CAfile)	CAfile	 = NULL;
   839         -    if (CAdir && !*CAdir)	CAdir	 = NULL;
   840         -    if (DHparams && !*DHparams)	DHparams = NULL;
          842  +    if (cert && !*cert)		        cert	        = NULL;
          843  +    if (key && !*key)		        key	        = NULL;
          844  +    if (certfile && !*certfile)         certfile	= NULL;
          845  +    if (keyfile && !*keyfile)		keyfile	        = NULL;
          846  +    if (ciphers && !*ciphers)	        ciphers	        = NULL;
          847  +    if (CAfile && !*CAfile)	        CAfile	        = NULL;
          848  +    if (CAdir && !*CAdir)	        CAdir	        = NULL;
          849  +    if (DHparams && !*DHparams)	        DHparams        = NULL;
   841    850   
   842    851       /* new SSL state */
   843    852       statePtr		= (State *) ckalloc((unsigned) sizeof(State));
   844    853       memset(statePtr, 0, sizeof(State));
   845    854   
   846    855       statePtr->flags	= flags;
   847    856       statePtr->interp	= interp;
................................................................................
   883    892   	    Tcl_AppendResult(interp, "bad channel \"",
   884    893   		    Tcl_GetChannelName(chan), "\": not a TLS channel", NULL);
   885    894   	    Tls_Free((char *) statePtr);
   886    895   	    return TCL_ERROR;
   887    896   	}
   888    897   	ctx = ((State *)Tcl_GetChannelInstanceData(chan))->ctx;
   889    898       } else {
   890         -	if ((ctx = CTX_Init(statePtr, server, proto, key, cert, CAdir, CAfile, ciphers,
   891         -		DHparams)) == (SSL_CTX*)0) {
          899  +	if ((ctx = CTX_Init(statePtr, server, proto, keyfile, certfile, key,
          900  +    cert, key_len, cert_len, CAdir, CAfile, ciphers,
          901  +    DHparams)) == (SSL_CTX*)0) {
   892    902   	    Tls_Free((char *) statePtr);
   893    903   	    return TCL_ERROR;
   894    904   	}
   895    905       }
   896    906   
   897    907       statePtr->ctx = ctx;
   898    908   
................................................................................
  1052   1062    * Side effects:
  1053   1063    *	constructs SSL context (CTX)
  1054   1064    *
  1055   1065    *-------------------------------------------------------------------
  1056   1066    */
  1057   1067   
  1058   1068   static SSL_CTX *
  1059         -CTX_Init(statePtr, isServer, proto, key, cert, CAdir, CAfile, ciphers, DHparams)
         1069  +CTX_Init(statePtr, isServer, proto, keyfile, certfile, key, cert,
         1070  +         key_len, cert_len, CAdir, CAfile, ciphers, DHparams)
  1060   1071       State *statePtr;
  1061   1072       int isServer;
  1062   1073       int proto;
  1063         -    char *key;
  1064         -    char *cert;
         1074  +    char *keyfile;
         1075  +    char *certfile;
         1076  +    unsigned char *key;
         1077  +    unsigned char *cert;
         1078  +    int key_len;
         1079  +    int cert_len;
  1065   1080       char *CAdir;
  1066   1081       char *CAfile;
  1067   1082       char *ciphers;
  1068   1083       char *DHparams;
  1069   1084   {
  1070   1085       Tcl_Interp *interp = statePtr->interp;
  1071   1086       SSL_CTX *ctx = NULL;
  1072   1087       Tcl_DString ds;
  1073   1088       Tcl_DString ds1;
  1074   1089       int off = 0;
         1090  +    int load_private_key;
  1075   1091       const SSL_METHOD *method;
  1076   1092   
  1077   1093       dprintf("Called");
  1078   1094   
  1079   1095       if (!proto) {
  1080   1096   	Tcl_AppendResult(interp, "no valid protocol selected", NULL);
  1081   1097   	return (SSL_CTX *)0;
................................................................................
  1247   1263   	}
  1248   1264   	SSL_CTX_set_tmp_dh(ctx, dh);
  1249   1265   	DH_free(dh);
  1250   1266       }
  1251   1267   #endif
  1252   1268   
  1253   1269       /* set our certificate */
  1254         -    if (cert != NULL) {
         1270  +    load_private_key = 0;
         1271  +    if (certfile != NULL) {
         1272  +	load_private_key = 1;
         1273  +
  1255   1274   	Tcl_DStringInit(&ds);
  1256   1275   
  1257         -	if (SSL_CTX_use_certificate_file(ctx, F2N( cert, &ds),
         1276  +	if (SSL_CTX_use_certificate_file(ctx, F2N( certfile, &ds),
  1258   1277   					SSL_FILETYPE_PEM) <= 0) {
  1259   1278   	    Tcl_DStringFree(&ds);
  1260   1279   	    Tcl_AppendResult(interp,
  1261         -			     "unable to set certificate file ", cert, ": ",
         1280  +			     "unable to set certificate file ", certfile, ": ",
         1281  +			     REASON(), (char *) NULL);
         1282  +	    SSL_CTX_free(ctx);
         1283  +	    return (SSL_CTX *)0;
         1284  +	}
         1285  +    } else if (cert != NULL) {
         1286  +	load_private_key = 1;
         1287  +	if (SSL_CTX_use_certificate_ASN1(ctx, cert_len, cert) <= 0) {
         1288  +	    Tcl_DStringFree(&ds);
         1289  +	    Tcl_AppendResult(interp,
         1290  +			     "unable to set certificate: ",
  1262   1291   			     REASON(), (char *) NULL);
  1263   1292   	    SSL_CTX_free(ctx);
  1264   1293   	    return (SSL_CTX *)0;
  1265   1294   	}
         1295  +    } else {
         1296  +	certfile = (char*)X509_get_default_cert_file();
  1266   1297   
  1267         -	/* get the private key associated with this certificate */
  1268         -	if (key == NULL) key=cert;
  1269         -
  1270         -	if (SSL_CTX_use_PrivateKey_file(ctx, F2N( key, &ds),
         1298  +	if (SSL_CTX_use_certificate_file(ctx, certfile,
  1271   1299   					SSL_FILETYPE_PEM) <= 0) {
         1300  +#if 0
  1272   1301   	    Tcl_DStringFree(&ds);
  1273         -	    /* flush the passphrase which might be left in the result */
  1274         -	    Tcl_SetResult(interp, NULL, TCL_STATIC);
  1275   1302   	    Tcl_AppendResult(interp,
  1276         -			     "unable to set public key file ", key, " ",
         1303  +			     "unable to use default certificate file ", certfile, ": ",
  1277   1304   			     REASON(), (char *) NULL);
  1278   1305   	    SSL_CTX_free(ctx);
  1279   1306   	    return (SSL_CTX *)0;
         1307  +#endif
         1308  +	}
         1309  +    }
         1310  +
         1311  +    /* set our private key */
         1312  +    if (load_private_key) {
         1313  +	if (keyfile == NULL && key == NULL) {
         1314  +	    keyfile = certfile;
  1280   1315   	}
  1281         -	Tcl_DStringFree(&ds);
         1316  +
         1317  +	if (keyfile != NULL) {
         1318  +	    /* get the private key associated with this certificate */
         1319  +	    if (keyfile == NULL) {
         1320  +		keyfile = certfile;
         1321  +	    }
         1322  +
         1323  +	    if (SSL_CTX_use_PrivateKey_file(ctx, F2N( keyfile, &ds), SSL_FILETYPE_PEM) <= 0) {
         1324  +		Tcl_DStringFree(&ds);
         1325  +		/* flush the passphrase which might be left in the result */
         1326  +		Tcl_SetResult(interp, NULL, TCL_STATIC);
         1327  +		Tcl_AppendResult(interp,
         1328  +			         "unable to set public key file ", keyfile, " ",
         1329  +			         REASON(), (char *) NULL);
         1330  +		SSL_CTX_free(ctx);
         1331  +		return (SSL_CTX *)0;
         1332  +	    }
         1333  +
         1334  +	    Tcl_DStringFree(&ds);
         1335  +	} else if (key != NULL) {
         1336  +	    if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, key,key_len) <= 0) {
         1337  +		Tcl_DStringFree(&ds);
         1338  +		/* flush the passphrase which might be left in the result */
         1339  +		Tcl_SetResult(interp, NULL, TCL_STATIC);
         1340  +		Tcl_AppendResult(interp,
         1341  +		                 "unable to set public key: ",
         1342  +		                 REASON(), (char *) NULL);
         1343  +		SSL_CTX_free(ctx);
         1344  +		return (SSL_CTX *)0;
         1345  +	    }
         1346  +	}
  1282   1347   	/* Now we know that a key and cert have been set against
  1283   1348   	 * the SSL context */
  1284   1349   	if (!SSL_CTX_check_private_key(ctx)) {
  1285   1350   	    Tcl_AppendResult(interp,
  1286   1351   			     "private key does not match the certificate public key",
  1287   1352   			     (char *) NULL);
  1288   1353   	    SSL_CTX_free(ctx);
  1289   1354   	    return (SSL_CTX *)0;
  1290   1355   	}
  1291         -    } else {
  1292         -	cert = (char*)X509_get_default_cert_file();
         1356  +    }
  1293   1357   
  1294         -	if (SSL_CTX_use_certificate_file(ctx, cert,
  1295         -					SSL_FILETYPE_PEM) <= 0) {
  1296         -#if 0
  1297         -	    Tcl_DStringFree(&ds);
  1298         -	    Tcl_AppendResult(interp,
  1299         -			     "unable to use default certificate file ", cert, ": ",
  1300         -			     REASON(), (char *) NULL);
  1301         -	    SSL_CTX_free(ctx);
  1302         -	    return (SSL_CTX *)0;
  1303         -#endif
  1304         -	}
  1305         -    }
  1306         -	
         1358  +    /* Set verification CAs */
  1307   1359       Tcl_DStringInit(&ds);
  1308   1360       Tcl_DStringInit(&ds1);
  1309   1361       if (!SSL_CTX_load_verify_locations(ctx, F2N(CAfile, &ds), F2N(CAdir, &ds1)) ||
  1310   1362   	!SSL_CTX_set_default_verify_paths(ctx)) {
  1311   1363   #if 0
  1312   1364   	Tcl_DStringFree(&ds);
  1313   1365   	Tcl_DStringFree(&ds1);
................................................................................
  1316   1368   		REASON(), (char *) NULL);
  1317   1369   	SSL_CTX_free(ctx);
  1318   1370   	return (SSL_CTX *)0;
  1319   1371   #endif
  1320   1372       }
  1321   1373   
  1322   1374       /* https://sourceforge.net/p/tls/bugs/57/ */
         1375  +    /* XXX:TODO: Let the user supply values here instead of something that exists on the filesystem */
  1323   1376       if ( CAfile != NULL ) {
  1324   1377           STACK_OF(X509_NAME) *certNames = SSL_load_client_CA_file( F2N(CAfile, &ds) );
  1325   1378   	if ( certNames != NULL ) { 
  1326   1379   	    SSL_CTX_set_client_CA_list(ctx, certNames );
  1327   1380   	}
  1328   1381       }
  1329   1382   

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

   163    163   <blockquote>
   164    164       <dl>
   165    165           <dt><strong>-cadir</strong> <em>dir</em></dt>
   166    166           <dd>Provide the directory containing the CA certificates.</dd>
   167    167           <dt><strong>-cafile </strong><em>filename</em></dt>
   168    168           <dd>Provide the CA file.</dd>
   169    169           <dt><strong>-certfile</strong> <em>filename</em></dt>
   170         -        <dd>Provide the certificate to use.</dd>
          170  +        <dd>Provide the name of a file containing certificate to use.</dd>
          171  +        <dt><strong>-cert</strong> <em>filename</em></dt>
          172  +        <dd>Provide the contents of a certificate to use, as a DER encoded binary value (X.509 DER).</dd>
   171    173           <dt><strong>-cipher </strong><em>string</em></dt>
   172    174           <dd>Provide the cipher suites to use. Syntax is as per
   173    175               OpenSSL.</dd>
   174    176           <dt><strong>-command</strong> <em>callback</em></dt>
   175    177           <dd>If specified, this callback will be invoked at several points
   176    178               during the OpenSSL handshake.  It can pass errors and tracing
   177    179               information, and it can allow Tcl scripts to perform
................................................................................
   181    183               See <a href="#CALLBACK OPTIONS">CALLBACK OPTIONS</a> for
   182    184               further discussion.</dd>
   183    185           <dt><strong>-dhparams </strong><em>filename</em></dt>
   184    186           <dd>Provide a Diffie-Hellman parameters file.</dd>
   185    187           <dt><strong>-keyfile</strong> <em>filename</em></dt>
   186    188           <dd>Provide the private key file. (<strong>default</strong>:
   187    189               value of -certfile)</dd>
          190  +        <dt><strong>-key</strong> <em>filename</em></dt>
          191  +        <dd>Provide the private key to use as a DER encoded value (PKCS#1 DER)</dd>
   188    192           <dt><strong>-model</strong> <em>channel</em></dt>
   189    193           <dd>This will force this channel to share the same <em><strong>SSL_CTX</strong></em>
   190    194               structure as the specified <em>channel</em>, and
   191    195               therefore share callbacks etc.</dd>
   192    196           <dt><strong>-password</strong> <em>callback</em></dt>
   193    197           <dd>If supplied, this callback will be invoked when OpenSSL needs
   194    198               to obtain a password, typically to unlock the private key of

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

    30     30       variable socketOptionRules {
    31     31           {0 -async sopts 0}
    32     32           {* -myaddr sopts 1}
    33     33           {0 -myport sopts 1}
    34     34           {* -type sopts 1}
    35     35           {* -cadir iopts 1}
    36     36           {* -cafile iopts 1}
           37  +        {* -cert iopts 1}
    37     38           {* -certfile iopts 1}
    38     39           {* -cipher iopts 1}
    39     40           {* -command iopts 1}
    40     41           {* -dhparams iopts 1}
           42  +        {* -key iopts 1}
    41     43           {* -keyfile iopts 1}
    42     44           {* -password iopts 1}
    43     45           {* -request iopts 1}
    44     46           {* -require iopts 1}
    45     47           {* -autoservername discardOpts 1}
    46     48           {* -servername iopts 1}
    47     49           {* -ssl2 iopts 1}