/** * We directly initiate a TLS handshake with the server. If the server is old * version (does not speak TLS) the connection will be denied. * @note the socket file descriptor in #conn_info must be connected and *not* * non-blocking * @return -1 in case of error */ int TLSTry(ConnectionInfo *conn_info) { if (PRIVKEY == NULL || PUBKEY == NULL) { Log(LOG_LEVEL_ERR, "No public/private key pair is loaded," " please create one using cf-key"); return -1; } assert(SSLCLIENTCONTEXT != NULL); conn_info->ssl = SSL_new(SSLCLIENTCONTEXT); if (conn_info->ssl == NULL) { Log(LOG_LEVEL_ERR, "SSL_new: %s", TLSErrorString(ERR_get_error())); return -1; } /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */ SSL_set_ex_data(conn_info->ssl, CONNECTIONINFO_SSL_IDX, conn_info); /* Initiate the TLS handshake over the already open TCP socket. */ SSL_set_fd(conn_info->ssl, conn_info->sd); int ret = SSL_connect(conn_info->ssl); if (ret <= 0) { TLSLogError(conn_info->ssl, LOG_LEVEL_ERR, "Failed to establish TLS connection", ret); return -1; } Log(LOG_LEVEL_VERBOSE, "TLS version negotiated: %8s; Cipher: %s,%s", SSL_get_version(conn_info->ssl), SSL_get_cipher_name(conn_info->ssl), SSL_get_cipher_version(conn_info->ssl)); Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust..."); return 0; }
/** * We directly initiate a TLS handshake with the server. If the server is old * version (does not speak TLS) the connection will be denied. * @note the socket file descriptor in #conn_info must be connected and *not* * non-blocking * @return -1 in case of error */ int TLSTry(ConnectionInfo *conn_info) { /* SSL Context might not be initialised up to now due to lack of keys, as * they might be generated as part of the policy (e.g. failsafe.cf). */ if (!TLSClientInitialize()) { return -1; } assert(SSLCLIENTCONTEXT != NULL && PRIVKEY != NULL && PUBKEY != NULL); ConnectionInfoSetSSL(conn_info, SSL_new(SSLCLIENTCONTEXT)); SSL *ssl = ConnectionInfoSSL(conn_info); if (ssl == NULL) { Log(LOG_LEVEL_ERR, "SSL_new: %s", TLSErrorString(ERR_get_error())); return -1; } /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */ SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn_info); /* Initiate the TLS handshake over the already open TCP socket. */ SSL_set_fd(ssl, ConnectionInfoSocket(conn_info)); int ret = SSL_connect(ssl); if (ret <= 0) { TLSLogError(ssl, LOG_LEVEL_ERR, "Failed to establish TLS connection", ret); return -1; } Log(LOG_LEVEL_VERBOSE, "TLS cipher negotiated: %s, %s", SSL_get_cipher_name(ssl), SSL_get_cipher_version(ssl)); Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust..."); return 0; }
/** * @retval 1 equal * @retval 0 not equal * @retval -1 error */ static int CompareCertToRSA(X509 *cert, RSA *rsa_key) { int ret; int retval = -1; /* ERROR */ EVP_PKEY *cert_pkey = X509_get_pubkey(cert); if (cert_pkey == NULL) { Log(LOG_LEVEL_ERR, "X509_get_pubkey: %s", TLSErrorString(ERR_get_error())); goto ret1; } if (EVP_PKEY_type(cert_pkey->type) != EVP_PKEY_RSA) { Log(LOG_LEVEL_ERR, "Received key of unknown type, only RSA currently supported!"); goto ret2; } RSA *cert_rsa_key = EVP_PKEY_get1_RSA(cert_pkey); if (cert_rsa_key == NULL) { Log(LOG_LEVEL_ERR, "TLSVerifyPeer: EVP_PKEY_get1_RSA failed!"); goto ret2; } EVP_PKEY *rsa_pkey = EVP_PKEY_new(); if (rsa_pkey == NULL) { Log(LOG_LEVEL_ERR, "TLSVerifyPeer: EVP_PKEY_new allocation failed!"); goto ret3; } ret = EVP_PKEY_set1_RSA(rsa_pkey, rsa_key); if (ret == 0) { Log(LOG_LEVEL_ERR, "TLSVerifyPeer: EVP_PKEY_set1_RSA failed!"); goto ret4; } ret = EVP_PKEY_cmp(cert_pkey, rsa_pkey); if (ret == 1) { Log(LOG_LEVEL_DEBUG, "Public key to certificate compare equal"); retval = 1; /* EQUAL */ } else if (ret == 0 || ret == -1) { Log(LOG_LEVEL_DEBUG, "Public key to certificate compare different"); retval = 0; /* NOT EQUAL */ } else { Log(LOG_LEVEL_ERR, "OpenSSL EVP_PKEY_cmp: %d %s", ret, TLSErrorString(ERR_get_error())); } ret4: EVP_PKEY_free(rsa_pkey); ret3: RSA_free(cert_rsa_key); ret2: EVP_PKEY_free(cert_pkey); ret1: return retval; }
/** * @warning Make sure you've called CryptoInitialize() first! * * @TODO if this function is called a second time, it just returns true, and * does not do nothing more. What if the settings (e.g. tls_min_version) have * changed? This can happen when cf-serverd reloads policy. Fixing this goes * much deeper though, as it would require cf-serverd to call * GenericAgentDiscoverContext() when reloading policy. */ bool TLSClientInitialize(const char *tls_min_version, const char *ciphers) { int ret; static bool is_initialised = false; if (is_initialised) { return true; } if (PRIVKEY == NULL || PUBKEY == NULL) { /* VERBOSE in case it's a custom, local-only installation. */ Log(LOG_LEVEL_VERBOSE, "No public/private key pair is loaded," " please create one using cf-key"); return false; } if (!TLSGenericInitialize()) { return false; } SSLCLIENTCONTEXT = SSL_CTX_new(SSLv23_client_method()); if (SSLCLIENTCONTEXT == NULL) { Log(LOG_LEVEL_ERR, "SSL_CTX_new: %s", TLSErrorString(ERR_get_error())); goto err1; } TLSSetDefaultOptions(SSLCLIENTCONTEXT, tls_min_version); if (ciphers != NULL) { Log(LOG_LEVEL_VERBOSE, "Setting cipher list for outgoing TLS connections to: %s", ciphers); ret = SSL_CTX_set_cipher_list(SSLCLIENTCONTEXT, ciphers); if (ret != 1) { Log(LOG_LEVEL_ERR, "No valid ciphers in cipher list: %s", ciphers); goto err2; } } /* Create cert into memory and load it into SSL context. */ SSLCLIENTCERT = TLSGenerateCertFromPrivKey(PRIVKEY); if (SSLCLIENTCERT == NULL) { Log(LOG_LEVEL_ERR, "Failed to generate in-memory-certificate from private key"); goto err2; } SSL_CTX_use_certificate(SSLCLIENTCONTEXT, SSLCLIENTCERT); ret = SSL_CTX_use_RSAPrivateKey(SSLCLIENTCONTEXT, PRIVKEY); if (ret != 1) { Log(LOG_LEVEL_ERR, "Failed to use RSA private key: %s", TLSErrorString(ERR_get_error())); goto err3; } /* Verify cert consistency. */ ret = SSL_CTX_check_private_key(SSLCLIENTCONTEXT); if (ret != 1) { Log(LOG_LEVEL_ERR, "Inconsistent key and TLS cert: %s", TLSErrorString(ERR_get_error())); goto err3; } is_initialised = true; return true; err3: X509_free(SSLCLIENTCERT); SSLCLIENTCERT = NULL; err2: SSL_CTX_free(SSLCLIENTCONTEXT); SSLCLIENTCONTEXT = NULL; err1: return false; }
/** * @warning Make sure you've called CryptoInitialize() first! */ bool ServerTLSInitialize() { int ret; if (!TLSGenericInitialize()) { return false; } assert(SSLSERVERCONTEXT == NULL); SSLSERVERCONTEXT = SSL_CTX_new(SSLv23_server_method()); if (SSLSERVERCONTEXT == NULL) { Log(LOG_LEVEL_ERR, "SSL_CTX_new: %s", TLSErrorString(ERR_get_error())); goto err1; } TLSSetDefaultOptions(SSLSERVERCONTEXT); /* * CFEngine is not a web server so we don't need many ciphers. We only * allow a safe but very common subset by default, extensible via * "allowciphers" in body server control. By default allow: * AES256-GCM-SHA384: most high-grade RSA-based cipher from TLSv1.2 * AES256-SHA: most backwards compatible but high-grade, from SSLv3 */ const char *cipher_list = SV.allowciphers; if (cipher_list == NULL) { cipher_list ="AES256-GCM-SHA384:AES256-SHA"; } ret = SSL_CTX_set_cipher_list(SSLSERVERCONTEXT, cipher_list); if (ret != 1) { Log(LOG_LEVEL_ERR, "No valid ciphers in cipher list: %s", cipher_list); } if (PRIVKEY == NULL || PUBKEY == NULL) { Log(LOG_LEVEL_ERR, "No public/private key pair is loaded, create one with cf-key"); goto err2; } assert(SSLSERVERCERT == NULL); /* Create cert into memory and load it into SSL context. */ SSLSERVERCERT = TLSGenerateCertFromPrivKey(PRIVKEY); if (SSLSERVERCERT == NULL) { Log(LOG_LEVEL_ERR, "Failed to generate in-memory certificate from private key"); goto err2; } SSL_CTX_use_certificate(SSLSERVERCONTEXT, SSLSERVERCERT); ret = SSL_CTX_use_RSAPrivateKey(SSLSERVERCONTEXT, PRIVKEY); if (ret != 1) { Log(LOG_LEVEL_ERR, "Failed to use RSA private key: %s", TLSErrorString(ERR_get_error())); goto err3; } /* Verify cert consistency. */ ret = SSL_CTX_check_private_key(SSLSERVERCONTEXT); if (ret != 1) { Log(LOG_LEVEL_ERR, "Inconsistent key and TLS cert: %s", TLSErrorString(ERR_get_error())); goto err3; } return true; err3: X509_free(SSLSERVERCERT); SSLSERVERCERT = NULL; err2: SSL_CTX_free(SSLSERVERCONTEXT); SSLSERVERCONTEXT = NULL; err1: return false; }
/** * @brief Accept a TLS connection and authenticate and identify. * @note Various fields in #conn are set, like username and keyhash. */ int ServerTLSSessionEstablish(ServerConnectionState *conn) { int ret; if (ConnectionInfoConnectionStatus(conn->conn_info) != CF_CONNECTION_ESTABLISHED) { assert(ConnectionInfoSSL(conn->conn_info) == NULL); SSL *ssl = SSL_new(SSLSERVERCONTEXT); if (ssl == NULL) { Log(LOG_LEVEL_ERR, "SSL_new: %s", TLSErrorString(ERR_get_error())); return -1; } ConnectionInfoSetSSL(conn->conn_info, ssl); /* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */ SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn->conn_info); /* Now we are letting OpenSSL take over the open socket. */ SSL_set_fd(ssl, ConnectionInfoSocket(conn->conn_info)); ret = SSL_accept(ssl); if (ret <= 0) { TLSLogError(ssl, LOG_LEVEL_ERR, "Failed to accept TLS connection", ret); return -1; } Log(LOG_LEVEL_VERBOSE, "TLS cipher negotiated: %s, %s", SSL_get_cipher_name(ssl), SSL_get_cipher_version(ssl)); Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust..."); /* Send/Receive "CFE_v%d" version string, agree on version, receive identity (username) of peer. */ char username[sizeof(conn->username)] = ""; bool b = ServerIdentificationDialog(conn->conn_info, username, sizeof(username)); if (b != true) { return -1; } /* We *now* (maybe a bit late) verify the key that the client sent us in * the TLS handshake, since we need the username to do so. TODO in the * future store keys irrelevant of username, so that we can match them * before IDENTIFY. */ ret = TLSVerifyPeer(conn->conn_info, conn->ipaddr, username); if (ret == -1) /* error */ { return -1; } if (ret == 1) /* trusted key */ { Log(LOG_LEVEL_VERBOSE, "%s: Client is TRUSTED, public key MATCHES stored one.", KeyPrintableHash(ConnectionInfoKey(conn->conn_info))); } if (ret == 0) /* untrusted key */ { if ((SV.trustkeylist != NULL) && (IsMatchItemIn(SV.trustkeylist, conn->ipaddr))) { Log(LOG_LEVEL_VERBOSE, "Peer was found in \"trustkeysfrom\" list"); Log(LOG_LEVEL_NOTICE, "Trusting new key: %s", KeyPrintableHash(ConnectionInfoKey(conn->conn_info))); SavePublicKey(username, KeyPrintableHash(conn->conn_info->remote_key), KeyRSA(ConnectionInfoKey(conn->conn_info))); } else { Log(LOG_LEVEL_NOTICE, "TRUST FAILED, peer presented an untrusted key, dropping connection!"); Log(LOG_LEVEL_VERBOSE, "Add peer to \"trustkeysfrom\" if you really want to start trusting this new key."); return -1; } } /* All checks succeeded, set conn->uid (conn->sid for Windows) * according to the received USERNAME identity. */ SetConnIdentity(conn, username); /* No CAUTH, SAUTH in non-classic protocol. */ conn->user_data_set = 1; conn->rsa_auth = 1; LastSaw1(conn->ipaddr, KeyPrintableHash(ConnectionInfoKey(conn->conn_info)), LAST_SEEN_ROLE_ACCEPT); ServerSendWelcome(conn); } return 1; }
int AuthenticateAgent(AgentConnection *conn, bool trust_key) { char sendbuffer[CF_EXPANDSIZE], in[CF_BUFSIZE], *out, *decrypted_cchall; BIGNUM *nonce_challenge, *bn = NULL; unsigned char digest[EVP_MAX_MD_SIZE]; int encrypted_len, nonce_len = 0, len, session_size; bool need_to_implicitly_trust_server; char enterprise_field = 'c'; if (PRIVKEY == NULL || PUBKEY == NULL) { Log(LOG_LEVEL_ERR, "No public/private key pair is loaded," " please create one using cf-key"); return false; } enterprise_field = CfEnterpriseOptions(); session_size = CfSessionKeySize(enterprise_field); /* Generate a random challenge to authenticate the server */ nonce_challenge = BN_new(); if (nonce_challenge == NULL) { Log(LOG_LEVEL_ERR, "Cannot allocate BIGNUM structure for server challenge"); return false; } BN_rand(nonce_challenge, CF_NONCELEN, 0, 0); nonce_len = BN_bn2mpi(nonce_challenge, in); if (FIPS_MODE) { HashString(in, nonce_len, digest, CF_DEFAULT_DIGEST); } else { HashString(in, nonce_len, digest, HASH_METHOD_MD5); } /* We assume that the server bound to the remote socket is the official one i.e. = root's */ /* Ask the server to send us the public key if we don't have it. */ RSA *server_pubkey = HavePublicKeyByIP(conn->username, conn->remoteip); if (server_pubkey) { need_to_implicitly_trust_server = false; encrypted_len = RSA_size(server_pubkey); } else { need_to_implicitly_trust_server = true; encrypted_len = nonce_len; } // Server pubkey is what we want to has as a unique ID snprintf(sendbuffer, sizeof(sendbuffer), "SAUTH %c %d %d %c", need_to_implicitly_trust_server ? 'n': 'y', encrypted_len, nonce_len, enterprise_field); out = xmalloc(encrypted_len); if (server_pubkey != NULL) { if (RSA_public_encrypt(nonce_len, in, out, server_pubkey, RSA_PKCS1_PADDING) <= 0) { Log(LOG_LEVEL_ERR, "Public encryption failed. (RSA_public_encrypt: %s)", CryptoLastErrorString()); free(out); RSA_free(server_pubkey); return false; } memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, out, encrypted_len); } else { memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, in, nonce_len); } /* proposition C1 - Send challenge / nonce */ SendTransaction(conn->conn_info, sendbuffer, CF_RSA_PROTO_OFFSET + encrypted_len, CF_DONE); BN_free(bn); BN_free(nonce_challenge); free(out); /*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); 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); SendTransaction(conn->conn_info, sendbuffer, len, CF_DONE); /* check reply about public key - server can break conn_info here */ /* proposition S1 */ memset(in, 0, CF_BUFSIZE); if (ReceiveTransaction(conn->conn_info, in, NULL) == -1) { Log(LOG_LEVEL_ERR, "Protocol transaction broken off (1). (ReceiveTransaction: %s)", GetErrorStr()); RSA_free(server_pubkey); return false; } if (BadProtoReply(in)) { Log(LOG_LEVEL_ERR, "Bad protocol reply: %s", in); RSA_free(server_pubkey); return false; } /* Get challenge response - should be CF_DEFAULT_DIGEST of challenge */ /* proposition S2 */ memset(in, 0, CF_BUFSIZE); if (ReceiveTransaction(conn->conn_info, in, NULL) == -1) { Log(LOG_LEVEL_ERR, "Protocol transaction broken off (2). (ReceiveTransaction: %s)", GetErrorStr()); RSA_free(server_pubkey); return false; } /* Check if challenge reply was correct */ if ((HashesMatch(digest, in, CF_DEFAULT_DIGEST)) || (HashesMatch(digest, in, HASH_METHOD_MD5))) // Legacy { if (need_to_implicitly_trust_server == false) { /* The IP was found in lastseen. */ Log(LOG_LEVEL_VERBOSE, ".....................[.h.a.i.l.]................................."); Log(LOG_LEVEL_VERBOSE, "Strong authentication of server '%s' connection confirmed", conn->this_server); } else /* IP was not found in lastseen */ { if (trust_key) { Log(LOG_LEVEL_VERBOSE, "Trusting server identity, promise to accept key from '%s' = '%s'", conn->this_server, conn->remoteip); } else { Log(LOG_LEVEL_ERR, "Not authorized to trust public key of server '%s' (trustkey = false)", conn->this_server); RSA_free(server_pubkey); return false; } } } else { Log(LOG_LEVEL_ERR, "Challenge response from server '%s/%s' was incorrect", conn->this_server, conn->remoteip); RSA_free(server_pubkey); return false; } /* Receive counter challenge from server */ /* proposition S3 */ memset(in, 0, CF_BUFSIZE); encrypted_len = ReceiveTransaction(conn->conn_info, in, NULL); if (encrypted_len == -1) { Log(LOG_LEVEL_ERR, "Protocol transaction sent illegal cipher length"); RSA_free(server_pubkey); return false; } decrypted_cchall = xmalloc(encrypted_len); if (RSA_private_decrypt(encrypted_len, in, decrypted_cchall, PRIVKEY, RSA_PKCS1_PADDING) <= 0) { Log(LOG_LEVEL_ERR, "Private decrypt failed, abandoning. (RSA_private_decrypt: %s)", CryptoLastErrorString()); RSA_free(server_pubkey); return false; } /* proposition C4 */ if (FIPS_MODE) { HashString(decrypted_cchall, nonce_len, digest, CF_DEFAULT_DIGEST); } else { HashString(decrypted_cchall, nonce_len, digest, HASH_METHOD_MD5); } if (FIPS_MODE) { SendTransaction(conn->conn_info, digest, CF_DEFAULT_DIGEST_LEN, CF_DONE); } else { SendTransaction(conn->conn_info, digest, CF_MD5_LEN, CF_DONE); } free(decrypted_cchall); /* If we don't have the server's public key, it will be sent */ if (server_pubkey == NULL) { RSA *newkey = RSA_new(); Log(LOG_LEVEL_VERBOSE, "Collecting public key from server!"); /* proposition S4 - conditional */ if ((len = ReceiveTransaction(conn->conn_info, in, NULL)) == -1) { Log(LOG_LEVEL_ERR, "Protocol error in RSA authentation from IP '%s'", conn->this_server); return false; } 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)", CryptoLastErrorString()); RSA_free(newkey); return false; } /* proposition S5 - conditional */ if ((len = ReceiveTransaction(conn->conn_info, in, NULL)) == -1) { 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) { 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; } server_pubkey = RSAPublicKey_dup(newkey); RSA_free(newkey); } assert(server_pubkey != NULL); /* proposition C5 */ if (!SetSessionKey(conn)) { Log(LOG_LEVEL_ERR, "Unable to set session key"); return false; } if (conn->session_key == NULL) { Log(LOG_LEVEL_ERR, "A random session key could not be established"); RSA_free(server_pubkey); return false; } encrypted_len = RSA_size(server_pubkey); out = xmalloc(encrypted_len); if (RSA_public_encrypt(session_size, conn->session_key, out, server_pubkey, RSA_PKCS1_PADDING) <= 0) { Log(LOG_LEVEL_ERR, "Public encryption failed. (RSA_public_encrypt: %s)", CryptoLastErrorString()); free(out); RSA_free(server_pubkey); return false; } SendTransaction(conn->conn_info, out, encrypted_len, CF_DONE); Key *key = KeyNew(server_pubkey, CF_DEFAULT_DIGEST); conn->conn_info->remote_key = key; Log(LOG_LEVEL_VERBOSE, "Public key identity of host '%s' is: %s", conn->remoteip, KeyPrintableHash(conn->conn_info->remote_key)); SavePublicKey(conn->username, KeyPrintableHash(conn->conn_info->remote_key), server_pubkey); unsigned int length = 0; LastSaw(conn->remoteip, KeyBinaryHash(conn->conn_info->remote_key, &length), LAST_SEEN_ROLE_CONNECT); free(out); return true; }
/** * @warning Make sure you've called CryptoInitialize() first! */ bool TLSClientInitialize() { int ret; static bool is_initialised = false; if (is_initialised) { return true; } if (!TLSGenericInitialize()) { return false; } SSLCLIENTCONTEXT = SSL_CTX_new(SSLv23_client_method()); if (SSLCLIENTCONTEXT == NULL) { Log(LOG_LEVEL_ERR, "SSL_CTX_new: %s", TLSErrorString(ERR_get_error())); goto err1; } TLSSetDefaultOptions(SSLCLIENTCONTEXT); if (PRIVKEY == NULL || PUBKEY == NULL) { Log(CryptoGetMissingKeyLogLevel(), "No public/private key pair is loaded, trying to reload"); LoadSecretKeys(); if (PRIVKEY == NULL || PUBKEY == NULL) { Log(CryptoGetMissingKeyLogLevel(), "No public/private key pair found"); goto err2; } } /* Create cert into memory and load it into SSL context. */ SSLCLIENTCERT = TLSGenerateCertFromPrivKey(PRIVKEY); if (SSLCLIENTCERT == NULL) { Log(LOG_LEVEL_ERR, "Failed to generate in-memory-certificate from private key"); goto err2; } SSL_CTX_use_certificate(SSLCLIENTCONTEXT, SSLCLIENTCERT); ret = SSL_CTX_use_RSAPrivateKey(SSLCLIENTCONTEXT, PRIVKEY); if (ret != 1) { Log(LOG_LEVEL_ERR, "Failed to use RSA private key: %s", TLSErrorString(ERR_get_error())); goto err3; } /* Verify cert consistency. */ ret = SSL_CTX_check_private_key(SSLCLIENTCONTEXT); if (ret != 1) { Log(LOG_LEVEL_ERR, "Inconsistent key and TLS cert: %s", TLSErrorString(ERR_get_error())); goto err3; } is_initialised = true; return true; err3: X509_free(SSLCLIENTCERT); SSLCLIENTCERT = NULL; err2: SSL_CTX_free(SSLCLIENTCONTEXT); SSLCLIENTCONTEXT = NULL; err1: return false; }