mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 12:54:27 +00:00
Update libsecureboot
Preparation for updating bearssl, pull in updates to libsecureboot. o fix handling of some out-of-memory cases o allow more control over reporting of Verified/Unverified files. this helps boot time when console output is slow o recheck verbose/debug level after reading any unverified file o more debug support for vectx o hash_string to support fake stat for tftp o tests/tvo add -v to simply verify signatures o vets.c allow for HAVE_BR_X509_TIME_CHECK which will greatly simplify verification in loader o report date when certificate fails validity period checks Reviewed by: stevek Sponsored by: Juniper Networks, Inc.
This commit is contained in:
parent
43d5661a9d
commit
666554111a
|
@ -48,8 +48,11 @@ unsigned char * read_file(const char *, size_t *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int DebugVe;
|
extern int DebugVe;
|
||||||
|
extern int VerifyFlags;
|
||||||
|
|
||||||
|
#ifndef DEBUG_PRINTF
|
||||||
#define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x
|
#define DEBUG_PRINTF(n, x) if (DebugVe >= n) printf x
|
||||||
|
#endif
|
||||||
|
|
||||||
int ve_trust_init(void);
|
int ve_trust_init(void);
|
||||||
size_t ve_trust_anchors_add_buf(unsigned char *, size_t);
|
size_t ve_trust_anchors_add_buf(unsigned char *, size_t);
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
|
||||||
* $FreeBSD$
|
|
||||||
*/
|
*/
|
||||||
#ifndef _VERIFY_FILE_H_
|
#ifndef _VERIFY_FILE_H_
|
||||||
#define _VERIFY_FILE_H_
|
#define _VERIFY_FILE_H_
|
||||||
|
@ -37,6 +35,11 @@
|
||||||
#define VE_UNVERIFIED_OK 0 /* not verified but that's ok */
|
#define VE_UNVERIFIED_OK 0 /* not verified but that's ok */
|
||||||
#define VE_NOT_VERIFYING 2 /* we are not verifying */
|
#define VE_NOT_VERIFYING 2 /* we are not verifying */
|
||||||
|
|
||||||
|
/* suitable buf size for hash_string */
|
||||||
|
#ifndef SHA_DIGEST_LENGTH
|
||||||
|
# define SHA_DIGEST_LENGTH 20
|
||||||
|
#endif
|
||||||
|
|
||||||
struct stat;
|
struct stat;
|
||||||
|
|
||||||
int verify_prep(int, const char *, off_t, struct stat *, const char *);
|
int verify_prep(int, const char *, off_t, struct stat *, const char *);
|
||||||
|
@ -47,8 +50,12 @@ int ve_status_get(int);
|
||||||
int load_manifest(const char *, const char *, const char *, struct stat *);
|
int load_manifest(const char *, const char *, const char *, struct stat *);
|
||||||
int pass_manifest(const char *, const char *);
|
int pass_manifest(const char *, const char *);
|
||||||
int pass_manifest_export_envs(void);
|
int pass_manifest_export_envs(void);
|
||||||
|
void verify_report(const char *, int, int, struct stat *);
|
||||||
int verify_file(int, const char *, off_t, int, const char *);
|
int verify_file(int, const char *, off_t, int, const char *);
|
||||||
void verify_pcr_export(void);
|
void verify_pcr_export(void);
|
||||||
|
int hash_string(char *s, size_t n, char *buf, size_t bufsz);
|
||||||
|
int is_verified(struct stat *);
|
||||||
|
void add_verify_status(struct stat *, int);
|
||||||
|
|
||||||
struct vectx;
|
struct vectx;
|
||||||
struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *, const char *);
|
struct vectx* vectx_open(int, const char *, off_t, struct stat *, int *, const char *);
|
||||||
|
|
|
@ -369,7 +369,7 @@ openpgp_verify(const char *filename,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
if ((flags & 1))
|
if ((flags & VEF_VERBOSE))
|
||||||
printf("Verified %s signed by %s\n",
|
printf("Verified %s signed by %s\n",
|
||||||
filename,
|
filename,
|
||||||
key->user ? key->user->name : "someone");
|
key->user ? key->user->name : "someone");
|
||||||
|
@ -447,7 +447,7 @@ openpgp_verify_file(const char *filename, unsigned char *fdata, size_t nbytes)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
sdata = read_file(sname, &sz);
|
sdata = read_file(sname, &sz);
|
||||||
return (openpgp_verify(filename, fdata, nbytes, sdata, sz, 1));
|
return (openpgp_verify(filename, fdata, nbytes, sdata, sz, VerifyFlags));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -34,20 +34,22 @@ read_fd(int fd, size_t len)
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
buf = malloc(len + 1);
|
buf = malloc(len + 1);
|
||||||
for (x = 0, m = len; m > 0; ) {
|
if (buf != NULL) {
|
||||||
n = read(fd, &buf[x], m);
|
for (x = 0, m = len; m > 0; ) {
|
||||||
if (n < 0)
|
n = read(fd, &buf[x], m);
|
||||||
break;
|
if (n < 0)
|
||||||
if (n > 0) {
|
break;
|
||||||
m -= n;
|
if (n > 0) {
|
||||||
x += n;
|
m -= n;
|
||||||
|
x += n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (m == 0) {
|
||||||
|
buf[len] = '\0';
|
||||||
|
return (buf);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
if (m == 0) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
return (buf);
|
|
||||||
}
|
|
||||||
free(buf);
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +67,16 @@ read_file(const char *path, size_t *len)
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
ucp = read_fd(fd, st.st_size);
|
ucp = read_fd(fd, st.st_size);
|
||||||
close(fd);
|
close(fd);
|
||||||
if (len != NULL && ucp != NULL)
|
if (ucp != NULL) {
|
||||||
*len = st.st_size;
|
if (len != NULL)
|
||||||
|
*len = st.st_size;
|
||||||
|
}
|
||||||
|
#ifdef _STANDALONE
|
||||||
|
else
|
||||||
|
printf("%s: out of memory! %lu\n", __func__,
|
||||||
|
(unsigned long)len);
|
||||||
|
#endif
|
||||||
|
|
||||||
return (ucp);
|
return (ucp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,12 @@ __FBSDID("$FreeBSD$");
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <verify_file.h>
|
#include <verify_file.h>
|
||||||
|
|
||||||
|
/* keep clang quiet */
|
||||||
|
extern char *Destdir;
|
||||||
|
extern size_t DestdirLen;
|
||||||
|
extern char *Skip;
|
||||||
|
extern time_t ve_utc;
|
||||||
|
|
||||||
size_t DestdirLen;
|
size_t DestdirLen;
|
||||||
char *Destdir;
|
char *Destdir;
|
||||||
char *Skip;
|
char *Skip;
|
||||||
|
@ -42,9 +48,9 @@ main(int argc, char *argv[])
|
||||||
int fd;
|
int fd;
|
||||||
int c;
|
int c;
|
||||||
int Vflag;
|
int Vflag;
|
||||||
|
int vflag;
|
||||||
char *cp;
|
char *cp;
|
||||||
char *prefix;
|
char *prefix;
|
||||||
char *destdir;
|
|
||||||
|
|
||||||
Destdir = NULL;
|
Destdir = NULL;
|
||||||
DestdirLen = 0;
|
DestdirLen = 0;
|
||||||
|
@ -52,10 +58,10 @@ main(int argc, char *argv[])
|
||||||
Skip = NULL;
|
Skip = NULL;
|
||||||
|
|
||||||
n = ve_trust_init();
|
n = ve_trust_init();
|
||||||
printf("Trust %d\n", n);
|
|
||||||
Vflag = 0;
|
Vflag = 0;
|
||||||
|
vflag = 0;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "D:dp:s:T:V")) != -1) {
|
while ((c = getopt(argc, argv, "D:dp:s:T:u:Vv")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'D':
|
case 'D':
|
||||||
Destdir = optarg;
|
Destdir = optarg;
|
||||||
|
@ -77,17 +83,25 @@ main(int argc, char *argv[])
|
||||||
case 'V':
|
case 'V':
|
||||||
Vflag = 1;
|
Vflag = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
vflag = 1;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
ve_utc = (time_t)atoi(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
errx(1, "unknown option: -%c", c);
|
errx(1, "unknown option: -%c", c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!vflag) {
|
||||||
|
printf("Trust %d\n", n);
|
||||||
#ifdef VE_PCR_SUPPORT
|
#ifdef VE_PCR_SUPPORT
|
||||||
ve_pcr_updating_set(1);
|
ve_pcr_updating_set(1);
|
||||||
#endif
|
#endif
|
||||||
ve_self_tests();
|
ve_self_tests();
|
||||||
|
}
|
||||||
for ( ; optind < argc; optind++) {
|
for ( ; optind < argc; optind++) {
|
||||||
if (Vflag) {
|
if (Vflag) {
|
||||||
/*
|
/*
|
||||||
|
@ -113,8 +127,9 @@ main(int argc, char *argv[])
|
||||||
if (cp) {
|
if (cp) {
|
||||||
printf("Verified: %s: %.28s...\n",
|
printf("Verified: %s: %.28s...\n",
|
||||||
argv[optind], cp);
|
argv[optind], cp);
|
||||||
fingerprint_info_add(argv[optind],
|
if (!vflag)
|
||||||
prefix, Skip, cp, NULL);
|
fingerprint_info_add(argv[optind],
|
||||||
|
prefix, Skip, cp, NULL);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: %s\n",
|
fprintf(stderr, "%s: %s\n",
|
||||||
argv[optind], ve_error_get());
|
argv[optind], ve_error_get());
|
||||||
|
@ -126,8 +141,9 @@ main(int argc, char *argv[])
|
||||||
if (cp) {
|
if (cp) {
|
||||||
printf("Verified: %s: %.28s...\n",
|
printf("Verified: %s: %.28s...\n",
|
||||||
argv[optind], cp);
|
argv[optind], cp);
|
||||||
fingerprint_info_add(argv[optind],
|
if (!vflag)
|
||||||
prefix, Skip, cp, NULL);
|
fingerprint_info_add(argv[optind],
|
||||||
|
prefix, Skip, cp, NULL);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%s: %s\n",
|
fprintf(stderr, "%s: %s\n",
|
||||||
argv[optind], ve_error_get());
|
argv[optind], ve_error_get());
|
||||||
|
@ -150,7 +166,8 @@ main(int argc, char *argv[])
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int error;
|
int error;
|
||||||
size_t off, n;
|
off_t off;
|
||||||
|
size_t nb;
|
||||||
|
|
||||||
fstat(fd, &st);
|
fstat(fd, &st);
|
||||||
lseek(fd, 0, SEEK_SET);
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
@ -167,10 +184,10 @@ main(int argc, char *argv[])
|
||||||
/* we can seek backwards! */
|
/* we can seek backwards! */
|
||||||
off = vectx_lseek(vp, off/2, SEEK_SET);
|
off = vectx_lseek(vp, off/2, SEEK_SET);
|
||||||
if (off < st.st_size) {
|
if (off < st.st_size) {
|
||||||
n = vectx_read(vp, buf,
|
nb = vectx_read(vp, buf,
|
||||||
sizeof(buf));
|
sizeof(buf));
|
||||||
if (n > 0)
|
if (nb > 0)
|
||||||
off += n;
|
off += nb;
|
||||||
}
|
}
|
||||||
off = vectx_lseek(vp, 0, SEEK_END);
|
off = vectx_lseek(vp, 0, SEEK_END);
|
||||||
/* repeating that should be harmless */
|
/* repeating that should be harmless */
|
||||||
|
|
|
@ -32,6 +32,11 @@ __FBSDID("$FreeBSD$");
|
||||||
#undef _KERNEL
|
#undef _KERNEL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef VECTX_DEBUG
|
||||||
|
static int vectx_debug = VECTX_DEBUG;
|
||||||
|
# define DEBUG_PRINTF(n, x) if (vectx_debug >= n) printf x
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "libsecureboot-priv.h"
|
#include "libsecureboot-priv.h"
|
||||||
#include <verify_file.h>
|
#include <verify_file.h>
|
||||||
|
|
||||||
|
@ -52,10 +57,11 @@ struct vectx {
|
||||||
const char *vec_want; /* hash value we want */
|
const char *vec_want; /* hash value we want */
|
||||||
off_t vec_off; /* current offset */
|
off_t vec_off; /* current offset */
|
||||||
off_t vec_hashed; /* where we have hashed to */
|
off_t vec_hashed; /* where we have hashed to */
|
||||||
size_t vec_size; /* size of path */
|
off_t vec_size; /* size of path */
|
||||||
size_t vec_hashsz; /* size of hash */
|
size_t vec_hashsz; /* size of hash */
|
||||||
int vec_fd; /* file descriptor */
|
int vec_fd; /* file descriptor */
|
||||||
int vec_status; /* verification status */
|
int vec_status; /* verification status */
|
||||||
|
int vec_closing; /* we are closing */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,6 +131,7 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp,
|
||||||
ctx->vec_want = NULL;
|
ctx->vec_want = NULL;
|
||||||
ctx->vec_status = 0;
|
ctx->vec_status = 0;
|
||||||
ctx->vec_hashsz = hashsz = 0;
|
ctx->vec_hashsz = hashsz = 0;
|
||||||
|
ctx->vec_closing = 0;
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
/* we are not verifying this */
|
/* we are not verifying this */
|
||||||
|
@ -229,6 +236,12 @@ vectx_read(struct vectx *ctx, void *buf, size_t nbytes)
|
||||||
x = nbytes - off;
|
x = nbytes - off;
|
||||||
x = MIN(PAGE_SIZE, x);
|
x = MIN(PAGE_SIZE, x);
|
||||||
d = n = read(ctx->vec_fd, &bp[off], x);
|
d = n = read(ctx->vec_fd, &bp[off], x);
|
||||||
|
if (ctx->vec_closing && n < x) {
|
||||||
|
DEBUG_PRINTF(3,
|
||||||
|
("%s: read %d off=%ld hashed=%ld size=%ld\n",
|
||||||
|
__func__, n, (long)ctx->vec_off,
|
||||||
|
(long)ctx->vec_hashed, (long)ctx->vec_size));
|
||||||
|
}
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
return (n);
|
return (n);
|
||||||
}
|
}
|
||||||
|
@ -242,6 +255,12 @@ vectx_read(struct vectx *ctx, void *buf, size_t nbytes)
|
||||||
ctx->vec_off += x;
|
ctx->vec_off += x;
|
||||||
}
|
}
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
|
if (ctx->vec_closing && d < PAGE_SIZE) {
|
||||||
|
DEBUG_PRINTF(3,
|
||||||
|
("%s: update %ld + %d\n",
|
||||||
|
__func__,
|
||||||
|
(long)ctx->vec_hashed, d));
|
||||||
|
}
|
||||||
ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], d);
|
ctx->vec_md->update(&ctx->vec_ctx.vtable, &bp[off], d);
|
||||||
off += d;
|
off += d;
|
||||||
ctx->vec_off += d;
|
ctx->vec_off += d;
|
||||||
|
@ -286,7 +305,14 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence)
|
||||||
/*
|
/*
|
||||||
* Convert whence to SEEK_SET
|
* Convert whence to SEEK_SET
|
||||||
*/
|
*/
|
||||||
|
DEBUG_PRINTF(3,
|
||||||
|
("%s(%s, %ld, %d)\n", __func__, ctx->vec_path, (long)off, whence));
|
||||||
if (whence == SEEK_END && off <= 0) {
|
if (whence == SEEK_END && off <= 0) {
|
||||||
|
if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) {
|
||||||
|
DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n",
|
||||||
|
__func__,
|
||||||
|
(long)(ctx->vec_size - ctx->vec_hashed)));
|
||||||
|
}
|
||||||
whence = SEEK_SET;
|
whence = SEEK_SET;
|
||||||
off += ctx->vec_size;
|
off += ctx->vec_size;
|
||||||
} else if (whence == SEEK_CUR) {
|
} else if (whence == SEEK_CUR) {
|
||||||
|
@ -294,12 +320,22 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence)
|
||||||
off += ctx->vec_off;
|
off += ctx->vec_off;
|
||||||
}
|
}
|
||||||
if (whence != SEEK_SET ||
|
if (whence != SEEK_SET ||
|
||||||
(size_t)off > ctx->vec_size) {
|
off > ctx->vec_size) {
|
||||||
printf("ERROR: %s: unsupported operation: whence=%d off=%lld -> %lld\n",
|
printf("ERROR: %s: unsupported operation: whence=%d off=%ld -> %ld\n",
|
||||||
__func__, whence, (long long)ctx->vec_off, (long long)off);
|
__func__, whence, (long)ctx->vec_off, (long)off);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
if (off < ctx->vec_hashed) {
|
if (off < ctx->vec_hashed) {
|
||||||
|
#ifdef _STANDALONE
|
||||||
|
struct open_file *f = fd2open_file(ctx->vec_fd);
|
||||||
|
|
||||||
|
if (f != NULL &&
|
||||||
|
strncmp(f->f_ops->fs_name, "tftp", 4) == 0) {
|
||||||
|
/* we cannot rewind if we've hashed much of the file */
|
||||||
|
if (ctx->vec_hashed > ctx->vec_size / 5)
|
||||||
|
return (-1); /* refuse! */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* seeking backwards! just do it */
|
/* seeking backwards! just do it */
|
||||||
ctx->vec_off = lseek(ctx->vec_fd, off, whence);
|
ctx->vec_off = lseek(ctx->vec_fd, off, whence);
|
||||||
return (ctx->vec_off);
|
return (ctx->vec_off);
|
||||||
|
@ -337,6 +373,7 @@ vectx_close(struct vectx *ctx, int severity, const char *caller)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
ctx->vec_closing = 1;
|
||||||
if (ctx->vec_hashsz == 0) {
|
if (ctx->vec_hashsz == 0) {
|
||||||
rc = ctx->vec_status;
|
rc = ctx->vec_status;
|
||||||
} else {
|
} else {
|
||||||
|
@ -356,16 +393,13 @@ vectx_close(struct vectx *ctx, int severity, const char *caller)
|
||||||
DEBUG_PRINTF(2,
|
DEBUG_PRINTF(2,
|
||||||
("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n",
|
("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n",
|
||||||
caller,ctx->vec_path, rc, severity));
|
caller,ctx->vec_path, rc, severity));
|
||||||
|
verify_report(ctx->vec_path, severity, rc, NULL);
|
||||||
if (rc == VE_FINGERPRINT_WRONG) {
|
if (rc == VE_FINGERPRINT_WRONG) {
|
||||||
printf("Unverified: %s\n", ve_error_get());
|
|
||||||
#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX)
|
#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX)
|
||||||
/* we are generally called with VE_MUST */
|
/* we are generally called with VE_MUST */
|
||||||
if (severity > VE_WANT)
|
if (severity > VE_WANT)
|
||||||
panic("cannot continue");
|
panic("cannot continue");
|
||||||
#endif
|
#endif
|
||||||
} else if (severity > VE_WANT) {
|
|
||||||
printf("%serified %s\n", (rc <= 0) ? "Unv" : "V",
|
|
||||||
ctx->vec_path);
|
|
||||||
}
|
}
|
||||||
free(ctx);
|
free(ctx);
|
||||||
return ((rc < 0) ? rc : 0);
|
return ((rc < 0) ? rc : 0);
|
||||||
|
|
|
@ -77,6 +77,13 @@ fingerprint_info_add(const char *filename, const char *prefix,
|
||||||
|
|
||||||
fingerprint_info_init();
|
fingerprint_info_init();
|
||||||
nfip = malloc(sizeof(struct fingerprint_info));
|
nfip = malloc(sizeof(struct fingerprint_info));
|
||||||
|
if (nfip == NULL) {
|
||||||
|
#ifdef _STANDALONE
|
||||||
|
printf("%s: out of memory! %lu\n", __func__,
|
||||||
|
(unsigned long)sizeof(struct fingerprint_info));
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (prefix) {
|
if (prefix) {
|
||||||
nfip->fi_prefix = strdup(prefix);
|
nfip->fi_prefix = strdup(prefix);
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,10 +122,9 @@ fingerprint_info_add(const char *filename, const char *prefix,
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
nfip->fi_dev = stp->st_dev;
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
nfip->fi_dev = 0;
|
nfip->fi_dev = 0;
|
||||||
#else
|
|
||||||
nfip->fi_dev = stp->st_dev;
|
|
||||||
#endif
|
#endif
|
||||||
nfip->fi_data = data;
|
nfip->fi_data = data;
|
||||||
nfip->fi_prefix_len = strlen(nfip->fi_prefix);
|
nfip->fi_prefix_len = strlen(nfip->fi_prefix);
|
||||||
|
@ -198,9 +204,10 @@ fingerprint_info_lookup(int fd, const char *path)
|
||||||
n = strlcpy(pbuf, path, sizeof(pbuf));
|
n = strlcpy(pbuf, path, sizeof(pbuf));
|
||||||
if (n >= sizeof(pbuf))
|
if (n >= sizeof(pbuf))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
#ifndef UNIT_TEST
|
|
||||||
if (fstat(fd, &st) == 0)
|
if (fstat(fd, &st) == 0)
|
||||||
dev = st.st_dev;
|
dev = st.st_dev;
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
dev = 0;
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* get the first entry - it will have longest prefix
|
* get the first entry - it will have longest prefix
|
||||||
|
|
|
@ -57,14 +57,27 @@ extern char *Skip;
|
||||||
* The extra slot is for tracking most recently opened.
|
* The extra slot is for tracking most recently opened.
|
||||||
*/
|
*/
|
||||||
#ifndef SOPEN_MAX
|
#ifndef SOPEN_MAX
|
||||||
#define SOPEN_MAX 64
|
#define SOPEN_MAX 64
|
||||||
#endif
|
#endif
|
||||||
static int ve_status[SOPEN_MAX+1];
|
static int ve_status[SOPEN_MAX+1];
|
||||||
static int ve_status_state;
|
static int ve_status_state;
|
||||||
struct verify_status;
|
struct verify_status;
|
||||||
struct verify_status *verified_files = NULL;
|
static struct verify_status *verified_files = NULL;
|
||||||
static int loaded_manifests = 0; /* have we loaded anything? */
|
static int loaded_manifests = 0; /* have we loaded anything? */
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VE_VERBOSE_SILENT, /* only report errors */
|
||||||
|
VE_VERBOSE_UNVERIFIED, /* all unverified files */
|
||||||
|
VE_VERBOSE_MUST, /* report VE_MUST */
|
||||||
|
VE_VERBOSE_ALL, /* report all */
|
||||||
|
VE_VERBOSE_DEBUG, /* extra noise */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef VE_VERBOSE_DEFAULT
|
||||||
|
# define VE_VERBOSE_DEFAULT VE_VERBOSE_MUST
|
||||||
|
#endif
|
||||||
|
static int Verbose = VE_VERBOSE_DEFAULT;
|
||||||
|
|
||||||
#define VE_STATUS_NONE 1
|
#define VE_STATUS_NONE 1
|
||||||
#define VE_STATUS_VALID 2
|
#define VE_STATUS_VALID 2
|
||||||
|
|
||||||
|
@ -138,11 +151,13 @@ add_verify_status(struct stat *stp, int status)
|
||||||
struct verify_status *vsp;
|
struct verify_status *vsp;
|
||||||
|
|
||||||
vsp = malloc(sizeof(struct verify_status));
|
vsp = malloc(sizeof(struct verify_status));
|
||||||
vsp->vs_next = verified_files;
|
if (vsp) {
|
||||||
vsp->vs_dev = stp->st_dev;
|
vsp->vs_next = verified_files;
|
||||||
vsp->vs_ino = stp->st_ino;
|
vsp->vs_dev = stp->st_dev;
|
||||||
vsp->vs_status = status;
|
vsp->vs_ino = stp->st_ino;
|
||||||
verified_files = vsp;
|
vsp->vs_status = status;
|
||||||
|
verified_files = vsp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,7 +188,7 @@ load_manifest(const char *name, const char *prefix,
|
||||||
}
|
}
|
||||||
/* loader has no sense of time */
|
/* loader has no sense of time */
|
||||||
ve_utc_set(stp->st_mtime);
|
ve_utc_set(stp->st_mtime);
|
||||||
content = (char *)verify_signed(name, VEF_VERBOSE);
|
content = (char *)verify_signed(name, VerifyFlags);
|
||||||
if (content) {
|
if (content) {
|
||||||
#ifdef UNIT_TEST
|
#ifdef UNIT_TEST
|
||||||
if (DestdirLen > 0 &&
|
if (DestdirLen > 0 &&
|
||||||
|
@ -216,6 +231,11 @@ find_manifest(const char *name)
|
||||||
rc = VE_FINGERPRINT_NONE;
|
rc = VE_FINGERPRINT_NONE;
|
||||||
for (tp = manifest_names; *tp; tp++) {
|
for (tp = manifest_names; *tp; tp++) {
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
|
snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
|
||||||
|
if (*tp[0] == '.') {
|
||||||
|
/* skip /../ */
|
||||||
|
if (prefix[0] == '\0' || prefix[1] == '\0')
|
||||||
|
continue;
|
||||||
|
}
|
||||||
DEBUG_PRINTF(5, ("looking for %s\n", buf));
|
DEBUG_PRINTF(5, ("looking for %s\n", buf));
|
||||||
if (stat(buf, &st) == 0 && st.st_size > 0) {
|
if (stat(buf, &st) == 0 && st.st_size > 0) {
|
||||||
#ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */
|
#ifdef MANIFEST_SKIP_ALWAYS /* very unlikely */
|
||||||
|
@ -243,20 +263,21 @@ find_manifest(const char *name)
|
||||||
#else
|
#else
|
||||||
# define ACCEPT_NO_FP_DEFAULT VE_MUST
|
# define ACCEPT_NO_FP_DEFAULT VE_MUST
|
||||||
#endif
|
#endif
|
||||||
#ifndef VE_VERBOSE_DEFAULT
|
|
||||||
# define VE_VERBOSE_DEFAULT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
severity_guess(const char *filename)
|
severity_guess(const char *filename)
|
||||||
{
|
{
|
||||||
const char *cp;
|
const char *cp;
|
||||||
|
|
||||||
/* Some files like *.conf and *.hints may be unsigned */
|
/*
|
||||||
|
* Some files like *.conf and *.hints may be unsigned,
|
||||||
|
* a *.tgz is expected to have its own signed manifest.
|
||||||
|
*/
|
||||||
if ((cp = strrchr(filename, '.'))) {
|
if ((cp = strrchr(filename, '.'))) {
|
||||||
if (strcmp(cp, ".conf") == 0 ||
|
if (strcmp(cp, ".conf") == 0 ||
|
||||||
strcmp(cp, ".cookie") == 0 ||
|
strcmp(cp, ".cookie") == 0 ||
|
||||||
strcmp(cp, ".hints") == 0)
|
strcmp(cp, ".hints") == 0 ||
|
||||||
|
strcmp(cp, ".tgz") == 0)
|
||||||
return (VE_TRY);
|
return (VE_TRY);
|
||||||
if (strcmp(cp, ".4th") == 0 ||
|
if (strcmp(cp, ".4th") == 0 ||
|
||||||
strcmp(cp, ".lua") == 0 ||
|
strcmp(cp, ".lua") == 0 ||
|
||||||
|
@ -270,15 +291,14 @@ static int Verifying = -1; /* 0 if not verifying */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
verify_tweak(int fd, off_t off, struct stat *stp,
|
verify_tweak(int fd, off_t off, struct stat *stp,
|
||||||
char *tweak, int *accept_no_fp,
|
char *tweak, int *accept_no_fp)
|
||||||
int *verbose)
|
|
||||||
{
|
{
|
||||||
if (strcmp(tweak, "off") == 0) {
|
if (strcmp(tweak, "off") == 0) {
|
||||||
Verifying = 0;
|
Verifying = 0;
|
||||||
} else if (strcmp(tweak, "strict") == 0) {
|
} else if (strcmp(tweak, "strict") == 0) {
|
||||||
/* anything caller wants verified must be */
|
/* anything caller wants verified must be */
|
||||||
*accept_no_fp = VE_WANT;
|
*accept_no_fp = VE_WANT;
|
||||||
*verbose = 1; /* warn of anything unverified */
|
Verbose = VE_VERBOSE_ALL;
|
||||||
/* treat self test failure as fatal */
|
/* treat self test failure as fatal */
|
||||||
if (!ve_self_tests()) {
|
if (!ve_self_tests()) {
|
||||||
panic("verify self tests failed");
|
panic("verify self tests failed");
|
||||||
|
@ -290,9 +310,13 @@ verify_tweak(int fd, off_t off, struct stat *stp,
|
||||||
/* best effort: always accept no fp */
|
/* best effort: always accept no fp */
|
||||||
*accept_no_fp = VE_MUST + 1;
|
*accept_no_fp = VE_MUST + 1;
|
||||||
} else if (strcmp(tweak, "verbose") == 0) {
|
} else if (strcmp(tweak, "verbose") == 0) {
|
||||||
*verbose = 1;
|
Verbose = VE_VERBOSE_ALL;
|
||||||
} else if (strcmp(tweak, "quiet") == 0) {
|
} else if (strcmp(tweak, "quiet") == 0) {
|
||||||
*verbose = 0;
|
Verbose = VE_VERBOSE_UNVERIFIED;
|
||||||
|
VerifyFlags = 0;
|
||||||
|
} else if (strcmp(tweak, "silent") == 0) {
|
||||||
|
Verbose = VE_VERBOSE_SILENT;
|
||||||
|
VerifyFlags = 0;
|
||||||
} else if (strncmp(tweak, "trust", 5) == 0) {
|
} else if (strncmp(tweak, "trust", 5) == 0) {
|
||||||
/* content is trust anchor to add or revoke */
|
/* content is trust anchor to add or revoke */
|
||||||
unsigned char *ucp;
|
unsigned char *ucp;
|
||||||
|
@ -338,6 +362,68 @@ getenv_int(const char *var, int def)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief report verification status
|
||||||
|
*
|
||||||
|
* @param[in] path
|
||||||
|
* path we attempted to verify
|
||||||
|
*
|
||||||
|
* @param[in] severity
|
||||||
|
* indicator of how to handle case of missing fingerprint
|
||||||
|
*
|
||||||
|
* @param[in] status
|
||||||
|
* result of verification
|
||||||
|
* 0 not a file to be verified, > 0 success, < 0 error
|
||||||
|
*
|
||||||
|
* @param[in] stp
|
||||||
|
* pointer to struct stat, used in extra info to be output
|
||||||
|
*
|
||||||
|
* The output is dictated by combinations of the above and the setting
|
||||||
|
* of Verbose:
|
||||||
|
*
|
||||||
|
* VE_VERBOSE_SILENT
|
||||||
|
* report only failure to verify if severity is VE_WANT or higher.
|
||||||
|
*
|
||||||
|
* VE_VERBOSE_UNVERIFIED
|
||||||
|
* report any unverified file.
|
||||||
|
*
|
||||||
|
* VE_VERBOSE_MUST
|
||||||
|
* report verified only if severity is VE_MUST or higher.
|
||||||
|
*
|
||||||
|
* VE_VERBOSE_ALL
|
||||||
|
* report all verified files.
|
||||||
|
*
|
||||||
|
* VE_VERBOSE_DEBUG
|
||||||
|
* if stp is not NULL report dev,inode for path
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
verify_report(const char *path, int severity, int status, struct stat *stp)
|
||||||
|
{
|
||||||
|
if (status < 0 || status == VE_FINGERPRINT_IGNORE) {
|
||||||
|
if (Verbose >= VE_VERBOSE_UNVERIFIED || severity > VE_TRY ||
|
||||||
|
status <= VE_FINGERPRINT_WRONG) {
|
||||||
|
if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
|
||||||
|
printf("Unverified %s %llu,%llu\n",
|
||||||
|
ve_error_get(),
|
||||||
|
(long long)stp->st_dev,
|
||||||
|
(long long)stp->st_ino);
|
||||||
|
else
|
||||||
|
printf("Unverified %s\n", ve_error_get());
|
||||||
|
}
|
||||||
|
} else if (status > 0 && Verbose >= VE_VERBOSE_MUST) {
|
||||||
|
if (severity >= VE_MUST || Verbose >= VE_VERBOSE_ALL) {
|
||||||
|
if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
|
||||||
|
printf("Unverified %s %llu,%llu\n",
|
||||||
|
path,
|
||||||
|
(long long)stp->st_dev,
|
||||||
|
(long long)stp->st_ino);
|
||||||
|
else
|
||||||
|
printf("Verified %s\n", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief prepare to verify an open file
|
* @brief prepare to verify an open file
|
||||||
*
|
*
|
||||||
|
@ -358,9 +444,6 @@ verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
|
||||||
|
|
||||||
if (Verifying < 0) {
|
if (Verifying < 0) {
|
||||||
Verifying = ve_trust_init();
|
Verifying = ve_trust_init();
|
||||||
#ifndef UNIT_TEST
|
|
||||||
ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
|
|
||||||
#endif
|
|
||||||
/* initialize ve_status with default result */
|
/* initialize ve_status with default result */
|
||||||
rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
|
rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
|
||||||
ve_status_set(0, rc);
|
ve_status_set(0, rc);
|
||||||
|
@ -377,9 +460,9 @@ verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
DEBUG_PRINTF(2,
|
DEBUG_PRINTF(2,
|
||||||
("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n",
|
("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%llu\n",
|
||||||
caller, fd, filename, (long long)off, (long long)stp->st_dev,
|
caller, fd, filename, (long long)off, (long long)stp->st_dev,
|
||||||
(long long)stp->st_ino));
|
(unsigned long long)stp->st_ino));
|
||||||
rc = is_verified(stp);
|
rc = is_verified(stp);
|
||||||
DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc));
|
DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc));
|
||||||
if (rc == VE_NOT_CHECKED) {
|
if (rc == VE_NOT_CHECKED) {
|
||||||
|
@ -421,23 +504,26 @@ int
|
||||||
verify_file(int fd, const char *filename, off_t off, int severity,
|
verify_file(int fd, const char *filename, off_t off, int severity,
|
||||||
const char *caller)
|
const char *caller)
|
||||||
{
|
{
|
||||||
static int once;
|
static int check_verbose = 1;
|
||||||
static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
|
static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
|
||||||
static int verbose = VE_VERBOSE_DEFAULT;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *cp;
|
char *cp;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (check_verbose) {
|
||||||
|
check_verbose = 0;
|
||||||
|
Verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
|
||||||
|
VerifyFlags = getenv_int("VE_VERIFY_FLAGS", VEF_VERBOSE);
|
||||||
|
#ifndef UNIT_TEST
|
||||||
|
ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
rc = verify_prep(fd, filename, off, &st, caller);
|
rc = verify_prep(fd, filename, off, &st, caller);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
if (!once) {
|
|
||||||
once++;
|
|
||||||
verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
|
if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
|
||||||
if (severity <= VE_GUESS)
|
if (severity <= VE_GUESS)
|
||||||
severity = severity_guess(filename);
|
severity = severity_guess(filename);
|
||||||
|
@ -455,26 +541,16 @@ verify_file(int fd, const char *filename, off_t off, int severity,
|
||||||
filename += DestdirLen;
|
filename += DestdirLen;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((rc = verify_fd(fd, filename, off, &st)) >= 0) {
|
rc = verify_fd(fd, filename, off, &st);
|
||||||
if (verbose || severity > VE_WANT) {
|
verify_report(filename, severity, rc, &st);
|
||||||
#if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
|
if (rc >= 0) {
|
||||||
printf("%serified %s %llu,%llu\n",
|
|
||||||
(rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
|
|
||||||
filename,
|
|
||||||
(long long)st.st_dev, (long long)st.st_ino);
|
|
||||||
#else
|
|
||||||
printf("%serified %s\n",
|
|
||||||
(rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
|
|
||||||
filename);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (severity < VE_MUST) { /* not a kernel or module */
|
if (severity < VE_MUST) { /* not a kernel or module */
|
||||||
if ((cp = strrchr(filename, '/'))) {
|
if ((cp = strrchr(filename, '/'))) {
|
||||||
cp++;
|
cp++;
|
||||||
if (strncmp(cp, "loader.ve.", 10) == 0) {
|
if (strncmp(cp, "loader.ve.", 10) == 0) {
|
||||||
cp += 10;
|
cp += 10;
|
||||||
verify_tweak(fd, off, &st, cp,
|
verify_tweak(fd, off, &st, cp,
|
||||||
&accept_no_fp, &verbose);
|
&accept_no_fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,15 +558,17 @@ verify_file(int fd, const char *filename, off_t off, int severity,
|
||||||
ve_status_set(fd, rc);
|
ve_status_set(fd, rc);
|
||||||
return (rc);
|
return (rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (severity || verbose || rc == VE_FINGERPRINT_WRONG)
|
|
||||||
printf("Unverified: %s\n", ve_error_get());
|
|
||||||
if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
|
if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
|
||||||
rc = VE_UNVERIFIED_OK;
|
rc = VE_UNVERIFIED_OK;
|
||||||
else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
|
else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
|
||||||
rc = VE_UNVERIFIED_OK;
|
rc = VE_UNVERIFIED_OK;
|
||||||
|
|
||||||
add_verify_status(&st, rc);
|
add_verify_status(&st, rc);
|
||||||
|
|
||||||
|
/* recheck debug/verbose level next time we are called */
|
||||||
|
if (rc == VE_UNVERIFIED_OK) {
|
||||||
|
check_verbose = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef LOADER_VERIEXEC_TESTING
|
#ifdef LOADER_VERIEXEC_TESTING
|
||||||
else if (rc != VE_FINGERPRINT_WRONG) {
|
else if (rc != VE_FINGERPRINT_WRONG) {
|
||||||
|
@ -550,7 +628,7 @@ verify_pcr_export(void)
|
||||||
hlen += KENV_MVALLEN -
|
hlen += KENV_MVALLEN -
|
||||||
(hlen % KENV_MVALLEN);
|
(hlen % KENV_MVALLEN);
|
||||||
if (snprintf(mvallen, sizeof(mvallen),
|
if (snprintf(mvallen, sizeof(mvallen),
|
||||||
"%d", (int) hlen) < sizeof(mvallen))
|
"%d", (int) hlen) < (int)sizeof(mvallen))
|
||||||
setenv("kenv_mvallen", mvallen, 1);
|
setenv("kenv_mvallen", mvallen, 1);
|
||||||
}
|
}
|
||||||
free(hinfo);
|
free(hinfo);
|
||||||
|
@ -559,3 +637,37 @@ verify_pcr_export(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For tftp and http we need to hash pathname
|
||||||
|
* to be able to fake stat(2) data.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
hash_string(char *s, size_t n, char *buf, size_t bufsz)
|
||||||
|
{
|
||||||
|
br_hash_compat_context mctx;
|
||||||
|
const br_hash_class *md;
|
||||||
|
|
||||||
|
switch (bufsz) {
|
||||||
|
case br_sha1_SIZE:
|
||||||
|
md = &br_sha1_vtable;
|
||||||
|
break;
|
||||||
|
case br_sha256_SIZE:
|
||||||
|
md = &br_sha256_vtable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (bufsz < br_sha1_SIZE)
|
||||||
|
return -1;
|
||||||
|
md = &br_sha1_vtable;
|
||||||
|
bufsz = br_sha1_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (n == 0)
|
||||||
|
n = strlen(s);
|
||||||
|
md->init(&mctx.vtable);
|
||||||
|
md->update(&mctx.vtable, s, n);
|
||||||
|
md->out(&mctx.vtable, buf);
|
||||||
|
return bufsz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$");
|
||||||
# define TRUST_ANCHOR_STR ta_PEM
|
# define TRUST_ANCHOR_STR ta_PEM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define EPOCH_YEAR 1970
|
||||||
|
#define AVG_SECONDS_PER_YEAR 31556952L
|
||||||
#define SECONDS_PER_DAY 86400
|
#define SECONDS_PER_DAY 86400
|
||||||
#define SECONDS_PER_YEAR 365 * SECONDS_PER_DAY
|
#define SECONDS_PER_YEAR 365 * SECONDS_PER_DAY
|
||||||
#ifndef VE_UTC_MAX_JUMP
|
#ifndef VE_UTC_MAX_JUMP
|
||||||
|
@ -52,6 +54,11 @@ __FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
int DebugVe = 0;
|
int DebugVe = 0;
|
||||||
|
|
||||||
|
#ifndef VE_VERIFY_FLAGS
|
||||||
|
# define VE_VERIFY_FLAGS VEF_VERBOSE
|
||||||
|
#endif
|
||||||
|
int VerifyFlags = VE_VERIFY_FLAGS;
|
||||||
|
|
||||||
typedef VECTOR(br_x509_certificate) cert_list;
|
typedef VECTOR(br_x509_certificate) cert_list;
|
||||||
typedef VECTOR(hash_data) digest_list;
|
typedef VECTOR(hash_data) digest_list;
|
||||||
|
|
||||||
|
@ -109,8 +116,59 @@ ve_error_set(const char *fmt, ...)
|
||||||
return (rc);
|
return (rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The *approximate* date.
|
||||||
|
*
|
||||||
|
* When certificate verification fails for being
|
||||||
|
* expired or not yet valid, it helps to indicate
|
||||||
|
* our current date.
|
||||||
|
* Since libsa lacks strftime and gmtime,
|
||||||
|
* this simple implementation suffices.
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
gdate(char *buf, size_t bufsz, time_t clock)
|
||||||
|
{
|
||||||
|
int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
int year, y, m, d;
|
||||||
|
|
||||||
|
y = clock / AVG_SECONDS_PER_YEAR;
|
||||||
|
year = EPOCH_YEAR + y;
|
||||||
|
for (y = EPOCH_YEAR; y < year; y++) {
|
||||||
|
clock -= SECONDS_PER_YEAR;
|
||||||
|
if (isleap(y))
|
||||||
|
clock -= SECONDS_PER_DAY;
|
||||||
|
}
|
||||||
|
d = clock / SECONDS_PER_DAY;
|
||||||
|
for (m = 0; d > 1 && m < 12; m++) {
|
||||||
|
if (d > days[m]) {
|
||||||
|
d -= days[m];
|
||||||
|
if (m == 1 && d > 0 && isleap(year))
|
||||||
|
d--;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d++;
|
||||||
|
if (d > days[m]) {
|
||||||
|
d = 1;
|
||||||
|
m++;
|
||||||
|
if (m >= 12) {
|
||||||
|
year++;
|
||||||
|
m = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)snprintf(buf, bufsz, "%04d-%02d-%02d", year, m+1, d);
|
||||||
|
return(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* this is the time we use for verifying certs */
|
/* this is the time we use for verifying certs */
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
extern time_t ve_utc;
|
||||||
|
time_t ve_utc = 0;
|
||||||
|
#else
|
||||||
static time_t ve_utc = 0;
|
static time_t ve_utc = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
|
@ -372,6 +430,40 @@ ve_trust_init(void)
|
||||||
return (once);
|
return (once);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BR_X509_TIME_CHECK
|
||||||
|
static int
|
||||||
|
verify_time_cb(void *tctx,
|
||||||
|
uint32_t not_before_days, uint32_t not_before_seconds,
|
||||||
|
uint32_t not_after_days, uint32_t not_after_seconds)
|
||||||
|
{
|
||||||
|
time_t not_before;
|
||||||
|
time_t not_after;
|
||||||
|
int rc;
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
char date[12], nb_date[12], na_date[12];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
not_before = ((not_before_days - X509_DAYS_TO_UTC0) * SECONDS_PER_DAY) + not_before_seconds;
|
||||||
|
not_after = ((not_after_days - X509_DAYS_TO_UTC0) * SECONDS_PER_DAY) + not_after_seconds;
|
||||||
|
if (ve_utc < not_before)
|
||||||
|
rc = -1;
|
||||||
|
else if (ve_utc > not_after)
|
||||||
|
rc = 1;
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
#ifdef UNIT_TEST
|
||||||
|
printf("notBefore %s notAfter %s date %s rc %d\n",
|
||||||
|
gdate(nb_date, sizeof(nb_date), not_before),
|
||||||
|
gdate(na_date, sizeof(na_date), not_after),
|
||||||
|
gdate(date, sizeof(date), ve_utc), rc);
|
||||||
|
#endif
|
||||||
|
#if defined(_STANDALONE)
|
||||||
|
rc = 0; /* don't fail */
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if we can verify the certificate chain in "certs",
|
* if we can verify the certificate chain in "certs",
|
||||||
* return the public key and if "xcp" is !NULL the associated
|
* return the public key and if "xcp" is !NULL the associated
|
||||||
|
@ -425,14 +517,17 @@ verify_signer_xcs(br_x509_certificate *xcs,
|
||||||
#endif
|
#endif
|
||||||
br_x509_minimal_set_name_elements(&mc, elts, num_elts);
|
br_x509_minimal_set_name_elements(&mc, elts, num_elts);
|
||||||
|
|
||||||
#ifdef _STANDALONE
|
#ifdef HAVE_BR_X509_TIME_CHECK
|
||||||
|
br_x509_minimal_set_time_callback(&mc, NULL, verify_time_cb);
|
||||||
|
#else
|
||||||
|
#if defined(_STANDALONE) || defined(UNIT_TEST)
|
||||||
/*
|
/*
|
||||||
* Clock is probably bogus so we use ve_utc.
|
* Clock is probably bogus so we use ve_utc.
|
||||||
*/
|
*/
|
||||||
mc.days = (ve_utc / SECONDS_PER_DAY) + X509_DAYS_TO_UTC0;
|
mc.days = (ve_utc / SECONDS_PER_DAY) + X509_DAYS_TO_UTC0;
|
||||||
mc.seconds = (ve_utc % SECONDS_PER_DAY);
|
mc.seconds = (ve_utc % SECONDS_PER_DAY);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
mc.vtable->start_chain(&mc.vtable, NULL);
|
mc.vtable->start_chain(&mc.vtable, NULL);
|
||||||
for (u = 0; u < VEC_LEN(chain); u ++) {
|
for (u = 0; u < VEC_LEN(chain); u ++) {
|
||||||
xc = &VEC_ELT(chain, u);
|
xc = &VEC_ELT(chain, u);
|
||||||
|
@ -452,7 +547,17 @@ verify_signer_xcs(br_x509_certificate *xcs,
|
||||||
err = mc.vtable->end_chain(&mc.vtable);
|
err = mc.vtable->end_chain(&mc.vtable);
|
||||||
pk = NULL;
|
pk = NULL;
|
||||||
if (err) {
|
if (err) {
|
||||||
ve_error_set("Validation failed, err = %d", err);
|
char date[12];
|
||||||
|
|
||||||
|
switch (err) {
|
||||||
|
case 54:
|
||||||
|
ve_error_set("Validation failed, certificate not valid as of %s",
|
||||||
|
gdate(date, sizeof(date), ve_utc));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ve_error_set("Validation failed, err = %d", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
|
tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
|
||||||
if (tpk != NULL) {
|
if (tpk != NULL) {
|
||||||
|
@ -866,7 +971,7 @@ verify_sig(const char *sigfile, int flags)
|
||||||
if (!ucp) {
|
if (!ucp) {
|
||||||
printf("Unverified %s (%s)\n", pbuf,
|
printf("Unverified %s (%s)\n", pbuf,
|
||||||
cn.status ? cn_buf : "unknown");
|
cn.status ? cn_buf : "unknown");
|
||||||
} else if ((flags & 1) != 0) {
|
} else if ((flags & VEF_VERBOSE) != 0) {
|
||||||
printf("Verified %s signed by %s\n", pbuf,
|
printf("Verified %s signed by %s\n", pbuf,
|
||||||
cn.status ? cn_buf : "someone we trust");
|
cn.status ? cn_buf : "someone we trust");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue