ref: 892d66fbdd25ed7f5b71278448769e5d5cfe7909
parent: b101cdfb863ff7952157fe31634cb6d349370401
	author: cinap_lenrek <cinap_lenrek@felloff.net>
	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");}
--
⑨