aboutsummaryrefslogtreecommitdiff
path: root/libinterp/keyring.c
diff options
context:
space:
mode:
authorbhgv <bhgv.empire@gmail.com>2018-03-01 16:54:45 +0200
committerbhgv <bhgv.empire@gmail.com>2018-03-01 16:54:45 +0200
commitb786f20bbab5a59046aa78a2c6c2a11536497202 (patch)
tree0851ecdec889eb9b7ba3751cc04d4f0b474e4a9e /libinterp/keyring.c
inferno-os tree was separated from the inferno-os-android (separated from the Android driver)
Diffstat (limited to 'libinterp/keyring.c')
-rw-r--r--libinterp/keyring.c3083
1 files changed, 3083 insertions, 0 deletions
diff --git a/libinterp/keyring.c b/libinterp/keyring.c
new file mode 100644
index 0000000..8b7fd40
--- /dev/null
+++ b/libinterp/keyring.c
@@ -0,0 +1,3083 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+
+/* arguably limbo -t should qualify type name */
+#define DigestState_copy Keyring_DigestState_copy
+#define IPint_random Keyring_IPint_random
+#include "keyringif.h"
+#include "keyring.h"
+
+#include "ipint.h"
+#include "../libkeyring/keys.h"
+
+static Type* TDigestState;
+static Type* TAESstate;
+static Type* TDESstate;
+static Type* TIDEAstate;
+static Type* TBFstate;
+static Type* TRC4state;
+
+static Type* TSigAlg;
+static Type* TCertificate;
+static Type* TSK;
+static Type* TPK;
+static Type* TAuthinfo;
+
+static Type* TDSAsk;
+static Type* TDSApk;
+static Type* TDSAsig;
+static Type* TEGsk;
+static Type* TEGpk;
+static Type* TEGsig;
+static Type* TRSAsk;
+static Type* TRSApk;
+static Type* TRSAsig;
+
+enum {
+ Maxmsg= 4096
+};
+
+static uchar DigestStatemap[] = Keyring_DigestState_map;
+static uchar AESstatemap[] = Keyring_AESstate_map;
+static uchar DESstatemap[] = Keyring_DESstate_map;
+static uchar IDEAstatemap[] = Keyring_IDEAstate_map;
+static uchar BFstatemap[] = Keyring_BFstate_map;
+static uchar RC4statemap[] = Keyring_RC4state_map;
+
+static uchar SigAlgmap[] = Keyring_SigAlg_map;
+static uchar SKmap[] = Keyring_SK_map;
+static uchar PKmap[] = Keyring_PK_map;
+static uchar Certificatemap[] = Keyring_Certificate_map;
+static uchar Authinfomap[] = Keyring_Authinfo_map;
+static uchar DSAskmap[] = Keyring_DSAsk_map;
+static uchar DSApkmap[] = Keyring_DSApk_map;
+static uchar DSAsigmap[] = Keyring_DSAsig_map;
+static uchar EGskmap[] = Keyring_EGsk_map;
+static uchar EGpkmap[] = Keyring_EGpk_map;
+static uchar EGsigmap[] = Keyring_EGsig_map;
+static uchar RSAskmap[] = Keyring_RSAsk_map;
+static uchar RSApkmap[] = Keyring_RSApk_map;
+static uchar RSAsigmap[] = Keyring_RSAsig_map;
+
+static PK* checkPK(Keyring_PK *k);
+
+extern void setid(char*, int);
+extern vlong osusectime(void);
+extern void freeIPint(Heap*, int);
+
+static char exBadSA[] = "bad signature algorithm";
+static char exBadSK[] = "bad secret key";
+static char exBadPK[] = "bad public key";
+static char exBadCert[] = "bad certificate";
+static char exBadBsize[] = "data not multiple of block size";
+static char exBadKey[] = "bad encryption key";
+static char exBadDigest[] = "bad digest value";
+static char exBadIvec[] = "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+typedef struct XBFstate XBFstate;
+
+/* BF state */
+struct XBFstate
+{
+ Keyring_BFstate x;
+ BFstate state;
+};
+
+/* convert a Big to base64 ascii */
+int
+bigtobase64(mpint* b, char *buf, int len)
+{
+ uchar *p;
+ int n, rv, o;
+
+ n = (b->top+1)*Dbytes;
+ p = malloc(n+1);
+ if(p == nil)
+ goto Err;
+ n = mptobe(b, p+1, n, nil);
+ if(n < 0)
+ goto Err;
+ p[0] = 0;
+ if(n != 0 && (p[1]&0x80)){
+ /* force leading 0 byte for compatibility with older representation */
+ /* TO DO: if b->sign < 0, complement bits and add one */
+ o = 0;
+ n++;
+ }else
+ o = 1;
+ rv = enc64(buf, len, p+o, n);
+ free(p);
+ return rv;
+
+Err:
+ free(p);
+ if(len > 0){
+ *buf = '*';
+ return 1;
+ }
+ return 0;
+}
+
+/* convert a Big to base64 ascii for %U */
+int
+big64conv(Fmt *f)
+{
+ mpint *b;
+ char *buf;
+ int n;
+
+ b = va_arg(f->args, mpint*);
+ n = (b->top+1)*Dbytes + 1;
+ n = ((n+3)/3)*4 + 1;
+ buf = malloc(n);
+ bigtobase64(b, buf, n);
+ n = fmtstrcpy(f, buf);
+ free(buf);
+ return n;
+}
+
+static void*
+newthing(Type *t, int add)
+{
+ Heap *h;
+
+ h = heap(t);
+ if(add)
+ ptradd(h);
+ return H2D(void*, h);
+}
+
+static Keyring_IPint*
+ipcopymp(mpint* b)
+{
+ if(b == nil)
+ return H;
+ return newIPint(mpcopy(b));
+}
+
+/* convert a base64 string to a big */
+mpint*
+base64tobig(char *str, char **strp)
+{
+ int n;
+ char *p;
+ mpint *b;
+ uchar hex[(MaxBigBytes*6 + 7)/8];
+
+ for(p = str; *p && *p != '\n'; p++)
+ ;
+ if(p == str)
+ return nil;
+ n = dec64(hex, sizeof(hex), str, p - str);
+ b = betomp(hex, n, nil);
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+ return b;
+}
+
+/*
+ * signature algorithms
+ */
+enum
+{
+ Maxalg = 8
+};
+static SigAlgVec *algs[Maxalg];
+static int nalg;
+
+static SigAlg*
+newSigAlg(SigAlgVec *vec)
+{
+ Heap *h;
+ SigAlg *sa;
+
+ h = heap(TSigAlg);
+ sa = H2D(SigAlg*, h);
+ retstr(vec->name, &sa->x.name);
+ sa->vec = vec;
+ return sa;
+}
+
+static void
+freeSigAlg(Heap *h, int swept)
+{
+ if(!swept)
+ freeheap(h, 0);
+}
+
+SigAlgVec*
+findsigalg(char *name)
+{
+ SigAlgVec **sap;
+
+ for(sap = algs; sap < &algs[nalg]; sap++)
+ if(strcmp(name, (*sap)->name) == 0)
+ return *sap;
+ return nil;
+}
+
+SigAlg*
+strtoalg(char *str, char **strp)
+{
+ int n;
+ char *p, name[20];
+ SigAlgVec *sa;
+
+
+ p = strchr(str, '\n');
+ if(p == 0){
+ p = str + strlen(str);
+ if(strp)
+ *strp = p;
+ } else {
+ if(strp)
+ *strp = p+1;
+ }
+
+ n = p - str;
+ if(n < sizeof(name)){
+ strncpy(name, str, n);
+ name[n] = 0;
+ sa = findsigalg(name);
+ if(sa != nil)
+ return newSigAlg(sa);
+ }
+ return nil;
+}
+
+static SigAlg*
+checkSigAlg(Keyring_SigAlg *ksa)
+{
+ SigAlgVec **sap;
+ SigAlg *sa;
+
+ sa = (SigAlg*)ksa;
+
+ for(sap = algs; sap < &algs[Maxalg]; sap++)
+ if(sa->vec == *sap)
+ return sa;
+ errorf("%s: %s", exType, exBadSA);
+ return nil;
+}
+
+/*
+ * parse next new line terminated string into a String
+ */
+String*
+strtostring(char *str, char **strp)
+{
+ char *p;
+ String *s;
+
+ p = strchr(str, '\n');
+ if(p == 0)
+ p = str + strlen(str);
+ s = H;
+ retnstr(str, p - str, &s);
+
+ if(strp){
+ if(*p)
+ p++;
+ *strp = p;
+ }
+
+ return s;
+}
+
+/*
+ * private part of a key
+ */
+static SK*
+newSK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ SK *k;
+
+ h = heap(TSK);
+ k = H2D(SK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+static void
+freeSK(Heap *h, int swept)
+{
+ SK *k;
+ SigAlg *sa;
+
+ k = H2D(SK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->skfree)(k->key);
+ freeheap(h, swept);
+}
+
+static SK*
+checkSK(Keyring_SK *k)
+{
+ SK *sk;
+
+ sk = (SK*)k;
+ if(sk == H || sk == nil || sk->key == 0 || D2H(sk)->t != TSK){
+ errorf("%s: %s", exType, exBadSK);
+ return nil;
+ }
+ return sk;
+}
+
+void
+Keyring_genSK(void *fp)
+{
+ F_Keyring_genSK *f;
+ SK *sk;
+ SigAlg *sa;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sa = strtoalg(string2c(f->algname), 0);
+ if(sa == nil)
+ return;
+
+ sk = newSK(sa, stringdup(f->owner), 0);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->gensk)(f->length);
+ acquire();
+}
+
+void
+Keyring_genSKfromPK(void *fp)
+{
+ F_Keyring_genSKfromPK *f;
+ SigAlg *sa;
+ PK *pk;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ sk = newSK(sa, stringdup(f->owner), 1);
+ *f->ret = (Keyring_SK*)sk;
+ release();
+ sk->key = (*sa->vec->genskfrompk)(pk->key);
+ acquire();
+}
+
+/* converts a sequence of newline-separated base64-encoded mpints to attr=hexval ... in f */
+static char*
+bigs2attr(Fmt *f, char *bigs, char **names)
+{
+ int i, n, nd;
+ char *b16, *vals[20];
+ uchar data[(MaxBigBytes*6 + 7)/8];
+
+ b16 = malloc(2*MaxBigBytes+1);
+ if(b16 == nil)
+ return nil;
+ n = getfields(bigs, vals, nelem(vals), 0, "\n");
+ for(i = 0; i < n-1; i++){
+ if(names == nil || names[i] == nil)
+ break; /* shouldn't happen */
+ nd = dec64(data, sizeof(data), vals[i], strlen(vals[i]));
+ if(nd < 0)
+ break;
+ enc16(b16, 2*MaxBigBytes+1, data, nd);
+ fmtprint(f, " %s=%s", names[i], b16);
+ }
+ free(b16);
+ return fmtstrflush(f);
+}
+
+void
+Keyring_sktoattr(void *fp)
+{
+ F_Keyring_sktoattr *f;
+ char *val, *buf, *owner;
+ SigAlg *sa;
+ Fmt o;
+ SK *sk;
+
+ f = fp;
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sk2str)(sk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q", string2c(sa->x.name));
+ owner = string2c(sk->x.owner);
+ if(*owner)
+ fmtprint(&o, " owner=%q", owner);
+ val = bigs2attr(&o, buf, sa->vec->skattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static int
+sktostr(SK *sk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(sk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name),
+ string2c(sk->x.owner));
+ return n + (*sa->vec->sk2str)(sk->key, buf+n, len - n);
+}
+
+void
+Keyring_sktostr(void *fp)
+{
+ F_Keyring_sktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ sktostr(checkSK(f->sk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+static SK*
+strtosk(char *buf)
+{
+ SK *sk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2sk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ sk = newSK(sa, owner, 0);
+ sk->key = key;
+
+ return sk;
+}
+
+void
+Keyring_strtosk(void *fp)
+{
+ F_Keyring_strtosk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_SK*)strtosk(string2c(f->s));
+}
+
+/*
+ * public part of a key
+ */
+PK*
+newPK(SigAlg *sa, String *owner, int increfsa)
+{
+ Heap *h;
+ PK *k;
+
+ h = heap(TPK);
+ k = H2D(PK*, h);
+ k->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ k->x.owner = owner;
+ k->key = 0;
+ return k;
+}
+
+void
+pkimmutable(PK *k)
+{
+ poolimmutable(D2H(k));
+ poolimmutable(D2H(k->x.sa));
+ poolimmutable(D2H(k->x.sa->name));
+ poolimmutable(D2H(k->x.owner));
+}
+
+void
+pkmutable(PK *k)
+{
+ poolmutable(D2H(k));
+ poolmutable(D2H(k->x.sa));
+ poolmutable(D2H(k->x.sa->name));
+ poolmutable(D2H(k->x.owner));
+}
+
+void
+freePK(Heap *h, int swept)
+{
+ PK *k;
+ SigAlg *sa;
+
+ k = H2D(PK*, h);
+ sa = checkSigAlg(k->x.sa);
+ if(k->key)
+ (*sa->vec->pkfree)(k->key);
+ freeheap(h, swept);
+}
+
+static PK*
+checkPK(Keyring_PK *k)
+{
+ PK *pk;
+
+ pk = (PK*)k;
+ if(pk == H || pk == nil || pk->key == 0 || D2H(pk)->t != TPK){
+ errorf("%s: %s", exType, exBadPK);
+ return nil;
+ }
+ return pk;
+}
+
+void
+Keyring_sktopk(void *fp)
+{
+ F_Keyring_sktopk *f;
+ PK *pk;
+ SigAlg *sa;
+ SK *sk;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+ pk = newPK(sa, stringdup(sk->x.owner), 1);
+ pk->key = (*sa->vec->sk2pk)(sk->key);
+ *f->ret = (Keyring_PK*)pk;
+}
+
+static int
+pktostr(PK *pk, char *buf, int len)
+{
+ int n;
+ SigAlg *sa;
+
+ sa = checkSigAlg(pk->x.sa);
+ n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name), string2c(pk->x.owner));
+ return n + (*sa->vec->pk2str)(pk->key, buf+n, len - n);
+}
+
+void
+Keyring_pktostr(void *fp)
+{
+ F_Keyring_pktostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ pktostr(checkPK(f->pk), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_pktoattr(void *fp)
+{
+ F_Keyring_pktoattr *f;
+ char *val, *buf, *owner;
+ SigAlg *sa;
+ Fmt o;
+ PK *pk;
+
+ f = fp;
+ pk = checkPK(f->pk);
+ sa = checkSigAlg(pk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->pk2str)(pk->key, buf, Maxbuf);
+ fmtstrinit(&o);
+ fmtprint(&o, "alg=%q", string2c(sa->x.name));
+ owner = string2c(pk->x.owner);
+ if(*owner)
+ fmtprint(&o, " owner=%q", owner);
+ val = bigs2attr(&o, buf, sa->vec->pkattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static PK*
+strtopk(char *buf)
+{
+ PK *pk;
+ char *p;
+ SigAlg *sa;
+ String *owner;
+ void *key;
+
+ sa = strtoalg(buf, &p);
+ if(sa == nil)
+ return H;
+ owner = strtostring(p, &p);
+ if(owner == H){
+ destroy(sa);
+ return H;
+ }
+
+ key = (*sa->vec->str2pk)(p, &p);
+ if(key == nil){
+ destroy(sa);
+ destroy(owner);
+ return H;
+ }
+ pk = newPK(sa, owner, 0);
+ pk->key = key;
+
+ return pk;
+}
+
+void
+Keyring_strtopk(void *fp)
+{
+ F_Keyring_strtopk *f;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+ *f->ret = (Keyring_PK*)strtopk(string2c(f->s));
+}
+
+/*
+ * Certificates/signatures
+ */
+
+void
+certimmutable(Certificate *c)
+{
+ poolimmutable(D2H(c));
+ poolimmutable(D2H(c->x.signer));
+ poolimmutable(D2H(c->x.ha));
+ poolimmutable(D2H(c->x.sa));
+ poolimmutable(D2H(c->x.sa->name));
+}
+
+void
+certmutable(Certificate *c)
+{
+ poolmutable(D2H(c));
+ poolmutable(D2H(c->x.signer));
+ poolmutable(D2H(c->x.ha));
+ Setmark(D2H(c->x.sa));
+ poolmutable(D2H(c->x.sa));
+ Setmark(D2H(c->x.sa->name));
+ poolmutable(D2H(c->x.sa->name));
+}
+
+Certificate*
+newCertificate(SigAlg *sa, String *ha, String *signer, long exp, int increfsa)
+{
+ Heap *h;
+ Certificate *c;
+
+ h = heap(TCertificate);
+ c = H2D(Certificate*, h);
+ c->x.sa = (Keyring_SigAlg*)sa;
+ if(increfsa) {
+ h = D2H(sa);
+ h->ref++;
+ Setmark(h);
+ }
+ c->x.signer = signer;
+ c->x.ha = ha;
+ c->x.exp = exp;
+ c->signa = 0;
+
+ return c;
+}
+
+void
+freeCertificate(Heap *h, int swept)
+{
+ Certificate *c;
+ SigAlg *sa;
+
+ c = H2D(Certificate*, h);
+ sa = checkSigAlg(c->x.sa);
+ if(c->signa)
+ (*sa->vec->sigfree)(c->signa);
+ freeheap(h, swept);
+}
+
+Certificate*
+checkCertificate(Keyring_Certificate *c)
+{
+ Certificate *cert;
+
+ cert = (Certificate*)c;
+ if(cert == H || cert == nil || cert->signa == 0 || D2H(cert)->t != TCertificate){
+ errorf("%s: %s", exType, exBadCert);
+ return nil;
+ }
+ return cert;
+}
+
+static int
+certtostr(Certificate *c, char *buf, int len)
+{
+ SigAlg *sa;
+ int n;
+
+ sa = checkSigAlg(c->x.sa);
+ n = snprint(buf, len, "%s\n%s\n%s\n%d\n", string2c(sa->x.name),
+ string2c(c->x.ha), string2c(c->x.signer), c->x.exp);
+ return n + (*sa->vec->sig2str)(c->signa, buf+n, len - n);
+}
+
+void
+Keyring_certtostr(void *fp)
+{
+ F_Keyring_certtostr *f;
+ char *buf;
+
+ f = fp;
+ buf = malloc(Maxbuf);
+
+ if(buf)
+ certtostr(checkCertificate(f->c), buf, Maxbuf);
+ retstr(buf, f->ret);
+
+ free(buf);
+}
+
+void
+Keyring_certtoattr(void *fp)
+{
+ F_Keyring_certtoattr *f;
+ char *val, *buf, *ha;
+ SigAlg *sa;
+ Fmt o;
+ Certificate *c;
+
+ f = fp;
+ c = checkCertificate(f->c);
+ sa = checkSigAlg(c->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(nil, f->ret);
+ return;
+ }
+ (*sa->vec->sig2str)(c->signa, buf, Maxbuf);
+ ha = string2c(c->x.ha);
+ if(strcmp(ha, "sha") == 0)
+ ha = "sha1"; /* normalise */
+ fmtstrinit(&o);
+ fmtprint(&o, "sigalg=%q-%q signer=%q expires=%ud", string2c(sa->x.name), ha,
+ string2c(c->x.signer), c->x.exp);
+ val = bigs2attr(&o, buf, sa->vec->sigattr);
+ free(buf);
+ retstr(val, f->ret);
+ free(val);
+}
+
+static Certificate*
+strtocert(char *buf)
+{
+ Certificate *c;
+ char *p;
+ SigAlg *sa;
+ String *signer, *ha;
+ long exp;
+ void *signa;
+
+ sa = strtoalg(buf, &p);
+ if(sa == 0)
+ return H;
+
+ ha = strtostring(p, &p);
+ if(ha == H){
+ destroy(sa);
+ return H;
+ }
+
+ signer = strtostring(p, &p);
+ if(signer == H){
+ destroy(sa);
+ destroy(ha);
+ return H;
+ }
+
+ exp = strtoul(p, &p, 10);
+ if(*p)
+ p++;
+ signa = (*sa->vec->str2sig)(p, &p);
+ if(signa == nil){
+ destroy(sa);
+ destroy(ha);
+ destroy(signer);
+ return H;
+ }
+
+ c = newCertificate(sa, ha, signer, exp, 0);
+ c->signa = signa;
+
+ return c;
+}
+
+void
+Keyring_strtocert(void *fp)
+{
+ F_Keyring_strtocert *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = (Keyring_Certificate*)strtocert(string2c(f->s));
+}
+
+static Certificate*
+sign(SK *sk, char *ha, ulong exp, uchar *a, int len)
+{
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ String *hastr;
+
+ hastr = H;
+ sa = checkSigAlg(sk->x.sa);
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return nil;
+
+ /* add signer name and expiration time to hash */
+ n = snprint(buf, Maxbuf, "%s %lud", string2c(sk->x.owner), exp);
+ if(strcmp(ha, "sha") == 0 || strcmp(ha, "sha1") == 0){
+ ds = sha1(a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(ha, "md5") == 0){
+ ds = md5(a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(ha, "md4") == 0){
+ ds = md4(a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return nil;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return nil;
+
+ /* sign */
+ retstr(ha, &hastr);
+ c = newCertificate(sa, hastr, stringdup(sk->x.owner), exp, 1);
+ certimmutable(c); /* hide from the garbage collector */
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+
+ return c;
+}
+
+void
+Keyring_sign(void *fp)
+{
+ F_Keyring_sign *f;
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa;
+ SK *sk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ ds = (XDigestState*)f->state;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(sk->x.owner), f->exp);
+ if(strcmp(string2c(f->ha), "sha") == 0 || strcmp(string2c(f->ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(f->ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(f->ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), f->exp, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+ mpfree(b);
+}
+
+void
+Keyring_signm(void *fp)
+{
+ F_Keyring_signm *f;
+ Certificate *c;
+ mpint *b;
+ SigAlg *sa;
+ SK *sk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ sk = checkSK(f->sk);
+ sa = checkSigAlg(sk->x.sa);
+
+ if(f->m == H)
+ return;
+ b = checkIPint(f->m);
+
+ /* sign */
+ c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), 0, 1);
+ *f->ret = (Keyring_Certificate*)c;
+ release();
+ c->signa = (*sa->vec->sign)(b, sk->key);
+ acquire();
+}
+
+static int
+verify(PK *pk, Certificate *c, char *a, int len)
+{
+ mpint *b;
+ int n;
+ SigAlg *sa, *pksa;
+ DigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ sa = checkSigAlg(c->x.sa);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return 0;
+
+ /* add signer name and expiration time to hash */
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return 0;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ ds = sha1((uchar*)a, len, 0, 0);
+ sha1((uchar*)buf, n, digest, ds);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ ds = md5((uchar*)a, len, 0, 0);
+ md5((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ ds = md4((uchar*)a, len, 0, 0);
+ md4((uchar*)buf, n, digest, ds);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return 0;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return 0;
+ /* verify */
+ release();
+ n = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+ return n;
+}
+
+void
+Keyring_verify(void *fp)
+{
+ F_Keyring_verify *f;
+ Certificate *c;
+ mpint *b;
+ int n;
+ SigAlg *sa, *pksa;
+ PK *pk;
+ XDigestState *ds;
+ uchar digest[SHA1dlen];
+ char *buf;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ /* add signer name and expiration time to hash */
+ if(f->state == H)
+ return;
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+ n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+ ds = (XDigestState*)f->state;
+
+ if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+ sha1((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_SHA1dlen;
+ } else if(strcmp(string2c(c->x.ha), "md5") == 0){
+ md5((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else if(strcmp(string2c(c->x.ha), "md4") == 0){
+ md4((uchar*)buf, n, digest, &ds->state);
+ n = Keyring_MD5dlen;
+ } else {
+ free(buf);
+ return;
+ }
+ free(buf);
+
+ /* turn message into a big integer */
+ b = betomp(digest, n, nil);
+ if(b == nil)
+ return;
+
+ /* verify */
+ release();
+ *f->ret = (*sa->vec->verify)(b, c->signa, pk->key);
+ acquire();
+
+ mpfree(b);
+}
+
+void
+Keyring_verifym(void *fp)
+{
+ F_Keyring_verifym *f;
+ Certificate *c;
+ SigAlg *sa, *pksa;
+ PK *pk;
+
+ f = fp;
+ *f->ret = 0;
+
+ c = checkCertificate(f->cert);
+ sa = checkSigAlg(c->x.sa);
+ pk = checkPK(f->pk);
+ pksa = checkSigAlg(pk->x.sa);
+ if(sa->vec != pksa->vec)
+ return;
+
+ if(f->m == H)
+ return;
+
+ release();
+ *f->ret = (*sa->vec->verify)(checkIPint(f->m), c->signa, pk->key);
+ acquire();
+}
+
+/*
+ * digests
+ */
+void
+Keyring_DigestState_copy(void *fp)
+{
+ F_DigestState_copy *f;
+ Heap *h;
+ XDigestState *ds, *ods;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->d != H){
+ ods = checktype(f->d, TDigestState, "DigestState", 0);
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memmove(&ds->state, &ods->state, sizeof(ds->state));
+ *f->ret = (Keyring_DigestState*)ds;
+ }
+}
+
+static Keyring_DigestState*
+keyring_digest_x(Array *buf, int n, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cbuf, *cdigest;
+
+ if(buf != H){
+ if(n > buf->len)
+ n = buf->len;
+ cbuf = buf->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cbuf = nil;
+ }
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cbuf, n, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_sha1(void *fp)
+{
+ F_Keyring_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Keyring_sha224(void *fp)
+{
+ F_Keyring_sha224 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Keyring_sha256(void *fp)
+{
+ F_Keyring_sha256 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Keyring_sha384(void *fp)
+{
+ F_Keyring_sha384 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Keyring_sha512(void *fp)
+{
+ F_Keyring_sha512 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Keyring_md5(void *fp)
+{
+ F_Keyring_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Keyring_md4(void *fp)
+{
+ F_Keyring_md4 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ *f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Keyring_DigestState*
+keyring_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+ Heap *h;
+ XDigestState *ds;
+ uchar *cdata, *cdigest;
+
+ if(data != H){
+ if(n > data->len)
+ n = data->len;
+ cdata = data->data;
+ }else{
+ if(n != 0)
+ error(exInval);
+ cdata = nil;
+ }
+
+ if(key == H || key->len > 64)
+ error(exBadKey);
+
+ if(digest != H){
+ if(digest->len < dlen)
+ error(exBadDigest);
+ cdigest = digest->data;
+ } else
+ cdigest = nil;
+
+ if(state == H){
+ h = heap(TDigestState);
+ ds = H2D(XDigestState*, h);
+ memset(&ds->state, 0, sizeof(ds->state));
+ } else
+ ds = checktype(state, TDigestState, "DigestState", 1);
+
+ (*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+ return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_hmac_sha1(void *fp)
+{
+ F_Keyring_hmac_sha1 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Keyring_hmac_md5(void *fp)
+{
+ F_Keyring_hmac_md5 *f;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ *f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Keyring_dhparams(void *fp)
+{
+ F_Keyring_dhparams *f;
+ mpint *p, *alpha;
+ void *v;
+
+ f = fp;
+ v = f->ret->t0;
+ f->ret->t0 = H;
+ destroy(v);
+ v = f->ret->t1;
+ f->ret->t1 = H;
+ destroy(v);
+
+ p = mpnew(0);
+ alpha = mpnew(0);
+ release();
+ if(f->nbits == 1024)
+ DSAprimes(alpha, p, nil);
+ else
+ gensafeprime(p, alpha, f->nbits, 0);
+ acquire();
+ f->ret->t0 = newIPint(alpha);
+ f->ret->t1 = newIPint(p);
+}
+
+static int
+sendmsg(int fd, void *buf, int n)
+{
+ char num[10];
+
+ release();
+ snprint(num, sizeof(num), "%4.4d\n", n);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ n = kwrite(fd, buf, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_sendmsg(void *fp)
+{
+ F_Keyring_sendmsg *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->buf == H || f->n < 0)
+ return;
+ n = f->n;
+ if(n < 0 || n > f->buf->len)
+ error(exBounds);
+ *f->ret = sendmsg(f->fd->fd, f->buf->data, n);
+}
+
+static int
+senderr(int fd, char *err, int addrmt)
+{
+ char num[10];
+ int n, m;
+
+ release();
+ n = strlen(err);
+ m = 0;
+ if(addrmt)
+ m = strlen("remote: ");
+ snprint(num, sizeof(num), "!%3.3d\n", n+m);
+ if(kwrite(fd, num, 5) != 5){
+ acquire();
+ return -1;
+ }
+ if(addrmt)
+ kwrite(fd, "remote: ", m);
+ n = kwrite(fd, err, n);
+ acquire();
+ return n;
+}
+
+void
+Keyring_senderrmsg(void *fp)
+{
+ F_Keyring_senderrmsg *f;
+ char *s;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H)
+ return;
+ s = string2c(f->s);
+ if(senderr(f->fd->fd, s, 0) > 0)
+ *f->ret = 0;
+}
+
+static int
+nreadn(int fd, void *av, int n)
+{
+
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = kread(fd, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
+
+#define MSG "input or format error"
+
+static void
+getmsgerr(char *buf, int n, int r)
+{
+ char *e;
+ int l;
+
+ e = r>0? MSG: "hungup";
+ l = strlen(e)+1;
+ if(n > l)
+ n = l;
+ memmove(buf, e, n-1);
+ buf[n-1] = 0;
+}
+
+static int
+getmsg(int fd, char *buf, int n)
+{
+ char num[6];
+ int len, r;
+
+ release();
+ if((r = nreadn(fd, num, 5)) != 5){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+ num[5] = 0;
+
+ if(num[0] == '!')
+ len = strtoul(num+1, 0, 10);
+ else
+ len = strtoul(num, 0, 10);
+
+ r = -1;
+ if(len < 0 || len >= n || (r = nreadn(fd, buf, len)) != len){
+ getmsgerr(buf, n, r);
+ acquire();
+ return -1;
+ }
+
+ buf[len] = 0;
+ acquire();
+ if(num[0] == '!')
+ return -len;
+
+ return len;
+}
+
+void
+Keyring_getmsg(void *fp)
+{
+ F_Keyring_getmsg *f;
+ char *buf;
+ int n;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ if(f->fd == H){
+ kwerrstr("nil fd");
+ return;
+ }
+
+ buf = malloc(Maxmsg);
+ if(buf == nil){
+ kwerrstr(exNomem);
+ return;
+ }
+
+ n = getmsg(f->fd->fd, buf, Maxmsg);
+ if(n < 0){
+ kwerrstr("%s", buf);
+ free(buf);
+ return;
+ }
+
+ *f->ret = mem2array(buf, n);
+ free(buf);
+}
+
+void
+Keyring_auth(void *fp)
+{
+ F_Keyring_auth *f;
+ mpint *r0, *r1, *p, *alpha, *alphar0, *alphar1, *alphar0r1;
+ SK *mysk;
+ PK *mypk, *spk, *hispk;
+ Certificate *cert, *hiscert, *alphacert;
+ char *buf, *err;
+ uchar *cvb;
+ int n, fd, version;
+ long now;
+
+ hispk = H;
+ hiscert = H;
+ alphacert = H;
+ err = nil;
+
+ /* null out the return values */
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ r0 = r1 = alphar0 = alphar1 = alphar0r1 = nil;
+
+ /* check args */
+ if(f->fd == H || f->fd->fd < 0){
+ retstr("bad fd", &f->ret->t0);
+ return;
+ }
+ fd = f->fd->fd;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil){
+ retstr(exNomem, &f->ret->t0);
+ return;
+ }
+
+ /* send auth protocol version number */
+ if(sendmsg(fd, "1", 1) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get auth protocol version number */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ version = atoi(buf);
+ if(version != 1 || n > 4){
+ err = "incompatible authentication protocol";
+ goto out;
+ }
+
+ if(f->info == H){
+ err = "no authentication information";
+ goto out;
+ }
+ if(f->info->p == H){
+ err = "missing diffie hellman mod";
+ goto out;
+ }
+ if(f->info->alpha == H){
+ err = "missing diffie hellman base";
+ goto out;
+ }
+ mysk = checkSK(f->info->mysk);
+ if(mysk == H){
+ err = "bad sk arg";
+ goto out;
+ }
+ mypk = checkPK(f->info->mypk);
+ if(mypk == H){
+ err = "bad pk arg";
+ goto out;
+ }
+ cert = checkCertificate(f->info->cert);
+ if(cert == H){
+ err = "bad certificate arg";
+ goto out;
+ }
+ spk = checkPK(f->info->spk);
+ if(spk == H){
+ err = "bad signer key arg";
+ goto out;
+ }
+
+ /* get alpha and p */
+ p = checkIPint(f->info->p);
+ alpha = checkIPint(f->info->alpha);
+
+ if(p->sign == -1) {
+ err = "-ve modulus";
+ goto out;
+ }
+
+ r0 = mpnew(0);
+ r1 = mpnew(0);
+ alphar0 = mpnew(0);
+ alphar0r1 = mpnew(0);
+
+ /* generate alpha**r0 */
+if(0)print("X");
+ release();
+ mprand(mpsignif(p), genrandom, r0);
+ mpexp(alpha, r0, p, alphar0);
+ acquire();
+if(0)print("Y");
+
+ /* send alpha**r0 mod p, mycert, and mypk */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = certtostr(cert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ n = pktostr(mypk, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+
+ /* get alpha**r1 mod p, hiscert, hispk */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphar1 = strtomp(buf, nil, 64, nil);
+
+ /* trying a fast one */
+ if(mpcmp(p, alphar1) <= 0){
+ err = "implausible parameter value";
+ goto out;
+ }
+
+ /* if alpha**r1 == alpha**r0, someone may be trying a replay */
+ if(mpcmp(alphar0, alphar1) == 0){
+ err = "possible replay attack";
+ goto out;
+ }
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hiscert = strtocert(buf);
+ if(hiscert == H){
+ err = "bad certificate syntax";
+ goto out;
+ }
+ certimmutable(hiscert); /* hide from the garbage collector */
+
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ hispk = strtopk(buf);
+ if(hispk == H){
+ err = "bad public key";
+ goto out;
+ }
+ pkimmutable(hispk); /* hide from the garbage collector */
+
+ /* verify his public key */
+ if(verify(spk, hiscert, buf, n) == 0){
+ err = "pk doesn't match certificate";
+ goto out;
+ }
+
+ /* check expiration date - in seconds of epoch */
+
+ now = osusectime()/1000000;
+ if(hiscert->x.exp != 0 && hiscert->x.exp <= now){
+ err = "certificate expired";
+ goto out;
+ }
+
+ /* sign alpha**r0 and alpha**r1 and send */
+ n = bigtobase64(alphar0, buf, Maxbuf);
+ n += bigtobase64(alphar1, buf+n, Maxbuf-n);
+ alphacert = sign(mysk, "sha1", 0, (uchar*)buf, n);
+ n = certtostr(alphacert, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0){
+ err = MSG;
+ goto out;
+ }
+ certmutable(alphacert);
+ destroy(alphacert);
+ alphacert = H;
+
+ /* get signature of alpha**r1 and alpha**r0 and verify */
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ err = buf;
+ goto out;
+ }
+ buf[n] = 0;
+ alphacert = strtocert(buf);
+ if(alphacert == H){
+ err = "alpha**r1 doesn't match certificate";
+ goto out;
+ }
+ certimmutable(alphacert); /* hide from the garbage collector */
+ n = bigtobase64(alphar1, buf, Maxbuf);
+ n += bigtobase64(alphar0, buf+n, Maxbuf-n);
+ if(verify(hispk, alphacert, buf, n) == 0){
+ err = "bad certificate";
+ goto out;
+ }
+
+ /* we are now authenticated and have a common secret, alpha**(r0*r1) */
+ f->ret->t0 = stringdup(hispk->x.owner);
+ mpexp(alphar1, r0, p, alphar0r1);
+ n = mptobe(alphar0r1, nil, Maxbuf, &cvb);
+ if(n < 0){
+ err = "bad conversion";
+ goto out;
+ }
+ f->ret->t1 = mem2array(cvb, n);
+ free(cvb);
+
+out:
+ /* return status */
+ if(f->ret->t0 == H){
+ if(err == buf)
+ senderr(fd, "missing your authentication data", 1);
+ else
+ senderr(fd, err, 1);
+ }else
+ sendmsg(fd, "OK", 2);
+
+ /* read responses */
+ if(err != buf){
+ for(;;){
+ n = getmsg(fd, buf, Maxbuf-1);
+ if(n < 0){
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+ if(err == nil){
+ if(n < -1)
+ err = buf;
+ else
+ err = MSG;
+ }
+ break;
+ }
+ if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
+ break;
+ }
+ }
+
+ /* set error and id to nobody */
+ if(f->ret->t0 == H){
+ if(err == nil)
+ err = MSG;
+ retstr(err, &f->ret->t0);
+ if(f->setid)
+ setid("nobody", 1);
+ } else {
+ /* change user id */
+ if(f->setid)
+ setid(string2c(f->ret->t0), 1);
+ }
+
+ /* free resources */
+ if(hispk != H){
+ pkmutable(hispk);
+ destroy(hispk);
+ }
+ if(hiscert != H){
+ certmutable(hiscert);
+ destroy(hiscert);
+ }
+ if(alphacert != H){
+ certmutable(alphacert);
+ destroy(alphacert);
+ }
+ free(buf);
+ if(r0 != nil){
+ mpfree(r0);
+ mpfree(r1);
+ mpfree(alphar0);
+ mpfree(alphar1);
+ mpfree(alphar0r1);
+ }
+}
+
+static Keyring_Authinfo*
+newAuthinfo(void)
+{
+ return H2D(Keyring_Authinfo*, heap(TAuthinfo));
+}
+
+void
+Keyring_writeauthinfo(void *fp)
+{
+ F_Keyring_writeauthinfo *f;
+ int n, fd;
+ char *buf;
+ PK *spk;
+ SK *mysk;
+ Certificate *c;
+ mpint *p, *alpha;
+
+ f = fp;
+ *f->ret = -1;
+
+ if(f->filename == H)
+ error(exNilref);
+ if(f->info == H)
+ error(exNilref);
+ alpha = checkIPint(f->info->alpha);
+ p = checkIPint(f->info->p);
+ spk = checkPK(f->info->spk);
+ mysk = checkSK(f->info->mysk);
+ c = checkCertificate(f->info->cert);
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ /*
+ * The file may already exist or be a file2chan file so first
+ * try opening with truncation since create will change the
+ * permissions of the file and create doesn't work with a
+ * file2chan.
+ */
+ release();
+ fd = kopen(string2c(f->filename), OTRUNC|OWRITE);
+ if(fd < 0)
+ fd = kcreate(string2c(f->filename), OWRITE, 0600);
+ if(fd < 0)
+ fd = kopen(string2c(f->filename), OWRITE);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = pktostr(spk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* certificate for my public key */
+ n = certtostr(c, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* my secret/public key */
+ n = sktostr(mysk, buf, Maxmsg);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman base */
+ n = bigtobase64(alpha, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ /* diffie hellman modulus */
+ n = bigtobase64(p, buf, Maxbuf);
+ if(sendmsg(fd, buf, n) <= 0)
+ goto out;
+
+ *f->ret = 0;
+out:
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ }
+}
+
+void
+Keyring_readauthinfo(void *fp)
+{
+ F_Keyring_readauthinfo *f;
+ int fd;
+ char *buf;
+ int n, ok;
+ PK *mypk;
+ SK *mysk;
+ SigAlg *sa;
+ Keyring_Authinfo *ai;
+ mpint *b;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ ok = 0;
+
+ if(f->filename == H)
+ return;
+
+ buf = malloc(Maxbuf);
+ if(buf == nil)
+ return;
+
+ ai = newAuthinfo();
+ *f->ret = ai;
+
+ release();
+ fd = kopen(string2c(f->filename), OREAD);
+ acquire();
+ if(fd < 0)
+ goto out;
+
+ /* signer's public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+
+ ai->spk = (Keyring_PK*)strtopk(buf);
+ if(ai->spk == H)
+ goto out;
+
+ /* certificate for my public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ ai->cert = (Keyring_Certificate*)strtocert(buf);
+ if(ai->cert == H)
+ goto out;
+
+ /* my secret/public key */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ mysk = strtosk(buf);
+ ai->mysk = (Keyring_SK*)mysk;
+ if(mysk == H)
+ goto out;
+ sa = checkSigAlg(mysk->x.sa);
+ mypk = newPK(sa, stringdup(mysk->x.owner), 1);
+ mypk->key = (*sa->vec->sk2pk)(mysk->key);
+ ai->mypk = (Keyring_PK*)mypk;
+
+ /* diffie hellman base */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->alpha = newIPint(b);
+
+ /* diffie hellman modulus */
+ n = getmsg(fd, buf, Maxmsg);
+ if(n < 0)
+ goto out;
+ b = strtomp(buf, nil, 64, nil);
+ ai->p = newIPint(b);
+ ok = 1;
+out:
+ if(!ok){
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+ }
+ free(buf);
+ if(fd >= 0){
+ release();
+ kclose(fd);
+ acquire();
+ kwerrstr("%q: %s", string2c(f->filename), MSG);
+ }
+}
+
+void
+keyringmodinit(void)
+{
+ SigAlgVec *sav;
+ extern SigAlgVec* elgamalinit(void);
+ extern SigAlgVec* rsainit(void);
+ extern SigAlgVec* dsainit(void);
+
+ ipintsmodinit(); /* in case only Keyring is configured */
+ TSigAlg = dtype(freeSigAlg, sizeof(SigAlg), SigAlgmap, sizeof(SigAlgmap));
+ TSK = dtype(freeSK, sizeof(SK), SKmap, sizeof(SKmap));
+ TPK = dtype(freePK, sizeof(PK), PKmap, sizeof(PKmap));
+ TCertificate = dtype(freeCertificate, sizeof(Certificate), Certificatemap,
+ sizeof(Certificatemap));
+ TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap,
+ sizeof(DigestStatemap));
+ TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap,
+ sizeof(AESstatemap));
+ TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap,
+ sizeof(DESstatemap));
+ TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap,
+ sizeof(IDEAstatemap));
+ TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap,
+ sizeof(BFstatemap));
+ TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap,
+ sizeof(RC4statemap));
+ TAuthinfo = dtype(freeheap, sizeof(Keyring_Authinfo), Authinfomap, sizeof(Authinfomap));
+ TDSAsk = dtype(freeheap, sizeof(Keyring_DSAsk), DSAskmap, sizeof(DSAskmap));
+ TDSApk = dtype(freeheap, sizeof(Keyring_DSApk), DSApkmap, sizeof(DSApkmap));
+ TDSAsig = dtype(freeheap, sizeof(Keyring_DSAsig), DSAsigmap, sizeof(DSAsigmap));
+ TEGsk = dtype(freeheap, sizeof(Keyring_EGsk), EGskmap, sizeof(EGskmap));
+ TEGpk = dtype(freeheap, sizeof(Keyring_EGpk), EGpkmap, sizeof(EGpkmap));
+ TEGsig = dtype(freeheap, sizeof(Keyring_EGsig), EGsigmap, sizeof(EGsigmap));
+ TRSAsk = dtype(freeheap, sizeof(Keyring_RSAsk), RSAskmap, sizeof(RSAskmap));
+ TRSApk = dtype(freeheap, sizeof(Keyring_RSApk), RSApkmap, sizeof(RSApkmap));
+ TRSAsig = dtype(freeheap, sizeof(Keyring_RSAsig), RSAsigmap, sizeof(RSAsigmap));
+
+ if((sav = elgamalinit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = rsainit()) != nil)
+ algs[nalg++] = sav;
+ if((sav = dsainit()) != nil)
+ algs[nalg++] = sav;
+
+ fmtinstall('U', big64conv);
+ builtinmod("$Keyring", Keyringmodtab, Keyringmodlen);
+}
+
+/*
+ * IO on a delimited channel. A message starting with 0x00 is a normal
+ * message. One starting with 0xff is an error string.
+ *
+ * return negative number for error messages (including hangup)
+ */
+static int
+getbuf(int fd, uchar *buf, int n, char *err, int nerr)
+{
+ int len;
+
+ release();
+ len = kread(fd, buf, n);
+ acquire();
+ if(len <= 0){
+ strncpy(err, "hungup", nerr);
+ buf[nerr-1] = 0;
+ return -1;
+ }
+ if(buf[0] == 0)
+ return len-1;
+ if(buf[0] != 0xff){
+ /*
+ * this happens when the client's password is wrong: both sides use a digest of the
+ * password as a crypt key for devssl. When they don't match decryption garbles
+ * messages
+ */
+ strncpy(err, "failure", nerr);
+ err[nerr-1] = 0;
+ return -1;
+ }
+
+ /* error string */
+ len--;
+ if(len < 1){
+ strncpy(err, "unknown", nerr);
+ err[nerr-1] = 0;
+ } else {
+ if(len >= nerr)
+ len = nerr-1;
+ memmove(err, buf+1, len);
+ err[len] = 0;
+ }
+ return -1;
+}
+
+void
+Keyring_getstring(void *fp)
+{
+ F_Keyring_getstring *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ retnstr(((char*)buf)+1, n, &f->ret->t0);
+
+ free(buf);
+}
+
+void
+Keyring_getbytearray(void *fp)
+{
+ F_Keyring_getbytearray *f;
+ uchar *buf;
+ char err[64];
+ int n;
+
+ f = fp;
+ destroy(f->ret->t0);
+ f->ret->t0 = H;
+ destroy(f->ret->t1);
+ f->ret->t1 = H;
+
+ if(f->fd == H)
+ return;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return;
+
+ n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+ if(n < 0)
+ retnstr(err, strlen(err), &f->ret->t1);
+ else
+ f->ret->t0 = mem2array(buf+1, n);
+
+ free(buf);
+}
+
+static int
+putbuf(int fd, void *p, int n)
+{
+ char *buf;
+
+ buf = malloc(Maxmsg);
+ if(buf == nil)
+ return -1;
+
+ release();
+ buf[0] = 0;
+ if(n < 0){
+ buf[0] = 0xff;
+ n = -n;
+ }
+ if(n >= Maxmsg)
+ n = Maxmsg - 1;
+ memmove(buf+1, p, n);
+ n = kwrite(fd, buf, n+1);
+ acquire();
+
+ free(buf);
+ return n;
+}
+
+void
+Keyring_putstring(void *fp)
+{
+ F_Keyring_putstring *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), strlen(string2c(f->s)));
+}
+
+void
+Keyring_puterror(void *fp)
+{
+ F_Keyring_puterror *f;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->s == H)
+ return;
+ *f->ret = putbuf(f->fd->fd, string2c(f->s), -strlen(string2c(f->s)));
+}
+
+void
+Keyring_putbytearray(void *fp)
+{
+ F_Keyring_putbytearray *f;
+ int n;
+
+ f = fp;
+ *f->ret = -1;
+ if(f->fd == H || f->a == H)
+ return;
+ n = f->n;
+ if(n < 0 || n > f->a->len)
+ error(exBounds);
+ *f->ret = putbuf(f->fd->fd, f->a->data, n);
+}
+
+void
+Keyring_dessetup(void *fp)
+{
+ F_Keyring_dessetup *f;
+ Heap *h;
+ XDESstate *ds;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len < 8)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TDESstate);
+ ds = H2D(XDESstate*, h);
+ setupDESstate(&ds->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_DESstate*)ds;
+}
+
+void
+Keyring_desecb(void *fp)
+{
+ F_Keyring_desecb *f;
+ XDESstate *ds;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Keyring_descbc(void *fp)
+{
+ F_Keyring_descbc *f;
+ XDESstate *ds;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ ds = checktype(f->state, TDESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ block_cipher(ds->state.expanded, p, 0);
+ memmove(ds->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ block_cipher(ds->state.expanded, p, 1);
+ p2 = tmp;
+ ip = ds->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_ideasetup(void *fp)
+{
+ F_Keyring_ideasetup *f;
+ Heap *h;
+ XIDEAstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len < 16)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < 8)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TIDEAstate);
+ is = H2D(XIDEAstate*, h);
+
+ setupIDEAstate(&is->state, f->key->data, ivec);
+
+ *f->ret = (Keyring_IDEAstate*)is;
+}
+
+void
+Keyring_ideaecb(void *fp)
+{
+ F_Keyring_ideaecb *f;
+ XIDEAstate *is;
+ int i;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ for(i = 8; i <= f->n; i += 8, p += 8)
+ idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Keyring_ideacbc(void *fp)
+{
+ F_Keyring_ideacbc *f;
+ XIDEAstate *is;
+ uchar *p, *ep, *ip, *p2, *eip;
+ uchar tmp[8];
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TIDEAstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0){
+ for(ep = p + f->n; p < ep; p += 8){
+ p2 = p;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; )
+ *p2++ ^= *ip++;
+ idea_cipher(is->state.edkey, p, 0);
+ memmove(is->state.ivec, p, 8);
+ }
+ } else {
+ for(ep = p + f->n; p < ep; ){
+ memmove(tmp, p, 8);
+ idea_cipher(is->state.edkey, p, 1);
+ p2 = tmp;
+ ip = is->state.ivec;
+ for(eip = ip+8; ip < eip; ){
+ *p++ ^= *ip;
+ *ip++ = *p2++;
+ }
+ }
+ }
+}
+
+void
+Keyring_aessetup(void *fp)
+{
+ F_Keyring_aessetup *f;
+ Heap *h;
+ XAESstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H ||
+ f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len < AESbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TAESstate);
+ is = H2D(XAESstate*, h);
+
+ setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Keyring_AESstate*)is;
+}
+
+void
+Keyring_aescbc(void *fp)
+{
+ F_Keyring_aescbc *f;
+ XAESstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+
+ is = checktype(f->state, TAESstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ aesCBCencrypt(p, f->n, &is->state);
+ else
+ aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_blowfishsetup(void *fp)
+{
+ F_Keyring_blowfishsetup *f;
+ Heap *h;
+ XBFstate *is;
+ uchar *ivec;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->key == H || f->key->len <= 0)
+ error(exBadKey);
+ if(f->ivec != H){
+ if(f->ivec->len != BFbsize)
+ error(exBadIvec);
+ ivec = f->ivec->data;
+ }else
+ ivec = nil;
+
+ h = heap(TBFstate);
+ is = H2D(XBFstate*, h);
+
+ setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+ *f->ret = (Keyring_BFstate*)is;
+}
+
+void
+Keyring_blowfishcbc(void *fp)
+{
+ F_Keyring_blowfishcbc *f;
+ XBFstate *is;
+ uchar *p;
+
+ f = fp;
+
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ if(f->n & 7)
+ error(exBadBsize);
+
+ is = checktype(f->state, TBFstate, exBadState, 0);
+ p = f->buf->data;
+
+ if(f->direction == 0)
+ bfCBCencrypt(p, f->n, &is->state);
+ else
+ bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_rc4setup(void *fp)
+{
+ F_Keyring_rc4setup *f;
+ Heap *h;
+ XRC4state *is;
+ void *r;
+
+ f = fp;
+ r = *f->ret;
+ *f->ret = H;
+ destroy(r);
+
+ if(f->seed == H)
+ return;
+
+ h = heap(TRC4state);
+ is = H2D(XRC4state*, h);
+
+ setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+ *f->ret = (Keyring_RC4state*)is;
+}
+
+void
+Keyring_rc4(void *fp)
+{
+ F_Keyring_rc4 *f;
+ XRC4state *is;
+ uchar *p;
+
+ f = fp;
+ if(f->buf == H)
+ return;
+ if(f->n < 0 || f->n > f->buf->len)
+ error(exBounds);
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ p = f->buf->data;
+ rc4(&is->state, p, f->n);
+}
+
+void
+Keyring_rc4skip(void *fp)
+{
+ F_Keyring_rc4skip *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4skip(&is->state, f->n);
+}
+
+void
+Keyring_rc4back(void *fp)
+{
+ F_Keyring_rc4back *f;
+ XRC4state *is;
+
+ f = fp;
+ is = checktype(f->state, TRC4state, exBadState, 0);
+ rc4back(&is->state, f->n);
+}
+
+/*
+ * public/secret keys, signing and verifying
+ */
+
+static void
+dsapk2pub(DSApub* p, Keyring_DSApk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ p->p = checkIPint(pk->p);
+ p->q = checkIPint(pk->q);
+ p->alpha = checkIPint(pk->alpha);
+ p->key = checkIPint(pk->key);
+}
+
+static void
+dsask2priv(DSApriv* p, Keyring_DSAsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ dsapk2pub(&p->pub, sk->pk);
+ p->secret = checkIPint(sk->secret);
+}
+
+static void
+dsapriv2sk(Keyring_DSAsk* sk, DSApriv* p)
+{
+ Keyring_DSApk* pk;
+
+ pk = sk->pk;
+ pk->p = ipcopymp(p->pub.p);
+ pk->q = ipcopymp(p->pub.q);
+ pk->alpha = ipcopymp(p->pub.alpha);
+ pk->key = ipcopymp(p->pub.key);
+ sk->secret = ipcopymp(p->secret);
+}
+
+void
+DSAsk_gen(void *fp)
+{
+ F_DSAsk_gen *f;
+ Keyring_DSAsk *sk;
+ DSApriv *p;
+ DSApub pub, *oldpk;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TDSAsk, 0);
+ sk->pk = newthing(TDSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ oldpk = nil;
+ if(f->oldpk != H){
+ dsapk2pub(&pub, f->oldpk);
+ oldpk = &pub;
+ }
+ release();
+ p = dsagen(oldpk);
+ acquire();
+ dsapriv2sk(sk, p);
+ dsaprivfree(p);
+}
+
+void
+DSAsk_sign(void *fp)
+{
+ F_DSAsk_sign *f;
+ Keyring_DSAsig *sig;
+ DSApriv p;
+ mpint *m;
+ DSAsig *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TDSAsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ dsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = dsasign(&p, m);
+ acquire();
+ sig->r = ipcopymp(s->r);
+ sig->s = ipcopymp(s->s);
+ dsasigfree(s);
+}
+
+void
+DSApk_verify(void *fp)
+{
+ F_DSApk_verify *f;
+ DSApub p;
+ DSAsig sig;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ dsapk2pub(&p, f->k);
+ sig.r = checkIPint(f->sig->r);
+ sig.s = checkIPint(f->sig->s);
+ m = checkIPint(f->m);
+ release();
+ *f->ret = dsaverify(&p, &sig, m) == 0;
+ acquire();
+}
+
+static void
+egpk2pub(EGpub* p, Keyring_EGpk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ p->p = checkIPint(pk->p);
+ p->alpha = checkIPint(pk->alpha);
+ p->key = checkIPint(pk->key);
+}
+
+static void
+egsk2priv(EGpriv* p, Keyring_EGsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ egpk2pub(&p->pub, sk->pk);
+ p->secret = checkIPint(sk->secret);
+}
+
+static void
+egpriv2sk(Keyring_EGsk* sk, EGpriv* p)
+{
+ Keyring_EGpk* pk;
+
+ pk = sk->pk;
+ pk->p = ipcopymp(p->pub.p);
+ pk->alpha = ipcopymp(p->pub.alpha);
+ pk->key = ipcopymp(p->pub.key);
+ sk->secret = ipcopymp(p->secret);
+}
+
+void
+EGsk_gen(void *fp)
+{
+ F_EGsk_gen *f;
+ Keyring_EGsk *sk;
+ EGpriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TEGsk, 0);
+ sk->pk = newthing(TEGpk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ for(;;){
+ p = eggen(f->nlen, f->nrep);
+ if(mpsignif(p->pub.p) == f->nlen)
+ break;
+ egprivfree(p);
+ }
+ acquire();
+ egpriv2sk(sk, p);
+ egprivfree(p);
+}
+
+void
+EGsk_sign(void *fp)
+{
+ F_EGsk_sign *f;
+ Keyring_EGsig *sig;
+ EGpriv p;
+ mpint *m;
+ EGsig *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TEGsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ egsk2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = egsign(&p, m);
+ acquire();
+ sig->r = ipcopymp(s->r);
+ sig->s = ipcopymp(s->s);
+ egsigfree(s);
+}
+
+void
+EGpk_verify(void *fp)
+{
+ F_EGpk_verify *f;
+ EGpub p;
+ EGsig sig;
+ mpint *m;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ egpk2pub(&p, f->k);
+ sig.r = checkIPint(f->sig->r);
+ sig.s = checkIPint(f->sig->s);
+ m = checkIPint(f->m);
+ release();
+ *f->ret = egverify(&p, &sig, m) == 0;
+ acquire();
+}
+
+static void
+rsapk2pub(RSApub* p, Keyring_RSApk* pk)
+{
+ if(pk == H)
+ error(exNilref);
+ memset(p, 0, sizeof(*p));
+ p->n = checkIPint(pk->n);
+ p->ek = checkIPint(pk->ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Keyring_RSAsk* sk)
+{
+ if(sk == H || sk->pk == H)
+ error(exNilref);
+ rsapk2pub(&p->pub, sk->pk);
+ p->dk = checkIPint(sk->dk);
+ p->p = checkIPint(sk->p);
+ p->q = checkIPint(sk->q);
+ p->kp = checkIPint(sk->kp);
+ p->kq = checkIPint(sk->kq);
+ p->c2 = checkIPint(sk->c2);
+}
+
+static void
+rsapriv2sk(Keyring_RSAsk* sk, RSApriv* p)
+{
+ Keyring_RSApk* pk;
+
+ pk = sk->pk;
+ pk->n = ipcopymp(p->pub.n);
+ pk->ek = ipcopymp(p->pub.ek);
+ sk->dk = ipcopymp(p->dk);
+ sk->p = ipcopymp(p->p);
+ sk->q = ipcopymp(p->q);
+ sk->kp = ipcopymp(p->kp);
+ sk->kq = ipcopymp(p->kq);
+ sk->c2 = ipcopymp(p->c2);
+}
+
+void
+RSApk_encrypt(void *fp)
+{
+ F_RSApk_encrypt *f;
+ RSApub p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsapk2pub(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ o = rsaencrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+RSAsk_gen(void *fp)
+{
+ F_RSAsk_gen *f;
+ Keyring_RSAsk *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TRSAsk, 0);
+ sk->pk = newthing(TRSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ for(;;){
+ p = rsagen(f->nlen, f->elen, f->nrep);
+ if(mpsignif(p->pub.n) == f->nlen)
+ break;
+ rsaprivfree(p);
+ }
+ acquire();
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+}
+
+void
+RSAsk_fill(void *fp)
+{
+ F_RSAsk_fill *f;
+ Keyring_RSAsk *sk;
+ RSApriv *p;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sk = newthing(TRSAsk, 0);
+ sk->pk = newthing(TRSApk, 0);
+ *f->ret = sk;
+ destroy(v);
+ release();
+ p = rsafill(checkIPint(f->n), checkIPint(f->e), checkIPint(f->d),
+ checkIPint(f->p), checkIPint(f->q));
+ acquire();
+ if(p == nil) {
+ *f->ret = H;
+ destroy(sk);
+ }else{
+ rsapriv2sk(sk, p);
+ rsaprivfree(p);
+ }
+}
+
+void
+RSAsk_decrypt(void *fp)
+{
+ F_RSAsk_decrypt *f;
+ RSApriv p;
+ mpint *m, *o;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ o = rsadecrypt(&p, m, nil);
+ acquire();
+ *f->ret = newIPint(o);
+}
+
+void
+RSAsk_sign(void *fp)
+{
+ F_RSAsk_sign *f;
+ Keyring_RSAsig *sig;
+ RSApriv p;
+ mpint *m, *s;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ sig = newthing(TRSAsig, 0);
+ *f->ret = sig;
+ destroy(v);
+
+ rsask2priv(&p, f->k);
+ m = checkIPint(f->m);
+ release();
+ s = rsadecrypt(&p, m, nil);
+ acquire();
+ sig->n = newIPint(s);
+}
+
+void
+RSApk_verify(void *fp)
+{
+ F_RSApk_verify *f;
+ RSApub p;
+ mpint *sig, *m, *t;
+
+ f = fp;
+ *f->ret = 0;
+ if(f->m == H || f->sig == H)
+ return;
+ rsapk2pub(&p, f->k);
+ sig = checkIPint(f->sig->n);
+ m = checkIPint(f->m);
+ release();
+ t = rsaencrypt(&p, sig, nil);
+ *f->ret = mpcmp(t, m) == 0;
+ mpfree(t);
+ acquire();
+}
+
+void
+Keyring_IPint_random(void *fp)
+{
+ F_IPint_random *f;
+ mpint *b;
+ void *v;
+
+ f = fp;
+ v = *f->ret;
+ *f->ret = H;
+ destroy(v);
+
+ release();
+ b = mprand(f->maxbits, genrandom, nil);
+ acquire();
+ *f->ret = newIPint(b);
+}