M format/openpgp/errors.ha => format/openpgp/errors.ha +18 -5
@@ 8,15 8,21 @@ export type invalid = !void;
export type unexpected = !void;
export type weakhash = !void;
+export type unknowntag = !u8;
export type critsigsub = !u8;
+export type unsupversion = !u8;
+export type unsupsenc = !u8;
+export type unsupkey = !u8;
-export type error = !(io::error | unsupported | badsig | invalid | unexpected |
- weakhash | critsigsub);
+export type error = !(io::error | unsupported | badsig | invalid | unexpected
+ | weakhash | unknowntag | critsigsub | unsupversion | unsupsenc
+ | unsupkey);
// 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...];
+ errbuf = [0...];
match (e) {
case let e: unsupported =>
@@ 30,17 36,24 @@ export fn strerror(e: error) str = {
case weakhash =>
return "Signature on key or data is done using a weak hash "
"function and can not be trusted.";
+ case let e: unknowntag =>
+ // XXX: could be unsupported, if implementation matures
+ return fmt::bsprintf(errbuf, "Unknown tag id: {}", e: u8);
+ case let e: unsupversion =>
+ return fmt::bsprintf(errbuf, "Unsupported format version: {}", e: u8);
case let e: critsigsub =>
return fmt::bsprint(errbuf, "Unsupported critical signature "
"subtype:", strsigsubtype(e));
+ case let e: unsupsenc =>
+ return fmt::bsprint(errbuf, "Unsupported symmetric encryption "
+ "algo:", strsenclgo(e));
+ case let e: unsupkey =>
+ return fmt::bsprint(errbuf, "Unsupported key:", strpubkeyalgo(e));
case let e: io::error =>
return io::strerror(e);
};
};
-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/key.ha => format/openpgp/key.ha +1 -1
@@ 127,7 127,7 @@ fn ivsz(algo: u8) (size | error) = {
case sencalgo::AES256 =>
return 32z;
case =>
- return unsupported_encalgo;
+ return (algo: unsupsenc): error;
};
};
M format/openpgp/reader.ha => format/openpgp/reader.ha +55 -62
@@ 80,9 80,7 @@ fn next(d: *reader) (packet | error) = {
};
fn hasnext(d: *reader) (bool | error) = {
- print("hasnext");
if (d.next is packet) {
- print("cached");
return true;
};
@@ 118,18 116,14 @@ 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,
@@ 140,14 134,11 @@ 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 | error) = {
const old = t & 0x40 == 0;
- print("old", old);
p.szt = sizetype::FIXED;
p.sz = 0z;
@@ 162,11 153,11 @@ fn parsesz(src: io::handle, p: *packet, t: u8) (void | error) = {
p.szt = sizetype::INDETERMINATE;
return;
case =>
+ // unreachable
abort();
};
if (io::readall(src, buf[..max])? is io::EOF) {
- print("wtf");
return invalid;
};
p.hsz += max;
@@ 174,7 165,6 @@ fn parsesz(src: io::handle, p: *packet, t: u8) (void | error) = {
p.sz <<= 8;
p.sz += buf[i];
};
- print("size", p.sz);
return;
};
@@ 260,23 250,23 @@ fn pkt_parse_pubkey(p: *packet, mh: *multihash) (*keypair | error) = {
let buf: [6]u8 = [0...];
if (io::readall(p, buf)? is io::EOF) {
- return errors::invalid;
+ return invalid;
};
- if (buf[0] != 4) {
- print("unsup1");
- return unsupported_key: unsupported;
+ const version = buf[0];
+ if (version != 4) {
+ return version: unsupversion;
};
let i = time::from_unix(endian::begetu32(buf[1..5]): i64);
- let d = date::from_instant(chrono::UTC, i);
+ let created = date::from_instant(chrono::UTC, i);
- if (buf[5] != 1) { // RSA sign or encrypt
- print("unsup2");
- return unsupported_key: unsupported;
+ const keyalgo = buf[5];
+ if (keyalgo != pubkeyalgo::RSA) { // RSA sign or encrypt
+ return keyalgo: unsupkey;
};
- let key = alloc(newrsakey(d)): *keypair;
+ let key = alloc(newrsakey(created)): *keypair;
key.vtable.read_pub(key, p)?;
let rawbuf = memio::buffer(&raw);
@@ 324,6 314,7 @@ export type keyiter = struct {
export fn load_keys(h: io::handle) keyiter = keyiter {
r = newreader(h),
+ ...
};
export fn parse_key(h: io::handle) (key | void | error) = {
@@ 331,16 322,36 @@ export fn parse_key(h: io::handle) (key | void | error) = {
return keys_next(&iter);
};
+fn pkt_skip_until(r: *reader, tags: tag...) (void | io::EOF | error) = {
+ for (true) {
+ if (!hasnext(r)?) {
+ return io::EOF;
+ };
+
+ const t = peek(r);
+ for (let i = 0z; i < len(tags); i += 1) {
+ if (t == tags[i]) {
+ return;
+ };
+ };
+
+ let p = next(r)?;
+ pkt_skip(&p)?;
+ };
+};
+
export fn keys_next(iter: *keyiter) (key | void | error) = {
- print("Next");
let mh = newmultihash();
- let g = &iter.r;
+ let r = &iter.r;
- if (!hasnext(g)?) {
- return void;
+ if (pkt_skip_until(r, tag::SECRET_KEY, tag::PUBLIC_KEY)? is io::EOF) {
+ return;
};
- let p = next(g)?;
- print(p.tag: u8);
+
+ let p = next(r)?;
+ // TODO: instead of defer, would be neat to safe p in iter or reader
+ // and skip it if set on pkt_skip_until. Requires ptr to compound
+ defer pkt_skip(&p)!;
const priv = switch (p.tag) {
case tag::SECRET_KEY =>
@@ 348,31 359,11 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
case tag::PUBLIC_KEY =>
yield false;
case =>
- 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;
+ return invalid;
};
+ let primary = pkt_parse_key(&p, &mh, priv)?;
+
let k = key {
primary = primary,
sub = [],
@@ 382,22 373,22 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
let valid = false;
defer if (!valid) key_finish(&k);
- for (hasnext(g)? && peek(g) == tag::SIGNATURE) {
- p = next(g)?;
+ for (hasnext(r)? && peek(r) == tag::SIGNATURE) {
+ p = next(r)?;
// TODO Zero or more revocation signatures
//println("TODO: REVOCATION SIGNATURE")!;
pkt_dump(&p);
};
- if (!hasnext(g)? || peek(g) != tag::USER_ID) {
+ if (!hasnext(r)? || peek(r) != tag::USER_ID) {
return invalid;
};
print("# parse user ids and attributes");
- for (hasnext(g)? && (peek(g) == tag::USER_ID || peek(g) == tag::USER_ATTRIBUTE)) {
+ for (hasnext(r)? && (peek(r) == tag::USER_ID || peek(r) == tag::USER_ATTRIBUTE)) {
let mh = multihash_clone(&mh);
- p = next(g)?;
+ p = next(r)?;
if (p.tag == tag::USER_ID) {
print("USER_ID");
@@ 408,10 399,10 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
io::copy(&mh, &p)?;
};
- for (hasnext(g)? && peek(g) == tag::SIGNATURE) {
+ for (hasnext(r)? && peek(r) == tag::SIGNATURE) {
let mh = multihash_clone(&mh);
print(" parse sig");
- p = next(g)?;
+ p = next(r)?;
let sig = pkg_parsesig(&p)?;
defer sig_free(&sig);
multihash_select(&mh, sig.hashalgo)?;
@@ 471,15 462,15 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
print("# parse sub keys");
const subkeytag = if (priv) tag::SECRET_SUBKEY else tag::PUBLIC_SUBKEY;
- for (hasnext(g)? && peek(g) == subkeytag) {
+ for (hasnext(r)? && peek(r) == subkeytag) {
print(" - subkey");
let mh = multihash_clone(&mh);
- p = next(g)?;
+ p = next(r)?;
let sk = pkt_parse_key(&p, &mh, priv)?;
append(k.sub, subkey { key = sk });
- p = next(g)?;
+ p = next(r)?;
let sig = pkg_parsesig(&p)?;
multihash_select(&mh, sig.hashalgo)?;
@@ 489,13 480,15 @@ export fn keys_next(iter: *keyiter) (key | void | error) = {
};
verify(&sig, &mh, &k)?;
- for (hasnext(g)? && peek(g) == tag::SIGNATURE) {
- p = next(g)?;
+ for (hasnext(r)? && peek(r) == tag::SIGNATURE) {
+ p = next(r)?;
pkt_dump(&p);
};
};
- print("done, next is", (g.next: packet).tag: u8);
+ if (r.next is packet) {
+ print("next is", strtag((r.next: packet).tag));
+ };
valid = true;
return k;
};
M format/openpgp/sig.ha => format/openpgp/sig.ha +1 -1
@@ 255,7 255,7 @@ fn pkg_parsesig(p: *packet) (sig | error) = {
};
s.v = readu8(p)?;
if (s.v != 4) {
- return unsupported_version;
+ return s.v: unsupversion;
};
s.sigtype = readu8(p)?;
M format/openpgp/types.ha => format/openpgp/types.ha +42 -27
@@ 1,6 1,7 @@
use crypto::sha256;
use crypto::sha512;
use errors;
+use fmt;
use hash;
use io;
use time::date;
@@ 14,11 15,11 @@ export type sizetype = enum {
fn strsizetype(s: sizetype) str = {
switch (s) {
case sizetype::FIXED =>
- return "fixed";
+ return "FIXED";
case sizetype::INDETERMINATE =>
- return "indeterminate";
+ return "INDETERMINATE";
case sizetype::PARTIAL =>
- return "partial";
+ return "PARTIAL";
case =>
abort();
};
@@ 55,9 56,9 @@ export type tag = enum u8 {
MODIFICATION_DETECTION_CODE = 19,
};
-fn u8totag(t: u8) (tag | errors::invalid) = {
+fn u8totag(t: u8) (tag | unknowntag) = {
if (t == 0 || t == 15 || t == 16 || t > 19) {
- return errors::invalid;
+ return t: unknowntag;
};
return t: tag;
@@ 66,41 67,41 @@ fn u8totag(t: u8) (tag | errors::invalid) = {
fn strtag(t: tag) str = {
switch (t) {
case tag::RESERVED =>
- return "reserved";
+ return "RESERVED";
case tag::PUBLIC_KEY_ENCRYPTED_SESSION_KEY =>
- return "public_key_encrypted_session_key";
+ return "PUBLIC_KEY_ENCRYPTED_SESSION_KEY";
case tag::SIGNATURE =>
- return "signature";
+ return "SIGNATURE";
case tag::ENCRYPTED_SESSION_KEY =>
- return "encrypted_session_key";
+ return "ENCRYPTED_SESSION_KEY";
case tag::ONE_PASS_SIGNATURE =>
- return "one_pass_signature";
+ return "ONE_PASS_SIGNATURE";
case tag::SECRET_KEY =>
- return "secret_key";
+ return "SECRET_KEY";
case tag::PUBLIC_KEY =>
- return "public_key";
+ return "PUBLIC_KEY";
case tag::SECRET_SUBKEY =>
- return "secret_subkey";
+ return "SECRET_SUBKEY";
case tag::COMPRESSED_DATA =>
- return "compressed_data";
+ return "COMPRESSED_DATA";
case tag::ENCRYPTED_DATA =>
- return "encrypted_data";
+ return "ENCRYPTED_DATA";
case tag::MARKER =>
- return "marker";
+ return "MARKER";
case tag::LITERAL_DATA =>
- return "literal_data";
+ return "LITERAL_DATA";
case tag::TRUST =>
- return "trust";
+ return "TRUST";
case tag::USER_ID =>
- return "user_id";
+ return "USER_ID";
case tag::PUBLIC_SUBKEY =>
- return "public_subkey";
+ return "PUBLIC_SUBKEY";
case tag::USER_ATTRIBUTE =>
- return "user_attribute";
+ return "USER_ATTRIBUTE";
case tag::ENCRYPTED_AND_INTEGRITY_PROTECTED_DATA =>
- return "encrypted_and_integrity_protected_data";
+ return "ENCRYPTED_AND_INTEGRITY_PROTECTED_DATA";
case tag::MODIFICATION_DETECTION_CODE =>
- return "modification_detection_code";
+ return "MODIFICATION_DETECTION_CODE";
};
};
@@ 166,7 167,9 @@ fn strhashalgo(hashalgo: u8) str = {
case hashalgo::SHA224 =>
return "SHA224";
case =>
- return "unsupported";
+ static let idbuf: [16]u8 = [0...];
+ idbuf = [0...];
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", hashalgo);
};
};
@@ 174,6 177,8 @@ type pubkeyalgo = enum u8 {
RSA = 1,
RSA_ENCRYPT = 2,
RSA_SIGN = 3,
+ ELGAMAL = 16,
+ DSA = 17,
};
fn strpubkeyalgo(pubkeyalgo: u8) str = {
@@ 184,8 189,14 @@ fn strpubkeyalgo(pubkeyalgo: u8) str = {
return "RSA_ENCRYPT";
case pubkeyalgo::RSA_SIGN =>
return "RSA_SIGN";
+ case pubkeyalgo::ELGAMAL =>
+ return "ELGAMAL";
+ case pubkeyalgo::DSA =>
+ return "DSA";
case =>
- return "unsupported";
+ static let idbuf: [16]u8 = [0...];
+ idbuf = [0...];
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", pubkeyalgo);
};
};
@@ 222,7 233,9 @@ fn strsenclgo(a: u8) str = {
case sencalgo::TWOFISH =>
return "TWOFISH";
case =>
- return "unsupported";
+ static let idbuf: [16]u8 = [0...];
+ idbuf = [0...];
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", a);
};
};
@@ 241,6 254,8 @@ fn strs2ktype(t: u8) str = {
case s2ktype::ITERATED_AND_SALTED =>
return "ITERATED_AND_SALTED";
case =>
- return "unsupported";
+ static let idbuf: [16]u8 = [0...];
+ idbuf = [0...];
+ return fmt::bsprintf(idbuf, "[UNKNOWN {}]", t);
};
};