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 "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 22void *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 38void *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 58void *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 79void *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 85void *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 101void *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) 109int 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 } 152 } 153 /* else data already loaded */ 154 155 p = (unsigned char *)&(b->data[off]); 156 q = p; 157 diff = len - off; 158 if (diff == 0) 159 goto err; 160 inf = ASN1_get_object(&q, &slen, &tag, &xclass, diff); 161 if (inf & 0x80) { 162 unsigned long e; 163 164 e = ERR_GET_REASON(ERR_peek_last_error()); 165 if (e != ASN1_R_TOO_LONG) 166 goto err; 167 ERR_pop_to_mark(); 168 } 169 i = q - p; /* header length */ 170 off += i; /* end of data */ 171 172 if (inf & 1) { 173 /* no data body so go round again */ 174 if (eos == UINT32_MAX) { 175 ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG); 176 goto err; 177 } 178 eos++; 179 want = HEADER_SIZE; 180 } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) { 181 /* eos value, so go back and read another header */ 182 eos--; 183 if (eos == 0) 184 break; 185 else 186 want = HEADER_SIZE; 187 } else { 188 /* suck in slen bytes of data */ 189 want = slen; 190 if (want > (len - off)) { 191 size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; 192 193 want -= (len - off); 194 if (want > INT_MAX /* BIO_read takes an int length */ || 195 len + want < len) { 196 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 197 goto err; 198 } 199 while (want > 0) { 200 /* 201 * Read content in chunks of increasing size 202 * so we can return an error for EOF without 203 * having to allocate the entire content length 204 * in one go. 205 */ 206 size_t chunk = want > chunk_max ? chunk_max : want; 207 208 if (!BUF_MEM_grow_clean(b, len + chunk)) { 209 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 210 goto err; 211 } 212 want -= chunk; 213 while (chunk > 0) { 214 i = BIO_read(in, &(b->data[len]), chunk); 215 if (i <= 0) { 216 ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); 217 goto err; 218 } 219 /* 220 * This can't overflow because |len+want| didn't 221 * overflow. 222 */ 223 len += i; 224 chunk -= i; 225 } 226 if (chunk_max < INT_MAX/2) 227 chunk_max *= 2; 228 } 229 } 230 if (off + slen < off) { 231 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 232 goto err; 233 } 234 off += slen; 235 if (eos == 0) { 236 break; 237 } else 238 want = HEADER_SIZE; 239 } 240 } 241 242 if (off > INT_MAX) { 243 ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); 244 goto err; 245 } 246 247 *pb = b; 248 return off; 249 err: 250 ERR_clear_last_mark(); 251 BUF_MEM_free(b); 252 return -1; 253} 254