]>
Commit | Line | Data |
---|---|---|
2039c421 | 1 | /* |
eec0ad10 | 2 | * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
365a2d99 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
2039c421 RS |
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 | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
d9a9d10f | 11 | #include <limits.h> |
b39fc560 | 12 | #include "internal/cryptlib.h" |
bd95d64a | 13 | #include "internal/numbers.h" |
ec577822 | 14 | #include <openssl/buffer.h> |
3a1f4302 | 15 | #include <openssl/asn1.h> |
16feca71 | 16 | #include "internal/asn1.h" |
25f2138b | 17 | #include "crypto/asn1.h" |
d02b48c6 | 18 | |
4e1209eb | 19 | #ifndef NO_OLD_ASN1 |
0f113f3e | 20 | # ifndef OPENSSL_NO_STDIO |
4e1209eb | 21 | |
0f113f3e MC |
22 | void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x) |
23 | { | |
24 | BIO *b; | |
25 | void *ret; | |
d02b48c6 | 26 | |
0f113f3e | 27 | if ((b = BIO_new(BIO_s_file())) == NULL) { |
9311d0c4 | 28 | ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB); |
26a7d938 | 29 | return NULL; |
0f113f3e MC |
30 | } |
31 | BIO_set_fp(b, in, BIO_NOCLOSE); | |
32 | ret = ASN1_d2i_bio(xnew, d2i, b, x); | |
33 | BIO_free(b); | |
26a7d938 | 34 | return ret; |
0f113f3e MC |
35 | } |
36 | # endif | |
d02b48c6 | 37 | |
0f113f3e MC |
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; | |
4e1209eb | 44 | |
0f113f3e MC |
45 | len = asn1_d2i_read_bio(in, &b); |
46 | if (len < 0) | |
47 | goto err; | |
4e1209eb | 48 | |
0f113f3e MC |
49 | p = (unsigned char *)b->data; |
50 | ret = d2i(x, &p, len); | |
51 | err: | |
25aaa98a | 52 | BUF_MEM_free(b); |
26a7d938 | 53 | return ret; |
0f113f3e | 54 | } |
4e1209eb DSH |
55 | |
56 | #endif | |
57 | ||
58 | void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x) | |
0f113f3e MC |
59 | { |
60 | BUF_MEM *b = NULL; | |
61 | const unsigned char *p; | |
62 | void *ret = NULL; | |
63 | int len; | |
4e1209eb | 64 | |
0f113f3e MC |
65 | len = asn1_d2i_read_bio(in, &b); |
66 | if (len < 0) | |
67 | goto err; | |
4e1209eb | 68 | |
0f113f3e MC |
69 | p = (const unsigned char *)b->data; |
70 | ret = ASN1_item_d2i(x, &p, len, it); | |
71 | err: | |
25aaa98a | 72 | BUF_MEM_free(b); |
26a7d938 | 73 | return ret; |
0f113f3e | 74 | } |
4e1209eb | 75 | |
4b618848 | 76 | #ifndef OPENSSL_NO_STDIO |
4e1209eb | 77 | void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) |
0f113f3e MC |
78 | { |
79 | BIO *b; | |
80 | char *ret; | |
4e1209eb | 81 | |
0f113f3e | 82 | if ((b = BIO_new(BIO_s_file())) == NULL) { |
9311d0c4 | 83 | ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB); |
26a7d938 | 84 | return NULL; |
0f113f3e MC |
85 | } |
86 | BIO_set_fp(b, in, BIO_NOCLOSE); | |
87 | ret = ASN1_item_d2i_bio(it, b, x); | |
88 | BIO_free(b); | |
26a7d938 | 89 | return ret; |
0f113f3e | 90 | } |
4e1209eb DSH |
91 | #endif |
92 | ||
93 | #define HEADER_SIZE 8 | |
c6298139 | 94 | #define ASN1_CHUNK_INITIAL_SIZE (16 * 1024) |
86f7b042 | 95 | int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) |
0f113f3e MC |
96 | { |
97 | BUF_MEM *b; | |
98 | unsigned char *p; | |
99 | int i; | |
0f113f3e | 100 | size_t want = HEADER_SIZE; |
bd95d64a | 101 | uint32_t eos = 0; |
0f113f3e MC |
102 | size_t off = 0; |
103 | size_t len = 0; | |
3e73111d | 104 | size_t diff; |
d02b48c6 | 105 | |
1880790e DSH |
106 | const unsigned char *q; |
107 | long slen; | |
108 | int inf, tag, xclass; | |
109 | ||
0f113f3e MC |
110 | b = BUF_MEM_new(); |
111 | if (b == NULL) { | |
9311d0c4 | 112 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
113 | return -1; |
114 | } | |
d02b48c6 | 115 | |
0f113f3e MC |
116 | ERR_clear_error(); |
117 | for (;;) { | |
3e73111d DDO |
118 | diff = len - off; |
119 | if (want >= diff) { | |
120 | want -= diff; | |
d02b48c6 | 121 | |
0f113f3e | 122 | if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { |
9311d0c4 | 123 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
124 | goto err; |
125 | } | |
126 | i = BIO_read(in, &(b->data[len]), want); | |
3e73111d | 127 | if (i < 0 && diff == 0) { |
9311d0c4 | 128 | ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); |
0f113f3e MC |
129 | goto err; |
130 | } | |
131 | if (i > 0) { | |
132 | if (len + i < len) { | |
9311d0c4 | 133 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
0f113f3e MC |
134 | goto err; |
135 | } | |
136 | len += i; | |
137 | } | |
138 | } | |
139 | /* else data already loaded */ | |
d02b48c6 | 140 | |
0f113f3e | 141 | p = (unsigned char *)&(b->data[off]); |
1880790e | 142 | q = p; |
3e73111d DDO |
143 | diff = len - off; |
144 | if (diff == 0) | |
145 | goto err; | |
146 | inf = ASN1_get_object(&q, &slen, &tag, &xclass, diff); | |
1880790e | 147 | if (inf & 0x80) { |
0f113f3e | 148 | unsigned long e; |
d02b48c6 | 149 | |
0f113f3e MC |
150 | e = ERR_GET_REASON(ERR_peek_error()); |
151 | if (e != ASN1_R_TOO_LONG) | |
152 | goto err; | |
3e73111d | 153 | ERR_clear_error(); |
0f113f3e | 154 | } |
1880790e | 155 | i = q - p; /* header length */ |
0f113f3e | 156 | off += i; /* end of data */ |
d02b48c6 | 157 | |
1880790e | 158 | if (inf & 1) { |
0f113f3e | 159 | /* no data body so go round again */ |
bd95d64a | 160 | if (eos == UINT32_MAX) { |
9311d0c4 | 161 | ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG); |
0f113f3e MC |
162 | goto err; |
163 | } | |
bd95d64a | 164 | eos++; |
0f113f3e | 165 | want = HEADER_SIZE; |
1880790e | 166 | } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) { |
0f113f3e MC |
167 | /* eos value, so go back and read another header */ |
168 | eos--; | |
bd95d64a | 169 | if (eos == 0) |
0f113f3e MC |
170 | break; |
171 | else | |
172 | want = HEADER_SIZE; | |
173 | } else { | |
1880790e DSH |
174 | /* suck in slen bytes of data */ |
175 | want = slen; | |
0f113f3e | 176 | if (want > (len - off)) { |
c6298139 DSH |
177 | size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; |
178 | ||
0f113f3e MC |
179 | want -= (len - off); |
180 | if (want > INT_MAX /* BIO_read takes an int length */ || | |
181 | len + want < len) { | |
9311d0c4 | 182 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
0f113f3e MC |
183 | goto err; |
184 | } | |
0f113f3e | 185 | while (want > 0) { |
c6298139 DSH |
186 | /* |
187 | * Read content in chunks of increasing size | |
188 | * so we can return an error for EOF without | |
189 | * having to allocate the entire content length | |
190 | * in one go. | |
191 | */ | |
192 | size_t chunk = want > chunk_max ? chunk_max : want; | |
193 | ||
194 | if (!BUF_MEM_grow_clean(b, len + chunk)) { | |
9311d0c4 | 195 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
0f113f3e MC |
196 | goto err; |
197 | } | |
c6298139 DSH |
198 | want -= chunk; |
199 | while (chunk > 0) { | |
200 | i = BIO_read(in, &(b->data[len]), chunk); | |
201 | if (i <= 0) { | |
9311d0c4 | 202 | ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA); |
c6298139 DSH |
203 | goto err; |
204 | } | |
0f113f3e MC |
205 | /* |
206 | * This can't overflow because |len+want| didn't | |
207 | * overflow. | |
208 | */ | |
c6298139 DSH |
209 | len += i; |
210 | chunk -= i; | |
211 | } | |
212 | if (chunk_max < INT_MAX/2) | |
213 | chunk_max *= 2; | |
0f113f3e MC |
214 | } |
215 | } | |
1880790e | 216 | if (off + slen < off) { |
9311d0c4 | 217 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
0f113f3e MC |
218 | goto err; |
219 | } | |
1880790e | 220 | off += slen; |
bd95d64a | 221 | if (eos == 0) { |
0f113f3e MC |
222 | break; |
223 | } else | |
224 | want = HEADER_SIZE; | |
225 | } | |
226 | } | |
d02b48c6 | 227 | |
0f113f3e | 228 | if (off > INT_MAX) { |
9311d0c4 | 229 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
0f113f3e MC |
230 | goto err; |
231 | } | |
d9a9d10f | 232 | |
0f113f3e MC |
233 | *pb = b; |
234 | return off; | |
235 | err: | |
25aaa98a | 236 | BUF_MEM_free(b); |
0f113f3e MC |
237 | return -1; |
238 | } |