From 548da160b52b25a106e9f6077d6a42c2c049586c Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Tue, 7 Mar 2023 00:19:33 -0500 Subject: Add a simple DER support header --- src/include/k5-der.h | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/include/k5-der.h diff --git a/src/include/k5-der.h b/src/include/k5-der.h new file mode 100644 index 0000000..b8371d9 --- /dev/null +++ b/src/include/k5-der.h @@ -0,0 +1,149 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* include/k5-der.h - Distinguished Encoding Rules (DER) declarations */ +/* + * Copyright (C) 2023 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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 HOLDER 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. + */ + +/* + * Most ASN.1 encoding and decoding is done using the table-driven framework in + * libkrb5. When that is not an option, these helpers can be used to encode + * and decode simple types. + */ + +#ifndef K5_DER_H +#define K5_DER_H + +#include +#include +#include "k5-buf.h" +#include "k5-input.h" + +/* Return the number of bytes needed to encode len as a DER encoding length. */ +static inline size_t +k5_der_len_len(size_t len) +{ + size_t llen; + + if (len < 128) + return 1; + llen = 1; + while (len > 0) { + len >>= 8; + llen++; + } + return llen; +} + +/* Return the number of bytes needed to encode a DER value (with identifier + * byte and length) for a given contents length. */ +static inline size_t +k5_der_value_len(size_t contents_len) +{ + return 1 + k5_der_len_len(contents_len) + contents_len; +} + +/* Add a DER identifier byte (composed by the caller, including the ASN.1 + * class, tag, and constructed bit) and length. */ +static inline void +k5_der_add_taglen(struct k5buf *buf, uint8_t idbyte, size_t len) +{ + uint8_t *p; + size_t llen = k5_der_len_len(len); + + p = k5_buf_get_space(buf, 1 + llen); + if (p == NULL) + return; + *p++ = idbyte; + if (len < 128) { + *p = len; + } else { + *p = 0x80 | (llen - 1); + /* Encode the length bytes backwards so the most significant byte is + * first. */ + p += llen; + while (len > 0) { + *--p = len & 0xFF; + len >>= 8; + } + } +} + +/* Add a DER value (identifier byte, length, and contents). */ +static inline void +k5_der_add_value(struct k5buf *buf, uint8_t idbyte, const void *contents, + size_t len) +{ + k5_der_add_taglen(buf, idbyte, len); + k5_buf_add_len(buf, contents, len); +} + +/* + * If the next byte in in matches idbyte and the subsequent DER length is + * valid, advance in past the value, set *contents_out to the value contents, + * and return true. Otherwise return false. Only set an error on in if the + * next bytes matches idbyte but the ensuing length is invalid. contents_out + * may be aliased to in; it will only be written to on successful decoding of a + * value. + */ +static inline bool +k5_der_get_value(struct k5input *in, uint8_t idbyte, + struct k5input *contents_out) +{ + uint8_t lenbyte, i; + size_t len; + const void *bytes; + + /* Do nothing if in is empty or the next byte doesn't match idbyte. */ + if (in->status || in->len == 0 || *in->ptr != idbyte) + return false; + + /* Advance past the identifier byte and decode the length. */ + (void)k5_input_get_byte(in); + lenbyte = k5_input_get_byte(in); + if (lenbyte < 128) { + len = lenbyte; + } else { + len = 0; + for (i = 0; i < (lenbyte & 0x7F); i++) { + if (len > (SIZE_MAX >> 8)) { + k5_input_set_status(in, EOVERFLOW); + return false; + } + len = (len << 8) | k5_input_get_byte(in); + } + } + + bytes = k5_input_get_bytes(in, len); + if (bytes == NULL) + return false; + k5_input_init(contents_out, bytes, len); + return true; +} + +#endif /* K5_DER_H */ -- cgit v1.1