summaryrefslogtreecommitdiff
path: root/appl/lib/spki/verifier.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/spki/verifier.b')
-rw-r--r--appl/lib/spki/verifier.b188
1 files changed, 188 insertions, 0 deletions
diff --git a/appl/lib/spki/verifier.b b/appl/lib/spki/verifier.b
new file mode 100644
index 00000000..d712fd2a
--- /dev/null
+++ b/appl/lib/spki/verifier.b
@@ -0,0 +1,188 @@
+implement Verifier;
+
+#
+# Copyright © 2004 Vita Nuova Holdings Limited
+#
+
+include "sys.m";
+ sys: Sys;
+
+include "keyring.m";
+ kr: Keyring;
+ IPint: import kr;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "sexprs.m";
+ sexprs: Sexprs;
+ Sexp: import sexprs;
+
+include "spki.m";
+ spki: SPKI;
+ Hash, Key, Cert, Name, Subject, Signature, Seqel, Toplev, Valid: import spki;
+ dump: import spki;
+
+include "encoding.m";
+ base64: Encoding;
+
+debug := 0;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ kr = load Keyring Keyring->PATH;
+ bufio = load Bufio Bufio->PATH;
+ sexprs = load Sexprs Sexprs->PATH;
+ spki = load SPKI SPKI->PATH;
+ base64 = load Encoding Encoding->BASE64PATH;
+
+ sexprs->init();
+ spki->init();
+}
+
+putkey(keys: list of ref Key, k: ref Key): list of ref Key
+{
+ for(kl := keys; kl != nil; kl = tl kl)
+ if(k.eq(hd kl))
+ return keys;
+ return k :: keys;
+}
+
+keybyhash(h: ref Hash, keys: list of ref Key): ref Key
+{
+ for(kl := keys; kl != nil; kl = tl kl){
+ k := hd kl;
+ if(k.hash != nil && h.eq(k.hash))
+ return k;
+ }
+ return nil;
+}
+
+verify(seq: list of ref Seqel): (ref Speaksfor, list of ref Seqel, string)
+{
+ stack: list of ref Seqel;
+ keys: list of ref Key;
+ n0: ref Name;
+ cn: ref Cert;
+ delegate := 1;
+ tag: ref Sexp;
+ val: ref Valid;
+ for(; seq != nil; seq = tl seq){
+ pick s := hd seq {
+ C =>
+ diag := checkcert(s.c);
+ if(diag != nil)
+ return (nil, seq, diag);
+ if(stack != nil){
+ pick h := hd stack {
+ C =>
+ if(!delegate)
+ return(nil, seq, "previous auth certificate did not delegate");
+ if(!h.c.subject.principal().eq(s.c.issuer.principal))
+ return (nil, seq, "certificate chain has mismatched principals");
+ if(debug)
+ sys->print("issuer %s ok\n", s.c.issuer.principal.text());
+ }
+ stack = tl stack;
+ }
+ stack = s :: stack;
+ if(n0 == nil)
+ n0 = s.c.issuer;
+ cn = s.c;
+ pick t := s.c {
+ A or KH or O =>
+ delegate = t.delegate;
+ if(tag != nil){
+ tag = spki->tagintersect(tag, t.tag);
+ if(tag == nil)
+ return (nil, seq, "certificate chain has null authority");
+ }else
+ tag = t.tag;
+ if(val != nil){
+ if(t.valid != nil){
+ (ok, iv) := (*val).intersect(*t.valid);
+ if(!ok)
+ return (nil, seq, "certificate chain is not currently valid");
+ *val = iv;
+ }
+ }else
+ val = t.valid;
+ }
+ K =>
+ stack = s :: stack;
+ O =>
+ if(s.op == "debug"){
+ debug = !debug;
+ continue;
+ }
+ if(s.op != "hash" || s.args == nil || tl s.args != nil)
+ return (nil, seq, "invalid operation to `do'");
+ alg := (hd s.args).astext();
+ if(alg != "md5" && alg != "sha1")
+ return (nil, seq, "invalid hash operation");
+ if(stack == nil)
+ return (nil, seq, "verification stack empty");
+ pick h := hd stack {
+ K =>
+ a := h.k.hashed(alg);
+ if(debug)
+ dump("do hash", a);
+ keys = putkey(keys, h.k);
+ stack = tl stack;
+ C =>
+ ;
+ * =>
+ return (nil, seq, "invalid type of operand for hash");
+ }
+ S =>
+ if(stack == nil)
+ return (nil, seq, "verification stack empty");
+ sig := s.sig;
+ if(sig.key == nil)
+ return (nil, seq, "neither hash nor key for signature");
+ if(sig.key.pk == nil){
+ k := keybyhash(sig.key.hash, keys);
+ if(k == nil)
+ return (nil, seq, "unknown key for signature");
+ sig.key = k;
+ }
+ pick c := hd stack {
+ C =>
+ if(c.c.e == nil)
+ return (nil, seq, "missing canonical expression for cert");
+ a := c.c.e.pack();
+ # verify signature ...
+ if(debug)
+ dump("cert a", a);
+ h := spki->hashbytes(a, "md5");
+ if(debug){
+ dump("hash cert", h);
+ sys->print("hash = %q\n", base64->enc(h));
+ }
+ failed := spki->checksig(c.c, sig);
+ if(debug)
+ sys->print("checksig: %q\n", failed);
+ if(failed != nil)
+ return (nil, seq, "signature verification failed: "+failed);
+ * =>
+ return (nil, seq, "invalid type of signature operand");
+ }
+ }
+ }
+ if(n0 != nil && cn != nil){
+ if(debug){
+ if(tag != nil)
+ auth := sys->sprint(" regarding %q", tag.text());
+ sys->print("%q speaks for %q%s\n", cn.subject.text(), n0.text(), auth);
+ }
+ return (ref Speaksfor(cn.subject, n0, tag, val), nil, nil);
+ }
+ return (nil, nil, nil);
+}
+
+checkcert(c: ref Cert): string
+{
+ return nil;
+}