예제 #1
0
static void set_server_temporary_key_info(TLS_REC *tls, SSL *ssl)
{
#ifdef SSL_get_server_tmp_key
	/* Show ephemeral key information. */
	EVP_PKEY *ephemeral_key = NULL;

	/* OPENSSL_NO_EC is for solaris 11.3 (2016), github ticket #598 */
#ifndef OPENSSL_NO_EC
	EC_KEY *ec_key = NULL;
#endif
	char *ephemeral_key_algorithm = NULL;
	char *cname = NULL;
	int nid;

	g_return_if_fail(tls != NULL);
	g_return_if_fail(ssl != NULL);

	if (SSL_get_server_tmp_key(ssl, &ephemeral_key)) {
		switch (EVP_PKEY_id(ephemeral_key)) {
			case EVP_PKEY_DH:
				tls_rec_set_ephemeral_key_algorithm(tls, "DH");
				tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key));
				break;

#ifndef OPENSSL_NO_EC
			case EVP_PKEY_EC:
				ec_key = EVP_PKEY_get1_EC_KEY(ephemeral_key);
				nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
				EC_KEY_free(ec_key);
				cname = (char *)OBJ_nid2sn(nid);
				ephemeral_key_algorithm = g_strdup_printf("ECDH: %s", cname);

				tls_rec_set_ephemeral_key_algorithm(tls, ephemeral_key_algorithm);
				tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key));

				g_free_and_null(ephemeral_key_algorithm);
				break;
#endif

			default:
				tls_rec_set_ephemeral_key_algorithm(tls, "Unknown");
				tls_rec_set_ephemeral_key_size(tls, EVP_PKEY_bits(ephemeral_key));
				break;
		}

		EVP_PKEY_free(ephemeral_key);
	}
#endif /* SSL_get_server_tmp_key. */
}
예제 #2
0
파일: tls_util.c 프로젝트: dedok/libusual
ssize_t
tls_get_connection_info(struct tls *ctx, char *buf, size_t buflen)
{
	SSL *conn = ctx->ssl_conn;
	const char *ocsp_pfx = "", *ocsp_info = "";
	const char *proto = "-", *cipher = "-";
	char dh[64];
	int used_dh_bits = ctx->used_dh_bits, used_ecdh_nid = ctx->used_ecdh_nid;

	if (conn != NULL) {
		proto = SSL_get_version(conn);
		cipher = SSL_get_cipher(conn);

#ifdef SSL_get_server_tmp_key
		if (ctx->flags & TLS_CLIENT) {
			EVP_PKEY *pk = NULL;
			int ok = SSL_get_server_tmp_key(conn, &pk);
			int pk_type = EVP_PKEY_id(pk);
			if (ok && pk) {
				if (pk_type == EVP_PKEY_DH) {
					DH *dh = EVP_PKEY_get0(pk);
					used_dh_bits = DH_size(dh) * 8;
				} else if (pk_type == EVP_PKEY_EC) {
					EC_KEY *ecdh = EVP_PKEY_get0(pk);
					const EC_GROUP *eg = EC_KEY_get0_group(ecdh);
					used_ecdh_nid = EC_GROUP_get_curve_name(eg);
				}
				EVP_PKEY_free(pk);
			}
		}
#endif
	}

	if (used_dh_bits) {
		snprintf(dh, sizeof dh, "/DH=%d", used_dh_bits);
	} else if (used_ecdh_nid) {
		snprintf(dh, sizeof dh, "/ECDH=%s", OBJ_nid2sn(used_ecdh_nid));
	} else {
		dh[0] = 0;
	}

	if (ctx->ocsp_result) {
		ocsp_info = ctx->ocsp_result;
		ocsp_pfx = "/OCSP=";
	}

	return snprintf(buf, buflen, "%s/%s%s%s%s", proto, cipher, dh, ocsp_pfx, ocsp_info);
}
예제 #3
0
파일: s_cb.c 프로젝트: bbbrumley/openbsd
int
ssl_print_tmp_key(BIO *out, SSL *s)
{
	const char *cname;
	EVP_PKEY *pkey;
	EC_KEY *ec;
	int nid;

	if (!SSL_get_server_tmp_key(s, &pkey))
		return 0;

	BIO_puts(out, "Server Temp Key: ");
	switch (EVP_PKEY_id(pkey)) {
	case EVP_PKEY_DH:
		BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(pkey));
		break;

	case EVP_PKEY_EC:
		ec = EVP_PKEY_get1_EC_KEY(pkey);
		nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
		EC_KEY_free(ec);

		if ((cname = EC_curve_nid2nist(nid)) == NULL)
			cname = OBJ_nid2sn(nid);

		BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(pkey));
		break;

	default:
		BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_id(pkey)),
		    EVP_PKEY_bits(pkey));
	}

	EVP_PKEY_free(pkey);
	return 1;
}
예제 #4
0
/*
 * Note that |extra| points to the correct client/server configuration
 * within |test_ctx|. When configuring the handshake, general mode settings
 * are taken from |test_ctx|, and client/server-specific settings should be
 * taken from |extra|.
 *
 * The configuration code should never reach into |test_ctx->extra| or
 * |test_ctx->resume_extra| directly.
 *
 * (We could refactor test mode settings into a substructure. This would result
 * in cleaner argument passing but would complicate the test configuration
 * parsing.)
 */
