aboutsummaryrefslogtreecommitdiffstats
path: root/g10/parse-packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/parse-packet.c')
-rw-r--r--g10/parse-packet.c270
1 files changed, 211 insertions, 59 deletions
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index aa6bac9da..8bd283b4b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -188,6 +188,109 @@ mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
}
+/* If NLENGTH is zero read an octet string of length NBYTES from INP
+ * and return it at R_DATA.
+ *
+ * If NLENGTH is either 1, 2, or 4 and NLENGTH is zero read an
+ * NLENGTH-octet count and use this count number octets from INP and
+ * return it at R_DATA.
+ *
+ * On error return an error code and store NULL at R_DATA. PKTLEN
+ * shall give the current length of the packet and is updated with
+ * each read. If SECURE is true, the integer is stored in 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)
+{
+ gpg_error_t err;
+ int c, i;
+ byte *buf = NULL;
+ byte *p;
+
+ *r_data = NULL;
+
+ if ((nbytes && nlength)
+ || (!nbytes && !(nlength == 1 || nlength == 2 || nlength == 4)))
+ {
+ err = gpg_error (GPG_ERR_INV_ARG);
+ goto leave;
+ }
+
+ if (nlength)
+ {
+ for (i = 0; i < nlength; i++)
+ {
+ if (!*pktlen)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ c = iobuf_readbyte (inp);
+ if (c < 0)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ --*pktlen;
+ nbytes <<= 8;
+ nbytes |= c;
+ }
+
+ if (!nbytes)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ }
+
+ if (nbytes*8 > (nbytes==4? MAX_EXTERN_KEYPARM_BITS:MAX_EXTERN_MPI_BITS)
+ || (nbytes*8 < nbytes))
+ {
+ log_error ("octet string too large (%u octets)\n", nbytes);
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ goto leave;
+ }
+
+ if (nbytes > *pktlen)
+ {
+ log_error ("octet string larger than packet (%u octets)\n", nbytes);
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
+ buf = secure ? gcry_malloc_secure (nbytes) : gcry_malloc (nbytes);
+ if (!buf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ p = buf;
+ for (i = 0; i < nbytes; i++)
+ {
+ c = iobuf_get (inp);
+ if (c == -1)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
+ p[i] = c;
+ --*pktlen;
+ }
+
+ *r_data = gcry_mpi_set_opaque (NULL, buf, nbytes*8);
+ gcry_mpi_set_flag (*r_data, GCRYMPI_FLAG_USER2);
+ return 0;
+
+ leave:
+ gcry_free (buf);
+ 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
@@ -1102,32 +1205,29 @@ read_rest (IOBUF inp, size_t pktlen)
/* Read a special size+body from INP. On success store an opaque MPI
- with it at R_DATA. On error return an error code and store NULL at
- R_DATA. Even in the error case store the number of read bytes at
- R_NREAD. The caller shall pass the remaining size of the packet in
- PKTLEN. */
+ * with it at R_DATA. The caller shall store the remaining size of
+ * the packet at PKTLEN. On error return an error code and store NULL
+ * at R_DATA. Even in the error case store the number of read bytes
+ * at PKTLEN is updated. */
static gpg_error_t
-read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
- gcry_mpi_t *r_data)
+read_sized_octet_string (iobuf_t inp, unsigned long *pktlen, gcry_mpi_t *r_data)
{
char buffer[256];
char *tmpbuf;
int i, c, nbytes;
- *r_nread = 0;
*r_data = NULL;
- if (!pktlen)
+ if (!*pktlen)
return gpg_error (GPG_ERR_INV_PACKET);
c = iobuf_readbyte (inp);
if (c < 0)
return gpg_error (GPG_ERR_INV_PACKET);
- pktlen--;
- ++*r_nread;
+ --*pktlen;
nbytes = c;
if (nbytes < 2 || nbytes > 254)
return gpg_error (GPG_ERR_INV_PACKET);
- if (nbytes > pktlen)
+ if (nbytes > *pktlen)
return gpg_error (GPG_ERR_INV_PACKET);
buffer[0] = nbytes;
@@ -1137,7 +1237,7 @@ read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
c = iobuf_get (inp);
if (c < 0)
return gpg_error (GPG_ERR_INV_PACKET);
- ++*r_nread;
+ --*pktlen;
buffer[1+i] = c;
}
@@ -1344,12 +1444,14 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
}
+/* Parse a public key encrypted packet (Tag 1). */
static int
parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
PACKET * packet)
{
int rc = 0;
int i, ndata;
+ unsigned int n;
PKT_pubkey_enc *k;
k = packet->pkt.pubkey_enc = xmalloc_clear (sizeof *packet->pkt.pubkey_enc);
@@ -1392,46 +1494,78 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
unknown_pubkey_warning (k->pubkey_algo);
k->data[0] = NULL; /* No need to store the encrypted data. */
}
+ else if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
+ {
+ log_assert (ndata == 2);
+ /* Get the ephemeral public key. */
+ n = pktlen;
+ k->data[0] = sos_read (inp, &n, 0);
+ pktlen -= n;
+ if (!k->data[0])
+ {
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ /* Get the wrapped symmetric key. */
+ rc = read_sized_octet_string (inp, &pktlen, k->data + 1);
+ if (rc)
+ goto leave;
+ }
+ else if (k->pubkey_algo == PUBKEY_ALGO_KYBER)
+ {
+ log_assert (ndata == 3);
+ /* Get the ephemeral public key. */
+ n = pktlen;
+ k->data[0] = sos_read (inp, &n, 0);
+ pktlen -= n;
+ if (!k->data[0])
+ {
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ /* Get the Kyber ciphertext. */
+ rc = read_octet_string (inp, &pktlen, 4, 0, 0, k->data + 1);
+ if (rc)
+ goto leave;
+ /* Get the algorithm id for the session key. */
+ if (!pktlen)
+ {
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ 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);
+ if (rc)
+ goto leave;
+ }
else
{
for (i = 0; i < ndata; i++)
{
- if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
- {
- if (i == 1)
- {
- size_t n;
- rc = read_size_body (inp, pktlen, &n, k->data+i);
- pktlen -= n;
- }
- else
- {
- int n = pktlen;
- k->data[i] = sos_read (inp, &n, 0);
- pktlen -= n;
- if (!k->data[i])
- rc = gpg_error (GPG_ERR_INV_PACKET);
- }
- }
- else
- {
- int n = pktlen;
- k->data[i] = mpi_read (inp, &n, 0);
- pktlen -= n;
- if (!k->data[i])
- rc = gpg_error (GPG_ERR_INV_PACKET);
- }
- if (rc)
- goto leave;
- if (list_mode)
- {
- es_fprintf (listfp, "\tdata: ");
- mpi_print (listfp, k->data[i], mpi_print_mode);
- es_putc ('\n', listfp);
- }
+ n = pktlen;
+ k->data[i] = mpi_read (inp, &n, 0);
+ pktlen -= n;
+ if (!k->data[i])
+ rc = gpg_error (GPG_ERR_INV_PACKET);
+ }
+ if (rc)
+ goto leave;
+ }
+ if (list_mode)
+ {
+ if (k->seskey_algo)
+ es_fprintf (listfp, "\tsession key algo: %d\n", k->seskey_algo);
+ for (i = 0; i < ndata; i++)
+ {
+ es_fprintf (listfp, "\tdata: ");
+ mpi_print (listfp, k->data[i], mpi_print_mode);
+ es_putc ('\n', listfp);
}
}
+
leave:
iobuf_skip_rest (inp, pktlen, 0);
return rc;
@@ -2598,19 +2732,25 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{
if ( (algorithm == PUBKEY_ALGO_ECDSA && (i == 0))
|| (algorithm == PUBKEY_ALGO_EDDSA && (i == 0))
- || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
+ || (algorithm == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))
+ || (algorithm == PUBKEY_ALGO_KYBER && (i == 0)))
{
/* Read the OID (i==0) or the KDF params (i==2). */
- size_t n;
- err = read_size_body (inp, pktlen, &n, pk->pkey+i);
- pktlen -= n;
+ err = read_sized_octet_string (inp, &pktlen, pk->pkey+i);
+ }
+ 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);
}
else
{
+ /* Read MPI or SOS. */
unsigned int n = pktlen;
if (algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH)
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER)
pk->pkey[i] = sos_read (inp, &n, 0);
else
pk->pkey[i] = mpi_read (inp, &n, 0);
@@ -2626,7 +2766,8 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
mpi_print (listfp, pk->pkey[i], mpi_print_mode);
if ((algorithm == PUBKEY_ALGO_ECDSA
|| algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH) && i==0)
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER) && i==0)
{
char *curve = openpgp_oid_to_str (pk->pkey[0]);
const char *name = openpgp_oid_to_curve (curve, 0);
@@ -2963,21 +3104,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
/* Not encrypted. */
for (i = npkey; i < nskey; i++)
{
- unsigned int n;
if (pktlen < 2) /* At least two bytes for the length. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
- n = pktlen;
- if (algorithm == PUBKEY_ALGO_ECDSA
- || algorithm == PUBKEY_ALGO_EDDSA
- || algorithm == PUBKEY_ALGO_ECDH)
- pk->pkey[i] = sos_read (inp, &n, 0);
+ if (algorithm == PUBKEY_ALGO_KYBER && i == npkey+1)
+ {
+ err = read_octet_string (inp, &pktlen, 4, 0, 1, pk->pkey+i);
+ if (err)
+ goto leave;
+ }
else
- pk->pkey[i] = mpi_read (inp, &n, 0);
- pktlen -= n;
+ {
+ unsigned int n = pktlen;
+
+ if (algorithm == PUBKEY_ALGO_ECDSA
+ || algorithm == PUBKEY_ALGO_EDDSA
+ || algorithm == PUBKEY_ALGO_ECDH
+ || algorithm == PUBKEY_ALGO_KYBER)
+ pk->pkey[i] = sos_read (inp, &n, 0);
+ else
+ pk->pkey[i] = mpi_read (inp, &n, 0);
+ pktlen -= n;
+ }
+
if (list_mode)
{
es_fprintf (listfp, "\tskey[%d]: ", i);