summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2017-03-01 07:54:04 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-03-01 09:36:33 +0100
commit43a4546e7f0842b2e4b70da6d97295f3d18c681c (patch)
tree60cb0fdca8506bee95abeaffb4e4116d85ee6d24
parent8a392fb989e933ce6b3867138bc7fdc1153abe2c (diff)
downloadgnutls-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.c6
-rw-r--r--lib/opencdk/keydb.c14
-rw-r--r--lib/opencdk/literal.c2
-rw-r--r--lib/opencdk/opencdk.h7
-rw-r--r--lib/opencdk/read-packet.c10
-rw-r--r--lib/openpgp/openpgp.c2
-rw-r--r--lib/openpgp/pgp.c2
-rw-r--r--lib/openpgp/privkey.c2
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();