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