static HANDSHAKE_RESULT *do_handshake_internal(
    SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx,
    const SSL_TEST_CTX *test_ctx, const SSL_TEST_EXTRA_CONF *extra,
    SSL_SESSION *session_in, SSL_SESSION **session_out)
{
    PEER server, client;
    BIO *client_to_server, *server_to_client;
    HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
    CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
    HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
    int client_turn = 1, client_turn_count = 0;
    connect_phase_t phase = HANDSHAKE;
    handshake_status_t status = HANDSHAKE_RETRY;
    const unsigned char* tick = NULL;
    size_t tick_len = 0;
    SSL_SESSION* sess = NULL;
    const unsigned char *proto = NULL;
    /* API dictates unsigned int rather than size_t. */
    unsigned int proto_len = 0;
    EVP_PKEY *tmp_key;

    memset(&server_ctx_data, 0, sizeof(server_ctx_data));
    memset(&server2_ctx_data, 0, sizeof(server2_ctx_data));
    memset(&client_ctx_data, 0, sizeof(client_ctx_data));
    memset(&server, 0, sizeof(server));
    memset(&client, 0, sizeof(client));

    configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx, extra,
                            &server_ctx_data, &server2_ctx_data, &client_ctx_data);

    /* Setup SSL and buffers; additional configuration happens below. */
    create_peer(&server, server_ctx);
    create_peer(&client, client_ctx);

    server.bytes_to_write = client.bytes_to_read = test_ctx->app_data_size;
    client.bytes_to_write = server.bytes_to_read = test_ctx->app_data_size;

    configure_handshake_ssl(server.ssl, client.ssl, extra);
    if (session_in != NULL) {
        /* In case we're testing resumption without tickets. */
        TEST_check(SSL_CTX_add_session(server_ctx, session_in));
        TEST_check(SSL_set_session(client.ssl, session_in));
    }

    memset(&server_ex_data, 0, sizeof(server_ex_data));
    memset(&client_ex_data, 0, sizeof(client_ex_data));

    ret->result = SSL_TEST_INTERNAL_ERROR;

    client_to_server = BIO_new(BIO_s_mem());
    server_to_client = BIO_new(BIO_s_mem());

    TEST_check(client_to_server != NULL);
    TEST_check(server_to_client != NULL);

    /* Non-blocking bio. */
    BIO_set_nbio(client_to_server, 1);
    BIO_set_nbio(server_to_client, 1);

    SSL_set_connect_state(client.ssl);
    SSL_set_accept_state(server.ssl);

    /* The bios are now owned by the SSL object. */
    SSL_set_bio(client.ssl, server_to_client, client_to_server);
    TEST_check(BIO_up_ref(server_to_client) > 0);
    TEST_check(BIO_up_ref(client_to_server) > 0);
    SSL_set_bio(server.ssl, client_to_server, server_to_client);

    ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL);
    TEST_check(ex_data_idx >= 0);

    TEST_check(SSL_set_ex_data(server.ssl, ex_data_idx, &server_ex_data) == 1);
    TEST_check(SSL_set_ex_data(client.ssl, ex_data_idx, &client_ex_data) == 1);

    SSL_set_info_callback(server.ssl, &info_cb);
    SSL_set_info_callback(client.ssl, &info_cb);

    client.status = server.status = PEER_RETRY;

    /*
     * Half-duplex handshake loop.
     * Client and server speak to each other synchronously in the same process.
     * We use non-blocking BIOs, so whenever one peer blocks for read, it
     * returns PEER_RETRY to indicate that it's the other peer's turn to write.
     * The handshake succeeds once both peers have succeeded. If one peer
     * errors out, we also let the other peer retry (and presumably fail).
     */
    for(;;) {
        if (client_turn) {
            do_connect_step(test_ctx, &client, phase);
            status = handshake_status(client.status, server.status,
                                      1 /* client went last */);
        } else {
            do_connect_step(test_ctx, &server, phase);
            status = handshake_status(server.status, client.status,
                                      0 /* server went last */);
        }

        switch (status) {
        case HANDSHAKE_SUCCESS:
            client_turn_count = 0;
            phase = next_phase(test_ctx, phase);
            if (phase == CONNECTION_DONE) {
                ret->result = SSL_TEST_SUCCESS;
                goto err;
            } else {
                client.status = server.status = PEER_RETRY;
                /*
                 * For now, client starts each phase. Since each phase is
                 * started separately, we can later control this more
                 * precisely, for example, to test client-initiated and
                 * server-initiated shutdown.
                 */
                client_turn = 1;
                break;
            }
        case CLIENT_ERROR:
            ret->result = SSL_TEST_CLIENT_FAIL;
            goto err;
        case SERVER_ERROR:
            ret->result = SSL_TEST_SERVER_FAIL;
            goto err;
        case INTERNAL_ERROR:
            ret->result = SSL_TEST_INTERNAL_ERROR;
            goto err;
        case HANDSHAKE_RETRY:
            if (client_turn_count++ >= 2000) {
                /*
                 * At this point, there's been so many PEER_RETRY in a row
                 * that it's likely both sides are stuck waiting for a read.
                 * It's time to give up.
                 */
                ret->result = SSL_TEST_INTERNAL_ERROR;
                goto err;
            }

            /* Continue. */
            client_turn ^= 1;
            break;
        }
    }
 err:
    ret->server_alert_sent = server_ex_data.alert_sent;
    ret->server_num_fatal_alerts_sent = server_ex_data.num_fatal_alerts_sent;
    ret->server_alert_received = client_ex_data.alert_received;
    ret->client_alert_sent = client_ex_data.alert_sent;
    ret->client_num_fatal_alerts_sent = client_ex_data.num_fatal_alerts_sent;
    ret->client_alert_received = server_ex_data.alert_received;
    ret->server_protocol = SSL_version(server.ssl);
    ret->client_protocol = SSL_version(client.ssl);
    ret->servername = server_ex_data.servername;
    if ((sess = SSL_get0_session(client.ssl)) != NULL)
        SSL_SESSION_get0_ticket(sess, &tick, &tick_len);
    if (tick == NULL || tick_len == 0)
        ret->session_ticket = SSL_TEST_SESSION_TICKET_NO;
    else
        ret->session_ticket = SSL_TEST_SESSION_TICKET_YES;
    ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call;

