diff options
Diffstat (limited to 'g10/parse-packet.c')
-rw-r--r-- | g10/parse-packet.c | 300 |
1 files changed, 129 insertions, 171 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 2065c22ef..c83524016 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -565,12 +565,9 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos, { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: - pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key); - rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt); - break; case PKT_SECRET_KEY: case PKT_SECRET_SUBKEY: - pkt->pkt.secret_key = xmalloc_clear (sizeof *pkt->pkt.secret_key); + pkt->pkt.public_key = xmalloc_clear (sizeof *pkt->pkt.public_key); rc = parse_key (inp, pkttype, pktlen, hdr, hdrlen, pkt); break; case PKT_SYMKEY_ENC: @@ -627,6 +624,7 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos, } leave: + /* FIXME: Do we leak in case of an error? */ if (!rc && iobuf_error (inp)) rc = G10ERR_INV_KEYRING; return rc; @@ -1815,6 +1813,7 @@ static int parse_key (IOBUF inp, int pkttype, unsigned long pktlen, byte * hdr, int hdrlen, PACKET * pkt) { + gpg_error_t err = 0; int i, version, algorithm; unsigned n; unsigned long timestamp, expiredate, max_expiredate; @@ -1822,9 +1821,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, int is_v4 = 0; int rc = 0; u32 keyid[2]; + PKT_public_key *pk; (void) hdr; + pk = pkt->pkt.public_key; /* PK has been cleared. */ + version = iobuf_get_noeof (inp); pktlen--; if (pkttype == PKT_PUBLIC_SUBKEY && version == '#') @@ -1853,14 +1855,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, else if (version != 2 && version != 3) { log_error ("packet(%d) with unknown version %d\n", pkttype, version); - rc = gpg_error (GPG_ERR_INV_PACKET); + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } if (pktlen < 11) { log_error ("packet(%d) too short\n", pkttype); - rc = gpg_error (GPG_ERR_INV_PACKET); + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } @@ -1894,38 +1896,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??", version, algorithm, timestamp, expiredate); - if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY) - { - PKT_secret_key *sk = pkt->pkt.secret_key; + pk->timestamp = timestamp; + pk->expiredate = expiredate; + pk->max_expiredate = max_expiredate; + pk->hdrbytes = hdrlen; + pk->version = version; + pk->is_primary = (pkttype == PKT_PUBLIC_KEY || pkttype == PKT_SECRET_KEY); + pk->pubkey_algo = algorithm; - sk->timestamp = timestamp; - sk->expiredate = expiredate; - sk->max_expiredate = max_expiredate; - sk->hdrbytes = hdrlen; - sk->version = version; - sk->is_primary = pkttype == PKT_SECRET_KEY; - sk->pubkey_algo = algorithm; - sk->req_usage = 0; - sk->pubkey_usage = 0; /* not yet used */ - } - else - { - PKT_public_key *pk = pkt->pkt.public_key; - - pk->timestamp = timestamp; - pk->expiredate = expiredate; - pk->max_expiredate = max_expiredate; - pk->hdrbytes = hdrlen; - pk->version = version; - pk->is_primary = pkttype == PKT_PUBLIC_KEY; - pk->pubkey_algo = algorithm; - pk->req_usage = 0; - pk->pubkey_usage = 0; /* not yet used */ - pk->is_revoked = 0; - pk->is_disabled = 0; - pk->keyid[0] = 0; - pk->keyid[1] = 0; - } nskey = pubkey_get_nskey (algorithm); npkey = pubkey_get_npkey (algorithm); if (!npkey) @@ -1936,62 +1914,77 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } - if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY) + if (!npkey) { - PKT_secret_key *sk = pkt->pkt.secret_key; - byte temp[16]; - size_t snlen = 0; - - if (!npkey) - { - sk->skey[0] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen, 0), - pktlen * 8); - pktlen = 0; - goto leave; - } - + /* Unknown algorithm - put data into an opaque MPI. */ + pk->pkey[0] = gcry_mpi_set_opaque (NULL, + read_rest (inp, pktlen, 0), + pktlen * 8); + pktlen = 0; + goto leave; + } + else + { + /* Fill in public key parameters. */ for (i = 0; i < npkey; i++) { n = pktlen; - sk->skey[i] = mpi_read (inp, &n, 0); + pk->pkey[i] = mpi_read (inp, &n, 0); pktlen -= n; if (list_mode) { - es_fprintf (listfp, "\tskey[%d]: ", i); - mpi_print (listfp, sk->skey[i], mpi_print_mode); + es_fprintf (listfp, "\tpkey[%d]: ", i); + mpi_print (listfp, pk->pkey[i], mpi_print_mode); es_putc ('\n', listfp); } - if (!sk->skey[i]) - rc = G10ERR_INVALID_PACKET; + if (!pk->pkey[i]) + err = gpg_error (GPG_ERR_INV_PACKET); } - if (rc) /* One of the MPIs were bad. */ + if (err) goto leave; - sk->protect.algo = iobuf_get_noeof (inp); + } + + if (list_mode) + keyid_from_pk (pk, keyid); + + if (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY) + { + struct seckey_info *ski; + byte temp[16]; + size_t snlen = 0; + + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); + if (!pk->seckey_info) + { + err = gpg_error_from_syserror (); + goto leave; + } + + ski->algo = iobuf_get_noeof (inp); pktlen--; - sk->protect.sha1chk = 0; - if (sk->protect.algo) + if (ski->algo) { - sk->is_protected = 1; - sk->protect.s2k.count = 0; - if (sk->protect.algo == 254 || sk->protect.algo == 255) + ski->is_protected = 1; + ski->s2k.count = 0; + if (ski->algo == 254 || ski->algo == 255) { if (pktlen < 3) { - rc = G10ERR_INVALID_PACKET; + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - sk->protect.sha1chk = (sk->protect.algo == 254); - sk->protect.algo = iobuf_get_noeof (inp); + ski->sha1chk = (ski->algo == 254); + ski->algo = iobuf_get_noeof (inp); pktlen--; - /* Note that a sk->protect.algo > 110 is illegal, but - I'm not erroring on it here as otherwise there would - be no way to delete such a key. */ - sk->protect.s2k.mode = iobuf_get_noeof (inp); + /* Note that a ski->algo > 110 is illegal, but I'm not + erroring on it here as otherwise there would be no + way to delete such a key. */ + ski->s2k.mode = iobuf_get_noeof (inp); pktlen--; - sk->protect.s2k.hash_algo = iobuf_get_noeof (inp); + ski->s2k.hash_algo = iobuf_get_noeof (inp); pktlen--; - /* check for the special GNU extension */ - if (is_v4 && sk->protect.s2k.mode == 101) + /* Check for the special GNU extension. */ + if (is_v4 && ski->s2k.mode == 101) { for (i = 0; i < 4 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); @@ -1999,26 +1992,30 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, { if (list_mode) es_fprintf (listfp, "\tunknown S2K %d\n", - sk->protect.s2k.mode); - rc = G10ERR_INVALID_PACKET; + ski->s2k.mode); + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } /* Here we know that it is a GNU extension. What * follows is the GNU protection mode: All values * have special meanings and they are mapped to MODE * with a base of 1000. */ - sk->protect.s2k.mode = 1000 + temp[3]; + ski->s2k.mode = 1000 + temp[3]; } - switch (sk->protect.s2k.mode) + + /* Read the salt. */ + switch (ski->s2k.mode) { case 1: case 3: for (i = 0; i < 8 && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); - memcpy (sk->protect.s2k.salt, temp, 8); + memcpy (ski->s2k.salt, temp, 8); break; } - switch (sk->protect.s2k.mode) + + /* Check the mode. */ + switch (ski->s2k.mode) { case 0: if (list_mode) @@ -2043,202 +2040,163 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, default: if (list_mode) es_fprintf (listfp, "\tunknown %sS2K %d\n", - sk->protect.s2k.mode < 1000 ? "" : "GNU ", - sk->protect.s2k.mode); - rc = G10ERR_INVALID_PACKET; + ski->s2k.mode < 1000 ? "" : "GNU ", + ski->s2k.mode); + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } + /* Print some info. */ if (list_mode) { es_fprintf (listfp, ", algo: %d,%s hash: %d", - sk->protect.algo, - sk->protect.sha1chk ? " SHA1 protection," - : " simple checksum,", sk->protect.s2k.hash_algo); - if (sk->protect.s2k.mode == 1 || sk->protect.s2k.mode == 3) + ski->algo, + ski->sha1chk ? " SHA1 protection," + : " simple checksum,", ski->s2k.hash_algo); + if (ski->s2k.mode == 1 || ski->s2k.mode == 3) { es_fprintf (listfp, ", salt: "); - es_write_hexstring (listfp, sk->protect.s2k.salt, 8, - 0, NULL); + es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL); } es_putc ('\n', listfp); } - if (sk->protect.s2k.mode == 3) + /* Read remaining protection parameters. */ + if (ski->s2k.mode == 3) { if (pktlen < 1) { - rc = G10ERR_INVALID_PACKET; + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - sk->protect.s2k.count = iobuf_get (inp); + ski->s2k.count = iobuf_get (inp); pktlen--; if (list_mode) es_fprintf (listfp, "\tprotect count: %lu\n", - (ulong) sk->protect.s2k.count); + (ulong) ski->s2k.count); } - else if (sk->protect.s2k.mode == 1002) + else if (ski->s2k.mode == 1002) { /* Read the serial number. */ if (pktlen < 1) { - rc = G10ERR_INVALID_PACKET; + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } snlen = iobuf_get (inp); pktlen--; if (pktlen < snlen || snlen == -1) { - rc = G10ERR_INVALID_PACKET; + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } } } else /* Old version; no S2K, so we set mode to 0, hash MD5. */ { - /* Note that a sk->protect.algo > 110 is illegal, but - I'm not erroring on it here as otherwise there would - be no way to delete such a key. */ - sk->protect.s2k.mode = 0; - sk->protect.s2k.hash_algo = DIGEST_ALGO_MD5; + /* Note that a ski->algo > 110 is illegal, but I'm not + erroring on it here as otherwise there would be no + way to delete such a key. */ + ski->s2k.mode = 0; + ski->s2k.hash_algo = DIGEST_ALGO_MD5; if (list_mode) es_fprintf (listfp, "\tprotect algo: %d (hash algo: %d)\n", - sk->protect.algo, sk->protect.s2k.hash_algo); + ski->algo, ski->s2k.hash_algo); } /* It is really ugly that we don't know the size * of the IV here in cases we are not aware of the algorithm. * so a - * sk->protect.ivlen = cipher_get_blocksize(sk->protect.algo); + * ski->ivlen = cipher_get_blocksize (ski->algo); * won't work. The only solution I see is to hardwire it. * NOTE: if you change the ivlen above 16, don't forget to * enlarge temp. */ - sk->protect.ivlen = openpgp_cipher_blocklen (sk->protect.algo); - assert (sk->protect.ivlen <= sizeof (temp)); + ski->ivlen = openpgp_cipher_blocklen (ski->algo); + assert (ski->ivlen <= sizeof (temp)); - if (sk->protect.s2k.mode == 1001) - sk->protect.ivlen = 0; - else if (sk->protect.s2k.mode == 1002) - sk->protect.ivlen = snlen < 16 ? snlen : 16; + if (ski->s2k.mode == 1001) + ski->ivlen = 0; + else if (ski->s2k.mode == 1002) + ski->ivlen = snlen < 16 ? snlen : 16; - if (pktlen < sk->protect.ivlen) + if (pktlen < ski->ivlen) { - rc = G10ERR_INVALID_PACKET; + err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - for (i = 0; i < sk->protect.ivlen && pktlen; i++, pktlen--) + for (i = 0; i < ski->ivlen && pktlen; i++, pktlen--) temp[i] = iobuf_get_noeof (inp); if (list_mode) { es_fprintf (listfp, - sk->protect.s2k.mode == 1002 ? "\tserial-number: " - : "\tprotect IV: "); - for (i = 0; i < sk->protect.ivlen; i++) + ski->s2k.mode == 1002 ? "\tserial-number: " + : "\tprotect IV: "); + for (i = 0; i < ski->ivlen; i++) es_fprintf (listfp, " %02x", temp[i]); es_putc ('\n', listfp); } - memcpy (sk->protect.iv, temp, sk->protect.ivlen); + memcpy (ski->iv, temp, ski->ivlen); } - else - sk->is_protected = 0; /* It does not make sense to read it into secure memory. * If the user is so careless, not to protect his secret key, * we can assume, that he operates an open system :=(. * So we put the key into secure memory when we unprotect it. */ - if (sk->protect.s2k.mode == 1001 || sk->protect.s2k.mode == 1002) + if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002) { /* Better set some dummy stuff here. */ - sk->skey[npkey] = gcry_mpi_set_opaque (NULL, + pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10 * 8); pktlen = 0; } - else if (is_v4 && sk->is_protected) + else if (is_v4 && ski->is_protected) { /* Ugly: The length is encrypted too, so we read all stuff * up to the end of the packet into the first SKEY * element. */ - sk->skey[npkey] = gcry_mpi_set_opaque (NULL, + pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, read_rest (inp, pktlen, 0), pktlen * 8); pktlen = 0; if (list_mode) - { - es_fprintf (listfp, "\tencrypted stuff follows\n"); - } + es_fprintf (listfp, "\tskey[%d]: [v4 protected]\n", npkey); } - else /* The v3 method: The mpi length is not encrypted. */ + else { + /* The v3 method: The mpi length is not encrypted. */ for (i = npkey; i < nskey; i++) { - if (sk->is_protected) + if (ski->is_protected) { - sk->skey[i] = read_protected_v3_mpi (inp, &pktlen); + pk->pkey[i] = read_protected_v3_mpi (inp, &pktlen); if (list_mode) - es_fprintf (listfp, "\tskey[%d]: [encrypted]\n", i); + es_fprintf (listfp, "\tskey[%d]: [v3 protected]\n", i); } else { n = pktlen; - sk->skey[i] = mpi_read (inp, &n, 0); + pk->pkey[i] = mpi_read (inp, &n, 0); pktlen -= n; if (list_mode) { es_fprintf (listfp, "\tskey[%d]: ", i); - mpi_print (listfp, sk->skey[i], mpi_print_mode); + mpi_print (listfp, pk->pkey[i], mpi_print_mode); es_putc ('\n', listfp); } } - if (!sk->skey[i]) - rc = G10ERR_INVALID_PACKET; + if (!pk->pkey[i]) + err = gpg_error (GPG_ERR_INV_PACKET); } - if (rc) + if (err) goto leave; - sk->csum = read_16 (inp); + ski->csum = read_16 (inp); pktlen -= 2; if (list_mode) - { - es_fprintf (listfp, "\tchecksum: %04hx\n", sk->csum); - } + es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum); } - - if (list_mode) - keyid_from_sk (sk, keyid); - } - else - { - PKT_public_key *pk = pkt->pkt.public_key; - - if (!npkey) - { - pk->pkey[0] = gcry_mpi_set_opaque (NULL, - read_rest (inp, pktlen, 0), - pktlen * 8); - pktlen = 0; - goto leave; - } - - for (i = 0; i < npkey; i++) - { - n = pktlen; - pk->pkey[i] = mpi_read (inp, &n, 0); - pktlen -= n; - if (list_mode) - { - es_fprintf (listfp, "\tpkey[%d]: ", i); - mpi_print (listfp, pk->pkey[i], mpi_print_mode); - es_putc ('\n', listfp); - } - if (!pk->pkey[i]) - rc = G10ERR_INVALID_PACKET; - } - if (rc) - goto leave; - if (list_mode) - keyid_from_pk (pk, keyid); } if (list_mode) |