libsec: sha256 support for thumbprint files, use it in ssh as well
initThumbprints() now takes an application tag argument so x509 and ssh can coexist. the thumbprint entries can now hold both sha1 and sha256 hashes. okThumbprint() now takes a len argument for the hash length used. the new function okCertificate() hashes the certificate with both and checks for any matches. on failure, okCertificate() returns 0 and sets error string. we also check for include loops now in thumbfiles, limiting the number of includes to 8.
This commit is contained in:
parent
2d1fbbdafa
commit
346f5828e0
11 changed files with 126 additions and 123 deletions
|
@ -461,7 +461,8 @@ DSApriv* asn1toDSApriv(uchar*, int);
|
||||||
*/
|
*/
|
||||||
typedef struct Thumbprint{
|
typedef struct Thumbprint{
|
||||||
struct Thumbprint *next;
|
struct Thumbprint *next;
|
||||||
uchar sha1[SHA1dlen];
|
uchar hash[SHA2_256dlen];
|
||||||
|
uchar len;
|
||||||
} Thumbprint;
|
} Thumbprint;
|
||||||
|
|
||||||
typedef struct TLSconn{
|
typedef struct TLSconn{
|
||||||
|
@ -487,9 +488,10 @@ int tlsClient(int fd, TLSconn *c);
|
||||||
int tlsServer(int fd, TLSconn *c);
|
int tlsServer(int fd, TLSconn *c);
|
||||||
|
|
||||||
/* thumb.c */
|
/* thumb.c */
|
||||||
Thumbprint* initThumbprints(char *ok, char *crl);
|
Thumbprint* initThumbprints(char *ok, char *crl, char *tag);
|
||||||
void freeThumbprints(Thumbprint *ok);
|
void freeThumbprints(Thumbprint *ok);
|
||||||
int okThumbprint(uchar *sha1, Thumbprint *ok);
|
int okThumbprint(uchar *hash, int len, Thumbprint *ok);
|
||||||
|
int okCertificate(uchar *cert, int len, Thumbprint *ok);
|
||||||
|
|
||||||
/* readcert.c */
|
/* readcert.c */
|
||||||
uchar *readcert(char *filename, int *pcertlen);
|
uchar *readcert(char *filename, int *pcertlen);
|
||||||
|
|
|
@ -453,7 +453,8 @@ DSApriv* asn1toDSApriv(uchar*, int);
|
||||||
*/
|
*/
|
||||||
typedef struct Thumbprint{
|
typedef struct Thumbprint{
|
||||||
struct Thumbprint *next;
|
struct Thumbprint *next;
|
||||||
uchar sha1[SHA1dlen];
|
uchar hash[SHA2_256dlen];
|
||||||
|
uchar len;
|
||||||
} Thumbprint;
|
} Thumbprint;
|
||||||
|
|
||||||
typedef struct TLSconn{
|
typedef struct TLSconn{
|
||||||
|
@ -479,9 +480,10 @@ int tlsClient(int fd, TLSconn *c);
|
||||||
int tlsServer(int fd, TLSconn *c);
|
int tlsServer(int fd, TLSconn *c);
|
||||||
|
|
||||||
/* thumb.c */
|
/* thumb.c */
|
||||||
Thumbprint* initThumbprints(char *ok, char *crl);
|
Thumbprint* initThumbprints(char *ok, char *crl, char *tag);
|
||||||
void freeThumbprints(Thumbprint *ok);
|
void freeThumbprints(Thumbprint *ok);
|
||||||
int okThumbprint(uchar *sha1, Thumbprint *ok);
|
int okThumbprint(uchar *hash, int len, Thumbprint *ok);
|
||||||
|
int okCertificate(uchar *cert, int len, Thumbprint *ok);
|
||||||
|
|
||||||
/* readcert.c */
|
/* readcert.c */
|
||||||
uchar *readcert(char *filename, int *pcertlen);
|
uchar *readcert(char *filename, int *pcertlen);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
.TH PUSHTLS 2
|
.TH PUSHTLS 2
|
||||||
.SH NAME
|
.SH NAME
|
||||||
pushtls, tlsClient, tlsServer, initThumbprints, freeThumbprints, okThumbprint, readcert, readcertchain \- attach TLS1 or SSL3 encryption to a communication channel
|
pushtls, tlsClient, tlsServer, initThumbprints, freeThumbprints, okThumbprint, okCertificate, readcert, readcertchain \- attach TLS1 or SSL3 encryption to a communication channel
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B #include <u.h>
|
.B #include <u.h>
|
||||||
.br
|
.br
|
||||||
|
@ -29,13 +29,16 @@ uchar *readcert(char *filename, int *pcertlen)
|
||||||
PEMchain *readcertchain(char *filename)
|
PEMchain *readcertchain(char *filename)
|
||||||
.PP
|
.PP
|
||||||
.B
|
.B
|
||||||
Thumbprint *initThumbprints(char *ok, char *crl)
|
Thumbprint *initThumbprints(char *ok, char *crl, char *tag)
|
||||||
.PP
|
.PP
|
||||||
.B
|
.B
|
||||||
void freeThumbprints(Thumbprint *table)
|
void freeThumbprints(Thumbprint *table)
|
||||||
.PP
|
.PP
|
||||||
.B
|
.B
|
||||||
int okThumbprint(uchar *hash, Thumbprint *table)
|
int okThumbprint(uchar *hash, int len, Thumbprint *table)
|
||||||
|
.PP
|
||||||
|
.B
|
||||||
|
int okCertificate(uchar *cert, int len, Thumbprint *table)
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Transport Layer Security (TLS) comprises a record layer protocol,
|
Transport Layer Security (TLS) comprises a record layer protocol,
|
||||||
doing message digesting and encrypting in the kernel,
|
doing message digesting and encrypting in the kernel,
|
||||||
|
@ -213,13 +216,10 @@ be freed by the application whenever convenient.
|
||||||
Start the client half of TLS and check the remote certificate:
|
Start the client half of TLS and check the remote certificate:
|
||||||
.IP
|
.IP
|
||||||
.EX
|
.EX
|
||||||
uchar hash[SHA1dlen];
|
|
||||||
|
|
||||||
conn = (TLSconn*)mallocz(sizeof *conn, 1);
|
conn = (TLSconn*)mallocz(sizeof *conn, 1);
|
||||||
fd = tlsClient(fd, conn);
|
fd = tlsClient(fd, conn);
|
||||||
sha1(conn->cert, conn->certlen, hash, nil);
|
if(!okCertificate(conn->cert, conn->certlen, table))
|
||||||
if(!okThumbprint(hash,table))
|
sysfatal("suspect server: %r");
|
||||||
exits("suspect server");
|
|
||||||
\fI...application begins...\fP
|
\fI...application begins...\fP
|
||||||
.EE
|
.EE
|
||||||
.PP
|
.PP
|
||||||
|
|
|
@ -8,6 +8,8 @@ for example by calling
|
||||||
.B tlsClient
|
.B tlsClient
|
||||||
and
|
and
|
||||||
.B okThumbprint
|
.B okThumbprint
|
||||||
|
or
|
||||||
|
.B okCertificate
|
||||||
(see
|
(see
|
||||||
.IR pushtls (2)),
|
.IR pushtls (2)),
|
||||||
check the remote side's public key by comparing against
|
check the remote side's public key by comparing against
|
||||||
|
@ -25,13 +27,21 @@ attribute/value pairs of the form
|
||||||
.IB attr = value
|
.IB attr = value
|
||||||
or
|
or
|
||||||
.IR attr .
|
.IR attr .
|
||||||
The first attribute must be
|
The first attribute must be the application tag:
|
||||||
.B x509
|
.B x509
|
||||||
and the second must be
|
for tls applications or
|
||||||
.BI sha1= {hex checksum of binary certificate}.
|
.B ssh
|
||||||
|
for ssh server fingerprints.
|
||||||
|
The second attribute must be a hash type of
|
||||||
|
.B sha1=
|
||||||
|
or
|
||||||
|
.BI sha256=
|
||||||
|
followed by the hex or base64 encoded hash of binary certificate
|
||||||
|
or public key.
|
||||||
All other attributes are treated as comments.
|
All other attributes are treated as comments.
|
||||||
The file may also contain lines of the form
|
The file may also contain lines of the form
|
||||||
.BI #include file
|
.B #include
|
||||||
|
.I file
|
||||||
.PP
|
.PP
|
||||||
For example, a web server might have thumbprint
|
For example, a web server might have thumbprint
|
||||||
.EX
|
.EX
|
||||||
|
|
|
@ -12,6 +12,7 @@ install all:V:
|
||||||
}
|
}
|
||||||
|
|
||||||
clean:V:
|
clean:V:
|
||||||
|
rm -f [$OS].* *.[$OS]
|
||||||
for(i in $DIRS)@{
|
for(i in $DIRS)@{
|
||||||
echo $i
|
echo $i
|
||||||
cd $i
|
cd $i
|
||||||
|
@ -34,5 +35,6 @@ everything:V:
|
||||||
|
|
||||||
APE=/sys/src/ape
|
APE=/sys/src/ape
|
||||||
<$APE/config
|
<$APE/config
|
||||||
|
|
||||||
$O.tlsclient: tlsclient.c
|
$O.tlsclient: tlsclient.c
|
||||||
$CC -o $target $CFLAGS -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_NET_EXTENSION tlsclient.c
|
$CC -o $target $CFLAGS -D_POSIX_SOURCE -D_PLAN9_SOURCE -D_NET_EXTENSION tlsclient.c
|
||||||
|
|
|
@ -107,7 +107,7 @@ main(int argc, char **argv)
|
||||||
sysfatal("specifying -x without -t is useless");
|
sysfatal("specifying -x without -t is useless");
|
||||||
|
|
||||||
if(file){
|
if(file){
|
||||||
thumb = initThumbprints(file, filex);
|
thumb = initThumbprints(file, filex, "x509");
|
||||||
if(thumb == nil)
|
if(thumb == nil)
|
||||||
sysfatal("initThumbprints: %r");
|
sysfatal("initThumbprints: %r");
|
||||||
} else
|
} else
|
||||||
|
@ -144,13 +144,8 @@ main(int argc, char **argv)
|
||||||
sysfatal("tlsclient: %r");
|
sysfatal("tlsclient: %r");
|
||||||
|
|
||||||
if(thumb){
|
if(thumb){
|
||||||
uchar digest[20];
|
if(!okCertificate(conn->cert, conn->certlen, thumb))
|
||||||
|
sysfatal("cert for %s not recognized: %r", servername ? servername : addr);
|
||||||
if(conn->cert==nil || conn->certlen<=0)
|
|
||||||
sysfatal("server did not provide TLS certificate");
|
|
||||||
sha1(conn->cert, conn->certlen, digest, nil);
|
|
||||||
if(!okThumbprint(digest, thumb))
|
|
||||||
sysfatal("server certificate %.*H not recognized", SHA1dlen, digest);
|
|
||||||
freeThumbprints(thumb);
|
freeThumbprints(thumb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <libsec.h>
|
#include <libsec.h>
|
||||||
#include <auth.h>
|
#include <auth.h>
|
||||||
#include <authsrv.h>
|
#include <authsrv.h>
|
||||||
#include <bio.h>
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MSG_DISCONNECT = 1,
|
MSG_DISCONNECT = 1,
|
||||||
|
@ -84,7 +83,6 @@ char *user, *service, *status, *host, *cmd;
|
||||||
|
|
||||||
Oneway recv, send;
|
Oneway recv, send;
|
||||||
void dispatch(void);
|
void dispatch(void);
|
||||||
int checkthumb(char*, uchar*);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
shutdown(void)
|
shutdown(void)
|
||||||
|
@ -580,22 +578,25 @@ Next1: switch(recvpkt()){
|
||||||
ds = hashstr(ys, 32, ds);
|
ds = hashstr(ys, 32, ds);
|
||||||
|
|
||||||
if(thumb[0] == 0){
|
if(thumb[0] == 0){
|
||||||
|
Thumbprint *ok;
|
||||||
|
|
||||||
sha2_256(ks, nks, h, nil);
|
sha2_256(ks, nks, h, nil);
|
||||||
i = snprint(thumb, sizeof(thumb), "%.*[", sizeof(h), h);
|
i = enc64(thumb, sizeof(thumb), h, sizeof(h));
|
||||||
while(i > 0 && thumb[i-1] == '=')
|
while(i > 0 && thumb[i-1] == '=')
|
||||||
thumb[--i] = '\0';
|
i--;
|
||||||
|
thumb[i] = '\0';
|
||||||
|
|
||||||
if(debug)
|
if(debug)
|
||||||
fprint(2, "host fingerprint: %s\n", thumb);
|
fprint(2, "host fingerprint: %s\n", thumb);
|
||||||
switch(checkthumb(thumbfile, h)){
|
|
||||||
case 0:
|
ok = initThumbprints(thumbfile, nil, "ssh");
|
||||||
werrstr("host unknown");
|
if(ok == nil || !okThumbprint(h, sizeof(h), ok)){
|
||||||
default:
|
if(ok != nil) werrstr("unknown host");
|
||||||
fprint(2, "%s: %r, to add after verification:\n", argv0);
|
fprint(2, "%s: %r, to add after verification:\n", argv0);
|
||||||
fprint(2, "\techo 'ssh sha256=%s # %s' >> %q\n", thumb, host, thumbfile);
|
fprint(2, "\techo 'ssh sha256=%s server=%s' >> %q\n", thumb, host, thumbfile);
|
||||||
sysfatal("checking hostkey failed: %r");
|
sysfatal("checking hostkey failed: %r");
|
||||||
case 1:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
freeThumbprints(ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((pub = ssh2rsapub(ks, nks)) == nil)
|
if((pub = ssh2rsapub(ks, nks)) == nil)
|
||||||
|
@ -1074,39 +1075,6 @@ rawon(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -1124,7 +1092,6 @@ main(int argc, char *argv[])
|
||||||
quotefmtinstall();
|
quotefmtinstall();
|
||||||
fmtinstall('B', mpfmt);
|
fmtinstall('B', mpfmt);
|
||||||
fmtinstall('H', encodefmt);
|
fmtinstall('H', encodefmt);
|
||||||
fmtinstall('[', encodefmt);
|
|
||||||
|
|
||||||
s = getenv("TERM");
|
s = getenv("TERM");
|
||||||
raw = s != nil && strcmp(s, "dumb") != 0;
|
raw = s != nil && strcmp(s, "dumb") != 0;
|
||||||
|
|
|
@ -87,7 +87,7 @@ main(int argc, char **argv)
|
||||||
sysfatal("specifying -x without -t is useless");
|
sysfatal("specifying -x without -t is useless");
|
||||||
|
|
||||||
if(file){
|
if(file){
|
||||||
thumb = initThumbprints(file, filex);
|
thumb = initThumbprints(file, filex, "x509");
|
||||||
if(thumb == nil)
|
if(thumb == nil)
|
||||||
sysfatal("initThumbprints: %r");
|
sysfatal("initThumbprints: %r");
|
||||||
} else
|
} else
|
||||||
|
@ -123,13 +123,8 @@ main(int argc, char **argv)
|
||||||
sysfatal("tlsclient: %r");
|
sysfatal("tlsclient: %r");
|
||||||
|
|
||||||
if(thumb){
|
if(thumb){
|
||||||
uchar digest[20];
|
if(!okCertificate(conn->cert, conn->certlen, thumb))
|
||||||
|
sysfatal("cert for %s not recognized: %r", servername ? servername : addr);
|
||||||
if(conn->cert==nil || conn->certlen<=0)
|
|
||||||
sysfatal("server did not provide TLS certificate");
|
|
||||||
sha1(conn->cert, conn->certlen, digest, nil);
|
|
||||||
if(!okThumbprint(digest, thumb))
|
|
||||||
sysfatal("server certificate %.*H not recognized", SHA1dlen, digest);
|
|
||||||
freeThumbprints(thumb);
|
freeThumbprints(thumb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
int
|
int
|
||||||
wraptls(int ofd, char *host)
|
wraptls(int ofd, char *host)
|
||||||
{
|
{
|
||||||
uchar digest[SHA1dlen];
|
|
||||||
Thumbprint *thumb;
|
Thumbprint *thumb;
|
||||||
TLSconn conn;
|
TLSconn conn;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -18,16 +17,10 @@ wraptls(int ofd, char *host)
|
||||||
close(ofd);
|
close(ofd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude");
|
thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude", "x509");
|
||||||
if(thumb != nil){
|
if(thumb != nil){
|
||||||
if(conn.cert == nil || conn.certlen <= 0){
|
if(!okCertificate(conn.cert, conn.certlen, thumb)){
|
||||||
werrstr("server did not provide TLS certificate");
|
werrstr("cert for %s not recognized: %r", host);
|
||||||
goto Err;
|
|
||||||
}
|
|
||||||
sha1(conn.cert, conn.certlen, digest, nil);
|
|
||||||
if(!okThumbprint(digest, thumb)){
|
|
||||||
werrstr("server certificate %.*H not recognized",
|
|
||||||
SHA1dlen, digest);
|
|
||||||
Err:
|
Err:
|
||||||
close(fd);
|
close(fd);
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
|
|
@ -388,9 +388,8 @@ wraptls(void)
|
||||||
{
|
{
|
||||||
TLSconn *c;
|
TLSconn *c;
|
||||||
Thumbprint *goodcerts;
|
Thumbprint *goodcerts;
|
||||||
char *h, *err;
|
char *err;
|
||||||
int fd;
|
int fd;
|
||||||
uchar hash[SHA1dlen];
|
|
||||||
|
|
||||||
goodcerts = nil;
|
goodcerts = nil;
|
||||||
err = Giveup;
|
err = Giveup;
|
||||||
|
@ -412,29 +411,19 @@ wraptls(void)
|
||||||
Bterm(&bin);
|
Bterm(&bin);
|
||||||
Binit(&bin, fd, OREAD);
|
Binit(&bin, fd, OREAD);
|
||||||
|
|
||||||
goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs);
|
goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs, "x509");
|
||||||
if (goodcerts == nil) {
|
if (goodcerts == nil) {
|
||||||
syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs);
|
syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs);
|
||||||
goto Out;
|
goto Out;
|
||||||
}
|
}
|
||||||
/* compute sha1 hash of remote's certificate, see if we know it */
|
if (!okCertificate(c->cert, c->certlen, goodcerts)) {
|
||||||
sha1(c->cert, c->certlen, hash, nil);
|
syslog(0, "smtp", "cert for %s not recognized: %r", ddomain);
|
||||||
if (!okThumbprint(hash, goodcerts)) {
|
|
||||||
/* TODO? if not excluded, add hash to thumb list */
|
|
||||||
h = malloc(2*sizeof hash + 1);
|
|
||||||
if (h == nil)
|
|
||||||
goto Out;
|
|
||||||
enc16(h, 2*sizeof hash + 1, hash, sizeof hash);
|
|
||||||
syslog(0, "smtp", "remote cert. has bad thumbprint: x509 sha1=%s server=%q",
|
|
||||||
h, ddomain);
|
|
||||||
free(h);
|
|
||||||
goto Out;
|
goto Out;
|
||||||
}
|
}
|
||||||
syslog(0, "smtp", "started TLS to %q", ddomain);
|
syslog(0, "smtp", "started TLS to %q", ddomain);
|
||||||
err = nil;
|
err = nil;
|
||||||
Out:
|
Out:
|
||||||
if(goodcerts != nil)
|
freeThumbprints(goodcerts);
|
||||||
freeThumbprints(goodcerts);
|
|
||||||
free(c->cert);
|
free(c->cert);
|
||||||
free(c->sessionID);
|
free(c->sessionID);
|
||||||
free(c);
|
free(c);
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
enum{ ThumbTab = 1<<10 };
|
enum{ ThumbTab = 1<<10 };
|
||||||
|
|
||||||
static Thumbprint*
|
static Thumbprint*
|
||||||
tablehead(uchar *sum, Thumbprint *table)
|
tablehead(uchar *hash, Thumbprint *table)
|
||||||
{
|
{
|
||||||
return &table[((sum[0]<<8) + sum[1]) & (ThumbTab-1)];
|
return &table[((hash[0]<<8) + hash[1]) & (ThumbTab-1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -27,15 +27,15 @@ freeThumbprints(Thumbprint *table)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
okThumbprint(uchar *sum, Thumbprint *table)
|
okThumbprint(uchar *hash, int len, Thumbprint *table)
|
||||||
{
|
{
|
||||||
Thumbprint *hd, *p;
|
Thumbprint *hd, *p;
|
||||||
|
|
||||||
if(table == nil)
|
if(table == nil)
|
||||||
return 0;
|
return 0;
|
||||||
hd = tablehead(sum, table);
|
hd = tablehead(hash, table);
|
||||||
for(p = hd->next; p; p = p->next){
|
for(p = hd->next; p; p = p->next){
|
||||||
if(memcmp(sum, p->sha1, SHA1dlen) == 0)
|
if(p->len == len && memcmp(hash, p->hash, len) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
if(p == hd)
|
if(p == hd)
|
||||||
break;
|
break;
|
||||||
|
@ -43,14 +43,51 @@ okThumbprint(uchar *sum, Thumbprint *table)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
okCertificate(uchar *cert, int len, Thumbprint *table)
|
||||||
|
{
|
||||||
|
uchar hash[SHA2_256dlen];
|
||||||
|
char thumb[2*SHA2_256dlen+1];
|
||||||
|
|
||||||
|
if(table == nil){
|
||||||
|
werrstr("no thumbprints provided");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(cert == nil || len <= 0){
|
||||||
|
werrstr("no certificate provided");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1(cert, len, hash, nil);
|
||||||
|
if(okThumbprint(hash, SHA1dlen, table))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
sha2_256(cert, len, hash, nil);
|
||||||
|
if(okThumbprint(hash, SHA2_256dlen, table))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
len = enc64(thumb, sizeof(thumb), hash, SHA2_256dlen);
|
||||||
|
while(len > 0 && thumb[len-1] == '=')
|
||||||
|
len--;
|
||||||
|
thumb[len] = '\0';
|
||||||
|
werrstr("sha256=%s", thumb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
loadThumbprints(char *file, Thumbprint *table, Thumbprint *crltab)
|
loadThumbprints(char *file, char *tag, Thumbprint *table, Thumbprint *crltab, int depth)
|
||||||
{
|
{
|
||||||
Thumbprint *hd, *entry;
|
Thumbprint *hd, *entry;
|
||||||
char *line, *field[50];
|
char *line, *field[50];
|
||||||
uchar sum[SHA1dlen];
|
uchar hash[SHA2_256dlen];
|
||||||
Biobuf *bin;
|
Biobuf *bin;
|
||||||
|
int len, n;
|
||||||
|
|
||||||
|
if(depth > 8){
|
||||||
|
werrstr("too many includes, last file %s", file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if(access(file, AEXIST) < 0)
|
if(access(file, AEXIST) < 0)
|
||||||
return 0; /* not an error */
|
return 0; /* not an error */
|
||||||
if((bin = Bopen(file, OREAD)) == nil)
|
if((bin = Bopen(file, OREAD)) == nil)
|
||||||
|
@ -59,20 +96,30 @@ loadThumbprints(char *file, Thumbprint *table, Thumbprint *crltab)
|
||||||
if(tokenize(line, field, nelem(field)) < 2)
|
if(tokenize(line, field, nelem(field)) < 2)
|
||||||
continue;
|
continue;
|
||||||
if(strcmp(field[0], "#include") == 0){
|
if(strcmp(field[0], "#include") == 0){
|
||||||
if(loadThumbprints(field[1], table, crltab) < 0)
|
if(loadThumbprints(field[1], tag, table, crltab, depth+1) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(strcmp(field[0], "x509") != 0 || strncmp(field[1], "sha1=", 5) != 0)
|
if(strcmp(field[0], tag) != 0)
|
||||||
continue;
|
continue;
|
||||||
field[1] += 5;
|
if(strncmp(field[1], "sha1=", 5) == 0){
|
||||||
if(dec16(sum, SHA1dlen, field[1], strlen(field[1])) != SHA1dlen){
|
field[1] += 5;
|
||||||
werrstr("malformed x509 entry in %s: %s", file, field[1]);
|
len = SHA1dlen;
|
||||||
|
} else if(strncmp(field[1], "sha256=", 7) == 0){
|
||||||
|
field[1] += 7;
|
||||||
|
len = SHA2_256dlen;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
n = strlen(field[1]);
|
||||||
|
if((n != len*2 || dec16(hash, len, field[1], n) != len)
|
||||||
|
&& dec64(hash, len, field[1], n) != len){
|
||||||
|
werrstr("malformed %s entry in %s: %s", tag, file, field[1]);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if(crltab && okThumbprint(sum, crltab))
|
if(crltab && okThumbprint(hash, len, crltab))
|
||||||
continue;
|
continue;
|
||||||
hd = tablehead(sum, table);
|
hd = tablehead(hash, table);
|
||||||
if(hd->next == nil)
|
if(hd->next == nil)
|
||||||
entry = hd;
|
entry = hd;
|
||||||
else {
|
else {
|
||||||
|
@ -81,7 +128,8 @@ loadThumbprints(char *file, Thumbprint *table, Thumbprint *crltab)
|
||||||
entry->next = hd->next;
|
entry->next = hd->next;
|
||||||
}
|
}
|
||||||
hd->next = entry;
|
hd->next = entry;
|
||||||
memcpy(entry->sha1, sum, SHA1dlen);
|
entry->len = len;
|
||||||
|
memcpy(entry->hash, hash, len);
|
||||||
}
|
}
|
||||||
Bterm(bin);
|
Bterm(bin);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -92,7 +140,7 @@ err:
|
||||||
}
|
}
|
||||||
|
|
||||||
Thumbprint *
|
Thumbprint *
|
||||||
initThumbprints(char *ok, char *crl)
|
initThumbprints(char *ok, char *crl, char *tag)
|
||||||
{
|
{
|
||||||
Thumbprint *table, *crltab;
|
Thumbprint *table, *crltab;
|
||||||
|
|
||||||
|
@ -101,13 +149,13 @@ initThumbprints(char *ok, char *crl)
|
||||||
if((crltab = malloc(ThumbTab * sizeof(*crltab))) == nil)
|
if((crltab = malloc(ThumbTab * sizeof(*crltab))) == nil)
|
||||||
goto err;
|
goto err;
|
||||||
memset(crltab, 0, ThumbTab * sizeof(*crltab));
|
memset(crltab, 0, ThumbTab * sizeof(*crltab));
|
||||||
if(loadThumbprints(crl, crltab, nil) < 0)
|
if(loadThumbprints(crl, tag, crltab, nil, 0) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if((table = malloc(ThumbTab * sizeof(*table))) == nil)
|
if((table = malloc(ThumbTab * sizeof(*table))) == nil)
|
||||||
goto err;
|
goto err;
|
||||||
memset(table, 0, ThumbTab * sizeof(*table));
|
memset(table, 0, ThumbTab * sizeof(*table));
|
||||||
if(loadThumbprints(ok, table, crltab) < 0){
|
if(loadThumbprints(ok, tag, table, crltab, 0) < 0){
|
||||||
freeThumbprints(table);
|
freeThumbprints(table);
|
||||||
table = nil;
|
table = nil;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue