Also use centralized logging for OpenSSL errors.
https://github.com/gsliepen/tinc/issues/347
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
- openssl/rsa.c
+ openssl/rsa.c \
+ openssl/log.c openssl/log.h
tinc_SOURCES += \
openssl/cipher.c openssl/cipher.h \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
openssl/prf.c \
openssl/rsa.c \
- openssl/rsagen.c
+ openssl/rsagen.c \
+ openssl/log.c openssl/log.h
sptps_test_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- openssl/prf.c
+ openssl/prf.c \
+ openssl/log.c openssl/log.h
sptps_keypair_SOURCES += \
openssl/crypto.c
sptps_speed_SOURCES += \
openssl/crypto.c \
openssl/digest.c openssl/digest.h \
- openssl/prf.c
+ openssl/prf.c \
+ openssl/log.c openssl/log.h
else
if GCRYPT
tincd_SOURCES += \
#include "../system.h"
-#include <openssl/rand.h>
#include <openssl/err.h>
#include <openssl/evp.h>
+#include "log.h"
#include "cipher.h"
#include "../cipher.h"
#include "../logger.h"
return true;
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("set key");
return false;
}
return true;
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Error while setting key: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("set key");
return false;
}
}
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("encrypt data");
return false;
}
}
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("decrypt data");
return false;
}
void crypto_init(void) {
random_init();
+#if OPENSSL_VERSION_MAJOR < 3
ENGINE_load_builtin_engines();
+#endif
if(!RAND_status()) {
fprintf(stderr, "Not enough entropy for the PRNG!\n");
#include <openssl/err.h>
#include <openssl/hmac.h>
+#if OPENSSL_VERSION_MAJOR >= 3
+#include <openssl/core_names.h>
+#endif
+
#include "digest.h"
#include "../digest.h"
#include "../logger.h"
+#include "log.h"
static void digest_open(digest_t *digest, const EVP_MD *evp_md, size_t maclength) {
digest->digest = evp_md;
}
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
+#if OPENSSL_VERSION_MAJOR < 3
digest->hmac_ctx = HMAC_CTX_new();
- HMAC_Init_ex(digest->hmac_ctx, key, (int)len, digest->digest, NULL);
if(!digest->hmac_ctx) {
abort();
}
+ HMAC_Init_ex(digest->hmac_ctx, key, (int)len, digest->digest, NULL);
+#else
+ EVP_MAC *mac = EVP_MAC_fetch(NULL, OSSL_MAC_NAME_HMAC, NULL);
+
+ if(!mac) {
+ openssl_err("fetch MAC");
+ return false;
+ }
+
+ digest->hmac_ctx = EVP_MAC_CTX_new(mac);
+ EVP_MAC_free(mac);
+
+ if(!digest->hmac_ctx) {
+ openssl_err("create MAC context");
+ return false;
+ }
+
+ const char *hmac_algo = EVP_MD_get0_name(digest->digest);
+
+ if(!hmac_algo) {
+ openssl_err("get HMAC algorithm name");
+ return false;
+ }
+
+ // The casts are okay, the parameters are not going to change. For example, see:
+ // https://github.com/openssl/openssl/blob/31b7f23d2f958491d46c8a8e61c2b77b1b546f3e/crypto/ec/ecdh_kdf.c#L37-L38
+ const OSSL_PARAM params[] = {
+ OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, (void *)key, len),
+ OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, (void *)hmac_algo, 0),
+ OSSL_PARAM_END,
+ };
+
+ if(!EVP_MAC_init(digest->hmac_ctx, NULL, 0, params)) {
+ openssl_err("set MAC context params");
+ return false;
+ }
+
+#endif
return true;
}
}
if(digest->hmac_ctx) {
+#if OPENSSL_VERSION_MAJOR < 3
HMAC_CTX_free(digest->hmac_ctx);
+#else
+ EVP_MAC_CTX_free(digest->hmac_ctx);
+#endif
}
memset(digest, 0, sizeof(*digest));
unsigned char tmpdata[len];
if(digest->hmac_ctx) {
- if(!HMAC_Init_ex(digest->hmac_ctx, NULL, 0, NULL, NULL)
- || !HMAC_Update(digest->hmac_ctx, indata, inlen)
- || !HMAC_Final(digest->hmac_ctx, tmpdata, NULL)) {
- logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
+ bool ok;
+
+#if OPENSSL_VERSION_MAJOR < 3
+ ok = HMAC_Init_ex(digest->hmac_ctx, NULL, 0, NULL, NULL)
+ && HMAC_Update(digest->hmac_ctx, indata, inlen)
+ && HMAC_Final(digest->hmac_ctx, tmpdata, NULL);
+#else
+ EVP_MAC_CTX *mac_ctx = EVP_MAC_CTX_dup(digest->hmac_ctx);
+
+ ok = mac_ctx
+ && EVP_MAC_update(mac_ctx, indata, inlen)
+ && EVP_MAC_final(mac_ctx, tmpdata, NULL, sizeof(tmpdata));
+
+ EVP_MAC_CTX_free(mac_ctx);
+#endif
+
+ if(!ok) {
+ openssl_err("create HMAC");
return false;
}
} else {
if(!EVP_DigestInit(digest->md_ctx, digest->digest)
|| !EVP_DigestUpdate(digest->md_ctx, indata, inlen)
|| !EVP_DigestFinal(digest->md_ctx, tmpdata, NULL)) {
- logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("create digest");
return false;
}
}
struct digest {
const EVP_MD *digest;
+#if OPENSSL_VERSION_MAJOR < 3
HMAC_CTX *hmac_ctx;
+#else
+ EVP_MAC_CTX *hmac_ctx;
+#endif
EVP_MD_CTX *md_ctx;
size_t maclength;
};
--- /dev/null
+#include <openssl/err.h>
+#include "log.h"
+#include "../logger.h"
+
+void openssl_err(const char *msg) {
+ const char *err = ERR_error_string(ERR_peek_last_error(), NULL);
+ logger(DEBUG_ALWAYS, LOG_ERR, "OpenSSL error: unable to %s: %s", msg, err);
+}
--- /dev/null
+#ifndef OPENSSL_LOG_H
+#define OPENSSL_LOG_H
+
+extern void openssl_err(const char *msg);
+
+#endif // OPENSSL_LOG_H
#include "../system.h"
#include <openssl/pem.h>
-#include <openssl/err.h>
#include <openssl/rsa.h>
#define TINC_RSA_INTERNAL
+
+#if OPENSSL_VERSION_MAJOR < 3
typedef RSA rsa_t;
+#else
+#include <openssl/encoder.h>
+#include <openssl/decoder.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#include <assert.h>
+
+typedef EVP_PKEY rsa_t;
+#endif
+#include "log.h"
#include "../logger.h"
#include "../rsa.h"
// Set RSA keys
-rsa_t *rsa_set_hex_public_key(const char *n, const char *e) {
- BIGNUM *bn_n = NULL;
- BIGNUM *bn_e = NULL;
+#if OPENSSL_VERSION_MAJOR >= 3
+static EVP_PKEY *build_rsa_key(int selection, const BIGNUM *bn_n, const BIGNUM *bn_e, const BIGNUM *bn_d) {
+ assert(bn_n);
+ assert(bn_e);
- if((size_t)BN_hex2bn(&bn_n, n) != strlen(n) || (size_t)BN_hex2bn(&bn_e, e) != strlen(e)) {
- BN_free(bn_e);
- BN_free(bn_n);
- return false;
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+
+ if(!ctx) {
+ openssl_err("initialize key context");
+ return NULL;
}
- rsa_t *rsa = RSA_new();
+ OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n);
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e);
- if(!rsa) {
- return NULL;
+ if(bn_d) {
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, bn_d);
}
- RSA_set0_key(rsa, bn_n, bn_e, NULL);
+ OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
+ EVP_PKEY *key = NULL;
- return rsa;
+ bool ok = EVP_PKEY_fromdata_init(ctx) > 0
+ && EVP_PKEY_fromdata(ctx, &key, selection, params) > 0;
+
+ OSSL_PARAM_free(params);
+ OSSL_PARAM_BLD_free(bld);
+ EVP_PKEY_CTX_free(ctx);
+
+ if(ok) {
+ return key;
+ }
+
+ openssl_err("build key");
+ return NULL;
}
+#endif
-rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) {
+static bool hex_to_bn(BIGNUM **bn, const char *hex) {
+ return (size_t)BN_hex2bn(bn, hex) == strlen(hex);
+}
+
+static rsa_t *rsa_set_hex_key(const char *n, const char *e, const char *d) {
+ rsa_t *rsa = NULL;
BIGNUM *bn_n = NULL;
BIGNUM *bn_e = NULL;
BIGNUM *bn_d = NULL;
- if((size_t)BN_hex2bn(&bn_n, n) != strlen(n) || (size_t)BN_hex2bn(&bn_e, e) != strlen(e) || (size_t)BN_hex2bn(&bn_d, d) != strlen(d)) {
+ if(!hex_to_bn(&bn_n, n) || !hex_to_bn(&bn_e, e) || (d && !hex_to_bn(&bn_d, d))) {
+ goto exit;
+ }
+
+#if OPENSSL_VERSION_MAJOR < 3
+ rsa = RSA_new();
+
+ if(rsa) {
+ RSA_set0_key(rsa, bn_n, bn_e, bn_d);
+ }
+
+#else
+ int selection = bn_d ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY;
+ rsa = build_rsa_key(selection, bn_n, bn_e, bn_d);
+#endif
+
+exit:
+#if OPENSSL_VERSION_MAJOR < 3
+
+ if(!rsa)
+#endif
+ {
BN_free(bn_d);
BN_free(bn_e);
BN_free(bn_n);
- return false;
}
- rsa_t *rsa = RSA_new();
+ return rsa;
+}
- if(!rsa) {
+rsa_t *rsa_set_hex_public_key(const char *n, const char *e) {
+ return rsa_set_hex_key(n, e, NULL);
+}
+
+rsa_t *rsa_set_hex_private_key(const char *n, const char *e, const char *d) {
+ return rsa_set_hex_key(n, e, d);
+}
+
+// Read PEM RSA keys
+
+#if OPENSSL_VERSION_MAJOR >= 3
+static rsa_t *read_key_from_pem(FILE *fp, int selection) {
+ rsa_t *rsa = NULL;
+ OSSL_DECODER_CTX *ctx = OSSL_DECODER_CTX_new_for_pkey(&rsa, "PEM", NULL, "RSA", selection, NULL, NULL);
+
+ if(!ctx) {
+ openssl_err("initialize decoder");
return NULL;
}
- RSA_set0_key(rsa, bn_n, bn_e, bn_d);
+ bool ok = OSSL_DECODER_from_fp(ctx, fp);
+ OSSL_DECODER_CTX_free(ctx);
+
+ if(!ok) {
+ rsa = NULL;
+ openssl_err("read RSA key from file");
+ }
return rsa;
}
-
-// Read PEM RSA keys
+#endif
rsa_t *rsa_read_pem_public_key(FILE *fp) {
- rsa_t *rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
+ rsa_t *rsa;
+
+#if OPENSSL_VERSION_MAJOR < 3
+ rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
if(!rsa) {
rewind(fp);
rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
}
+#else
+ rsa = read_key_from_pem(fp, OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
+#endif
+
if(!rsa) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("read RSA public key");
}
return rsa;
}
rsa_t *rsa_read_pem_private_key(FILE *fp) {
- rsa_t *rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+ rsa_t *rsa;
+
+#if OPENSSL_VERSION_MAJOR < 3
+ rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+#else
+ rsa = read_key_from_pem(fp, OSSL_KEYMGMT_SELECT_PRIVATE_KEY);
+#endif
if(!rsa) {
- logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", ERR_error_string(ERR_get_error(), NULL));
+ openssl_err("read RSA private key");
}
return rsa;
}
size_t rsa_size(const rsa_t *rsa) {
+#if OPENSSL_VERSION_MAJOR < 3
return RSA_size(rsa);
+#else
+ return EVP_PKEY_get_size(rsa);
+#endif
}
bool rsa_public_encrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
+#if OPENSSL_VERSION_MAJOR < 3
+
if((size_t)RSA_public_encrypt((int) len, in, out, rsa, RSA_NO_PADDING) == len) {
return true;
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA encryption: %s", ERR_error_string(ERR_get_error(), NULL));
+#else
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(rsa, NULL);
+
+ if(ctx) {
+ size_t outlen = len;
+
+ bool ok = EVP_PKEY_encrypt_init(ctx) > 0
+ && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) > 0
+ && EVP_PKEY_encrypt(ctx, out, &outlen, in, len) > 0
+ && outlen == len;
+
+ EVP_PKEY_CTX_free(ctx);
+
+ if(ok) {
+ return true;
+ }
+ }
+
+#endif
+
+ openssl_err("perform RSA encryption");
return false;
}
bool rsa_private_decrypt(rsa_t *rsa, const void *in, size_t len, void *out) {
+#if OPENSSL_VERSION_MAJOR < 3
+
if((size_t)RSA_private_decrypt((int) len, in, out, rsa, RSA_NO_PADDING) == len) {
return true;
}
- logger(DEBUG_ALWAYS, LOG_ERR, "Unable to perform RSA decryption: %s", ERR_error_string(ERR_get_error(), NULL));
+#else
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(rsa, NULL);
+
+ if(ctx) {
+ size_t outlen = len;
+
+ bool ok = EVP_PKEY_decrypt_init(ctx) > 0
+ && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) > 0
+ && EVP_PKEY_decrypt(ctx, out, &outlen, in, len) > 0
+ && outlen == len;
+
+ EVP_PKEY_CTX_free(ctx);
+
+ if(ok) {
+ return true;
+ }
+ }
+
+#endif
+
+ openssl_err("perform RSA decryption");
return false;
}
void rsa_free(rsa_t *rsa) {
if(rsa) {
+#if OPENSSL_VERSION_MAJOR < 3
RSA_free(rsa);
+#else
+ EVP_PKEY_free(rsa);
+#endif
}
}
#include <openssl/err.h>
#define TINC_RSA_INTERNAL
+
+#if OPENSSL_VERSION_MAJOR < 3
typedef RSA rsa_t;
+#else
+typedef EVP_PKEY rsa_t;
+#include <openssl/encoder.h>
+#include <openssl/evp.h>
+#endif
#include "../logger.h"
#include "../rsagen.h"
+#include "log.h"
+#if OPENSSL_VERSION_MAJOR < 3
/* This function prettyprints the key generation process */
static int indicator(int a, int b, BN_GENCB *cb) {
return 1;
}
+#endif
// Generate RSA key
rsa_t *rsa_generate(size_t bits, unsigned long exponent) {
BIGNUM *bn_e = BN_new();
- rsa_t *rsa = RSA_new();
- BN_GENCB *cb = BN_GENCB_new();
+ rsa_t *rsa = NULL;
- if(!bn_e || !rsa || !cb) {
+ if(!bn_e) {
abort();
}
BN_set_word(bn_e, exponent);
+
+#if OPENSSL_VERSION_MAJOR < 3
+ rsa = RSA_new();
+ BN_GENCB *cb = BN_GENCB_new();
+
+ if(!rsa || !cb) {
+ abort();
+ }
+
BN_GENCB_set(cb, indicator, NULL);
int result = RSA_generate_key_ex(rsa, (int) bits, bn_e, cb);
BN_GENCB_free(cb);
- BN_free(bn_e);
if(!result) {
fprintf(stderr, "Error during key generation!\n");
RSA_free(rsa);
- return NULL;
+ rsa = NULL;
+ }
+
+#else
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+
+ bool ok = ctx
+ && EVP_PKEY_keygen_init(ctx) > 0
+ && EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn_e) > 0
+ && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)bits) > 0
+ && EVP_PKEY_keygen(ctx, &rsa) > 0;
+
+ if(ctx) {
+ EVP_PKEY_CTX_free(ctx);
}
+ if(!ok) {
+ openssl_err("generate key");
+ rsa = NULL;
+ }
+
+#endif
+
+ BN_free(bn_e);
+
return rsa;
}
// Write PEM RSA keys
+#if OPENSSL_VERSION_MAJOR >= 3
+static bool write_key_to_pem(const rsa_t *rsa, FILE *fp, int selection) {
+ OSSL_ENCODER_CTX *enc = OSSL_ENCODER_CTX_new_for_pkey(rsa, selection, "PEM", NULL, NULL);
+
+ if(!enc) {
+ openssl_err("create encoder context");
+ return false;
+ }
+
+ bool ok = OSSL_ENCODER_to_fp(enc, fp);
+ OSSL_ENCODER_CTX_free(enc);
+
+ if(!ok) {
+ openssl_err("write key to file");
+ }
+
+ return ok;
+}
+#endif
+
bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
+#if OPENSSL_VERSION_MAJOR < 3
return PEM_write_RSAPublicKey(fp, rsa);
+#else
+ return write_key_to_pem(rsa, fp, OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
+#endif
}
bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
+#if OPENSSL_VERSION_MAJOR < 3
return PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL);
+#else
+ return write_key_to_pem(rsa, fp, OSSL_KEYMGMT_SELECT_PRIVATE_KEY);
+#endif
}