aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/factotum/sshrsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/factotum/sshrsa.c')
-rw-r--r--src/cmd/factotum/sshrsa.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/cmd/factotum/sshrsa.c b/src/cmd/factotum/sshrsa.c
new file mode 100644
index 00000000..7227c855
--- /dev/null
+++ b/src/cmd/factotum/sshrsa.c
@@ -0,0 +1,172 @@
+/*
+ * SSH RSA authentication.
+ *
+ * Client protocol:
+ * read public key
+ * if you don't like it, read another, repeat
+ * write challenge
+ * read response
+ * all numbers are hexadecimal biginits parsable with strtomp.
+ */
+
+#include "dat.h"
+
+enum {
+ CHavePub,
+ CHaveResp,
+
+ Maxphase,
+};
+
+static char *phasenames[] = {
+[CHavePub] "CHavePub",
+[CHaveResp] "CHaveResp",
+};
+
+struct State
+{
+ RSApriv *priv;
+ mpint *resp;
+ int off;
+ Key *key;
+};
+
+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;
+ if((a=strfindattr(k->attr, "n"))==nil || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!p"))==nil || (priv->p=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!q"))==nil || (priv->q=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!kp"))==nil || (priv->kp=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!kq"))==nil || (priv->kq=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!c2"))==nil || (priv->c2=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ if((a=strfindattr(k->privattr, "!dk"))==nil || (priv->dk=strtomp(a, nil, 16, nil))==nil)
+ goto Error;
+ return priv;
+
+Error:
+ rsaprivfree(priv);
+ return nil;
+}
+
+static int
+sshrsainit(Proto*, Fsstate *fss)
+{
+ int iscli;
+ State *s;
+
+ if((iscli = isclient(strfindattr(fss->attr, "role"))) < 0)
+ return failure(fss, nil);
+ if(iscli==0)
+ return failure(fss, "sshrsa server unimplemented");
+
+ s = emalloc(sizeof *s);
+ fss->phasename = phasenames;
+ fss->maxphase = Maxphase;
+ fss->phase = CHavePub;
+ fss->ps = s;
+ return RpcOk;
+}
+
+static int
+sshrsaread(Fsstate *fss, void *va, uint *n)
+{
+ RSApriv *priv;
+ State *s;
+
+ s = fss->ps;
+ switch(fss->phase){
+ default:
+ return phaseerror(fss, "read");
+ case CHavePub:
+ if(s->key){
+ closekey(s->key);
+ s->key = nil;
+ }
+ if((s->key = findkey(fss, Kuser, nil, s->off, fss->attr, nil)) == nil)
+ return failure(fss, nil);
+ s->off++;
+ priv = s->key->priv;
+ *n = snprint(va, *n, "%B", priv->pub.n);
+ return RpcOk;
+ case CHaveResp:
+ *n = snprint(va, *n, "%B", s->resp);
+ fss->phase = Established;
+ return RpcOk;
+ }
+}
+
+static int
+sshrsawrite(Fsstate *fss, void *va, uint)
+{
+ mpint *m;
+ State *s;
+
+ s = fss->ps;
+ switch(fss->phase){
+ default:
+ return phaseerror(fss, "write");
+ case CHavePub:
+ if(s->key == nil)
+ return failure(fss, "no current key");
+ m = strtomp(va, nil, 16, nil);
+ m = rsadecrypt(s->key->priv, m, m);
+ s->resp = m;
+ fss->phase = CHaveResp;
+ return RpcOk;
+ }
+}
+
+static void
+sshrsaclose(Fsstate *fss)
+{
+ State *s;
+
+ s = fss->ps;
+ if(s->key)
+ closekey(s->key);
+ if(s->resp)
+ mpfree(s->resp);
+ free(s);
+}
+
+static int
+sshrsaaddkey(Key *k)
+{
+ fmtinstall('B', mpconv);
+
+ if((k->priv = readrsapriv(k)) == nil){
+ werrstr("malformed key data");
+ return -1;
+ }
+ return replacekey(k);
+}
+
+static void
+sshrsaclosekey(Key *k)
+{
+ rsaprivfree(k->priv);
+}
+
+Proto sshrsa = {
+.name= "sshrsa",
+.init= sshrsainit,
+.write= sshrsawrite,
+.read= sshrsaread,
+.close= sshrsaclose,
+.addkey= sshrsaaddkey,
+.closekey= sshrsaclosekey,
+};