diff options
Diffstat (limited to 'lib/libsecureboot/openpgp/decode.c')
-rw-r--r-- | lib/libsecureboot/openpgp/decode.c | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/lib/libsecureboot/openpgp/decode.c b/lib/libsecureboot/openpgp/decode.c new file mode 100644 index 000000000000..c59b5722c29e --- /dev/null +++ b/lib/libsecureboot/openpgp/decode.c @@ -0,0 +1,302 @@ +/*- + * Copyright (c) 2018, Juniper Networks, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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); +} + +/** + * @brief decode packet tag + * + * Also indicate if new/old and in the later case + * the length type + * + * @sa rfc4880:4.2 + */ +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); /* we are lost! */ + *isnew = tag & OPENPGP_TAG_ISNEW; + if (*isnew) { + *ltype = -1; /* irrelevant */ + tag &= OPENPGP_TAG_NEW_MASK; + } else { + *ltype = tag & OPENPGP_TAG_OLD_TYPE; + tag = (tag & OPENPGP_TAG_OLD_MASK) >> 2; + } + return (tag); +} + +/** + * @brief return packet length + * + * @sa rfc4880:4.2.2 + */ +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); /* not supported */ + + 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); +} + +/** + * @brief return packet length + * + * @sa rfc4880:4.2.1 + */ +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: + /* Not supported */ + len = -1; + } + + *pptr = ptr; + return (len); +} + +/** + * @brief return pointer and length of an mpi + * + * @sa rfc4880:3.2 + */ +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++; /* number of bits */ + mlen = (mlen + 7) / 8; /* number of bytes */ + *sz = mlen; + data = ptr; + ptr += mlen; + *pptr = ptr; + return (data); +} + +/** + * @brief return an OpenSSL BIGNUM from mpi + * + * @sa rfc4880:3.2 + */ +#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++; /* number of bits */ + mlen = (mlen + 7) / 8; /* number of bytes */ + bn = BN_bin2bn(ptr, mlen, NULL); + ptr += mlen; + *pptr = ptr; + + return (bn); +} +#endif + +/** + * @brief decode a packet + * + * If want is set, check that the packet tag matches + * if all good, call the provided decoder with its arg + * + * @return count of unconsumed data + * + * @sa rfc4880:4.2 + */ +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; /* consume it */ + + if (decoder) + rc = decoder(tag, &ptr, len, decoder_arg); + *pptr = nptr; + nbytes -= (size_t)(hlen + len); + if (rc < 0) + return (rc); /* error */ + return ((int)nbytes); /* unconsumed data */ +} + +/** + * @brief decode a sub packet + * + * @sa rfc4880:5.2.3.1 + */ +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); +} |