Module Name: src Committed By: agc Date: Wed Oct 24 02:27:25 UTC 2012
Modified Files: src/crypto/external/bsd/netpgp/dist/src/libverify [agc-netpgp-standalone]: libverify.c pgpsum.c verify.h Log Message: various improvements in netpgpverify: + store the revocation code in the signature + attempt to be bug compatible with gpg - if a signature on a text document does not match the first time, try again, this time trimming trailing white space (' ' and '\t' characters) from the text document. this makes the verification work the same as gpg. this behavior is not activated for binary documents. i have absolutely no idea why this is done in the first place; christoph badura thinks it may be to do with original pgp compatibility. this and the stripping of the trailing \r\n on text document digest calculation make no sense to me. + only compare the leading Q bits (i.e. the length of the DSA Q value) when verifying a DSA signature, per RFC 4880. helps with sha256 digests and smaller keys. + calculate the displayed size of DSA keys a bit differently, no functional difference. To generate a diff of this commit: cvs rdiff -u -r1.1.2.6 -r1.1.2.7 \ src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c cvs rdiff -u -r1.1.2.1 -r1.1.2.2 \ src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c cvs rdiff -u -r1.1.2.5 -r1.1.2.6 \ src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c diff -u src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c:1.1.2.6 src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c:1.1.2.7 --- src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c:1.1.2.6 Tue Oct 23 15:00:56 2012 +++ src/crypto/external/bsd/netpgp/dist/src/libverify/libverify.c Wed Oct 24 02:27:25 2012 @@ -713,10 +713,10 @@ static int read_sig_subpackets(pgpv_sigpkt_t *sigpkt, uint8_t *p, size_t pktlen) { pgpv_sigsubpkt_t subpkt; - const int is_subpkt = 0; - unsigned lenlen; - unsigned i; - uint8_t *start; + const int is_subpkt = 0; + unsigned lenlen; + unsigned i; + uint8_t *start; start = p; for (i = 0 ; (unsigned)(p - start) < sigpkt->subslen ; i++) { @@ -784,6 +784,7 @@ read_sig_subpackets(pgpv_sigpkt_t *sigpk sigpkt->sig.features = (char *)(void *)p; break; case SUBPKT_REVOCATION_REASON: + sigpkt->sig.revoked = *p++ + 1; sigpkt->sig.why_revoked = (char *)(void *)p; break; default: @@ -1326,16 +1327,7 @@ numkeybits(const pgpv_pubkey_t *pubkey) return pubkey->bn[RSA_N].bits; case PUBKEY_DSA: case PUBKEY_ECDSA: - switch(BITS_TO_BYTES(pubkey->bn[DSA_Q].bits)) { - case 20: - return 1024; - case 28: - return 2048; - case 32: - return 3072; - default: - return 0; - } + return BITS_TO_BYTES(pubkey->bn[DSA_Q].bits) * 64; case PUBKEY_ELGAMAL_ENCRYPT: case PUBKEY_ELGAMAL_ENCRYPT_OR_SIGN: return pubkey->bn[ELGAMAL_P].bits; @@ -1356,6 +1348,7 @@ fmt_pubkey(char *s, size_t size, pgpv_pu if (pubkey->expiry) { cc += fmt_time(&s[cc], size - cc, " [Expiry ", pubkey->birth + pubkey->expiry, "]", 0); } + /* XXX - revoked? */ cc += snprintf(&s[cc], size - cc, "\n"); cc += fmt_fingerprint(&s[cc], size - cc, &pubkey->fingerprint, "fingerprint: "); return cc; @@ -1451,18 +1444,23 @@ rsa_verify(uint8_t *calculated, unsigned return memcmp(&decrypted[i + prefixlen], calculated, calclen) == 0; } +#define BAD_BIGNUM(s, k) \ + (BN_is_zero((s)->bn) || BN_is_negative((s)->bn) || BN_cmp((s)->bn, (k)->bn) >= 0) + #ifndef DSA_MAX_MODULUS_BITS #define DSA_MAX_MODULUS_BITS 10000 #endif /* verify DSA signature */ static int -verify_dsa_verify(uint8_t *calculated, unsigned calclen, pgpv_bignum_t *sig, pgpv_pubkey_t *pubkey) +verify_dsa_sig(uint8_t *calculated, unsigned calclen, pgpv_bignum_t *sig, pgpv_pubkey_t *pubkey) { unsigned qbits; BIGNUM *M; BIGNUM *W; BIGNUM *t1; + uint8_t calcnum[128]; + uint8_t signum[128]; int ret; if (pubkey[DSA_P].bn == NULL || pubkey[DSA_Q].bn == NULL || pubkey[DSA_G].bn == NULL) { @@ -1489,8 +1487,8 @@ verify_dsa_verify(uint8_t *calculated, u } ret = 0; if ((M = BN_new()) == NULL || (W = BN_new()) == NULL || (t1 = BN_new()) == NULL || - BN_is_zero(sig[DSA_R].bn) || BN_is_negative(sig[DSA_R].bn) || BN_cmp(sig[DSA_R].bn, pubkey->bn[DSA_Q].bn) >= 0 || - BN_is_zero(sig[DSA_S].bn) || BN_is_negative(sig[DSA_S].bn) || BN_cmp(sig[DSA_S].bn, pubkey->bn[DSA_Q].bn) >= 0 || + BAD_BIGNUM(&sig[DSA_R], &pubkey->bn[DSA_Q]) || + BAD_BIGNUM(&sig[DSA_S], &pubkey->bn[DSA_Q]) || BN_mod_inverse(W, sig[DSA_S].bn, pubkey->bn[DSA_Q].bn, NULL) == NULL) { goto done; } @@ -1506,7 +1504,10 @@ verify_dsa_verify(uint8_t *calculated, u !BN_div(NULL, t1, t1, pubkey->bn[DSA_Q].bn, NULL)) { goto done; } - ret = (BN_cmp(t1, sig[DSA_R].bn) == 0); + /* only compare the first q bits */ + BN_bn2bin(t1, calcnum); + BN_bn2bin(sig[DSA_R].bn, signum); + ret = memcmp(calcnum, signum, BITS_TO_BYTES(qbits)) == 0; done: if (M) { BN_free(M); @@ -1946,6 +1947,54 @@ fixup_detached(pgpv_cursor_t *cursor, co return 1; } +/* match the calculated signature against the oen in the signature packet */ +static int +match_sig(pgpv_cursor_t *cursor, pgpv_signature_t *signature, pgpv_pubkey_t *pubkey, uint8_t *data, size_t size) +{ + unsigned calclen; + uint8_t calculated[64]; + int match; + + calclen = pgpv_digest_memory(calculated, sizeof(calculated), + data, size, + get_ref(&signature->hashstart), signature->hashlen, + (signature->type == SIGTYPE_TEXT) ? 't' : 'b'); + if (ALG_IS_RSA(signature->keyalg)) { + match = rsa_verify(calculated, calclen, signature->hashalg, signature->bn, pubkey); + } else if (ALG_IS_DSA(signature->keyalg)) { + match = verify_dsa_sig(calculated, calclen, signature->bn, pubkey); + } else { + snprintf(cursor->why, sizeof(cursor->why), "Signature type %u not recognised", signature->keyalg); + return 0; + } + if (!match && signature->type == SIGTYPE_TEXT) { + /* second try for cleartext data, ignoring trailing whitespace */ + calclen = pgpv_digest_memory(calculated, sizeof(calculated), + data, size, + get_ref(&signature->hashstart), signature->hashlen, 'w'); + if (ALG_IS_RSA(signature->keyalg)) { + match = rsa_verify(calculated, calclen, signature->hashalg, signature->bn, pubkey); + } else if (ALG_IS_DSA(signature->keyalg)) { + match = verify_dsa_sig(calculated, calclen, signature->bn, pubkey); + } + } + if (!match) { + snprintf(cursor->why, sizeof(cursor->why), "Signature on data did not match"); + return 0; + } + if (valid_dates(signature, pubkey, cursor->why, sizeof(cursor->why)) > 0) { + return 0; + } + if (key_expired(pubkey, cursor->why, sizeof(cursor->why))) { + return 0; + } + if (signature->revoked) { + snprintf(cursor->why, sizeof(cursor->why), "Signature was revoked"); + return 0; + } + return 1; +} + /************************************************************************/ /* start of exported functions */ /************************************************************************/ @@ -2018,8 +2067,6 @@ pgpv_verify(pgpv_cursor_t *cursor, pgpv_ pgpv_litdata_t *litdata; pgpv_pubkey_t *pubkey; unsigned primary; - unsigned calclen; - uint8_t calculated[64]; uint8_t *data; size_t pkt; size_t insize; @@ -2077,28 +2124,7 @@ pgpv_verify(pgpv_cursor_t *cursor, pgpv_ cursor->sigtime = signature->birth; /* calc hash on data packet */ data = get_literal_data(cursor, litdata, &insize); - calclen = pgpv_digest_memory(calculated, sizeof(calculated), - data, insize, - get_ref(&signature->hashstart), signature->hashlen, - (signature->type == SIGTYPE_TEXT)); - if (ALG_IS_RSA(signature->keyalg)) { - if (!rsa_verify(calculated, calclen, signature->hashalg, signature->bn, pubkey)) { - snprintf(cursor->why, sizeof(cursor->why), "Signature on data did not match"); - return 0; - } - } else if (ALG_IS_DSA(signature->keyalg)) { - if (!verify_dsa_verify(calculated, calclen, signature->bn, pubkey)) { - snprintf(cursor->why, sizeof(cursor->why), "Signature on data did not match"); - return 0; - } - } else { - snprintf(cursor->why, sizeof(cursor->why), "Signature type %u not recognised", signature->keyalg); - return 0; - } - if (valid_dates(signature, pubkey, cursor->why, sizeof(cursor->why)) > 0) { - return 0; - } - if (key_expired(pubkey, cursor->why, sizeof(cursor->why))) { + if (!match_sig(cursor, signature, pubkey, data, insize)) { return 0; } ARRAY_APPEND(cursor->datacookies, pkt); Index: src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c diff -u src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c:1.1.2.1 src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c:1.1.2.2 --- src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c:1.1.2.1 Sat Oct 20 04:59:53 2012 +++ src/crypto/external/bsd/netpgp/dist/src/libverify/pgpsum.c Wed Oct 24 02:27:25 2012 @@ -39,16 +39,22 @@ /* add the ascii armor line endings (except for last line) */ static size_t -don_armor(digest_t *hash, uint8_t *in, size_t insize) +don_armor(digest_t *hash, uint8_t *in, size_t insize, int doarmor) { uint8_t *from; + uint8_t *newp; uint8_t *p; uint8_t dos_line_end[2]; dos_line_end[0] = '\r'; dos_line_end[1] = '\n'; for (from = in ; (p = memchr(from, '\n', insize - (size_t)(from - in))) != NULL ; from = p + 1) { - digest_update(hash, from, (size_t)(p - from)); + for (newp = p ; doarmor == 'w' && newp > from ; --newp) { + if (*(newp - 1) != ' ' && *(newp - 1) != '\t') { + break; + } + } + digest_update(hash, from, (size_t)(newp - from)); digest_update(hash, dos_line_end, sizeof(dos_line_end)); } digest_update(hash, from, insize - (size_t)(from - in)); @@ -118,9 +124,9 @@ calcsum(uint8_t *out, size_t size, const writefile(mem, cc); #endif digest_init(&hash, hashalg); - if (doarmor && !already_armored(mem, cc)) { + if (strchr("tw", doarmor) != NULL && !already_armored(mem, cc)) { /* this took me ages to find - something causes gpg to truncate its input */ - don_armor(&hash, mem, cc - 1); + don_armor(&hash, mem, cc - 1, doarmor); } else { digest_update(&hash, mem, cc); } Index: src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h diff -u src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h:1.1.2.5 src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h:1.1.2.6 --- src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h:1.1.2.5 Tue Oct 23 15:00:56 2012 +++ src/crypto/external/bsd/netpgp/dist/src/libverify/verify.h Wed Oct 24 02:27:25 2012 @@ -133,6 +133,7 @@ typedef struct pgpv_signature_t { uint8_t pref_compress_alg; uint8_t notation; uint8_t type_key; + uint8_t revoked; /* subtract 1 to get real reason, 0 == not revoked */ } pgpv_signature_t; /* a signature packet */