~apreiml/hare-tls

hare-tls: Adapt to stdlib memio/strio/bufio rewrite v1 APPLIED

Conrad Hoffmann: 1
 Adapt to stdlib memio/strio/bufio rewrite

 14 files changed, 50 insertions(+), 47 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~apreiml/hare-tls/patches/43428/mbox | git am -3
Learn more about email & git

[PATCH hare-tls] Adapt to stdlib memio/strio/bufio rewrite Export this patch

See https://git.sr.ht/~sircmpwn/hare/commit/ed762a2 for context.
---
I wanted to play with hare-tls a bit and this was the first thing I ran
into. I tried to faithfully convert everything. I still have two broken
tests, but I am pretty sure they are unrelated:

Failures:
crypto::tls::connectself: /home/conrad/hack/hare/hare-tls/crypto/tls/clienthandshake.ha:444:35: slice or array access out of bounds
integr::nginx::nginx: /home/conrad/hack/hare/hare-tls/integr/nginx/test.ha:65:38: error occurred

All other tests pass. I hope this may spare you the tedious task, even
if you need to make a modification or two. I'll investigate the failing
tests further, but it might take some time.

 crypto/tls/+test/message.ha   |  6 +++---
 crypto/tls/cert.ha            |  6 +++---
 crypto/tls/clienthandshake.ha | 10 +++++-----
 crypto/tls/serverhandshake.ha |  6 +++---
 crypto/x509/cert.ha           | 12 ++++++------
 crypto/x509/key.ha            |  6 +++---
 crypto/x509/store.ha          |  6 +++---
 encoding/asn1/der+test.ha     | 13 ++++++++-----
 encoding/asn1/dump.ha         |  4 ++--
 encoding/asn1/oid.ha          |  6 +++---
 encoding/asn1/types.ha        |  6 +++---
 format/pkcs/+test.ha          |  4 ++--
 format/pkcs/rsa.ha            |  6 +++---
 integr/nginx/test.ha          |  6 +++---
 14 files changed, 50 insertions(+), 47 deletions(-)

diff --git a/crypto/tls/+test/message.ha b/crypto/tls/+test/message.ha
index f74a803..8755bdd 100644
--- a/crypto/tls/+test/message.ha
+++ b/crypto/tls/+test/message.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use bytes;
use crypto::tls::cs;
use encoding::hex;
@@ -144,10 +144,10 @@ use fmt;
	let w = newmsgreader(&bufs, buf)!;
	let lw = io::limitreader(&w, n);

	let res = bufio::dynamic(io::mode::WRITE);
	let res = memio::dynamic();
	io::copy(&res, &lw)!;

	let result = bufio::buffer(&res);
	let result = memio::buffer(&res);
	for (let i = 0z; i < n; i += 1) {
		assert(result[i] == i: u8);
	};
diff --git a/crypto/tls/cert.ha b/crypto/tls/cert.ha
index c2cd0cf..146167c 100644
--- a/crypto/tls/cert.ha
+++ b/crypto/tls/cert.ha
@@ -1,7 +1,7 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bytes;
use bufio;
use memio;
use crypto::ed25519;
use encoding::pem;
use errors;
@@ -27,9 +27,9 @@ export fn loadcerts(src: io::handle) ([]cert | io::error) = {
		return errors::invalid;
	};

	let cbuf = bufio::dynamic(io::mode::WRITE);
	let cbuf = memio::dynamic();
	io::copy(&cbuf, &csec.1)!;
	return alloc([bufio::buffer(&cbuf): cert]);
	return alloc([memio::buffer(&cbuf): cert]);
};

