Exemplo n.º 1
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)
{
    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;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
/**
 * @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;
}
Exemplo n.º 5
0
/**
 * @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;
}
Exemplo n.º 6
0
/**
 * @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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
/**
 * @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;
}