M format/openpgp/errors.ha => format/openpgp/errors.ha +17 -4
@@ 1,4 1,5 @@
use io;
+use fmt;
export type unsupported = !str;
@@ 7,12 8,19 @@ export type invalid = !void;
export type unexpected = !void;
export type weakhash = !void;
-export type error = !(io::error | unsupported | badsig | invalid | unexpected | weakhash);
+export type critsigsub = !u8;
+export type error = !(io::error | unsupported | badsig | invalid | unexpected |
+ weakhash | critsigsub);
+
+// Returns the string representation of error 'e'. The string can depend on a
+// statically allocated buffer.
export fn strerror(e: error) str = {
+ static let errbuf: [256]u8 = [0...];
+
match (e) {
- case unsupported =>
- return "Unsupported";
+ case let e: unsupported =>
+ return e;
case badsig =>
return "Signature verification failed";
case invalid =>
@@ 20,7 28,11 @@ export fn strerror(e: error) str = {
case unexpected =>
return "Unexpected data";
case weakhash =>
- return "Signature on key or data is done using a weak hash function and can not be trusted.";
+ return "Signature on key or data is done using a weak hash "
+ "function and can not be trusted.";
+ case let e: critsigsub =>
+ return fmt::bsprint(errbuf, "Unsupported critical signature "
+ "subtype:", strsigsubtype(e));
case let e: io::error =>
return io::strerror(e);
};
@@ 29,5 41,6 @@ export fn strerror(e: error) str = {
let unsupported_version: unsupported = "Unsupported file version";
let unsupported_encalgo: unsupported = "Unsupported encryption algorithm";
let unsupported_hashalgo: unsupported = "Unsupported hash algorithm";
+let unsupported_key: unsupported = "Unsupported public key crypto algorithm";
let unsupported_fp: unsupported = "Unsupported fingerprint method";
let unsupported_critsub: unsupported = "Unsupported critical signature sub-packet";
M format/openpgp/reader.ha => format/openpgp/reader.ha +65 -22
@@ 118,14 118,18 @@ fn trynext(d: *reader) (packet | error | io::EOF) = {
if (io::readall(d.h, buf[..1])? is io::EOF) {
return io::EOF;
};
+ print("HEAD");
+ hexdump(buf);
let hsz = 1z;
let t = buf[0];
if (t & 0x80 != 0x80) {
+ print("inv1");
return invalid;
};
const old = t & 0x40 == 0;
+ print("ha", old);
let p = packet {
stream = &packet_vtable,
h = d.h,
@@ 136,11 140,14 @@ fn trynext(d: *reader) (packet | error | io::EOF) = {
parsesz(d.h, &p, t)?;
+ print("TAG", p.tag: u8);
+ print("SZ", p.sz);
return p;
};
-fn parsesz(src: io::handle, p: *packet, t: u8) (void | io::error) = {
+fn parsesz(src: io::handle, p: *packet, t: u8) (void | error) = {
const old = t & 0x40 == 0;
+ print("old", old);
p.szt = sizetype::FIXED;
p.sz = 0z;
@@ 159,13 166,15 @@ fn parsesz(src: io::handle, p: *packet, t: u8) (void | io::error) = {
};
if (io::readall(src, buf[..max])? is io::EOF) {
- return errors::invalid;
+ print("wtf");
+ return invalid;
};
p.hsz += max;
for (let i = 0z; i < max; i += 1) {
p.sz <<= 8;
p.sz += buf[i];
};
+ print("size", p.sz);
return;
};
@@ 255,14 264,16 @@ fn pkt_parse_pubkey(p: *packet, mh: *multihash) (*keypair | error) = {
};
if (buf[0] != 4) {
- return errors::unsupported;
+ print("unsup1");
+ return unsupported_key: unsupported;
};
let i = time::from_unix(endian::begetu32(buf[1..5]): i64);
let d = date::from_instant(chrono::UTC, i);
if (buf[5] != 1) { // RSA sign or encrypt
- return errors::unsupported;
+ print("unsup2");
+ return unsupported_key: unsupported;
};
let key = alloc(newrsakey(d)): *keypair;
@@ 340,8 351,30 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
return unexpected;
};
+ let primary = match (pkt_parse_key(&p, &mh, priv)) {
+ case let k: *keypair =>
+ yield k;
+ case let e: unsupported =>
+ print("unsupported");
+ for (true) {
+ print("skip");
+ pkt_skip(&p)?;
+ if (hasnext(g)?) {
+ print("peek", peek(g): u8);
+ };
+ if (!hasnext(g)? || peek(g) == tag::SECRET_KEY
+ || peek(g) == tag::PUBLIC_KEY) {
+ return e;
+ };
+ p = next(g)?;
+ };
+ case let e: error =>
+ // TODO fail iterator?
+ return e;
+ };
+
let k = key {
- primary = pkt_parse_key(&p, &mh, priv)?,
+ primary = primary,
sub = [],
userids = [],
...
@@ 360,17 393,24 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
return invalid;
};
- print("parse user ids");
- for (hasnext(g)? && peek(g) == tag::USER_ID) {
- print(" user id");
+ print("# parse user ids and attributes");
+ for (hasnext(g)? && (peek(g) == tag::USER_ID || peek(g) == tag::USER_ATTRIBUTE)) {
+
let mh = multihash_clone(&mh);
p = next(g)?;
- let id = pkt_parseuserid(&p, &mh)?;
- append(k.userids, userid { id = id });
+
+ if (p.tag == tag::USER_ID) {
+ print("USER_ID");
+ let id = pkt_parseuserid(&p, &mh)?;
+ append(k.userids, userid { id = id });
+ } else {
+ print("USER_ATTRIBUTE (skip)");
+ io::copy(&mh, &p)?;
+ };
for (hasnext(g)? && peek(g) == tag::SIGNATURE) {
let mh = multihash_clone(&mh);
- print(" sig");
+ print(" parse sig");
p = next(g)?;
let sig = pkg_parsesig(&p)?;
defer sig_free(&sig);
@@ 415,15 455,6 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
// contain an issuer subpacket for each key, as a way of explicitly
// tying those keys to the signature.
- print("parse user attributes");
- for (hasnext(g)? && peek(g) == tag::USER_ATTRIBUTE) {
- print(" has attr");
- p = next(g)?;
-
- if (hasnext(g)? && peek(g) == tag::SIGNATURE) {
- p = next(g)?;
- };
- };
// TODO
@@ 438,7 469,7 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
// used only for certifying subkeys that are used for encryption and
// signatures.
- print("parse sub keys");
+ print("# parse sub keys");
const subkeytag = if (priv) tag::SECRET_SUBKEY else tag::PUBLIC_SUBKEY;
for (hasnext(g)? && peek(g) == subkeytag) {
print(" - subkey");
@@ 458,7 489,7 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
};
verify(&sig, &mh, &k)?;
- if (hasnext(g)? && peek(g) == tag::SIGNATURE) {
+ for (hasnext(g)? && peek(g) == tag::SIGNATURE) {
p = next(g)?;
pkt_dump(&p);
};
@@ 475,3 506,15 @@ fn pkt_dump(p: *packet) void = {
io::copy(&buf, p)!;
hex::dump(os::stdout, memio::buffer(&buf))!;
};
+
+fn pkt_skip(p: *packet) (void | io::error) = {
+ return match (io::copy(io::empty, p)) {
+ case size =>
+ void;
+ case let e: io::error =>
+ if (e is io::underread) {
+ return;
+ };
+ return e;
+ };
+};
M format/openpgp/rsa.ha => format/openpgp/rsa.ha +16 -0
@@ 9,6 9,8 @@ use errors;
use hash;
use io;
+use debug::*;
+
export type rsakey = struct {
key: keypair,
pub: []u8,
@@ 116,10 118,24 @@ fn rsa_verify(
};
let sig = sig[2..];
+
+ let pp = rsa::pubkey_params(k.pub);
+
+ let sigbuf: []u8 = [];
+ defer free(sigbuf);
+
+ if (len(sig) < len(pp.n)) {
+ // sig must be the same length as n.
+ sigbuf = alloc([0...], len(pp.n));
+ sigbuf[len(pp.n) - len(sig)..] = sig[..];
+ sig = sigbuf;
+ };
+
const algo = rsa_hashalgo(hashalgo)?;
let r = rsa::pkcs1_verify(k.pub, hashsum, sig, algo, buf);
if (r is rsa::error) {
+ print("!!2");
return badsig;
};
};
M format/openpgp/sig.ha => format/openpgp/sig.ha +25 -4
@@ 74,6 74,8 @@ export type sigtype = enum u8 {
};
export fn strsigtype(st: u8) str = {
+ static let idbuf: [16]u8 = [0...];
+
switch (st) {
case sigtype::BINARY =>
return "BINARY";
@@ 106,7 108,7 @@ export fn strsigtype(st: u8) str = {
case sigtype::THIRD_PARTY_CONFIRM_SIG =>
return "THIRD_PARTY_CONFIRM_SIG";
case =>
- return "UNKNOWN";
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", st);
};
};
@@ 136,7 138,8 @@ export type subtype = enum u8 {
ISSUER_FINGERPRINT = 33,
};
-export fn strsubtype(st: u8) str = {
+export fn strsigsubtype(st: u8) str = {
+ let idbuf: [16]u8 = [0...];
switch (st) {
case subtype::SIG_CREATION_TIME =>
return "SIG_CREATION_TIME";
@@ 185,7 188,8 @@ export fn strsubtype(st: u8) str = {
case subtype::ISSUER_FINGERPRINT =>
return "ISSUER_FINGERPRINT";
case =>
- return "UNKNOWN";
+ idbuf = [0...];
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", st);
};
};
@@ 231,6 235,7 @@ export type sigopts = struct {
keyfp: []u8,
keyflags: u8,
createdat: (void | date::date),
+ expiresat: (void | date::date),
};
export fn sig_free(s: *sig) void = {
@@ 243,6 248,7 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
let s = sig {
opts = sigopts {
createdat = void,
+ expiresat = void,
...
},
...
@@ 261,6 267,7 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
s.hsub = io::drain(&io::limitreader(p, hsubsz))!;
+ print("parse hsub");
let hs = memio::fixed(s.hsub);
for (true) {
let sz = match (parsesubsz(&hs)?) {
@@ 285,6 292,13 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
n += io::read(&sub, tbuf) as size;
let in = time::from_unix(endian::begetu32(tbuf): i64);
s.opts.createdat = date::from_instant(chrono::UTC, in);
+ case subtype::SIG_EXPIRATION_TIME =>
+ // TODO duplicate code
+ if (subsz != 4) return invalid;
+ let tbuf: [4]u8 = [0...];
+ n += io::read(&sub, tbuf) as size;
+ let in = time::from_unix(endian::begetu32(tbuf): i64);
+ s.opts.expiresat = date::from_instant(chrono::UTC, in);
case subtype::KEYFLAGS =>
s.opts.keyflags = readu8(&sub)?;
n += 1;
@@ 294,11 308,16 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
s.opts.keyfp = io::drain(&sub)?;
n += 1 + len(s.opts.keyfp);
case =>
- if (crit) return unsupported_critsub;
+ print("CRIT", crit, stype);
+ if (crit) {
+ hexdump(&sub);
+ return stype: critsigsub;
+ };
n += io::copy(io::empty, &sub)?;
};
if (n != subsz) {
+ print("WTF");
return invalid;
};
//fmt::printfln(" SUB [{}], crit: {}", stype & 0x7f, stype & 0x80 == 0x80)!;
@@ 312,6 331,7 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
readall(p, s.hprefix)?;
s.s = io::drain(p)!;
+ print("SIGOK");
return s;
};
@@ 385,6 405,7 @@ export fn verify(s: *sig, h: *hash::hash, k: *key) (void | error) = {
};
let sr = memio::fixed(s.s);
+ print("Keypair_verify");
// TODO figure out signing key, if not primary?
return keypair_verify(k.primary, &sr, sum, s.hashalgo);
};