diff options
Diffstat (limited to 'g10/parse-packet.c')
| -rw-r--r-- | g10/parse-packet.c | 615 |
1 files changed, 512 insertions, 103 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c index a9d6dd264..aaa96b3c5 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -38,6 +38,11 @@ #include "../common/mbox-util.h" +/* It is better to always allow parsing the 9980 packets but we keep + * the macro for documentaion reasons. */ +#undef RFC9980 +#define RFC9980 1 + static int mpi_print_mode; static int list_mode; static estream_t listfp; @@ -81,9 +86,9 @@ static int parse_compressed (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb, int partial); -static gpg_error_t parse_encrypted_aead (IOBUF inp, int pkttype, - unsigned long pktlen, PACKET *packet, - int partial); +static gpg_error_t parse_encrypted_ocb (iobuf_t inp, int pkttype, + unsigned long pktlen, PACKET *packet, + int partial); static int parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet, int new_ctb); static int parse_gpg_control (IOBUF inp, int pkttype, unsigned long pktlen, @@ -201,9 +206,9 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure) * memory (allocated using gcry_xmalloc_secure). */ static gpg_error_t -read_octet_string (iobuf_t inp, unsigned long *pktlen, - unsigned int nlength, unsigned int nbytes, - int secure, gcry_mpi_t *r_data) +read_raw_octet_string (iobuf_t inp, unsigned long *pktlen, + unsigned int nlength, unsigned int nbytes, + int secure, gcry_mpi_t *r_data) { gpg_error_t err; int c, i; @@ -256,7 +261,7 @@ read_octet_string (iobuf_t inp, unsigned long *pktlen, if (nbytes > *pktlen) { - log_error ("octet string larger than packet (%u octets)\n", nbytes); + log_error ("octet string larger than packet (%u/%lu)\n", nbytes, *pktlen); err = gpg_error (GPG_ERR_INV_PACKET); goto leave; } @@ -282,7 +287,6 @@ read_octet_string (iobuf_t inp, unsigned long *pktlen, } *r_data = gcry_mpi_set_opaque (NULL, buf, nbytes*8); - gcry_mpi_set_flag (*r_data, GCRYMPI_FLAG_USER2); return 0; leave: @@ -291,6 +295,22 @@ read_octet_string (iobuf_t inp, unsigned long *pktlen, } +/* Read a simple octet string (SOS) and mark the result as such a + * value. For details see read_raw_octet_string. */ +static gpg_error_t +read_sos_octet_string (iobuf_t inp, unsigned long *pktlen, + unsigned int nlength, unsigned int nbytes, + int secure, gcry_mpi_t *r_data) +{ + gpg_error_t err; + + err = read_raw_octet_string (inp, pktlen, nlength, nbytes, secure, r_data); + if (!err) + gcry_mpi_set_flag (*r_data, GCRYMPI_FLAG_USER2); + return err; +} + + /* Read an external representation of an SOS and return the opaque MPI with GCRYMPI_FLAG_USER2. The external format is a 16-bit unsigned value stored in network byte order giving information for the @@ -747,7 +767,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, again: log_assert (!pkt->pkt.generic); - if (retpos || list_mode) + if (retpos || list_mode || opt.verbose > 1) { pos = iobuf_tell (inp); if (retpos) @@ -850,7 +870,7 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_PLAINTEXT: case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: - case PKT_ENCRYPTED_AEAD: + case PKT_ENCRYPTED_OCB: case PKT_COMPRESSED: iobuf_set_partial_body_length_mode (inp, c & 0xff); pktlen = 0; /* To indicate partial length. */ @@ -1034,8 +1054,8 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, case PKT_MDC: rc = parse_mdc (inp, pkttype, pktlen, pkt, new_ctb); break; - case PKT_ENCRYPTED_AEAD: - rc = parse_encrypted_aead (inp, pkttype, pktlen, pkt, partial); + case PKT_ENCRYPTED_OCB: + rc = parse_encrypted_ocb (inp, pkttype, pktlen, pkt, partial); break; case PKT_GPG_CONTROL: rc = parse_gpg_control (inp, pkttype, pktlen, pkt, partial); @@ -1049,6 +1069,17 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos, break; } + if (gpg_err_code (rc) == GPG_ERR_INV_PACKET && opt.verbose > 1) + { + log_error ("parse_packet: read error: %s\n", gpg_strerror (rc)); + print_further_info + ("packet %u off=%lu ctb=%02x tag=%d hlen=%d plen=%lu%s%s", + ctx->n_parsed_packets, + (unsigned long)pos, ctb, pkttype, hdrlen, pktlen, + partial? (new_ctb ? " partial" : " indeterminate") :"", + new_ctb? " new-ctb":""); + } + /* Store a shallow copy of certain packets in the context. */ free_packet (NULL, ctx); if (!rc && (pkttype == PKT_PUBLIC_KEY @@ -1457,6 +1488,7 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet) { int rc = 0; + int is_v6 = 0; int i, ndata; unsigned int n; PKT_pubkey_enc *k; @@ -1472,7 +1504,11 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, } k->version = iobuf_get_noeof (inp); pktlen--; - if (k->version != 2 && k->version != 3) + if (k->version == 2 || k->version == 3) + ; + else if (RFC9980 && k->version == 6) + is_v6 = 1; + else { log_error ("packet(%d) with unknown version %d\n", pkttype, k->version); if (list_mode) @@ -1480,10 +1516,66 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - k->keyid[0] = read_32 (inp); - pktlen -= 4; - k->keyid[1] = read_32 (inp); - pktlen -= 4; + + if (is_v6) + { + int keyver; + + k->fprlen = iobuf_get_noeof (inp); /* Actually the 1 + fprlen. */ + pktlen--; + if (k->fprlen) + { + keyver = iobuf_get_noeof (inp); + pktlen--; k->fprlen--; + /* fprlen has now the correct value. */ + if (pktlen < k->fprlen || k->fprlen > MAX_FINGERPRINT_LEN) + { + log_error ("packet(%d) too short for fingerprint (%d)\n", + pkttype, k->fprlen); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + if (iobuf_read (inp, k->fpr, k->fprlen) != k->fprlen) + { + log_error ("premature eof while reading " + "fingerprint from packet(%d)\n", pkttype); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + pktlen -= k->fprlen; + if (k->fprlen == 20 && keyver == 4) + { + k->keyid[0] = buf32_to_u32 (k->fpr+12); + k->keyid[1] = buf32_to_u32 (k->fpr+16); + } + else if (k->fprlen == 32 && keyver >= 5) + { + k->keyid[0] = buf32_to_u32 (k->fpr); + k->keyid[1] = buf32_to_u32 (k->fpr+4); + } + else + { + log_error ("packet(%d) inconsistent fingerprint (v=%d,n=%d)\n", + pkttype, keyver, k->fprlen); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + } + } + else + { + k->keyid[0] = read_32 (inp); + pktlen -= 4; + k->keyid[1] = read_32 (inp); + pktlen -= 4; + } + + if (!pktlen) + { + log_error ("packet(%d) too short for public-key algo\n", pkttype); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } k->pubkey_algo = iobuf_get_noeof (inp); pktlen--; k->throw_keyid = 0; /* Only used as flag for build_packet. */ @@ -1518,6 +1610,38 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, if (rc) goto leave; } + else if (k->pubkey_algo == PUBKEY_ALGO_X25519 && RFC9980) + { + log_assert (ndata == 2); + /* Get the ephemeral public key. */ + rc = read_raw_octet_string (inp, &pktlen, 0, 32, 0, k->data + 0); + if (rc) + goto leave; + if (pktlen < 2) + { + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + n = iobuf_get_noeof (inp); + pktlen--; + if (list_mode) + es_fprintf (listfp, "\tlength octet: %u\n", n); + if (!is_v6) + { + k->seskey_algo = iobuf_get_noeof (inp); + if (!n || !pktlen) + { + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + pktlen--; + n--; + } + /* Get the encrypted symmetric key (keylen+8 due to AESWRAP). */ + rc = read_raw_octet_string (inp, &pktlen, 0, n, 0, k->data + 1); + if (rc) + goto leave; + } else if (k->pubkey_algo == PUBKEY_ALGO_KYBER) { log_assert (ndata == 3); @@ -1531,7 +1655,7 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } /* Get the Kyber ciphertext. */ - rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1); + rc = read_sos_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1); if (rc) goto leave; /* Get the algorithm id for the session key. */ @@ -1543,7 +1667,56 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen, k->seskey_algo = iobuf_get_noeof (inp); pktlen--; /* Get the encrypted symmetric key. */ - rc = read_octet_string (inp, &pktlen, 1, 0, 0, k->data + 2); + rc = read_sos_octet_string (inp, &pktlen, 1, 0, 0, k->data + 2); + if (rc) + goto leave; + } + else if (IS_PUBKEY_ALGO_MLK (k->pubkey_algo)) + { + log_assert (ndata == 3); + /* Get the ephemeral public key. */ + rc = read_raw_octet_string + (inp, &pktlen, 0, + (k->pubkey_algo == PUBKEY_ALGO_MLK768_25519? 32 : + k->pubkey_algo == PUBKEY_ALGO_MLK768_NP384? 97 : + k->pubkey_algo == PUBKEY_ALGO_MLK768_BP384? 97 : + k->pubkey_algo == PUBKEY_ALGO_MLK1024_448? 56 : + k->pubkey_algo == PUBKEY_ALGO_MLK1024_NP521? 133 : + k->pubkey_algo == PUBKEY_ALGO_MLK1024_BP512? 129 : 0), + 0, k->data + 0); + if (rc) + goto leave; + + /* Get the Kyber ciphertext. */ + rc = read_raw_octet_string (inp, &pktlen, 0, + (IS_PUBKEY_ALGO_MLK768 (k->pubkey_algo)? + 1088 : 1568), + 0, k->data + 1); + if (rc) + goto leave; + /* Get the size octet and algo id for the session key. */ + if (pktlen < 2) + { + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + n = iobuf_get_noeof (inp); + pktlen--; + if (list_mode) + es_fprintf (listfp, "\tlength octet: %u\n", n); + if (!is_v6) + { + k->seskey_algo = iobuf_get_noeof (inp); + if (!n || !pktlen) + { + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + pktlen--; + n--; + } + /* Get the encrypted symmetric key (keylen+8 due to AESWRAP). */ + rc = read_raw_octet_string (inp, &pktlen, 0, n, 0, k->data + 2); if (rc) goto leave; } @@ -2235,8 +2408,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, PKT_signature * sig) { int md5_len = 0; - unsigned n; - int is_v4or5 = 0; + unsigned int n; + int is_v4plus = 0; int rc = 0; int i, ndata; @@ -2249,8 +2422,9 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, } sig->version = iobuf_get_noeof (inp); pktlen--; - if (sig->version == 4 || sig->version == 5) - is_v4or5 = 1; + if (sig->version == 4 || sig->version == 5 + || (sig->version == 6 && RFC9980)) + is_v4plus = 1; else if (sig->version != 2 && sig->version != 3) { log_error ("packet(%d) with unknown version %d\n", @@ -2261,7 +2435,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, goto leave; } - if (!is_v4or5) + if (!is_v4plus) { if (pktlen == 0) goto underflow; @@ -2272,7 +2446,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, goto underflow; sig->sig_class = iobuf_get_noeof (inp); pktlen--; - if (!is_v4or5) + if (!is_v4plus) { if (pktlen < 12) goto underflow; @@ -2291,12 +2465,22 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, pktlen--; sig->flags.exportable = 1; sig->flags.revocable = 1; - if (is_v4or5) /* Read subpackets. */ + if (is_v4plus) /* Read subpackets. */ { - if (pktlen < 2) - goto underflow; - n = read_16 (inp); - pktlen -= 2; /* Length of hashed data. */ + if (sig->version == 6) + { + if (pktlen < 4) + goto underflow; + n = read_32 (inp); + pktlen -= 4; /* Length of hashed data. */ + } + else + { + if (pktlen < 2) + goto underflow; + n = read_16 (inp); + pktlen -= 2; /* Length of hashed data. */ + } if (pktlen < n) goto underflow; if (n > 30000) @@ -2324,10 +2508,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, } pktlen -= n; } - if (pktlen < 2) - goto underflow; - n = read_16 (inp); - pktlen -= 2; /* Length of unhashed data. */ + if (sig->version == 6) + { + if (pktlen < 4) + goto underflow; + n = read_32 (inp); + pktlen -= 4; /* Length of unhashed data. */ + } + else + { + if (pktlen < 2) + goto underflow; + n = read_16 (inp); + pktlen -= 2; /* Length of unhashed data. */ + } if (pktlen < n) goto underflow; if (n > 10000) @@ -2365,7 +2559,23 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, sig->digest_start[1] = iobuf_get_noeof (inp); pktlen--; - if (is_v4or5 && sig->pubkey_algo) /* Extract required information. */ + if (sig->version == 6) + { + int saltlen; + + /* Note that we allow for a zero length salt. */ + saltlen = iobuf_get (inp); + if (saltlen < 0 || !pktlen) + rc = gpg_error (GPG_ERR_INV_PACKET); + else if (saltlen) + rc = read_raw_octet_string (inp, &pktlen, 0, saltlen, 0, &sig->salt); + pktlen--; /* Adjust for saltlen octet read above. */ + + if (rc) + goto leave; + } + + if (is_v4plus && sig->pubkey_algo) /* Extract required information. */ { const byte *p; size_t len; @@ -2392,7 +2602,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, sig->keyid[0] = buf32_to_u32 (p + 1 + 12); sig->keyid[1] = buf32_to_u32 (p + 1 + 16); } - else if (p && len == 33 && p[0] == 5) + else if (p && len == 33 && (p[0] == 5 || p[0] == 6)) { sig->keyid[0] = buf32_to_u32 (p + 1 ); sig->keyid[1] = buf32_to_u32 (p + 1 + 4); @@ -2512,7 +2722,14 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, (ulong) sig->keyid[0], (ulong) sig->keyid[1], sig->version, (ulong) sig->timestamp, md5_len, sig->sig_class, sig->digest_algo, sig->digest_start[0], sig->digest_start[1]); - if (is_v4or5) + if (sig->version == 6 && sig->salt) + { + es_fprintf (listfp, "\tsalt: "); + mpi_print (listfp, sig->salt, 1 /* Always print the salt. */); + es_putc ('\n', listfp); + } + + if (is_v4plus) { parse_sig_subpkt (sig, 1, SIGSUBPKT_LIST_HASHED, NULL); parse_sig_subpkt (sig, 0, SIGSUBPKT_LIST_UNHASHED, NULL); @@ -2548,13 +2765,22 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen, { for (i = 0; i < ndata; i++) { - n = pktlen; - if (sig->pubkey_algo == PUBKEY_ALGO_ECDSA - || sig->pubkey_algo == PUBKEY_ALGO_EDDSA) - sig->data[i] = sos_read (inp, &n, 0); + if (sig->pubkey_algo == PUBKEY_ALGO_ED25519 && RFC9980) + { + rc = read_raw_octet_string (inp, &pktlen, 0, 64, 0, sig->data+i); + if (rc) + goto leave; + } else - sig->data[i] = mpi_read (inp, &n, 0); - pktlen -= n; + { + n = pktlen; + if (sig->pubkey_algo == PUBKEY_ALGO_ECDSA + || sig->pubkey_algo == PUBKEY_ALGO_EDDSA) + sig->data[i] = sos_read (inp, &n, 0); + else + sig->data[i] = mpi_read (inp, &n, 0); + pktlen -= n; + } if (list_mode) { es_fprintf (listfp, "\tdata: "); @@ -2585,7 +2811,6 @@ static int parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen, PKT_onepass_sig * ops) { - int version; int rc = 0; if (pktlen < 13) @@ -2596,11 +2821,11 @@ parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen, rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - version = iobuf_get_noeof (inp); + ops->version = iobuf_get_noeof (inp); pktlen--; - if (version != 3) + if (!(ops->version == 3 || (RFC9980 && ops->version == 6))) { - log_error ("onepass_sig with unknown version %d\n", version); + log_error ("onepass_sig with unknown version %d\n", ops->version); if (list_mode) es_fputs (":onepass_sig packet: [unknown version]\n", listfp); rc = gpg_error (GPG_ERR_INV_PACKET); @@ -2612,21 +2837,63 @@ parse_onepass_sig (IOBUF inp, int pkttype, unsigned long pktlen, pktlen--; ops->pubkey_algo = iobuf_get_noeof (inp); pktlen--; - ops->keyid[0] = read_32 (inp); - pktlen -= 4; - ops->keyid[1] = read_32 (inp); - pktlen -= 4; + + if (ops->version == 6) + { + /* FIXME: We should save the fingerprint and check it against + * the regular packet. Howeever, we have not done that for + * keyid either. */ + unsigned char fpr[32]; + + rc = read_raw_octet_string (inp, &pktlen, 1, 0, 0, &ops->salt); + if (rc) + goto leave; + + if (pktlen < sizeof fpr) + { + log_error ("packet(%d) too short for fingerprint (%lu/%zu)\n", + pkttype, pktlen, sizeof fpr); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + if (iobuf_read (inp, fpr, sizeof fpr) != sizeof fpr) + { + log_error ("premature eof while reading " + "fingerprint from packet(%d)\n", pkttype); + rc = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + pktlen -= sizeof fpr; + + ops->keyid[0] = buf32_to_u32 (fpr); + ops->keyid[1] = buf32_to_u32 (fpr+4); + } + else + { + ops->keyid[0] = read_32 (inp); + pktlen -= 4; + ops->keyid[1] = read_32 (inp); + pktlen -= 4; + } + ops->last = iobuf_get_noeof (inp); pktlen--; if (list_mode) - es_fprintf (listfp, - ":onepass_sig packet: keyid %08lX%08lX\n" - "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, " - "last=%d\n", - (ulong) ops->keyid[0], (ulong) ops->keyid[1], - version, ops->sig_class, - ops->digest_algo, ops->pubkey_algo, ops->last); - + { + es_fprintf (listfp, + ":onepass_sig packet: keyid %08lX%08lX\n" + "\tversion %d, sigclass 0x%02x, digest %d, pubkey %d, " + "last=%d\n", + (ulong) ops->keyid[0], (ulong) ops->keyid[1], + ops->version, ops->sig_class, + ops->digest_algo, ops->pubkey_algo, ops->last); + if (ops->version == 6 && ops->salt) + { + es_fprintf (listfp, "\tsalt: "); + mpi_print (listfp, ops->salt, 1); + es_putc ('\n', listfp); + } + } leave: iobuf_skip_rest (inp, pktlen, 0); @@ -2644,7 +2911,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, int npkey, nskey; u32 keyid[2]; PKT_public_key *pk; - int is_v5; + int is_v5 = 0; + int is_v6 = 0; unsigned int pkbytes; /* For v5 keys: Number of bytes in the public * key material. For v4 keys: 0. */ @@ -2678,9 +2946,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, return 0; } else if (version == 4) - is_v5 = 0; + ; else if (version == 5) is_v5 = 1; + else if (version == 6 && RFC9980) + is_v6 = 1; else if (version == 2 || version == 3) { /* Not anymore supported since 2.1. Use an older gpg version @@ -2725,7 +2995,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, max_expiredate = 0; algorithm = iobuf_get_noeof (inp); pktlen--; - if (is_v5) + if (is_v5 || is_v6) { pkbytes = read_32 (inp); pktlen -= 4; @@ -2742,7 +3012,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, pkttype == PKT_PUBLIC_SUBKEY ? "public sub" : pkttype == PKT_SECRET_SUBKEY ? "secret sub" : "??", version, algorithm, timestamp, expiredate); - if (is_v5) + if (is_v5 || is_v6) es_fprintf (listfp, ", pkbytes %u\n", pkbytes); else es_fprintf (listfp, "\n"); @@ -2790,7 +3060,55 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, else if (algorithm == PUBKEY_ALGO_KYBER && i == 2) { /* Read the four-octet count prefixed Kyber public key. */ - err = read_octet_string (inp, &pktlen, 4, 0, 0, pk->pkey+i); + err = read_sos_octet_string (inp, &pktlen, 4, 0, 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_X25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, + 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_MLK768_25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, i==0? 32 : 1184, + 0, pk->pkey+i); + } + else if ((algorithm == PUBKEY_ALGO_MLK768_NP384 + || algorithm == PUBKEY_ALGO_MLK768_BP384) && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, i==0? 97 : 1184, + 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_448 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, i==0? 56 : 1568, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_NP521 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, i==0? 133 : 1568, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_BP512 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, i==0? 129 : 1568, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_X25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_ED25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, 0, pk->pkey+i); } else { @@ -2865,7 +3183,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, ski->algo = iobuf_get_noeof (inp); pktlen--; - if (is_v5) + if (is_v5 || (is_v6 && ski->algo)) { unsigned int protcount = 0; @@ -3166,7 +3484,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, /* Not encrypted. */ for (i = npkey; i < nskey; i++) { - if (pktlen < 2) /* At least two bytes for the length. */ { err = gpg_error (GPG_ERR_INV_PACKET); @@ -3174,10 +3491,66 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, } if (algorithm == PUBKEY_ALGO_KYBER && i == npkey+1) { - err = read_octet_string (inp, &pktlen, 4, 0, 1, pk->pkey+i); + err = read_sos_octet_string (inp, &pktlen, 4, 0, + 1, pk->pkey+i); if (err) goto leave; } + else if (algorithm == PUBKEY_ALGO_X25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, + 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_MLK768_25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, + i == npkey? 32 : 64, + 0, pk->pkey+i); + } + else if ((algorithm == PUBKEY_ALGO_MLK768_NP384 + || algorithm == PUBKEY_ALGO_MLK768_BP384) && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, + i == npkey? 48 : 64, + 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_448 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, + i == npkey? 56 : 64, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_NP521 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, + i == npkey? 66 : 64, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_MLK1024_BP512 && RFC9980) + { + if (is_v6) + err = read_raw_octet_string (inp, &pktlen, 0, + i == npkey? 64 : 64, + 0, pk->pkey+i); + else + err = gpg_error (GPG_ERR_INV_PACKET); + } + else if (algorithm == PUBKEY_ALGO_X25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, + 0, pk->pkey+i); + } + else if (algorithm == PUBKEY_ALGO_ED25519 && RFC9980) + { + err = read_raw_octet_string (inp, &pktlen, 0, 32, + 0, pk->pkey+i); + } else { unsigned int n = pktlen; @@ -3205,18 +3578,21 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, if (err) goto leave; - if (pktlen < 2) - { - if (opt.verbose) - log_info ("checksum is missing (remaining bytes: %lu)\n", - pktlen); - err = gpg_error (GPG_ERR_INV_PACKET); - goto leave; - } - ski->csum = read_16 (inp); - pktlen -= 2; - if (list_mode) - es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum); + if (!is_v6) + { + if (pktlen < 2) + { + if (opt.verbose) + log_info ("checksum is missing (remaining bytes: %lu)\n", + pktlen); + err = gpg_error (GPG_ERR_INV_PACKET); + goto leave; + } + ski->csum = read_16 (inp); + pktlen -= 2; + if (list_mode) + es_fprintf (listfp, "\tchecksum: %04hx\n", ski->csum); + } } } @@ -3224,6 +3600,21 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen, if (list_mode) es_fprintf (listfp, "\tkeyid: %08lX%08lX\n", (ulong) keyid[0], (ulong) keyid[1]); + if (list_mode && (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY) + && (opt.list_options & LIST_DEBUG_SHOW_SEXP)) + { + nvc_t nvc = seckey_packet_to_nvc (pk); + + es_fputs ("\ts-exp: ", listfp); + if (!nvc) + es_fputs ("[error getting key]\n", listfp); + else + { + nvc_write (nvc, listfp); + nvc_release (nvc); + } + } + leave: iobuf_skip_rest (inp, pktlen, 0); @@ -3756,31 +4147,43 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, ed->buf = NULL; ed->new_ctb = new_ctb; ed->is_partial = partial; + ed->seipd = 0; + ed->version = 0; ed->aead_algo = 0; + ed->mdc_method = 0; ed->cipher_algo = 0; /* Only used with AEAD. */ ed->chunkbyte = 0; /* Only used with AEAD. */ if (pkttype == PKT_ENCRYPTED_MDC) { - /* Fixme: add some pktlen sanity checks. */ - int version; - - version = iobuf_get_noeof (inp); + ed->seipd = 1; + ed->version = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; - if (version != 1) + if (ed->version == 1) + ed->mdc_method = DIGEST_ALGO_SHA1; + else if (ed->version == 2 && RFC9980) + { + ed->cipher_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->aead_algo = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + ed->chunkbyte = iobuf_get_noeof (inp); + if (orig_pktlen) + pktlen--; + } + else { log_error ("encrypted_mdc packet with unknown version %d\n", - version); + ed->version); if (list_mode) es_fputs (":encrypted data packet: [unknown version]\n", listfp); /*skip_rest(inp, pktlen); should we really do this? */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; } - ed->mdc_method = DIGEST_ALGO_SHA1; } - else - ed->mdc_method = 0; /* A basic sanity check. We need at least an 8 byte IV plus the 2 detection bytes. Note that we don't known the algorithm and thus @@ -3803,13 +4206,17 @@ parse_encrypted (IOBUF inp, int pkttype, unsigned long pktlen, if (list_mode) { + es_fprintf (listfp, ":encrypted data packet:\n\tversion: %d\n", + ed->version); + if (ed->mdc_method) + es_fprintf (listfp, "\t mdc: %d\n", ed->mdc_method); + if (ed->version == 2) + es_fprintf (listfp, "\t cipher: %u\n\t aead: %u\n\t cbyte: %u\n", + ed->cipher_algo, ed->aead_algo, ed->chunkbyte); if (orig_pktlen) - es_fprintf (listfp, ":encrypted data packet:\n\tlength: %lu\n", - orig_pktlen); + es_fprintf (listfp, "\t length: %lu\n", orig_pktlen); else - es_fprintf (listfp, ":encrypted data packet:\n\tlength: unknown\n"); - if (ed->mdc_method) - es_fprintf (listfp, "\tmdc_method: %d\n", ed->mdc_method); + es_fprintf (listfp, "\t length: unknown\n"); } ed->buf = inp; @@ -3850,14 +4257,14 @@ parse_mdc (IOBUF inp, int pkttype, unsigned long pktlen, } +/* Note that PKTLEN may be 0 to indicate partial length encoding. */ static gpg_error_t -parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, - PACKET *pkt, int partial) +parse_encrypted_ocb (iobuf_t inp, int pkttype, unsigned long pktlen, + PACKET *pkt, int partial) { int rc = 0; PKT_encrypted *ed; unsigned long orig_pktlen = pktlen; - int version; ed = pkt->pkt.encrypted = xtrymalloc (sizeof *pkt->pkt.encrypted); if (!ed) @@ -3867,6 +4274,8 @@ parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, ed->buf = NULL; ed->new_ctb = 1; /* (packet number requires a new CTB anyway.) */ ed->is_partial = partial; + ed->seipd = 0; + ed->version = 0; ed->mdc_method = 0; /* A basic sanity check. We need one version byte, one algo byte, * one aead algo byte, one chunkbyte, at least 15 byte IV. */ @@ -3874,21 +4283,21 @@ parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, { log_error ("packet(%d) too short\n", pkttype); if (list_mode) - es_fputs (":aead encrypted packet: [too short]\n", listfp); + es_fputs (":ocb encrypted packet: [too short]\n", listfp); rc = gpg_error (GPG_ERR_INV_PACKET); iobuf_skip_rest (inp, pktlen, partial); goto leave; } - version = iobuf_get_noeof (inp); + ed->version = iobuf_get_noeof (inp); if (orig_pktlen) pktlen--; - if (version != 1) + if (ed->version != 1) { - log_error ("aead encrypted packet with unknown version %d\n", - version); + log_error ("ocb encrypted packet with unknown version %d\n", + ed->version); if (list_mode) - es_fputs (":aead encrypted packet: [unknown version]\n", listfp); + es_fputs (":ocb encrypted packet: [unknown version]\n", listfp); /*skip_rest(inp, pktlen); should we really do this? */ rc = gpg_error (GPG_ERR_INV_PACKET); goto leave; @@ -3910,7 +4319,7 @@ parse_encrypted_aead (iobuf_t inp, int pkttype, unsigned long pktlen, if (list_mode) { - es_fprintf (listfp, ":aead encrypted packet: cipher=%u aead=%u cb=%u\n", + es_fprintf (listfp, ":ocb encrypted packet: cipher=%u aead=%u cb=%u\n", ed->cipher_algo, ed->aead_algo, ed->chunkbyte); if (orig_pktlen) es_fprintf (listfp, "\tlength: %lu\n", orig_pktlen); |
