From 3cb899302df930796db2da8bb3b6a36a6d179d96 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 9 Nov 2025 00:23:22 +0100 Subject: [PATCH] Avoid using deprecated OpenSSL functions Replace deprecated OpenSSL functions related to RSA key handling with ones that don't generate warnings from OpenSSL 3.0 and later. Warn about obsolete PublicKey and PrivateKey statements, which were no longer generated by tinc since 1.0pre4. --- doc/tinc.conf.5.in | 6 -- doc/tinc.texi | 10 --- m4/openssl.m4 | 2 +- src/connection.c | 2 +- src/connection.h | 3 +- src/net_setup.c | 155 ++++++++++++++++++++++++-------------------- src/protocol_auth.c | 48 +++++++++++--- src/tincd.c | 91 +++----------------------- 8 files changed, 135 insertions(+), 182 deletions(-) diff --git a/doc/tinc.conf.5.in b/doc/tinc.conf.5.in index cd7d1a0d..309c15ca 100644 --- a/doc/tinc.conf.5.in +++ b/doc/tinc.conf.5.in @@ -379,9 +379,6 @@ and the others will be notified of this. .It Va PriorityInheritance Li = yes | no Po no Pc Bq experimental When this option is enabled the value of the TOS field of tunneled IPv4 packets will be inherited by the UDP packets that are sent out. -.It Va PrivateKey Li = Ar key Bq obsolete -The private RSA key of this tinc daemon. -It will allow this tinc daemon to authenticate itself to other daemons. .It Va PrivateKeyFile Li = Ar filename Po Pa @sysconfdir@/tinc/ Ns Ar NETNAME Ns Pa /rsa_key.priv Pc The file in which the private RSA key of this tinc daemon resides. .It Va ProcessPriority Li = low | normal | high @@ -508,9 +505,6 @@ The port number on which this tinc daemon is listening for incoming connections, which is used if no port number is specified in an .Va Address statement. -.It Va PublicKey Li = Ar key Bq obsolete -The public RSA key of this tinc daemon. -It will be used to cryptographically verify it's identity and to set up a secure connection. .It Va PublicKeyFile Li = Ar filename Bq obsolete The file in which the public RSA key of this tinc daemon resides. .Pp diff --git a/doc/tinc.texi b/doc/tinc.texi index 4e2ba516..255dfb6a 100644 --- a/doc/tinc.texi +++ b/doc/tinc.texi @@ -1045,12 +1045,6 @@ the connection is terminated, and the others will be notified of this. When this option is enabled the value of the TOS field of tunneled IPv4 packets will be inherited by the UDP packets that are sent out. -@cindex PrivateKey -@item PrivateKey = <@var{key}> [obsolete] -This is the RSA private key for tinc. However, for safety reasons it is -advised to store private keys of any kind in separate files. This prevents -accidental eavesdropping if you are editing the configuration file. - @cindex PrivateKeyFile @item PrivateKeyFile = <@var{path}> (@file{@value{sysconfdir}/tinc/@var{netname}/rsa_key.priv}) This is the full path name of the RSA private key file that was @@ -1195,10 +1189,6 @@ After the path MTU has been discovered, it will be enforced on the VPN. This is the port this tinc daemon listens on. You can use decimal portnumbers or symbolic names (as listed in @file{/etc/services}). -@cindex PublicKey -@item PublicKey = <@var{key}> [obsolete] -This is the RSA public key for this host. - @cindex PublicKeyFile @item PublicKeyFile = <@var{path}> [obsolete] This is the full path name of the RSA public key file that was generated diff --git a/m4/openssl.m4 b/m4/openssl.m4 index 99023c24..12b92aa9 100644 --- a/m4/openssl.m4 +++ b/m4/openssl.m4 @@ -35,7 +35,7 @@ AC_DEFUN([tinc_OPENSSL], LDFLAGS="$LDFLAGS -L$withval"] ) - AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/engine.h], + AC_CHECK_HEADERS([openssl/evp.h openssl/rsa.h openssl/rand.h openssl/err.h openssl/sha.h openssl/pem.h openssl/param_build.h], [], [AC_MSG_ERROR([LibreSSL/OpenSSL header files not found.]); break] ) diff --git a/src/connection.c b/src/connection.c index d137af12..00154ebb 100644 --- a/src/connection.c +++ b/src/connection.c @@ -108,7 +108,7 @@ void free_connection_partially(connection_t *c) { } if(c->rsa_key) { - RSA_free(c->rsa_key); + EVP_PKEY_free(c->rsa_key); c->rsa_key = NULL; } } diff --git a/src/connection.h b/src/connection.h index 629e16b9..fa43e3e2 100644 --- a/src/connection.h +++ b/src/connection.h @@ -21,7 +21,6 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include "avl_tree.h" @@ -67,7 +66,7 @@ typedef struct connection_t { struct node_t *node; /* node associated with the other end */ struct edge_t *edge; /* edge associated with this connection */ - RSA *rsa_key; /* his public/private key */ + EVP_PKEY *rsa_key; /* his public/private key */ const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */ const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */ EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */ diff --git a/src/net_setup.c b/src/net_setup.c index 501fecd3..7bde753b 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -22,12 +22,11 @@ #include "system.h" -#include -#include -#include #include #include -#include +#include +#include +#include #include "avl_tree.h" #include "conf.h" @@ -54,17 +53,24 @@ bool read_rsa_public_key(connection_t *c) { char *pubname; char *hcfname; char *key; - BIGNUM *n = NULL; - BIGNUM *e = NULL; if(!c->rsa_key) { - c->rsa_key = RSA_new(); -// RSA_blinding_on(c->rsa_key, NULL); + EVP_PKEY_free(c->rsa_key); + c->rsa_key = NULL; } /* First, check for simple PublicKey statement */ if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key)) { + BIGNUM *n = NULL; + BIGNUM *e = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *param = NULL; + EVP_PKEY_CTX *ctx = NULL; + int result; + + logger(LOG_WARNING, "Obsolete PublicKey statement for %s!", c->name); + if((size_t)BN_hex2bn(&n, key) != strlen(key)) { free(key); logger(LOG_ERR, "Invalid PublicKey for %s!", c->name); @@ -74,36 +80,38 @@ bool read_rsa_public_key(connection_t *c) { free(key); BN_hex2bn(&e, "FFFF"); - if(!n || !e || RSA_set0_key(c->rsa_key, n, e, NULL) != 1) { - BN_free(e); - BN_free(n); - logger(LOG_ERR, "RSA_set0_key() failed with PublicKey for %s!", c->name); - return false; + bld = OSSL_PARAM_BLD_new(); + + if(!bld) { + abort(); } - return true; - } + OSSL_PARAM_BLD_push_BN(bld, "n", n); + OSSL_PARAM_BLD_push_BN(bld, "e", e); + param = OSSL_PARAM_BLD_to_param(bld); + OSSL_PARAM_BLD_free(bld); - /* Else, check for PublicKeyFile statement and read it */ + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &pubname)) { - fp = fopen(pubname, "r"); + if(!ctx) { + abort(); + } - if(!fp) { - logger(LOG_ERR, "Error reading RSA public key file `%s': %s", pubname, strerror(errno)); - free(pubname); + EVP_PKEY_fromdata_init(ctx); + result = EVP_PKEY_fromdata(ctx, &c->rsa_key, EVP_PKEY_PUBLIC_KEY, param); + EVP_PKEY_CTX_free(ctx); + + if(result <= 0) { + logger(LOG_ERR, "Failed to parse PublicKey for %s!", c->name); return false; } - c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); - fclose(fp); + return true; + } - if(c->rsa_key) { - free(pubname); - return true; /* Woohoo. */ - } + /* Else, check for PublicKeyFile statement and read it */ - /* If it fails, try PEM_read_RSA_PUBKEY. */ + if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &pubname)) { fp = fopen(pubname, "r"); if(!fp) { @@ -112,13 +120,12 @@ bool read_rsa_public_key(connection_t *c) { return false; } - c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL); + c->rsa_key = PEM_read_PUBKEY(fp, &c->rsa_key, NULL, NULL); fclose(fp); if(c->rsa_key) { -// RSA_blinding_on(c->rsa_key, NULL); free(pubname); - return true; + return true; /* Woohoo. */ } logger(LOG_ERR, "Reading RSA public key file `%s' failed: %s", pubname, strerror(errno)); @@ -137,7 +144,7 @@ bool read_rsa_public_key(connection_t *c) { return false; } - c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL); + c->rsa_key = PEM_read_PUBKEY(fp, &c->rsa_key, NULL, NULL); fclose(fp); if(c->rsa_key) { @@ -145,25 +152,6 @@ bool read_rsa_public_key(connection_t *c) { return true; } - /* Try again with PEM_read_RSA_PUBKEY. */ - - fp = fopen(hcfname, "r"); - - if(!fp) { - logger(LOG_ERR, "Error reading RSA public key file `%s': %s", hcfname, strerror(errno)); - free(hcfname); - return false; - } - - free(hcfname); - c->rsa_key = PEM_read_RSA_PUBKEY(fp, &c->rsa_key, NULL, NULL); -// RSA_blinding_on(c->rsa_key, NULL); - fclose(fp); - - if(c->rsa_key) { - return true; - } - logger(LOG_ERR, "No public key for %s specified!", c->name); return false; @@ -171,44 +159,67 @@ bool read_rsa_public_key(connection_t *c) { static bool read_rsa_private_key(void) { FILE *fp; - char *fname, *key, *pubkey; - BIGNUM *n = NULL; - BIGNUM *e = NULL; - BIGNUM *d = NULL; + char *fname, *key; if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key)) { - myself->connection->rsa_key = RSA_new(); + char *pubkey; + BIGNUM *n = NULL; + BIGNUM *e = NULL; + BIGNUM *d = NULL; + OSSL_PARAM_BLD *bld = NULL; + OSSL_PARAM *param = NULL; + EVP_PKEY_CTX *ctx = NULL; + int result; -// RSA_blinding_on(myself->connection->rsa_key, NULL); - if((size_t)BN_hex2bn(&d, key) != strlen(key)) { - logger(LOG_ERR, "Invalid PrivateKey for myself!"); - free(key); - return false; - } - - free(key); + logger(LOG_WARNING, "Obsolete PrivateKey statement for myself!"); if(!get_config_string(lookup_config(config_tree, "PublicKey"), &pubkey)) { - BN_free(d); logger(LOG_ERR, "PrivateKey used but no PublicKey found!"); return false; } + if((size_t)BN_hex2bn(&d, key) != strlen(key)) { + free(pubkey); + free(key); + logger(LOG_ERR, "Invalid PrivateKey for myself!"); + return false; + } + if((size_t)BN_hex2bn(&n, pubkey) != strlen(pubkey)) { free(pubkey); - BN_free(d); + free(key); logger(LOG_ERR, "Invalid PublicKey for myself!"); return false; } free(pubkey); + free(key); BN_hex2bn(&e, "FFFF"); - if(!n || !e || !d || RSA_set0_key(myself->connection->rsa_key, n, e, d) != 1) { - BN_free(d); - BN_free(e); - BN_free(n); - logger(LOG_ERR, "RSA_set0_key() failed with PrivateKey for myself!"); + bld = OSSL_PARAM_BLD_new(); + + if(!bld) { + abort(); + } + + OSSL_PARAM_BLD_push_BN(bld, "n", n); + OSSL_PARAM_BLD_push_BN(bld, "e", e); + OSSL_PARAM_BLD_push_BN(bld, "d", d); + param = OSSL_PARAM_BLD_to_param(bld); + OSSL_PARAM_BLD_free(bld); + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); + + if(!ctx) { + abort(); + } + + EVP_PKEY_fromdata_init(ctx); + result = EVP_PKEY_fromdata(ctx, &myself->connection->rsa_key, EVP_PKEY_KEYPAIR, param); + EVP_PKEY_CTX_free(ctx); + + if(result <= 0) { + logger(LOG_ERR, "Failed to parse PrivateKey for myself!"); return false; } @@ -241,7 +252,7 @@ static bool read_rsa_private_key(void) { #endif - myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + myself->connection->rsa_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL); fclose(fp); if(!myself->connection->rsa_key) { diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 15807c33..063823c8 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "avl_tree.h" #include "conf.h" @@ -144,8 +145,10 @@ static uint64_t byte_budget(const EVP_CIPHER *cipher) { bool send_metakey(connection_t *c) { bool x; + int result; - int len = RSA_size(c->rsa_key); + int len = EVP_PKEY_get_size(c->rsa_key); + size_t outlen = len; /* Allocate buffers for the meta key */ @@ -196,7 +199,20 @@ bool send_metakey(connection_t *c) { with a length equal to that of the modulus of the RSA key. */ - if(RSA_public_encrypt(len, (unsigned char *)c->outkey, (unsigned char *)buffer, c->rsa_key, RSA_NO_PADDING) != len) { + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(c->rsa_key, NULL); + + if(!ctx) { + logger(LOG_ERR, "Error during encryption of meta key for %s (%s): %s", + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + return false; + } + + EVP_PKEY_encrypt_init(ctx); + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING); + result = EVP_PKEY_encrypt(ctx, (unsigned char *)buffer, &outlen, (const unsigned char *)c->outkey, len); + EVP_PKEY_CTX_free(ctx); + + if(result <= 0 || outlen != len) { logger(LOG_ERR, "Error during encryption of meta key for %s (%s): %s", c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; @@ -237,6 +253,8 @@ bool metakey_h(connection_t *c) { char buffer[MAX_STRING_SIZE]; int cipher, digest, maclength, compression; int len; + size_t outlen; + int result; if(sscanf(c->buffer, "%*d %d %d %d %d " MAX_STRING, &cipher, &digest, &maclength, &compression, buffer) != 5) { logger(LOG_ERR, "Got bad %s from %s (%s)", "METAKEY", c->name, @@ -244,7 +262,8 @@ bool metakey_h(connection_t *c) { return false; } - len = RSA_size(myself->connection->rsa_key); + len = EVP_PKEY_get_size(myself->connection->rsa_key); + outlen = len; /* Check if the length of the meta key is all right */ @@ -274,7 +293,20 @@ bool metakey_h(connection_t *c) { /* Decrypt the meta key */ - if(RSA_private_decrypt(len, (unsigned char *)buffer, (unsigned char *)c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) { /* See challenge() */ + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(myself->connection->rsa_key, NULL); + + if(!ctx) { + logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s", + c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); + return false; + } + + EVP_PKEY_decrypt_init(ctx); + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING); + result = EVP_PKEY_decrypt(ctx, (unsigned char *)c->inkey, &outlen, (const unsigned char *)buffer, len); + EVP_PKEY_CTX_free(ctx); + + if(result <= 0 || outlen != len) { /* See challenge() */ logger(LOG_ERR, "Error during decryption of meta key for %s (%s): %s", c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL)); return false; @@ -343,7 +375,7 @@ bool metakey_h(connection_t *c) { bool send_challenge(connection_t *c) { /* CHECKME: what is most reasonable value for len? */ - int len = RSA_size(c->rsa_key); + int len = EVP_PKEY_get_size(c->rsa_key); /* Allocate buffers for the challenge */ @@ -379,7 +411,7 @@ bool challenge_h(connection_t *c) { return false; } - len = RSA_size(myself->connection->rsa_key); + len = EVP_PKEY_get_size(myself->connection->rsa_key); /* Check if the length of the challenge is all right */ @@ -424,7 +456,7 @@ bool send_chal_reply(connection_t *c) { } if(!EVP_DigestInit(ctx, c->indigest) - || !EVP_DigestUpdate(ctx, c->mychallenge, RSA_size(myself->connection->rsa_key)) + || !EVP_DigestUpdate(ctx, c->mychallenge, EVP_PKEY_get_size(myself->connection->rsa_key)) || !EVP_DigestFinal(ctx, (unsigned char *)hash, NULL)) { EVP_MD_CTX_destroy(ctx); logger(LOG_ERR, "Error during calculation of response for %s (%s): %s", @@ -479,7 +511,7 @@ bool chal_reply_h(connection_t *c) { } if(!EVP_DigestInit(ctx, c->outdigest) - || !EVP_DigestUpdate(ctx, c->hischallenge, RSA_size(c->rsa_key)) + || !EVP_DigestUpdate(ctx, c->hischallenge, EVP_PKEY_get_size(c->rsa_key)) || !EVP_DigestFinal(ctx, (unsigned char *)myhash, NULL)) { EVP_MD_CTX_destroy(ctx); logger(LOG_ERR, "Error during calculation of response from %s (%s): %s", diff --git a/src/tincd.c b/src/tincd.c index c1f2e5a2..69875788 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -34,11 +34,8 @@ #endif #include -#include #include #include -#include -#include #ifdef HAVE_LZO #include LZO1X_H @@ -361,97 +358,29 @@ static bool parse_options(int argc, char **argv) { return true; } -/* This function prettyprints the key generation process */ - -static int indicator(int a, int b, BN_GENCB *cb) { - (void)cb; - - switch(a) { - case 0: - fprintf(stderr, "."); - break; - - case 1: - fprintf(stderr, "+"); - break; - - case 2: - fprintf(stderr, "-"); - break; - - case 3: - switch(b) { - case 0: - fprintf(stderr, " p\n"); - break; - - case 1: - fprintf(stderr, " q\n"); - break; - - default: - fprintf(stderr, "?"); - } - - break; - - default: - fprintf(stderr, "?"); - } - - return 1; -} - /* Generate a public/private RSA keypair, and ask for a file to store them in. */ static bool keygen(int bits) { - BIGNUM *e = NULL; - RSA *rsa_key; + EVP_PKEY *rsa_key; FILE *f; char filename[PATH_MAX]; - BN_GENCB *cb; - int result; - - fprintf(stderr, "Generating %d bits keys:\n", bits); - - cb = BN_GENCB_new(); - - if(!cb) { - abort(); - } - - BN_GENCB_set(cb, indicator, NULL); - rsa_key = RSA_new(); + fprintf(stderr, "Generating %d bits keys...\n", bits); - if(BN_hex2bn(&e, "10001") == 0) { - abort(); - } - - if(!rsa_key || !e) { - abort(); - } - - result = RSA_generate_key_ex(rsa_key, bits, e, cb); + rsa_key = EVP_RSA_gen(bits); - BN_free(e); - BN_GENCB_free(cb); - - if(!result) { + if(!rsa_key) { fprintf(stderr, "Error during key generation!\n"); - RSA_free(rsa_key); return false; - } else { - fprintf(stderr, "Done.\n"); } snprintf(filename, sizeof(filename), "%s/rsa_key.priv", confbase); f = ask_and_open(filename, "private RSA key"); if(!f) { - RSA_free(rsa_key); + EVP_PKEY_free(rsa_key); return false; } @@ -461,7 +390,7 @@ static bool keygen(int bits) { #endif fputc('\n', f); - PEM_write_RSAPrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL); + PEM_write_PrivateKey(f, rsa_key, NULL, NULL, 0, NULL, NULL); fclose(f); char *name = get_name(); @@ -476,15 +405,15 @@ static bool keygen(int bits) { f = ask_and_open(filename, "public RSA key"); if(!f) { - RSA_free(rsa_key); + EVP_PKEY_free(rsa_key); return false; } fputc('\n', f); - PEM_write_RSAPublicKey(f, rsa_key); + PEM_write_PUBKEY(f, rsa_key); fclose(f); - RSA_free(rsa_key); + EVP_PKEY_free(rsa_key); return true; } @@ -676,8 +605,6 @@ int main(int argc, char **argv) { init_configuration(&config_tree); - ENGINE_load_builtin_engines(); - if(generate_keys) { read_server_config(); return !keygen(generate_keys); -- 2.47.3