зеркало из https://github.com/microsoft/ivy.git
working on QUIC encryption
This commit is contained in:
Родитель
49c9b061e7
Коммит
489a50db05
|
@ -426,7 +426,14 @@ around tls_recv_event {
|
|||
# crypto_pos(pcid,0) := crypto_pos(pcid,0) + data.end
|
||||
}
|
||||
|
||||
#
|
||||
# Client initial request event
|
||||
# ============================
|
||||
#
|
||||
# This event occurs when a client transmits in initial request to open
|
||||
# a connection.
|
||||
|
||||
action client_initial_request(src:ip.endpoint,dst:ip.endpoint,pkt:quic_packet)
|
||||
|
||||
# Packet events
|
||||
# -------------
|
||||
|
@ -640,8 +647,9 @@ around packet_event(src:ip.endpoint,dst:ip.endpoint,pkt:quic_packet) {
|
|||
| (pkt.payload.value(I) isa frame.connection_close));
|
||||
# require ~conn_closed(src,scid); # [6]
|
||||
|
||||
# An initial packet with an unseen source cid is a connection request.
|
||||
if ~conn_seen(scid) {
|
||||
# An initial packet with an unseen destination cid is a connection request.
|
||||
if ~conn_seen(dcid) {
|
||||
call client_initial_request(src,dst,pkt);
|
||||
conn_requested(src,dst,scid) := true;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
#lang ivy1.7
|
||||
|
||||
# Here, we define functions for QUIC packet packet protection.
|
||||
|
||||
include tls_msg
|
||||
include byte_stream
|
||||
include quic_types
|
||||
|
||||
module quic_protection(tls) = {
|
||||
|
||||
# Protect a packet, given the TLS session and the actual (not compressed)
|
||||
# sequence number of the packet;
|
||||
|
||||
action encrypt(c:tls.cid,seq:pkt_num,pkt:stream_data) returns (pkt:stream_data)
|
||||
|
||||
# Protect a packet, given the TLS session and the actual (not
|
||||
# compressed) highest sequence number of any packet received so
|
||||
# far. The latter is used to guess the real sequence number of the
|
||||
# packet, which is needed to decrypt the payload. This means that
|
||||
# a significantly delayed packet might not be successfully
|
||||
# decrypted, since we might not guess its full sequence number
|
||||
# correctly. The return parameter `ok` is true if the packet is
|
||||
# successfully decrypted. Note, unsuccessful decryption might
|
||||
# indicate a stateless reset.
|
||||
|
||||
action decrypt(c:tls.cid,seq:pkt_num,pkt:stream_data) returns (ok:bool, pkt:stream_data)
|
||||
|
||||
implement encrypt {
|
||||
var level := get_level(pkt);
|
||||
var sample_size := tls.iv_size(level);
|
||||
var pnum_pos := get_pnum_pos(pkt);
|
||||
var pnum_len := get_pnum_len(pkt,pnum_pos);
|
||||
var hdr_len := pnum_pos + pnum_len;
|
||||
var hdr := pkt.segment(0,pnum_pos);
|
||||
var pnum := pkt.segment(pnum_pos,hdr_len);
|
||||
var pyld := pkt.segment(hdr_len,pkt.end);
|
||||
var auth := pkt.segment(0,hdr_len);
|
||||
var seq := get_pnum(pnum,0,pnum_len);
|
||||
pyld := tls.encrypt_aead(c,level,pyld,seq,auth);
|
||||
|
||||
# Computing the sample position is a bit tricky. First we
|
||||
# assume the length of the pnum is 4, which means the offset
|
||||
# of the sample withing the payload is `4 -
|
||||
# pnum_len`. However, if there are not enough bytes in the
|
||||
# payload, we change it to `payld.end - sample`. Note,
|
||||
# however, that we are using natural numbers, so if the
|
||||
# position would be negative, it saturates to zero. This is
|
||||
# consistent with the statement that you should never sample
|
||||
# any bytes from the packet number itself. This leaves the
|
||||
# possibility that there are not enough bytes to sample, that
|
||||
# is, in the sample, there will be some trailing
|
||||
# zeros. Nonetheless, the spec says that the sample size will
|
||||
# never be larger than the smallest encrypted payload, so we
|
||||
# should be OK.
|
||||
|
||||
var sample_pos := 4 - pnum_len;
|
||||
if sample_pos + sample_size > pyld.end {
|
||||
sample_pos := pyld.end - sample_size
|
||||
};
|
||||
var sample := pyld.segment(sample_pos,sample_pos+sample_size);
|
||||
var pnum := tls.encrypt_cipher(c,level,pnum,sample);
|
||||
pkt := hdr.extend(pnum).extend(pyld);
|
||||
}
|
||||
|
||||
implement decrypt {
|
||||
var level := get_level(pkt);
|
||||
var sample_size := tls.iv_size(level);
|
||||
var pnum_pos := get_pnum_pos(pkt);
|
||||
|
||||
var sample_pos := pnum_pos + 4;
|
||||
if sample_pos + sample_size > pkt.end {
|
||||
sample_pos := pkt.end - sample_size
|
||||
};
|
||||
var sample := pkt.segment(sample_pos,sample_pos+sample_size);
|
||||
var pnum := pkt.segment(pnum_pos,pnum_pos+4);
|
||||
(ok,pnum) := tls.decrypt_cipher(c,level,pnum,sample);
|
||||
|
||||
if ok {
|
||||
var pnum_len := get_pnum_len(pnum,0);
|
||||
var hdr := pkt.segment(0,pnum_pos);
|
||||
hdr := hdr.extend(pnum.segment(0,pnum_len);
|
||||
var new_seq := get_pnum(pnum,0,pnum_len);
|
||||
new_seq := correct_pnum(seq,new_seq);
|
||||
var pyld := pkt.segment(pnum_pos + pnum_len);
|
||||
(ok,pyld) := tls.decrypt_aead(c,level,pyld,new_seq,hdr);
|
||||
if ok {
|
||||
pkt := hdr.extend(pyld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# This returns the encryption level of a protected or unprotected
|
||||
# packet.
|
||||
|
||||
action get_level(pkt:stream_data) returns (level:tls.level) = {
|
||||
var hdr_type := pkt.value(0);
|
||||
if hdr_type = 0x7f {
|
||||
level := 0;
|
||||
} else if hdr_type = 0x7d {
|
||||
level := 2;
|
||||
} else {
|
||||
level := 3;
|
||||
}
|
||||
}
|
||||
|
||||
# This returns the position of the packet number in a protected or
|
||||
# unprotected packet. For long packets, we have to skip over 6
|
||||
# bytes of header, plus the two cid's, plus the retry token length
|
||||
# and bytes, plus the payload length. For short packets, we just
|
||||
# skip ver the type byte and the cid. Since we don't know the
|
||||
# length of the cid here, we assume it is 8.
|
||||
|
||||
action get_pnum_pos(pkt:stream_data) returns (pnum_pos:stream_pos) = {
|
||||
var hdr_type := pkt.value(0);
|
||||
if hdr_type = 0x7f | hdr_type = 0x7d {
|
||||
var lens := pkt.value[5];
|
||||
var dcil := bfe[4][7](lens);
|
||||
var scil := bfe[0][3](lens);
|
||||
dcil := dcil + 3 if dcil ~= 0 else 0;
|
||||
scil := scil + 3 if scil ~= 0 else 0;
|
||||
pnum_pos := 6 + dcil + scil;
|
||||
var len := get_var_int_len(pkt,pnum_pos);
|
||||
var retry_token_len := get_var_int(pkt,pnum_pos,len);
|
||||
pnum_pos := pnum_pos + len + retry_token_len;
|
||||
pnum_pos := pnum_pos + len := get_var_int_len(pkt,pnum_pos);
|
||||
}
|
||||
else {
|
||||
pnum_pos := 9;
|
||||
}
|
||||
}
|
||||
|
||||
# Get the length of a packet number at position `pos`
|
||||
|
||||
action get_pnum_len(pkt:stream_data,pnum_pos:stream_pos) returns (pnum_len:stream_pos) = {
|
||||
var byte = pkt.value(pnum_pos);
|
||||
if bvand(byte,0x80) = 0 {
|
||||
pnum_len := 1;
|
||||
} else if bvand(byte,0x40) = 0 {
|
||||
pnum_len := 2;
|
||||
} else {
|
||||
pnum_len := 4;
|
||||
}
|
||||
}
|
||||
|
||||
# Given the length of the packet number, get the number it encodes.
|
||||
|
||||
action get_pnum_len(pkt:stream_data,pnum_pos:stream_pos,pnum_len:stream_pos)
|
||||
returns (seq:pkt_num) =
|
||||
{
|
||||
var data := pkt.segment(pnum_pos,pnum_pos + pnum_len);
|
||||
var mask:byte := 0x7f if pnum_len = 1 else 0x3f;
|
||||
var data := data.set(0,bvand(mask,data.value(0)));
|
||||
seq := 0;
|
||||
var idx:stream_pos := 0;
|
||||
while idx < data.end {
|
||||
seq := 256 * seq + data.value(idx);
|
||||
idx := idx.next;
|
||||
}
|
||||
}
|
||||
|
||||
# Get the length of a variable-length ingteger in a packet.
|
||||
|
||||
action get_var_int_len(pkt:stream_data,pos:stream_pos) returns (len:stream_pos) = {
|
||||
var code := bfe[6][7](pkt.value(pos));
|
||||
if code = 0 {
|
||||
len := 1;
|
||||
} else if code = 1 {
|
||||
len := 2;
|
||||
} else if code = 2 {
|
||||
len := 4;
|
||||
} else {
|
||||
len := 8;
|
||||
}
|
||||
}
|
||||
|
||||
# Get the value of a variable-length integer at position `pos`,
|
||||
# whose length is `len`.
|
||||
|
||||
action get_var_int(pkt:stream_data,pos:stream_pos,len:stream_pos) returns (val:stream_pos) {
|
||||
var idx:stream_pos := pos;
|
||||
val := 0;
|
||||
while idx < pos + len {
|
||||
var byte := pkt.value(idx);
|
||||
if idx = pos {
|
||||
byte := bvand(byte,0x3f);
|
||||
}
|
||||
val := 256 * val + byte;
|
||||
idx := idx.next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ include quic_connection
|
|||
include quic_deser
|
||||
include quic_ser
|
||||
include quic_infer
|
||||
include tls
|
||||
include tls_msg
|
||||
include udp_impl
|
||||
include serdes
|
||||
|
||||
|
@ -163,6 +163,47 @@ before packet_event(src:ip.endpoint,dst:ip.endpoint,pkt:quic_packet) {
|
|||
|
||||
# Hook up to the remote server
|
||||
|
||||
# If this is an initial client request, we set up the initial keys
|
||||
# based on the destination cid (which in principle is a random sequence
|
||||
# of bytes. Note, the "salt" is specified in QUIC-TLS version 15, and is
|
||||
# unchanged in version 16.
|
||||
|
||||
after client_initial_request(src:ip.endpoint,dst:ip.endpoint,pkt:quic_packet) {
|
||||
var ikm := cid_to_bytes(pkt.dst_cid,pkt.dcid + 3 if pkt.dcid > 0 else 0);
|
||||
var salt : stream_data := stream_data.empty;
|
||||
salt := salt.append(0x9c);
|
||||
salt := salt.append(0x10);
|
||||
salt := salt.append(0x8f);
|
||||
salt := salt.append(0x98);
|
||||
salt := salt.append(0x52);
|
||||
salt := salt.append(0x0a);
|
||||
salt := salt.append(0x5c);
|
||||
salt := salt.append(0x5c);
|
||||
salt := salt.append(0x32);
|
||||
salt := salt.append(0x96);
|
||||
salt := salt.append(0x8e);
|
||||
salt := salt.append(0x95);
|
||||
salt := salt.append(0x0e);
|
||||
salt := salt.append(0x8a);
|
||||
salt := salt.append(0x2c);
|
||||
salt := salt.append(0x5f);
|
||||
salt := salt.append(0xe0);
|
||||
salt := salt.append(0x6d);
|
||||
salt := salt.append(0x6c);
|
||||
salt := salt.append(0x38);
|
||||
call botan.upper.set_initial_keys(0,salt,ikm);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
>>>
|
||||
}
|
||||
|
||||
|
||||
# When the client sends a packet, route it to the server on the socket
|
||||
# corresponding to the ip endpoint. TODO: coalesce packets. As of now,
|
||||
# we send only one QUIC packet per UDP datagram.
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
#lang ivy
|
||||
|
||||
include tls_picotls
|
||||
|
||||
# This module defines the interface to TLS at the message level. This
|
||||
# interface eliminates the TLS record layer, instead delegating
|
||||
# encryption to the client, as needed by the QUIC protocol. The
|
||||
# interface provides suiatable encryption and decryption methods that
|
||||
# can be used for this purpose.
|
||||
|
||||
module tls_lower_intf(cid,bytes) = {
|
||||
|
||||
# Transfers message data from connection to underlying transport
|
||||
|
||||
action send(c:cid,data:bytes)
|
||||
|
||||
# Transfers message data from the underlying transport to connection
|
||||
|
||||
action recv(c:cid,data:bytes)
|
||||
|
||||
}
|
||||
|
||||
# This module defines the interface of a TLS endpoint (either a client
|
||||
# or a server. The parameters are:
|
||||
#
|
||||
# `cid` : the type of connection identifiers
|
||||
# `bytes` : the type of byte arrays
|
||||
# `lower` : the interface to the underlying transport
|
||||
# `extens` : the type of lists of extensions
|
||||
# `exten_ser` : serializer for extensions
|
||||
|
||||
module tls_intf(cid,index,bytes,lower,extens,exten_ser,seq_num) = {
|
||||
|
||||
# The upper interface is between TLS and the application
|
||||
|
||||
# Transfers connection data to application
|
||||
|
||||
action recv(c:cid,data:bytes)
|
||||
|
||||
# Transfers application data to conection
|
||||
|
||||
action send(c:cid,data:bytes)
|
||||
|
||||
# Alert from connection to application
|
||||
|
||||
action alert(c:cid,data:bytes)
|
||||
|
||||
# Indicates to application that a session is established,
|
||||
# meaning the connection is ready to send on.
|
||||
|
||||
action session_established(c:cid)
|
||||
|
||||
# Generates key material based on master secret, per RFC 5705.
|
||||
|
||||
action key_material_export(c:cid,label:bytes,context:bytes,length:index)
|
||||
returns (key:bytes)
|
||||
|
||||
# Create a new connection with a fresh cid, and list of extensions
|
||||
|
||||
action create(c:cid, is_server : bool, e : extens)
|
||||
|
||||
# Destroy an existing connection
|
||||
|
||||
action destroy(c:cid)
|
||||
|
||||
# Set the initial keys for a session. There are determined by the
|
||||
# salt and the initial key material `ikm`. In QUIC, the salt is
|
||||
# fixed by the protocol version, whereas `ikm` is the client's
|
||||
# initial destination connection id.
|
||||
|
||||
action set_initial_keys(c:cid,salt:bytes,ikm:bytes)
|
||||
|
||||
# Get the size of the cipher initial value for a given level.
|
||||
|
||||
action iv_size(c:cid,l:level) returns (sz:index)
|
||||
|
||||
# Encrypt data with cipher for given level and initial value.
|
||||
|
||||
action encrypt_cipher(c:dic,l:level,clear:bytes,iv:bytes) returns (cipher:bytes)
|
||||
|
||||
# Decrypt data with cipher for given level and initial value. Return parameter
|
||||
# `ok` indicates decryption was successful.
|
||||
|
||||
action decrypt_cipher(c:dic,l:level,cipher:bytes,iv:bytes) returns (ok:bool,clear:bytes)
|
||||
|
||||
# Encrypt data with AEAD for given level, additional data `ad` and
|
||||
# sequence number `seq`.
|
||||
|
||||
action encrypt_aead(c:dic,l:level,clear:bytes,seq:seq_num,ad:bytes) returns (cipher:bytes)
|
||||
|
||||
# Decrypt data with cipher for given level, additional data `ad`
|
||||
# and sequence number `seq`. Return parameter `ok` indicates
|
||||
# decryption was successful.
|
||||
|
||||
action decrypt_cipher(c:dic,l:level,cipher:bytes,seq:seq_num,ad:bytes)
|
||||
returns (ok:bool,clear:bytes)
|
||||
|
||||
specification {
|
||||
|
||||
relation open(C:cid)
|
||||
relation established(C:cid)
|
||||
|
||||
after init {
|
||||
open(C) := false;
|
||||
established(C) := false;
|
||||
}
|
||||
|
||||
around create {
|
||||
require ~open(c);
|
||||
...
|
||||
open(c) := true;
|
||||
}
|
||||
|
||||
around destroy {
|
||||
require open(c);
|
||||
...
|
||||
open(c) := false;
|
||||
established(c) := false;
|
||||
}
|
||||
|
||||
before recv {
|
||||
require open(c);
|
||||
}
|
||||
|
||||
before send {
|
||||
require open(c) & established(c);
|
||||
}
|
||||
|
||||
before session_established {
|
||||
require open(c) & ~established(c);
|
||||
established(c) := true
|
||||
}
|
||||
|
||||
before key_material_export {
|
||||
require open(c) & established(c);
|
||||
}
|
||||
|
||||
invariant established(C) -> open(C)
|
||||
}
|
||||
|
||||
implementation {
|
||||
instance impl : tls_gnutls(cid,index,bytes,extens,exten_ser,lower,this)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -94,9 +94,11 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
std::vector<char> input;
|
||||
int handshake_status;
|
||||
std::vector<quic_crypto_context_t> crypto_context;
|
||||
bool is_server;
|
||||
|
||||
picotls_connection(`cid` id, ptls_t *gs, tls_callbacks cb,
|
||||
ptls_handshake_properties_t *hsp)
|
||||
: id(id),gs(gs),cb(cb),hsp(hsp) {
|
||||
ptls_handshake_properties_t *hsp, bool is_server)
|
||||
: id(id),gs(gs),cb(cb),hsp(hsp),is_server(is_server) {
|
||||
handshake_status = 0;
|
||||
crypto_context.resize(4);
|
||||
}
|
||||
|
@ -114,8 +116,14 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
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_QUIC_BASE "quic "
|
||||
#define QUIC_LABEL_PN "pn"
|
||||
#define QUIC_LABEL_INITIAL_CLIENT "client in"
|
||||
#define QUIC_LABEL_INITIAL_SERVER "server in"
|
||||
|
||||
// The following mess is to get the traffic keys from picotls
|
||||
|
||||
|
@ -157,6 +165,54 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// This additional mess sets the initial traffic keys
|
||||
|
||||
|
||||
void bail(int ret, const char *msg) {
|
||||
if (ret) {
|
||||
std::cerr << msg;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
int setup_initial_traffic_keys(picotls_connection *session,
|
||||
const `bytes` &salt_vec,
|
||||
const `bytes` &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;
|
||||
|
||||
vec_to_ptls_iovec(salt,salt_vec);
|
||||
vec_to_ptls_iovec(ikm,ikm_vec);
|
||||
ret = ptls_hkdf_extract(cipher.hash, master_secret, salt, ikm);
|
||||
bail(ret,"tls: failed to set up initial master secret\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),
|
||||
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),
|
||||
QUIC_LABEL_QUIC_BASE);
|
||||
bail(ret,"tls: failed to set up initial server secret\n");
|
||||
quic_set_key_from_secret(&cipher, session->is_server, &session->crypto_context[0], server_secret);
|
||||
quic_set_key_from_secret(&cipher, !session->is_server, &session->crypto_context[0], client_secret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Some parameters for picotls as used by picoquic.
|
||||
|
@ -192,87 +248,6 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
|
||||
// Handle callback from gnutls to send data
|
||||
|
||||
ssize_t gnutls_session_push_func(gnutls_transport_ptr_t ptr, const void* data, size_t len) {
|
||||
gnutls_connection *s = (gnutls_connection *) ptr;
|
||||
`cid` c = s->id;
|
||||
unsigned char *d = (unsigned char *)data;
|
||||
`bytes` bytes;
|
||||
bytes.resize(len);
|
||||
std::copy(d,d+len,bytes.begin());
|
||||
s->cb.ls(c,bytes);
|
||||
return len;
|
||||
}
|
||||
|
||||
// Handle callback from gnutls to recv data
|
||||
|
||||
ssize_t gnutls_session_pull_func(gnutls_transport_ptr_t ptr, void* data, size_t len){
|
||||
gnutls_connection *s = (gnutls_connection *) ptr;
|
||||
`cid` c = s->id;
|
||||
std::vector<char> &input = s->input;
|
||||
size_t res = input.size();
|
||||
if (len < res)
|
||||
res = len;
|
||||
if (res == 0) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
char *d = (char *)data;
|
||||
for (size_t i = 0; i < res; i++) {
|
||||
d[i] = input[i];
|
||||
}
|
||||
input.erase(input.begin(),input.begin()+res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Start or resume handshake
|
||||
|
||||
void gnutls_do_handshake(gnutls_connection *s) {
|
||||
// HACK HACK HACK HACK
|
||||
// set the read and write epochs to zero to hopefully disable encryption of records
|
||||
// s->gs->security_parameters.epoch_read = 0;
|
||||
// s->gs->security_parameters.epoch_write = 0;
|
||||
s->handshake_status = gnutls_handshake(s->gs);
|
||||
if (s->handshake_status != GNUTLS_E_SUCCESS &&
|
||||
s->handshake_status != GNUTLS_E_AGAIN) {
|
||||
std::cerr << "gnutls_handshake returned error\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// This is horrible, but it can't be helped, because the gnutls
|
||||
// callbacks for external extensions don't have parameters.
|
||||
|
||||
hash_space::hash_map<gnutls_session_t,std::vector<std::vector<unsigned char> > > gnutls_ext_data_map;
|
||||
|
||||
// Send extension data
|
||||
|
||||
int gnutls_ext_supp_recv_params(gnutls_session_t session, const unsigned char *data, size_t _data_size) {
|
||||
const unsigned char *d = (const unsigned char *) data;
|
||||
std::vector<unsigned char> v;
|
||||
v.resize(_data_size);
|
||||
std::copy(d,d+_data_size,v.begin());
|
||||
gnutls_ext_data_map[session].push_back(v);
|
||||
return _data_size;
|
||||
}
|
||||
|
||||
// Receive extension data
|
||||
|
||||
int gnutls_ext_supp_send_params(gnutls_session_t session, gnutls_buffer_t buf) {
|
||||
std::vector<std::vector<unsigned char> > &datas = gnutls_ext_data_map[session];
|
||||
std::vector<unsigned char> v = datas.front();
|
||||
int len = v.size();
|
||||
if (gnutls_buffer_append_data(buf, &v[0], len) < 0) {
|
||||
std::cerr << "gnutls_buffer_append_data returned error\n";
|
||||
exit(1);
|
||||
}
|
||||
datas.erase(datas.begin());
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
>>>
|
||||
|
||||
# Here we put any new members of the ivy C++ class. If we have allocated a per-instance
|
||||
|
@ -366,7 +341,7 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
|
||||
ptls_t *session;
|
||||
session = ptls_new(ctx,is_server ? 1 : 0);
|
||||
picotls_connection *s = new picotls_connection(c,session,*`cb`,handshake_properties);
|
||||
picotls_connection *s = new picotls_connection(c,session,*`cb`,handshake_properties,is_server);
|
||||
*ptls_get_data_ptr(session) = s;
|
||||
|
||||
`cid_map`[c] = s;
|
||||
|
@ -390,6 +365,47 @@ module tls_gnutls(cid,index,bytes,extens,exten_ser,lower,upper) = {
|
|||
|
||||
}
|
||||
|
||||
# Set the initial key material.
|
||||
|
||||
implement set_initial_keys(c:cid,salt:bytes,ikm:bytes) {
|
||||
<<< impure
|
||||
|
||||
picotls_connection *s = `cid_map`[c];
|
||||
setup_initial_traffic_keys(s,salt,ikm);
|
||||
|
||||
>>>
|
||||
}
|
||||
|
||||
# Get the cipher initial value size
|
||||
|
||||
implement iv_size(c:cid,l:level) returns (sz:index) {
|
||||
<<< impure
|
||||
|
||||
picotls_connection *s = `cid_map`[c];
|
||||
ptls_cipher_context_t *pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_enc);
|
||||
sz = pn_enc->algo->iv_size
|
||||
|
||||
>>>
|
||||
}
|
||||
|
||||
implement encrypt_cipher(c:dic,l:level,clear:bytes,iv:bytes) returns (cipher:bytes) {
|
||||
<<< impure
|
||||
|
||||
picotls_connection *s = `cid_map`[c];
|
||||
ptls_cipher_context_t *pn_enc = (ptls_cipher_context_t *)(s->crypto_context[l].pn_enc);
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(iv.size());
|
||||
std::copy(iv.begin(),iv.end(),bytes.end());
|
||||
ptls_cipher_init(pn_enc, &bytes[0]);
|
||||
std::vector<uint8_t> input, output;
|
||||
input.resize(clear.size());
|
||||
std::
|
||||
output.resize(clear.size() + aead_checksum_size);
|
||||
ptls_cipher_encrypt(pn_enc, &output[0], &input, len);
|
||||
|
||||
>>>
|
||||
}
|
||||
|
||||
# upper.send is called with application data to be transmitted to the peer.
|
||||
|
||||
implement upper.send(c:cid,data:bytes) {
|
||||
|
|
|
@ -1592,7 +1592,8 @@ def create_constructor_schemata(mod):
|
|||
for sortname,destrs in mod.sort_destructors.iteritems():
|
||||
if any(len(f.sort.dom) > 1 for f in destrs):
|
||||
continue # TODO: higher-order constructors!
|
||||
sort = destrs[0].sort.dom[0]
|
||||
sort = ivy_logic.find_sort(sortname)
|
||||
#sort = destrs[0].sort.dom[0]
|
||||
Y = ivy_logic.Variable('Y',sort)
|
||||
eqs = [ivy_logic.Equals(f(Y),ivy_logic.Variable('X'+str(n),f.sort.rng)) for n,f in enumerate(destrs)]
|
||||
fmla = ivy_logic.Exists([Y],ivy_logic.And(*eqs))
|
||||
|
|
Загрузка…
Ссылка в новой задаче