#include <sys/cdefs.h>
#include <libsecureboot.h>
#include "decode.h"
char *
octets2hex(unsigned char *ptr, size_t n)
{
char *hex;
char *cp;
size_t i;
hex = malloc(2 * n + 1);
if (hex != NULL) {
for (i = 0, cp = hex; i < n; i++) {
snprintf(&cp[i*2], 3, "%02X", ptr[i]);
}
}
return (hex);
}
unsigned char *
i2octets(int n, size_t i)
{
static unsigned char o[16];
int x, j;
if (n > 15)
return (NULL);
for (j = 0, x = n - 1; x >= 0; x--, j++) {
o[j] = (unsigned char)((i & (0xff << x * 8)) >> x * 8);
}
return (o);
}
int
octets2i(unsigned char *ptr, size_t n)
{
size_t i;
int val;
for (val = i = 0; i < n; i++) {
val |= (*ptr++ << ((n - i - 1) * 8));
}
return (val);
}
int
decode_tag(unsigned char *ptr, int *isnew, int *ltype)
{
int tag;
if (!ptr || !isnew || !ltype)
return (-1);
tag = *ptr;
if (!(tag & OPENPGP_TAG_ISTAG))
return (-1);
*isnew = tag & OPENPGP_TAG_ISNEW;
if (*isnew) {
*ltype = -1;
tag &= OPENPGP_TAG_NEW_MASK;
} else {
*ltype = tag & OPENPGP_TAG_OLD_TYPE;
tag = (tag & OPENPGP_TAG_OLD_MASK) >> 2;
}
return (tag);
}
static int
decode_new_len(unsigned char **pptr)
{
unsigned char *ptr;
int len = -1;
if (pptr == NULL)
return (-1);
ptr = *pptr;
if (!(*ptr < 224 || *ptr == 255))
return (-1);
if (*ptr < 192)
len = *ptr++;
else if (*ptr < 224) {
len = ((*ptr - 192) << 8) + *(ptr+1) + 192;
ptr++;
} else if (*ptr == 255) {
len = (*ptr++ << 24);
len |= (*ptr++ << 16);
len |= (*ptr++ < 8);
len |= *ptr++;
}
*pptr = ptr;
return (len);
}
static int
decode_len(unsigned char **pptr, int ltype)
{
unsigned char *ptr;
int len;
if (ltype < 0)
return (decode_new_len(pptr));
if (pptr == NULL)
return (-1);
ptr = *pptr;
switch (ltype) {
case 0:
len = *ptr++;
break;
case 1:
len = (*ptr++ << 8);
len |= *ptr++;
break;
case 2:
len = *ptr++ << 24;
len |= *ptr++ << 16;
len |= *ptr++ << 8;
len |= *ptr++;
break;
case 3:
default:
len = -1;
}
*pptr = ptr;
return (len);
}
unsigned char *
decode_mpi(unsigned char **pptr, size_t *sz)
{
unsigned char *data;
unsigned char *ptr;
size_t mlen;
if (pptr == NULL || sz == NULL)
return (NULL);
ptr = *pptr;
mlen = (size_t)(*ptr++ << 8);
mlen |= (size_t)*ptr++;
mlen = (mlen + 7) / 8;
*sz = mlen;
data = ptr;
ptr += mlen;
*pptr = ptr;
return (data);
}
#ifdef USE_BEARSSL
unsigned char *
mpi2bn(unsigned char **pptr, size_t *sz)
{
return (decode_mpi(pptr, sz));
}
#else
BIGNUM *
mpi2bn(unsigned char **pptr)
{
BIGNUM *bn = NULL;
unsigned char *ptr;
int mlen;
if (pptr == NULL)
return (NULL);
ptr = *pptr;
mlen = (*ptr++ << 8);
mlen |= *ptr++;
mlen = (mlen + 7) / 8;
bn = BN_bin2bn(ptr, mlen, NULL);
ptr += mlen;
*pptr = ptr;
return (bn);
}
#endif
int
decode_packet(int want, unsigned char **pptr, size_t nbytes,
decoder_t decoder, void *decoder_arg)
{
int tag;
unsigned char *ptr;
unsigned char *nptr;
int isnew, ltype;
int len;
int hlen;
int rc = 0;
nptr = ptr = *pptr;
tag = decode_tag(ptr, &isnew, <ype);
if (want > 0 && tag != want)
return (-1);
ptr++;
len = rc = decode_len(&ptr, ltype);
hlen = (int)(ptr - nptr);
nptr = ptr + len;
if (decoder)
rc = decoder(tag, &ptr, len, decoder_arg);
*pptr = nptr;
nbytes -= (size_t)(hlen + len);
if (rc < 0)
return (rc);
return ((int)nbytes);
}
unsigned char *
decode_subpacket(unsigned char **pptr, int *stag, int *sz)
{
unsigned char *ptr;
int len;
ptr = *pptr;
len = decode_len(&ptr, -1);
*sz = (int)(len + ptr - *pptr);
*pptr = ptr + len;
*stag = *ptr++;
return (ptr);
}