1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Copyright (c) 2014, Google Inc. 2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Permission to use, copy, modify, and/or distribute this software for any 4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * purpose with or without fee is hereby granted, provided that the above 5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * copyright notice and this permission notice appear in all copies. 6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/buf.h> 16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/mem.h> 17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/bytestring.h> 18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <assert.h> 20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <string.h> 21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "internal.h" 23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 25d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyvoid CBS_init(CBS *cbs, const uint8_t *data, size_t len) { 26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley cbs->data = data; 27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley cbs->len = len; 28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 30d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int cbs_get(CBS *cbs, const uint8_t **p, size_t n) { 31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (cbs->len < n) { 32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 34d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *p = cbs->data; 36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley cbs->data += n; 37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley cbs->len -= n; 38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 41d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_skip(CBS *cbs, size_t len) { 42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const uint8_t *dummy; 43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get(cbs, &dummy, len); 44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 46d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyconst uint8_t *CBS_data(const CBS *cbs) { 47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs->data; 48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 50d9e397b599b13d642138480a28c14db7a136bf0Adam Langleysize_t CBS_len(const CBS *cbs) { 51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs->len; 52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 54d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) { 55e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley OPENSSL_free(*out_ptr); 56e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley *out_ptr = NULL; 57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_len = 0; 58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (cbs->len == 0) { 60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 62d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_ptr = BUF_memdup(cbs->data, cbs->len); 63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (*out_ptr == NULL) { 64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_len = cbs->len; 67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 68d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 70d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_strdup(const CBS *cbs, char **out_ptr) { 71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (*out_ptr != NULL) { 72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley OPENSSL_free(*out_ptr); 73d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_ptr = BUF_strndup((const char*)cbs->data, cbs->len); 75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return (*out_ptr != NULL); 76d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 78d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_contains_zero_byte(const CBS *cbs) { 79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return memchr(cbs->data, 0, cbs->len) != NULL; 80d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 81d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 82d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { 83e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (len != cbs->len) { 84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 85e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 86d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return CRYPTO_memcmp(cbs->data, data, len) == 0; 87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 88d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 89d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { 90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint32_t result = 0; 91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t i; 92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const uint8_t *data; 93d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 94d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get(cbs, &data, len)) { 95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley for (i = 0; i < len; i++) { 98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley result <<= 8; 99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley result |= data[i]; 100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = result; 102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 105d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u8(CBS *cbs, uint8_t *out) { 106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const uint8_t *v; 107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get(cbs, &v, 1)) { 108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 110d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = *v; 111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 112d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 114d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u16(CBS *cbs, uint16_t *out) { 115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint32_t v; 116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get_u(cbs, &v, 2)) { 117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 119d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = v; 120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 122d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 123d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u24(CBS *cbs, uint32_t *out) { 124d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_u(cbs, out, 3); 125d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 126d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 127d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u32(CBS *cbs, uint32_t *out) { 128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_u(cbs, out, 4); 129d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 131d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_bytes(CBS *cbs, CBS *out, size_t len) { 132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const uint8_t *v; 133d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get(cbs, &v, len)) { 134d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 136d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_init(out, v, len); 137d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 140d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) { 141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint32_t len; 142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get_u(cbs, &len, len_len)) { 143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 144d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 145d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return CBS_get_bytes(cbs, out, len); 146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 148d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) { 149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_length_prefixed(cbs, out, 1); 150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 151d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 152d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) { 153d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_length_prefixed(cbs, out, 2); 154d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 155d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 156d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { 157d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_length_prefixed(cbs, out, 3); 158d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 159d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 16053b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langleystatic int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, 16153b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley size_t *out_header_len, int ber_ok) { 162d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint8_t tag, length_byte; 163d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS header = *cbs; 164d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS throwaway; 165d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 166d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out == NULL) { 167d9e397b599b13d642138480a28c14db7a136bf0Adam Langley out = &throwaway; 168d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 169d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 170d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_u8(&header, &tag) || 171d9e397b599b13d642138480a28c14db7a136bf0Adam Langley !CBS_get_u8(&header, &length_byte)) { 172d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 173d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 174d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 175d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if ((tag & 0x1f) == 0x1f) { 176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Long form tags are not supported. */ 177d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 178d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 179d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 180d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out_tag != NULL) { 181d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_tag = tag; 182d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 183d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 184d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t len; 185d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if ((length_byte & 0x80) == 0) { 186d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Short form length. */ 187d9e397b599b13d642138480a28c14db7a136bf0Adam Langley len = ((size_t) length_byte) + 2; 188d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out_header_len != NULL) { 189d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_header_len = 2; 190d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 191d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 192d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Long form length. */ 193d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const size_t num_bytes = length_byte & 0x7f; 194d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint32_t len32; 195d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 19653b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { 197d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* indefinite length */ 19853b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley if (out_header_len != NULL) { 19953b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley *out_header_len = 2; 20053b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley } 201d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return CBS_get_bytes(cbs, out, 2); 202d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 203d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 204d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (num_bytes == 0 || num_bytes > 4) { 205d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 206d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 207d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!cbs_get_u(&header, &len32, num_bytes)) { 208d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 209d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 210d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (len32 < 128) { 211d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Length should have used short-form encoding. */ 212d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 213d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 214d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if ((len32 >> ((num_bytes-1)*8)) == 0) { 215d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Length should have been at least one byte shorter. */ 216d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 217d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 218d9e397b599b13d642138480a28c14db7a136bf0Adam Langley len = len32; 219d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (len + 2 + num_bytes < len) { 220d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Overflow. */ 221d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 222d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 223d9e397b599b13d642138480a28c14db7a136bf0Adam Langley len += 2 + num_bytes; 224d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out_header_len != NULL) { 225d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_header_len = 2 + num_bytes; 226d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 227d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 228d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 229d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return CBS_get_bytes(cbs, out, len); 230d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 231d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 23253b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langleyint CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, 23353b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley size_t *out_header_len) { 23453b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, 23553b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley 0 /* DER only */); 23653b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley} 23753b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley 23853b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langleyint CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, 23953b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley size_t *out_header_len) { 24053b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, 24153b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley 1 /* BER allowed */); 24253b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley} 24353b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley 244d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, 245d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int skip_header) { 246d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t header_len; 247d9e397b599b13d642138480a28c14db7a136bf0Adam Langley unsigned tag; 248d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS throwaway; 249d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 250d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out == NULL) { 251d9e397b599b13d642138480a28c14db7a136bf0Adam Langley out = &throwaway; 252d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 253d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 254d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || 25553b272a2813a0b11f107d77100ff8805ada8fbd2Adam Langley tag != tag_value) { 256d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 257d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 258d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 259d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (skip_header && !CBS_skip(out, header_len)) { 260d9e397b599b13d642138480a28c14db7a136bf0Adam Langley assert(0); 261d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 262d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 263d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 264d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 265d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 266d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 267d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) { 268d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); 269d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 270d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 271d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) { 272d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); 273d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 274d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 275d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { 276d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (CBS_len(cbs) < 1) { 277d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 278d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 279d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return CBS_data(cbs)[0] == tag_value; 280d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 281d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 282d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { 283d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS bytes; 284d9e397b599b13d642138480a28c14db7a136bf0Adam Langley const uint8_t *data; 285d9e397b599b13d642138480a28c14db7a136bf0Adam Langley size_t i, len; 286d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 287d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) { 288d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 289d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 290d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 291d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = 0; 292d9e397b599b13d642138480a28c14db7a136bf0Adam Langley data = CBS_data(&bytes); 293d9e397b599b13d642138480a28c14db7a136bf0Adam Langley len = CBS_len(&bytes); 294d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 295d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (len == 0) { 296d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* An INTEGER is encoded with at least one octet. */ 297d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 298d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 299d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 300d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if ((data[0] & 0x80) != 0) { 301e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley /* Negative number. */ 302e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley return 0; 303e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley } 304e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley 305e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) { 306e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley /* Extra leading zeros. */ 307d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 308d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 309d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 310d9e397b599b13d642138480a28c14db7a136bf0Adam Langley for (i = 0; i < len; i++) { 311d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if ((*out >> 56) != 0) { 312d9e397b599b13d642138480a28c14db7a136bf0Adam Langley /* Too large to represent as a uint64_t. */ 313d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 314d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 315d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out <<= 8; 316d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out |= data[i]; 317d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 318d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 319d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 320d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 321d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 322d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) { 323d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (CBS_peek_asn1_tag(cbs, tag)) { 324d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_asn1(cbs, out, tag)) { 325d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 326d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 327d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_present = 1; 328d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 329d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_present = 0; 330d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 331d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 332d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 333d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 334d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, 335d9e397b599b13d642138480a28c14db7a136bf0Adam Langley unsigned tag) { 336d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS child; 337d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int present; 338d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { 339d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 340d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 341d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (present) { 342d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || 343d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_len(&child) != 0) { 344d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 345d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 346d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 347d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_init(out, NULL, 0); 348d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 349d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (out_present) { 350d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out_present = present; 351d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 352d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 353d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 354d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 355d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, 356d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint64_t default_value) { 357d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS child; 358d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int present; 359d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { 360d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 361d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 362d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (present) { 363d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_asn1_uint64(&child, out) || 364d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_len(&child) != 0) { 365d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 366d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 367d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 368d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = default_value; 369d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 370d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 371d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 372d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 373d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, 374d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int default_value) { 375d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS child, child2; 376d9e397b599b13d642138480a28c14db7a136bf0Adam Langley int present; 377d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { 378d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 379d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 380d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (present) { 381d9e397b599b13d642138480a28c14db7a136bf0Adam Langley uint8_t boolean; 382d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 383d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || 384d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_len(&child2) != 1 || 385d9e397b599b13d642138480a28c14db7a136bf0Adam Langley CBS_len(&child) != 0) { 386d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 387d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 388d9e397b599b13d642138480a28c14db7a136bf0Adam Langley 389d9e397b599b13d642138480a28c14db7a136bf0Adam Langley boolean = CBS_data(&child2)[0]; 390d9e397b599b13d642138480a28c14db7a136bf0Adam Langley if (boolean == 0) { 391d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = 0; 392d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else if (boolean == 0xff) { 393d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = 1; 394d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 395d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 0; 396d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 397d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } else { 398d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *out = default_value; 399d9e397b599b13d642138480a28c14db7a136bf0Adam Langley } 400d9e397b599b13d642138480a28c14db7a136bf0Adam Langley return 1; 401d9e397b599b13d642138480a28c14db7a136bf0Adam Langley} 402