diff options
Diffstat (limited to 'src/cmd/auth/factotum/rsa.c')
-rw-r--r-- | src/cmd/auth/factotum/rsa.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/cmd/auth/factotum/rsa.c b/src/cmd/auth/factotum/rsa.c new file mode 100644 index 00000000..327dbc5b --- /dev/null +++ b/src/cmd/auth/factotum/rsa.c @@ -0,0 +1,191 @@ +#include "std.h" +#include "dat.h" + +/* + * RSA authentication. + * + * Client: + * start n=xxx ek=xxx + * write msg + * read decrypt(msg) + * + * Sign (PKCS #1 using hash=sha1 or hash=md5) + * start n=xxx ek=xxx + * write hash(msg) + * read signature(hash(msg)) + * + * all numbers are hexadecimal biginits parsable with strtomp. + * must be lower case for attribute matching in start. + */ + +static int +rsaclient(Conv *c) +{ + char *chal; + mpint *m; + Key *k; + + k = keylookup("%A", c->attr); + if(k == nil) + return -1; + c->state = "read challenge"; + if(convreadm(c, &chal) < 0){ + keyclose(k); + return -1; + } + if(strlen(chal) < 32){ + badchal: + free(chal); + convprint(c, "bad challenge"); + keyclose(k); + return -1; + } + m = strtomp(chal, nil, 16, nil); + if(m == nil) + goto badchal; + free(chal); + m = rsadecrypt(k->priv, m, m); + convprint(c, "%B", m); + mpfree(m); + keyclose(k); + return 0; +} + +static int +xrsasign(Conv *c) +{ + char *hash; + int dlen, n; + DigestAlg *hashfn; + Key *k; + uchar sig[1024], digest[64]; + + k = keylookup("%A", c->attr); + if(k == nil) + return -1; + hash = strfindattr(k->attr, "hash"); + if(hash == nil) + hash = "sha1"; + if(strcmp(hash, "sha1") == 0){ + hashfn = sha1; + dlen = SHA1dlen; + }else if(strcmp(hash, "md5") == 0){ + hashfn = md5; + dlen = MD5dlen; + }else{ + werrstr("unknown hash function %s", hash); + return -1; + } + c->state = "read data"; + if((n=convread(c, digest, dlen)) < 0){ + keyclose(k); + return -1; + } + memset(sig, 0xAA, sizeof sig); + n = rsasign(k->priv, hashfn, digest, dlen, sig, sizeof sig); + keyclose(k); + if(n < 0) + return -1; + convwrite(c, sig, n); + return 0; +} + +/* + * convert to canonical form (lower case) + * for use in attribute matches. + */ +static void +strlwr(char *a) +{ + for(; *a; a++){ + if('A' <= *a && *a <= 'Z') + *a += 'a' - 'A'; + } +} + +static RSApriv* +readrsapriv(Key *k) +{ + char *a; + RSApriv *priv; + + priv = rsaprivalloc(); + + if((a=strfindattr(k->attr, "ek"))==nil + || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->attr, "n"))==nil + || (priv->pub.n=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!p"))==nil + || (priv->p=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!q"))==nil + || (priv->q=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!kp"))==nil + || (priv->kp=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!kq"))==nil + || (priv->kq=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!c2"))==nil + || (priv->c2=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + if((a=strfindattr(k->privattr, "!dk"))==nil + || (priv->dk=strtomp(a, nil, 16, nil))==nil) + goto Error; + strlwr(a); + return priv; + +Error: + rsaprivfree(priv); + return nil; +} + +static int +rsacheck(Key *k) +{ + static int first = 1; + + if(first){ + fmtinstall('B', mpfmt); + first = 0; + } + + if((k->priv = readrsapriv(k)) == nil){ + werrstr("malformed key data"); + return -1; + } + return 0; +} + +static void +rsaclose(Key *k) +{ + rsaprivfree(k->priv); + k->priv = nil; +} + +static Role +rsaroles[] = +{ + "client", rsaclient, + "sign", xrsasign, + 0 +}; + +Proto rsa = { + "rsa", + rsaroles, + nil, + rsacheck, + rsaclose +}; |