1/* 2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include <stdio.h> 11#include <limits.h> 12#include "internal/cryptlib.h" 13#include <openssl/asn1.h> 14#include "asn1_local.h" 15 16static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, 17 long max); 18static void asn1_put_length(unsigned char **pp, int length); 19 20static int _asn1_check_infinite_end(const unsigned char **p, long len) 21{ 22 /* 23 * If there is 0 or 1 byte left, the length check should pick things up 24 */ 25 if (len <= 0) { 26 return 1; 27 } else { 28 if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) { 29 (*p) += 2; 30 return 1; 31 } 32 } 33 return 0; 34} 35 36int ASN1_check_infinite_end(unsigned char **p, long len) 37{ 38 return _asn1_check_infinite_end((const unsigned char **)p, len); 39} 40 41int ASN1_const_check_infinite_end(const unsigned char **p, long len) 42{ 43 return _asn1_check_infinite_end(p, len); 44} 45 46int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, 47 int *pclass, long omax) 48{ 49 int i, ret; 50 long len; 51 const unsigned char *p = *pp; 52 int tag, xclass, inf; 53 long max = omax; 54 55 if (omax <= 0) { 56 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL); 57 return 0x80; 58 } 59 ret = (*p & V_ASN1_CONSTRUCTED); 60 xclass = (*p & V_ASN1_PRIVATE); 61 i = *p & V_ASN1_PRIMITIVE_TAG; 62 if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */ 63 p++; 64 if (--max == 0) 65 goto err; 66 len = 0; 67 while (*p & 0x80) { 68 len <<= 7L; 69 len |= *(p++) & 0x7f; 70 if (--max == 0) 71 goto err; 72 if (len > (INT_MAX >> 7L)) 73 goto err; 74 } 75 len <<= 7L; 76 len |= *(p++) & 0x7f; 77 tag = (int)len; 78 if (--max == 0) 79 goto err; 80 } else { 81 tag = i; 82 p++; 83 if (--max == 0) 84 goto err; 85 } 86 *ptag = tag; 87 *pclass = xclass; 88 if (!asn1_get_length(&p, &inf, plength, max)) 89 goto err; 90 91 if (inf && !(ret & V_ASN1_CONSTRUCTED)) 92 goto err; 93 94 if (*plength > (omax - (p - *pp))) { 95 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 96 /* 97 * Set this so that even if things are not long enough the values are 98 * set correctly 99 */ 100 ret |= 0x80; 101 } 102 *pp = p; 103 return ret | inf; 104 err: 105 ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG); 106 return 0x80; 107} 108 109/* 110 * Decode a length field. 111 * The short form is a single byte defining a length 0 - 127. 112 * The long form is a byte 0 - 127 with the top bit set and this indicates 113 * the number of following octets that contain the length. These octets 114 * are stored most significant digit first. 115 */ 116static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, 117 long max) 118{ 119 const unsigned char *p = *pp; 120 unsigned long ret = 0; 121 int i; 122 123 if (max-- < 1) 124 return 0; 125 if (*p == 0x80) { 126 *inf = 1; 127 p++; 128 } else { 129 *inf = 0; 130 i = *p & 0x7f; 131 if (*p++ & 0x80) { 132 if (max < i + 1) 133 return 0; 134 /* Skip leading zeroes */ 135 while (i > 0 && *p == 0) { 136 p++; 137 i--; 138 } 139 if (i > (int)sizeof(long)) 140 return 0; 141 while (i > 0) { 142 ret <<= 8; 143 ret |= *p++; 144 i--; 145 } 146 if (ret > LONG_MAX) 147 return 0; 148 } else { 149 ret = i; 150 } 151 } 152 *pp = p; 153 *rl = (long)ret; 154 return 1; 155} 156 157/* 158 * constructed == 2 for indefinite length constructed 159 */ 160void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, 161 int xclass) 162{ 163 unsigned char *p = *pp; 164 int i, ttag; 165 166 i = (constructed) ? V_ASN1_CONSTRUCTED : 0; 167 i |= (xclass & V_ASN1_PRIVATE); 168 if (tag < 31) { 169 *(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG); 170 } else { 171 *(p++) = i | V_ASN1_PRIMITIVE_TAG; 172 for (i = 0, ttag = tag; ttag > 0; i++) 173 ttag >>= 7; 174 ttag = i; 175 while (i-- > 0) { 176 p[i] = tag & 0x7f; 177 if (i != (ttag - 1)) 178 p[i] |= 0x80; 179 tag >>= 7; 180 } 181 p += ttag; 182 } 183 if (constructed == 2) 184 *(p++) = 0x80; 185 else 186 asn1_put_length(&p, length); 187 *pp = p; 188} 189 190int ASN1_put_eoc(unsigned char **pp) 191{ 192 unsigned char *p = *pp; 193 194 *p++ = 0; 195 *p++ = 0; 196 *pp = p; 197 return 2; 198} 199 200static void asn1_put_length(unsigned char **pp, int length) 201{ 202 unsigned char *p = *pp; 203 int i, len; 204 205 if (length <= 127) { 206 *(p++) = (unsigned char)length; 207 } else { 208 len = length; 209 for (i = 0; len > 0; i++) 210 len >>= 8; 211 *(p++) = i | 0x80; 212 len = i; 213 while (i-- > 0) { 214 p[i] = length & 0xff; 215 length >>= 8; 216 } 217 p += len; 218 } 219 *pp = p; 220} 221 222int ASN1_object_size(int constructed, int length, int tag) 223{ 224 int ret = 1; 225 226 if (length < 0) 227 return -1; 228 if (tag >= 31) { 229 while (tag > 0) { 230 tag >>= 7; 231 ret++; 232 } 233 } 234 if (constructed == 2) { 235 ret += 3; 236 } else { 237 ret++; 238 if (length > 127) { 239 int tmplen = length; 240 while (tmplen > 0) { 241 tmplen >>= 8; 242 ret++; 243 } 244 } 245 } 246 if (ret >= INT_MAX - length) 247 return -1; 248 return ret + length; 249} 250 251int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) 252{ 253 if (str == NULL) 254 return 0; 255 dst->type = str->type; 256 if (!ASN1_STRING_set(dst, str->data, str->length)) 257 return 0; 258 /* Copy flags but preserve embed value */ 259 dst->flags &= ASN1_STRING_FLAG_EMBED; 260 dst->flags |= str->flags & ~ASN1_STRING_FLAG_EMBED; 261 return 1; 262} 263 264ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str) 265{ 266 ASN1_STRING *ret; 267 268 if (!str) 269 return NULL; 270 ret = ASN1_STRING_new(); 271 if (ret == NULL) 272 return NULL; 273 if (!ASN1_STRING_copy(ret, str)) { 274 ASN1_STRING_free(ret); 275 return NULL; 276 } 277 return ret; 278} 279 280int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in) 281{ 282 unsigned char *c; 283 const char *data = _data; 284 size_t len; 285 286 if (len_in < 0) { 287 if (data == NULL) 288 return 0; 289 len = strlen(data); 290 } else { 291 len = (size_t)len_in; 292 } 293 /* 294 * Verify that the length fits within an integer for assignment to 295 * str->length below. The additional 1 is subtracted to allow for the 296 * '\0' terminator even though this isn't strictly necessary. 297 */ 298 if (len > INT_MAX - 1) { 299 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE); 300 return 0; 301 } 302 if ((size_t)str->length <= len || str->data == NULL) { 303 c = str->data; 304#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 305 /* No NUL terminator in fuzzing builds */ 306 str->data = OPENSSL_realloc(c, len != 0 ? len : 1); 307#else 308 str->data = OPENSSL_realloc(c, len + 1); 309#endif 310 if (str->data == NULL) { 311 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 312 str->data = c; 313 return 0; 314 } 315 } 316 str->length = len; 317 if (data != NULL) { 318 memcpy(str->data, data, len); 319#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION 320 /* Set the unused byte to something non NUL and printable. */ 321 if (len == 0) 322 str->data[len] = '~'; 323#else 324 /* 325 * Add a NUL terminator. This should not be necessary - but we add it as 326 * a safety precaution 327 */ 328 str->data[len] = '\0'; 329#endif 330 } 331 return 1; 332} 333 334void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) 335{ 336 OPENSSL_free(str->data); 337 str->data = data; 338 str->length = len; 339} 340 341ASN1_STRING *ASN1_STRING_new(void) 342{ 343 return ASN1_STRING_type_new(V_ASN1_OCTET_STRING); 344} 345 346ASN1_STRING *ASN1_STRING_type_new(int type) 347{ 348 ASN1_STRING *ret; 349 350 ret = OPENSSL_zalloc(sizeof(*ret)); 351 if (ret == NULL) { 352 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 353 return NULL; 354 } 355 ret->type = type; 356 return ret; 357} 358 359void ossl_asn1_string_embed_free(ASN1_STRING *a, int embed) 360{ 361 if (a == NULL) 362 return; 363 if (!(a->flags & ASN1_STRING_FLAG_NDEF)) 364 OPENSSL_free(a->data); 365 if (embed == 0) 366 OPENSSL_free(a); 367} 368 369void ASN1_STRING_free(ASN1_STRING *a) 370{ 371 if (a == NULL) 372 return; 373 ossl_asn1_string_embed_free(a, a->flags & ASN1_STRING_FLAG_EMBED); 374} 375 376void ASN1_STRING_clear_free(ASN1_STRING *a) 377{ 378 if (a == NULL) 379 return; 380 if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF)) 381 OPENSSL_cleanse(a->data, a->length); 382 ASN1_STRING_free(a); 383} 384 385int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) 386{ 387 int i; 388 389 i = (a->length - b->length); 390 if (i == 0) { 391 if (a->length != 0) 392 i = memcmp(a->data, b->data, a->length); 393 if (i == 0) 394 return a->type - b->type; 395 else 396 return i; 397 } else { 398 return i; 399 } 400} 401 402int ASN1_STRING_length(const ASN1_STRING *x) 403{ 404 return x->length; 405} 406 407#ifndef OPENSSL_NO_DEPRECATED_3_0 408void ASN1_STRING_length_set(ASN1_STRING *x, int len) 409{ 410 x->length = len; 411} 412#endif 413 414int ASN1_STRING_type(const ASN1_STRING *x) 415{ 416 return x->type; 417} 418 419const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) 420{ 421 return x->data; 422} 423 424#ifndef OPENSSL_NO_DEPRECATED_1_1_0 425unsigned char *ASN1_STRING_data(ASN1_STRING *x) 426{ 427 return x->data; 428} 429#endif 430 431/* |max_len| excludes NUL terminator and may be 0 to indicate no restriction */ 432char *ossl_sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text, 433 const char *sep, size_t max_len) 434{ 435 int i; 436 ASN1_UTF8STRING *current; 437 size_t length = 0, sep_len; 438 char *result = NULL; 439 char *p; 440 441 if (sep == NULL) 442 sep = ""; 443 sep_len = strlen(sep); 444 445 for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) { 446 current = sk_ASN1_UTF8STRING_value(text, i); 447 if (i > 0) 448 length += sep_len; 449 length += ASN1_STRING_length(current); 450 if (max_len != 0 && length > max_len) 451 return NULL; 452 } 453 if ((result = OPENSSL_malloc(length + 1)) == NULL) 454 return NULL; 455 456 p = result; 457 for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) { 458 current = sk_ASN1_UTF8STRING_value(text, i); 459 length = ASN1_STRING_length(current); 460 if (i > 0 && sep_len > 0) { 461 strncpy(p, sep, sep_len + 1); /* using + 1 to silence gcc warning */ 462 p += sep_len; 463 } 464 strncpy(p, (const char *)ASN1_STRING_get0_data(current), length); 465 p += length; 466 } 467 *p = '\0'; 468 469 return result; 470} 471