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.
8296465Sdelphij *
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).
15296465Sdelphij *
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.
22296465Sdelphij *
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 :-).
37296465Sdelphij * 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)"
40296465Sdelphij *
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.
52296465Sdelphij *
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
68296465Sdelphij# ifndef OPENSSL_NO_FP_API
69109998Smarkm
70296465Sdelphijvoid *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
71296465Sdelphij{
72296465Sdelphij    BIO *b;
73296465Sdelphij    void *ret;
7455714Skris
75296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
76296465Sdelphij        ASN1err(ASN1_F_ASN1_D2I_FP, ERR_R_BUF_LIB);
77296465Sdelphij        return (NULL);
78296465Sdelphij    }
79296465Sdelphij    BIO_set_fp(b, in, BIO_NOCLOSE);
80296465Sdelphij    ret = ASN1_d2i_bio(xnew, d2i, b, x);
81296465Sdelphij    BIO_free(b);
82296465Sdelphij    return (ret);
83296465Sdelphij}
84296465Sdelphij# endif
8555714Skris
86296465Sdelphijvoid *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
87296465Sdelphij{
88296465Sdelphij    BUF_MEM *b = NULL;
89296465Sdelphij    const unsigned char *p;
90296465Sdelphij    void *ret = NULL;
91296465Sdelphij    int len;
92109998Smarkm
93296465Sdelphij    len = asn1_d2i_read_bio(in, &b);
94296465Sdelphij    if (len < 0)
95296465Sdelphij        goto err;
96109998Smarkm
97296465Sdelphij    p = (unsigned char *)b->data;
98296465Sdelphij    ret = d2i(x, &p, len);
99296465Sdelphij err:
100296465Sdelphij    if (b != NULL)
101296465Sdelphij        BUF_MEM_free(b);
102296465Sdelphij    return (ret);
103296465Sdelphij}
104109998Smarkm
105109998Smarkm#endif
106109998Smarkm
107109998Smarkmvoid *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
108296465Sdelphij{
109296465Sdelphij    BUF_MEM *b = NULL;
110296465Sdelphij    const unsigned char *p;
111296465Sdelphij    void *ret = NULL;
112296465Sdelphij    int len;
113109998Smarkm
114296465Sdelphij    len = asn1_d2i_read_bio(in, &b);
115296465Sdelphij    if (len < 0)
116296465Sdelphij        goto err;
117109998Smarkm
118296465Sdelphij    p = (const unsigned char *)b->data;
119296465Sdelphij    ret = ASN1_item_d2i(x, &p, len, it);
120296465Sdelphij err:
121296465Sdelphij    if (b != NULL)
122296465Sdelphij        BUF_MEM_free(b);
123296465Sdelphij    return (ret);
124296465Sdelphij}
125109998Smarkm
126109998Smarkm#ifndef OPENSSL_NO_FP_API
127109998Smarkmvoid *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
128296465Sdelphij{
129296465Sdelphij    BIO *b;
130296465Sdelphij    char *ret;
131109998Smarkm
132296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
133296465Sdelphij        ASN1err(ASN1_F_ASN1_ITEM_D2I_FP, ERR_R_BUF_LIB);
134296465Sdelphij        return (NULL);
135296465Sdelphij    }
136296465Sdelphij    BIO_set_fp(b, in, BIO_NOCLOSE);
137296465Sdelphij    ret = ASN1_item_d2i_bio(it, b, x);
138296465Sdelphij    BIO_free(b);
139296465Sdelphij    return (ret);
140296465Sdelphij}
141109998Smarkm#endif
142109998Smarkm
143109998Smarkm#define HEADER_SIZE   8
144109998Smarkmstatic int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
145296465Sdelphij{
146296465Sdelphij    BUF_MEM *b;
147296465Sdelphij    unsigned char *p;
148296465Sdelphij    int i;
149296465Sdelphij    ASN1_const_CTX c;
150296465Sdelphij    size_t want = HEADER_SIZE;
151296465Sdelphij    int eos = 0;
152296465Sdelphij    size_t off = 0;
153296465Sdelphij    size_t len = 0;
15455714Skris
155296465Sdelphij    b = BUF_MEM_new();
156296465Sdelphij    if (b == NULL) {
157296465Sdelphij        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
158296465Sdelphij        return -1;
159296465Sdelphij    }
16055714Skris
161296465Sdelphij    ERR_clear_error();
162296465Sdelphij    for (;;) {
163296465Sdelphij        if (want >= (len - off)) {
164296465Sdelphij            want -= (len - off);
16555714Skris
166296465Sdelphij            if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
167296465Sdelphij                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
168296465Sdelphij                goto err;
169296465Sdelphij            }
170296465Sdelphij            i = BIO_read(in, &(b->data[len]), want);
171296465Sdelphij            if ((i < 0) && ((len - off) == 0)) {
172296465Sdelphij                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_NOT_ENOUGH_DATA);
173296465Sdelphij                goto err;
174296465Sdelphij            }
175296465Sdelphij            if (i > 0) {
176296465Sdelphij                if (len + i < len) {
177296465Sdelphij                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
178296465Sdelphij                    goto err;
179296465Sdelphij                }
180296465Sdelphij                len += i;
181296465Sdelphij            }
182296465Sdelphij        }
183296465Sdelphij        /* else data already loaded */
18455714Skris
185296465Sdelphij        p = (unsigned char *)&(b->data[off]);
186296465Sdelphij        c.p = p;
187296465Sdelphij        c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass),
188296465Sdelphij                                len - off);
189296465Sdelphij        if (c.inf & 0x80) {
190296465Sdelphij            unsigned long e;
19155714Skris
192296465Sdelphij            e = ERR_GET_REASON(ERR_peek_error());
193296465Sdelphij            if (e != ASN1_R_TOO_LONG)
194296465Sdelphij                goto err;
195296465Sdelphij            else
196296465Sdelphij                ERR_clear_error(); /* clear error */
197296465Sdelphij        }
198296465Sdelphij        i = c.p - p;            /* header length */
199296465Sdelphij        off += i;               /* end of data */
20055714Skris
201296465Sdelphij        if (c.inf & 1) {
202296465Sdelphij            /* no data body so go round again */
203296465Sdelphij            eos++;
204296465Sdelphij            if (eos < 0) {
205296465Sdelphij                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG);
206296465Sdelphij                goto err;
207296465Sdelphij            }
208296465Sdelphij            want = HEADER_SIZE;
209296465Sdelphij        } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
210296465Sdelphij            /* eos value, so go back and read another header */
211296465Sdelphij            eos--;
212296465Sdelphij            if (eos <= 0)
213296465Sdelphij                break;
214296465Sdelphij            else
215296465Sdelphij                want = HEADER_SIZE;
216296465Sdelphij        } else {
217296465Sdelphij            /* suck in c.slen bytes of data */
218296465Sdelphij            want = c.slen;
219296465Sdelphij            if (want > (len - off)) {
220296465Sdelphij                want -= (len - off);
221296465Sdelphij                if (want > INT_MAX /* BIO_read takes an int length */  ||
222296465Sdelphij                    len + want < len) {
223296465Sdelphij                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
224296465Sdelphij                    goto err;
225296465Sdelphij                }
226296465Sdelphij                if (!BUF_MEM_grow_clean(b, len + want)) {
227296465Sdelphij                    ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ERR_R_MALLOC_FAILURE);
228296465Sdelphij                    goto err;
229296465Sdelphij                }
230296465Sdelphij                while (want > 0) {
231296465Sdelphij                    i = BIO_read(in, &(b->data[len]), want);
232296465Sdelphij                    if (i <= 0) {
233296465Sdelphij                        ASN1err(ASN1_F_ASN1_D2I_READ_BIO,
234296465Sdelphij                                ASN1_R_NOT_ENOUGH_DATA);
235296465Sdelphij                        goto err;
236296465Sdelphij                    }
237296465Sdelphij                    /*
238296465Sdelphij                     * This can't overflow because |len+want| didn't
239296465Sdelphij                     * overflow.
240296465Sdelphij                     */
241296465Sdelphij                    len += i;
242296465Sdelphij                    want -= i;
243296465Sdelphij                }
244296465Sdelphij            }
245296465Sdelphij            if (off + c.slen < off) {
246296465Sdelphij                ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
247296465Sdelphij                goto err;
248296465Sdelphij            }
249296465Sdelphij            off += c.slen;
250296465Sdelphij            if (eos <= 0) {
251296465Sdelphij                break;
252296465Sdelphij            } else
253296465Sdelphij                want = HEADER_SIZE;
254296465Sdelphij        }
255296465Sdelphij    }
25655714Skris
257296465Sdelphij    if (off > INT_MAX) {
258296465Sdelphij        ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
259296465Sdelphij        goto err;
260296465Sdelphij    }
261234954Sbz
262296465Sdelphij    *pb = b;
263296465Sdelphij    return off;
264296465Sdelphij err:
265296465Sdelphij    if (b != NULL)
266296465Sdelphij        BUF_MEM_free(b);
267296465Sdelphij    return -1;
268296465Sdelphij}
269