#include <openssl/ssl.h>
#include <stdio.h>
#include <string.h>
#include "ssl_local.h"
#include "tests.h"
static uint8_t cipher_bytes[] = {
0xcc, 0xa8,
0xcc, 0xa9,
0xcc, 0xaa,
0x00, 0x9c,
0x00, 0x3d,
};
static uint8_t cipher_bytes_seclevel3[] = {
0xcc, 0xa8,
0xcc, 0xa9,
0xcc, 0xaa,
};
static uint16_t cipher_values[] = {
0xcca8,
0xcca9,
0xccaa,
0x009c,
0x003d,
};
#define N_CIPHERS (sizeof(cipher_bytes) / 2)
static int
ssl_bytes_to_list_alloc(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
{
SSL_CIPHER *cipher;
uint16_t value;
CBS cbs;
int i;
CBS_init(&cbs, cipher_bytes, sizeof(cipher_bytes));
*ciphers = ssl_bytes_to_cipher_list(s, &cbs);
CHECK(*ciphers != NULL);
CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
for (i = 0; i < sk_SSL_CIPHER_num(*ciphers); i++) {
cipher = sk_SSL_CIPHER_value(*ciphers, i);
CHECK(cipher != NULL);
value = SSL_CIPHER_get_value(cipher);
CHECK(value == cipher_values[i]);
}
return 1;
}
static int
ssl_list_to_bytes_scsv(SSL *s, STACK_OF(SSL_CIPHER) **ciphers,
const uint8_t *cb, size_t cb_len)
{
CBB cbb;
unsigned char *buf = NULL;
size_t buflen, outlen;
int ret = 0;
CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
buflen = cb_len + 2 + 2;
CHECK((buf = calloc(1, buflen)) != NULL);
s->renegotiate = 0;
CHECK_GOTO(CBB_init_fixed(&cbb, buf, buflen));
CHECK_GOTO(ssl_cipher_list_to_bytes(s, *ciphers, &cbb));
CHECK_GOTO(CBB_finish(&cbb, NULL, &outlen));
CHECK_GOTO(outlen > 0 && outlen == cb_len + 2);
CHECK_GOTO(memcmp(buf, cb, cb_len) == 0);
CHECK_GOTO(buf[buflen - 4] == 0x00 && buf[buflen - 3] == 0xff);
CHECK_GOTO(buf[buflen - 2] == 0x00 && buf[buflen - 1] == 0x00);
ret = 1;
err:
free(buf);
return ret;
}
static int
ssl_list_to_bytes_no_scsv(SSL *s, STACK_OF(SSL_CIPHER) **ciphers,
const uint8_t *cb, size_t cb_len)
{
CBB cbb;
unsigned char *buf = NULL;
size_t buflen, outlen;
int ret = 0;
CHECK(sk_SSL_CIPHER_num(*ciphers) == N_CIPHERS);
buflen = cb_len + 2;
CHECK((buf = calloc(1, buflen)) != NULL);
buf[buflen - 2] = 0xfe;
buf[buflen - 1] = 0xab;
s->renegotiate = 1;
CHECK_GOTO(CBB_init_fixed(&cbb, buf, buflen));
CHECK_GOTO(ssl_cipher_list_to_bytes(s, *ciphers, &cbb));
CHECK_GOTO(CBB_finish(&cbb, NULL, &outlen));
CHECK_GOTO(outlen > 0 && outlen == cb_len);
CHECK_GOTO(memcmp(buf, cb, cb_len) == 0);
CHECK_GOTO(buf[buflen - 2] == 0xfe && buf[buflen - 1] == 0xab);
ret = 1;
err:
free(buf);
return ret;
}
static int
ssl_bytes_to_list_invalid(SSL *s, STACK_OF(SSL_CIPHER) **ciphers)
{
uint8_t empty_cipher_bytes[] = {0};
CBS cbs;
sk_SSL_CIPHER_free(*ciphers);
CBS_init(&cbs, cipher_bytes, sizeof(cipher_bytes) - 1);
*ciphers = ssl_bytes_to_cipher_list(s, &cbs);
CHECK(*ciphers == NULL);
CBS_init(&cbs, empty_cipher_bytes, sizeof(empty_cipher_bytes));
*ciphers = ssl_bytes_to_cipher_list(s, &cbs);
CHECK(*ciphers == NULL);
return 1;
}
int
main(void)
{
STACK_OF(SSL_CIPHER) *ciphers = NULL;
SSL_CTX *ctx = NULL;
SSL *s = NULL;
int rv = 1;
SSL_library_init();
CHECK_GOTO((ctx = SSL_CTX_new(TLSv1_2_client_method())) != NULL);
CHECK_GOTO((s = SSL_new(ctx)) != NULL);
SSL_set_security_level(s, 2);
if (!ssl_bytes_to_list_alloc(s, &ciphers))
goto err;
if (!ssl_list_to_bytes_scsv(s, &ciphers, cipher_bytes,
sizeof(cipher_bytes)))
goto err;
if (!ssl_list_to_bytes_no_scsv(s, &ciphers, cipher_bytes,
sizeof(cipher_bytes)))
goto err;
if (!ssl_bytes_to_list_invalid(s, &ciphers))
goto err;
sk_SSL_CIPHER_free(ciphers);
ciphers = NULL;
SSL_set_security_level(s, 3);
if (!ssl_bytes_to_list_alloc(s, &ciphers))
goto err;
if (!ssl_list_to_bytes_scsv(s, &ciphers, cipher_bytes_seclevel3,
sizeof(cipher_bytes_seclevel3)))
goto err;
if (!ssl_list_to_bytes_no_scsv(s, &ciphers, cipher_bytes_seclevel3,
sizeof(cipher_bytes_seclevel3)))
goto err;
rv = 0;
err:
sk_SSL_CIPHER_free(ciphers);
SSL_CTX_free(ctx);
SSL_free(s);
if (!rv)
printf("PASS %s\n", __FILE__);
return rv;
}