155714Skris/* crypto/asn1/a_d2i_fp.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280297Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280297Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280297Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280297Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280297Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280297Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
60234954Sbz#include <limits.h>
6155714Skris#include "cryptlib.h"
6255714Skris#include <openssl/buffer.h>
6355714Skris#include <openssl/asn1_mac.h>
6455714Skris
65109998Smarkmstatic int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
6655714Skris
67109998Smarkm#ifndef NO_OLD_ASN1
68280297Sjkim# ifndef OPENSSL_NO_FP_API
69109998Smarkm
70280297Sjkimvoid *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
71280297Sjkim{
72280297Sjkim    BIO *b;
73280297Sjkim    void *ret;
7455714Skris
75280297Sjkim    if ((b = BIO_new(BIO_s_file())) == NULL) {
76280297Sjkim        ASN1err(ASN1_F_ASN1_D2I_FP, ERR_R_BUF_LIB);
77280297Sjkim        return (NULL);
78280297Sjkim    }
79280297Sjkim    BIO_set_fp(b, in, BIO_NOCLOSE);
80280297Sjkim    ret = ASN1_d2i_bio(xnew, d2i, b, x);
81280297Sjkim    BIO_free(b);
82280297Sjkim    return (ret);
83280297Sjkim}
84280297Sjkim# endif
8555714Skris
86280297Sjkimvoid *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
87280297Sjkim{
88280297Sjkim    BUF_MEM *b = NULL;
89280297Sjkim    const unsigned char *p;
90280297Sjkim    void *ret = NULL;
91280297Sjkim    int len;
92109998Smarkm
93280297Sjkim    len = asn1_d2i_read_bio(in, &b);
94280297Sjkim    if (len < 0)
95280297Sjkim        goto err;
96109998Smarkm
97280297Sjkim    p = (unsigned char *)b->data;
98280297Sjkim    ret = d2i(x, &p, len);
99280297Sjkim err:
100280297Sjkim    if (b != NULL)
101280297Sjkim        BUF_MEM_free(b);
102280297Sjkim    return (ret);
103280297Sjkim}
104109998Smarkm
105109998Smarkm#endif
106109998Smarkm
107109998Smarkmvoid *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
108280297Sjkim{
109280297Sjkim    BUF_MEM *b = NULL;
110280297Sjkim    const unsigned char *p;
111280297Sjkim    void *ret = NULL;
112280297Sjkim    int len;
113109998Smarkm
114280297Sjkim    len = asn1_d2i_read_bio(in, &b);
115280297Sjkim    if (len < 0)
116280297Sjkim        goto err;
117109998Smarkm
118280297Sjkim    p = (const unsigned char *)b->data;
119280297Sjkim    ret = ASN1_item_d2i(x, &p, len, it);
120280297Sjkim err:
121280297Sjkim    if (b != NULL)
122280297Sjkim        BUF_MEM_free(b);
123280297Sjkim    return (ret);
124280297Sjkim}
125109998Smarkm
126109998Smarkm#ifndef OPENSSL_NO_FP_API
127109998Smarkmvoid *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
128280297Sjkim{
129280297Sjkim    BIO *b;
130280297Sjkim    char *ret;
131109998Smarkm
132280297Sjkim    if ((b = BIO_new(BIO_s_file())) == NULL) {
133280297Sjkim        ASN1err(ASN1_F_ASN1_ITEM_D2I_FP, ERR_R_BUF_LIB);
134280297Sjkim        return (NULL);
135280297Sjkim    }
136280297Sjkim    BIO_set_fp(b, in, BIO_NOCLOSE);
137280297Sjkim    ret = ASN1_item_d2i_bio(it, b, x);
138280297Sjkim    BIO_free(b);
139280297Sjkim    return (ret);
140280297Sjkim}
141109998Smarkm#endif
142109998Smarkm
143109998Smarkm#define HEADER_SIZE   8
144298998Sjkim#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
145109998Smarkmstatic int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
146280297Sjkim{
147280297Sjkim    BUF_MEM *b;
148280297Sjkim    unsigned char *p;
149280297Sjkim    int i;
150280297Sjkim    ASN1_const_CTX c;
151280297Sjkim    size_t want = HEADER_SIZE;
152280297Sjkim    int eos = 0;
153280297Sjkim    size_t off = 0;
154280297Sjkim    size_t len = 0;
15555714Skris
156280297Sjkim    b = BUF_MEM_new();
157280297Sjkim    if (b == NULL) {
158280297Sjkim        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
159280297Sjkim        return -1;
160280297Sjkim    }
16155714Skris
162280297Sjkim    ERR_clear_error();
163280297Sjkim    for (;;) {
164280297Sjkim        if (want >= (len - off)) {
165280297Sjkim            want -= (len - off);
16655714Skris
167280297Sjkim            if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
168280297Sjkim                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
169280297Sjkim                goto err;
170280297Sjkim            }
171280297Sjkim            i = BIO_read(in, &(b->data[len]), want);
172280297Sjkim            if ((i < 0) && ((len - off) == 0)) {
173280297Sjkim                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA);
174280297Sjkim                goto err;
175280297Sjkim            }
176280297Sjkim            if (i > 0) {
177280297Sjkim                if (len + i < len) {
178280297Sjkim                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
179280297Sjkim                    goto err;
180280297Sjkim                }
181280297Sjkim                len += i;
182280297Sjkim            }
183280297Sjkim        }
184280297Sjkim        /* else data already loaded */
18555714Skris
186280297Sjkim        p = (unsigned char *)&(b->data[off]);
187280297Sjkim        c.p = p;
188280297Sjkim        c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass),
189280297Sjkim                                len - off);
190280297Sjkim        if (c.inf & 0x80) {
191280297Sjkim            unsigned long e;
19255714Skris
193280297Sjkim            e = ERR_GET_REASON(ERR_peek_error());
194280297Sjkim            if (e != ASN1_R_TOO_LONG)
195280297Sjkim                goto err;
196280297Sjkim            else
197280297Sjkim                ERR_clear_error(); /* clear error */
198280297Sjkim        }
199280297Sjkim        i = c.p - p;            /* header length */
200280297Sjkim        off += i;               /* end of data */
20155714Skris
202280297Sjkim        if (c.inf & 1) {
203280297Sjkim            /* no data body so go round again */
204280297Sjkim            eos++;
205280297Sjkim            if (eos < 0) {
206280297Sjkim                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG);
207280297Sjkim                goto err;
208280297Sjkim            }
209280297Sjkim            want = HEADER_SIZE;
210280297Sjkim        } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
211280297Sjkim            /* eos value, so go back and read another header */
212280297Sjkim            eos--;
213280297Sjkim            if (eos <= 0)
214280297Sjkim                break;
215280297Sjkim            else
216280297Sjkim                want = HEADER_SIZE;
217280297Sjkim        } else {
218280297Sjkim            /* suck in c.slen bytes of data */
219280297Sjkim            want = c.slen;
220280297Sjkim            if (want > (len - off)) {
221298998Sjkim                size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
222298998Sjkim
223280297Sjkim                want -= (len - off);
224280297Sjkim                if (want > INT_MAX /* BIO_read takes an int length */  ||
225280297Sjkim                    len + want < len) {
226280297Sjkim                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
227280297Sjkim                    goto err;
228280297Sjkim                }
229280297Sjkim                while (want > 0) {
230298998Sjkim                    /*
231298998Sjkim                     * Read content in chunks of increasing size
232298998Sjkim                     * so we can return an error for EOF without
233298998Sjkim                     * having to allocate the entire content length
234298998Sjkim                     * in one go.
235298998Sjkim                     */
236298998Sjkim                    size_t chunk = want > chunk_max ? chunk_max : want;
237298998Sjkim
238298998Sjkim                    if (!BUF_MEM_grow_clean(b, len + chunk)) {
239298998Sjkim                        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
240280297Sjkim                        goto err;
241280297Sjkim                    }
242298998Sjkim                    want -= chunk;
243298998Sjkim                    while (chunk > 0) {
244298998Sjkim                        i = BIO_read(in, &(b->data[len]), chunk);
245298998Sjkim                        if (i <= 0) {
246298998Sjkim                            ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
247298998Sjkim                                    ASN1_R_NOT_ENOUGH_DATA);
248298998Sjkim                            goto err;
249298998Sjkim                        }
250280297Sjkim                    /*
251280297Sjkim                     * This can't overflow because |len+want| didn't
252280297Sjkim                     * overflow.
253280297Sjkim                     */
254298998Sjkim                        len += i;
255298998Sjkim                        chunk -= i;
256298998Sjkim                    }
257298998Sjkim                    if (chunk_max < INT_MAX/2)
258298998Sjkim                        chunk_max *= 2;
259280297Sjkim                }
260280297Sjkim            }
261280297Sjkim            if (off + c.slen < off) {
262280297Sjkim                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
263280297Sjkim                goto err;
264280297Sjkim            }
265280297Sjkim            off += c.slen;
266280297Sjkim            if (eos <= 0) {
267280297Sjkim                break;
268280297Sjkim            } else
269280297Sjkim                want = HEADER_SIZE;
270280297Sjkim        }
271280297Sjkim    }
27255714Skris
273280297Sjkim    if (off > INT_MAX) {
274280297Sjkim        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
275280297Sjkim        goto err;
276280297Sjkim    }
277234954Sbz
278280297Sjkim    *pb = b;
279280297Sjkim    return off;
280280297Sjkim err:
281280297Sjkim    if (b != NULL)
282280297Sjkim        BUF_MEM_free(b);
283280297Sjkim    return -1;
284280297Sjkim}
285