From 15e035116bf2d3ccba251fc7bc39f5e2e5b7eed7 Mon Sep 17 00:00:00 2001 From: Dimitrios Apostolou Date: Wed, 25 Oct 2017 17:03:39 +0200 Subject: [PATCH 3/3] Merge pull request #2916 from jimis/openssl_1_1 CFE-2629: Openssl 1.1 compatibility --- cf-agent/cf-agent.c | 2 + cf-key/cf-key-functions.c | 6 +- cf-key/cf-key-functions.h | 1 + cf-serverd/cf-serverd-functions.c | 8 +- cf-serverd/server_classic.c | 49 ++- cf-serverd/server_common.c | 27 +- cf-serverd/server_tls.c | 4 +- configure.ac | 2 +- libcfnet/client_code.c | 32 +- libcfnet/client_protocol.c | 34 +- libcfnet/connection_info.h | 2 + libcfnet/key.h | 4 +- libcfnet/tls_generic.c | 4 +- libpromises/crypto.c | 58 +-- libpromises/files_hashes.c | 111 +++--- libpromises/files_hashes.h | 2 +- libpromises/generic_agent.c | 12 +- libpromises/locks.c | 32 +- libutils/Makefile.am | 1 + libutils/encode.c | 1 + libutils/hash.c | 69 ++-- libutils/hashes.c | 22 +- libutils/libcrypto-compat.c | 414 +++++++++++++++++++++ libutils/libcrypto-compat.h | 62 +++ libutils/string_lib.c | 2 + .../serial/nondefault_ciphers_tlsversion.srv | 4 +- tests/unit/Makefile.am | 12 - tests/unit/crypto_symmetric_test.c | 8 +- tests/unit/tls_generic_test.c | 11 + 29 files changed, 806 insertions(+), 190 deletions(-) create mode 100644 libutils/libcrypto-compat.c create mode 100644 libutils/libcrypto-compat.h diff --git a/cf-agent/cf-agent.c b/cf-agent/cf-agent.c index 9578b291b4ac..a11f6ff4daad 100644 --- a/cf-agent/cf-agent.c +++ b/cf-agent/cf-agent.c @@ -241,6 +241,8 @@ int main(int argc, char *argv[]) GenericAgentDiscoverContext(ctx, config); + /* FIXME: (CFE-2709) ALWAYS_VALIDATE will always be false here, since it can + * only change in KeepPromises(), five lines later on. */ Policy *policy = SelectAndLoadPolicy(config, ctx, ALWAYS_VALIDATE, true); if (!policy) diff --git a/cf-key/cf-key-functions.c b/cf-key/cf-key-functions.c index 68b1657e9ed8..ee994af6ad38 100644 --- a/cf-key/cf-key-functions.c +++ b/cf-key/cf-key-functions.c @@ -27,6 +27,7 @@ #include /* BN_*, BIGNUM */ #include /* RAND_* */ +#include #include #include @@ -48,6 +49,7 @@ RSA *LoadPublicKey(const char *filename) { FILE *fp; RSA *key; + const BIGNUM *n, *e; fp = safe_fopen(filename, "r"); if (fp == NULL) @@ -69,7 +71,9 @@ RSA *LoadPublicKey(const char *filename) fclose(fp); - if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e)) + RSA_get0_key(key, &n, &e, NULL); + + if (BN_num_bits(e) < 2 || !BN_is_odd(e)) { Log(LOG_LEVEL_ERR, "Error while reading public key '%s' - RSA Exponent is too small or not odd. (BN_num_bits: %s)", filename, GetErrorStr()); diff --git a/cf-key/cf-key-functions.h b/cf-key/cf-key-functions.h index 59b33a56cc6d..7080b2c624fa 100644 --- a/cf-key/cf-key-functions.h +++ b/cf-key/cf-key-functions.h @@ -39,6 +39,7 @@ #include #include + extern bool LOOKUP_HOSTS; RSA *LoadPublicKey(const char *filename); diff --git a/cf-serverd/cf-serverd-functions.c b/cf-serverd/cf-serverd-functions.c index 8d10a0f5487f..346c6493f925 100644 --- a/cf-serverd/cf-serverd-functions.c +++ b/cf-serverd/cf-serverd-functions.c @@ -869,7 +869,13 @@ static void AcceptAndHandle(EvalContext *ctx, int sd) int StartServer(EvalContext *ctx, Policy **policy, GenericAgentConfig *config) { InitSignals(); - ServerTLSInitialize(); + + bool tls_init_ok = ServerTLSInitialize(); + if (!tls_init_ok) + { + return -1; + } + int sd = SetServerListenState(ctx, QUEUESIZE, SERVER_LISTEN, &InitServer); /* Necessary for our use of select() to work in WaitForIncoming(): */ diff --git a/cf-serverd/server_classic.c b/cf-serverd/server_classic.c index 97bc8abb0c90..2ebec9a390c4 100644 --- a/cf-serverd/server_classic.c +++ b/cf-serverd/server_classic.c @@ -23,7 +23,9 @@ */ #include -#include /* BN_* */ +#include /* BN_* */ +#include /* ERR_get_error */ +#include #include #include /* IsMatchItemIn */ @@ -36,6 +38,7 @@ #include /* HashString */ #include /* HavePublicKey */ #include /* ReceiveCollectCall */ +#include #include "server.h" /* ServerConnectionState */ #include "server_common.h" /* ListPersistentClasses */ @@ -579,7 +582,11 @@ static int CheckStoreKey(ServerConnectionState *conn, RSA *key) "A public key was already known from %s/%s - no trust required", conn->hostname, conn->ipaddr); - if ((BN_cmp(savedkey->e, key->e) == 0) && (BN_cmp(savedkey->n, key->n) == 0)) + const BIGNUM *key_n, *key_e, *savedkey_n, *savedkey_e; + RSA_get0_key(key, &key_n, &key_e, NULL); + RSA_get0_key(savedkey, &savedkey_n, &savedkey_e, NULL); + + if ((BN_cmp(savedkey_e, key_e) == 0) && (BN_cmp(savedkey_n, key_n) == 0)) { Log(LOG_LEVEL_VERBOSE, "The public key identity was confirmed as %s@%s", @@ -770,8 +777,9 @@ char iscrypt, enterprise_field; HashString(challenge, challenge_len, digest, digestType); } +BIGNUM *newkey_n, *newkey_e; + /* proposition C2 - Receive client's public key modulus */ -RSA *newkey = RSA_new(); { int len_n = ReceiveTransaction(conn->conn_info, recvbuffer, NULL); @@ -779,16 +787,14 @@ RSA *newkey = RSA_new(); { Log(LOG_LEVEL_ERR, "Authentication failure: " "error while receiving public key modulus"); - RSA_free(newkey); return false; } - if ((newkey->n = BN_mpi2bn(recvbuffer, len_n, NULL)) == NULL) + if ((newkey_n = BN_mpi2bn(recvbuffer, len_n, NULL)) == NULL) { Log(LOG_LEVEL_ERR, "Authentication failure: " "private decrypt of received public key modulus failed " "(%s)", CryptoLastErrorString()); - RSA_free(newkey); return false; } } @@ -800,20 +806,38 @@ RSA *newkey = RSA_new(); { Log(LOG_LEVEL_ERR, "Authentication failure: " "error while receiving public key exponent"); - RSA_free(newkey); return false; } - if ((newkey->e = BN_mpi2bn(recvbuffer, len_e, NULL)) == NULL) + if ((newkey_e = BN_mpi2bn(recvbuffer, len_e, NULL)) == NULL) { Log(LOG_LEVEL_ERR, "Authentication failure: " "private decrypt of received public key exponent failed " "(%s)", CryptoLastErrorString()); - RSA_free(newkey); + BN_free(newkey_n); return false; } } +RSA *newkey = RSA_new(); +if (newkey == NULL) +{ + Log(LOG_LEVEL_ERR, "Failed to allocate RSA key: %s", + TLSErrorString(ERR_get_error())); + BN_free(newkey_n); + BN_free(newkey_e); + return false; +} +if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1) +{ + Log(LOG_LEVEL_ERR, "Failed to set RSA key: %s", + TLSErrorString(ERR_get_error())); + BN_free(newkey_n); + BN_free(newkey_e); + RSA_free(newkey); + return false; +} + /* Compute and store hash of the client's public key. */ { Key *key = KeyNew(newkey, CF_DEFAULT_DIGEST); @@ -897,12 +921,15 @@ RSA *newkey = RSA_new(); char bignum_buf[CF_BUFSIZE] = { 0 }; + const BIGNUM *n, *e; + RSA_get0_key(PUBKEY, &n, &e, NULL); + /* proposition S4 - conditional */ - int len_n = BN_bn2mpi(PUBKEY->n, bignum_buf); + int len_n = BN_bn2mpi(n, bignum_buf); SendTransaction(conn->conn_info, bignum_buf, len_n, CF_DONE); /* proposition S5 - conditional */ - int len_e = BN_bn2mpi(PUBKEY->e, bignum_buf); + int len_e = BN_bn2mpi(e, bignum_buf); SendTransaction(conn->conn_info, bignum_buf, len_e, CF_DONE); } } diff --git a/cf-serverd/server_common.c b/cf-serverd/server_common.c index 931689dff977..4cce4a7e9a1f 100644 --- a/cf-serverd/server_common.c +++ b/cf-serverd/server_common.c @@ -43,6 +43,7 @@ static const int CF_NOSIZE = -1; #include #include /* SendSocketStream */ #include /* SendTransaction,ReceiveTransaction */ +#include /* ERR_get_error */ #include /* TLSSend */ #include #include @@ -557,7 +558,6 @@ void CfEncryptGetFile(ServerFileGetState *args) unsigned char iv[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; int blocksize = CF_BUFSIZE - 4 * CF_INBAND_OFFSET; - EVP_CIPHER_CTX ctx; char *key, enctype; struct stat sb; ConnectionInfo *conn_info = args->conn->conn_info; @@ -579,9 +579,16 @@ void CfEncryptGetFile(ServerFileGetState *args) Log(LOG_LEVEL_INFO, "REFUSE access to file: %s", filename); RefuseAccess(args->conn, args->replyfile); FailedTransfer(conn_info); + return; } - EVP_CIPHER_CTX_init(&ctx); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + { + Log(LOG_LEVEL_ERR, "Failed to allocate cipher: %s", + TLSErrorString(ERR_get_error())); + return; + } if ((fd = safe_open(filename, O_RDONLY)) == -1) { @@ -630,20 +637,20 @@ void CfEncryptGetFile(ServerFileGetState *args) if (n_read > 0) { - EVP_EncryptInit_ex(&ctx, CfengineCipher(enctype), NULL, key, iv); + EVP_EncryptInit_ex(ctx, CfengineCipher(enctype), NULL, key, iv); - if (!EVP_EncryptUpdate(&ctx, out, &cipherlen, sendbuffer, n_read)) + if (!EVP_EncryptUpdate(ctx, out, &cipherlen, sendbuffer, n_read)) { FailedTransfer(conn_info); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); close(fd); return; } - if (!EVP_EncryptFinal_ex(&ctx, out + cipherlen, &finlen)) + if (!EVP_EncryptFinal_ex(ctx, out + cipherlen, &finlen)) { FailedTransfer(conn_info); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); close(fd); return; } @@ -654,7 +661,7 @@ void CfEncryptGetFile(ServerFileGetState *args) if (SendTransaction(conn_info, out, cipherlen + finlen, CF_DONE) == -1) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); close(fd); return; } @@ -666,14 +673,14 @@ void CfEncryptGetFile(ServerFileGetState *args) { Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr()); close(fd); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return; } } } } - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); close(fd); } diff --git a/cf-serverd/server_tls.c b/cf-serverd/server_tls.c index 2bbc17f55f1b..0edcfc9b3a54 100644 --- a/cf-serverd/server_tls.c +++ b/cf-serverd/server_tls.c @@ -186,7 +186,9 @@ void ServerTLSDeInitialize() */ int ServerTLSPeek(ConnectionInfo *conn_info) { - assert(SSLSERVERCONTEXT != NULL && PRIVKEY != NULL && PUBKEY != NULL); + assert(SSLSERVERCONTEXT != NULL); + assert(PRIVKEY != NULL); + assert(PUBKEY != NULL); assert(ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_UNDEFINED); diff --git a/configure.ac b/configure.ac index 93323facd299..2eab4527e85c 100644 --- a/configure.ac +++ b/configure.ac @@ -435,7 +435,7 @@ fi CF3_WITH_LIBRARY(openssl, [ AC_CHECK_LIB(crypto, RSA_generate_key_ex, [], []) - AC_CHECK_LIB(ssl, SSL_library_init, [], []) + AC_CHECK_LIB(ssl, SSL_free, [], []) AC_CHECK_DECLS([SSL_CTX_clear_options], [], [], [[#include ]]) AC_CHECK_HEADERS([openssl/opensslv.h], [], [AC_MSG_ERROR(Cannot find OpenSSL)]) diff --git a/libcfnet/client_code.c b/libcfnet/client_code.c index f6348a16e021..0c1314d720f9 100644 --- a/libcfnet/client_code.c +++ b/libcfnet/client_code.c @@ -28,6 +28,8 @@ #include #include /* RecvSocketStream */ #include /* SendTransaction,ReceiveTransaction */ +#include /* ERR_get_error */ +#include #include /* TLSTry */ #include /* TLSVerifyPeer */ #include @@ -42,7 +44,6 @@ #include /* MemSpan,MemSpanInverse */ #include /* ProgrammingError */ #include /* PRINTSIZE */ - #include /* LastSaw */ @@ -514,7 +515,6 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, char *buf, in[CF_BUFSIZE], out[CF_BUFSIZE], workbuf[CF_BUFSIZE], cfchangedstr[265]; unsigned char iv[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; - EVP_CIPHER_CTX crypto_ctx; snprintf(cfchangedstr, 255, "%s%s", CF_CHANGEDSTR1, CF_CHANGEDSTR2); @@ -543,7 +543,6 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, } workbuf[0] = '\0'; - EVP_CIPHER_CTX_init(&crypto_ctx); snprintf(in, CF_BUFSIZE - CF_PROTO_OFFSET, "GET dummykey %s", source); cipherlen = EncryptString(out, sizeof(out), in, strlen(in) + 1, conn->encryption_type, conn->session_key); @@ -568,6 +567,15 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, return false; } + EVP_CIPHER_CTX *crypto_ctx = EVP_CIPHER_CTX_new(); + if (crypto_ctx == NULL) + { + Log(LOG_LEVEL_ERR, "Failed to allocate cipher: %s", + TLSErrorString(ERR_get_error())); + close(dd); + return false; + } + buf = xmalloc(CF_BUFSIZE + sizeof(int)); bool last_write_made_hole = false; @@ -577,7 +585,9 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, { if ((cipherlen = ReceiveTransaction(conn->conn_info, buf, &more)) == -1) { + close(dd); free(buf); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } @@ -591,6 +601,7 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied", conn->this_server, source); close(dd); free(buf); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } @@ -599,22 +610,25 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, Log(LOG_LEVEL_INFO, "Source '%s:%s' changed while copying", conn->this_server, source); close(dd); free(buf); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } - EVP_DecryptInit_ex(&crypto_ctx, CfengineCipher(CfEnterpriseOptions()), NULL, conn->session_key, iv); + EVP_DecryptInit_ex(crypto_ctx, CfengineCipher(CfEnterpriseOptions()), NULL, conn->session_key, iv); - if (!EVP_DecryptUpdate(&crypto_ctx, workbuf, &plainlen, buf, cipherlen)) + if (!EVP_DecryptUpdate(crypto_ctx, workbuf, &plainlen, buf, cipherlen)) { close(dd); free(buf); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } - if (!EVP_DecryptFinal_ex(&crypto_ctx, workbuf + plainlen, &finlen)) + if (!EVP_DecryptFinal_ex(crypto_ctx, workbuf + plainlen, &finlen)) { close(dd); free(buf); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } @@ -631,7 +645,7 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, unlink(dest); close(dd); conn->error = true; - EVP_CIPHER_CTX_cleanup(&crypto_ctx); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } @@ -646,12 +660,12 @@ int EncryptCopyRegularFileNet(const char *source, const char *dest, off_t size, { unlink(dest); free(buf); - EVP_CIPHER_CTX_cleanup(&crypto_ctx); + EVP_CIPHER_CTX_free(crypto_ctx); return false; } free(buf); - EVP_CIPHER_CTX_cleanup(&crypto_ctx); + EVP_CIPHER_CTX_free(crypto_ctx); return true; } diff --git a/libcfnet/client_protocol.c b/libcfnet/client_protocol.c index ca2ddb4f94b1..db5909999ebe 100644 --- a/libcfnet/client_protocol.c +++ b/libcfnet/client_protocol.c @@ -24,7 +24,9 @@ #include -#include /* BN_* */ +#include /* BN_* */ +#include /* ERR_get_error */ +#include #include #include @@ -43,6 +45,7 @@ extern char VFQNAME[]; #include #include #include +#include /* TLSErrorString */ /*********************************************************************/ @@ -196,7 +199,10 @@ static bool SetSessionKey(AgentConnection *conn) return false; } - conn->session_key = (unsigned char *) bp->d; + conn->session_key = xmalloc(BN_num_bytes(bp)); + BN_bn2bin(bp, conn->session_key); + + BN_clear_free(bp); return true; } @@ -293,13 +299,16 @@ int AuthenticateAgent(AgentConnection *conn, bool trust_key) /*Send the public key - we don't know if server has it */ /* proposition C2 */ + const BIGNUM *pubkey_n, *pubkey_e; + RSA_get0_key(PUBKEY, &pubkey_n, &pubkey_e, NULL); + memset(sendbuffer, 0, CF_EXPANDSIZE); - len = BN_bn2mpi(PUBKEY->n, sendbuffer); + len = BN_bn2mpi(pubkey_n, sendbuffer); SendTransaction(conn->conn_info, sendbuffer, len, CF_DONE); /* No need to encrypt the public key ... */ /* proposition C3 */ memset(sendbuffer, 0, CF_EXPANDSIZE); - len = BN_bn2mpi(PUBKEY->e, sendbuffer); + len = BN_bn2mpi(pubkey_e, sendbuffer); SendTransaction(conn->conn_info, sendbuffer, len, CF_DONE); /* check reply about public key - server can break conn_info here */ @@ -432,7 +441,8 @@ int AuthenticateAgent(AgentConnection *conn, bool trust_key) return false; } - if ((newkey->n = BN_mpi2bn(in, len, NULL)) == NULL) + BIGNUM *newkey_n, *newkey_e; + if ((newkey_n = BN_mpi2bn(in, len, NULL)) == NULL) { Log(LOG_LEVEL_ERR, "Private key decrypt failed. (BN_mpi2bn: %s)", @@ -447,15 +457,27 @@ int AuthenticateAgent(AgentConnection *conn, bool trust_key) { Log(LOG_LEVEL_INFO, "Protocol error in RSA authentation from IP '%s'", conn->this_server); + BN_clear_free(newkey_n); RSA_free(newkey); return false; } - if ((newkey->e = BN_mpi2bn(in, len, NULL)) == NULL) + if ((newkey_e = BN_mpi2bn(in, len, NULL)) == NULL) { Log(LOG_LEVEL_ERR, "Public key decrypt failed. (BN_mpi2bn: %s)", CryptoLastErrorString()); + BN_clear_free(newkey_n); + RSA_free(newkey); + return false; + } + + if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1) + { + Log(LOG_LEVEL_ERR, "Failed to set RSA key: %s", + TLSErrorString(ERR_get_error())); + BN_clear_free(newkey_e); + BN_clear_free(newkey_n); RSA_free(newkey); return false; } diff --git a/libcfnet/connection_info.h b/libcfnet/connection_info.h index 4d1dfff2d73a..d2eaf46a95d0 100644 --- a/libcfnet/connection_info.h +++ b/libcfnet/connection_info.h @@ -27,7 +27,9 @@ #include + #include + #include diff --git a/libcfnet/key.h b/libcfnet/key.h index 5ddab0e09a9d..efebce763a7e 100644 --- a/libcfnet/key.h +++ b/libcfnet/key.h @@ -25,9 +25,11 @@ #ifndef KEY_H #define KEY_H -#include #include +#include + + /** @brief Structure to simplify the key management. diff --git a/libcfnet/tls_generic.c b/libcfnet/tls_generic.c index db74be34221d..0e255a4441d0 100644 --- a/libcfnet/tls_generic.c +++ b/libcfnet/tls_generic.c @@ -88,7 +88,7 @@ static int CompareCertToRSA(X509 *cert, RSA *rsa_key) TLSErrorString(ERR_get_error())); goto ret1; } - if (EVP_PKEY_type(cert_pkey->type) != EVP_PKEY_RSA) + if (EVP_PKEY_base_id(cert_pkey) != EVP_PKEY_RSA) { Log(LOG_LEVEL_ERR, "Received key of unknown type, only RSA currently supported!"); @@ -300,7 +300,7 @@ int TLSVerifyPeer(ConnectionInfo *conn_info, const char *remoteip, const char *u retval = -1; goto ret2; } - if (EVP_PKEY_type(received_pubkey->type) != EVP_PKEY_RSA) + if (EVP_PKEY_base_id(received_pubkey) != EVP_PKEY_RSA) { Log(LOG_LEVEL_ERR, "Received key of unknown type, only RSA currently supported!"); diff --git a/libpromises/crypto.c b/libpromises/crypto.c index 36fbb9c903c2..56138f7fbd2a 100644 --- a/libpromises/crypto.c +++ b/libpromises/crypto.c @@ -27,6 +27,7 @@ #include /* ERR_* */ #include /* RAND_* */ #include /* BN_* */ +#include #include #include @@ -220,11 +221,15 @@ bool LoadSecretKeys(void) fclose(fp); } - if (PUBKEY != NULL - && ((BN_num_bits(PUBKEY->e) < 2) || (!BN_is_odd(PUBKEY->e)))) + if (PUBKEY != NULL) { - Log(LOG_LEVEL_ERR, "The public key RSA exponent is too small or not odd"); - return false; + const BIGNUM *n, *e; + RSA_get0_key(PUBKEY, &n, &e, NULL); + if ((BN_num_bits(e) < 2) || (!BN_is_odd(e))) + { + Log(LOG_LEVEL_ERR, "The public key RSA exponent is too small or not odd"); + return false; + } } return true; @@ -366,12 +371,16 @@ RSA *HavePublicKey(const char *username, const char *ipaddress, const char *dige fclose(fp); - if ((BN_num_bits(newkey->e) < 2) || (!BN_is_odd(newkey->e))) { - Log(LOG_LEVEL_ERR, "RSA Exponent too small or not odd for key: %s", - newname); - RSA_free(newkey); - return NULL; + const BIGNUM *n, *e; + RSA_get0_key(newkey, &n, &e, NULL); + if ((BN_num_bits(e) < 2) || (!BN_is_odd(e))) + { + Log(LOG_LEVEL_ERR, "RSA Exponent too small or not odd for key: %s", + newname); + RSA_free(newkey); + return NULL; + } } return newkey; @@ -438,7 +447,6 @@ int EncryptString(char *out, size_t out_size, const char *in, int plainlen, int cipherlen = 0, tmplen; unsigned char iv[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; - EVP_CIPHER_CTX ctx; if (key == NULL) ProgrammingError("EncryptString: session key == NULL"); @@ -451,18 +459,18 @@ int EncryptString(char *out, size_t out_size, const char *in, int plainlen, max_ciphertext_size, out_size); } - EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit_ex(&ctx, CfengineCipher(type), NULL, key, iv); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_EncryptInit_ex(ctx, CfengineCipher(type), NULL, key, iv); - if (!EVP_EncryptUpdate(&ctx, out, &cipherlen, in, plainlen)) + if (!EVP_EncryptUpdate(ctx, out, &cipherlen, in, plainlen)) { - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return -1; } - if (!EVP_EncryptFinal_ex(&ctx, out + cipherlen, &tmplen)) + if (!EVP_EncryptFinal_ex(ctx, out + cipherlen, &tmplen)) { - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return -1; } @@ -474,7 +482,7 @@ int EncryptString(char *out, size_t out_size, const char *in, int plainlen, cipherlen, max_ciphertext_size); } - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return cipherlen; } @@ -521,7 +529,6 @@ int DecryptString(char *out, size_t out_size, const char *in, int cipherlen, int plainlen = 0, tmplen; unsigned char iv[32] = { 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; - EVP_CIPHER_CTX ctx; if (key == NULL) ProgrammingError("DecryptString: session key == NULL"); @@ -534,22 +541,22 @@ int DecryptString(char *out, size_t out_size, const char *in, int cipherlen, max_plaintext_size, out_size); } - EVP_CIPHER_CTX_init(&ctx); - EVP_DecryptInit_ex(&ctx, CfengineCipher(type), NULL, key, iv); + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + EVP_DecryptInit_ex(ctx, CfengineCipher(type), NULL, key, iv); - if (!EVP_DecryptUpdate(&ctx, out, &plainlen, in, cipherlen)) + if (!EVP_DecryptUpdate(ctx, out, &plainlen, in, cipherlen)) { Log(LOG_LEVEL_ERR, "Failed to decrypt string"); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return -1; } - if (!EVP_DecryptFinal_ex(&ctx, out + plainlen, &tmplen)) + if (!EVP_DecryptFinal_ex(ctx, out + plainlen, &tmplen)) { unsigned long err = ERR_get_error(); Log(LOG_LEVEL_ERR, "Failed to decrypt at final of cipher length %d. (EVP_DecryptFinal_ex: %s)", cipherlen, ERR_error_string(err, NULL)); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_free(ctx); return -1; } @@ -561,8 +568,7 @@ int DecryptString(char *out, size_t out_size, const char *in, int cipherlen, plainlen, max_plaintext_size); } - EVP_CIPHER_CTX_cleanup(&ctx); - + EVP_CIPHER_CTX_free(ctx); return plainlen; } diff --git a/libpromises/files_hashes.c b/libpromises/files_hashes.c index 8663e2d06081..ce9d54ea129d 100644 --- a/libpromises/files_hashes.c +++ b/libpromises/files_hashes.c @@ -24,8 +24,10 @@ #include +#include /* ERR_* */ #include /* BN_* */ #include /* EVP_* */ +#include #include #include @@ -40,7 +42,6 @@ void HashFile(const char *filename, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type) { FILE *file; - EVP_MD_CTX context; int len, md_len; unsigned char buffer[1024]; const EVP_MD *md = NULL; @@ -48,30 +49,37 @@ void HashFile(const char *filename, unsigned char digest[EVP_MAX_MD_SIZE + 1], H if ((file = safe_fopen(filename, "rb")) == NULL) { Log(LOG_LEVEL_INFO, "Cannot open file for hashing '%s'. (fopen: %s)", filename, GetErrorStr()); + return; } - else - { - md = EVP_get_digestbyname(HashNameFromId(type)); - EVP_DigestInit(&context, md); + md = EVP_get_digestbyname(HashNameFromId(type)); + EVP_MD_CTX *context = EVP_MD_CTX_new(); + if (context == NULL) + { + Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context"); + return; + } + + if (EVP_DigestInit(context, md) == 1) + { while ((len = fread(buffer, 1, 1024, file))) { - EVP_DigestUpdate(&context, buffer, len); + EVP_DigestUpdate(context, buffer, len); } - EVP_DigestFinal(&context, digest, &md_len); - - /* Digest length stored in md_len */ - fclose(file); + EVP_DigestFinal(context, digest, &md_len); } + + /* Digest length stored in md_len */ + fclose(file); + EVP_MD_CTX_free(context); } /*******************************************************************/ void HashString(const char *buffer, int len, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type) { - EVP_MD_CTX context; const EVP_MD *md = NULL; int md_len; @@ -89,10 +97,18 @@ void HashString(const char *buffer, int len, unsigned char digest[EVP_MAX_MD_SIZ { Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", HashNameFromId(type)); } - else if (EVP_DigestInit(&context, md)) + + EVP_MD_CTX *context = EVP_MD_CTX_new(); + if (context == NULL) + { + Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context"); + return; + } + + if (EVP_DigestInit(context, md) == 1) { - EVP_DigestUpdate(&context, (unsigned char *) buffer, (size_t) len); - EVP_DigestFinal(&context, digest, &md_len); + EVP_DigestUpdate(context, buffer, len); + EVP_DigestFinal(context, digest, &md_len); } else { @@ -100,63 +116,60 @@ void HashString(const char *buffer, int len, unsigned char digest[EVP_MAX_MD_SIZ // TODO: handle this someway } + EVP_MD_CTX_free(context); break; } } /*******************************************************************/ -void HashPubKey(RSA *key, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type) +void HashPubKey(const RSA *key, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type) { - EVP_MD_CTX context; - const EVP_MD *md = NULL; - int md_len, i, buf_len, actlen; - unsigned char *buffer; - - if (key->n) + if (type == HASH_METHOD_CRYPT) { - buf_len = (size_t) BN_num_bytes(key->n); + Log(LOG_LEVEL_ERR, "The crypt support is not presently implemented, please use sha256 instead"); + return; } - else + + const EVP_MD *md = EVP_get_digestbyname(HashNameFromId(type)); + if (md == NULL) { - buf_len = 0; + Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", HashNameFromId(type)); } - if (key->e) + EVP_MD_CTX *context = EVP_MD_CTX_new(); + if (context == NULL) { - if (buf_len < (i = (size_t) BN_num_bytes(key->e))) - { - buf_len = i; - } + Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context"); + return; } - buffer = xmalloc(buf_len + 10); + const BIGNUM *n, *e; + RSA_get0_key(key, &n, &e, NULL); - switch (type) - { - case HASH_METHOD_CRYPT: - Log(LOG_LEVEL_ERR, "The crypt support is not presently implemented, please use sha256 instead"); - break; + size_t n_len = (n == NULL) ? 0 : (size_t) BN_num_bytes(n); + size_t e_len = (e == NULL) ? 0 : (size_t) BN_num_bytes(e); + size_t buf_len = MAX(n_len, e_len); - default: - md = EVP_get_digestbyname(HashNameFromId(type)); + unsigned char buffer[buf_len]; + int md_len, actlen; - if (md == NULL) - { - Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", HashNameFromId(type)); - } + if (EVP_DigestInit(context, md) == 1) + { + actlen = BN_bn2bin(n, buffer); + CF_ASSERT(actlen <= buf_len, "Buffer overflow n, %d > %zu!", + actlen, buf_len); + EVP_DigestUpdate(context, buffer, actlen); - EVP_DigestInit(&context, md); + actlen = BN_bn2bin(e, buffer); + CF_ASSERT(actlen <= buf_len, "Buffer overflow e, %d > %zu!", + actlen, buf_len); + EVP_DigestUpdate(context, buffer, actlen); - actlen = BN_bn2bin(key->n, buffer); - EVP_DigestUpdate(&context, buffer, actlen); - actlen = BN_bn2bin(key->e, buffer); - EVP_DigestUpdate(&context, buffer, actlen); - EVP_DigestFinal(&context, digest, &md_len); - break; + EVP_DigestFinal(context, digest, &md_len); } - free(buffer); + EVP_MD_CTX_free(context); } /*******************************************************************/ diff --git a/libpromises/files_hashes.h b/libpromises/files_hashes.h index 0f6194291593..636a9ab2cd35 100644 --- a/libpromises/files_hashes.h +++ b/libpromises/files_hashes.h @@ -40,7 +40,7 @@ int HashesMatch(const unsigned char digest1[EVP_MAX_MD_SIZE + 1], char *HashPrintSafe(char *dst, size_t dst_size, const unsigned char *digest, HashMethod type, bool use_prefix); char *SkipHashType(char *hash); -void HashPubKey(RSA *key, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type); +void HashPubKey(const RSA *key, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type); #endif diff --git a/libpromises/generic_agent.c b/libpromises/generic_agent.c index b8c32f0baf59..0a247e55ee83 100644 --- a/libpromises/generic_agent.c +++ b/libpromises/generic_agent.c @@ -66,6 +66,9 @@ #include #include #include +#include +#include + static pthread_once_t pid_cleanup_once = PTHREAD_ONCE_INIT; /* GLOBAL_T */ @@ -1163,16 +1166,17 @@ static bool GeneratePolicyReleaseIDFromTree(char *release_id_out, size_t out_siz } // fallback, produce some pseudo sha1 hash - EVP_MD_CTX crypto_ctx; - EVP_DigestInit(&crypto_ctx, EVP_get_digestbyname(HashNameFromId(GENERIC_AGENT_CHECKSUM_METHOD))); + EVP_MD_CTX *crypto_ctx = EVP_MD_CTX_new(); + EVP_DigestInit(crypto_ctx, EVP_get_digestbyname(HashNameFromId(GENERIC_AGENT_CHECKSUM_METHOD))); bool success = HashDirectoryTree(policy_dir, (const char *[]) { ".cf", ".dat", ".txt", ".conf", ".mustache", ".json", ".yaml", NULL}, - &crypto_ctx); + crypto_ctx); int md_len; unsigned char digest[EVP_MAX_MD_SIZE + 1] = { 0 }; - EVP_DigestFinal(&crypto_ctx, digest, &md_len); + EVP_DigestFinal(crypto_ctx, digest, &md_len); + EVP_MD_CTX_free(crypto_ctx); HashPrintSafe(release_id_out, out_size, digest, GENERIC_AGENT_CHECKSUM_METHOD, false); diff --git a/libpromises/locks.c b/libpromises/locks.c index 8ebac0cd4a92..5f2542ee4def 100644 --- a/libpromises/locks.c +++ b/libpromises/locks.c @@ -39,6 +39,9 @@ #include #include #include +#include +#include + #define CFLOGSIZE 1048576 /* Size of lock-log before rotation */ #define CF_LOCKHORIZON ((time_t)(SECONDS_PER_WEEK * 4)) @@ -509,7 +512,7 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges { static const char PACK_UPIFELAPSED_SALT[] = "packageuplist"; - EVP_MD_CTX context; + EVP_MD_CTX *context = EVP_MD_CTX_new(); int md_len; const EVP_MD *md = NULL; Rlist *rp; @@ -520,29 +523,29 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges md = EVP_get_digestbyname(HashNameFromId(type)); - EVP_DigestInit(&context, md); + EVP_DigestInit(context, md); // multiple packages (promisers) may share same package_list_update_ifelapsed lock if ( (!salt) || strcmp(salt, PACK_UPIFELAPSED_SALT) ) { - EVP_DigestUpdate(&context, pp->promiser, strlen(pp->promiser)); + EVP_DigestUpdate(context, pp->promiser, strlen(pp->promiser)); } if (pp->comment) { - EVP_DigestUpdate(&context, pp->comment, strlen(pp->comment)); + EVP_DigestUpdate(context, pp->comment, strlen(pp->comment)); } if (pp->parent_promise_type && pp->parent_promise_type->parent_bundle) { if (pp->parent_promise_type->parent_bundle->ns) { - EVP_DigestUpdate(&context, pp->parent_promise_type->parent_bundle->ns, strlen(pp->parent_promise_type->parent_bundle->ns)); + EVP_DigestUpdate(context, pp->parent_promise_type->parent_bundle->ns, strlen(pp->parent_promise_type->parent_bundle->ns)); } if (pp->parent_promise_type->parent_bundle->name) { - EVP_DigestUpdate(&context, pp->parent_promise_type->parent_bundle->name, strlen(pp->parent_promise_type->parent_bundle->name)); + EVP_DigestUpdate(context, pp->parent_promise_type->parent_bundle->name, strlen(pp->parent_promise_type->parent_bundle->name)); } } @@ -550,7 +553,7 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges if (salt) { - EVP_DigestUpdate(&context, salt, strlen(salt)); + EVP_DigestUpdate(context, salt, strlen(salt)); } if (pp->conlist) @@ -559,7 +562,7 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges { Constraint *cp = SeqAt(pp->conlist, i); - EVP_DigestUpdate(&context, cp->lval, strlen(cp->lval)); + EVP_DigestUpdate(context, cp->lval, strlen(cp->lval)); // don't hash rvals that change (e.g. times) doHash = true; @@ -581,13 +584,13 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges switch (cp->rval.type) { case RVAL_TYPE_SCALAR: - EVP_DigestUpdate(&context, cp->rval.item, strlen(cp->rval.item)); + EVP_DigestUpdate(context, cp->rval.item, strlen(cp->rval.item)); break; case RVAL_TYPE_LIST: for (rp = cp->rval.item; rp != NULL; rp = rp->next) { - EVP_DigestUpdate(&context, RlistScalarValue(rp), strlen(RlistScalarValue(rp))); + EVP_DigestUpdate(context, RlistScalarValue(rp), strlen(RlistScalarValue(rp))); } break; @@ -597,18 +600,18 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges fp = (FnCall *) cp->rval.item; - EVP_DigestUpdate(&context, fp->name, strlen(fp->name)); + EVP_DigestUpdate(context, fp->name, strlen(fp->name)); for (rp = fp->args; rp != NULL; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: - EVP_DigestUpdate(&context, RlistScalarValue(rp), strlen(RlistScalarValue(rp))); + EVP_DigestUpdate(context, RlistScalarValue(rp), strlen(RlistScalarValue(rp))); break; case RVAL_TYPE_FNCALL: - EVP_DigestUpdate(&context, RlistFnCallValue(rp)->name, strlen(RlistFnCallValue(rp)->name)); + EVP_DigestUpdate(context, RlistFnCallValue(rp)->name, strlen(RlistFnCallValue(rp)->name)); break; default: @@ -624,7 +627,8 @@ void PromiseRuntimeHash(const Promise *pp, const char *salt, unsigned char diges } } - EVP_DigestFinal(&context, digest, &md_len); + EVP_DigestFinal(context, digest, &md_len); + EVP_MD_CTX_free(context); /* Digest length stored in md_len */ } diff --git a/libutils/Makefile.am b/libutils/Makefile.am index c55379418a7a..f9dc629ceb6e 100644 --- a/libutils/Makefile.am +++ b/libutils/Makefile.am @@ -75,6 +75,7 @@ libutils_la_SOURCES = \ regex.c regex.h \ encode.c encode.h \ pcre_wrap.c pcre_wrap.h \ + libcrypto-compat.c libcrypto-compat.h \ printsize.h if !NT diff --git a/libutils/encode.c b/libutils/encode.c index c0ee32714767..dc03729f8f1d 100644 --- a/libutils/encode.c +++ b/libutils/encode.c @@ -28,6 +28,7 @@ #include /* BUF_MEM */ #include /* BIO_* */ #include /* BIO_f_base64 */ +#include #include diff --git a/libutils/hash.c b/libutils/hash.c index 4e27152698ff..9a52944fb8f4 100644 --- a/libutils/hash.c +++ b/libutils/hash.c @@ -26,10 +26,13 @@ #include /* EVP_* */ #include /* BN_bn2bin */ +#include #include #include #include +#include + static const char *const CF_DIGEST_TYPES[10] = { @@ -198,49 +201,55 @@ Hash *HashNewFromKey(const RSA *rsa, HashMethod method) { return NULL; } - EVP_MD_CTX *context = NULL; - const EVP_MD *md = NULL; - int md_len = 0; - unsigned char *buffer = NULL; - int buffer_length = 0; - int actual_length = 0; - if (rsa->n) - { - buffer_length = (size_t) BN_num_bytes(rsa->n); - } - else + const BIGNUM *n, *e; + RSA_get0_key(rsa, &n, &e, NULL); + + size_t n_len = (n == NULL) ? 0 : (size_t) BN_num_bytes(n); + size_t e_len = (e == NULL) ? 0 : (size_t) BN_num_bytes(e); + size_t buf_len = MAX(n_len, e_len); + + const EVP_MD *md = EVP_get_digestbyname(CF_DIGEST_TYPES[method]); + if (md == NULL) { - buffer_length = 0; + Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", CF_DIGEST_TYPES[method]); + return NULL; } - if (rsa->e) + EVP_MD_CTX *context = EVP_MD_CTX_new(); + if (context == NULL) { - if (buffer_length < (size_t) BN_num_bytes(rsa->e)) - { - buffer_length = (size_t) BN_num_bytes(rsa->e); - } + Log(LOG_LEVEL_ERR, "Failed to allocate openssl hashing context"); + return NULL; } - md = EVP_get_digestbyname(CF_DIGEST_TYPES[method]); - if (md == NULL) + + if (EVP_DigestInit_ex(context, md, NULL) != 1) { - Log(LOG_LEVEL_INFO, "Digest type %s not supported by OpenSSL library", CF_DIGEST_TYPES[method]); + EVP_MD_CTX_free(context); return NULL; } + + unsigned char buffer[buf_len]; + int md_len, actlen; + + actlen = BN_bn2bin(n, buffer); + CF_ASSERT(actlen <= buf_len, "Buffer overflow n, %d > %zu!", + actlen, buf_len); + EVP_DigestUpdate(context, buffer, actlen); + + actlen = BN_bn2bin(e, buffer); + CF_ASSERT(actlen <= buf_len, "Buffer overflow e, %d > %zu!", + actlen, buf_len); + EVP_DigestUpdate(context, buffer, actlen); + Hash *hash = HashBasicInit(method); - context = EVP_MD_CTX_create(); - EVP_DigestInit_ex(context, md, NULL); - buffer = xmalloc(buffer_length); - actual_length = BN_bn2bin(rsa->n, buffer); - EVP_DigestUpdate(context, buffer, actual_length); - actual_length = BN_bn2bin(rsa->e, buffer); - EVP_DigestUpdate(context, buffer, actual_length); EVP_DigestFinal_ex(context, hash->digest, &md_len); - EVP_MD_CTX_destroy(context); - free (buffer); + + EVP_MD_CTX_free(context); + /* Update the printable representation */ HashCalculatePrintableRepresentation(hash); - /* Return the hash */ + return hash; } diff --git a/libutils/hashes.c b/libutils/hashes.c index b074ed2e43c5..1213c886ca77 100644 --- a/libutils/hashes.c +++ b/libutils/hashes.c @@ -27,6 +27,7 @@ #include #include +#include int FileChecksum(const char *filename, unsigned char digest[EVP_MAX_MD_SIZE + 1]) @@ -40,25 +41,36 @@ int FileChecksum(const char *filename, unsigned char digest[EVP_MAX_MD_SIZE + 1] else { const EVP_MD *md = EVP_get_digestbyname("md5"); - if (!md) { fclose(file); return 0; } - EVP_MD_CTX context; - EVP_DigestInit(&context, md); + EVP_MD_CTX *context = EVP_MD_CTX_new(); + if (context == NULL) + { + fclose(file); + return 0; + } + + if (EVP_DigestInit_ex(context, md, NULL) != 1) + { + fclose(file); + EVP_MD_CTX_free(context); + return 0; + } int len = 0; unsigned char buffer[1024]; while ((len = fread(buffer, 1, 1024, file))) { - EVP_DigestUpdate(&context, buffer, len); + EVP_DigestUpdate(context, buffer, len); } unsigned int md_len = 0; - EVP_DigestFinal(&context, digest, &md_len); + EVP_DigestFinal(context, digest, &md_len); + EVP_MD_CTX_free(context); fclose(file); return md_len; diff --git a/libutils/libcrypto-compat.c b/libutils/libcrypto-compat.c new file mode 100644 index 000000000000..3fc39092a16d --- /dev/null +++ b/libutils/libcrypto-compat.c @@ -0,0 +1,414 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + + +#include + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#include +#include +#include /* BN_* */ + + +static void *OPENSSL_zalloc(size_t num) +{ + void *ret = OPENSSL_malloc(num); + + if (ret != NULL) + memset(ret, 0, num); + return ret; +} + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) +{ + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) + || (r->e == NULL && e == NULL)) + return 0; + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} + +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) +{ + /* If the fields p and q in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->p == NULL && p == NULL) + || (r->q == NULL && q == NULL)) + return 0; + + if (p != NULL) { + BN_free(r->p); + r->p = p; + } + if (q != NULL) { + BN_free(r->q); + r->q = q; + } + + return 1; +} + +int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) +{ + /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->dmp1 == NULL && dmp1 == NULL) + || (r->dmq1 == NULL && dmq1 == NULL) + || (r->iqmp == NULL && iqmp == NULL)) + return 0; + + if (dmp1 != NULL) { + BN_free(r->dmp1); + r->dmp1 = dmp1; + } + if (dmq1 != NULL) { + BN_free(r->dmq1); + r->dmq1 = dmq1; + } + if (iqmp != NULL) { + BN_free(r->iqmp); + r->iqmp = iqmp; + } + + return 1; +} + +void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} + +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) +{ + if (p != NULL) + *p = r->p; + if (q != NULL) + *q = r->q; +} + +void RSA_get0_crt_params(const RSA *r, + const BIGNUM **dmp1, const BIGNUM **dmq1, + const BIGNUM **iqmp) +{ + if (dmp1 != NULL) + *dmp1 = r->dmp1; + if (dmq1 != NULL) + *dmq1 = r->dmq1; + if (iqmp != NULL) + *iqmp = r->iqmp; +} + +void DSA_get0_pqg(const DSA *d, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; +} + +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p, q and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((d->p == NULL && p == NULL) + || (d->q == NULL && q == NULL) + || (d->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(d->p); + d->p = p; + } + if (q != NULL) { + BN_free(d->q); + d->q = q; + } + if (g != NULL) { + BN_free(d->g); + d->g = g; + } + + return 1; +} + +void DSA_get0_key(const DSA *d, + const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = d->pub_key; + if (priv_key != NULL) + *priv_key = d->priv_key; +} + +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in d is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (d->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(d->pub_key); + d->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(d->priv_key); + d->priv_key = priv_key; + } + + return 1; +} + +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void DH_get0_pqg(const DH *dh, + const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + *p = dh->p; + if (q != NULL) + *q = dh->q; + if (g != NULL) + *g = dh->g; +} + +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) +{ + /* If the fields p and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. q may remain NULL. + */ + if ((dh->p == NULL && p == NULL) + || (dh->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(dh->p); + dh->p = p; + } + if (q != NULL) { + BN_free(dh->q); + dh->q = q; + } + if (g != NULL) { + BN_free(dh->g); + dh->g = g; + } + + if (q != NULL) { + dh->length = BN_num_bits(q); + } + + return 1; +} + +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) +{ + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) +{ + /* If the field pub_key in dh is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (dh->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +int DH_set_length(DH *dh, long length) +{ + dh->length = length; + return 1; +} + +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) +{ + return ctx->iv; +} + +EVP_MD_CTX *EVP_MD_CTX_new(void) +{ + return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); +} + +void EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth) +{ + RSA_METHOD *ret; + + ret = OPENSSL_malloc(sizeof(RSA_METHOD)); + + if (ret != NULL) { + memcpy(ret, meth, sizeof(*meth)); + ret->name = OPENSSL_strdup(meth->name); + if (ret->name == NULL) { + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name) +{ + char *tmpname; + + tmpname = OPENSSL_strdup(name); + if (tmpname == NULL) { + return 0; + } + + OPENSSL_free((char *)meth->name); + meth->name = tmpname; + + return 1; +} + +int RSA_meth_set_priv_enc(RSA_METHOD *meth, + int (*priv_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_enc = priv_enc; + return 1; +} + +int RSA_meth_set_priv_dec(RSA_METHOD *meth, + int (*priv_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + meth->rsa_priv_dec = priv_dec; + return 1; +} + +int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) +{ + meth->finish = finish; + return 1; +} + +void RSA_meth_free(RSA_METHOD *meth) +{ + if (meth != NULL) { + OPENSSL_free((char *)meth->name); + OPENSSL_free(meth); + } +} + +int RSA_bits(const RSA *r) +{ + return (BN_num_bits(r->n)); +} + +RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) +{ + if (pkey->type != EVP_PKEY_RSA) { + return NULL; + } + return pkey->pkey.rsa; +} + + +#endif /* OPENSSL_VERSION_NUMBER */ diff --git a/libutils/libcrypto-compat.h b/libutils/libcrypto-compat.h new file mode 100644 index 000000000000..fa3eb1444a1e --- /dev/null +++ b/libutils/libcrypto-compat.h @@ -0,0 +1,62 @@ +#ifndef LIBCRYPTO_COMPAT_H +#define LIBCRYPTO_COMPAT_H + +#include +#include + + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + +#include +#include +#include +#include +#include +#include + +int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); +int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q); +int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp); +void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); +void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q); +void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp); + +void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key); +int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key); + +void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); +int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); +int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s); + +void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); +int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); +void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); +int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); +int DH_set_length(DH *dh, long length); + +const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); +unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); +EVP_MD_CTX *EVP_MD_CTX_new(void); +void EVP_MD_CTX_free(EVP_MD_CTX *ctx); +#define EVP_CIPHER_impl_ctx_size(e) e->ctx_size +#define EVP_CIPHER_CTX_get_cipher_data(ctx) ctx->cipher_data + +RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth); +int RSA_meth_set1_name(RSA_METHOD *meth, const char *name); +#define RSA_meth_get_finish(meth) meth->finish +int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); +int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); +int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)); +void RSA_meth_free(RSA_METHOD *meth); + +int RSA_bits(const RSA *r); + +RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); + +#endif /* OPENSSL_VERSION_NUMBER */ + +#endif /* LIBCRYPTO_COMPAT_H */ diff --git a/libutils/string_lib.c b/libutils/string_lib.c index 8f4d58dcb376..2b8ef041eee6 100644 --- a/libutils/string_lib.c +++ b/libutils/string_lib.c @@ -28,12 +28,14 @@ #include /* BUF_MEM */ #include /* BIO_* */ #include /* BIO_f_base64 */ +#include #include #include #include #include + char *StringVFormat(const char *fmt, va_list ap) { char *value; diff --git a/tests/acceptance/16_cf-serverd/serial/nondefault_ciphers_tlsversion.srv b/tests/acceptance/16_cf-serverd/serial/nondefault_ciphers_tlsversion.srv index 39ed761fbc9d..9dad9f2a066d 100644 --- a/tests/acceptance/16_cf-serverd/serial/nondefault_ciphers_tlsversion.srv +++ b/tests/acceptance/16_cf-serverd/serial/nondefault_ciphers_tlsversion.srv @@ -14,8 +14,8 @@ body server control { port => "9888"; - # Only this non-default cipher is to be accepted - allowciphers => "RC4-MD5"; + # Only this cipher is to be accepted + allowciphers => "AES128-GCM-SHA256"; # Allow only TLSv1.1 or higher allowtlsversion => "1.1"; diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 9db71ed02184..073973c64158 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -420,18 +420,6 @@ mon_load_test_LDADD = ../../libpromises/libpromises.la libtest.la mon_processes_test_SOURCES = mon_processes_test.c ../../cf-monitord/mon.h ../../cf-monitord/mon_processes.c mon_processes_test_LDADD = ../../libpromises/libpromises.la libtest.la -# tls_generic_test uses stub functions interposition which does not work (yet) -# under OS X. Another way of stubbing functions from libpromises is needed. -if !XNU -check_PROGRAMS += tls_generic_test -tls_generic_test_SOURCES = tls_generic_test.c -tls_generic_test_LDADD = libtest.la \ - ../../libutils/libutils.la \ - ../../libpromises/libpromises.la \ - ../../libcfnet/libcfnet.la \ - ../../cf-serverd/libcf-serverd.la -endif - version_test_SOURCES = version_test.c hash_test_SOURCES = hash_test.c diff --git a/tests/unit/crypto_symmetric_test.c b/tests/unit/crypto_symmetric_test.c index 8bbdc4546079..89a34d040f31 100644 --- a/tests/unit/crypto_symmetric_test.c +++ b/tests/unit/crypto_symmetric_test.c @@ -30,11 +30,11 @@ static void test_cipher_init(void) { unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; unsigned char iv[] = {1,2,3,4,5,6,7,8}; - EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(&ctx); - EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv); - EVP_CIPHER_CTX_cleanup(&ctx); + EVP_CIPHER_CTX_init(ctx); + EVP_EncryptInit_ex(ctx, EVP_bf_cbc(), NULL, key, iv); + EVP_CIPHER_CTX_free(ctx); } static void test_symmetric_encrypt(void) diff --git a/tests/unit/tls_generic_test.c b/tests/unit/tls_generic_test.c index 69579ecbf457..4b98c901c999 100644 --- a/tests/unit/tls_generic_test.c +++ b/tests/unit/tls_generic_test.c @@ -1,3 +1,14 @@ +/* + * WARNING: THIS TEST HAS BEEN DISABLED + * + * This test is written in a very unportable manner: it replicates source code + * of OpenSSL, it uses internals of data structures etc. Do not re-enable it + * unless you delete all the code from the OpenSSL internals, and refactor it + * to mock the library routines properly, for example with `ld --wrap`. See + * "CMocka" and "Mimick" unit testing frameworks. + */ + + #include #include -- 2.15.0