include quic_connection
include attack_connection
include tls_msg
include serdes
include quic_deser
include quic_ser
include quic_deser_vn
include quic_ser_vn
include quic_deser_retry
include quic_ser_retry
include quic_deser_zerortt
include quic_ser_zerortt
include quic_deser_forged
include quic_ser_forged
include quic_protection
include random_value
include quic_network_controler
The QUIC test shim¤
This shim translates between the randomized mirror process generated by Ivy for the QUIC specification, and the test locale. The test locale contains a server or client implementation under test (as a separate process), the network, and one instance of TLS for each client or server process that communcates with the process under test.
The shim makes this connection by two methods:
- It uses a implements clause to attach code to actions.
- It implements call-back actions of the processes in the locale
In particular, the implementations of protocol actions can send messages by UDP to the client/server under test. Reception of messages can in turn trigger inferred protocol actions.
The test shim uses an instance of the QUIC protection module to protect packts (see comment below). This module in turn uses the services of TLS.
instance prot : quic_protection(tls_api.id,tls_api.upper)
include quic_endpoint
include quic_locale
include quic_loss_recovery
include quic_congestion_control
include ivy_quic_server
include ivy_quic_client
include ivy_quic_client_server
include ivy_quic_victim
include ivy_quic_mim
When a UDP datagram arrives, decrypt it, deserialize it, then
generate a packet_event.
Note: the net API deserializes the datagram into a sequence of
packets. Thus, we have to iterate over the packets. If a packet
is undecryptable, we call the action undecryptable_packet_event.
This is not necessarily a protocol error, as an undecryptable
packet may be a stateless reset.
Test type config¤
relation initial_keys_set(C:cid)
relation tp_client_set # (C:cid) TODO strange segfault for level 2 not set with quant
function client_initial_rcid : cid
function client_initial_scid : cid
function client_initial_scil : stream_pos
function client_initial_dcid : cid
function client_initial_dcil : stream_pos
function client_initial_version : version
relation client_non_zero_scil
relation zero_rtt_allowed
relation zero_rtt_sent
relation send_connection_close # TODO, send co_close at end of test or not
after init {
initial_keys_set(C) := false;
tp_client_set := false;
client_non_zero_scil := false;
zero_rtt_allowed := false;
zero_rtt_sent := false;
send_connection_close := false;
}
relation zero_rtt_client_test
relation zero_rtt_server_test # TODO should be parameters
function nclients : stream_pos
instance cids : array(index,cid)
function the_cids : cids
function server_cids : cids
Ps
for modelisation purpose, for each differents client, we associate one virtual server Should only instanciate one server TODO
instance clients : quic_endpoint.clients_ep(client_addr,client_port,2)
instance servers : quic_endpoint.servers_ep(server_addr,server_port,2)
var the_cid_alt : cid
var server_cid_alt : cid
instance ip_endpoints : array(index,ip.endpoint)
relation allowed_migration
relation allowed_multiple_migration
relation first_datagram_received
function last_datagram_received_size : stream_pos
relation version_negociated
function initial_version : version # init in each entities/test
relation negocation_of_version(E:ip.endpoint)
relation negocation_of_version_initiated(E:ip.endpoint)
after init {
zero_rtt_client_test := false;
zero_rtt_server_test := false;
allowed_migration := true;
allowed_multiple_migration := false;
version_negociated := false;
negocation_of_version_initiated(E) := false;
negocation_of_version(E):= false;
first_datagram_received := false;
last_datagram_received_size := 0;
nclients := 1;
}
RTT config¤
var early_data_end : stream_data after init { # Need to be local for mvfst STRANGE # TODO global -> quic-go crash if not global early_data_end := stream_data.empty; early_data_end := early_data_end.append(0xff); early_data_end := early_data_end.append(0xff); early_data_end := early_data_end.append(0xff); early_data_end := early_data_end.append(0xff); }
Padding-only packet management¤
function last_packet_type(C:cid) : quic_packet_type
function last_packet_length(C:cid) : stream_pos
function total_data_received: stream_pos
function total_data_sent : stream_pos
after init {
last_packet_type(C) := quic_packet_type.initial;
last_packet_length(C) := 1200;
total_data_received := 0;
total_data_sent := 0;
}
Version (negociation) config¤
parameter iversion : stream_pos = 0x1
parameter vnversion : stream_pos = 0x1 # TODO
relation version_not_found(E:ip.endpoint)
var supported_versions : versions
var final_version : version # TODO test function
var supported_versions_bv : versions_bv
after init {
supported_versions := versions.empty;
var v1 := stream_data.empty;
supported_versions_bv := versions_bv.empty;
if iversion = 1 {
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x01); # TODO stop bv and non-bv conversion
supported_versions_bv := supported_versions_bv.append(0x00000001);
initial_version := 0x00000001;
} else if iversion = 34 {
v1 := v1.append(0xff);
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x22); # TODO
supported_versions_bv := supported_versions_bv.append(0xff000022);
initial_version := 0xff000022;
} else if iversion = 29 {
v1 := v1.append(0xff);
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x1d); # TODO
supported_versions_bv := supported_versions_bv.append(0xff00001d);
initial_version := 0xff00001d;
} else if iversion = 28 {
v1 := v1.append(0xff);
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x1c); # TODO
supported_versions_bv := supported_versions_bv.append(0xff00001c);
initial_version := 0xff00001c;
} else if iversion = 27 {
v1 := v1.append(0xff);
v1 := v1.append(0x0);
v1 := v1.append(0x0);
v1 := v1.append(0x1b); # TODO
supported_versions_bv := supported_versions_bv.append(0xff00001b);
initial_version := 0xff00001b;
};
supported_versions := supported_versions.append(v1);
final_version := 0x0000000; # This is init value, meaning that VN is proceed or not
version_not_found(E) := false;
}
implement net.recv(host:endpoint_id, s:net.socket, src:ip.endpoint, pkts:prot.arr) {
call show_socket_debug_event(s);
if(is_lost_recv) {
call on_purpose_lost_packet_event(host,src,pkts);
} else {
if host = endpoint_id.server { # for client test (tested implem = client <-> ivy implem = server)
call server.behavior(host,s,src,pkts);
} else if host = endpoint_id.client | host = endpoint_id.client_alt { # for server test (tested implem = server <-> ivy implem = client)
call client.behavior(host,s,src,pkts);
} else {
call undefined_host_error(host,s,src);
};
}
}
import action recv_packet(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:quic_packet)
import action recv_packet_mim(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:stream_data)
import action recv_protected_packet_mim(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:forged_protected_quic_packet)
import action recv_packet_victim(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:stream_data)
import action padding_packet_event(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:stream_data)
import action undecryptable_packet_event(host:endpoint_id,src:ip.endpoint,dst:ip.endpoint,pkt:stream_data)
import action on_purpose_lost_packet_event(host:endpoint_id,src:ip.endpoint,pkt:prot.arr)
import action undefined_host_error(host:endpoint_id, s:net.socket, src:ip.endpoint)
import action show_last_datagram_size(size:stream_pos)
import action show_socket_debug_event(n:net.socket)
Here, we connect protocol events at the security layer to API calls of the TLS 1.3 service (a part of the test locale).
TLS send event shim¤
When a TLS instance in the locale sends message data, we generate a
tls_send_event. This causes the data to be recorded in the
appropriate abstract crypto stream, and later to be transmitted via
a generated crypto frame event.
TODO mvfst no helloretry mvfst &ptls_openssl_x25519,&ptls_openssl_secp256r1 other &ptls_openssl_secp256r1, &ptls_openssl_x25519 TODO
TODO merge shim for client
implement tls_api.lower.send(tls_id:tls_api.id, bytes:stream_data, lev:tls_api.lower.level) {
var early_data_end := stream_data.empty; # TODO global -> quic-go crash if not global
call show_biatch_debug_event(tls_id_to_dst(tls_id));
early_data_end := early_data_end.append(0xff);
early_data_end := early_data_end.append(0xff);
early_data_end := early_data_end.append(0xff);
early_data_end := early_data_end.append(0xff);
var e := quic_packet_type.initial if lev = 0
else (quic_packet_type.handshake if lev = 2 else quic_packet_type.zero_rtt);
if(bytes.value(0) = 0x4 & bytes.segment(bytes.end-4,bytes.end) = early_data_end) {
e := quic_packet_type.one_rtt; # TODO
};
var scid := tls_id_to_cid(tls_id);
call tls_send_event(tls_id_to_src(tls_id), tls_id_to_dst(tls_id), scid,
0, bytes,crypto_data_end(scid,e),e, tls_id);
}
import action show_biatch_debug_event(src:ip.endpoint)
import action show_tls_lower_send_debug_event(bytes:stream_data)
after tls_send_event(src:ip.endpoint, dst:ip.endpoint, scid:cid, dcid:cid, data : stream_data,
pos:stream_pos, e:quic_packet_type, tls_id:tls_api.id) {
call show_tls_send_event(src,dst,scid,dcid,data,pos,e, tls_id);
}
This occurs when a TLS instance establishes the encryption keys for an encryption
level. This is translated into a tls_keys_established_event at the security layer.
implement tls_api.upper.keys_established(tls_id:tls_api.id,lev:tls_api.upper.level) {
var e := quic_packet_type.handshake if lev = 2 else quic_packet_type.zero_rtt;
call tls_keys_established_event(tls_id_to_cid(tls_id),e); #tls_id = server.tls_id for client ?
}
import action show_tls_id_to_cid_debug_event(ver:cid)
When TLS handshake data is conceputally generated by the peer, we feed it to the real TLS.
Todo
We do it at this point because we may need it to generate the
keys for the next packet to be decrypted. This should really happen
on a tls_recv_event, but that would be too late. Of course, this could
happen in reality. That is, a 1-rtt packet could arrive before the
handshake that establishes the keys. The trouble is this will happen too
frequently if we delay the TLS reception event. Perhaps the solution to
this is to infer a TLC reception event after an incoming packet if there
were any crypto frames.
after tls.handshake_data_event(src : ip.endpoint, dst : ip.endpoint, data:stream_data) {
if dst_is_generated_tls(dst) {
call tls_api.lower.recv(src_tls_id(dst),data,0); # TODO: fill in the encryption level
}
}
This event corresponds to the client creating a new connection. We set up the initial keys based on the nonce cid, which is used as initial key material. Note, the "salt" is specified in the QUIC-TLS document.
Todo
this assumes the cid length is 8 bytes. Also, the ikm and salt should really be computed in the protection layer and passed to TLS here in the shim.
after tls_client_initial_request(src:ip.endpoint,dst:ip.endpoint,nonce:cid, pversion:version, id:tls_api.id) {
client_initial_scil := scid_size_pos(false);
var ikm := cid_to_bytes(nonce,dcid_size_cl(retry_response(the_cid)));
call show_set_initial_keys(ikm, id);
var salt : stream_data := stream_data.empty;
if pversion = 0xfaceb002 | pversion = 0xff00001b | pversion = 0xff00001c {
salt := salt.append(0xc3);
salt := salt.append(0xee);
salt := salt.append(0xf7);
salt := salt.append(0x12);
salt := salt.append(0xc7);
salt := salt.append(0x2e);
salt := salt.append(0xbb);
salt := salt.append(0x5a);
salt := salt.append(0x11);
salt := salt.append(0xa7);
salt := salt.append(0xd2);
salt := salt.append(0x43);
salt := salt.append(0x2b);
salt := salt.append(0xb4);
salt := salt.append(0x63);
salt := salt.append(0x65);
salt := salt.append(0xbe);
salt := salt.append(0xf9);
salt := salt.append(0xf5);
salt := salt.append(0x02);
}
else if pversion = 0xff00001d {
salt := salt.append(0xaf);
salt := salt.append(0xbf);
salt := salt.append(0xec);
salt := salt.append(0x28);
salt := salt.append(0x99);
salt := salt.append(0x93);
salt := salt.append(0xd2);
salt := salt.append(0x4c);
salt := salt.append(0x9e);
salt := salt.append(0x97);
salt := salt.append(0x86);
salt := salt.append(0xf1);
salt := salt.append(0x9c);
salt := salt.append(0x61);
salt := salt.append(0x11);
salt := salt.append(0xe0);
salt := salt.append(0x43);
salt := salt.append(0x90);
salt := salt.append(0xa8);
salt := salt.append(0x99);
}
else if pversion = 0x00000001 | pversion = 0xff000022 {
salt := salt.append(0x38);
salt := salt.append(0x76);
salt := salt.append(0x2c);
salt := salt.append(0xf7);
salt := salt.append(0xf5);
salt := salt.append(0x59);
salt := salt.append(0x34);
salt := salt.append(0xb3);
salt := salt.append(0x4d);
salt := salt.append(0x17);
salt := salt.append(0x9a);
salt := salt.append(0xe6);
salt := salt.append(0xa4);
salt := salt.append(0xc8);
salt := salt.append(0x0c);
salt := salt.append(0xad);
salt := salt.append(0xcc);
salt := salt.append(0xbb);
salt := salt.append(0x7f);
salt := salt.append(0x0a);
};
call tls_api.upper.set_initial_keys(id,salt,ikm); ## WTF TODO error id tls_api.upper.set_initial_keys(id,salt,ikm);
}
import action show_l(ver:stream_pos)
This event corresponds to the server responding to client creating a new connection. We set up the initial keys based on the destination cid, which is used as initial key material. Note, the "salt" is specified in the QUIC-TLS document.
Todo
this assumes the cid length is 8 bytes. Also, the ikm and salt should really be computed in the protection layer and passed to TLS here in the shim.
after tls_client_initial_response(src:ip.endpoint,dst:ip.endpoint,spkt: stream_data) {
if nclients > 1 {
var cdx := clients.clients.begin;
while cdx < clients.clients.end {
var cc := clients.clients.value(cdx);
cdx := cdx.next;
}
} else {
call client.set_ep(src);
}
var version := bytes_to_version(spkt.segment(1,5));
var lens := spkt.value(5);
var dcil : stream_pos := bfe[0][7](spkt.value(5));
var ikm := cid_to_bytes(0,1); # dcid
if(~dcil = 0) {
client_initial_dcil := dcil;
ikm := spkt.segment(6,6+dcil); # dcid
};
var dcid : cid := bytes_to_cid(ikm);
var scil : stream_pos := bfe[0][7](spkt.value(6+dcil));
var skm := cid_to_bytes(0,1); # scid
if(~scil = 0) {
client_initial_scil := scil;
client_non_zero_scil := true;
skm := spkt.segment(6+dcil+1,6+dcil+1+scil); # scid
};
var scid : cid := bytes_to_cid(skm);
if scil = 0 | dcil = 0 {
issued_zero_length_cid := true;
}
require dcil >= 8;
if ~retry_sent(dcid) {
client_initial_dcid := dcid;
client_initial_scid := scid; # skm
call export_length_cid_extension(dcil,scil);
call export_length_cid(dcil,scil);
};
if ~tp_client_set | negocation_of_version(src) {
var extns := tls_extensions.empty;
extns := extns.append(make_transport_parameters);
if zero_rtt_client_test {
call tls_api.upper.create_0rtt_client(0,true,extns);
} else {
call tls_api.upper.create(0,true,extns);
}
tp_client_set := true;
};
client_initial_version := version;
if client_initial_version ~= initial_version & client_initial_version ~= 0xfaceb002 { #initial_version todo
negocation_of_version(src) := true;
}
else if (~initial_keys_set(dcid) & retry_client_test -> retry_sent(dcid)) | negocation_of_version(src) {
call export_length_cid_extension(dcil,scil);
negocation_of_version(src) := false;
var salt : stream_data := stream_data.empty;
if client_initial_version = 0xfaceb002
| client_initial_version = 0xff00001b
| client_initial_version = 0xff00001c {
salt := salt.append(0xc3);
salt := salt.append(0xee);
salt := salt.append(0xf7);
salt := salt.append(0x12);
salt := salt.append(0xc7);
salt := salt.append(0x2e);
salt := salt.append(0xbb);
salt := salt.append(0x5a);
salt := salt.append(0x11);
salt := salt.append(0xa7);
salt := salt.append(0xd2);
salt := salt.append(0x43);
salt := salt.append(0x2b);
salt := salt.append(0xb4);
salt := salt.append(0x63);
salt := salt.append(0x65);
salt := salt.append(0xbe);
salt := salt.append(0xf9);
salt := salt.append(0xf5);
salt := salt.append(0x02);
};
if client_initial_version = 0xff00001d {
salt := salt.append(0xaf);
salt := salt.append(0xbf);
salt := salt.append(0xec);
salt := salt.append(0x28);
salt := salt.append(0x99);
salt := salt.append(0x93);
salt := salt.append(0xd2);
salt := salt.append(0x4c);
salt := salt.append(0x9e);
salt := salt.append(0x97);
salt := salt.append(0x86);
salt := salt.append(0xf1);
salt := salt.append(0x9c);
salt := salt.append(0x61);
salt := salt.append(0x11);
salt := salt.append(0xe0);
salt := salt.append(0x43);
salt := salt.append(0x90);
salt := salt.append(0xa8);
salt := salt.append(0x99);
};
if client_initial_version = 0x00000001 | client_initial_version = 0xff000022 {
salt := salt.append(0x38);
salt := salt.append(0x76);
salt := salt.append(0x2c);
salt := salt.append(0xf7);
salt := salt.append(0xf5);
salt := salt.append(0x59);
salt := salt.append(0x34);
salt := salt.append(0xb3);
salt := salt.append(0x4d);
salt := salt.append(0x17);
salt := salt.append(0x9a);
salt := salt.append(0xe6);
salt := salt.append(0xa4);
salt := salt.append(0xc8);
salt := salt.append(0x0c);
salt := salt.append(0xad);
salt := salt.append(0xcc);
salt := salt.append(0xbb);
salt := salt.append(0x7f);
salt := salt.append(0x0a);
};
call show_set_initial_keys(ikm, 0);
call tls_api.upper.set_initial_keys(0,salt,ikm);
initial_keys_set(dcid) := true;
}
}
import action show_set_initial_keys(ik: stream_data, id: tls_api.id)
import action show_version(ver:version)
import action show_kk
If the version selected by the client is not acceptable to the server, the server responds with a Version Negotiation packet; see Section 17.2.1. This includes a list of versions that the server will accept. An endpoint MUST NOT send a Version Negotiation packet in response to receiving a Version Negotiation packet.
This system allows a server to process packets with unsupported versions without retaining state. Though either the Initial packet or the Version Negotiation packet that is sent in response could be lost, the client will send new packets until it successfully receives a response or it abandons the connection attempt. As a result, the client discards all state for the connection and does not send any more packets on the connection.
Version Negotiation packets are designed to allow for functionality to be defined in the future that allows QUIC to negotiate the version of QUIC to use for a connection. Future Standards Track specifications might change how implementations that support multiple versions of QUIC react to Version Negotiation packets received in response to an attempt to establish a connection using this version.
We simply resend Initial packet
after tls_client_version_response(src:ip.endpoint,dst:ip.endpoint,spkt: stream_data) {
var tls_id := src_tls_id(src);
var dcil : stream_pos := bfe[0][7](spkt.value(5));
var dcid := prot.bytes_to_cid(spkt.segment(6,6+dcil));
var scil : stream_pos := bfe[0][7](spkt.value(6+dcil));
var scid := prot.bytes_to_cid(spkt.segment(7+dcil,7+dcil+scil));
var versions_vn := spkt.segment(3 + 4 + dcil + scil,spkt.end);
call export_length_cid_extension(dcil,scil);
if version_not_found(src) {
versions_vn := spkt.segment(0,spkt.end);
};
var sv := versions.empty;
var idx := versions_vn.begin;
while (~versions_vn.value(idx) = 0xff | ~versions_vn.value(idx) = 0x00) & version_not_found(src) {
idx := idx.next;
};
while idx < versions_vn.end {
var i : stream_pos := 0;
var v := stream_data.empty;
while i < 4 {
v := v.append(versions_vn.value(idx));
i := i + 1;
idx := idx.next;
};
sv := sv.append(v);
};
var idxx : index := 0;
var idxx_bv : index := 0;
while idxx < sv.end {
var ii : index := 0 ;
while ii < supported_versions.end {
if sv.value(idxx) = supported_versions.value(ii) {
final_version := supported_versions_bv.value(idxx_bv);
idxx_bv := idxx_bv.next;
};
ii := ii.next;
};
idxx := idxx.next;
};
if final_version ~= 0x00000000 {
version_negociated := true;
var pkt := pkt_serdes_vn.from_bytes(spkt);
pkt.ptype := quic_packet_type.version_negociation; # no real type so hardcode
call recv_vn_pkt(src,dst,pkt);
call infer_tls_events_vn(src,dst,pkt);
call packet_event_vn(src,dst,pkt); # also an inferred event
} else {
version_not_found(src) := true;
call version_not_found_event;
};
}
import action recv_vn_pkt(src:ip.endpoint,dst:ip.endpoint,spkt: quic_packet_vn)
after tls_client_retry_response(src:ip.endpoint,dst:ip.endpoint,spkt: stream_data) {
header_retry := bfe[0][7](spkt.value(0));
var dcil : stream_pos := bfe[0][7](spkt.value(5));
var dcid := prot.bytes_to_cid(spkt.segment(6,6+dcil));
var scil : stream_pos := bfe[0][7](spkt.value(6+dcil));
var scid := prot.bytes_to_cid(spkt.segment(7+dcil,7+dcil+scil));
call export_length_cid_extension(scil,dcil);
var pkt := pkt_serdes_retry.from_bytes(spkt);
pkt.ptype := quic_packet_type.retry;
call recv_retry_pkt(src,dst,pkt);
call infer_tls_events_retry(src,dst,pkt);
retry_token(dcid) := pkt.token;
if pkt.token.end = 0 {
zero_length_token := true;
};
retry_response(dcid) := true;
call packet_event_retry(src,dst,pkt); # also an inferred event
}
after tls_client_0rtt_response(src:ip.endpoint,dst:ip.endpoint,spkt: stream_data) {
if nclients > 1 {
var cdx := clients.clients.begin;
while cdx < clients.clients.end {
var cc := clients.clients.value(cdx);
cdx := cdx.next;
}
} else {
call client.set_ep(src);
}
var ver := bytes_to_version(spkt.segment(1,5));
var lens := spkt.value(5);
var dcil : stream_pos := bfe[0][7](spkt.value(5));
var ikm := cid_to_bytes(0,1); # dcid
if(~dcil = 0) {
client_initial_dcil := dcil;
ikm := spkt.segment(6,6+dcil); # dcid
};
var scil : stream_pos := bfe[0][7](spkt.value(6+dcil));
var skm := cid_to_bytes(0,1); # scid
if(~scil = 0) {
client_initial_scil := scil;
client_non_zero_scil := true;
skm := spkt.segment(6+dcil+1,6+dcil+1+scil); # scid
};
require dcil >= 8;
client_initial_dcid := bytes_to_cid(ikm);
client_initial_scid := bytes_to_cid(skm); # skm
call export_length_cid_extension(scil,dcil);
var pkt := pkt_serdes_0rtt.from_bytes(spkt);
pkt.ptype := quic_packet_type.zero_rtt;
call recv_0rtt_pkt(src,dst,pkt);
call infer_tls_events_0rtt(src,dst,pkt);
call packet_event_0rtt(src,dst,pkt); # also an inferred event
}
import action recv_retry_pkt(src:ip.endpoint,dst:ip.endpoint,spkt: quic_packet_retry)
import action recv_0rtt_pkt(src:ip.endpoint,dst:ip.endpoint,spkt: quic_packet_0rtt)
import action version_not_found_event
To estimate the sequence number of packets, we have to know the encryption level. This action gets the encryption level from the packet header.
action packet_encryption_level(h:prot.header_info) returns (e:quic_packet_type) = {
e := quic_packet_type.zero_rtt if ~h.hdr_long # & ~established_1rtt_keys(scid)
else (quic_packet_type.initial if h.hdr_type = 0x7f
else quic_packet_type.handshake);
}
action packet_encryption_level_up(h:prot.header_info) returns (e:quic_packet_type) = {
e := quic_packet_type.zero_rtt if ~h.hdr_long #& ~established_1rtt_keys(scid)
else (quic_packet_type.initial if bvand(h.hdr_type,0x30) = 0x00
else quic_packet_type.handshake);
}
action packet_scid(h:prot.header_info) returns (scid:cid) = {
if h.hdr_long {
scid := h.scid;
} else {
if used_cid(h.dcid) {
scid := connected_to(h.dcid);
} else {
scid := 0;
}
}
}
last_pkt_num(scid,e) where e is the
encryption level. We infer the encryption level from the packet type.
action reference_pkt_num(spkt:stream_data,decrypt:bool) returns (pnum:pkt_num) = {
var h := prot.get_header_info(spkt,decrypt);
var e := packet_encryption_level(h);
var scid := packet_scid(h);
last_packet_type(scid) := packet_encryption_level_up(h);
last_packet_length(scid) := h.payload_length;
pnum := last_pkt_num(scid,e);
}
action is_padding_packet(spkt:stream_data) returns (is_padding:bool) = {
<<<
is_padding = true;
for (unsigned i = 0; i < spkt.size(); i++)
is_padding = is_padding && (spkt[i] == 0);
>>>
}
action is_random_padding_packet(spkt:stream_data) returns (is_padding:bool) = {
var h := prot.get_header_info(spkt,true);
var e := packet_encryption_level_up(h);
if last_packet_type(h.scid) = quic_packet_type.initial & last_packet_length(h.scid) < 1200 { # Hack
is_padding := true;
} else {
is_padding := false;
};
}
instance pkt_serdes : serdes(quic_packet,stream_data,quic_ser,quic_deser)
instance pkt_serdes_vn : serdes(quic_packet_vn,stream_data,quic_ser_vn,quic_deser_vn)
instance pkt_serdes_retry : serdes(quic_packet_retry,stream_data,quic_ser_retry,quic_deser_retry)
instance pkt_serdes_0rtt_coal : serdes(quic_packet_coal_0rtt,stream_data,quic_ser_zerortt,quic_deser_zerortt)
instance pkt_serdes_0rtt : serdes(quic_packet_0rtt,stream_data,quic_ser_zerortt,quic_deser_zerortt)
instance forged_protected_pkt_serdes : serdes(forged_protected_quic_packet,stream_data,quic_ser_forged,quic_deser_forged)
instance forged_pkt_serdes : serdes(forged_quic_packet,stream_data,quic_ser,quic_deser)
instance forged_pkt_serdes_vn : serdes(forged_quic_packet_vn,stream_data,quic_ser_vn,quic_deser_vn)
instance forged_pkt_serdes_retry : serdes(forged_quic_packet_retry,stream_data,quic_ser_retry,quic_deser_retry)
instance replayed_pkt_serdes_0rtt : serdes(replayed_quic_packet_0rtt,stream_data,quic_ser_zerortt,quic_deser_zerortt)
action cid_to_bytes(c:cid,len:cid_length) returns(res:stream_data) = {
<<<
res.resize(len);
for (unsigned i = 0; i < len; i++) {
res[len-i-1] = 0xff & (c.val >> (i * 8));
}
>>>
}
action cid_to_tls_id(c:cid) returns(res:tls_api.id) = {
<<<
res = c.val;
>>>
}
action cidseq_to_seqnum(c:cid_seq) returns(res:pkt_num) = {
<<<
res = c.val;
>>>
}
action seqnum_to_streampos(c:pkt_num) returns(res:stream_pos) = {
<<<
res = c;
>>>
}
action streampos_to_seqnum(c:stream_pos) returns(res:pkt_num) = {
<<<
res = c;
>>>
}
action dcid_size_cl(cond:bool) returns(res:cid_length) = {
<<<
res = 0;
if(const char* env_p2 = std::getenv("TEST_TYPE")) {
if(strcmp(env_p2, "client") == 0 || cond) {
if(const char* env_p3 = std::getenv("TEST_DCIL")) {
std::cerr << "TEST_DCIL " << env_p3 << "\n";
res = atoi(env_p3);
}
else
res = 8;
} else
res = 8;
} else
res = 8;
std::cerr << "dcid_size_cl size: " << res << "\n";
>>>
}
action scid_size_pos(cond:bool) returns(res:stream_pos) = {
<<<
res = 0;
if(const char* env_p2 = std::getenv("TEST_TYPE")) {
if(strcmp(env_p2, "server") == 0 || cond) {
if(const char* env_p3 = std::getenv("TEST_SCIL")) {
std::cerr << "TEST_SCIL " << env_p3 << "\n";
res = atoi(env_p3);
} else
res = 8;
} else
res = 8;
} else
res = 8;
std::cerr << "scid_size_pos size: " << res << "\n";
>>>
}
action dcid_size_pos(cond:bool) returns(res:stream_pos) = {
<<<
res = 0;
if(const char* env_p2 = std::getenv("TEST_TYPE")) {
if(strcmp(env_p2, "server") == 0 || cond) {
if(const char* env_p3 = std::getenv("TEST_DCIL")) {
std::cerr << "TEST_DCIL " << env_p3 << "\n";
res = atoi(env_p3);
} else
res = 8;
} else
res = 8;
} else
res = 8;
std::cerr << "dcid_size_pos size: " << res << "\n";
>>>
}
action hi_byte_pos(x:stream_pos) returns (res:byte) = {
<<< res = (x >> 8) & 0xff; >>>
}
action lo_byte_pos(x:stream_pos) returns (res:byte) = {
<<< res = x & 0xff; >>>
}
action bytes_to_cid(bytes:stream_data) returns (val:cid) = {
<<<
val.val = 0;
for (unsigned i = 0; i < bytes.size(); i++)
val.val = (val.val << 8) + bytes[i];
>>>
}
action bytes_to_version(bytes:stream_data) returns (val:version) = {
<<<
val = 0;
for (unsigned i = 0; i < bytes.size(); i++)
val = (val << 8) + bytes[i];
>>>
}
action bytes_to_itoken(bytes:stream_data) returns (val:itoken) = {
<<<
val.val = 0;
for (unsigned i = 0; i < bytes.size(); i++)
val.val = (val.val << 8) + bytes[i];
>>>
}
action export_length_cid_extension(dcil:stream_pos,scil:stream_pos) = {
<<<
std::cerr << "export_length_cid_extension" << "\n";
char str_d[20];
sprintf(str_d,"%llu",dcil);
if(setenv("TEST_DCIL",str_d,true) != 0)
fprintf(stderr, "setenv failed\n");
char str[20];
sprintf(str,"%llu",scil);
if(setenv("TEST_SCIL",str,true) != 0)
fprintf(stderr, "setenv failed\n");
char str_p[20];
sprintf(str_p,"%llu",scil);
if(setenv("TEST_PCIL",str_p,true) != 0)
fprintf(stderr, "setenv failed\n");
>>>
}
action export_length_cid(dcil:stream_pos,scil:stream_pos) = {
<<<
scid_h = scil;
dcid_h = dcil;
>>>
}
action export_length_cid_mim(dcil:stream_pos,scil:stream_pos) = {
<<<
scid_mim = scil;
dcid_mim = dcil;
>>>
}