#ifndef OPENSSL_NO_NEXTPROTONEG
    SSL_get0_next_proto_negotiated(client.ssl, &proto, &proto_len);
    ret->client_npn_negotiated = dup_str(proto, proto_len);

    SSL_get0_next_proto_negotiated(server.ssl, &proto, &proto_len);
    ret->server_npn_negotiated = dup_str(proto, proto_len);
#endif

    SSL_get0_alpn_selected(client.ssl, &proto, &proto_len);
    ret->client_alpn_negotiated = dup_str(proto, proto_len);

    SSL_get0_alpn_selected(server.ssl, &proto, &proto_len);
    ret->server_alpn_negotiated = dup_str(proto, proto_len);

    ret->client_resumed = SSL_session_reused(client.ssl);
    ret->server_resumed = SSL_session_reused(server.ssl);

    if (session_out != NULL)
        *session_out = SSL_get1_session(client.ssl);

    if (SSL_get_server_tmp_key(client.ssl, &tmp_key)) {
        ret->tmp_key_type = pkey_type(tmp_key);
        EVP_PKEY_free(tmp_key);
    }

    SSL_get_peer_signature_nid(client.ssl, &ret->server_sign_hash);
    SSL_get_peer_signature_nid(server.ssl, &ret->client_sign_hash);

    SSL_get_peer_signature_type_nid(client.ssl, &ret->server_sign_type);
    SSL_get_peer_signature_type_nid(server.ssl, &ret->client_sign_type);

    ret->server_cert_type = peer_pkey_type(client.ssl);
    ret->client_cert_type = peer_pkey_type(server.ssl);

    ctx_data_free_data(&server_ctx_data);
    ctx_data_free_data(&server2_ctx_data);
    ctx_data_free_data(&client_ctx_data);

    peer_free_data(&server);
    peer_free_data(&client);
    return ret;
}