cfengine/0003-Merge-pull-request-2916-from-jimis-openssl_1_1.patch

1903 lines
61 KiB
Diff

From 15e035116bf2d3ccba251fc7bc39f5e2e5b7eed7 Mon Sep 17 00:00:00 2001
From: Dimitrios Apostolou <jimis@northern.tech>
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 <openssl/bn.h> /* BN_*, BIGNUM */
#include <openssl/rand.h> /* RAND_* */
+#include <libcrypto-compat.h>
#include <lastseen.h>
#include <dir.h>
@@ -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 <eval_context.h>
#include <crypto.h>
+
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 <platform.h>
-#include <openssl/bn.h> /* BN_* */
+#include <openssl/bn.h> /* BN_* */
+#include <openssl/err.h> /* ERR_get_error */
+#include <libcrypto-compat.h>
#include <cf3.defs.h>
#include <item_lib.h> /* IsMatchItemIn */
@@ -36,6 +38,7 @@
#include <files_hashes.h> /* HashString */
#include <crypto.h> /* HavePublicKey */
#include <cf-serverd-enterprise-stubs.h> /* ReceiveCollectCall */
+#include <tls_generic.h>
#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 <pipes.h>
#include <classic.h> /* SendSocketStream */
#include <net.h> /* SendTransaction,ReceiveTransaction */
+#include <openssl/err.h> /* ERR_get_error */
#include <tls_generic.h> /* TLSSend */
#include <rlist.h>
#include <cf-serverd-enterprise-stubs.h>
@@ -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 <openssl/ssl.h>]])
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 <connection_info.h>
#include <classic.h> /* RecvSocketStream */
#include <net.h> /* SendTransaction,ReceiveTransaction */
+#include <openssl/err.h> /* ERR_get_error */
+#include <libcrypto-compat.h>
#include <tls_client.h> /* TLSTry */
#include <tls_generic.h> /* TLSVerifyPeer */
#include <dir.h>
@@ -42,7 +44,6 @@
#include <string_lib.h> /* MemSpan,MemSpanInverse */
#include <misc_lib.h> /* ProgrammingError */
#include <printsize.h> /* PRINTSIZE */
-
#include <lastseen.h> /* 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 <client_protocol.h>
-#include <openssl/bn.h> /* BN_* */
+#include <openssl/bn.h> /* BN_* */
+#include <openssl/err.h> /* ERR_get_error */
+#include <libcrypto-compat.h>
#include <communication.h>
#include <net.h>
@@ -43,6 +45,7 @@ extern char VFQNAME[];
#include <known_dirs.h>
#include <hash.h>
#include <connection_info.h>
+#include <tls_generic.h> /* 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 <platform.h>
+
#include <openssl/ssl.h>
+
#include <key.h>
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 <hash.h>
#include <openssl/rsa.h>
+#include <hash.h>
+
+
/**
@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 <openssl/err.h> /* ERR_* */
#include <openssl/rand.h> /* RAND_* */
#include <openssl/bn.h> /* BN_* */
+#include <libcrypto-compat.h>
#include <cf3.defs.h>
#include <lastseen.h>
@@ -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 <files_hashes.h>
+#include <openssl/err.h> /* ERR_* */
#include <openssl/bn.h> /* BN_* */
#include <openssl/evp.h> /* EVP_* */
+#include <libcrypto-compat.h>
#include <dbm_api.h>
#include <files_interfaces.h>
@@ -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 <loading.h>
#include <signals.h>
#include <addr_lib.h>
+#include <openssl/evp.h>
+#include <libcrypto-compat.h>
+
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 <misc_lib.h>
#include <known_dirs.h>
#include <sysinfo.h>
+#include <openssl/evp.h>
+#include <libcrypto-compat.h>
+
#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 <openssl/buffer.h> /* BUF_MEM */
#include <openssl/bio.h> /* BIO_* */
#include <openssl/evp.h> /* BIO_f_base64 */
+#include <libcrypto-compat.h>
#include <alloc.h>
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 <openssl/evp.h> /* EVP_* */
#include <openssl/bn.h> /* BN_bn2bin */
+#include <libcrypto-compat.h>
#include <alloc.h>
#include <logging.h>
#include <hash.h>
+#include <misc_lib.h>
+
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 <file_lib.h>
#include <openssl/evp.h>
+#include <libcrypto-compat.h>
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 <libcrypto-compat.h>
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <string.h>
+#include <openssl/engine.h>
+#include <openssl/bn.h> /* 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 <platform.h>
+#include <openssl/opensslv.h>
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+
+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 <openssl/buffer.h> /* BUF_MEM */
#include <openssl/bio.h> /* BIO_* */
#include <openssl/evp.h> /* BIO_f_base64 */
+#include <libcrypto-compat.h>
#include <alloc.h>
#include <writer.h>
#include <misc_lib.h>
#include <logging.h>
+
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 <test.h>
#include <sys/socket.h>
--
2.15.0