ref: 7a7dfee4fab3e9a725422edff93251ef0a717492
dir: /libinterp/keyring.c/
#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);
}