root/regress/lib/libssl/dtls/dtls_wire_test.c
/* $OpenBSD: dtls_wire_test.c,v 1.1 2026/04/25 14:36:12 jsing Exp $ */
/*
 * Copyright (c) 2026 Joel Sing <jsing@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>

#include <openssl/bio.h>
#include <openssl/ssl.h>

#include "dtls_local.h"
#include "ssl_local.h"

static void
hexdump(const unsigned char *buf, size_t len)
{
        size_t i;

        for (i = 1; i <= len; i++)
                fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");

        fprintf(stderr, "\n");
}

static const uint8_t dtls12_hm_wire_bytes[] = {
        0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x01, 0xf3, 0x16, 0x00, 0x04,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xe7, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x01, 0x01, 0xf3, 0x16, 0x00, 0x04,
        0x00, 0x00, 0x00, 0x00, 0x01, 0xe7, 0x00, 0x01,
        0xe7, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x02, 0x00, 0x3e, 0x16, 0x00, 0x04,
        0x00, 0x00, 0x00, 0x00, 0x03, 0xce, 0x00, 0x00,
        0x32, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
        0x41, 0x41, 0x41,
};

static int
dtls_send_handshake_message_test(void)
{
        BIO *rbio = NULL, *wbio = NULL;
        char *wbuf, rbuf[1];
        CBB handshake, body;
        uint8_t *p;
        SSL_CTX *ssl_ctx = NULL;
        SSL *ssl = NULL;
        long len;
        int failed = 1;

        if ((ssl_ctx = SSL_CTX_new(DTLS_client_method())) == NULL) {
                fprintf(stderr, "FAIL: failed to create SSL_CTX\n");
                goto failure;
        }
        if ((ssl = SSL_new(ssl_ctx)) == NULL) {
                fprintf(stderr, "FAIL: failed to create SSL\n");
                goto failure;
        }

        if ((rbio = BIO_new_mem_buf(rbuf, sizeof(rbuf))) == NULL) {
                fprintf(stderr, "FAIL: failed to create rbio\n");
                goto failure;
        }
        if ((wbio = BIO_new(BIO_s_mem())) == NULL) {
                fprintf(stderr, "FAIL: failed to create wbio\n");
                goto failure;
        }

        BIO_up_ref(rbio);
        BIO_up_ref(wbio);
        SSL_set_bio(ssl, rbio, wbio);

        if (!ssl3_setup_init_buffer(ssl)) {
                fprintf(stderr, "FAIL: failed to setup init buffer\n");
                goto failure;
        }
        if (!ssl3_setup_write_buffer(ssl)) {
                fprintf(stderr, "FAIL: failed to setup write buffer\n");
                goto failure;
        }
        if (!ssl_get_new_session(ssl, 0)) {
                fprintf(stderr, "FAIL: failed to create session\n");
                goto failure;
        }
        if (!tls1_transcript_init(ssl)) {
                fprintf(stderr, "FAIL: failed to init transcript\n");
                goto failure;
        }

        ssl->s3->hs.cipher = ssl3_get_cipher_by_value(
            TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 & 0xffff);

        ssl->s3->hs.state = SSL3_ST_CW_CLNT_HELLO_B;
        ssl->d1->mtu = 512;

        if (!ssl3_handshake_msg_start(ssl, &handshake, &body, SSL3_RT_HANDSHAKE)) {
                fprintf(stderr, "FAIL: failed to start handshake message\n");
                goto failure;
        }
        if (!CBB_add_space(&body, &p, 1024))
                goto failure;
        memset(p, 'A', 1024);
        if (!ssl3_handshake_msg_finish(ssl, &handshake)) {
                fprintf(stderr, "FAIL: failed to finish handshake message\n");
                goto failure;
        }

        ssl3_connect(ssl);

        if (ssl->s3->hs.state != SSL3_ST_CR_SRVR_HELLO_A) {
                fprintf(stderr, "FAIL: got state 0x%x, want 0x%x\n",
                    ssl->s3->hs.state, SSL3_ST_CR_SRVR_HELLO_A);
                goto failure;
        }

        if ((len = BIO_get_mem_data(wbio, &wbuf)) != sizeof(dtls12_hm_wire_bytes)) {
                fprintf(stderr, "FAIL: got handshake message length = %ld, want %zu\n",
                    len, sizeof(dtls12_hm_wire_bytes));
                goto failure;
        }
        if (memcmp(wbuf, dtls12_hm_wire_bytes, len) != 0) {
                fprintf(stderr, "FAIL: got handshake message wire bytes:\n");
                hexdump(wbuf, len);
                fprintf(stderr, "want handshake message wire bytes:\n");
                hexdump(dtls12_hm_wire_bytes, len);
        }

        failed = 0;

 failure:
        SSL_CTX_free(ssl_ctx);
        SSL_free(ssl);

        BIO_free(rbio);
        BIO_free(wbio);

        return failed;
}

static const uint8_t dtls12_ccs_wire_bytes[] = {
        0x14, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
};

static int
dtls_send_ccs_test(void)
{
        BIO *rbio = NULL, *wbio = NULL;
        char *wbuf, rbuf[1];
        SSL_CTX *ssl_ctx = NULL;
        SSL *ssl = NULL;
        long len;
        int failed = 1;

        if ((ssl_ctx = SSL_CTX_new(DTLS_client_method())) == NULL) {
                fprintf(stderr, "FAIL: failed to create SSL_CTX\n");
                goto failure;
        }
        if ((ssl = SSL_new(ssl_ctx)) == NULL) {
                fprintf(stderr, "FAIL: failed to create SSL\n");
                goto failure;
        }

        if ((rbio = BIO_new_mem_buf(rbuf, sizeof(rbuf))) == NULL) {
                fprintf(stderr, "FAIL: failed to create rbio\n");
                goto failure;
        }
        if ((wbio = BIO_new(BIO_s_mem())) == NULL) {
                fprintf(stderr, "FAIL: failed to create wbio\n");
                goto failure;
        }

        BIO_up_ref(rbio);
        BIO_up_ref(wbio);
        SSL_set_bio(ssl, rbio, wbio);

        if (!ssl3_setup_init_buffer(ssl)) {
                fprintf(stderr, "FAIL: failed to setup init buffer\n");
                goto failure;
        }
        if (!ssl3_setup_write_buffer(ssl)) {
                fprintf(stderr, "FAIL: failed to setup write buffer\n");
                goto failure;
        }
        if (!ssl_get_new_session(ssl, 0)) {
                fprintf(stderr, "FAIL: failed to create session\n");
                goto failure;
        }

        ssl->s3->hs.cipher = ssl3_get_cipher_by_value(
            TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 & 0xffff);

        ssl->s3->hs.state = SSL3_ST_CW_CHANGE_A;
        ssl->d1->mtu = 512;

        ssl3_connect(ssl);

        if (ssl->s3->hs.state != SSL3_ST_CW_FINISHED_A) {
                fprintf(stderr, "FAIL: got state 0x%x, want 0x%x\n",
                    ssl->s3->hs.state, SSL3_ST_CW_FINISHED_A);
                goto failure;
        }

        if ((len = BIO_get_mem_data(wbio, &wbuf)) != sizeof(dtls12_ccs_wire_bytes)) {
                fprintf(stderr, "FAIL: got CCS length = %ld, want %zu\n", len,
                    sizeof(dtls12_ccs_wire_bytes));
                goto failure;
        }
        if (memcmp(wbuf, dtls12_ccs_wire_bytes, len) != 0) {
                fprintf(stderr, "FAIL: got CCS wire bytes:\n");
                hexdump(wbuf, len);
                fprintf(stderr, "want CCS wire bytes:\n");
                hexdump(dtls12_ccs_wire_bytes, len);
        }

        failed = 0;

 failure:
        SSL_CTX_free(ssl_ctx);
        SSL_free(ssl);

        BIO_free(rbio);
        BIO_free(wbio);

        return failed;
}

int
main(int argc, char **argv)
{
        int failed = 0;

        failed |= dtls_send_handshake_message_test();
        failed |= dtls_send_ccs_test();

        return failed;
}