diff --git a/security/netpgpverify/Makefile b/security/netpgpverify/Makefile --- a/security/netpgpverify/Makefile +++ b/security/netpgpverify/Makefile @@ -1,21 +1,25 @@ # $NetBSD: Makefile,v 1.19 2015/11/03 16:50:32 agc Exp $ -DISTNAME= netpgpverify-20151103 +DISTNAME= netpgpverify-${VERSION} CATEGORIES= security MASTER_SITES= # empty DISTFILES= # empty MAINTAINER= agc@NetBSD.org HOMEPAGE= http://www.NetBSD.org/ COMMENT= Standalone PGP and ssh signature verification utility LICENSE= modified-bsd AUTO_MKDIRS= yes GNU_CONFIGURE= yes TEST_TARGET= tst +.include "../../mk/bsd.prefs.mk" + +VERSION!= ${AWK} '/\#define.*NETPGP_VERIFY_H_/ {print $$3}' ${FILESDIR}/verify.h + do-extract: @${CP} -R ${FILESDIR} ${WRKSRC} .include "../../mk/bsd.pkg.mk" diff --git a/security/netpgpverify/files/bzlib.c b/security/netpgpverify/files/bzlib.c --- a/security/netpgpverify/files/bzlib.c +++ b/security/netpgpverify/files/bzlib.c @@ -30,16 +30,20 @@ bzBuffToBuffDecompress. Fixed. */ #include "config.h" #include "bzlib_private.h" +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + /* $NetBSD: bzlib.c,v 1.4 2015/02/03 21:13:17 agc Exp $ */ /*-------------------------------------------------------------*/ /*--- Table for randomising repetitive blocks ---*/ /*--- randtable.c ---*/ /*-------------------------------------------------------------*/ diff --git a/security/netpgpverify/files/digest.c b/security/netpgpverify/files/digest.c --- a/security/netpgpverify/files/digest.c +++ b/security/netpgpverify/files/digest.c @@ -40,16 +40,20 @@ #include "md5.h" #include "rmd160.h" #include "sha1.h" #include "sha2.h" #include "digest.h" +#ifndef USE_ARG +#define USE_ARG(x) /*LINTED*/(void)&(x) +#endif + static uint8_t prefix_md5[] = { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 }; static uint8_t prefix_sha1[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 diff --git a/security/netpgpverify/files/libverify.c b/security/netpgpverify/files/libverify.c --- a/security/netpgpverify/files/libverify.c +++ b/security/netpgpverify/files/libverify.c @@ -28,16 +28,17 @@ #include #include #include #include #include #include +#include #include #include #include #include #include #include #include "bzlib.h" @@ -162,16 +163,81 @@ #define SIGTYPE_TIMESTAMP_SIG 0x40 /* Timestamp signature */ #define SIGTYPE_3RDPARTY 0x50 /* Third-Party Confirmation signature */ /* Forward declarations */ static int read_all_packets(pgpv_t */*pgp*/, pgpv_mem_t */*mem*/, const char */*op*/); static int read_binary_file(pgpv_t */*pgp*/, const char */*op*/, const char */*fmt*/, ...) __printflike(3, 4); static int read_binary_memory(pgpv_t */*pgp*/, const char */*op*/, const void */*memory*/, size_t /*size*/); +/* output buffer structure */ +typedef struct obuf_t { + size_t alloc; /* amount of memory allocated */ + size_t c; /* # of chars used so far */ + uint8_t *v; /* array of bytes */ + uint32_t endian; /* byte order of output stream */ +} obuf_t; + +/* grow the buffer, if needed */ +static bool +growbuf(obuf_t *obuf, size_t cc) +{ + size_t newalloc; + uint8_t *newv; + + if (obuf->c + cc > obuf->alloc) { + newalloc = howmany(obuf->alloc + cc, 128) * 128; + newv = realloc(obuf->v, newalloc); + if (newv == NULL) { + return false; + } + obuf->v = newv; + obuf->alloc = newalloc; + } + return true; +} + +/* add a fixed-length area of memory */ +static bool +obuf_add_mem(obuf_t *obuf, const char *s, size_t len) +{ + if (obuf && s && len > 0) { + if (!growbuf(obuf, len)) { + return false; + } + memcpy(&obuf->v[obuf->c], s, len); + obuf->c += len; + return true; + } + return false; +} + +/* varargs-based printf to string */ +static bool +obuf_printf(obuf_t *obuf, const char *fmt, ...) +{ + va_list args; + char *cp; + bool ret; + int cc; + + if (obuf && fmt) { + ret = true; + va_start(args, fmt); + cc = vasprintf(&cp, fmt, args); + va_end(args); + if (cc > 0) { + ret = obuf_add_mem(obuf, cp, (size_t)cc); + free(cp); + } + return ret; + } + return false; +} + /* read a file into the pgpv_mem_t struct */ static int read_file(pgpv_t *pgp, const char *f) { struct stat st; pgpv_mem_t *mem; ARRAY_EXPAND(pgp->areas); @@ -410,25 +476,26 @@ fmt_16(uint8_t *p, uint16_t a) { a = pgp_hton16(a); memcpy(p, &a, sizeof(a)); return sizeof(a); } /* format a binary string in memory */ static size_t -fmt_binary(char *s, size_t size, const uint8_t *bin, unsigned len) +fmt_binary(obuf_t *obuf, const uint8_t *bin, unsigned len) { unsigned i; - size_t cc; - for (cc = 0, i = 0 ; i < len && cc < size ; i++) { - cc += snprintf(&s[cc], size - cc, "%02x", bin[i]); + for (i = 0 ; i < len ; i++) { + if (!obuf_printf(obuf, "%02hhx", bin[i])) { + return false; + } } - return cc; + return true; } /* format an mpi into memory */ static unsigned fmt_binary_mpi(pgpv_bignum_t *mpi, uint8_t *p, size_t size) { unsigned bytes; PGPV_BIGNUM *bn; @@ -547,29 +614,31 @@ pgpv_calc_fingerprint(pgpv_fingerprint_t } } /* exhausted all avenues, really */ memset(fingerprint->v, 0xff, fingerprint->len = PGPV_KEYID_LEN); return 1; } /* format a fingerprint into memory */ -static size_t -fmt_fingerprint(char *s, size_t size, pgpv_fingerprint_t *fingerprint, const char *name) +static bool +fmt_fingerprint(obuf_t *obuf, pgpv_fingerprint_t *fingerprint, const char *name) { unsigned i; - size_t cc; - cc = snprintf(s, size, "%s ", name); + if (!obuf_printf(obuf, "%s ", name)) { + return false; + } for (i = 0 ; i < fingerprint->len ; i++) { - cc += snprintf(&s[cc], size - cc, "%02hhx%s", - fingerprint->v[i], (i % 2 == 1) ? " " : ""); + if (!obuf_printf(obuf, "%02hhx%s", + fingerprint->v[i], (i % 2 == 1) ? " " : "")) { + return false; + } } - cc += snprintf(&s[cc], size - cc, "\n"); - return cc; + return obuf_printf(obuf, "\n"); } /* calculate keyid from a pubkey */ static int calc_keyid(pgpv_pubkey_t *key, const char *hashtype) { pgpv_calc_fingerprint(&key->fingerprint, key, hashtype); memcpy(key->keyid, &key->fingerprint.v[key->fingerprint.len - PGPV_KEYID_LEN], PGPV_KEYID_LEN); @@ -654,40 +723,42 @@ get_32(uint8_t *p) #define HOURSECS (int64_t)(60 * 60) #define DAYSECS (int64_t)(24 * 60 * 60) #define MONSECS (int64_t)(30 * DAYSECS) #define YEARSECS (int64_t)(365 * DAYSECS) /* format (human readable) time into memory */ static size_t -fmt_time(char *s, size_t size, const char *header, int64_t n, const char *trailer, int relative) +fmt_time(obuf_t *obuf, const char *header, int64_t n, const char *trailer, int relative) { struct tm tm; time_t elapsed; time_t now; time_t t; - size_t cc; t = (time_t)n; now = time(NULL); elapsed = now - t; gmtime_r(&t, &tm); - cc = snprintf(s, size, "%s%04d-%02d-%02d", header, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + if (!obuf_printf(obuf, "%s%04d-%02d-%02d", header, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday)) { + return false; + } if (relative) { - cc += snprintf(&s[cc], size - cc, " (%lldy %lldm %lldd %lldh %s)", + if (!obuf_printf(obuf, " (%lldy %lldm %lldd %lldh %s)", llabs((long long)elapsed / YEARSECS), llabs(((long long)elapsed % YEARSECS) / MONSECS), llabs(((long long)elapsed % MONSECS) / DAYSECS), llabs(((long long)elapsed % DAYSECS) / HOURSECS), - (now > t) ? "ago" : "ahead"); + (now > t) ? "ago" : "ahead")) { + return false; + } } - cc += snprintf(&s[cc], size - cc, "%s", trailer); - return cc; + return obuf_printf(obuf, "%s", trailer); } /* dump key mpis to stdout */ static void print_key_mpis(pgpv_bignum_t *v, uint8_t keyalg) { char s[8192]; @@ -1426,92 +1497,110 @@ numkeybits(const pgpv_pubkey_t *pubkey) case PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN: return pubkey->bn[ELGAMAL_P].bits; default: return 0; } } /* print a public key */ -static size_t -fmt_pubkey(char *s, size_t size, pgpv_pubkey_t *pubkey, const char *leader) +static bool +fmt_pubkey(obuf_t *obuf, pgpv_pubkey_t *pubkey, const char *leader) { - size_t cc; - - cc = snprintf(s, size, "%s %u/%s ", leader, numkeybits(pubkey), fmtkeyalg(pubkey->keyalg)); - cc += fmt_binary(&s[cc], size - cc, pubkey->keyid, PGPV_KEYID_LEN); - cc += fmt_time(&s[cc], size - cc, " ", pubkey->birth, "", 0); + if (!obuf_printf(obuf, "%s %u/%s ", leader, numkeybits(pubkey), fmtkeyalg(pubkey->keyalg))) { + return false; + } + if (!fmt_binary(obuf, pubkey->keyid, PGPV_KEYID_LEN)) { + return false; + } + if (!fmt_time(obuf, " ", pubkey->birth, "", 0)) { + return false; + } if (pubkey->expiry) { - cc += fmt_time(&s[cc], size - cc, " [Expiry ", pubkey->birth + pubkey->expiry, "]", 0); + if (!fmt_time(obuf, " [Expiry ", pubkey->birth + pubkey->expiry, "]", 0)) { + return false; + } } - cc += snprintf(&s[cc], size - cc, "\n"); - cc += fmt_fingerprint(&s[cc], size - cc, &pubkey->fingerprint, "fingerprint "); - return cc; + if (!obuf_printf(obuf, "\n")) { + return false; + } + return fmt_fingerprint(obuf, &pubkey->fingerprint, "fingerprint "); } /* we add 1 to revocation value to denote compromised */ #define COMPROMISED (0x02 + 1) /* format a userid - used to order the userids when formatting */ -static size_t -fmt_userid(char *s, size_t size, pgpv_primarykey_t *primary, uint8_t u) +static bool +fmt_userid(obuf_t *obuf, pgpv_primarykey_t *primary, uint8_t u) { pgpv_signed_userid_t *userid; userid = &ARRAY_ELEMENT(primary->signed_userids, u); - return snprintf(s, size, "uid %.*s%s\n", + return obuf_printf(obuf, "uid %.*s%s\n", (int)userid->userid.size, userid->userid.data, (userid->revoked == COMPROMISED) ? " [COMPROMISED AND REVOKED]" : (userid->revoked) ? " [REVOKED]" : ""); } /* format a trust sig - used to order the userids when formatting */ -static size_t -fmt_trust(char *s, size_t size, pgpv_signed_userid_t *userid, uint32_t u) +static bool +fmt_trust(obuf_t *obuf, pgpv_signed_userid_t *userid, uint32_t u) { pgpv_signature_t *sig; - size_t cc; sig = &ARRAY_ELEMENT(userid->sigs, u); - cc = snprintf(s, size, "trust "); - cc += fmt_binary(&s[cc], size - cc, sig->signer, 8); - return cc + snprintf(&s[cc], size - cc, "\n"); + if (!obuf_printf(obuf, "trust ")) { + return false; + } + if (!fmt_binary(obuf, sig->signer, 8)) { + return false; + } + return obuf_printf(obuf, "\n"); } /* print a primary key, per RFC 4880 */ -static size_t -fmt_primary(char *s, size_t size, pgpv_primarykey_t *primary, unsigned subkey, const char *modifiers) +static bool +fmt_primary(obuf_t *obuf, pgpv_primarykey_t *primary, unsigned subkey, const char *modifiers) { pgpv_signed_userid_t *userid; pgpv_pubkey_t *pubkey; unsigned i; unsigned j; - size_t cc; pubkey = (subkey == 0) ? &primary->primary : &ARRAY_ELEMENT(primary->signed_subkeys, subkey - 1).subkey; - cc = fmt_pubkey(s, size, pubkey, "signature "); - cc += fmt_userid(&s[cc], size - cc, primary, primary->primary_userid); + if (!fmt_pubkey(obuf, pubkey, "signature ")) { + return false; + } + if (!fmt_userid(obuf, primary, primary->primary_userid)) { + return false; + } for (i = 0 ; i < ARRAY_COUNT(primary->signed_userids) ; i++) { if (i != primary->primary_userid) { - cc += fmt_userid(&s[cc], size - cc, primary, i); + if (!fmt_userid(obuf, primary, i)) { + return false; + } if (strcasecmp(modifiers, "trust") == 0) { userid = &ARRAY_ELEMENT(primary->signed_userids, i); for (j = 0 ; j < ARRAY_COUNT(userid->sigs) ; j++) { - cc += fmt_trust(&s[cc], size - cc, userid, j); + if (!fmt_trust(obuf, userid, j)) { + return false; + } } } } } if (strcasecmp(modifiers, "subkeys") == 0) { for (i = 0 ; i < ARRAY_COUNT(primary->signed_subkeys) ; i++) { - cc += fmt_pubkey(&s[cc], size - cc, &ARRAY_ELEMENT(primary->signed_subkeys, i).subkey, "encryption"); + if (!fmt_pubkey(obuf, &ARRAY_ELEMENT(primary->signed_subkeys, i).subkey, "encryption")) { + return false; + } } } - cc += snprintf(&s[cc], size - cc, "\n"); - return cc; + return obuf_printf(obuf, "\n"); } /* check the padding on the signature */ static int rsa_padding_check_none(uint8_t *to, int tlen, const uint8_t *from, int flen, int num) { USE_ARG(num); @@ -2526,35 +2615,33 @@ pgpv_close(pgpv_t *pgp) #define NO_SUBKEYS 0 /* return the formatted entry for the primary key desired */ size_t pgpv_get_entry(pgpv_t *pgp, unsigned ent, char **s, const char *modifiers) { unsigned subkey; unsigned prim; - size_t cc; + obuf_t obuf; prim = ((ent >> 8) & 0xffffff); subkey = (ent & 0xff); if (s == NULL || pgp == NULL || prim >= ARRAY_COUNT(pgp->primaries)) { return 0; } *s = NULL; - cc = ARRAY_ELEMENT(pgp->primaries, prim).fmtsize; if (modifiers == NULL || (strcasecmp(modifiers, "trust") != 0 && strcasecmp(modifiers, "subkeys") != 0)) { modifiers = "no-subkeys"; } - if (strcasecmp(modifiers, "trust") == 0) { - cc *= 2048; - } - if ((*s = calloc(1, cc)) == NULL) { + memset(&obuf, 0x0, sizeof(obuf)); + if (!fmt_primary(&obuf, &ARRAY_ELEMENT(pgp->primaries, prim), subkey, modifiers)) { return 0; } - return fmt_primary(*s, cc, &ARRAY_ELEMENT(pgp->primaries, prim), subkey, modifiers); + *s = (char *)obuf.v; + return obuf.c; } /* fixup key id, with birth, keyalg and hashalg value from signature */ static int fixup_ssh_keyid(pgpv_t *pgp, pgpv_signature_t *signature, const char *hashtype) { pgpv_pubkey_t *pubkey; unsigned i; @@ -2673,17 +2760,17 @@ pgpv_get_cursor_element(pgpv_cursor_t *c size_t pgpv_verify(pgpv_cursor_t *cursor, pgpv_t *pgp, const void *p, ssize_t size) { pgpv_signature_t *signature; pgpv_onepass_t *onepass; pgpv_litdata_t *litdata; unsigned sub; size_t pkt; - char strkeyid[PGPV_STR_KEYID_LEN]; + obuf_t obuf; int j; if (cursor == NULL || pgp == NULL || p == NULL) { return 0; } if (!setup_data(cursor, pgp, p, size)) { snprintf(cursor->why, sizeof(cursor->why), "No input data"); return 0; @@ -2700,46 +2787,63 @@ pgpv_verify(pgpv_cursor_t *cursor, pgpv_ return 0; } pkt -= 1; onepass = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt).u.onepass; litdata = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt + 1).u.litdata; signature = &ARRAY_ELEMENT(cursor->pgp->pkts, pkt + 2).u.sigpkt.sig; /* sanity check values in signature and onepass agree */ if (signature->birth == 0) { - fmt_time(cursor->why, sizeof(cursor->why), "Signature creation time [", - signature->birth, "] out of range", 0); + if (!fmt_time(&obuf, "Signature creation time [", + signature->birth, "] out of range", 0)) { + } + snprintf(cursor->why, sizeof(cursor->why), "%.*s", (int)obuf.c, (char *)obuf.v); return 0; } + memset(&obuf, 0x0, sizeof(obuf)); if (memcmp(onepass->keyid, signature->signer, PGPV_KEYID_LEN) != 0) { - fmt_binary(strkeyid, sizeof(strkeyid), onepass->keyid, (unsigned)sizeof(onepass->keyid)); - snprintf(cursor->why, sizeof(cursor->why), "Signature key id %s does not match onepass keyid", - strkeyid); + if (!fmt_binary(&obuf, onepass->keyid, (unsigned)sizeof(onepass->keyid))) { + snprintf(cursor->why, sizeof(cursor->why), "Memory allocation failure"); + return 0; + } + snprintf(cursor->why, sizeof(cursor->why), + "Signature key id %.*s does not match onepass keyid", + (int)obuf.c, (char *)obuf.v); return 0; } if (onepass->hashalg != signature->hashalg) { - snprintf(cursor->why, sizeof(cursor->why), "Signature hashalg %u does not match onepass hashalg %u", + snprintf(cursor->why, sizeof(cursor->why), + "Signature hashalg %u does not match onepass hashalg %u", signature->hashalg, onepass->hashalg); return 0; } if (onepass->keyalg != signature->keyalg) { - snprintf(cursor->why, sizeof(cursor->why), "Signature keyalg %u does not match onepass keyalg %u", + snprintf(cursor->why, sizeof(cursor->why), + "Signature keyalg %u does not match onepass keyalg %u", signature->keyalg, onepass->keyalg); return 0; } if (cursor->pgp->ssh) { fixup_ssh_keyid(cursor->pgp, signature, "sha1"); } sub = 0; if ((j = find_keyid(cursor->pgp, NULL, onepass->keyid, &sub)) < 0) { - fmt_binary(strkeyid, sizeof(strkeyid), onepass->keyid, (unsigned)sizeof(onepass->keyid)); - snprintf(cursor->why, sizeof(cursor->why), "Signature key id %s not found ", strkeyid); + if (!fmt_binary(&obuf, onepass->keyid, (unsigned)sizeof(onepass->keyid))) { + snprintf(cursor->why, sizeof(cursor->why), "Memory allocation failure"); + return 0; + } + snprintf(cursor->why, sizeof(cursor->why), + "Signature key id %.*s not found ", + (int)obuf.c, (char *)obuf.v); return 0; } if (!match_sig_id(cursor, signature, litdata, (unsigned)j, sub)) { + snprintf(cursor->why, sizeof(cursor->why), + "Signature does not match %.*s", + (int)obuf.c, (char *)obuf.v); return 0; } ARRAY_APPEND(cursor->datacookies, pkt); j = ((j & 0xffffff) << 8) | (sub & 0xff); ARRAY_APPEND(cursor->found, j); return pkt + 1; } diff --git a/security/netpgpverify/files/verify.h b/security/netpgpverify/files/verify.h --- a/security/netpgpverify/files/verify.h +++ b/security/netpgpverify/files/verify.h @@ -18,19 +18,19 @@ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef NETPGP_VERIFY_H_ -#define NETPGP_VERIFY_H_ 20151103 +#define NETPGP_VERIFY_H_ 20160214 -#define NETPGPVERIFY_VERSION "netpgpverify portable 20151103" +#define NETPGPVERIFY_VERSION "netpgpverify portable 20160214" #include #include #ifndef PGPV_ARRAY /* creates 2 unsigned vars called "name"c and "name"size in current scope */ /* also creates an array called "name"s in current scope */