// Frees certs allocated by [[loadcerts]].
diff --git a/crypto/tls/clienthandshake.ha b/crypto/tls/clienthandshake.ha
index b3e6e7f..e139e78 100644
--- a/crypto/tls/clienthandshake.ha
+++ b/crypto/tls/clienthandshake.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use crypto::random;
use crypto::aes;
use crypto::cipher;
@@ -209,7 +209,7 @@ fn client_inithandshakehash(c: *client, sum: []u8) void = {
	// hash sum of all handshake messages, which is used for key derivation.

	let h = &c.thash;
	// let h = bufio::dynamic(io::mode::WRITE);
	// let h = memio::dynamic();

	// TODO fix the hacks
	const start = c.stream.sbufs.start;
@@ -242,7 +242,7 @@ fn client_inithandshakehash(c: *client, sum: []u8) void = {
	hash::sum(h, sum);
	log::lprintln(c.log, "first transcript hash:", hex::encodestr(sum));
	// fmt::println("hahsshshs")!;
	// hex::dump(os::stderr, bufio::buffer(h))!;
	// hex::dump(os::stderr, memio::buffer(h))!;
};

fn ext_readkeyshare(c: *client, m: *msgstream) (void | error) = {
@@ -334,7 +334,7 @@ fn hkdfexpandlabel(dest: []u8, key: []u8, label: []u8, context: []u8) void = {
	// RFC 8446 7.1
	// TODO static
	let hkdflabel: []u8 = alloc([0...], 2 + 6 + 1 + len(label) + 1 + len(context));
	let w = bufio::dynamic(io::mode::WRITE);
	let w = memio::dynamic();

	writeu16(&w, len(dest): u16)!;
	writeu8(&w, len(label): u8 + 6)!;
@@ -347,7 +347,7 @@ fn hkdfexpandlabel(dest: []u8, key: []u8, label: []u8, context: []u8) void = {
	let h = sha512::sha384();
	let buf: []u8 = alloc([0...], hash::sz(&h) + hash::bsz(&h));

	hkdf::expand(&h, dest, key, bufio::buffer(&w), buf);
	hkdf::expand(&h, dest, key, memio::buffer(&w), buf);
};

fn client_parseencext(c: *client, ms: *msgstream) (void | error) = {
diff --git a/crypto/tls/serverhandshake.ha b/crypto/tls/serverhandshake.ha
index c132c95..0ff5aaf 100644
--- a/crypto/tls/serverhandshake.ha
+++ b/crypto/tls/serverhandshake.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use encoding::hex;
use fmt;
use io;
@@ -329,7 +329,7 @@ fn srv_sendcertverify(s: *server) (void | error) = {
	let hh: []u8 = alloc([0...], sha512::SIZE384);
	hash::sum(&s.thash, hh);

	let sigmsg = bufio::dynamic(io::mode::WRITE);
	let sigmsg = memio::dynamic();
	defer io::close(&sigmsg)!;
	let prefix: [64]u8 = [0x20...];
	io::writeall(&sigmsg, prefix)!;
@@ -346,7 +346,7 @@ fn srv_sendcertverify(s: *server) (void | error) = {
	let cfg = s.cfg as *config;
	let pk = cfg.privkey as *privkey;
	edkey[..] = pk.key[..ed25519::PRIVKEYSZ];
	let sig = ed25519::sign(&edkey, bufio::buffer(&sigmsg));
	let sig = ed25519::sign(&edkey, memio::buffer(&sigmsg));
	write(&m, sig)?;

	// TODO
diff --git a/crypto/x509/cert.ha b/crypto/x509/cert.ha
index c060368..3343165 100644
--- a/crypto/x509/cert.ha
+++ b/crypto/x509/cert.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use bytes;
use crypto::ed25519;
use crypto::sha256;
@@ -95,7 +95,7 @@ export fn cert_fromder(b: []u8) (cert | error) = {
		...
	};

	let mem = bufio::fixed(b, io::mode::READ);
	let mem = memio::fixed(b);
	let d = asn1::derdecoder(&mem);

	const h = asn1::peek(&d)?;
@@ -343,7 +343,7 @@ fn parseext(c: *cert, d: *asn1::decoder) (void | error) = {
fn cert_parseext(c: *cert, d: *asn1::decoder, oid: []u8) (bool | error) = {
	if (bytes::equal(oidbasicc, oid)) {
		let sr = asn1::octstrreader(d)?;
		let tmp = bufio::dynamic(io::mode::WRITE);
		let tmp = memio::dynamic();
		let ed = asn1::derdecoder(&sr);

		asn1::openseq(&ed)?;
@@ -480,7 +480,7 @@ fn cert_parsesig(c: *cert, d: *asn1::decoder) (void | error) = {

fn cert_rawval(c: *cert, pos: size) []u8 = {
	let buf = c.raw[pos..];
	let r = bufio::fixed(buf, io::mode::READ);
	let r = memio::fixed(buf);
	let d = asn1::derdecoder(&r);
	const h = asn1::peek(&d) as asn1::head;
	return buf[h.data..h.end];
@@ -495,7 +495,7 @@ export fn cert_checksigfrom(c: *cert, p: *cert) (void | error) = {
	// TODO certpos?
	const pos = 4z;
	let buf = c.raw[pos..];
	let r = bufio::fixed(buf, io::mode::READ);
	let r = memio::fixed(buf);
	let d = asn1::derdecoder(&r);
	const h = asn1::peek(&d) as asn1::head;
	let cert = buf[..h.end];
@@ -540,7 +540,7 @@ export fn dump(out: io::handle, data: []u8) (void | error) = {
fn dumpname(out: io::handle, name: []u8) (void | error) = {
	// TODO iterator?

	let buf = bufio::fixed(name, io::mode::READ);
	let buf = memio::fixed(name);
	let dec = asn1::derdecoder(&buf);
	let d = &dec;

diff --git a/crypto/x509/key.ha b/crypto/x509/key.ha
index c10542c..fd207a7 100644
--- a/crypto/x509/key.ha
+++ b/crypto/x509/key.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use crypto::ec;
use crypto::ed25519;
use crypto::rsa;
@@ -179,7 +179,7 @@ fn rsa_verify(
};

fn rsa_parsepub(pubkey: []u8, src: []u8) (void | error) = {
	let mem = bufio::fixed(src, io::mode::READ);
	let mem = memio::fixed(src);
	let d = asn1::derdecoder(&mem);
	asn1::openseq(&d)?;

@@ -266,7 +266,7 @@ fn ec_verify(
	let r: [128]u8 = [0...];
	let s: [128]u8 = [0...];

	let mem = bufio::fixed(sig, io::mode::READ);
	let mem = memio::fixed(sig);
	let d = asn1::derdecoder(&mem);
	// TODO error
	asn1::openseq(&d)!;
diff --git a/crypto/x509/store.ha b/crypto/x509/store.ha
index 3902d37..22272b8 100644
--- a/crypto/x509/store.ha
+++ b/crypto/x509/store.ha
@@ -6,7 +6,7 @@ use os;
use fs;
use io;
use encoding::pem;
use bufio;
use memio;

// TODO use a proper data structure for certs with better lookup and
// de-duplication
@@ -102,13 +102,13 @@ fn store_addfromhandle(s: *store, f: io::handle) (void | fs::error | error) = {
			yield e.1;
		};

		let buf = bufio::dynamic(io::mode::WRITE);
		let buf = memio::dynamic();

		match (io::copy(&buf, &dec)) {
		case size => yield;
		case let e: io::error => return e: fs::error;
		};
		let raw = bufio::buffer(&buf);
		let raw = memio::buffer(&buf);
		append(s, cert_fromder(raw)?);
	};
};
diff --git a/encoding/asn1/der+test.ha b/encoding/asn1/der+test.ha
index 7786ab2..d374575 100644
--- a/encoding/asn1/der+test.ha
+++ b/encoding/asn1/der+test.ha
@@ -2,31 +2,34 @@
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use io;
use memio;
use os;
use types;

// XXX: would be nice to just declare this as mem: bufio::memstream.
let mem: nullable *bufio::memstream = null;
let mem: nullable *bufio::stream = null;
let rbuf: [os::BUFSIZ]u8 = [0...];

fn d(i: []u8) decoder = {
	let buf = bufio::fixed(i, io::mode::READ);
	let buf = bufio::init(&memio::fixed(i), rbuf, []);
	match (mem) {
	case null =>
		mem = alloc(buf);
	case let m: *bufio::memstream =>
	case let m: *bufio::stream =>
		*m = buf;
	};
	return derdecoder(mem);
};

@init fn newdec() void = {
	mem = alloc(bufio::fixed([], io::mode::READ));
	mem = alloc(bufio::init(&memio::fixed([]), rbuf, []));
};

@fini fn freetdec() void = {
	match (mem) {
	case null =>
		yield;
	case let m: *bufio::memstream =>
	case let m: *bufio::stream =>
		free(m);
		mem = null;
	};
diff --git a/encoding/asn1/dump.ha b/encoding/asn1/dump.ha
index 4ee01d8..af75a45 100644
--- a/encoding/asn1/dump.ha
+++ b/encoding/asn1/dump.ha
@@ -1,6 +1,6 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use encoding::hex;
use errors;
use fmt;
@@ -9,7 +9,7 @@ use os;

// Dumps der encoded 'data' to 'out'.
export fn dump(out: io::handle, data: []u8) (void | error) = {
	let s = bufio::fixed(data, io::mode::READ);
	let s = memio::fixed(data);
	let p = derdecoder(&s);
	match (dumpvar(out, &p, 0)?) {
	case void =>
diff --git a/encoding/asn1/oid.ha b/encoding/asn1/oid.ha
index a7ce30c..dee31ff 100644
--- a/encoding/asn1/oid.ha
+++ b/encoding/asn1/oid.ha
@@ -5,7 +5,7 @@ use errors;
use fmt;
use io;
use math::{divu};
use strio;
use memio;
use strings;

// estimate
@@ -88,7 +88,7 @@ export fn oid_fromder(der: []u8, oid: []u32) (size | errors::invalid | errors::o

// Caller must free returned value.
export fn oidstr(der: []u8) (str | errors::invalid | errors::overflow) = {
	let s = strio::dynamic();
	let s = memio::dynamic();
	defer io::close(&s)!;

	let oid: [OIDMAXLEN]u32 = [0...];
@@ -101,7 +101,7 @@ export fn oidstr(der: []u8) (str | errors::invalid | errors::overflow) = {
		};
	};

	return strings::dup(strio::string(&s));
	return strings::dup(memio::string(&s)!);
};

export fn stroid(der: []u8) str = {
diff --git a/encoding/asn1/types.ha b/encoding/asn1/types.ha
index c76bcca..4174e12 100644
--- a/encoding/asn1/types.ha
+++ b/encoding/asn1/types.ha
@@ -2,7 +2,7 @@
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use fmt;
use io;
use strio;
use memio;

// Invalid encoding.
export type invalid = !void;
@@ -85,14 +85,14 @@ let tagstrbuf: [64]u8 = [0...];
// String representation of universal tag ids.
export fn strtag(dh: head) str = {
	if (dh.class != class::UNIVERSAL) {
		let tagstr = strio::fixed(tagstrbuf);
		let tagstr = memio::fixed(tagstrbuf);

		fmt::fprint(&tagstr, "[")!;
		if (dh.class != class::CONTEXT_SPECIFIC) {
			fmt::fprintf(&tagstr, "{} ", strclass(dh.class))!;
		};
		fmt::fprintf(&tagstr, "{:x}]", dh.tagid)!;
		return strio::string(&tagstr);
		return memio::string(&tagstr)!;
	};

	if (dh.tagid >> 8 != 0) {
diff --git a/format/pkcs/+test.ha b/format/pkcs/+test.ha
index e61d681..22d8d28 100644
--- a/format/pkcs/+test.ha
+++ b/format/pkcs/+test.ha
@@ -1,12 +1,12 @@
// License: MPL-2.0
// (c) 2023 Armin Preiml <apreiml@strohwolke.at>
use bufio;
use memio;
use fmt;
use io;
use strings;

@test fn rsapem() void = {
	let pksrc = bufio::fixed(strings::toutf8(privkeystr), io::mode::READ);
	let pksrc = memio::fixed(strings::toutf8(privkeystr));
	let buf: [1024]u8 = [0...];
	// let pk = match (parsepriv(&pksrc, buf)) {
	// case let e: error =>
diff --git a/format/pkcs/rsa.ha b/format/pkcs/rsa.ha
index 1d08333..ebaebfe 100644
--- a/format/pkcs/rsa.ha
+++ b/format/pkcs/rsa.ha
@@ -9,7 +9,7 @@ use errors;
use fmt;
use io;
use os;
use bufio;
use memio;

export type error = !(...asn1::error | errors::overflow | errors::invalid | io::error);

@@ -45,7 +45,7 @@ export type pkcs1_rsapub = struct {
};

fn pkcs1_parsersapriv(src: io::handle, buf: []u8) (pkcs1_rsapriv | error) = {
	let kbuf = bufio::dynamic(io::mode::WRITE);
	let kbuf = memio::dynamic();
	let dec = asn1::derdecoder(src);

	asn1::openseq(&dec)?;
@@ -101,7 +101,7 @@ fn writeint(d: *asn1::decoder, buf: []u8) (([]u8, []u8) | error) = {
export type ed25519privkey = []u8;

fn parseed25519(src: io::handle, buf: []u8) (ed25519privkey | error) = {
	let kbuf = bufio::dynamic(io::mode::WRITE);
	let kbuf = memio::dynamic();
	let dec = asn1::derdecoder(src);

	let seed: ed25519::seed = [0...];
diff --git a/integr/nginx/test.ha b/integr/nginx/test.ha
index 5b77d75..6cf6100 100644
--- a/integr/nginx/test.ha
+++ b/integr/nginx/test.ha
@@ -4,7 +4,7 @@ use time;
use os::exec;
use fmt;
use os;
use strio;
use memio;
use io;
use net;
use net::dial;
@@ -20,13 +20,13 @@ use unix::signal;
const GET = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";

@test fn nginx() void = {
	let wd = strio::dynamic();
	let wd = memio::dynamic();
	defer io::close(&wd)!;
	fmt::fprint(&wd, "-p")!;
	fmt::fprint(&wd, os::getcwd())!;
	fmt::fprint(&wd, "/integr/nginx")!;

	let cmd = exec::cmd("nginx", strio::string(&wd), "-cnginx.conf")!;
	let cmd = exec::cmd("nginx", memio::string(&wd)!, "-cnginx.conf")!;
	exec::nullstd(&cmd);
	let p = exec::start(&cmd)!;

-- 
2.41.0
Very Nice! Thanks!

The tests are failing because I've started to add certificate validation and
the certificates are missing or expired. I didn't bother to update the test
certificates yet. Also hostname checking does not work yet and some critical
extensions are still ignored.