]>
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" |
bd95d64a | 13 | #include "internal/numbers.h" |
ec577822 | 14 | #include <openssl/buffer.h> |
3a1f4302 | 15 | #include <openssl/asn1.h> |
d02b48c6 | 16 | |
4e1209eb | 17 | static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); |
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 MC |
27 | if ((b = BIO_new(BIO_s_file())) == NULL) { |
28 | ASN1err(ASN1_F_ASN1_D2I_FP, 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 | |
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); |
0f113f3e MC |
53 | return (ret); |
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); |
0f113f3e MC |
73 | return (ret); |
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 MC |
82 | if ((b = BIO_new(BIO_s_file())) == NULL) { |
83 | ASN1err(ASN1_F_ASN1_ITEM_D2I_FP, ERR_R_BUF_LIB); | |
84 | return (NULL); | |
85 | } | |
86 | BIO_set_fp(b, in, BIO_NOCLOSE); | |
87 | ret = ASN1_item_d2i_bio(it, b, x); | |
88 | BIO_free(b); | |
89 | return (ret); | |
90 | } | |
4e1209eb DSH |
91 | #endif |
92 | ||
93 | #define HEADER_SIZE 8 | |
c6298139 | 94 | #define ASN1_CHUNK_INITIAL_SIZE (16 * 1024) |
4e1209eb | 95 | static 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; | |
d02b48c6 | 104 | |
1880790e DSH |
105 | const unsigned char *q; |
106 | long slen; | |
107 | int inf, tag, xclass; | |
108 | ||
0f113f3e MC |
109 | b = BUF_MEM_new(); |
110 | if (b == NULL) { | |
111 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); | |
112 | return -1; | |
113 | } | |
d02b48c6 | 114 | |
0f113f3e MC |
115 | ERR_clear_error(); |
116 | for (;;) { | |
117 | if (want >= (len - off)) { | |
118 | want -= (len - off); | |
d02b48c6 | 119 | |
0f113f3e MC |
120 | if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) { |
121 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); | |
122 | goto err; | |
123 | } | |
124 | i = BIO_read(in, &(b->data[len]), want); | |
125 | if ((i < 0) && ((len - off) == 0)) { | |
126 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA); | |
127 | goto err; | |
128 | } | |
129 | if (i > 0) { | |
130 | if (len + i < len) { | |
131 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); | |
132 | goto err; | |
133 | } | |
134 | len += i; | |
135 | } | |
136 | } | |
137 | /* else data already loaded */ | |
d02b48c6 | 138 | |
0f113f3e | 139 | p = (unsigned char *)&(b->data[off]); |
1880790e DSH |
140 | q = p; |
141 | inf = ASN1_get_object(&q, &slen, &tag, &xclass, len - off); | |
142 | if (inf & 0x80) { | |
0f113f3e | 143 | unsigned long e; |
d02b48c6 | 144 | |
0f113f3e MC |
145 | e = ERR_GET_REASON(ERR_peek_error()); |
146 | if (e != ASN1_R_TOO_LONG) | |
147 | goto err; | |
148 | else | |
149 | ERR_clear_error(); /* clear error */ | |
150 | } | |
1880790e | 151 | i = q - p; /* header length */ |
0f113f3e | 152 | off += i; /* end of data */ |
d02b48c6 | 153 | |
1880790e | 154 | if (inf & 1) { |
0f113f3e | 155 | /* no data body so go round again */ |
bd95d64a | 156 | if (eos == UINT32_MAX) { |
0f113f3e MC |
157 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG); |
158 | goto err; | |
159 | } | |
bd95d64a | 160 | eos++; |
0f113f3e | 161 | want = HEADER_SIZE; |
1880790e | 162 | } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) { |
0f113f3e MC |
163 | /* eos value, so go back and read another header */ |
164 | eos--; | |
bd95d64a | 165 | if (eos == 0) |
0f113f3e MC |
166 | break; |
167 | else | |
168 | want = HEADER_SIZE; | |
169 | } else { | |
1880790e DSH |
170 | /* suck in slen bytes of data */ |
171 | want = slen; | |
0f113f3e | 172 | if (want > (len - off)) { |
c6298139 DSH |
173 | size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE; |
174 | ||
0f113f3e MC |
175 | want -= (len - off); |
176 | if (want > INT_MAX /* BIO_read takes an int length */ || | |
177 | len + want < len) { | |
178 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); | |
179 | goto err; | |
180 | } | |
0f113f3e | 181 | while (want > 0) { |
c6298139 DSH |
182 | /* |
183 | * Read content in chunks of increasing size | |
184 | * so we can return an error for EOF without | |
185 | * having to allocate the entire content length | |
186 | * in one go. | |
187 | */ | |
188 | size_t chunk = want > chunk_max ? chunk_max : want; | |
189 | ||
190 | if (!BUF_MEM_grow_clean(b, len + chunk)) { | |
191 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE); | |
0f113f3e MC |
192 | goto err; |
193 | } | |
c6298139 DSH |
194 | want -= chunk; |
195 | while (chunk > 0) { | |
196 | i = BIO_read(in, &(b->data[len]), chunk); | |
197 | if (i <= 0) { | |
198 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, | |
199 | ASN1_R_NOT_ENOUGH_DATA); | |
200 | goto err; | |
201 | } | |
0f113f3e MC |
202 | /* |
203 | * This can't overflow because |len+want| didn't | |
204 | * overflow. | |
205 | */ | |
c6298139 DSH |
206 | len += i; |
207 | chunk -= i; | |
208 | } | |
209 | if (chunk_max < INT_MAX/2) | |
210 | chunk_max *= 2; | |
0f113f3e MC |
211 | } |
212 | } | |
1880790e | 213 | if (off + slen < off) { |
0f113f3e MC |
214 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); |
215 | goto err; | |
216 | } | |
1880790e | 217 | off += slen; |
bd95d64a | 218 | if (eos == 0) { |
0f113f3e MC |
219 | break; |
220 | } else | |
221 | want = HEADER_SIZE; | |
222 | } | |
223 | } | |
d02b48c6 | 224 | |
0f113f3e MC |
225 | if (off > INT_MAX) { |
226 | ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG); | |
227 | goto err; | |
228 | } | |
d9a9d10f | 229 | |
0f113f3e MC |
230 | *pb = b; |
231 | return off; | |
232 | err: | |
25aaa98a | 233 | BUF_MEM_free(b); |
0f113f3e MC |
234 | return -1; |
235 | } |