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