Index: tls.c ================================================================== --- tls.c +++ tls.c @@ -21,11 +21,13 @@ * */ #include "tlsInt.h" #include "tclOpts.h" +#include #include +#include /* * External functions */ @@ -37,13 +39,13 @@ (((key) == NULL) ? (char *) NULL : \ Tcl_TranslateFileName(interp, (key), (dsp))) #define REASON() ERR_reason_error_string(ERR_get_error()) static SSL_CTX *CTX_Init(State *statePtr, int isServer, int proto, char *key, - 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); + 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 @@ -90,19 +92,23 @@ #define OPENSSL_THREAD_DEFINES #include #ifdef OPENSSL_THREADS #include +/* Added */ +#include /* * Threaded operation requires locking callbacks * Based from /crypto/cryptlib.c of OpenSSL and NSOpenSSL. */ static Tcl_Mutex *locks = NULL; static int locksCount = 0; static Tcl_Mutex init_mx; + +# if OPENSSL_VERSION_NUMBER < 0x10100000L void CryptoThreadLockCallback(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) { /* This debugging is turned off by default -- it's too noisy. */ @@ -129,10 +135,11 @@ dprintf("Returning %lu", ret); return(ret); } +#endif #endif /* OPENSSL_THREADS */ #endif /* TCL_THREADS */ /* @@ -428,11 +435,11 @@ * variable to access the Tcl interpreter. */ static int PasswordCallback(char *buf, int size, int verify) { return -1; - buf = buf; + buf = buf; size = size; verify = verify; } #else static int @@ -474,15 +481,15 @@ Tcl_Release((ClientData) statePtr); if (code == TCL_OK) { char *ret = (char *) Tcl_GetStringResult(interp); if (strlen(ret) < size - 1) { - strncpy(buf, ret, (size_t) size); + strncpy(buf, ret, (size_t) size); Tcl_Release((ClientData) interp); - return (int)strlen(ret); + return (int)strlen(ret); } - } + } Tcl_Release((ClientData) interp); return -1; } #endif @@ -517,66 +524,66 @@ char *cp, buf[BUFSIZ]; int index, verbose = 0; dprintf("Called"); - if (objc < 2 || objc > 3) { + if ((objc < 2) || (objc > 3)) { Tcl_WrongNumArgs(interp, 1, objv, "protocol ?verbose?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj( interp, objv[1], protocols, "protocol", 0, &index) != TCL_OK) { return TCL_ERROR; } - if (objc > 2 && Tcl_GetBooleanFromObj( interp, objv[2], + if ((objc > 2) && Tcl_GetBooleanFromObj( interp, objv[2], &verbose) != TCL_OK) { return TCL_ERROR; } switch ((enum protocol)index) { case TLS_SSL2: -#if defined(NO_SSL2) +#if OPENSSL_VERSION_NUMBER >= 0x10101000L || defined(NO_SSL2) || defined(OPENSSL_NO_SSL2) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(SSLv2_method()); break; #endif case TLS_SSL3: -#if defined(NO_SSL3) +#if defined(NO_SSL3) || defined(OPENSSL_NO_SSL3) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(SSLv3_method()); break; #endif case TLS_TLS1: -#if defined(NO_TLS1) +#if defined(NO_TLS1) || defined(OPENSSL_NO_TLS1) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(TLSv1_method()); break; #endif case TLS_TLS1_1: -#if defined(NO_TLS1_1) +#if defined(NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(TLSv1_1_method()); break; #endif case TLS_TLS1_2: -#if defined(NO_TLS1_2) +#if defined(NO_TLS1_2) || defined(OPENSSL_NO_TLS1_2) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(TLSv1_2_method()); break; #endif case TLS_TLS1_3: -#if defined(NO_TLS1_3) +#if defined(NO_TLS1_3) || defined(OPENSSL_NO_TLS1_3) Tcl_AppendResult(interp, protocols[index], ": protocol not supported", NULL); return TCL_ERROR; #else ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_min_proto_version (ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version (ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version (ctx, TLS1_3_VERSION); break; #endif default: break; } @@ -605,12 +612,12 @@ for (index = 0; index < sk_SSL_CIPHER_num(sk); index++) { register size_t i; SSL_CIPHER_description( sk_SSL_CIPHER_value( sk, index), buf, sizeof(buf)); for (i = strlen(buf) - 1; i ; i--) { - if (buf[i] == ' ' || buf[i] == '\n' || - buf[i] == '\r' || buf[i] == '\t') { + if ((buf[i] == ' ') || (buf[i] == '\n') || + (buf[i] == '\r') || (buf[i] == '\t')) { buf[i] = '\0'; } else { break; } } @@ -621,11 +628,11 @@ SSL_free(ssl); SSL_CTX_free(ctx); Tcl_SetObjResult( interp, objPtr); return TCL_OK; - clientData = clientData; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -682,11 +689,11 @@ } else if (ret < 0) { errStr = statePtr->err; Tcl_ResetResult(interp); Tcl_SetErrno(err); - if (!errStr || *errStr == 0) { + if (!errStr || (*errStr == 0)) { errStr = Tcl_PosixError(interp); } Tcl_AppendResult(interp, "handshake failed: ", errStr, (char *) NULL); dprintf("Returning TCL_ERROR with handshake failed: %s", errStr); @@ -701,11 +708,11 @@ dprintf("Returning TCL_OK with data \"%i\"", ret); Tcl_SetObjResult(interp, Tcl_NewIntObj(ret)); return(TCL_OK); - clientData = clientData; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -755,26 +762,26 @@ int proto = 0; int verify = 0, require = 0, request = 1; dprintf("Called"); -#if defined(NO_TLS1) && defined(NO_TLS1_1) && defined(NO_TLS1_2) && defined(NO_SSL3) && !defined(NO_SSL2) +#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_NO_SSL2) && defined(NO_TLS1) && defined(NO_TLS1_1) && defined(NO_TLS1_2) && defined(NO_TLS1_3) && defined(NO_SSL3) && !defined(NO_SSL2) ssl2 = 1; #endif -#if defined(NO_TLS1) && defined(NO_TLS1_1) && defined(NO_TLS1_2) && defined(NO_SSL2) && !defined(NO_SSL3) +#if !defined(OPENSSL_NO_SSL3) && defined(NO_TLS1) && defined(NO_TLS1_1) && defined(NO_TLS1_2) && defined(NO_TLS1_3) && defined(NO_SSL2) && !defined(NO_SSL3) ssl3 = 1; #endif -#if defined(NO_TLS1) +#if defined(NO_TLS1) || defined(OPENSSL_NO_TLS1) tls1 = 0; #endif -#if defined(NO_TLS1_1) +#if defined(NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1) tls1_1 = 0; #endif -#if defined(NO_TLS1_2) +#if defined(NO_TLS1_2) || defined(OPENSSL_NO_TLS1_2) tls1_2 = 0; #endif -#if defined(NO_TLS1_3) +#if defined(NO_TLS1_3) || defined(OPENSSL_NO_TLS1_3) tls1_3 = 0; #endif if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "channel ?options?"); @@ -808,11 +815,11 @@ OPTOBJ( "-password", password); OPTBOOL( "-require", require); OPTBOOL( "-request", request); OPTBOOL( "-server", server); #ifndef OPENSSL_NO_TLSEXT - OPTSTR( "-servername", servername); + OPTSTR( "-servername", servername); OPTOBJ( "-alpn", alpn); #endif OPTBOOL( "-ssl2", ssl2); OPTBOOL( "-ssl3", ssl3); @@ -821,11 +828,11 @@ OPTBOOL( "-tls1.2", tls1_2); OPTBOOL( "-tls1.3", tls1_3); OPTBYTE("-cert", cert, cert_len); OPTBYTE("-key", key, key_len); - OPTBAD( "option", "-alpn, -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"); + OPTBAD( "option", "-alpn, -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; @@ -882,14 +889,14 @@ if (chan == (Tcl_Channel) NULL) { Tls_Free((char *) statePtr); return TCL_ERROR; } - /* - * Make sure to operate on the topmost channel - */ - chan = Tcl_GetTopChannel(chan); + /* + * 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); Tls_Free((char *) statePtr); return TCL_ERROR; @@ -950,16 +957,16 @@ return TCL_ERROR; } #ifndef OPENSSL_NO_TLSEXT if (servername) { - if (!SSL_set_tlsext_host_name(statePtr->ssl, servername) && require) { - Tcl_AppendResult(interp, "setting TLS host name extension failed", - (char *) NULL); - Tls_Free((char *) statePtr); - return TCL_ERROR; - } + if (!SSL_set_tlsext_host_name(statePtr->ssl, servername) && require) { + Tcl_AppendResult(interp, "setting TLS host name extension failed", + (char *) NULL); + Tls_Free((char *) statePtr); + return TCL_ERROR; + } } if (alpn) { /* Convert a Tcl list into a protocol-list in wire-format */ unsigned char *protos, *p; unsigned int protoslen = 0; @@ -1030,11 +1037,11 @@ */ dprintf("Returning %s", Tcl_GetChannelName(statePtr->self)); Tcl_SetResult(interp, (char *) Tcl_GetChannelName(statePtr->self), TCL_VOLATILE); return TCL_OK; - clientData = clientData; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1081,11 +1088,11 @@ if (Tcl_UnstackChannel(interp, chan) == TCL_ERROR) { return TCL_ERROR; } return TCL_OK; - clientData = clientData; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1118,130 +1125,134 @@ Tcl_AppendResult(interp, "no valid protocol selected", NULL); return (SSL_CTX *)0; } /* create SSL context */ -#if defined(NO_SSL2) +#if OPENSSL_VERSION_NUMBER >= 0x10101000L || defined(NO_SSL2) || defined(OPENSSL_NO_SSL2) if (ENABLED(proto, TLS_PROTO_SSL2)) { Tcl_AppendResult(interp, "SSL2 protocol not supported", NULL); return (SSL_CTX *)0; } #endif -#if defined(NO_SSL3) +#if defined(NO_SSL3) || defined(OPENSSL_NO_SSL3) if (ENABLED(proto, TLS_PROTO_SSL3)) { Tcl_AppendResult(interp, "SSL3 protocol not supported", NULL); return (SSL_CTX *)0; } #endif -#if defined(NO_TLS1) +#if defined(NO_TLS1) || defined(OPENSSL_NO_TLS1) if (ENABLED(proto, TLS_PROTO_TLS1)) { Tcl_AppendResult(interp, "TLS 1.0 protocol not supported", NULL); return (SSL_CTX *)0; } #endif -#if defined(NO_TLS1_1) +#if defined(NO_TLS1_1) || defined(OPENSSL_NO_TLS1_1) if (ENABLED(proto, TLS_PROTO_TLS1_1)) { Tcl_AppendResult(interp, "TLS 1.1 protocol not supported", NULL); return (SSL_CTX *)0; } #endif -#if defined(NO_TLS1_2) +#if defined(NO_TLS1_2) || defined(OPENSSL_NO_TLS1_2) if (ENABLED(proto, TLS_PROTO_TLS1_2)) { Tcl_AppendResult(interp, "TLS 1.2 protocol not supported", NULL); return (SSL_CTX *)0; } #endif -#if defined(NO_TLS1_3) +#if defined(NO_TLS1_3) || defined(OPENSSL_NO_TLS1_3) if (ENABLED(proto, TLS_PROTO_TLS1_3)) { Tcl_AppendResult(interp, "TLS 1.3 protocol not supported", NULL); return (SSL_CTX *)0; } #endif switch (proto) { -#if !defined(NO_SSL2) +#if OPENSSL_VERSION_NUMBER < 0x10101000L && !defined(NO_SSL2) && !defined(OPENSSL_NO_SSL2) case TLS_PROTO_SSL2: method = SSLv2_method(); break; #endif -#if !defined(NO_SSL3) +#if !defined(NO_SSL3) && !defined(OPENSSL_NO_SSL3) case TLS_PROTO_SSL3: method = SSLv3_method(); break; #endif -#if !defined(NO_TLS1) +#if !defined(NO_TLS1) && !defined(OPENSSL_NO_TLS1) case TLS_PROTO_TLS1: method = TLSv1_method(); break; #endif -#if !defined(NO_TLS1_1) +#if !defined(NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1) case TLS_PROTO_TLS1_1: method = TLSv1_1_method(); break; #endif -#if !defined(NO_TLS1_2) +#if !defined(NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2) case TLS_PROTO_TLS1_2: method = TLSv1_2_method(); break; #endif -#if !defined(NO_TLS1_3) +#if !defined(NO_TLS1_3) && !defined(OPENSSL_NO_TLS1_3) case TLS_PROTO_TLS1_3: - /* - * The version range is constrained below, - * after the context is created. Use the - * generic method here. - */ + /* + * The version range is constrained below, + * after the context is created. Use the + * generic method here. + */ method = TLS_method(); break; #endif default: -#ifdef HAVE_TLS_METHOD - method = TLS_method(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + /* Negotiate highest available SSL/TLS version */ + method = TLS_method(); #else - method = SSLv23_method(); + method = SSLv23_method(); #endif -#if !defined(NO_SSL2) +#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(NO_SSL2) && !defined(OPENSSL_NO_SSL2) off |= (ENABLED(proto, TLS_PROTO_SSL2) ? 0 : SSL_OP_NO_SSLv2); #endif -#if !defined(NO_SSL3) +#if !defined(NO_SSL3) && !defined(OPENSSL_NO_SSL3) off |= (ENABLED(proto, TLS_PROTO_SSL3) ? 0 : SSL_OP_NO_SSLv3); #endif -#if !defined(NO_TLS1) +#if !defined(NO_TLS1) && !defined(OPENSSL_NO_TLS1) off |= (ENABLED(proto, TLS_PROTO_TLS1) ? 0 : SSL_OP_NO_TLSv1); #endif -#if !defined(NO_TLS1_1) +#if !defined(NO_TLS1_1) && !defined(OPENSSL_NO_TLS1_1) off |= (ENABLED(proto, TLS_PROTO_TLS1_1) ? 0 : SSL_OP_NO_TLSv1_1); #endif -#if !defined(NO_TLS1_2) +#if !defined(NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_2) off |= (ENABLED(proto, TLS_PROTO_TLS1_2) ? 0 : SSL_OP_NO_TLSv1_2); #endif -#if !defined(NO_TLS1_3) +#if !defined(NO_TLS1_3) && !defined(OPENSSL_NO_TLS1_3) off |= (ENABLED(proto, TLS_PROTO_TLS1_3) ? 0 : SSL_OP_NO_TLSv1_3); #endif break; } 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) +#if !defined(NO_TLS1_3) && !defined(OPENSSL_NO_TLS1_3) if (proto == TLS_PROTO_TLS1_3) { - SSL_CTX_set_min_proto_version (ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version (ctx, TLS1_3_VERSION); + SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION); } #endif SSL_CTX_set_app_data( ctx, (void*)interp); /* remember the interpreter */ SSL_CTX_set_options( ctx, SSL_OP_ALL); /* all SSL bug workarounds */ SSL_CTX_set_options( ctx, off); /* all SSL bug workarounds */ +#if OPENSSL_VERSION_NUMBER < 0x10101000L + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); /* handle new handshakes in background */ +#endif SSL_CTX_sess_set_cache_size( ctx, 128); if (ciphers != NULL) SSL_CTX_set_cipher_list(ctx, ciphers); @@ -1398,11 +1409,11 @@ } /* 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) ); + STACK_OF(X509_NAME) *certNames = SSL_load_client_CA_file( F2N(CAfile, &ds) ); if ( certNames != NULL ) { SSL_CTX_set_client_CA_list(ctx, certNames ); } } @@ -1488,11 +1499,11 @@ Tcl_NewStringObj ("sbits", -1)); Tcl_ListObjAppendElement (interp, objPtr, Tcl_NewIntObj (SSL_get_cipher_bits (statePtr->ssl, NULL))); ciphers = (char*)SSL_get_cipher(statePtr->ssl); - if (ciphers != NULL && strcmp(ciphers, "(NONE)")!=0) { + if ((ciphers != NULL) && (strcmp(ciphers, "(NONE)") != 0)) { Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj("cipher", -1)); Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_cipher(statePtr->ssl), -1)); } @@ -1510,11 +1521,11 @@ Tcl_ListObjAppendElement(interp, objPtr, Tcl_NewStringObj(SSL_get_version(statePtr->ssl), -1)); Tcl_SetObjResult( interp, objPtr); return TCL_OK; - clientData = clientData; + clientData = clientData; } /* *------------------------------------------------------------------- * @@ -1536,13 +1547,13 @@ objPtr = Tcl_NewStringObj(OPENSSL_VERSION_TEXT, -1); Tcl_SetObjResult(interp, objPtr); return TCL_OK; - clientData = clientData; - objc = objc; - objv = objv; + clientData = clientData; + objc = objc; + objv = objv; } /* *------------------------------------------------------------------- * @@ -1586,10 +1597,19 @@ BIO *out=NULL; char *k_C="",*k_ST="",*k_L="",*k_O="",*k_OU="",*k_CN="",*k_Email=""; char *keyout,*pemout,*str; int keysize,serial=0,days=365; + +#if OPENSSL_VERSION_NUMBER <= 0x10100000L + RSA *rsa = NULL; +#elif OPENSSL_VERSION_NUMBER < 0x30000000L + BIGNUM *bne = NULL; + RSA *rsa = NULL; +#else + EVP_PKEY_CTX *ctx = NULL; +#endif if ((objc<5) || (objc>6)) { Tcl_WrongNumArgs(interp, 2, objv, "keysize keyfile certfile ?info?"); return TCL_ERROR; } @@ -1640,18 +1660,37 @@ Tcl_SetResult(interp,"Unknown parameter",NULL); return TCL_ERROR; } } } - if ((pkey = EVP_PKEY_new()) != NULL) { - if (!EVP_PKEY_assign_RSA(pkey, - RSA_generate_key(keysize, 0x10001, NULL, NULL))) { - Tcl_SetResult(interp,"Error generating private key",NULL); - EVP_PKEY_free(pkey); - return TCL_ERROR; - } - + +#if OPENSSL_VERSION_NUMBER <= 0x10100000L + pkey = EVP_PKEY_new(); + rsa = RSA_generate_key(keysize, 0x10001, NULL, NULL); + if (pkey == NULL || rsa == NULL || !EVP_PKEY_assign_RSA(pkey, rsa)) { + EVP_PKEY_free(pkey); + /* RSA_free(rsa); freed by EVP_PKEY_free */ +#elif OPENSSL_VERSION_NUMBER < 0x30000000L + bne = BN_new(); + rsa = RSA_new(); + pkey = EVP_PKEY_new(); + if (bne == NULL || rsa == NULL || pkey == NULL || !BN_set_word(bne,RSA_F4) || + !RSA_generate_key_ex(rsa, keysize, bne, NULL) || !EVP_PKEY_assign_RSA(pkey, rsa)) { + EVP_PKEY_free(pkey); + /* RSA_free(rsa); freed by EVP_PKEY_free */ + BN_free(bne); +#else + pkey = EVP_RSA_gen((unsigned int) keysize); + ctx = EVP_PKEY_CTX_new(pkey,NULL); + if (pkey == NULL || ctx == NULL || !EVP_PKEY_keygen_init(ctx) || + !EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keysize) || !EVP_PKEY_keygen(ctx, &pkey)) { + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); +#endif + Tcl_SetResult(interp,"Error generating private key",NULL); + return TCL_ERROR; + } else { if (isStr) { out=BIO_new(BIO_s_mem()); PEM_write_bio_PrivateKey(out,pkey,NULL,NULL,0,NULL,NULL); i=BIO_read(out,buffer,sizeof(buffer)-1); i=(i<0) ? 0 : i; @@ -1661,23 +1700,32 @@ BIO_free(out); } else { out=BIO_new(BIO_s_file()); BIO_write_filename(out,keyout); PEM_write_bio_PrivateKey(out,pkey,NULL,NULL,0,NULL,NULL); + /* PEM_write_bio_RSAPrivateKey(out, rsa, NULL, NULL, 0, NULL, NULL); */ BIO_free_all(out); - } + } if ((cert=X509_new())==NULL) { Tcl_SetResult(interp,"Error generating certificate request",NULL); EVP_PKEY_free(pkey); +#if OPENSSL_VERSION_NUMBER > 0x10100000L && OPENSSL_VERSION_NUMBER < 0x30000000L + BN_free(bne); +#endif return(TCL_ERROR); } X509_set_version(cert,2); ASN1_INTEGER_set(X509_get_serialNumber(cert),serial); +#if OPENSSL_VERSION_NUMBER < 0x10100000L X509_gmtime_adj(X509_get_notBefore(cert),0); X509_gmtime_adj(X509_get_notAfter(cert),(long)60*60*24*days); +#else + X509_gmtime_adj(X509_getm_notBefore(cert),0); + X509_gmtime_adj(X509_getm_notAfter(cert),(long)60*60*24*days); +#endif X509_set_pubkey(cert,pkey); name=X509_get_subject_name(cert); X509_NAME_add_entry_by_txt(name,"C", MBSTRING_ASC, (const unsigned char *) k_C, -1, -1, 0); @@ -1688,13 +1736,16 @@ X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (const unsigned char *) k_CN, -1, -1, 0); X509_NAME_add_entry_by_txt(name,"Email", MBSTRING_ASC, (const unsigned char *) k_Email, -1, -1, 0); X509_set_subject_name(cert,name); - if (!X509_sign(cert,pkey,EVP_sha1())) { + if (!X509_sign(cert,pkey,EVP_sha256())) { X509_free(cert); EVP_PKEY_free(pkey); +#if OPENSSL_VERSION_NUMBER > 0x10100000L && OPENSSL_VERSION_NUMBER < 0x30000000L + BN_free(bne); +#endif Tcl_SetResult(interp,"Error signing certificate",NULL); return TCL_ERROR; } if (isStr) { @@ -1713,13 +1764,13 @@ BIO_free_all(out); } X509_free(cert); EVP_PKEY_free(pkey); - } else { - Tcl_SetResult(interp,"Error generating private key",NULL); - return TCL_ERROR; +#if OPENSSL_VERSION_NUMBER > 0x10100000L && OPENSSL_VERSION_NUMBER < 0x30000000L + BN_free(bne); +#endif } } break; default: break; @@ -1828,14 +1879,14 @@ */ DLLEXPORT int Tls_Init(Tcl_Interp *interp) { const char tlsTclInitScript[] = { #include "tls.tcl.h" - 0x00 + 0x00 }; - dprintf("Called"); + dprintf("Called"); /* * We only support Tcl 8.4 or newer */ if ( @@ -1926,12 +1977,17 @@ dprintf("Asked to uninitialize"); #if defined(OPENSSL_THREADS) && defined(TCL_THREADS) Tcl_MutexLock(&init_mx); +#if OPENSSL_VERSION_NUMBER < 0x10000000L CRYPTO_set_locking_callback(NULL); CRYPTO_set_id_callback(NULL); +#elif OPENSSL_VERSION_NUMBER < 0x10100000L + CRYPTO_set_locking_callback(NULL); + CRYPTO_THREADID_set_callback(NULL) +#endif if (locks) { free(locks); locks = NULL; locksCount = 0; @@ -1957,26 +2013,46 @@ Tcl_MutexLock(&init_mx); #endif initialized = 1; #if defined(OPENSSL_THREADS) && defined(TCL_THREADS) +#if OPENSSL_VERSION_NUMBER < 0x10100000L num_locks = CRYPTO_num_locks(); - locksCount = num_locks; +#else + num_locks = 1; +#endif + locksCount = (int) num_locks; locks = malloc(sizeof(*locks) * num_locks); memset(locks, 0, sizeof(*locks) * num_locks); +#if OPENSSL_VERSION_NUMBER < 0x10000000L CRYPTO_set_locking_callback(CryptoThreadLockCallback); CRYPTO_set_id_callback(CryptoThreadIdCallback); +#elif OPENSSL_VERSION_NUMBER < 0x10100000L + CRYPTO_set_locking_callback(CryptoThreadLockCallback); + CRYPTO_THREADID_set_callback(CryptoThreadIdCallback) +#endif #endif +# if OPENSSL_VERSION_NUMBER < 0x10100000L if (SSL_library_init() != 1) { status = TCL_ERROR; goto done; } +#else + /* Initialize BOTH libcrypto and libssl. */ + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS + | OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); +#endif +# if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_load_error_strings(); ERR_load_crypto_strings(); +#else + /* Only initialize libcrypto */ + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); +#endif BIO_new_tcl(NULL, 0); #if 0 /* @@ -2001,12 +2077,14 @@ } RAND_seed(rnd_seed, sizeof(rnd_seed)); } while (RAND_status() != 1); #endif +# if OPENSSL_VERSION_NUMBER < 0x10100000L done: +#endif #if defined(OPENSSL_THREADS) && defined(TCL_THREADS) Tcl_MutexUnlock(&init_mx); #endif return(status); } Index: tls.htm ================================================================== --- tls.htm +++ tls.htm @@ -143,11 +143,11 @@
cipher cipher
The current cipher in use between the client and server channels.
sbits n
The number of bits used for the session key.
-
certificate n
+
certificate cert
The PEM encoded certificate.
sha1_hash hash
The SHA1 hash of the certificate.
sha256_hash hash
The SHA256 hash of the certificate.
@@ -154,11 +154,11 @@
alpn protocol
The protocol selected after Application-Layer Protocol Negotiation (ALPN).
version value
The protocol version used for the connection: - SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, unknown
+ SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3, unknown
tls::import channel Index: tlsBIO.c ================================================================== --- tlsBIO.c +++ tlsBIO.c @@ -14,13 +14,13 @@ #define BIO_set_init(bio, val) (bio)->init = (val) #define BIO_set_shutdown(bio, val) (bio)->shutdown = (val) /* XXX: This assumes the variable being assigned to is BioMethods */ #define BIO_meth_new(type_, name_) (BIO_METHOD *)Tcl_Alloc(sizeof(BIO_METHOD)); \ - memset(BioMethods, 0, sizeof(BIO_METHOD)); \ - BioMethods->type = type_; \ - BioMethods->name = name_; + memset(BioMethods, 0, sizeof(BIO_METHOD)); \ + BioMethods->type = type_; \ + BioMethods->name = name_; #define BIO_meth_set_write(bio, val) (bio)->bwrite = val; #define BIO_meth_set_read(bio, val) (bio)->bread = val; #define BIO_meth_set_puts(bio, val) (bio)->bputs = val; #define BIO_meth_set_ctrl(bio, val) (bio)->ctrl = val; #define BIO_meth_set_create(bio, val) (bio)->create = val; Index: tlsIO.c ================================================================== --- tlsIO.c +++ tlsIO.c @@ -617,16 +617,16 @@ Tcl_Channel downChan = Tls_GetParent(statePtr, TLS_TCL_FASTPATH); Tcl_DriverGetOptionProc *getOptionProc; getOptionProc = Tcl_ChannelGetOptionProc(Tcl_GetChannelType(downChan)); if (getOptionProc != NULL) { - return (*getOptionProc)(Tcl_GetChannelInstanceData(downChan), interp, optionName, dsPtr); + return (*getOptionProc)(Tcl_GetChannelInstanceData(downChan), interp, optionName, dsPtr); } else if (optionName == (char*) NULL) { - /* - * Request is query for all options, this is ok. - */ - return TCL_OK; + /* + * Request is query for all options, this is ok. + */ + return TCL_OK; } /* * Request for a specific option has to fail, we don't have any. */ return TCL_ERROR; @@ -660,53 +660,53 @@ dprintf("TlsWatchProc(0x%x)", mask); /* Pretend to be dead as long as the verify callback is running. * Otherwise that callback could be invoked recursively. */ if (statePtr->flags & TLS_TCL_CALLBACK) { - dprintf("Callback is on-going, doing nothing"); - return; + dprintf("Callback is on-going, doing nothing"); + return; } dprintFlags(statePtr); downChan = Tls_GetParent(statePtr, TLS_TCL_FASTPATH); if (statePtr->flags & TLS_TCL_HANDSHAKE_FAILED) { - dprintf("Asked to watch a socket with a failed handshake -- nothing can happen here"); + dprintf("Asked to watch a socket with a failed handshake -- nothing can happen here"); dprintf("Unregistering interest in the lower channel"); (Tcl_GetChannelType(downChan))->watchProc(Tcl_GetChannelInstanceData(downChan), 0); statePtr->watchMask = 0; - return; - } - - statePtr->watchMask = mask; - - /* No channel handlers any more. We will be notified automatically - * about events on the channel below via a call to our - * 'TransformNotifyProc'. But we have to pass the interest down now. - * We are allowed to add additional 'interest' to the mask if we want - * to. But this transformation has no such interest. It just passes - * the request down, unchanged. - */ - - - dprintf("Registering our interest in the lower channel (chan=%p)", (void *) downChan); - (Tcl_GetChannelType(downChan)) - ->watchProc(Tcl_GetChannelInstanceData(downChan), mask); - - /* - * Management of the internal timer. - */ - - if (statePtr->timer != (Tcl_TimerToken) NULL) { - dprintf("A timer was found, deleting it"); - Tcl_DeleteTimerHandler(statePtr->timer); - statePtr->timer = (Tcl_TimerToken) NULL; - } + return; + } + + statePtr->watchMask = mask; + + /* No channel handlers any more. We will be notified automatically + * about events on the channel below via a call to our + * 'TransformNotifyProc'. But we have to pass the interest down now. + * We are allowed to add additional 'interest' to the mask if we want + * to. But this transformation has no such interest. It just passes + * the request down, unchanged. + */ + + + dprintf("Registering our interest in the lower channel (chan=%p)", (void *) downChan); + (Tcl_GetChannelType(downChan)) + ->watchProc(Tcl_GetChannelInstanceData(downChan), mask); + + /* + * Management of the internal timer. + */ + + if (statePtr->timer != (Tcl_TimerToken) NULL) { + dprintf("A timer was found, deleting it"); + Tcl_DeleteTimerHandler(statePtr->timer); + statePtr->timer = (Tcl_TimerToken) NULL; + } if ((mask & TCL_READABLE) && ((Tcl_InputBuffered(statePtr->self) > 0) || (BIO_ctrl_pending(statePtr->bio) > 0))) { /* * There is interest in readable events and we actually have Index: tlsX509.c ================================================================== --- tlsX509.c +++ tlsX509.c @@ -1,9 +1,15 @@ /* * Copyright (C) 1997-2000 Sensus Consulting Ltd. * Matt Newman */ +#include +#include +#include +#include +#include +#include #include "tlsInt.h" /* * Ensure these are not macros - known to be defined on Win32 */ @@ -33,35 +39,35 @@ { static char bp[128]; char *v; int gmt=0; static char *mon[12]={ - "Jan","Feb","Mar","Apr","May","Jun", - "Jul","Aug","Sep","Oct","Nov","Dec"}; + "Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec"}; int i; int y=0,M=0,d=0,h=0,m=0,s=0; i=tm->length; v=(char *)tm->data; if (i < 10) goto err; if (v[i-1] == 'Z') gmt=1; for (i=0; i<10; i++) - if ((v[i] > '9') || (v[i] < '0')) goto err; + if ((v[i] > '9') || (v[i] < '0')) goto err; y= (v[0]-'0')*10+(v[1]-'0'); if (y < 70) y+=100; M= (v[2]-'0')*10+(v[3]-'0'); if ((M > 12) || (M < 1)) goto err; d= (v[4]-'0')*10+(v[5]-'0'); h= (v[6]-'0')*10+(v[7]-'0'); m= (v[8]-'0')*10+(v[9]-'0'); if ( (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) - s= (v[10]-'0')*10+(v[11]-'0'); + s= (v[10]-'0')*10+(v[11]-'0'); sprintf(bp,"%s %2d %02d:%02d:%02d %d%s", - mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":""); + mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":""); return bp; err: return "Bad time value"; } @@ -100,11 +106,11 @@ char certStr[CERT_STR_SIZE], *certStr_p; int certStr_len, toRead; #ifndef NO_SSL_SHA char sha1_hash_ascii[SHA_DIGEST_LENGTH * 2 + 1]; unsigned char sha1_hash_binary[SHA_DIGEST_LENGTH]; - char sha256_hash_ascii[SHA256_DIGEST_LENGTH*2+1]; + char sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2 + 1]; unsigned char sha256_hash_binary[SHA256_DIGEST_LENGTH]; const char *shachars="0123456789ABCDEF"; sha1_hash_ascii[SHA_DIGEST_LENGTH * 2] = '\0'; sha256_hash_ascii[SHA256_DIGEST_LENGTH * 2] = '\0'; @@ -135,43 +141,48 @@ n = BIO_read(bio, serial, min(BIO_pending(bio), BUFSIZ - 1)); n = max(n, 0); serial[n] = 0; (void)BIO_flush(bio); - if (PEM_write_bio_X509(bio, cert)) { - certStr_p = certStr; - certStr_len = 0; - while (1) { - toRead = min(BIO_pending(bio), CERT_STR_SIZE - certStr_len - 1); - toRead = min(toRead, BUFSIZ); - if (toRead == 0) { - break; - } - dprintf("Reading %i bytes from the certificate...", toRead); - n = BIO_read(bio, certStr_p, toRead); - if (n <= 0) { - break; - } - certStr_len += n; - certStr_p += n; - } - *certStr_p = '\0'; - (void)BIO_flush(bio); - } + if (PEM_write_bio_X509(bio, cert)) { + certStr_p = certStr; + certStr_len = 0; + while (1) { + toRead = min(BIO_pending(bio), CERT_STR_SIZE - certStr_len - 1); + toRead = min(toRead, BUFSIZ); + if (toRead == 0) { + break; + } + dprintf("Reading %i bytes from the certificate...", toRead); + n = BIO_read(bio, certStr_p, toRead); + if (n <= 0) { + break; + } + certStr_len += n; + certStr_p += n; + } + *certStr_p = '\0'; + (void)BIO_flush(bio); + } BIO_free(bio); } +#if OPENSSL_VERSION_NUMBER < 0x10100000L strcpy( notBefore, ASN1_UTCTIME_tostr( X509_get_notBefore(cert) )); strcpy( notAfter, ASN1_UTCTIME_tostr( X509_get_notAfter(cert) )); +#else + strcpy( notBefore, ASN1_UTCTIME_tostr( X509_getm_notBefore(cert) )); + strcpy( notAfter, ASN1_UTCTIME_tostr( X509_getm_notAfter(cert) )); +#endif #ifndef NO_SSL_SHA /* SHA1 */ X509_digest(cert, EVP_sha1(), sha1_hash_binary, NULL); for (int n = 0; n < SHA_DIGEST_LENGTH; n++) { - sha1_hash_ascii[n * 2] = shachars[(sha1_hash_binary[n] & 0xF0) >> 4]; - sha1_hash_ascii[n * 2 + 1] = shachars[(sha1_hash_binary[n] & 0x0F)]; + sha1_hash_ascii[n*2] = shachars[(sha1_hash_binary[n] & 0xF0) >> 4]; + sha1_hash_ascii[n*2+1] = shachars[(sha1_hash_binary[n] & 0x0F)]; } Tcl_ListObjAppendElement( interp, certPtr, Tcl_NewStringObj("sha1_hash", -1) ); Tcl_ListObjAppendElement( interp, certPtr, Tcl_NewStringObj(sha1_hash_ascii, SHA_DIGEST_LENGTH * 2) ); /* SHA256 */