Index: tclOpts.h ================================================================== --- tclOpts.h +++ tclOpts.h @@ -42,10 +42,15 @@ 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) Index: tls.c ================================================================== --- tls.c +++ tls.c @@ -60,12 +60,13 @@ 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 *cert, char *CAdir, char *CAfile, char *ciphers, - char *DHparams); + char *certfile, unsigned char *key_asn1, unsigned char *cert_asn1, + 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 @@ -727,26 +728,30 @@ 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; @@ -793,15 +798,15 @@ 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); @@ -813,12 +818,14 @@ 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; @@ -830,16 +837,18 @@ 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)); @@ -885,12 +894,13 @@ 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; } } @@ -1054,16 +1064,21 @@ * *------------------------------------------------------------------- */ 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; { @@ -1249,33 +1264,35 @@ 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; } /* get the private key associated with this certificate */ - if (key == NULL) key=cert; + if (keyfile == NULL) { + keyfile = certfile; + } - if (SSL_CTX_use_PrivateKey_file(ctx, F2N( key, &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 ", key, " ", + "unable to set public key file ", keyfile, " ", REASON(), (char *) NULL); SSL_CTX_free(ctx); return (SSL_CTX *)0; } Tcl_DStringFree(&ds); @@ -1286,19 +1303,42 @@ "private key does not match the certificate public key", (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; + } + if (key == NULL) { + key = cert; + key_len = cert_len; + } + if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, key,key_len) <= 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: ", + REASON(), (char *) NULL); + SSL_CTX_free(ctx); + return (SSL_CTX *)0; + } } else { - cert = (char*)X509_get_default_cert_file(); + certfile = (char*)X509_get_default_cert_file(); - if (SSL_CTX_use_certificate_file(ctx, cert, + 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 ", cert, ": ", + "unable to use default certificate file ", certfile, ": ", REASON(), (char *) NULL); SSL_CTX_free(ctx); return (SSL_CTX *)0; #endif } Index: tls.htm ================================================================== --- tls.htm +++ tls.htm @@ -165,11 +165,13 @@
-cadir dir
Provide the directory containing the CA certificates.
-cafile filename
Provide the CA file.
-certfile filename
-
Provide the certificate to use.
+
Provide the name of a file containing certificate to use.
+
-cert filename
+
Provide the contents of a certificate to use, as a DER encoded binary value (X.509 DER).
-cipher string
Provide the cipher suites to use. Syntax is as per OpenSSL.
-command callback
If specified, this callback will be invoked at several points @@ -183,10 +185,12 @@
-dhparams filename
Provide a Diffie-Hellman parameters file.
-keyfile filename
Provide the private key file. (default: value of -certfile)
+
-key filename
+
Provide the private key to use as a DER encoded value (PKCS#1 DER)
-model channel
This will force this channel to share the same SSL_CTX structure as the specified channel, and therefore share callbacks etc.
-password callback
Index: tls.tcl ================================================================== --- tls.tcl +++ tls.tcl @@ -32,14 +32,16 @@ {* -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}