shithub: riscv

Download patch

ref: da0a7ac387a0e99e46be7611fd8d7083c6ff85db
parent: 2b10f79119c2e6bead4b50a5173e531cb27dc36f
author: cinap_lenrek <[email protected]>
date: Sat Apr 22 22:54:41 EDT 2017

ssh: implement primitive hostkey verification

this checks $home/lib/sshthumbs for the sha256 hash
of the hosts rsa public key. if its not there, it
prints the rc command to add it and exits.

--- a/sys/src/cmd/ssh.c
+++ b/sys/src/cmd/ssh.c
@@ -4,6 +4,7 @@
 #include <libsec.h>
 #include <auth.h>
 #include <authsrv.h>
+#include <bio.h>
 
 enum {
 	MSG_DISCONNECT = 1,
@@ -76,7 +77,7 @@
 
 int nsid;
 uchar sid[256];
-char thumb[2*SHA2_256dlen+1];
+char thumb[2*SHA2_256dlen+1], *thumbfile;
 
 int fd, intr, raw, debug;
 char *user, *service, *status, *host, *cmd;
@@ -83,6 +84,7 @@
 
 Oneway recv, send;
 void dispatch(void);
+int checkthumb(char*, uchar*);
 
 void
 shutdown(void)
@@ -577,14 +579,25 @@
 	ds = hashstr(yc, 32, ds);
 	ds = hashstr(ys, 32, ds);
 
-	sha2_256(ks, nks, h, nil);
-	i = snprint(thumb, sizeof(thumb), "%.*[", sizeof(h), h);
-	while(i > 0 && thumb[i-1] == '=')
-		thumb[--i] = '\0';
+	if(thumb[0] == 0){
+		sha2_256(ks, nks, h, nil);
+		i = snprint(thumb, sizeof(thumb), "%.*[", sizeof(h), h);
+		while(i > 0 && thumb[i-1] == '=')
+			thumb[--i] = '\0';
+		if(debug)
+			fprint(2, "host fingerprint: %s\n", thumb);
+		switch(checkthumb(thumbfile, h)){
+		case 0:
+			werrstr("host unknown");
+		default:
+			fprint(2, "%s: %r, to add after verification:\n", argv0);
+			fprint(2, "\techo 'ssh sha256=%s # %s' >> %q\n", thumb, host, thumbfile);
+			sysfatal("checking hostkey failed: %r");
+		case 1:
+			break;
+		}
+	}
 
-if(debug)
-	fprint(2, "host fingerprint: %s\n", thumb);
-
 	if((pub = ssh2rsapub(ks, nks)) == nil)
 		sysfatal("bad server public key");
 	if((S = ssh2rsasig(sig, nsig)) == nil)
@@ -1061,10 +1074,43 @@
 	}
 }
 
+int
+checkthumb(char *file, uchar hash[SHA2_256dlen])
+{
+	uchar sum[SHA2_256dlen];
+	char *line, *field[50];
+	Biobuf *bin;
+
+	if((bin = Bopen(file, OREAD)) == nil)
+		return -1;
+	for(; (line = Brdstr(bin, '\n', 1)) != nil; free(line)){
+		if(tokenize(line, field, nelem(field)) < 2)
+			continue;
+		if(strcmp(field[0], "ssh") != 0 || strncmp(field[1], "sha256=", 7) != 0)
+			continue;
+		field[1] += 7;
+		if(dec64(sum, SHA2_256dlen, field[1], strlen(field[1])) != SHA2_256dlen){
+			werrstr("malformed ssh entry in %s: %s", file, field[1]);
+			goto err;
+		}
+		if(memcmp(sum, hash, SHA2_256dlen) == 0){
+			free(line);
+			Bterm(bin);
+			return 1;
+		}
+	}
+	Bterm(bin);
+	return 0;
+err:
+	free(line);
+	Bterm(bin);
+	return -1;
+}
+
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-dR] [-u user] [user@]host [cmd]\n", argv0);
+	fprint(2, "usage: %s [-dR] [-t thumbfile] [-u user] [user@]host [cmd]\n", argv0);
 	exits("usage");
 }
 
@@ -1094,6 +1140,9 @@
 	case 'u':
 		user = EARGF(usage());
 		break;
+	case 't':
+		thumbfile = EARGF(usage());
+		break;
 	} ARGEND;
 
 	if(argc == 0)
@@ -1134,10 +1183,14 @@
 
 	send.l = recv.l = &sl;
 
-	kex(0);
-
 	if(user == nil)
 		user = getuser();
+	if(thumbfile == nil)
+		thumbfile = smprint("%s/lib/sshthumbs", getenv("home"));
+
+	kex(0);
+
+
 	service = "ssh-connection";
 
 	sendpkt("bs", MSG_SERVICE_REQUEST, "ssh-userauth", 12);