1 /* 2 * Copyright 1995-2024 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 "internal/numbers.h" 14 #include <openssl/buffer.h> 15 #include <openssl/asn1.h> 16 #include "internal/asn1.h" 17 #include "crypto/asn1.h" 18 19 #ifndef NO_OLD_ASN1 20 # ifndef OPENSSL_NO_STDIO 21 22 void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x) 23 { 24 BIO *b; 25 void *ret; 26 27 if ((b = BIO_new(BIO_s_file())) == NULL) { 28 ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB); 29 return NULL; 30 } 31 BIO_set_fp(b, in, BIO_NOCLOSE); 32 ret = ASN1_d2i_bio(xnew, d2i, b, x); 33 BIO_free(b); 34 return ret; 35 } 36 # endif 37 38 void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x) 39 { 40 BUF_MEM *b = NULL; 41 const unsigned char *p; 42 void *ret = NULL; 43 int len; 44 45 len = asn1_d2i_read_bio(in, &b); 46 if (len < 0) 47 goto err; 48 49 p = (unsigned char *)b->data; 50 ret = d2i(x, &p, len); 51 err: 52 BUF_MEM_free(b); 53 return ret; 54 } 55 56 #endif 57 58 void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *x, 59 OSSL_LIB_CTX *libctx, const char *propq) 60 { 61 BUF_MEM *b = NULL; 62 const unsigned char *p; 63 void *ret = NULL; 64 int len; 65 66 if (in == NULL) 67 return NULL; 68 len = asn1_d2i_read_bio(in, &b); 69 if (len < 0) 70 goto err; 71 72 p = (const unsigned char *)b->data; 73 ret = ASN1_item_d2i_ex(x, &p, len, it, libctx, propq); 74 err: 75 BUF_MEM_free(b); 76 return ret; 77 } 78 79 void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x) 80 { 81 return ASN1_item_d2i_bio_ex(it, in, x, NULL, NULL); 82 } 83 84 #ifndef OPENSSL_NO_STDIO 85 void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x, 86 OSSL_LIB_CTX *libctx, const char *propq) 87 { 88 BIO *b; 89 char *ret; 90 91 if ((b = BIO_new(BIO_s_file())) == NULL) { 92 ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB); 93 return NULL; 94 } 95 BIO_set_fp(b, in, BIO_NOCLOSE); 96 ret = ASN1_item_d2i_bio_ex(it, b, x, libctx, propq); 97 BIO_free(b); 98 return ret; 99 } 100 101 void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) 102 { 103 return ASN1_item_d2i_fp_ex(it, in, x, NULL, NULL); 104 } 105 #endif 106 107 #define HEADER_SIZE 8 108 #define ASN1_CHUNK_INITIAL_SIZE (16 * 1024) 109 int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) 110 { 111 BUF_MEM *b; 112 unsigned char *p; 113 int i; 114 size_t want = HEADER_SIZE; 115 uint32_t eos = 0; 116 size_t off = 0; 117 size_t len = 0; 118 size_t diff; 119 120 const unsigned char *q; 121 long slen; 122 int inf, tag, xclass; 123 124 b = BUF_MEM_new(); 125 if (b == NULL) { 126 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 127 return -1; 128 } 129 130 ERR_set_mark(); 131 for (;;) { 132 diff = len - off; 133 if (want >= diff) { 134 want -= diff; 135 136 if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { 137 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 138 goto err; 139 } 140 i = BIO_read(in, &(b->data[len]), want); 141 if (i < 0 && diff == 0) { 142 ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); 143 goto err; 144 } 145 if (i > 0) { 146 if (len + i < len) { 147 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 148 goto err; 149 } 150 len += i; 151 if ((size_t)i < want) 152 continue; 153 154 } 155 } 156 /* else data already loaded */ 157 158 p = (unsigned char *)&(b->data[off]); 159 q = p; 160 diff = len - off; 161 if (diff == 0) 162 goto err; 163 inf = ASN1_get_object(&q, &slen, &tag, &xclass, diff); 164 if (inf & 0x80) { 165 unsigned long e; 166 167 e = ERR_GET_REASON(ERR_peek_last_error()); 168 if (e != ASN1_R_TOO_LONG) 169 goto err; 170 ERR_pop_to_mark(); 171 } 172 i = q - p; /* header length */ 173 off += i; /* end of data */ 174 175 if (inf & 1) { 176 /* no data body so go round again */ 177 if (eos == UINT32_MAX) { 178 ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG); 179 goto err; 180 } 181 eos++; 182 want = HEADER_SIZE; 183 } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) { 184 /* eos value, so go back and read another header */ 185 eos--; 186 if (eos == 0) 187 break; 188 else 189 want = HEADER_SIZE; 190 } else { 191 /* suck in slen bytes of data */ 192 want = slen; 193 if (want > (len - off)) { 194 size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; 195 196 want -= (len - off); 197 if (want > INT_MAX /* BIO_read takes an int length */ || 198 len + want < len) { 199 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 200 goto err; 201 } 202 while (want > 0) { 203 /* 204 * Read content in chunks of increasing size 205 * so we can return an error for EOF without 206 * having to allocate the entire content length 207 * in one go. 208 */ 209 size_t chunk = want > chunk_max ? chunk_max : want; 210 211 if (!BUF_MEM_grow_clean(b, len + chunk)) { 212 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 213 goto err; 214 } 215 want -= chunk; 216 while (chunk > 0) { 217 i = BIO_read(in, &(b->data[len]), chunk); 218 if (i <= 0) { 219 ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); 220 goto err; 221 } 222 /* 223 * This can't overflow because |len+want| didn't 224 * overflow. 225 */ 226 len += i; 227 chunk -= i; 228 } 229 if (chunk_max < INT_MAX/2) 230 chunk_max *= 2; 231 } 232 } 233 if (off + slen < off) { 234 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 235 goto err; 236 } 237 off += slen; 238 if (eos == 0) { 239 break; 240 } else 241 want = HEADER_SIZE; 242 } 243 } 244 245 if (off > INT_MAX) { 246 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 247 goto err; 248 } 249 250 *pb = b; 251 return off; 252 err: 253 ERR_clear_last_mark(); 254 BUF_MEM_free(b); 255 return -1; 256 } 257