commit efd1f6e16dacf1582945fcc0783902882fff06a2
parent 99a2ba4ad4720e7253642c78e4eaf156deb2a2d2
Author: Bor Grošelj Simić <bgs@turminal.net>
Date: Tue, 17 May 2022 21:54:28 +0200
encoding::pem: implement writer
Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>
Diffstat:
2 files changed, 70 insertions(+), 22 deletions(-)
diff --git a/encoding/pem/+test.ha b/encoding/pem/+test.ha
@@ -3,9 +3,14 @@
use bufio;
use bytes;
use io;
+use fmt;
use strings;
+use strio;
@test fn read() void = {
+ const testcert_str = fmt::asprintf(
+ "garbage\ngarbage\ngarbage\n{}garbage\n", cert_str);
+ defer free(testcert_str);
const in = bufio::fixed(strings::toutf8(testcert_str), io::mode::READ);
const dec = newdecoder(&in);
defer finish(&dec);
@@ -22,6 +27,8 @@ use strings;
};
@test fn read_many() void = {
+ const testmany = fmt::asprintf("{}{}", cert_str, privkey_str);
+ defer free(testmany);
const in = bufio::fixed(strings::toutf8(testmany), io::mode::READ);
const dec = newdecoder(&in);
defer finish(&dec);
@@ -40,11 +47,24 @@ use strings;
assert(next(&dec) is io::EOF);
};
-const testcert_str: str = `
-garbage
-garbage
-garbage
------BEGIN CERTIFICATE-----
+@test fn write() void = {
+ let out = strio::dynamic();
+ const stream = newencoder("CERTIFICATE", &out)!;
+ io::writeall(&stream, testcert_bin)!;
+ io::close(&stream)!;
+ assert(strio::string(&out) == cert_str);
+ io::close(&out)!;
+
+ let out = strio::dynamic();
+ const stream = newencoder("PRIVATE KEY", &out)!;
+ io::writeall(&stream, testprivkey_bin)!;
+ io::close(&stream)!;
+ assert(strio::string(&out) == privkey_str);
+ io::close(&out)!;
+};
+
+const cert_str: str =
+`-----BEGIN CERTIFICATE-----
MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G
A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y
aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0
@@ -58,7 +78,6 @@ DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG
SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA
l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo=
-----END CERTIFICATE-----
-garbage
`;
const testcert_bin: [_]u8 = [
@@ -111,22 +130,8 @@ const testcert_bin: [_]u8 = [
0x22, 0xdd, 0x35, 0x81, 0x46, 0x93, 0x22, 0x9a,
];
-const testmany: str = `
------BEGIN CERTIFICATE-----
-MIICLDCCAdKgAwIBAgIBADAKBggqhkjOPQQDAjB9MQswCQYDVQQGEwJCRTEPMA0G
-A1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2VydGlmaWNhdGUgYXV0aG9y
-aXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdudVRMUyBjZXJ0aWZpY2F0
-ZSBhdXRob3JpdHkwHhcNMTEwNTIzMjAzODIxWhcNMTIxMjIyMDc0MTUxWjB9MQsw
-CQYDVQQGEwJCRTEPMA0GA1UEChMGR251VExTMSUwIwYDVQQLExxHbnVUTFMgY2Vy
-dGlmaWNhdGUgYXV0aG9yaXR5MQ8wDQYDVQQIEwZMZXV2ZW4xJTAjBgNVBAMTHEdu
-dVRMUyBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkwWTATBgcqhkjOPQIBBggqhkjOPQMB
-BwNCAARS2I0jiuNn14Y2sSALCX3IybqiIJUvxUpj+oNfzngvj/Niyv2394BWnW4X
-uQ4RTEiywK87WRcWMGgJB5kX/t2no0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1Ud
-DwEB/wQFAwMHBgAwHQYDVR0OBBYEFPC0gf6YEr+1KLlkQAPLzB9mTigDMAoGCCqG
-SM49BAMCA0gAMEUCIDGuwD1KPyG+hRf88MeyMQcqOFZD0TbVleF+UsAGQ4enAiEA
-l4wOuDwKQa+upc8GftXE2C//4mKANBC6It01gUaTIpo=
------END CERTIFICATE-----
------BEGIN PRIVATE KEY-----
+const privkey_str: str =
+`-----BEGIN PRIVATE KEY-----
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgVcB/UNPxalR9zDYAjQIf
jojUDiQuGnSJrFEEzZPT/92hRANCAASc7UJtgnF/abqWM60T3XNJEzBv5ez9TdwK
H0M6xpM2q+53wmsN/eYLdgtjgBd3DBmHtPilCkiFICXyaA8z9LkJ
diff --git a/encoding/pem/pem.ha b/encoding/pem/pem.ha
@@ -4,6 +4,7 @@ use ascii;
use bufio;
use encoding::base64;
use errors;
+use fmt;
use io;
use os;
use strings;
@@ -195,3 +196,45 @@ fn b64_read(st: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
return len(sub);
};
+
+export type pemencoder = struct {
+ stream: io::stream,
+ out: *io::stream,
+ b64: base64::encoder,
+ label: str,
+};
+
+const pemencoder_vt: io::vtable = io::vtable {
+ writer = &pem_write,
+ closer = &pem_wclose,
+ ...
+};
+
+// Creates a new PEM encoder stream. The stream has to be closed to write the
+// trailer.
+export fn newencoder(label: str, s: *io::stream) (pemencoder | io::error) = {
+ fmt::fprintf(s, "{}{}{}\n", begin, label, suffix)?;
+ return pemencoder {
+ stream = &pemencoder_vt,
+ out = s,
+ b64 = base64::newencoder(&base64::std_encoding, s),
+ label = label,
+ };
+};
+
+fn pem_write(s: *io::stream, buf: const []u8) (size | io::error) = {
+ let s = s: *pemencoder;
+ let buf = buf: []u8;
+ let z = 0z;
+ for (len(buf) >= 48; buf = buf[48..]) {
+ z += io::writeall(&s.b64, buf[..48])?;
+ z += io::write(s.out, ['\n'])?;
+ };
+ return z + io::writeall(&s.b64, buf)?;
+};
+
+fn pem_wclose(s: *io::stream) (void | io::error) = {
+ let s = s: *pemencoder;
+ io::close(&s.b64)?;
+ fmt::fprintf(s.out, "\n{}{}{}\n", end, s.label, suffix)?;
+};