diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-03-01 07:54:04 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2017-03-01 09:36:33 +0100 |
commit | 43a4546e7f0842b2e4b70da6d97295f3d18c681c (patch) | |
tree | 60cb0fdca8506bee95abeaffb4e4116d85ee6d24 | |
parent | 8a392fb989e933ce6b3867138bc7fdc1153abe2c (diff) | |
download | gnutls-43a4546e7f0842b2e4b70da6d97295f3d18c681c.tar.gz |
opencdk: do not parse any secret keys in packet when reading a certificate
This reduces the attack surface on the parsers, and prevents any bugs
in the secret key parser to be exploitable by inserting secret key
sub-packets into an openpgp certificate.
This addresses:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=354
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=360
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
-rw-r--r-- | lib/opencdk/kbnode.c | 6 | ||||
-rw-r--r-- | lib/opencdk/keydb.c | 14 | ||||
-rw-r--r-- | lib/opencdk/literal.c | 2 | ||||
-rw-r--r-- | lib/opencdk/opencdk.h | 7 | ||||
-rw-r--r-- | lib/opencdk/read-packet.c | 10 | ||||
-rw-r--r-- | lib/openpgp/openpgp.c | 2 | ||||
-rw-r--r-- | lib/openpgp/pgp.c | 2 | ||||
-rw-r--r-- | lib/openpgp/privkey.c | 2 |
8 files changed, 28 insertions, 17 deletions
diff --git a/lib/opencdk/kbnode.c b/lib/opencdk/kbnode.c index abd1d9524c..cad9beb882 100644 --- a/lib/opencdk/kbnode.c +++ b/lib/opencdk/kbnode.c @@ -369,12 +369,14 @@ cdk_packet_t cdk_kbnode_get_packet(cdk_kbnode_t node) * @armor: whether base64 or not * @buf: the buffer which stores the key sequence * @buflen: the length of the buffer + * @public: non-zero if reading a public key * * Tries to read a key node from the memory buffer @buf. **/ cdk_error_t cdk_kbnode_read_from_mem(cdk_kbnode_t * ret_node, - int armor, const byte * buf, size_t buflen) + int armor, const byte * buf, size_t buflen, + unsigned public) { cdk_stream_t inp; cdk_error_t rc; @@ -393,7 +395,7 @@ cdk_kbnode_read_from_mem(cdk_kbnode_t * ret_node, if (armor) cdk_stream_set_armor_flag(inp, 0); - rc = cdk_keydb_get_keyblock(inp, ret_node); + rc = cdk_keydb_get_keyblock(inp, ret_node, public); if (rc) gnutls_assert(); cdk_stream_close(inp); diff --git a/lib/opencdk/keydb.c b/lib/opencdk/keydb.c index 4e9c1dc54f..6fc0b9ec43 100644 --- a/lib/opencdk/keydb.c +++ b/lib/opencdk/keydb.c @@ -106,7 +106,7 @@ static cdk_error_t keydb_idx_build(const char *file) while (!cdk_stream_eof(inp)) { off_t pos = cdk_stream_tell(inp); - rc = cdk_pkt_read(inp, pkt); + rc = cdk_pkt_read(inp, pkt, 1); if (rc) { _cdk_log_debug ("index build failed packet off=%lu\n", @@ -607,7 +607,7 @@ cdk_keydb_search(cdk_keydb_search_t st, cdk_keydb_hd_t hd, if (st->type == CDK_DBSEARCH_NEXT) cdk_stream_seek(kr, st->off); - rc = cdk_keydb_get_keyblock(kr, &knode); + rc = cdk_keydb_get_keyblock(kr, &knode, 1); if (rc) { if (rc == CDK_EOF) @@ -1468,7 +1468,7 @@ add_key_usage(cdk_kbnode_t knode, u32 keyid[2], unsigned int usage) } cdk_error_t -cdk_keydb_get_keyblock(cdk_stream_t inp, cdk_kbnode_t * r_knode) +cdk_keydb_get_keyblock(cdk_stream_t inp, cdk_kbnode_t * r_knode, unsigned public) { cdk_packet_t pkt; cdk_kbnode_t knode, node; @@ -1495,7 +1495,7 @@ cdk_keydb_get_keyblock(cdk_stream_t inp, cdk_kbnode_t * r_knode) while (!cdk_stream_eof(inp)) { cdk_pkt_new(&pkt); old_off = cdk_stream_tell(inp); - rc = cdk_pkt_read(inp, pkt); + rc = cdk_pkt_read(inp, pkt, public); if (rc) { cdk_pkt_release(pkt); if (rc == CDK_EOF) @@ -1915,7 +1915,7 @@ cdk_error_t cdk_keydb_check_sk(cdk_keydb_hd_t hd, u32 * keyid) return rc; } cdk_pkt_new(&pkt); - while (!cdk_pkt_read(db, pkt)) { + while (!cdk_pkt_read(db, pkt, 0)) { if (pkt->pkttype != CDK_PKT_SECRET_KEY && pkt->pkttype != CDK_PKT_SECRET_SUBKEY) { cdk_pkt_free(pkt); @@ -2030,14 +2030,14 @@ cdk_error_t cdk_listkey_next(cdk_listkey_t ctx, cdk_kbnode_t * ret_key) } if (ctx->type && ctx->u.patt[0] == '*') - return cdk_keydb_get_keyblock(ctx->inp, ret_key); + return cdk_keydb_get_keyblock(ctx->inp, ret_key, 1); else if (ctx->type) { cdk_kbnode_t node; struct cdk_keydb_search_s ks; cdk_error_t rc; for (;;) { - rc = cdk_keydb_get_keyblock(ctx->inp, &node); + rc = cdk_keydb_get_keyblock(ctx->inp, &node, 1); if (rc) { gnutls_assert(); return rc; diff --git a/lib/opencdk/literal.c b/lib/opencdk/literal.c index 2c7b1b86a4..7756bb33c7 100644 --- a/lib/opencdk/literal.c +++ b/lib/opencdk/literal.c @@ -67,7 +67,7 @@ static cdk_error_t literal_decode(void *data, FILE * in, FILE * out) return rc; cdk_pkt_new(&pkt); - rc = cdk_pkt_read(si, pkt); + rc = cdk_pkt_read(si, pkt, 1); if (rc || pkt->pkttype != CDK_PKT_LITERAL) { cdk_pkt_release(pkt); cdk_stream_close(si); diff --git a/lib/opencdk/opencdk.h b/lib/opencdk/opencdk.h index 07bac6128d..094a90ba47 100644 --- a/lib/opencdk/opencdk.h +++ b/lib/opencdk/opencdk.h @@ -553,7 +553,7 @@ extern "C" { void cdk_pkt_release(cdk_packet_t pkt); /* Read or write the given output from or to the stream. */ - cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt); + cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt, unsigned public); cdk_error_t cdk_pkt_write(cdk_stream_t out, cdk_packet_t pkt); /* Sub packet routines */ @@ -814,7 +814,8 @@ extern "C" { /* Try to read the next key block from the given input stream. The key will be returned in @RET_KEY on success. */ cdk_error_t cdk_keydb_get_keyblock(cdk_stream_t inp, - cdk_kbnode_t * ret_key); + cdk_kbnode_t * ret_key, + unsigned public); /* Rebuild the key db index if possible. */ cdk_error_t cdk_keydb_idx_rebuild(cdk_keydb_hd_t db, @@ -848,7 +849,7 @@ extern "C" { cdk_error_t cdk_kbnode_read_from_mem(cdk_kbnode_t * ret_node, int armor, const unsigned char *buf, - size_t buflen); + size_t buflen, unsigned public); cdk_error_t cdk_kbnode_write_to_mem(cdk_kbnode_t node, unsigned char *buf, size_t * r_nbytes); diff --git a/lib/opencdk/read-packet.c b/lib/opencdk/read-packet.c index ba1223bd3e..3052dbfdf1 100644 --- a/lib/opencdk/read-packet.c +++ b/lib/opencdk/read-packet.c @@ -959,7 +959,7 @@ static cdk_error_t skip_packet(cdk_stream_t inp, size_t pktlen) * * Parse the next packet on the @inp stream and return its contents in @pkt. **/ -cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt) +cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt, unsigned public) { int ctb, is_newctb; int pkttype; @@ -1067,6 +1067,10 @@ cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt) break; case CDK_PKT_SECRET_KEY: + if (public) { + /* read secret key when expecting public */ + return gnutls_assert_val(CDK_Inv_Packet); + } pkt->pkt.secret_key = cdk_calloc(1, sizeof *pkt->pkt.secret_key); if (!pkt->pkt.secret_key) @@ -1082,6 +1086,10 @@ cdk_error_t cdk_pkt_read(cdk_stream_t inp, cdk_packet_t pkt) break; case CDK_PKT_SECRET_SUBKEY: + if (public) { + /* read secret key when expecting public */ + return gnutls_assert_val(CDK_Inv_Packet); + } pkt->pkt.secret_key = cdk_calloc(1, sizeof *pkt->pkt.secret_key); if (!pkt->pkt.secret_key) diff --git a/lib/openpgp/openpgp.c b/lib/openpgp/openpgp.c index 783f77af12..b70726fb12 100644 --- a/lib/openpgp/openpgp.c +++ b/lib/openpgp/openpgp.c @@ -584,7 +584,7 @@ int gnutls_openpgp_count_key_names(const gnutls_datum_t * cert) return 0; } - if (cdk_kbnode_read_from_mem(&knode, 0, cert->data, cert->size)) { + if (cdk_kbnode_read_from_mem(&knode, 0, cert->data, cert->size, 1)) { gnutls_assert(); return 0; } diff --git a/lib/openpgp/pgp.c b/lib/openpgp/pgp.c index dd6957e247..03a507d4c4 100644 --- a/lib/openpgp/pgp.c +++ b/lib/openpgp/pgp.c @@ -99,7 +99,7 @@ gnutls_openpgp_crt_import(gnutls_openpgp_crt_t key, armor = 1; rc = cdk_kbnode_read_from_mem(&key->knode, armor, data->data, - data->size); + data->size, 1); if (rc) { rc = _gnutls_map_cdk_rc(rc); gnutls_assert(); diff --git a/lib/openpgp/privkey.c b/lib/openpgp/privkey.c index 5766a142bf..a90541dae8 100644 --- a/lib/openpgp/privkey.c +++ b/lib/openpgp/privkey.c @@ -186,7 +186,7 @@ gnutls_openpgp_privkey_import(gnutls_openpgp_privkey_t key, armor = 1; rc = cdk_kbnode_read_from_mem(&key->knode, armor, data->data, - data->size); + data->size, 0); if (rc != 0) { rc = _gnutls_map_cdk_rc(rc); gnutls_assert(); |