shithub: riscv

Download patch

ref: 57f8b6ec7591007ff22627038b51c4f4aa2a9be8
parent: b42d441a230bad9fd1ae8e3543b1c0f28c7c62aa
author: cinap_lenrek <[email protected]>
date: Fri Dec 29 22:07:47 EST 2017

libsec: implement SPKI fingerprinting for okCertificate()

Instead of only using a hash over the whole certificate for
white/black-listing, now we can also use a hash over the
Subject Public Key Info (SPKI) field of the certificate which
contians the public key algorithm and the public key itself.

This allows certificates to be renewed independendtly of the
public key.

X509dump() now prints the public key thumbprint in addition
to the certificate thumbprint.

tlsclient will print the certificate when run with -D flag.

okCertificate() will print the public key thumbprint in its
error string when no match has been found.

--- a/sys/include/ape/libsec.h
+++ b/sys/include/ape/libsec.h
@@ -382,7 +382,9 @@
 int		asn1encodeRSApub(RSApub *pk, uchar *buf, int len);
 int		asn1encodedigest(DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*),
 			uchar *digest, uchar *buf, int len);
- 
+
+int		X509digestSPKI(uchar *, int, DigestState* (*)(uchar*, ulong, uchar*, DigestState*), uchar *);
+
 /*
  * elgamal
  */
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -375,6 +375,7 @@
 int		asn1encodedigest(DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*),
 			uchar *digest, uchar *buf, int len);
 
+int		X509digestSPKI(uchar *, int, DigestState* (*)(uchar*, ulong, uchar*, DigestState*), uchar *);
 
 /*
  * elgamal
--- a/sys/man/8/tlssrv
+++ b/sys/man/8/tlssrv
@@ -134,9 +134,8 @@
 (and, optionally, the
 .B -x
 flag)
-is given, the remote server must present a key
-whose SHA1 hash is listed in
-the file
+is given, the remote server must present a public key
+whose SHA1 or SHA256 hash is listed in the file
 .I trustedkeys
 but not in the file
 .IR excludedkeys .
--- a/sys/src/cmd/tlsclient.c
+++ b/sys/src/cmd/tlsclient.c
@@ -49,6 +49,8 @@
 	Thumbprint *thumb;
 	AuthInfo *ai = nil;
 
+	fmtinstall('B', mpfmt);
+	fmtinstall('[', encodefmt);
 	fmtinstall('H', encodefmt);
 
 	ARGBEGIN{
@@ -121,6 +123,9 @@
 	fd = tlsClient(fd, conn);
 	if(fd < 0)
 		sysfatal("tlsclient: %r");
+
+	if(debug)
+		X509dump(conn->cert, conn->certlen);
 
 	if(thumb){
 		if(!okCertificate(conn->cert, conn->certlen, thumb))
--- a/sys/src/libsec/port/thumb.c
+++ b/sys/src/libsec/port/thumb.c
@@ -66,6 +66,11 @@
 	if(okThumbprint(hash, SHA2_256dlen, table))
 		return 1;
 
+	if(X509digestSPKI(cert, len, sha2_256, hash) < 0)
+		return 0;
+	if(okThumbprint(hash, SHA2_256dlen, table))
+		return 1;
+
 	len = enc64(thumb, sizeof(thumb), hash, SHA2_256dlen);
 	while(len > 0 && thumb[len-1] == '=')
 		len--;
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -2897,6 +2897,32 @@
 	return cert;
 }
 
+static void
+digestSPKI(int alg, uchar *pubkey, int npubkey, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
+{
+	Bytes *b = nil;
+	Elem e = mkseq(mkel(mkalg(alg), mkel(mkbits(pubkey, npubkey), nil)));
+	encode(e, &b);
+	freevalfields(&e.val);
+	(*fun)(b->data, b->len, digest, nil);
+	freebytes(b);
+}
+
+int
+X509digestSPKI(uchar *cert, int ncert, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
+{
+	CertX509 *c;
+
+	c = decode_cert(cert, ncert);
+	if(c == nil){
+		werrstr("cannot decode cert");
+		return -1;
+	}
+	digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, fun, digest);
+	freecert(c);
+	return 0;
+}
+
 static char*
 tagdump(Tag tag)
 {
@@ -3047,6 +3073,16 @@
 		ecdomfree(&ecdom);
 		break;
 	}
+
+	digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, sha2_256, digest);
+	print("publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+
+	sha2_256(cert, ncert, digest, nil);
+	print("cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+
+	sha1(cert, ncert, digest, nil);
+	print("cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
+
 	freecert(c);
 	print("end X509dump\n");
 }