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.
This commit is contained in:
cinap_lenrek 2017-12-30 03:07:47 +01:00
parent b42d441a23
commit 57f8b6ec75
6 changed files with 52 additions and 4 deletions

View file

@ -382,7 +382,9 @@ int pkcs1unpadbuf(uchar *buf, int len, mpint *modulus, int blocktype);
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
*/

View file

@ -375,6 +375,7 @@ 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

View file

@ -134,9 +134,8 @@ flag
(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 .

View file

@ -49,6 +49,8 @@ main(int argc, char **argv)
Thumbprint *thumb;
AuthInfo *ai = nil;
fmtinstall('B', mpfmt);
fmtinstall('[', encodefmt);
fmtinstall('H', encodefmt);
ARGBEGIN{
@ -122,6 +124,9 @@ main(int argc, char **argv)
if(fd < 0)
sysfatal("tlsclient: %r");
if(debug)
X509dump(conn->cert, conn->certlen);
if(thumb){
if(!okCertificate(conn->cert, conn->certlen, thumb))
sysfatal("cert for %s not recognized: %r", servername ? servername : addr);

View file

@ -66,6 +66,11 @@ okCertificate(uchar *cert, int len, Thumbprint *table)
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--;

View file

@ -2897,6 +2897,32 @@ errret:
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 @@ X509dump(uchar *cert, int ncert)
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");
}