Tls picotls
https://github.com/h2o/picotls/blob/master/t/picotls.c
This is an implementation of the generic TLS interface based on the picotls library. The parameters are:
cid : the type of connection ids
index : an unbounded sequence type
bytes : a type of byte arrays indexed by <code>index</code>
extens : a type of lists of extensions
lower : the lower interface
upper : the upper interface
module tls_gnutls(cid,index,bytes,extens,hextens,exten_ser,lower,upper) = {
attribute libspec = "picotls-core,picotls-minicrypto,picotls-openssl,ssl,crypto,dl,picotls.lib,libcrypto.lib,libssl.lib,cifra.lib,bcrypt.lib"
object cb = {} # struct holding the callbacks
object cid_map = {} # map from cid's to connections
<<< header
extern "C" {
//#include "picotls.c"
//#include <fmt/core.h>
}
// TODO: put any forward class definitions here
class tls_callbacks;
class picotls_connection;
>>>
<<< impl
// This structure holds all the callbacks. These are functions
// that are called synchronously.
struct tls_callbacks {
%`lower.send` ls;
%`upper.recv` ur;
%`upper.alert` ua;
%`upper.keys_established` use;
tls_callbacks(
const %`lower.send` ls,
const %`upper.recv` ur,
const %`upper.alert` ua,
const %`upper.keys_established` use
)
: ls(ls), ur(ur), ua(ua), use(use) {}
};
bool is_rtt = false;
bool is_client_test = false;
/* Per epoch crypto context. There are four such contexts:
* 0: Initial context, with encryption based on a version dependent key,
* 1: 0-RTT context
* 2: Handshake context
* 3: Application data
*/
struct quic_crypto_context_t {
void* aead_encrypt;
void* aead_decrypt;
void* pn_enc; /* Used for PN encryption */
void* pn_dec; /* Used for PN decryption */
quic_crypto_context_t() {
aead_encrypt = aead_decrypt = pn_enc = pn_dec = 0;
}
};
// Structure to hold state of a tls session
struct picotls_connection {
`cid` id;
ptls_t *gs;
ptls_context_t *cctx;
tls_callbacks cb;
ptls_handshake_properties_t *hsp;
std::vector<char> input;
int handshake_status;
std::vector<quic_crypto_context_t> crypto_context;
bool is_server;
uint8_t* session_ticket; //TOODO
st_ptls_buffer_t message;
void * ticket_aead_encrypt;
void * ticket_aead_decrypt;
picotls_connection(`cid` id, ptls_t *gs, ptls_context_t *cctx , tls_callbacks cb,
ptls_handshake_properties_t *hsp, bool is_server)
: id(id),gs(gs),cctx(cctx),cb(cb),hsp(hsp),is_server(is_server) {
handshake_status = 0;
session_ticket = NULL;
crypto_context.resize(4);
ticket_aead_encrypt = 0;
ticket_aead_decrypt = 0;
}
};
static int tls_collect_extensions_cb(ptls_t* tls, struct st_ptls_handshake_properties_t* properties, uint16_t type)
{
std::cerr << "tls_collect_extensions_cb " << type << "\n";
return (type & 0xff00) == 0xff00;
}
/*
* The client signals its willingness to receive session resume tickets by providing
* the "save ticket" callback in the client's quic context.
* from picoquic
*/
static int tls_client_save_ticket_cb(ptls_save_ticket_t* save_ticket_ctx,ptls_t* tls, ptls_iovec_t input)
{
int ret = 0;
std::cerr << "tls_client_save_ticket_cb\n" << input.len << "\n" << input.base << "\n";
// for(int i = 0; i < input.len; i++)
// std::cerr << input.base[i];
// std::cerr << "\n";
const char* env_p = std::getenv("TEST_IMPL");
int m = 0;
bool is_quiche = false;
const char * session_file = getenv("SESSION_TICKET_FILE");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
for(int j = 0; j < input.len-m && fp != NULL; j++) {
fprintf(fp, "%02x", input.base[j]);
}
fclose(fp);
}
return ret;
}
static uint64_t public_random_seed[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
static int public_random_index = 0;
static const uint64_t public_random_multiplier = 1181783497276652981ull;
static uint64_t public_random_obfuscator = 0x5555555555555555ull;
static uint64_t quic_public_random_step(void)
{
uint64_t s1;
const uint64_t s0 = public_random_seed[public_random_index++];
public_random_index &= 15;
s1 = public_random_seed[public_random_index];
s1 ^= (s1 << 31); // a
s1 ^= (s1 >> 11); // b
s1 ^= (s0 ^ (s0 >> 30)); // c
public_random_seed[public_random_index] = s1;
return s1;
}
uint64_t quic_public_random_64(void)
{
uint64_t s1 = quic_public_random_step();
s1 *= public_random_multiplier;
s1 ^= public_random_obfuscator;
return s1;
}
/* Integer parsing macros */
void picoformat_64(uint8_t* bytes, uint64_t n64)
{
bytes[0] = (uint8_t)(n64 >> 56);
bytes[1] = (uint8_t)(n64 >> 48);
bytes[2] = (uint8_t)(n64 >> 40);
bytes[3] = (uint8_t)(n64 >> 32);
bytes[4] = (uint8_t)(n64 >> 24);
bytes[5] = (uint8_t)(n64 >> 16);
bytes[6] = (uint8_t)(n64 >> 8);
bytes[7] = (uint8_t)(n64);
}
void picoformat_32(uint8_t* bytes, uint32_t n32)
{
bytes[0] = (uint8_t)(n32 >> 24);
bytes[1] = (uint8_t)(n32 >> 16);
bytes[2] = (uint8_t)(n32 >> 8);
bytes[3] = (uint8_t)(n32);
}
static int tls_server_encrypt_ticket_cb(ptls_encrypt_ticket_t* encrypt_ticket_ctx,
ptls_t* tls, int is_encrypt, ptls_buffer_t* dst, ptls_iovec_t src)
{
std::cerr << "tls_server_encrypt_ticket_cb - ENTRY (is_encrypt=" << is_encrypt << ", src.len=" << src.len << ") \n";
int ret = 0;
// Add NULL pointer check to prevent segfault
void** data_ptr = ptls_get_data_ptr(tls);
if (!data_ptr || !*data_ptr) {
std::cerr << "ERROR: tls_server_encrypt_ticket_cb - TLS data pointer is NULL" << "\n";
return -1;
}
picotls_connection *s = (picotls_connection*)*data_ptr;
std::cerr << "tls_server_encrypt_ticket_cb - Successfully accessed data pointer, connection id=" << s->id << "\n";
if (is_encrypt != 0) {
const char * session_file = getenv("ENCRYPT_TICKET_FILE");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
for(int j = 0; j < src.len; j++) {
fprintf(fp, "%02x", src.base[j]); //length field
}
fclose(fp);
}
ptls_aead_context_t *aead_enc = (ptls_aead_context_t *)(s->ticket_aead_encrypt);
std::cerr << "tls_server_encrypt_ticket_cb 3a ticket_aead_encrypt " << s->ticket_aead_encrypt << "\n";
//ptls_aead_context_t* aead_enc = (ptls_aead_context_t*)quic->aead_encrypt_ticket_ctx;
/* Encoding*/
if (aead_enc == NULL) {
ret = -1;
} else if ((ret = ptls_buffer_reserve(dst, 8 + src.len + aead_enc->algo->tag_size)) == 0) {
/* Create and store the ticket sequence number */
//uint32_t version_number = 0x00000001; //TODO
uint64_t seq_num = quic_public_random_64();
std::cerr << "tls_server_encrypt_ticket_cb 4a " << seq_num << "\n";
size_t start_off;
size_t data_length;
picoformat_64(dst->base + dst->off, seq_num);
dst->off += 8;
start_off = dst->off;
/* Copy initial ticket to dst field before encryption. */
memcpy(dst->base + dst->off, src.base, src.len);
data_length = src.len;
/* Add the version number */
// picoformat_32(dst->base + dst->off + data_length, version_number);
// data_length += 4;
/* Run AEAD encryption */
dst->off += ptls_aead_encrypt(aead_enc, dst->base + dst->off,
dst->base + start_off, data_length, seq_num, NULL, 0);
/* Remember issued ticket ID in connection context */
//quic->cnx_in_progress->issued_ticket_id = seq_num;
}
} else {
std::cerr << "tls_server_encrypt_ticket_cb 2b\n";
ptls_aead_context_t *aead_dec = (ptls_aead_context_t *)(s->ticket_aead_decrypt);
//ptls_aead_context_t* aead_dec = (ptls_aead_context_t*)quic->aead_decrypt_ticket_ctx;
/* Encoding*/
if (aead_dec == NULL) {
ret = -1;
} else if (src.len < 8 + aead_dec->algo->tag_size) {
ret = -1;
} else if ((ret = ptls_buffer_reserve(dst, src.len)) == 0) {
/* Decode the ticket sequence number */
uint64_t seq_num = PICOPARSE_64(src.base);
std::cerr << "tls_server_encrypt_ticket_cb 4b " << seq_num << "\n";
/* Decrypt */
size_t decrypted = ptls_aead_decrypt(aead_dec, dst->base + dst->off,
src.base + 8, src.len - 8, seq_num, NULL, 0);
if (decrypted > src.len - 8) {
std::cerr << "tls_server_encrypt_ticket_cb 5b decryption ERROR " << decrypted << "\n";
/* decryption error */
ret = -1;
} else {
dst->off += decrypted;
/* Remember resumed ticket ID in connection context */
//quic->cnx_in_progress->resumed_ticket_id = seq_num;
const char * session_file = getenv("ENCRYPT_TICKET_FILE");
std::cerr << "tls_server_encrypt_ticket_cb 5b " << src.len << "\n";
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
for(int j = 0; j < src.len; j++) {
fprintf(fp, "%02x", dst->base[j]); //length field
}
fclose(fp);
}
}
}
}
return ret;
}
static int tls_collected_extensions_cb(ptls_t* tls, ptls_handshake_properties_t* properties,
ptls_raw_extension_t* slots)
{
// TODO: do something with incoming extensions
std::cerr << "tls_collected_extensions_cb " << slots->type << "\n";
return 0;
}
static int tls_on_extension_cb(ptls_on_extension_t* ext, ptls_t* tls, uint8_t type_tls,
uint16_t type, ptls_iovec_t input)
{
// TODO: do something with incoming extensions
std::cerr << "tls_on_extension_cb " << type_tls << "\n";
std::cerr << "tls_on_extension_cb " << type << "\n";
std::cerr << "tls_on_extension_cb " << input.len << "\n\n";
return 0;
}
// These are some parameters defined byt the QUIC-TLS standard. They
// don't really belong here, but then again, QUIC is currently the only
// existing client of this TLS interface.
define QUIC_LABEL_RETRY1 "quic key" define QUIC_LABEL_RETRY2 "quic iv"
define PTLS_HELLO_RANDOM_SIZE 32
define PTLS_HANDSHAKE_HEADER_SIZE 4
//SSL: ptls_get_client_random(), quic_update_traffic_key_cb
// The following mess is to get the traffic keys from picotls
void *aead_from_secret(ptls_cipher_suite_t * cipher, int is_enc, const void *secret)
{
return ptls_aead_new(cipher->aead, cipher->hash, is_enc, secret, QUIC_LABEL_QUIC_BASE);
}
static int quic_set_aead_from_secret(void ** v_aead,ptls_cipher_suite_t * cipher, int is_enc, const void *secret, const char *prefix_label)
{
int ret = 0;
std::cerr << "quic_set_aead_from_secret 1 " << *v_aead << "\n";
if (*v_aead != NULL) {
ptls_aead_free((ptls_aead_context_t*)*v_aead);
}
std::cerr << "quic_set_aead_from_secret 2" <<"\n";
if ((*v_aead = ptls_aead_new(cipher->aead, cipher->hash, is_enc, secret, prefix_label)) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
}
std::cerr << "quic_set_aead_from_secret 3 " << *v_aead << "\n";
return ret;
}
void *pn_enc_from_secret(ptls_cipher_suite_t * cipher, int is_enc, const void *secret)
{
uint8_t key[PTLS_MAX_SECRET_SIZE];
ptls_hkdf_expand_label(cipher->hash, key,
cipher->aead->ctr_cipher->key_size,
ptls_iovec_init(secret, cipher->hash->digest_size),
"quic hp",
ptls_iovec_init(NULL, 0),
NULL);
return ptls_cipher_new(cipher->aead->ctr_cipher, is_enc, key);
}
void quic_set_key_from_secret(ptls_cipher_suite_t * cipher, int is_enc, quic_crypto_context_t * ctx, const void *secret)
{
std::cerr << "quic_set_key_from_secret 1" <<"\n";
if (is_enc) {
std::cerr << "quic_set_key_from_secret 2q" <<"\n";
ctx->aead_encrypt = aead_from_secret(cipher, is_enc, secret);
std::cerr << "quic_set_key_from_secret 3q" <<"\n";
ctx->pn_enc = pn_enc_from_secret(cipher, is_enc, secret);
} else {
std::cerr << "quic_set_key_from_secret 2v" <<"\n";
ctx->aead_decrypt = aead_from_secret(cipher, is_enc, secret);
std::cerr << "quic_set_key_from_secret 3v" <<"\n";
ctx->pn_dec = pn_enc_from_secret(cipher, is_enc, secret);
}
}
static int quic_update_traffic_key_cb(ptls_update_traffic_key_t * self, ptls_t *tls, int is_enc, size_t epoch, const void *secret)
{
std::cerr << "quic_update_traffic_key_cb - ENTRY (is_enc=" << is_enc << ", epoch=" << epoch << ", secret=" << secret << ")\n";
static const char *log_labels[2][4] = {
{NULL, "CLIENT_EARLY_TRAFFIC_SECRET", "CLIENT_HANDSHAKE_TRAFFIC_SECRET", "CLIENT_TRAFFIC_SECRET_0"},
{NULL, NULL, "SERVER_HANDSHAKE_TRAFFIC_SECRET", "SERVER_TRAFFIC_SECRET_0"}};
const char * keylogfile = getenv("SSLKEYLOGFILE");
const char * keylogfile_0rtt = getenv("ZRTT_SSLKEYLOG_FILE");
//const char * is_zrtt = getenv("ZERORTT_TEST");
FILE *fp;
FILE *fp_0rtt;
const char *secret_label = log_labels[ptls_is_server(tls) == is_enc][epoch];
std::cerr << "quic_update_traffic_key_cb "<< secret_label <<"\n";
if(keylogfile != NULL) {
fp = fopen(keylogfile,"a");
fprintf(fp, "%s ", secret_label);
ptls_iovec_t crandom = ptls_get_client_random(tls);
for (int i = 0 ; i < crandom.len ; i++) {
fprintf(fp, "%02hhx", crandom.base[i]);
}
fprintf(fp, " ");
}
if(keylogfile_0rtt != NULL && (!is_rtt || strcmp(secret_label, "CLIENT_EARLY_TRAFFIC_SECRET") == 0 || is_client_test)) {
const char *secret_label = log_labels[ptls_is_server(tls) == is_enc][epoch];
if(strcmp(secret_label, "SERVER_HANDSHAKE_TRAFFIC_SECRET") == 0) {
fp_0rtt = fopen(keylogfile_0rtt,"w"); //erase
fprintf(fp_0rtt, "%s", "");
fclose(fp_0rtt);
}
fp_0rtt = fopen(keylogfile_0rtt,"a");
fprintf(fp_0rtt, "%s ", secret_label);
ptls_iovec_t crandom = ptls_get_client_random(tls);
for (int i = 0 ; i < crandom.len ; i++) {
fprintf(fp_0rtt, "%02hhx", crandom.base[i]);
}
fprintf(fp_0rtt, " ");
}
// Add NULL pointer check to prevent segfault
void** data_ptr = ptls_get_data_ptr(tls);
if (!data_ptr || !*data_ptr) {
std::cerr << "ERROR: quic_update_traffic_key_cb - TLS data pointer is NULL" << "\n";
if(keylogfile != NULL) fclose(fp);
if(keylogfile_0rtt != NULL) fclose(fp_0rtt);
return -1;
}
picotls_connection* cnx = (picotls_connection*)*data_ptr;
std::cerr << "quic_update_traffic_key_cb - Successfully accessed data pointer, connection id=" << cnx->id << "\n";
ptls_cipher_suite_t * cipher = ptls_get_cipher(tls);
if(keylogfile != NULL) {
for (int i = 0 ; i < cipher->hash->digest_size ; i++) {
fprintf(fp, "%02hhx", ((uint8_t *) secret)[i]);
}
fprintf(fp, "\n");
}
if(keylogfile_0rtt != NULL && (!is_rtt || strcmp(secret_label, "CLIENT_EARLY_TRAFFIC_SECRET") == 0)) {
for (int i = 0 ; i < cipher->hash->digest_size ; i++) {
fprintf(fp_0rtt, "%02hhx", ((uint8_t *) secret)[i]);
}
fprintf(fp_0rtt, "\n");
}
quic_set_key_from_secret(cipher, is_enc, &cnx->crypto_context[epoch], secret);
if (cnx->crypto_context[epoch].aead_encrypt && cnx->crypto_context[epoch].aead_decrypt) {
cnx->cb.use(cnx->id,epoch);
}
if(keylogfile != NULL) {
fclose(fp);
}
if(keylogfile_0rtt != NULL && (!is_rtt || strcmp(secret_label, "CLIENT_EARLY_TRAFFIC_SECRET") == 0)) {
fclose(fp_0rtt);
}
return 0;
}
int convert(const char *hex_str, uint8_t *byte_array, int byte_array_max)
{
std::cerr << "convert 1" <<"\n";
int hex_str_len = strnlen(hex_str,byte_array_max);
int i = 0, j = 0;
// The output array size is half the hex_str length (rounded up)
int byte_array_size = (hex_str_len)/2;
fprintf(stderr,"pipi %d\n",byte_array_size);
std::cerr << "convert 2" <<"\n";
if (byte_array_size > byte_array_max)
{
// Too big for the output array
return -1;
}
if (hex_str_len % 2 == 1)
{
// hex_str is an odd length, so assume an implicit "0" prefix
if (sscanf(&(hex_str[0]), "%1hhx", &(byte_array[0])) != 1)
{
return -1;
}
i = j = 1;
}
for (; i < hex_str_len; i+=2, j++)
{
if (sscanf(&(hex_str[i]), "%2hhx", &(byte_array[j])) != 1)
{
return -1;
}
}
return byte_array_size;
}
void vec_to_ptls_iovec(ptls_iovec_t &res, const `bytes` &vec) {
res.base = new uint8_t[vec.size()];
std::copy(vec.begin(),vec.end(),res.base);
res.len = vec.size();
}
void vec_to_ptls_iovec(ptls_iovec_t &res, uint8_t* vec, int size) {
res.base = new uint8_t[size];
std::cerr << "vec_to_ptls_iovec " << std::dec << size << std::endl;
for(int i = 0; i < size; i++) {
res.base[i] = vec[i];
std::cerr << res.base[i];
}
std::cerr << std::endl;
//std::copy(std::begin(vec),std::end(vec),res.base);
res.len = size;
}
// This additional mess sets the initial traffic keys
void bail(int ret, const char *msg) {
if (ret) {
std::cerr << msg;
exit(1);
}
}
/**
* @brief from https://gitlab.com/wireshark/wireshark/-/blob/master/wsutil/str_util.c
*
* @param ch
* @return int
*/
int
ws_xton(char ch)
{
switch (ch) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return -1;
}
}
/**
* @brief
* Derive-Secret(Secret, Label, Messages) =
HKDF-Expand-Label(Secret, Label,
Transcript-Hash(Messages), Hash.length)
*/
int setup_initial_traffic_keys(picotls_connection *session,
const `bytes` &salt_vec,
const `bytes` &ikm_vec)
{
std::cerr << "setup_initial_traffic_keys\n";
std::cerr << salt_vec;
std::cerr << ikm_vec;
int ret = 0;
uint8_t master_secret[256]; /* secret_max */
ptls_cipher_suite_t cipher = { 0, &ptls_openssl_aes128gcm, &ptls_openssl_sha256 };
ptls_iovec_t salt;
ptls_iovec_t ikm;
ptls_iovec_t prk;
uint8_t client_secret[256];
uint8_t server_secret[256];
uint8_t *secret1, *secret2;
std::cerr << "setup_initial_traffic_keys 2 \n";
vec_to_ptls_iovec(salt,salt_vec);
vec_to_ptls_iovec(ikm,ikm_vec);
std::cerr << "setup_initial_traffic_keys 3\n";
ret = ptls_hkdf_extract(cipher.hash, master_secret, salt, ikm);
bail(ret,"tls: failed to set up initial master secret\n");
std::cerr << "setup_initial_traffic_keys 4\n";
prk.base = master_secret;
prk.len = cipher.hash->digest_size;
ret = ptls_hkdf_expand_label(cipher.hash, client_secret, cipher.hash->digest_size,
prk, QUIC_LABEL_INITIAL_CLIENT, ptls_iovec_init(NULL, 0),NULL);
// QUIC_LABEL_QUIC_BASE);
bail(ret,"tls: failed to set up initial client secret\n");
ret = ptls_hkdf_expand_label(cipher.hash, server_secret, cipher.hash->digest_size,
prk, QUIC_LABEL_INITIAL_SERVER, ptls_iovec_init(NULL, 0),NULL);
// QUIC_LABEL_QUIC_BASE);
bail(ret,"tls: failed to set up initial server secret\n");
std::cerr << "setup_initial_traffic_keys 5\n";
quic_set_key_from_secret(&cipher, session->is_server, &session->crypto_context[0], server_secret);
std::cerr << "setup_initial_traffic_keys 6\n";
quic_set_key_from_secret(&cipher, !session->is_server, &session->crypto_context[0], client_secret);
return ret;
}
void encrypt_symm(ptls_cipher_context_t *pn_enc, const `bytes` &clear, const `bytes` &iv, `bytes` &cipher) {
std::vector<uint8_t> bytes;
bytes.resize(iv.size());
std::copy(iv.begin(),iv.end(),bytes.begin());
ptls_cipher_init(pn_enc, &bytes[0]);
std::vector<uint8_t> input, output;
input.resize(clear.size());
std::copy(clear.begin(),clear.end(),input.begin());
output.resize(clear.size());
ptls_cipher_encrypt(pn_enc, &output[0], &input[0], input.size());
cipher.resize(output.size());
std::copy(output.begin(),output.end(),cipher.begin());
}
// Some parameters for picotls as used by picoquic.
//mvfst -> No HelloRetry &ptls_openssl_x25519,&ptls_openssl_secp256r1
ptls_key_exchange_algorithm_t *picotls_key_exchanges[] =
{ &ptls_openssl_x25519,&ptls_openssl_secp256r1, NULL };
// ptls_key_exchange_algorithm_t *picotls_key_exchanges[] =
// { &ptls_openssl_secp256r1, &ptls_openssl_x25519, NULL };
ptls_cipher_suite_t *picotls_cipher_suites[] = {
&ptls_openssl_aes128gcmsha256, &ptls_openssl_aes256gcmsha384,
&ptls_minicrypto_chacha20poly1305sha256, NULL };
// Here we process handshake data on a TLS connection. The in_epoch is a picotls
// epoch. For the initial client handshake, input is null.
int picotls_do_handshake(picotls_connection *s, size_t in_epoch, void *input, size_t inlen ) {
if(ptls_is_psk_handshake(s->gs)) { //segfault without ??
std::cerr << "ptls_is_psk_handshake= " << ptls_is_psk_handshake(s->gs) << std::endl;
} else {
std::cerr << "ptls_is_psk_handshake= " << ptls_is_psk_handshake(s->gs) << std::endl;
}
size_t epoch_offsets[5] = { 0, 0, 0, 0, 0 };
struct st_ptls_buffer_t sendbuf;
ptls_buffer_init(&sendbuf, (void *)"", 0);
int ret = ptls_handle_message(s->gs, &sendbuf, epoch_offsets, in_epoch, input, inlen, s->hsp);
std::cerr << "picotls_do_handshake ptls_handle_message end " << "\n";
if (ret == PTLS_ERROR_IN_PROGRESS) {
std::cerr << "PICOTLS RETURNED PTLS_ERROR_IN_PROGRESS " << ret << "\n";
} else if (ret != 0) {
std::cerr << "PICOTLS RETURNED ERROR: " << ret << "\n";
}
// Any generated bytes go to the lower send callback (even in case of error).
if (sendbuf.off > 0) {
for (size_t ep = 0; ep < 4; ep++) {
size_t num_bytes = epoch_offsets[ep+1] - epoch_offsets[ep];
if (num_bytes) {
`bytes` bytes;
bytes.resize(num_bytes);
std::copy(sendbuf.base+epoch_offsets[ep],sendbuf.base+epoch_offsets[ep+1],bytes.begin());
s->cb.ls(s->id,bytes,ep);
}
}
}
std::cerr << "PICOTLS handshake handle message finish" << "\n";
return ret;
}
static int set_sign_certificate_from_key(EVP_PKEY* pkey, ptls_context_t* ctx)
{
int ret = 0;
ptls_openssl_sign_certificate_t* signer;
signer = (ptls_openssl_sign_certificate_t*)malloc(sizeof(ptls_openssl_sign_certificate_t));
if (signer == NULL || pkey == NULL) {
ret = -1;
} else {
ret = ptls_openssl_init_sign_certificate(signer, pkey);
ctx->sign_certificate = &signer->super;
}
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
if (ret != 0 && signer != NULL) {
free(signer);
}
return ret;
}
static int set_sign_certificate_from_key_file(char const* keypem, ptls_context_t* ctx)
{
int ret = 0;
BIO* bio = BIO_new_file(keypem, "rb");
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
if (pkey == NULL) {
ret = -1;
}
else {
ret = set_sign_certificate_from_key(pkey, ctx);
}
BIO_free(bio);
return ret;
}
void printt(unsigned char *byte_array, int byte_array_size)
{
int i = 0;
fprintf(stderr,"%s","0x");
for(; i < byte_array_size; i++)
{
fprintf(stderr,"%02x ", byte_array[i]);
}
fprintf(stderr,"%s","\n");
}
void get_session_ticket(uint8_t* secret, int size) {
const char * session_file = getenv("SESSION_TICKET_FILE");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
std::cerr << "get_session_ticket 1 " << line << std::endl;
std::cerr << "get_session_ticket hex_len " << size << std::endl;
int sizze = convert(line, secret, size*2+1);
if (sizze < 0)
{
fprintf(stderr,"Failed to convert '%s'\n", line);
printt(secret, sizze);
}
else if (sizze == 0)
{
fprintf(stderr,"Nothing to convert for '%s'\n", line);
printt(secret, sizze);
}
else
{
fprintf(stderr,"%s","OK OK\n");
printt(secret, sizze);
}
}
}
}
int get_session_ticket_size() {
const char * session_file = getenv("SESSION_TICKET_FILE");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
if(line != NULL) {
std::cerr << "get_session_ticket_size " << line << std::endl;
int hex_len = (strnlen(line,2000))/2; //strnlen(line,300)-1
std::cerr << "get_session_ticket_size " << hex_len << std::endl;
return hex_len;
}
}
return 0;
}
>>>
<<< member
hash_space::hash_map<`cid`,picotls_connection *> `cid_map`; // maps cid's to connections
tls_callbacks *`cb`; // the callbacks to ivy
>>>
<<< init
// Create the callbacks. When you put an
// action in anti-quotes it creates a function object (a "thunk")
// that captures the instance environment, in this case including
// the instance's endpoint id "me".
`cb` = new tls_callbacks(`lower.send`,`upper.recv`,`upper.alert`,`upper.keys_established`);
>>>
object impl = {
implement eavesdrop_client(c:cid) {
<<< impure
std::cerr << "eavesdrop_client create cid = " << c << std::endl;
ptls_context_t* ctx;
ctx = new ptls_context_t;
memset(ctx, 0, sizeof(ptls_context_t));
ctx->random_bytes = ptls_openssl_random_bytes;
ctx->key_exchanges = picotls_key_exchanges;
ctx->cipher_suites = picotls_cipher_suites;
ctx->send_change_cipher_spec = 0;
// ctx->hkdf_label_prefix = QUIC_LABEL_QUIC_BASE;
ctx->hkdf_label_prefix__obsolete = NULL;
ctx->update_traffic_key = (ptls_update_traffic_key_t *)malloc(sizeof(ptls_update_traffic_key_t));
memset(ctx->update_traffic_key, 0, sizeof(ptls_update_traffic_key_t));
//ctx->update_traffic_key = new ptls_update_traffic_key_t;
ctx->update_traffic_key->cb = quic_update_traffic_key_cb;
ctx->get_time = &ptls_get_time;
//ctx->on_extension = new ptls_on_extension_t;
ctx->on_extension = (ptls_on_extension_t *)malloc(sizeof(ptls_on_extension_t));
memset(ctx->on_extension, 0, sizeof(ptls_on_extension_t));
ctx->on_extension->cb = tls_on_extension_cb;
ptls_t *session;
session = ptls_new(ctx, 0);
// Initialize data pointer to NULL to prevent callbacks from accessing garbage
*ptls_get_data_ptr(session) = NULL;
std::cerr << "PICOTLS: Initialized session data pointer to NULL for safety\n";
ptls_set_server_name(session, "servername", strlen("servername"));
ptls_handshake_properties_t *handshake_properties = new ptls_handshake_properties_t;
memset(handshake_properties, 0, sizeof(ptls_handshake_properties_t));
handshake_properties->collect_extension = tls_collect_extensions_cb;
handshake_properties->collected_extensions = tls_collected_extensions_cb;
ptls_iovec_t *alpn_vec = new(ptls_iovec_t); // TODO: will leak this
// h3-x == HTTP/3 over QUIC
// hq-x == HTTP/0.9 over QUIC
alpn_vec->base = (uint8_t*) "hq-interop";
if(const char* env_p = std::getenv("TEST_ALPN")) {
std::cerr << "TEST_ALPN " << env_p << std::endl;
alpn_vec->base = (uint8_t*) env_p;
}
alpn_vec->len = strlen((char *)(alpn_vec->base));
handshake_properties->client.negotiated_protocols.count = 1;
handshake_properties->client.negotiated_protocols.list = alpn_vec;
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
ptls_set_negotiated_protocol(session,
(const char*) handshake_properties->client.negotiated_protocols.list[0].base,
handshake_properties->client.negotiated_protocols.list[0].len);
picotls_connection *s = new picotls_connection(c, session, ctx, *`cb`, handshake_properties, false);
*ptls_get_data_ptr(session) = s;
std::cerr << "PICOTLS: Set session data pointer to connection object (id=" << c << ")\n";
`cid_map`[c] = s;
std::cerr << "cid_map[c] = s;" << std::endl;
>>>
}
implement eavesdrop_server(c:cid) {
<<< impure
std::cerr << "eavesdrop_server create cid = " << c << std::endl;
ptls_context_t* ctx;
ctx = new ptls_context_t;
memset(ctx, 0, sizeof(ptls_context_t));
ctx->random_bytes = ptls_openssl_random_bytes;
ctx->key_exchanges = picotls_key_exchanges;
ctx->cipher_suites = picotls_cipher_suites;
ctx->send_change_cipher_spec = 0;
// ctx->hkdf_label_prefix = QUIC_LABEL_QUIC_BASE;
ctx->hkdf_label_prefix__obsolete = NULL;
ctx->update_traffic_key = (ptls_update_traffic_key_t *)malloc(sizeof(ptls_update_traffic_key_t));
memset(ctx->update_traffic_key, 0, sizeof(ptls_update_traffic_key_t));
//ctx->update_traffic_key = new ptls_update_traffic_key_t;
ctx->update_traffic_key->cb = quic_update_traffic_key_cb;
ctx->get_time = &ptls_get_time;
//ctx->on_extension = new ptls_on_extension_t;
ctx->on_extension = (ptls_on_extension_t *)malloc(sizeof(ptls_on_extension_t));
memset(ctx->on_extension, 0, sizeof(ptls_on_extension_t));
ctx->on_extension->cb = tls_on_extension_cb;
const char* cert_path = getenv("PANTHER_IVY_CERT_PATH");
if (!cert_path) {
const char* base_dir = getenv("PANTHER_IVY_BASE_DIR");
if (base_dir) {
static std::string cert_path_str = std::string(base_dir) + "/quic/leaf_cert.pem";
cert_path = cert_path_str.c_str();
} else {
cert_path = "/opt/panther_ivy/protocol-testing/quic/quic/leaf_cert.pem";
}
}
int r = ptls_load_certificates(ctx, cert_path);
std::cerr << "ptls_load_certificates " << r << std::endl;
/* Read the certificate file */
if (r != 0) {
std::cerr << "could not load certificate file hardcoded leaf_cert.pem\n";
exit(1);
} else if(const char* key_path = getenv("PANTHER_IVY_KEY_PATH")) {
std::cerr << "PANTHER_IVY_KEY_PATH " << key_path << std::endl;
if (!key_path) {
const char* base_dir = getenv("PANTHER_IVY_BASE_DIR");
if (base_dir) {
static std::string key_path_str = std::string(base_dir) + "/quic/leaf_cert.key";
key_path = key_path_str.c_str();
} else {
key_path = "/opt/panther_ivy/protocol-testing/quic/quic/leaf_cert.key";
}
}
} else {
std::cerr << "PANTHER_IVY_KEY_PATH not set, using hardcoded leaf_cert.key\n";
key_path = "/opt/panther_ivy/protocol-testing/quic/quic/leaf_cert.key";
}
if (set_sign_certificate_from_key_file(key_path, ctx)) {
std::cerr << "could not load key file leaf_cert.key\n";
exit(1);
}
ptls_t *session;
session = ptls_new(ctx, 1);
// Initialize data pointer to NULL to prevent callbacks from accessing garbage
*ptls_get_data_ptr(session) = NULL;
std::cerr << "PICOTLS: Initialized session data pointer to NULL for safety\n";
ptls_set_server_name(session, "servername", strlen("servername"));
ptls_handshake_properties_t *handshake_properties = new ptls_handshake_properties_t;
memset(handshake_properties, 0, sizeof(ptls_handshake_properties_t));
handshake_properties->collect_extension = tls_collect_extensions_cb;
handshake_properties->collected_extensions = tls_collected_extensions_cb;
ptls_iovec_t *alpn_vec = new(ptls_iovec_t); // TODO: will leak this
// h3-x == HTTP/3 over QUIC
// hq-x == HTTP/0.9 over QUIC
alpn_vec->base = (uint8_t*) "hq-interop";
if(const char* env_p = std::getenv("TEST_ALPN")) {
std::cerr << "TEST_ALPN " << env_p << std::endl;
alpn_vec->base = (uint8_t*) env_p;
}
alpn_vec->len = strlen((char *)(alpn_vec->base));
handshake_properties->client.negotiated_protocols.count = 1;
handshake_properties->client.negotiated_protocols.list = alpn_vec;
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
ptls_set_negotiated_protocol(session,
(const char*) handshake_properties->client.negotiated_protocols.list[0].base,
handshake_properties->client.negotiated_protocols.list[0].len);
picotls_connection *s = new picotls_connection(c, session, ctx, *`cb`, handshake_properties, true);
*ptls_get_data_ptr(session) = s;
std::cerr << "PICOTLS: Set session data pointer to connection object (id=" << c << ")\n";
`cid_map`[c] = s;
std::cerr << "cid_map[c] = s;" << std::endl;
>>>
}
implement create(c:cid, is_server:bool, e:extens) {
<<< impure
//is_rtt = true; //todo
if(is_server)
is_client_test = true;
std::cerr << "create cid = " << c << std::endl;
std::cerr << "is_server = " << is_server << std::endl;
// We create a new picootls session, and add an entry in the cid_map
// for it.
ptls_context_t* ctx;
ctx = new ptls_context_t;
memset(ctx, 0, sizeof(ptls_context_t));
/*
HelloRetryRequest random:
CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
*/
ctx->random_bytes = ptls_openssl_random_bytes;
ctx->key_exchanges = picotls_key_exchanges;
ctx->cipher_suites = picotls_cipher_suites;
ctx->send_change_cipher_spec = 0;
// ctx->hkdf_label_prefix = QUIC_LABEL_QUIC_BASE;
ctx->hkdf_label_prefix__obsolete = NULL;
ctx->update_traffic_key = (ptls_update_traffic_key_t *)malloc(sizeof(ptls_update_traffic_key_t));
memset(ctx->update_traffic_key, 0, sizeof(ptls_update_traffic_key_t));
//ctx->update_traffic_key = new ptls_update_traffic_key_t;
ctx->update_traffic_key->cb = quic_update_traffic_key_cb;
//ctx->on_extension = new ptls_on_extension_t;
ctx->on_extension = (ptls_on_extension_t *)malloc(sizeof(ptls_on_extension_t));
memset(ctx->on_extension, 0, sizeof(ptls_on_extension_t));
ctx->on_extension->cb = tls_on_extension_cb;
ctx->get_time = &ptls_get_time;
const char * is_zrtt = getenv("ZERORTT_TEST");
// ctx->client_mode = !is_server;
ctx->max_early_data_size = 0xFFFFFFFF;
ctx->omit_end_of_early_data = 0;
std::cerr << "PROUT 3 " << std::endl;
//ctx->use_exporter = 1; // master secrets should be recorded
ptls_handshake_properties_t *handshake_properties = new ptls_handshake_properties_t;
memset(handshake_properties, 0, sizeof(ptls_handshake_properties_t));
handshake_properties->collect_extension = tls_collect_extensions_cb;
handshake_properties->collected_extensions = tls_collected_extensions_cb;
std::cerr << "PROUT 4 " << std::endl;
ptls_iovec_t *alpn_vec = new(ptls_iovec_t); // TODO: will leak this
// h3-x == HTTP/3 over QUIC
// hq-x == HTTP/0.9 over QUIC
alpn_vec->base = (uint8_t*) "hq-interop";
if(const char* env_p = std::getenv("TEST_ALPN")) {
std::cerr << "TEST_ALPN " << env_p << std::endl;
alpn_vec->base = (uint8_t*) env_p;
}
alpn_vec->len = strlen((char *)(alpn_vec->base));
handshake_properties->client.negotiated_protocols.count = 1;
handshake_properties->client.negotiated_protocols.list = alpn_vec;
// add the extensions
ptls_raw_extension_t *ptls_exts = new ptls_raw_extension_t[e.size()+1];
for (unsigned i = 0; i < e.size(); i++) {
`exten_ser` ser;
std::cerr << "etype =" << std::endl;
__ser(ser,e[i]);
// Validate extension data has minimum required size
if (ser.res.size() < 4) {
std::cerr << "Extension data too small: " << ser.res.size() << " bytes, skipping" << std::endl;
continue;
}
unsigned etype = (((unsigned char)(ser.res[0])) << 8) + ((unsigned char)(ser.res[1]));
unsigned len = (((unsigned char)(ser.res[2])) << 8) + ((unsigned char)(ser.res[3]));
// Validate extension length matches available data
if (len > ser.res.size() - 4) {
std::cerr << "Extension length mismatch: claimed=" << len << " available=" << (ser.res.size()-4) << ", skipping" << std::endl;
continue;
}
// Special handling for certificate_authorities extension (type 57)
if (etype == 57) {
std::cerr << "Processing certificate_authorities extension (type 57) with length " << len << std::endl;
}
unsigned char *data = new unsigned char[ser.res.size()-4];
std::copy(ser.res.begin()+4,ser.res.end(),data);
ptls_exts[i].type = etype;
std::cerr << "etype =" << etype << std::endl;
ptls_exts[i].data.base = data;
//std::cerr << "data =" << data << std::endl;
ptls_exts[i].data.len = len;
std::cerr << "len =" << len << std::endl;
// int eres = gnutls_session_ext_register (session, "ext_name", etype,
// GNUTLS_EXT_APPLICATION, gnutls_ext_supp_recv_params,
// gnutls_ext_supp_send_params, 0,0,0,0);
// if (eres != GNUTLS_E_SUCCESS) {
// std::cerr << "gnutls_session_ext_register\n";
// exit(1);
// }
}
ptls_exts[e.size()].type = 0xffff;
ptls_exts[e.size()].data.base = NULL;
ptls_exts[e.size()].data.len = 0;
for (unsigned i = 0; i < e.size(); i++) {
std::cerr << "ptls_exts[i].type = " << ptls_exts[i].type << std::endl;
//std::cerr << "ptls_exts[i].base = " << ptls_exts[i].data.base << std::endl;
std::cerr << "ptls_exts[i].len = " << ptls_exts[i].data.len << std::endl;
}
handshake_properties->additional_extensions = ptls_exts;
// Read the certificate, if we are a server
if (is_server) { //segfault ??
const char* cert_path = getenv("PANTHER_IVY_CERT_PATH");
std::cerr << "PANTHER_IVY_CERT_PATH " << cert_path << std::endl;
if (!cert_path) {
const char* base_dir = getenv("PANTHER_IVY_BASE_DIR");
std::cerr << "PANTHER_IVY_BASE_DIR " << base_dir << std::endl;
if (base_dir) {
static std::string cert_path_str = std::string(base_dir) + "/quic/leaf_cert.pem";
cert_path = cert_path_str.c_str();
} else {
// Fixed path: removed extra /quic directory
cert_path = "/opt/panther_ivy/protocol-testing/quic/leaf_cert.pem";
}
}
// Check if certificate file exists before loading
std::ifstream cert_file(cert_path);
if (!cert_file.good()) {
std::cerr << "Certificate file does not exist: " << cert_path << std::endl;
// Try alternative certificate path
cert_path = "/opt/panther_ivy/protocol-testing/quic/cert.pem";
std::cerr << "Trying alternative certificate: " << cert_path << std::endl;
}
int r = ptls_load_certificates(ctx, cert_path);
std::cerr << "ptls_load_certificates result: " << r << " for path: " << cert_path << std::endl;
/* Read the certificate file */
if (r != 0) {
std::cerr << "could not load certificate file: " << cert_path << std::endl;
std::cerr << "This may cause certificate_authorities extension (type 57) validation to fail" << std::endl;
exit(1);
}
const char* key_path = getenv("PANTHER_IVY_KEY_PATH");
if (key_path) {
std::cerr << "PANTHER_IVY_KEY_PATH " << key_path << std::endl;
} else {
const char* base_dir = getenv("PANTHER_IVY_BASE_DIR");
if (base_dir) {
const static std::string key_path_str = std::string(base_dir) + "/quic/leaf_cert.key";
key_path = key_path_str.c_str();
} else {
key_path = "/opt/panther_ivy/protocol-testing/quic/quic/leaf_cert.key";
}
}
if (key_path) {
std::cerr << "PANTHER_IVY_KEY_PATH " << key_path << std::endl;
} else {
std::cerr << "PANTHER_IVY_KEY_PATH not set, using hardcoded leaf_cert.key\n";
key_path = "/opt/panther_ivy/protocol-testing/quic/quic/leaf_cert.key";
}
if (set_sign_certificate_from_key_file(key_path, ctx)) {
std::cerr << "could not load key file leaf_cert.key\n";
exit(1);
}
}
ptls_t *session;
session = ptls_new(ctx,is_server ? 1 : 0);
// Initialize data pointer to NULL to prevent callbacks from accessing garbage
*ptls_get_data_ptr(session) = NULL;
std::cerr << "PICOTLS: Initialized session data pointer to NULL for safety\n";
ptls_set_server_name(session, "servername", strlen("servername"));
//if(const char* env_p = std::getenv("TEST_IMPL")) {
// std::cerr << "TEST_IMPL " << env_p << std::endl;
// std::cerr << "is_server " << is_server << std::endl;
// if(strncmp(env_p,"quic-go",10) == 0
// || strncmp(env_p,"quiche",10) == 0
// || strncmp(env_p,"lsquic",10) == 0
// || strncmp(env_p,"quinn",10) == 0
// || strncmp(env_p,"aioquic",10) == 0) //TODO ask why sometime ALPN needed
// if (is_server) { // && false
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
ptls_set_negotiated_protocol(session,
(const char*) handshake_properties->client.negotiated_protocols.list[0].base,
handshake_properties->client.negotiated_protocols.list[0].len);
// }
//}
picotls_connection *s = new picotls_connection(c, session, ctx, *`cb`, handshake_properties, is_server);
*ptls_get_data_ptr(session) = s;
std::cerr << "PICOTLS: Set session data pointer to connection object (id=" << c << ", is_server=" << is_server << ")\n";
if(is_zrtt != NULL){ //is_server &&
/**
* @brief picoquic_server_setup_ticket_aead_contexts
*/
uint8_t temp_secret[256]; /* secret_max */
int ret = 0;
std::cerr << "picoquic_server_setup_ticket_aead_contexts 1 " << std::endl;
ptls_cipher_suite_t cipher_ticket ={ 0, &ptls_openssl_aes128gcm, &ptls_openssl_sha256 };
// { 0, &ptls_openssl_aes256gcmsha384, &ptls_openssl_aes128gcmsha256, &ptls_minicrypto_chacha20poly1305sha256 };
//{ 0, &ptls_openssl_aes128gcm, &ptls_openssl_sha256, &ptls_openssl_aes128gcm };
if (cipher_ticket.hash->digest_size > sizeof(temp_secret)) {
ret = -1;
} else {
std::cerr << "picoquic_server_setup_ticket_aead_contexts 2 " << std::endl;
//ctx->random_bytes(temp_secret, cipher_ticket.hash->digest_size);
for(int i = 0; i < cipher_ticket.hash->digest_size; i++)
temp_secret[i] = 1;
std::cerr << "picoquic_server_setup_ticket_aead_contexts 3 " << std::endl;
/* Create the AEAD contexts */
ret = quic_set_aead_from_secret(&s->ticket_aead_encrypt, &cipher_ticket, 1, temp_secret, "random label");
if (ret == 0) {
std::cerr << "picoquic_server_setup_ticket_aead_contexts 4 " << std::endl;
ret = quic_set_aead_from_secret(&s->ticket_aead_decrypt, &cipher_ticket, 0, temp_secret, "random label");
}
std::cerr << "picoquic_server_setup_ticket_aead_contexts 5 " << std::endl;
/* erase the temporary secret */
ptls_clear_memory(temp_secret, cipher_ticket.hash->digest_size);
}
ptls_iovec_t ticket_psk = ptls_iovec_init(NULL, 0);
std::cerr << "ptls_encrypt_ticket_t " << is_zrtt << std::endl;
ptls_encrypt_ticket_t* encrypt_ticket = (ptls_encrypt_ticket_t*) malloc(sizeof(ptls_encrypt_ticket_t)+ sizeof(ptls_iovec_t*));
if (encrypt_ticket != NULL) {
encrypt_ticket->cb = tls_server_encrypt_ticket_cb;
ptls_iovec_t** ppreceiver = (ptls_iovec_t**)(((char*)encrypt_ticket) + sizeof(ptls_encrypt_ticket_t));
*ppreceiver = &ticket_psk;
ctx->encrypt_ticket = encrypt_ticket;
}
ctx->ticket_lifetime = 100000; /* 100,000 seconds, a bit more than one day */
ctx->max_early_data_size = 0xFFFFFFFF;
ctx->require_dhe_on_psk = 1;
ptls_iovec_t ticket_psk2 = ptls_iovec_init(NULL, 0);
std::cerr << "ptls_save_ticket_t " << is_zrtt << std::endl;
ptls_save_ticket_t* save_ticket = (ptls_save_ticket_t*) malloc(sizeof(ptls_save_ticket_t)+ sizeof(ptls_iovec_t*)); // + sizeof(ptls_iovec_t*)
if (save_ticket != NULL) {
save_ticket->cb = tls_client_save_ticket_cb; //memory error
ptls_iovec_t** ppreceiver2 = (ptls_iovec_t**)(((char*)save_ticket) + sizeof(ptls_save_ticket_t));
*ppreceiver2 = &ticket_psk2;
ctx->save_ticket = save_ticket;
}
} else {
ctx->ticket_lifetime = 0; // no ticket? was: 100000; /* 100,000 seconds, a bit more than one day */
ctx->require_dhe_on_psk = 1;
}
`cid_map`[c] = s;
// Start the handshake if we are the client. The in_epoch is zero for "initial".
if (!is_server)
picotls_do_handshake(s,0,0,0);
>>>
}
implement create_0rtt_client(c:cid, is_server:bool, e:extens) {
<<< impure
//is_rtt = true; //todo
if(is_server)
is_client_test = true;
std::cerr << "create cid = " << c << std::endl;
// We create a new picootls session, and add an entry in the cid_map
// for it.
ptls_context_t* ctx;
ctx = new ptls_context_t;
memset(ctx, 0, sizeof(ptls_context_t));
/*
HelloRetryRequest random:
CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
*/
ctx->random_bytes = ptls_openssl_random_bytes;
ctx->key_exchanges = picotls_key_exchanges;
ctx->cipher_suites = picotls_cipher_suites;
ctx->send_change_cipher_spec = 0;
// ctx->hkdf_label_prefix = QUIC_LABEL_QUIC_BASE;
ctx->hkdf_label_prefix__obsolete = NULL;
ctx->update_traffic_key = (ptls_update_traffic_key_t *)malloc(sizeof(ptls_update_traffic_key_t));
memset(ctx->update_traffic_key, 0, sizeof(ptls_update_traffic_key_t));
//ctx->update_traffic_key = new ptls_update_traffic_key_t;
ctx->update_traffic_key->cb = quic_update_traffic_key_cb;
//ctx->on_extension = new ptls_on_extension_t;
ctx->on_extension = (ptls_on_extension_t *)malloc(sizeof(ptls_on_extension_t));
memset(ctx->on_extension, 0, sizeof(ptls_on_extension_t));
ctx->on_extension->cb = tls_on_extension_cb;
ctx->get_time = &ptls_get_time;
const char * is_zrtt = getenv("ZERORTT_TEST");
ctx->max_early_data_size = 0xFFFFFFFF;
std::cerr << "PROUT 3 " << std::endl;
ptls_handshake_properties_t *handshake_properties = new ptls_handshake_properties_t;
memset(handshake_properties, 0, sizeof(ptls_handshake_properties_t));
handshake_properties->collect_extension = tls_collect_extensions_cb;
handshake_properties->collected_extensions = tls_collected_extensions_cb;
std::cerr << "PROUT 4 " << std::endl;
ptls_iovec_t *alpn_vec = new(ptls_iovec_t); // TODO: will leak this
// h3-x == HTTP/3 over QUIC
// hq-x == HTTP/0.9 over QUIC
alpn_vec->base = (uint8_t*) "hq-interop";
if(const char* env_p = std::getenv("TEST_ALPN")) {
std::cerr << "TEST_ALPN " << env_p << std::endl;
alpn_vec->base = (uint8_t*) env_p;
}
alpn_vec->len = strlen((char *)(alpn_vec->base));
handshake_properties->client.negotiated_protocols.count = 1;
handshake_properties->client.negotiated_protocols.list = alpn_vec;
// add the extensions
ptls_raw_extension_t *ptls_exts = new ptls_raw_extension_t[e.size()+1];
for (unsigned i = 0; i < e.size(); i++) {
`exten_ser` ser;
std::cerr << "etype =" << std::endl;
__ser(ser,e[i]);
// Validate extension data has minimum required size
if (ser.res.size() < 4) {
std::cerr << "Extension data too small: " << ser.res.size() << " bytes, skipping" << std::endl;
continue;
}
unsigned etype = (((unsigned char)(ser.res[0])) << 8) + ((unsigned char)(ser.res[1]));
unsigned len = (((unsigned char)(ser.res[2])) << 8) + ((unsigned char)(ser.res[3]));
// Validate extension length matches available data
if (len > ser.res.size() - 4) {
std::cerr << "Extension length mismatch: claimed=" << len << " available=" << (ser.res.size()-4) << ", skipping" << std::endl;
continue;
}
// Special handling for certificate_authorities extension (type 57)
if (etype == 57) {
std::cerr << "Processing certificate_authorities extension (type 57) with length " << len << std::endl;
}
unsigned char *data = new unsigned char[ser.res.size()-4];
std::copy(ser.res.begin()+4,ser.res.end(),data);
ptls_exts[i].type = etype;
std::cerr << "etype =" << etype << std::endl;
ptls_exts[i].data.base = data;
//std::cerr << "data =" << data << std::endl;
ptls_exts[i].data.len = len;
std::cerr << "len =" << len << std::endl;
// int eres = gnutls_session_ext_register (session, "ext_name", etype,
// GNUTLS_EXT_APPLICATION, gnutls_ext_supp_recv_params,
// gnutls_ext_supp_send_params, 0,0,0,0);
// if (eres != GNUTLS_E_SUCCESS) {
// std::cerr << "gnutls_session_ext_register\n";
// exit(1);
// }
}
ptls_exts[e.size()].type = 0xffff;
ptls_exts[e.size()].data.base = NULL;
ptls_exts[e.size()].data.len = 0;
handshake_properties->additional_extensions = ptls_exts;
// Read the certificate, if we are a server
if (is_server) { //segfault ??
const char* cert_path_alt = getenv("PANTHER_IVY_CERT_PATH");
if (!cert_path_alt) cert_path_alt = "/opt/panther_ivy/protocol-testing/quic/leaf_cert.pem";
int r = ptls_load_certificates(ctx, cert_path_alt);
std::cerr << "ptls_load_certificates " << r << std::endl;
/* Read the certificate file */
if (r != 0) {
std::cerr << "could not load certificate file leaf_cert.pem\n";
exit(1);
} else if(set_sign_certificate_from_key_file("/opt/panther_ivy/protocol-testing/quic/leaf_cert.key", ctx)) {
std::cerr << "could not load key file leaf_cert.key\n";
exit(1);
}
}
ptls_t *session;
session = ptls_new(ctx,is_server ? 1 : 0);
// Initialize data pointer to NULL to prevent callbacks from accessing garbage
*ptls_get_data_ptr(session) = NULL;
std::cerr << "PICOTLS: Initialized session data pointer to NULL for safety \n";
ptls_set_server_name(session, "servername", strlen("servername"));
if(const char* env_p = std::getenv("TEST_IMPL")) {
std::cerr << "TEST_IMPL " << env_p << std::endl;
std::cerr << "is_server " << is_server << std::endl;
if(strncmp(env_p,"quic-go",10) == 0
|| strncmp(env_p,"quiche",10) == 0
|| strncmp(env_p,"lsquic",10) == 0
|| strncmp(env_p,"quinn",10) == 0
|| strncmp(env_p,"aioquic",10) == 0) //TODO ask why sometime ALPN needed
if (is_server) { // && false
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
ptls_set_negotiated_protocol(session,
(const char*) handshake_properties->client.negotiated_protocols.list[0].base,
handshake_properties->client.negotiated_protocols.list[0].len);
}
}
picotls_connection *s = new picotls_connection(c, session, ctx, *`cb`, handshake_properties, is_server);
*ptls_get_data_ptr(session) = s;
std::cerr << "PICOTLS: Set session data pointer to connection object (id=" << c << ", is_server=" << is_server << ")\n";
if(is_zrtt != NULL){ //is_server &&
/**
* @brief picoquic_server_setup_ticket_aead_contexts
*/
uint8_t temp_secret[256]; /* secret_max */
int ret = 0;
std::cerr << "picoquic_server_setup_ticket_aead_contexts 1 " << std::endl;
ptls_cipher_suite_t cipher_ticket = { 0, &ptls_openssl_aes128gcm, &ptls_openssl_sha256 };
if (cipher_ticket.hash->digest_size > sizeof(temp_secret)) {
ret = -1;
} else {
std::cerr << "picoquic_server_setup_ticket_aead_contexts 2 " << std::endl;
//ctx->random_bytes(temp_secret, cipher_ticket.hash->digest_size);
for(int i = 0; i < cipher_ticket.hash->digest_size; i++)
temp_secret[i] = 1;
std::cerr << "picoquic_server_setup_ticket_aead_contexts 3 " << std::endl;
/* Create the AEAD contexts */
ret = quic_set_aead_from_secret(&s->ticket_aead_encrypt, &cipher_ticket, 1, temp_secret, "random label");
if (ret == 0) {
std::cerr << "picoquic_server_setup_ticket_aead_contexts 4 " << std::endl;
ret = quic_set_aead_from_secret(&s->ticket_aead_decrypt, &cipher_ticket, 0, temp_secret, "random label");
}
std::cerr << "picoquic_server_setup_ticket_aead_contexts 5 " << std::endl;
/* erase the temporary secret */
ptls_clear_memory(temp_secret, cipher_ticket.hash->digest_size);
}
ptls_iovec_t ticket_psk = ptls_iovec_init(NULL, 0);
std::cerr << "ptls_encrypt_ticket_t " << is_zrtt << std::endl;
ptls_encrypt_ticket_t* encrypt_ticket = (ptls_encrypt_ticket_t*) malloc(sizeof(ptls_encrypt_ticket_t)+ sizeof(ptls_iovec_t*));
if (encrypt_ticket != NULL) {
encrypt_ticket->cb = tls_server_encrypt_ticket_cb;
ptls_iovec_t** ppreceiver = (ptls_iovec_t**)(((char*)encrypt_ticket) + sizeof(ptls_encrypt_ticket_t));
*ppreceiver = &ticket_psk;
ctx->encrypt_ticket = encrypt_ticket;
}
ctx->ticket_lifetime = 100000; /* 100,000 seconds, a bit more than one day */
ctx->max_early_data_size = 0xFFFFFFFF;
ctx->require_dhe_on_psk = 1;
ctx->omit_end_of_early_data = 1;
ptls_iovec_t ticket_psk2 = ptls_iovec_init(NULL, 0);
std::cerr << "ptls_save_ticket_t " << is_zrtt << std::endl;
ptls_save_ticket_t* save_ticket = (ptls_save_ticket_t*) malloc(sizeof(ptls_save_ticket_t)+ sizeof(ptls_iovec_t*)); // + sizeof(ptls_iovec_t*)
if (save_ticket != NULL) {
save_ticket->cb = tls_client_save_ticket_cb; //memory error
ptls_iovec_t** ppreceiver2 = (ptls_iovec_t**)(((char*)save_ticket) + sizeof(ptls_save_ticket_t));
*ppreceiver2 = &ticket_psk2;
ctx->save_ticket = save_ticket;
}
}
if(is_zrtt == NULL){
std::cerr << "PROUT 2 " << std::endl;
ctx->ticket_lifetime = 0; // no ticket? was: 100000; /* 100,000 seconds, a bit more than one day */
ctx->require_dhe_on_psk = 1;
ctx->omit_end_of_early_data = 0;
}
std::cerr << "ptls_get_data_ptr" << std::endl;
`cid_map`[c] = s;
std::cerr << "cid_map[c] = s;" << std::endl;
// Start the handshake if we are the client. The in_epoch is zero for "initial".
if (!is_server)
picotls_do_handshake(s,0,0,0);
>>>
}
implement create_0rtt(c:cid, is_server:bool, e:extens, he:hextens) {
<<< impure
is_rtt = true;
uint8_t *bytes;
int bbsize = 0;
std::cerr << "XXXXXXXXXXXX" << "\n";
bbsize = get_session_ticket_size();
bytes = (uint8_t*) malloc(bbsize * sizeof(uint8_t));
get_session_ticket(bytes,bbsize);
ptls_iovec_t ticket_psk;
vec_to_ptls_iovec(ticket_psk,bytes,bbsize);
ptls_context_t* ctx;
ctx = new ptls_context_t;
memset(ctx, 0, sizeof(ptls_context_t));
ctx->random_bytes = ptls_openssl_random_bytes;
ctx->key_exchanges = picotls_key_exchanges;
ctx->cipher_suites = picotls_cipher_suites;
ctx->send_change_cipher_spec = 0;
// ctx->hkdf_label_prefix = QUIC_LABEL_QUIC_BASE;
ctx->hkdf_label_prefix__obsolete = NULL;
//ctx->update_traffic_key = new ptls_update_traffic_key_t;
ctx->update_traffic_key = (ptls_update_traffic_key_t *)malloc(sizeof(ptls_update_traffic_key_t));
memset(ctx->update_traffic_key, 0, sizeof(ptls_update_traffic_key_t));
ctx->update_traffic_key->cb = quic_update_traffic_key_cb;
//ctx->on_extension = new ptls_on_extension_t;
ctx->on_extension = (ptls_on_extension_t *)malloc(sizeof(ptls_on_extension_t));
memset(ctx->on_extension, 0, sizeof(ptls_on_extension_t));
ctx->on_extension->cb = tls_on_extension_cb;
//ctx->client_mode = !is_server;
ctx->require_client_authentication = 0;
ctx->get_time = &ptls_get_time;
const char * is_zrtt = getenv("ZERORTT_TEST");
if(is_zrtt == NULL){
ctx->ticket_lifetime = 0; // no ticket? was: 100000; /* 100,000 seconds, a bit more than one day */
ctx->require_dhe_on_psk = 1;
ctx->max_early_data_size = 0xFFFFFFFF;
ctx->omit_end_of_early_data = 1;
}
else {
std::cerr << "PROUT " << is_zrtt << std::endl;
ctx->ticket_lifetime = 60 * 60 * 24;
ctx->require_dhe_on_psk = 1;
ctx->max_early_data_size = 0xFFFFFFFF;
ctx->omit_end_of_early_data = 1;
}
// ctx->use_exporter = 1; // master secrets should be recorded
ptls_handshake_properties_t *handshake_properties = new ptls_handshake_properties_t;
memset(handshake_properties, 0, sizeof(ptls_handshake_properties_t));
handshake_properties->collect_extension = tls_collect_extensions_cb;
handshake_properties->collected_extensions = tls_collected_extensions_cb;
ptls_iovec_t *alpn_vec = new(ptls_iovec_t); // TODO: will leak this
// h3-x == HTTP/3 over QUIC
// hq-x == HTTP/0.9 over QUIC
alpn_vec->base = (uint8_t*) "hq-interop";
if(const char* env_p = std::getenv("TEST_ALPN")) {
std::cerr << "TEST_ALPN " << env_p << std::endl;
alpn_vec->base = (uint8_t*) env_p;
}
alpn_vec->len = strlen((char *)(alpn_vec->base));
handshake_properties->client.negotiated_protocols.count = 1;
handshake_properties->client.negotiated_protocols.list = alpn_vec;
ptls_raw_extension_t *ptls_exts = new ptls_raw_extension_t[e.size()+he.size()];
for (unsigned i = 0; i < e.size(); i++) {
`exten_ser` ser;
std::cerr << "etype =" << std::endl;
__ser(ser,e[i]);
// Validate extension data has minimum required size
if (ser.res.size() < 4) {
std::cerr << "Extension data too small: " << ser.res.size() << " bytes, skipping" << std::endl;
continue;
}
unsigned etype = (((unsigned char)(ser.res[0])) << 8) + ((unsigned char)(ser.res[1]));
unsigned len = (((unsigned char)(ser.res[2])) << 8) + ((unsigned char)(ser.res[3]));
// Validate extension length matches available data
if (len > ser.res.size() - 4) {
std::cerr << "Extension length mismatch: claimed=" << len << " available=" << (ser.res.size()-4) << ", skipping" << std::endl;
continue;
}
// Special handling for certificate_authorities extension (type 57)
if (etype == 57) {
std::cerr << "Processing certificate_authorities extension (type 57) with length " << len << std::endl;
}
unsigned char *data = new unsigned char[ser.res.size()-4];
std::copy(ser.res.begin()+4,ser.res.end(),data);
ptls_exts[i].type = etype;
std::cerr << "etype =" << etype << std::endl;
ptls_exts[i].data.base = data;
//std::cerr << "data =" << data << std::endl;
ptls_exts[i].data.len = len;
std::cerr << "len =" << len << std::endl;
// int eres = gnutls_session_ext_register (session, "ext_name", etype,
// GNUTLS_EXT_APPLICATION, gnutls_ext_supp_recv_params,
// gnutls_ext_supp_send_params, 0,0,0,0);
// if (eres != GNUTLS_E_SUCCESS) {
// std::cerr << "gnutls_session_ext_register\n";
// exit(1);
// }
}
for (unsigned i = 0; i < he.size(); i++) {
`exten_ser` ser;
std::cerr << "etype =" << std::endl;
__ser(ser,he[i]);
// unsigned char etype = (((unsigned char)(ser.res[0])));
// unsigned len = (((unsigned char)(ser.res[1])) << 16) + (((unsigned char)(ser.res[2])) << 8) + ((unsigned char)(ser.res[3]));
// unsigned char *data = new unsigned char[ser.res.size()-4];
unsigned etype = (((unsigned char)(ser.res[0])) << 8) + ((unsigned char)(ser.res[1]));
unsigned len = (((unsigned char)(ser.res[2])) << 8) + ((unsigned char)(ser.res[3]));
unsigned char *data = new unsigned char[ser.res.size()-4];
std::copy(ser.res.begin()+4,ser.res.end(),data);
ptls_exts[e.size()+i].type = etype;
std::cerr << "etype =" << etype << std::endl;
ptls_exts[e.size()+i].data.base = data;
std::cerr << "data =" << data << std::endl;
ptls_exts[e.size()+i].data.len = len;
std::cerr << "len =" << len << std::endl;
// int eres = gnutls_session_ext_register (session, "ext_name", etype,
// GNUTLS_EXT_APPLICATION, gnutls_ext_supp_recv_params,
// gnutls_ext_supp_send_params, 0,0,0,0);
// if (eres != GNUTLS_E_SUCCESS) {
// std::cerr << "gnutls_session_ext_register\n";
// exit(1);
// }
}
ptls_exts[e.size()+he.size()].type = 0xffff;
ptls_exts[e.size()+he.size()].data.base = NULL;
ptls_exts[e.size()+he.size()].data.len = 0;
handshake_properties->additional_extensions = ptls_exts;
handshake_properties->client.negotiate_before_key_exchange = 0; // 1 = HELLORETRY
if (ticket_psk.base != NULL && !is_server) {
std::cerr << "ticket_psk " << ticket_psk.len << "\n";
//std::cerr << "ticket_psk " << ticket_psk.base << "\n";
handshake_properties->client.session_ticket.base = ticket_psk.base;
handshake_properties->client.session_ticket.len = ticket_psk.len;
size_t m = 0xFFFFFFFF; //0xFFFFFFFF
handshake_properties->client.max_early_data_size = &m;
}
// Read the certificate, if we are a server
if (is_server) {
/* Read the certificate file */
if (const char* cert_path_alt = getenv("PANTHER_IVY_CERT_PATH")) {
if (!cert_path_alt) cert_path_alt = "/opt/panther_ivy/protocol-testing/quic/leaf_cert.pem";
int r = ptls_load_certificates(ctx, cert_path_alt) != 0) {
std::cerr << "could not load certificate file leaf_cert.pem\n";
exit(1);
} else if(set_sign_certificate_from_key_file("/opt/panther_ivy/protocol-testing/quic/leaf_cert.key", ctx)) {
std::cerr << "could not load key file leaf_cert.key\n";
exit(1);
}
}
ptls_t *session;
session = ptls_new(ctx,is_server ? 1 : 0);
// Initialize data pointer to NULL to prevent callbacks from accessing garbage
*ptls_get_data_ptr(session) = NULL;
std::cerr << "PICOTLS: Initialized session data pointer to NULL for safety \n";
ptls_set_server_name(session, "servername", strlen("servername"));
if(const char* env_p = std::getenv("TEST_IMPL")) {
std::cerr << "TEST_IMPL " << env_p << std::endl;
std::cerr << "TEST_IMPL " << env_p << std::endl;
std::cerr << "is_server " << is_server << std::endl;
if(strncmp(env_p,"quic-go",10) == 0
|| strncmp(env_p,"quiche",10) == 0
|| strncmp(env_p,"lsquic",10) == 0
|| strncmp(env_p,"quinn",10) == 0
|| strncmp(env_p,"aioquic",10) == 0 || true) //TODO ask why sometime ALPN needed
if (is_server) {
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
std::cerr << "ptls_set_negotiated_protocol" << std::endl;
ptls_set_negotiated_protocol(session,
(const char*) handshake_properties->client.negotiated_protocols.list[0].base,
handshake_properties->client.negotiated_protocols.list[0].len);
}
}
picotls_connection *s = new picotls_connection(c,session,ctx,*`cb`,handshake_properties,is_server);
*ptls_get_data_ptr(session) = s;
std::cerr << "PICOTLS: Set session data pointer to connection object (id=" << c << ", is_server=" << is_server << ")\n";
`cid_map`[c] = s;
if (!is_server)
picotls_do_handshake(s,0,0,0);
std::cerr << "create 0rtt finish" << "\n";
>>>
}
implement get_old_retry_token returns (b:stream_data) {
<<< impure
const char * session_file = getenv("RETRY_TOKEN_FILE");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
std::cerr << "RETRY_TOKEN_FILE 1 " << line << std::endl;
int hex_len = strlen(line);
std::cerr << "RETRY_TOKEN_FILE hex_len " << hex_len << std::endl;
uint8_t secret[hex_len/2];
for (int j = 0; j < hex_len/2; j++) {
int a = ws_xton(line[j*2]);
int b = ws_xton(line[j*2 + 1]);
if (a == -1 || b == -1) {
is_error = true;
std::cerr << "a ERROR " << line[j*2] << std::endl;
std::cerr << "b ERROR " << line[j*2 + 1] << std::endl;
std::cerr << "RETRY_TOKEN_FILE ERROR " << std::endl;
break;
}
secret[j] = a << 4 | b;
// std::cerr << "RETRY_TOKEN_FILE a " << a << std::endl;
// std::cerr << "RETRY_TOKEN_FILE b " << b << std::endl;
// std::cerr << "RETRY_TOKEN_FILE secret[j] " << secret[j] << std::endl;
}
std::cerr << "TEST_ST 2 " << secret << std::endl;
/*for(int i = (hex_len/2)-1; i >=0 && !is_error; i--)
b.push_back(secret[i]);*/
for(int i = 0; i < hex_len/2 && !is_error; i++)
b.push_back(secret[i]);
}
}
>>>
}
implement get_old_new_token returns (b:stream_data) {
<<< impure
const char * session_file = getenv("NEW_TOKEN_FILE");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
// std::cerr << "NEW_TOKEN_FILE 1 " << line << std::endl;
int hex_len = strlen(line);
// std::cerr << "NEW_TOKEN_FILE hex_len " << hex_len << std::endl;
uint8_t secret[hex_len/2];
for (int j = 0; j < hex_len/2; j++) {
int a = ws_xton(line[j*2]);
int b = ws_xton(line[j*2 + 1]);
if (a == -1 || b == -1) {
is_error = true;
std::cerr << "a ERROR " << line[j*2] << std::endl;
std::cerr << "b ERROR " << line[j*2 + 1] << std::endl;
std::cerr << "NEW_TOKEN_FILE ERROR " << std::endl;
break;
}
secret[j] = a << 4 | b;
// std::cerr << "NEW_TOKEN_FILE a " << a << std::endl;
// std::cerr << "NEW_TOKEN_FILE b " << b << std::endl;
// std::cerr << "NEW_TOKEN_FILE secret[j] " << secret[j] << std::endl;
}
//std::cerr << "NEW_TOKEN_FILE 2 " << secret << std::endl;
/*for(int i = (hex_len/2)-1; i >=0 && !is_error; i--)
b.push_back(secret[i]);*/
for(int i = 0; i < hex_len/2 && !is_error; i++)
b.push_back(secret[i]);
}
}
>>>
}
implement destroy(c:cid) {
<<< impure
// TODO: actually delete everything here
picotls_connection *s = `cid_map`[c];
ptls_free(s->gs);
free(s->cctx);
free(s->hsp);
free(s->session_ticket);
`cid_map`.erase(c);
>>>
}
implement set_initial_keys(c:cid,salt:bytes,ikm:bytes) {
<<< impure
picotls_connection *s = `cid_map`[c];
std::cerr << "setup_initial_traffic_keys cid: " << c << "\n";
std::cerr << "setup_initial_traffic_keys session: " << s->is_server << "\n";
setup_initial_traffic_keys(s,salt,ikm);
std::cerr << "setup_initial_traffic_keys salt: " << salt << "\n";
std::cerr << "setup_initial_traffic_keys ikm: " << ikm << "\n";
>>>
}
implement iv_size(c:cid,l:level) returns (sz:index) {
<<< impure
std::cerr << "iv_size start " << "\n";
std::cerr << "iv_size cid " << c << "\n";
std::cerr << "iv_size level " << l << "\n";
// Check if c exists in cid_map
if (`cid_map`.find(c) == `cid_map`.end()) {
std::cerr << "cid " << c << " not found in cid_map\n";
return 0;
}
picotls_connection *s = `cid_map`[c];
ptls_cipher_context_t *pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_enc);
if (!pn_enc)
pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_dec);
if (!pn_enc) {
std::cerr << "cipher for level " << l << " is not set\n";
sz = 0;
}
else sz = pn_enc->algo->iv_size;
std::cerr << "iv_size end " << sz << "\n";
return sz;
>>>
}
implement encrypt_cipher(c:cid,l:level,clear:bytes,iv:bytes,recv:bool) returns (cipher:bytes) {
<<< impure
std::cerr << "encrypt_cipher start " << "\n";
std::cerr << "encrypt_cipher c " << c << "\n";
std::cerr << "encrypt_cipher iv " << iv << "\n";
picotls_connection *s = `cid_map`[c];
ptls_cipher_context_t *pn_enc;
if (recv) {
pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_dec);
std::cerr << "encrypt_cipher pn_dec " << pn_enc << "\n";
}
else {
pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_enc);
std::cerr << "encrypt_cipher pn_enc " << pn_enc << "\n";
}
if(pn_enc != 0)
encrypt_symm(pn_enc,clear,iv,cipher);
std::cerr << "encrypt_cipher end " << cipher << "\n";
return cipher;
>>>
}
implement decrypt_cipher(c:cid,l:level,cipher:bytes,iv:bytes) returns (clear:bytes) {
<<< impure
std::cerr << "decrypt_cipher start " << "\n";
picotls_connection *s = `cid_map`[c];
ptls_cipher_context_t *pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_dec);
encrypt_symm(pn_enc,cipher,iv,clear);
std::cerr << "decrypt_cipher end " << "\n";
>>>
}
implement save_token(token:stream_data) {
<<< impure
unsigned str_d[token.size()];
for (int i = 0; i < token.size(); i++)
str_d[i] = token[i];
const char * session_file = getenv("NEW_TOKEN_FILE");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
for (int i = 0; i < token.size(); i++) {
//std::cerr << "str_d[i] " << str_d[i] << std::endl;
//std::cerr << "str_d[i] == 0 " << (str_d[i] == 0) << std::endl;
if(str_d[i] < 16)
fprintf(fp, "0%x", str_d[i]);
else
fprintf(fp, "%x", str_d[i]);
}
fclose(fp);
}
>>>
}
implement save_initial_max_stream_data_uni(i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_uni");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
fprintf(fp, "%llu", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_initial_max_stream_data_uni returns (i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_uni");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint32_t) std::stoll(line);
}
}
>>>
}
implement save_initial_max_stream_data_bidi_remote(i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_bidi_remote");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
fprintf(fp, "%llu", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_initial_max_stream_data_bidi_remote returns (i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_bidi_remote");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint32_t) std::stoll(line);
}
}
>>>
}
implement save_initial_max_data(i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_data");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
fprintf(fp, "%llu", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_initial_max_data returns (i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_data");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint32_t) std::stoll(line);
}
}
>>>
}
implement save_initial_max_stream_data_bidi_local(i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_bidi_local");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
fprintf(fp, "%llu", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_initial_max_stream_data_bidi_local returns (i:stream_pos) {
<<< impure
const char * session_file = getenv("initial_max_stream_data_bidi_local");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint32_t) std::stoll(line);
}
}
>>>
}
implement save_initial_max_stream_id_bidi(i:stream_id) {
<<< impure
const char * session_file = getenv("initial_max_stream_id_bidi");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
if(i < 16)
fprintf(fp, "0%x", i);
else
fprintf(fp, "%x", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_initial_max_stream_id_bidi returns (i:stream_id) {
<<< impure
const char * session_file = getenv("initial_max_stream_id_bidi");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint16_t) std::stoll(line);
}
}
>>>
}
implement save_active_connection_id_limit(i:stream_pos) {
<<< impure
const char * session_file = getenv("active_connection_id_limit");
FILE *fp;
if(session_file != NULL) {
fp = fopen(session_file,"w");
if (fp != NULL) {
fprintf(fp, "%llu", i);
fclose(fp);
} else {
fprintf(stderr, "Warning: Could not open file %s for writing\n", session_file);
}
}
>>>
}
implement get_active_connection_id_limit returns (i:stream_pos) {
<<< impure
const char * session_file = getenv("active_connection_id_limit");
FILE *fp;
size_t len = 0;
ssize_t read;
char * line = NULL;
if(session_file != NULL) {
fp = fopen(session_file,"r");
read = getline(&line, &len, fp);
fclose(fp);
bool is_error = false;
if(line != NULL) {
i = (uint32_t) std::stoll(line);
}
}
>>>
}
implement compute_retry_integrity_tag(odcil: stream_pos, odcid: cid,
pversion: version,
dcil: stream_pos, dcid: cid,
scil: stream_pos, scid: cid,
token : stream_data,
seq:seq_num, h: stream_pos,is_recv: bool) returns (cipher:bytes) {
<<< impure
const char * session_file = getenv("RETRY_TOKEN_FILE");
FILE *fp;
if(session_file != NULL && is_recv) {
unsigned str_d[token.size()];
for (int i = 0; i < token.size(); i++)
str_d[i] = token[i];
fp = fopen(session_file,"w");
for (int i = 0; i < token.size(); i++) {
//std::cerr << "str_d[i] " << str_d[i] << std::endl;
//std::cerr << "str_d[i] == 0 " << (str_d[i] == 0) << std::endl;
if(str_d[i] < 16)
fprintf(fp, "0%x", str_d[i]);
else
fprintf(fp, "%x", str_d[i]);
}
fclose(fp);
}
uint8_t plaintext[] = "";
//0xbe 0c 69 0b 9f 66 57 5a 1d 76 6b 54 e3 68 c8 4e : rfc9001
/*uint8_t key[16] = { 0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57,
0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68,
0xc8, 0x4e };*/
//0xcc ce 18 7e d0 9a 09 d0 57 28 15 5a 6c b9 6b e1
//0xcc 0xce 0x18 0x7e 0xd0 0x9a 0x09 0xd0 0x57 0x28 0x15 0x5a 0x6c 0xb9 0x6b 0xe1 : draft 29
uint8_t key[16];
//0x4d 0x32 0xec 0xdb 0x2a 0x21 0x33 0xc8 0x41 0xe4 0x04 0x3d 0xf2 0x7d 0x44 0x30
if(pversion == 0xff00001c) {
uint8_t key2[16] = { 0x4d, 0x32, 0xec, 0xdb, 0x2a,
0x21, 0x33, 0xc8, 0x41, 0xe4,
0x04, 0x3d, 0xf2, 0x7d, 0x44,
0x30 };
for(int i = 0; i < 16;i++)
key[i] = key2[i];
}
else if(pversion == 0xff00001d) {
uint8_t key2[16] = { 0xcc, 0xce, 0x18, 0x7e, 0xd0,
0x9a, 0x09, 0xd0, 0x57, 0x28,
0x15, 0x5a, 0x6c, 0xb9, 0x6b,
0xe1 };
for(int i = 0; i < 16;i++)
key[i] = key2[i];
}
else if(pversion == 0x00000001) {
//0xbe 0x0c 0x69 0x0b 0x9f 0x66 0x57 0x5a 0x1d 0x76 0x6b 0x54 0xe3 0x68 0xc8 0x4e
uint8_t key2[16] = { 0xbe, 0x0c, 0x69, 0x0b, 0x9f,
0x66, 0x57, 0x5a, 0x1d, 0x76,
0x6b, 0x54, 0xe3, 0x68, 0xc8,
0x4e };
for(int i = 0; i < 16;i++)
key[i] = key2[i];
}
//0x461599d35d632bf2239825bb
/*uint8_t nonce[12] = { 0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b,
0xf2, 0x23, 0x98, 0x25, 0xbb };*/
//0xe5 0x49 0x30 0xf9 0x7f 0x21 0x36 0xf0 0x53 0x0a 0x8c 0x1c : draft 29
uint8_t nonce[12];
//0x4d 0x16 0x11 0xd0 0x55 0x13 0xa5 0x52 0xc5 0x87 0xd5 0x75
if(pversion == 0xff00001c) {
uint8_t nonce2[12] = { 0x4d, 0x16, 0x11, 0xd0, 0x55,
0x13, 0xa5, 0x52, 0xc5, 0x87,
0xd5, 0x75 }; //nonce[12]
for(int i = 0; i < 12; i++)
nonce[i] = nonce2[i];
}
else if(pversion == 0xff00001d) {
uint8_t nonce2[12] = { 0xe5, 0x49, 0x30, 0xf9, 0x7f,
0x21, 0x36, 0xf0, 0x53, 0x0a,
0x8c, 0x1c }; //nonce[12]
for(int i = 0; i < 12; i++)
nonce[i] = nonce2[i];
}
else if(pversion == 0x00000001) {
//0x46 0x15 0x99 0xd3 0x5d 0x63 0x2b 0xf2 0x23 0x98 0x25 0xbb
uint8_t nonce2[12] = { 0x46, 0x15, 0x99, 0xd3, 0x5d,
0x63, 0x2b, 0xf2, 0x23, 0x98,
0x25, 0xbb }; //nonce[12]
for(int i = 0; i < 12; i++)
nonce[i] = nonce2[i];
}
ptls_aead_context_t *aead = ptls_aead_new_direct(&ptls_openssl_aes128gcm, 1, key, nonce);
std::cerr << "compute_retry_integrity_tag aead " << aead << "\n";
uint32_t checksum_length = aead->algo->tag_size;
std::cerr << "c 3 \n";
std::cerr << "compute_retry_integrity_tag ptls_aead_context_t " << "\n";
std::vector<uint8_t> ad;
//ad.resize(sizeof(odcid));
std::cerr << "compute_retry_integrity_tag odcil " << odcil << "\n";
std::cerr << "compute_retry_integrity_tag odcid " << std::hex << odcid << "\n";
std::cerr << "compute_retry_integrity_tag h " << h << "\n";
std::cerr << "compute_retry_integrity_tag pversion " << std::hex << pversion << "\n";
std::cerr << "compute_retry_integrity_tag dcil " << dcil << "\n";
std::cerr << "compute_retry_integrity_tag dcid " << std::hex << dcid << "\n";
std::cerr << "compute_retry_integrity_tag scil " << scil << "\n";
std::cerr << "compute_retry_integrity_tag scid " << std::hex << scid << "\n";
std::cerr << "compute_retry_integrity_tag seq " << std::dec << seq << "\n";
uint8_t pushed;
std::cerr << "compute_retry_integrity_tag odcil \n";
ad.push_back(odcil);
for (int i = odcil-1; i >= 0; --i) {
pushed = (odcid.val >> (8*i)) & 0xff;
std::cerr << std::to_string(pushed) << " ";
ad.push_back(pushed);
}
std::cerr << "\n";
ad.push_back(h);
std::cerr << "compute_retry_integrity_tag version \n";
for (int i = 4-1; i >= 0; --i) {
pushed = (pversion >> (8*i)) & 0xff;
std::cerr << std::to_string(pushed) << " ";
ad.push_back(pushed);
}
std::cerr << "\n";
std::cerr << "compute_retry_integrity_tag dcid \n";
ad.push_back(dcil);
for (int i = dcil-1; i >= 0; --i) {
pushed = (dcid.val >> (8*i)) & 0xff;
std::cerr << std::to_string(pushed) << " ";
ad.push_back(pushed);
}
std::cerr << "\n";
std::cerr << "compute_retry_integrity_tag scid \n";
ad.push_back(scil); //scil
for (int i = scil-1; i >= 0; --i) {
pushed = (scid.val >> (8*i)) & 0xff;
std::cerr << std::to_string(pushed) << " ";
ad.push_back(pushed);
}
std::cerr << "\n";
std::cerr << "compute_retry_integrity_tag token size: " << token.size() << "\n";
for (unsigned i = 0; i < token.size(); i++) {
std::cerr << std::hex << token[i] << ' ';
ad.push_back(token[i]);
}
std::cerr << "\n";
//std::copy(token.begin(),token.end(),ad.end());
std::vector<uint8_t> bytes;
bytes.resize(ad.size());
std::cerr << "compute_retry_integrity_tag ad size: " << std::dec << ad.size() << "\n";
std::cerr << "\n";
std::copy(ad.begin(),ad.end(),bytes.begin());
std::cerr << "compute_retry_integrity_tag bytes size: " << std::dec << bytes.size() << "\n";
std::cerr << "\n";
std::vector<uint8_t> output;
output.resize(16);
std::cerr << "compute_retry_integrity_tag output size: " << std::dec << output.size() << "\n";
size_t encrypted = ptls_aead_encrypt(aead,
&output[0], &plaintext[0], 0 , seq, //seq, strnlen ?strlen(plaintext)
&bytes[0], bytes.size());
cipher.resize(output.size());
std::copy(output.begin(),output.end(),cipher.begin());
std::cerr << "compute_retry_integrity_tag encrypted size: " << std::dec << encrypted << "\n";
std::cerr << "compute_retry_integrity_tag output size: " << std::dec << output.size() << "\n";
std::cerr << "\n";
std::cerr << "compute_retry_integrity_tag finish " << "\n";
>>>
}
implement encrypt_aead(c:cid,l:level,clear:bytes,seq:seq_num,ad:bytes) returns (cipher:bytes) {
<<< impure
std::cerr << "encrypt_aead start l " << l << "\n";
std::cerr << "encrypt_aead start c " << c << "\n";
std::cerr << "encrypt_aead start seq " << seq << "\n";
picotls_connection *s = `cid_map`[c];
ptls_aead_context_t *aead = (ptls_aead_context_t *)(s->crypto_context[l].aead_encrypt);
std::cerr << "encrypt_aead aead " << aead << "\n";
uint32_t checksum_length = aead->algo->tag_size;
std::vector<uint8_t> bytes;
bytes.resize(ad.size());
std::copy(ad.begin(),ad.end(),bytes.begin());
std::vector<uint8_t> input, output;
input.resize(clear.size());
std::copy(clear.begin(),clear.end(),input.begin());
output.resize(clear.size() + checksum_length);
std::cerr << "encrypt_aead encrypted 1" << "\n";
size_t encrypted = ptls_aead_encrypt(aead,
&output[0], &input[0], input.size(), seq,
&bytes[0], bytes.size());
std::cerr << "encrypt_aead encrypted " << encrypted << "\n";
cipher.resize(output.size());
std::copy(output.begin(),output.end(),cipher.begin());
std::cerr << "encrypt_aead finish " << "\n";
return cipher;
>>>
}
implement decrypt_aead(c:cid,l:level,cipher:bytes,seq:seq_num,ad:bytes)
returns (res:decrypt_result) {
<<< impure
std::cerr << "decrypt_aead start " << "\n";
std::cerr << "decrypt_aead ad " << ad.size() << "\n";
picotls_connection *s = `cid_map`[c];
ptls_aead_context_t *aead = (ptls_aead_context_t *)(s->crypto_context[l].aead_decrypt);
std::cerr << "aead == " << aead << "\n";
if(aead != 0) {
uint32_t checksum_length = aead->algo->tag_size;
std::cerr << "checksum_length == " << checksum_length << "\n";
std::vector<uint8_t> bytes;
bytes.resize(ad.size());
std::copy(ad.begin(),ad.end(),bytes.begin());
std::cerr << "seq == " << seq << "\n";
std::cerr << "bytes.size() == " << bytes.size() << "\n";
std::vector<uint8_t> input, output;
input.resize(cipher.size());
std::copy(cipher.begin(),cipher.end(),input.begin());
output.resize(cipher.size() - checksum_length);
size_t decrypted = ptls_aead_decrypt(aead,
&output[0],
&input[0],
input.size(),
seq,
&bytes[0], bytes.size());
res.ok = decrypted <= input.size();
std::cerr << "decrypted <= input.size() == " << (decrypted <= input.size()) << "\n";
if (res.ok) {
res.data.resize(output.size());
std::copy(output.begin(),output.end(),res.data.begin());
}
} else {
std::cerr << "decrypt_aead failure " << "\n";
res.ok = false;
}
std::cerr << "decrypt_aead finish " << "\n";
>>>
}
implement upper.send(c:cid,data:bytes) {
<<< impure
// TODO: implement this
//picotls_connection *s = `cid_map`[c];
std::cerr << "upper.send s " << "\n";
>>>
}
implement lower.recv(c:cid,data:bytes,lev:lower.level) {
<<< impure
std::cerr << "lower.recv c " << c << "\n";
picotls_connection *s = `cid_map`[c];
std::cerr << "lower.recv s " << s << "\n";
std::vector<char> &input = s->input;
for (unsigned i = 0; i < data.size(); i++) {
input.push_back(data[i]);
}
// TODO: make the epoch a parameter of this call
// For now, we assume that the epochs come in order
size_t in_epoch = ptls_get_read_epoch(s->gs);
const char * test_type = getenv("TEST_TYPE");
if(test_type != NULL && strcmp(test_type,"mim") != 0) {
picotls_do_handshake(s,in_epoch,&(s->input[0]),s->input.size());
std::cerr << "before clear" << std::endl;
s->input.clear();
std::cerr << "after clear" << std::endl;
} else {
std::cerr << "mim test -> no handshake" << std::endl;
}
>>>
}
trusted isolate iso = this
attribute test = impl
}
}