* Re: [9front] obsolete cryptographic algorithms
2022-09-29 5:01 ` ori
@ 2022-09-29 6:17 ` unobe
2022-09-29 6:30 ` unobe
2022-09-29 8:53 ` hiro
1 sibling, 1 reply; 18+ messages in thread
From: unobe @ 2022-09-29 6:17 UTC (permalink / raw)
To: 9front
[-- Attachment #1: Type: text/plain, Size: 725 bytes --]
Quoth ori@eigenstate.org:
> Quoth hiro <23hiro@gmail.com>:
> > git history is a shitty way to organise rarely used files.
> >
>
> the belief here is that they're never used.
>
Please don't remove it.
I have a patch to ssh.c to access rsync.net. It was never cleaned up,
but it serves my purposes well, until ssh-ed25519 is supported in
9front for key exchange.
The thread where I discussed this was back in June 2020. The patch
has changed since then (due to changes to ssh.c itself), but it allows
me to use 9front in just one more area of my life without trampolining
through a linux or mac host.
Attached is my current patch that shows using the DSA code in case
anyone else wants to drive fast and take chances.
[-- Attachment #2: ssh-dss.c.patch --]
[-- Type: text/plain, Size: 22473 bytes --]
diff 3a47c8bfbe9298fed2b6dcc5ac19a7af4c96c52f uncommitted
--- a/sys/src/cmd/ssh.c
+++ b/sys/src/cmd/ssh.c
@@ -1,3 +1,14 @@
+/*
+ 2020-June (Romano)
+ I think this would be better if refactored into its own subdir with separate files, e.g.:
+ ssh/ssh.h <-- structs, enums, et c.
+ ssh/debug.c <-- debugging statement stuff, e.g. printKexinitp()
+ ssh/alloc.c <-- kexinitalloc() et c.
+ ssh/kex.c <-- key exchange and host server algorithm stuff
+ ssh/algs.c <-- cipher, mac, zip, and lang stuff
+ ssh/ssh.c <-- main loop
+*/
+
#include <u.h>
#include <libc.h>
#include <mp.h>
@@ -5,6 +16,7 @@
#include <auth.h>
#include <authsrv.h>
+/* Cf. RFC2450 & RFC8268 */
enum {
MSG_DISCONNECT = 1,
MSG_IGNORE,
@@ -47,7 +59,7 @@
enum {
- Overhead = 256, // enougth for MSG_CHANNEL_DATA header
+ Overhead = 256, // enough for MSG_CHANNEL_DATA header
MaxPacket = 1<<15,
WinPackets = 8, // (1<<15) * 8 = 256K
};
@@ -76,6 +88,280 @@
Rendez;
} Oneway;
+/* BEGIN RFC 4253 name-list agreement structure and implementation */
+struct nameseq {
+ char *val;
+ struct nameseq *next;
+};
+typedef struct nameseq Nameseq;
+
+Nameseq*
+nameseqalloc(void)
+{
+ Nameseq *nameseq;
+
+ nameseq = mallocz(sizeof(*nameseq), 1);
+ if(nameseq == nil)
+ sysfatal("nameseqalloc");
+ return nameseq;
+}
+
+void
+nameseqfree(Nameseq *nameseq)
+{
+ if(nameseq == nil)
+ return;
+ nameseqfree(nameseq->next);
+ free(nameseq);
+}
+
+Nameseq *
+getnameseq(char *c)
+{
+ Nameseq *orderp = nameseqalloc();
+ Nameseq *pp = orderp;
+ char *str = strdup(c);
+ while (str = strtok(str, ",")) {
+ pp->val = str;
+ pp->next = nameseqalloc();
+ pp = pp->next;
+ str = nil;
+ }
+ return orderp;
+}
+
+char *
+nameseqagree(char *c, char *s)
+{
+ Nameseq *cp, *sp, *startsp;
+ char *val = nil;
+
+ if (strlen(c) == 0 && strlen(s) == 0 )
+ return "";
+
+ cp = getnameseq(c);
+ startsp = sp = getnameseq(s);
+ while (cp) {
+ if (cp->val && sp->val && !strcmp(cp->val, sp->val)) {
+ val = strdup(cp->val);
+ break;
+ }
+ if(!(sp = sp->next)) {
+ if(!(cp = cp->next))
+ break;
+ sp = startsp;
+ }
+ }
+
+ nameseqfree(cp);
+ nameseqfree(sp);
+ return val;
+}
+/* END RFC 4253 name-list agreement implementation */
+
+typedef struct algs {
+ char *cipher;
+ char *mac;
+ char *zip;
+ char *lang;
+} Algs;
+typedef Algs *Algsp;
+
+typedef struct kexhost {
+ char *kex;
+ char *host;
+} Kexhost;
+typedef Kexhost *Kexhostp;
+
+typedef struct kexother {
+ uint firstkexpkt;
+ ulong reserved;
+ uchar msg;
+ uchar cookie[16];
+} Kexother;
+typedef Kexother *Kexotherp;
+
+typedef struct kexinit {
+ Kexhostp kh;
+ Algsp ctos;
+ Algsp stoc;
+ Kexotherp ko;
+} Kexinit;
+typedef Kexinit *Kexinitp;
+
+Algsp
+algsalloc(void)
+{
+ Algsp data;
+
+ data = mallocz(sizeof(data), 1);
+ if(data == nil)
+ sysfatal("algsalloc");
+ return data;
+}
+
+Kexhostp
+kexhostalloc(void)
+{
+ Kexhostp data;
+
+ data = mallocz(sizeof(data), 1);
+ if(data == nil)
+ sysfatal("kexhostalloc");
+ return data;
+}
+
+Kexotherp
+kexotheralloc(void)
+{
+ Kexotherp data;
+
+ data = mallocz(sizeof(data), 1);
+ if(data == nil)
+ sysfatal("kexotheralloc");
+ return data;
+}
+
+void
+printKexhostp(char *prefix, Kexhostp data) {
+ fprint(2, "%s ->%s: %s\n", prefix, "kex", data->kex );
+ fprint(2, "%s ->%s: %s\n", prefix, "host", data->host );
+}
+
+Kexinitp
+kexinitalloc(void)
+{
+ Kexinitp data;
+
+ data = mallocz(sizeof(data), 1);
+ if(data == nil)
+ sysfatal("kexinitalloc");
+ data->ko = kexotheralloc();
+ data->kh = kexhostalloc();
+ data->ctos = algsalloc();
+ data->stoc = algsalloc();
+ return data;
+}
+
+void
+defKexotherp(Kexotherp kop) {
+ kop->msg = MSG_KEXINIT;
+ kop->firstkexpkt = 0;
+ kop->reserved = 0L;
+ genrandom(kop->cookie, sizeof(kop->cookie));
+}
+
+void
+defKexhostp(Kexhostp khp) {
+ khp->kex = "curve25519-sha256,curve25519-sha256@libssh.org";
+
+ /*
+ ssh-dss is required per RFC4253. OpenSSH has deprecated its use, but
+ does there's no real basis to support that decision for larger modulo.
+ Support it as a secondary algorithm, most likely until ssh-ed25519 is
+ supported.
+ */
+ khp->host = "ssh-rsa,ssh-dss";
+}
+
+void
+defAlgsp(Algsp algsp) {
+ /*
+ 'At some future time, it is expected that another algorithm, one with better
+ strength, will become so prevalent and ubiquitous that the use of
+ "3des-cbc" will be deprecated by another STANDARDS ACTION.' - RFC4253
+ No standards action has yet deprecated it, but have not seen it supported
+ by default in any server.
+ */
+ algsp->cipher = "chacha20-poly1305@openssh.com";
+
+ /*
+ hmac-sha1 is a required algorithm by RFC4253, and some servers still check
+ for it; it's effectively ignored since chacha20-poly1305 cipher is AEAD.
+ No RFC has deprecated it, only provided other algorithms to be placed
+ before it (e.g., SHA-2).
+ */
+ algsp->mac = "hmac-sha1";
+
+ algsp->zip = "none";
+ algsp->lang = "";
+}
+
+void
+printKexotherp(char *prefix, Kexotherp data) {
+ fprint(2, "%s ->%s: %uc\n", prefix, "msg", data->msg );
+ fprint(2, "%s ->%s: %uhd\n", prefix, "cookie", *data->cookie );
+ fprint(2, "%s ->%s: %ud\n", prefix, "firstkexpkt", data->firstkexpkt );
+ fprint(2, "%s ->%s: %uld\n", prefix, "reserved", data->reserved );
+}
+
+void
+printAlgsp(char *prefix, Algsp data) {
+ fprint(2, "%s ->%s: %s\n", prefix, "cipher", data->cipher );
+ fprint(2, "%s ->%s: %s\n", prefix, "mac", data->mac );
+ fprint(2, "%s ->%s: %s\n", prefix, "zip", data->zip );
+ fprint(2, "%s ->%s: %s\n", prefix, "lang", data->lang );
+}
+
+void
+printKexinitp(char *prefix, Kexinitp data) {
+ fprint(2, "%s %llX:\n", prefix, (vlong)data);
+ fprint(2, "%s ko->\n", prefix);
+ printKexotherp(prefix, data->ko );
+ fprint(2, "%s kh->\n", prefix);
+ printKexhostp(prefix, data->kh );
+ fprint(2, "%s ctos->\n", prefix);
+ printAlgsp(prefix, data->ctos );
+ fprint(2, "%s stoc->\n", prefix);
+ printAlgsp(prefix, data->stoc );
+}
+
+Kexhostp
+khagree(Kexhostp a, Kexhostp b) {
+ Kexhostp c = kexhostalloc();
+ c->kex = nameseqagree(a->kex, b->kex);
+ if(!c->kex)
+ sysfatal("Cannot agree on key exchange algorithm");
+
+ c->host = nameseqagree(a->host, b->host);
+ if(!c->host)
+ sysfatal("Cannot agree on host server algorithm");
+
+ return c;
+}
+
+Algsp
+algsagree(Algsp a, Algsp b, char * cxt) {
+ Algsp c = algsalloc();
+ c->cipher = nameseqagree(a->cipher, b->cipher);
+ if(!c->cipher)
+ sysfatal(smprint("Cannot agree on cipher algorithm for %s", cxt));
+
+ c->mac = nameseqagree(a->mac, b->mac);
+ if(!c->mac)
+ sysfatal(smprint("Cannot agree on mac algorithm for %s", cxt));
+
+ c->zip = nameseqagree(a->zip, b->zip);
+ if(!c->zip)
+ sysfatal(smprint("Cannot agree on zip algorithm for %s", cxt));
+
+ c->lang = nameseqagree(a->lang, b->lang);
+ if(!c->lang)
+ sysfatal(smprint("Cannot agree on lang algorithm for %s", cxt));
+
+ return c;
+}
+
+Kexinitp agreep;
+
+void
+authagree(Kexinitp client, Kexinitp server) {
+ agreep = kexinitalloc();
+ agreep->kh = khagree(client->kh, server->kh);
+ agreep->ctos = algsagree(client->ctos, server->ctos, "ctos");
+ agreep->stoc = algsagree(client->stoc, server->stoc, "stoc");
+}
+
int nsid;
uchar sid[256];
char thumb[2*SHA2_256dlen+1], *thumbfile;
@@ -84,6 +370,7 @@
char *user, *service, *status, *host, *remote, *cmd;
Oneway recv, send;
+
void dispatch(void);
void
@@ -163,6 +450,16 @@
memmove(p, s, u);
p += u;
break;
+ /* Why does 's' exist with passing the string length, when it can just be calculated with strlen()? */
+ case 'S':
+ s = va_arg(a, char*);
+ u = strlen(s);
+ if(p+4 > e) goto err;
+ PUT4(p, u), p += 4;
+ if(u > e-p) goto err;
+ memmove(p, s, u);
+ p += u;
+ break;
case 'u':
u = va_arg(a, int);
if(p+4 > e) goto err;
@@ -211,6 +508,14 @@
*va_arg(a, int*) = u;
p += u;
break;
+ /* Why does 's' exist with passing the string length? casting to (char *) is null-terminated and can simply move that way: */
+ case 'S':
+ if(p+4 > e) goto err;
+ u = GET4(p), p += 4;
+ if(u > e-p) goto err;
+ *va_arg(a, char**)= (char*)p;
+ p += u;
+ break;
case '[':
s = va_arg(a, void*);
u = va_arg(a, int);
@@ -280,7 +585,7 @@
send.r = send.b;
send.w = send.b+n;
-if(debug > 1)
+if(debug > 2)
fprint(2, "sendpkt: (%d) %.*H\n", send.r[0], (int)(send.w-send.r), send.r);
if(nsid){
@@ -309,6 +614,26 @@
send.seq++;
}
+void
+sendkexinitpkt(Kexinitp data) {
+ sendpkt(
+ "b[SSSSSSSSSSbu",
+ data->ko->msg,
+ data->ko->cookie, sizeof(data->ko->cookie),
+ data->kh->kex,
+ data->kh->host,
+ data->ctos->cipher,
+ data->stoc->cipher,
+ data->ctos->mac,
+ data->stoc->mac,
+ data->ctos->zip,
+ data->stoc->zip,
+ data->ctos->lang,
+ data->stoc->lang,
+ data->ko->firstkexpkt,
+ data->ko->reserved);
+}
+
int
readall(int fd, uchar *data, int len)
{
@@ -366,52 +691,101 @@
recv.w = recv.r + n;
recv.seq++;
-if(debug > 1)
+if(debug > 2)
fprint(2, "recvpkt: (%d) %.*H\n", recv.r[0], (int)(recv.w-recv.r), recv.r);
return recv.r[0];
}
-static char sshrsa[] = "ssh-rsa";
+Kexinitp
+recvkexinit(void) {
+ Kexinitp spropp = kexinitalloc();
+ if(unpack(recv.r, recv.w-recv.r, "b[SSSSSSSSSSbu", &(spropp->ko->msg), spropp->ko->cookie, sizeof(spropp->ko->cookie), &(spropp->kh->kex), &(spropp->kh->host), &(spropp->ctos->cipher), &(spropp->stoc->cipher), &(spropp->ctos->mac), &(spropp->stoc->mac), &(spropp->ctos->zip), &(spropp->stoc->zip), &(spropp->ctos->lang), &(spropp->stoc->lang), &(spropp->ko->firstkexpkt), &(spropp->ko->reserved) ) < 0)
+ sysfatal("bad MSG_KEXINIT reply");
+
+ if(debug > 1)
+ printKexinitp("server kexinit proposal", spropp);
+
+ return spropp;
+}
+
+typedef struct {
+ RSApub *rsa;
+ DSApub *dsa;
+} Pub;
+
+static Pub *pub;
+
int
-rsapub2ssh(RSApub *rsa, uchar *data, int len)
+dsapub2ssh(uchar *data, int len)
{
- return pack(data, len, "smm", sshrsa, sizeof(sshrsa)-1, rsa->ek, rsa->n);
+ return pack(data, len, "smmmm", "ssh-dss", sizeof("ssh-dss")-1, pub->dsa->p, pub->dsa->q, pub->dsa->alpha, pub->dsa->key);
}
-RSApub*
-ssh2rsapub(uchar *data, int len)
+void
+ssh2dsapub(uchar *data, int len)
{
- RSApub *pub;
char *s;
int n;
- pub = rsapuballoc();
- pub->n = mpnew(0);
- pub->ek = mpnew(0);
- if(unpack(data, len, "smm", &s, &n, pub->ek, pub->n) < 0
- || n != sizeof(sshrsa)-1 || memcmp(s, sshrsa, n) != 0){
- rsapubfree(pub);
- return nil;
+ pub->dsa = dsapuballoc();
+ pub->dsa->p = mpnew(0);
+ pub->dsa->q = mpnew(0);
+ pub->dsa->alpha = mpnew(0);
+ pub->dsa->key = mpnew(0);
+ // RFC4253 Section 6.6: alpha is g, key is y
+ if(unpack(data, len, "smmmm", &s, &n, pub->dsa->p, pub->dsa->q, pub->dsa->alpha, pub->dsa->key ) < 0
+ || n != sizeof("ssh-dss")-1 || memcmp(s, "ssh-dss", n) != 0){
+ dsapubfree(pub->dsa);
}
- return pub;
}
static char rsasha256[] = "rsa-sha2-256";
int
-rsasig2ssh(RSApub *pub, mpint *S, uchar *data, int len)
+dsasig2ssh(mpint *S, uchar *data, int len)
{
- int l = (mpsignif(pub->n)+7)/8;
- if(4+12+4+l > len)
- return -1;
- mptober(S, data+4+12+4, l);
- return pack(data, len, "ss", rsasha256, sizeof(rsasha256)-1, data+4+12+4, l);
+ DSApriv *dsapriv = dsagen(pub->dsa);
+ DSAsig *dsasig = dsasign(dsapriv, S);
+ mptobe(dsasig->r, data, SHA1dlen, nil);
+ mptobe(dsasig->s, data+SHA1dlen, SHA1dlen, nil);
+ dsasigfree(dsasig);
+ dsaprivfree(dsapriv);
+ return pack(data, len, "ss", "ssh-dss", sizeof("ssh-dss")-1, data, len+2*SHA1dlen);
}
+int
+dsasha1verify(uchar *data, int len, mpint *S)
+{
+ mpint *V;
+ int ret;
+ uchar digest[SHA1dlen];
+
+ sha1(data, len, digest, nil);
+ V = betomp(digest, SHA1dlen, nil);
+ ret = V != nil;
+ if(ret){
+ DSAsig *dsasig = dsasigalloc();
+ dsasig->r = mpnew(0);
+ dsasig->s = mpnew(0);
+ mpright(S, 160, dsasig->r);
+ mptrunc(S, 160, dsasig->s);
+ if(debug > 2) {
+ fmtinstall('B', mpfmt);
+ fprint(2, "V: %B\n", V);
+ fprint(2, "S: %B\n", S);
+ fprint(2, "r:%B; s:%B\n", dsasig->r, dsasig->s);
+ }
+ ret = !dsaverify(pub->dsa, dsasig, V);
+ dsasigfree(dsasig);
+ mpfree(V);
+ }
+ return ret;
+}
+
mpint*
-ssh2rsasig(uchar *data, int len)
+ssh2sig(uchar *data, int len)
{
mpint *m;
char *s;
@@ -419,7 +793,7 @@
m = mpnew(0);
if(unpack(data, len, "sm", &s, &n, m) < 0
- || n != sizeof(rsasha256)-1 || memcmp(s, rsasha256, n) != 0){
+ || n != sizeof(agreep->kh->host)-1 || memcmp(s, agreep->kh->host, n) != 0){
mpfree(m);
return nil;
}
@@ -426,25 +800,58 @@
return m;
}
+static char sshrsa[] = "ssh-rsa";
+
+int
+rsapub2ssh(uchar *data, int len)
+{
+ return pack(data, len, "smm", agreep->kh->host, sizeof(agreep->kh->host)-1, pub->rsa->ek, pub->rsa->n);
+}
+
+void
+ssh2rsapub(uchar *data, int len)
+{
+ char *s;
+ int n;
+
+ pub->rsa = rsapuballoc();
+ pub->rsa->n = mpnew(0);
+ pub->rsa->ek = mpnew(0);
+ if(unpack(data, len, "smm", &s, &n, pub->rsa->ek, pub->rsa->n) < 0
+ || n != sizeof(agreep->kh->host)-1 || memcmp(s, agreep->kh->host, n) != 0){
+ rsapubfree(pub->rsa);
+ }
+}
+
+int
+rsasig2ssh(mpint *S, uchar *data, int len)
+{
+ int l = (mpsignif(pub->rsa->n)+7)/8;
+ if(4+7+4+l > len)
+ return -1;
+ mptober(S, data+4+7+4, l);
+ return pack(data, len, "ss", agreep->kh->host, sizeof(agreep->kh->host)-1, data+4+7+4, l);
+}
+
mpint*
-pkcs1digest(uchar *data, int len, RSApub *pub)
+pkcs1digest(uchar *data, int len)
{
uchar digest[SHA2_256dlen], buf[256];
sha2_256(data, len, digest, nil);
- return pkcs1padbuf(buf, asn1encodedigest(sha2_256, digest, buf, sizeof(buf)), pub->n, 1);
+ return pkcs1padbuf(buf, asn1encodedigest(sha1, digest, buf, sizeof(buf)), pub->rsa->n, 1);
}
int
-pkcs1verify(uchar *data, int len, RSApub *pub, mpint *S)
+pkcs1verify(uchar *data, int len, mpint *S)
{
mpint *V;
int ret;
- V = pkcs1digest(data, len, pub);
+ V = pkcs1digest(data, len);
ret = V != nil;
if(ret){
- rsaencrypt(pub, S, S);
+ rsaencrypt(pub->rsa, S, S);
ret = mpcmp(V, S) == 0;
mpfree(V);
}
@@ -488,37 +895,28 @@
void
kex(int gotkexinit)
{
- static char kexalgs[] = "curve25519-sha256,curve25519-sha256@libssh.org";
- static char cipheralgs[] = "chacha20-poly1305@openssh.com";
- static char zipalgs[] = "none";
- static char macalgs[] = "";
- static char langs[] = "";
+ Kexinitp cpropp = kexinitalloc();
+ defKexotherp(cpropp->ko);
+ defKexhostp(cpropp->kh);
+ defAlgsp(cpropp->ctos);
+ defAlgsp(cpropp->stoc);
- uchar cookie[16], x[32], yc[32], z[32], k[32+1], h[SHA2_256dlen], *ys, *ks, *sig;
+ if(debug > 1)
+ printKexinitp("client kexinit properties", cpropp);
+
+ uchar x[32], yc[32], z[32], k[32+1], h[SHA2_256dlen], *ys, *ks, *sig;
uchar k12[2*ChachaKeylen];
int i, nk, nys, nks, nsig;
DigestState *ds;
mpint *S, *K;
- RSApub *pub;
+ if (pub==nil)
+ pub = mallocz(sizeof(pub), 1);
+
ds = hashstr(send.v, strlen(send.v), nil);
ds = hashstr(recv.v, strlen(recv.v), ds);
- genrandom(cookie, sizeof(cookie));
- sendpkt("b[ssssssssssbu", MSG_KEXINIT,
- cookie, sizeof(cookie),
- kexalgs, sizeof(kexalgs)-1,
- rsasha256, sizeof(rsasha256)-1,
- cipheralgs, sizeof(cipheralgs)-1,
- cipheralgs, sizeof(cipheralgs)-1,
- macalgs, sizeof(macalgs)-1,
- macalgs, sizeof(macalgs)-1,
- zipalgs, sizeof(zipalgs)-1,
- zipalgs, sizeof(zipalgs)-1,
- langs, sizeof(langs)-1,
- langs, sizeof(langs)-1,
- 0,
- 0);
+ sendkexinitpkt(cpropp);
ds = hashstr(send.r, send.w-send.r, ds);
if(!gotkexinit){
@@ -532,26 +930,12 @@
}
ds = hashstr(recv.r, recv.w-recv.r, ds);
- if(debug){
- char *tab[] = {
- "kexalgs", "hostalgs",
- "cipher1", "cipher2",
- "mac1", "mac2",
- "zip1", "zip2",
- "lang1", "lang2",
- nil,
- }, **t, *s;
- uchar *p = recv.r+17;
- int n;
- for(t=tab; *t != nil; t++){
- if(unpack(p, recv.w-p, "s.", &s, &n, &p) < 0)
- break;
- fprint(2, "%s: %.*s\n", *t, utfnlen(s, n), s);
- }
- }
-
+ Kexinitp spropp = recvkexinit();
+ authagree(cpropp, spropp);
+ if (debug > 1)
+ printKexinitp("agreement", agreep);
curve25519_dh_new(x, yc);
- yc[31] &= ~0x80;
+ yc[31] &= ~0x80; /* curve25519_dh_new does & 0x80, so why reverse? */
sendpkt("bs", MSG_ECDH_INIT, yc, sizeof(yc));
Next1: switch(recvpkt()){
@@ -561,6 +945,8 @@
case MSG_KEXINIT:
sysfatal("inception");
case MSG_ECDH_REPLY:
+
+ /* RFC5656; ys is being set to Q_S */
if(unpack(recv.r, recv.w-recv.r, "_sss", &ks, &nks, &ys, &nys, &sig, &nsig) < 0)
sysfatal("bad ECDH_REPLY");
break;
@@ -567,7 +953,7 @@
}
if(nys != 32)
- sysfatal("bad server ECDH ephermal public key length");
+ sysfatal("bad server ECDH ephemeral public key length");
ds = hashstr(ks, nks, ds);
ds = hashstr(yc, 32, ds);
@@ -589,18 +975,29 @@
if(ok == nil || !okThumbprint(h, sizeof(h), ok)){
if(ok != nil) werrstr("unknown host");
fprint(2, "%s: %r\n", argv0);
- fprint(2, "verify hostkey: %s %.*[\n", sshrsa, nks, ks);
+ fprint(2, "verify hostkey: %s %.*[\n", agreep->kh->host, nks, ks);
fprint(2, "add thumbprint after verification:\n");
- fprint(2, "\techo 'ssh sha256=%s server=%s' >> %q\n", thumb, host, thumbfile);
+ fprint(2, "\techo 'ssh sha256=%s server=%s type=%s' >> %q\n", thumb, host, agreep->kh->host, thumbfile);
sysfatal("checking hostkey failed: %r");
}
freeThumbprints(ok);
}
- if((pub = ssh2rsapub(ks, nks)) == nil)
- sysfatal("bad server public key");
- if((S = ssh2rsasig(sig, nsig)) == nil)
- sysfatal("bad server signature");
+ // TODO: branch for ed25519
+ if(!strcmp(agreep->kh->host,"ssh-dss")) {
+ ssh2dsapub(ks, nks);
+ if(pub->dsa == nil)
+ sysfatal("bad server dss public key");
+ if((S = ssh2sig(sig, nsig)) == nil)
+ sysfatal("no server dss signature");
+ }
+ else {
+ ssh2rsapub(ks, nks);
+ if(pub->rsa == nil)
+ sysfatal("bad server rsa public key");
+ if((S = ssh2sig(sig, nsig)) == nil)
+ sysfatal("no server rsa signature");
+ }
if(!curve25519_dh_finish(x, ys, z))
sysfatal("unlucky shared key");
@@ -612,10 +1009,17 @@
ds = hashstr(k, nk, ds);
sha2_256(nil, 0, h, ds);
- if(!pkcs1verify(h, sizeof(h), pub, S))
- sysfatal("server verification failed");
+ // TODO: branch for ssh-ed25519
+ if(!strcmp(agreep->kh->host,"ssh-dss")){
+ if(!dsasha1verify(h, sizeof(h), S))
+ sysfatal("server dss verification failed");
+ }
+ else {
+ if(!pkcs1verify(h, sizeof(h), S))
+ sysfatal("server rsa verification failed");
+ rsapubfree(pub->rsa);
+ }
mpfree(S);
- rsapubfree(pub);
sendpkt("b", MSG_NEWKEYS);
Next2: switch(recvpkt()){
@@ -708,7 +1112,6 @@
char *s;
mpint *S;
AuthRpc *rpc;
- RSApub *pub;
if(!authok(authmeth))
return -1;
@@ -720,7 +1123,7 @@
return -1;
}
- s = "proto=rsa service=ssh role=client";
+ s = !strcmp(agreep->kh->host,"ssh-dss") ? "proto=dsa service=ssh role=client" : "proto=rsa service=ssh role=client";
if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){
auth_freerpc(rpc);
close(afd);
@@ -727,19 +1130,50 @@
return -1;
}
- pub = rsapuballoc();
- pub->n = mpnew(0);
- pub->ek = mpnew(0);
+ // TODO: branch for ssh-ed25519
+ if(!strcmp(agreep->kh->host,"ssh-dss")){
+ pub->dsa = dsapuballoc();
+ pub->dsa->p = mpnew(0);
+ pub->dsa->q = mpnew(0);
+ pub->dsa->alpha = mpnew(0);
+ pub->dsa->key = mpnew(0);
+ }
+ else {
+ pub->rsa = rsapuballoc();
+ pub->rsa->n = mpnew(0);
+ pub->rsa->ek = mpnew(0);
+ }
while(auth_rpc(rpc, "read", nil, 0) == ARok){
s = rpc->arg;
- if(strtomp(s, &s, 16, pub->n) == nil)
- break;
- if(*s++ != ' ')
- continue;
- if(strtomp(s, nil, 16, pub->ek) == nil)
- continue;
- npk = rsapub2ssh(pub, pk, sizeof(pk));
+ // TODO: branch for ssh-ed25519
+ if(!strcmp(agreep->kh->host,"ssh-dss")){
+ // This seems brittle and dependent upon the order of values set in factotum
+ if(strtomp(s, &s, 16, pub->dsa->p) == nil)
+ break;
+ if(*s++ != ' ')
+ continue;
+ if(strtomp(s, nil, 16, pub->dsa->q) == nil)
+ continue;
+ if(*s++ != ' ')
+ continue;
+ if(strtomp(s, nil, 16, pub->dsa->alpha) == nil)
+ continue;
+ if(*s++ != ' ')
+ continue;
+ if(strtomp(s, nil, 16, pub->dsa->key) == nil)
+ continue;
+ npk = dsapub2ssh(pk, sizeof(pk));
+ }
+ else {
+ if(strtomp(s, &s, 16, pub->rsa->n) == nil)
+ break;
+ if(*s++ != ' ')
+ continue;
+ if(strtomp(s, nil, 16, pub->rsa->ek) == nil)
+ continue;
+ npk = rsapub2ssh(pk, sizeof(pk));
+ }
sendpkt("bsssbss", MSG_USERAUTH_REQUEST,
user, strlen(user),
@@ -746,7 +1180,7 @@
service, strlen(service),
authmeth, sizeof(authmeth)-1,
0,
- rsasha256, sizeof(rsasha256)-1,
+ agreep->kh->host, sizeof(agreep->kh->host)-1,
pk, npk);
Next1: switch(recvpkt()){
default:
@@ -769,9 +1203,16 @@
service, strlen(service),
authmeth, sizeof(authmeth)-1,
1,
- rsasha256, sizeof(rsasha256)-1,
+ agreep->kh->host, sizeof(agreep->kh->host)-1,
pk, npk);
- S = pkcs1digest(send.b, n, pub);
+ // TODO branch for ssh-ed25519
+ if (!strcmp(agreep->kh->host,"ssh-dss")){
+ sha1(send.b, n, sig, nil);
+ S = strtomp((char *)sig, nil, 10, nil);
+ }
+ else {
+ S = pkcs1digest(send.b, n);
+ }
n = snprint((char*)send.b, sizeof(send.b), "%B", S);
mpfree(S);
@@ -781,7 +1222,13 @@
break;
S = strtomp(rpc->arg, nil, 16, nil);
- nsig = rsasig2ssh(pub, S, sig, sizeof(sig));
+ // TODO branch for ssh-ed25519
+ if (!strcmp(agreep->kh->host,"ssh-dss")){
+ nsig = dsasig2ssh(S, sig, sizeof(sig));
+ }
+ else {
+ nsig = rsasig2ssh(S, sig, sizeof(sig));
+ }
mpfree(S);
/* send final userauth request with the signature */
@@ -790,7 +1237,7 @@
service, strlen(service),
authmeth, sizeof(authmeth)-1,
1,
- rsasha256, sizeof(rsasha256)-1,
+ agreep->kh->host, sizeof(agreep->kh->host)-1,
pk, npk,
sig, nsig);
Next2: switch(recvpkt()){
@@ -804,13 +1251,25 @@
case MSG_USERAUTH_SUCCESS:
break;
}
- rsapubfree(pub);
+ // TODO: branch for ssh-ed25519
+ if (!strcmp(agreep->kh->host,"ssh-dss")){
+ dsapubfree(pub->dsa);
+ }
+ else {
+ rsapubfree(pub->rsa);
+ }
auth_freerpc(rpc);
close(afd);
return 0;
}
Failed:
- rsapubfree(pub);
+ // TODO: branch for ssh-ed25519
+ if (!strcmp(agreep->kh->host,"ssh-dss")){
+ dsapubfree(pub->dsa);
+ }
+ else {
+ rsapubfree(pub->rsa);
+ }
auth_freerpc(rpc);
close(afd);
return -1;
@@ -1171,7 +1630,7 @@
void
usage(void)
{
- fprint(2, "usage: %s [-dR] [-t thumbfile] [-T tries] [-u user] [-h] [user@]host [-W remote!port] [cmd args...]\n", argv0);
+ fprint(2, "usage: %s [-d] [-R] [-r] [-t thumbfile] [-T tries] [-u user] [-h] [user@]host [-W remote!port] [cmd args...]\n", argv0);
exits("usage");
}
^ permalink raw reply [flat|nested] 18+ messages in thread