• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
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
8  */
9 
10 #include <stdio.h>
11 #include <limits.h>
12 #include "internal/cryptlib.h"
13 #include "internal/numbers.h"
14 #include <openssl/buffer.h>
15 #include <openssl/asn1.h>
16 #include "crypto/asn1.h"
17 
18 #ifndef NO_OLD_ASN1
19 # ifndef OPENSSL_NO_STDIO
20 
ASN1_d2i_fp(void * (* xnew)(void),d2i_of_void * d2i,FILE * in,void ** x)21 void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
22 {
23     BIO *b;
24     void *ret;
25 
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
36 
ASN1_d2i_bio(void * (* xnew)(void),d2i_of_void * d2i,BIO * in,void ** x)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;
43 
44     len = asn1_d2i_read_bio(in, &b);
45     if (len < 0)
46         goto err;
47 
48     p = (unsigned char *)b->data;
49     ret = d2i(x, &p, len);
50  err:
51     BUF_MEM_free(b);
52     return ret;
53 }
54 
55 #endif
56 
ASN1_item_d2i_bio(const ASN1_ITEM * it,BIO * in,void * x)57 void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
58 {
59     BUF_MEM *b = NULL;
60     const unsigned char *p;
61     void *ret = NULL;
62     int len;
63 
64     len = asn1_d2i_read_bio(in, &b);
65     if (len < 0)
66         goto err;
67 
68     p = (const unsigned char *)b->data;
69     ret = ASN1_item_d2i(x, &p, len, it);
70  err:
71     BUF_MEM_free(b);
72     return ret;
73 }
74 
75 #ifndef OPENSSL_NO_STDIO
ASN1_item_d2i_fp(const ASN1_ITEM * it,FILE * in,void * x)76 void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
77 {
78     BIO *b;
79     char *ret;
80 
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 }
90 #endif
91 
92 #define HEADER_SIZE   8
93 #define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
asn1_d2i_read_bio(BIO * in,BUF_MEM ** pb)94 int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
95 {
96     BUF_MEM *b;
97     unsigned char *p;
98     int i;
99     size_t want = HEADER_SIZE;
100     uint32_t eos = 0;
101     size_t off = 0;
102     size_t len = 0;
103 
104     const unsigned char *q;
105     long slen;
106     int inf, tag, xclass;
107 
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     }
113 
114     ERR_clear_error();
115     for (;;) {
116         if (want >= (len - off)) {
117             want -= (len - off);
118 
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 */
137 
138         p = (unsigned char *)&(b->data[off]);
139         q = p;
140         inf = ASN1_get_object(&q, &slen, &tag, &xclass, len - off);
141         if (inf & 0x80) {
142             unsigned long e;
143 
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         }
150         i = q - p;            /* header length */
151         off += i;               /* end of data */
152 
153         if (inf & 1) {
154             /* no data body so go round again */
155             if (eos == UINT32_MAX) {
156                 ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_HEADER_TOO_LONG);
157                 goto err;
158             }
159             eos++;
160             want = HEADER_SIZE;
161         } else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) {
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 {
169             /* suck in slen bytes of data */
170             want = slen;
171             if (want > (len - off)) {
172                 size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
173 
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                 }
180                 while (want > 0) {
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);
191                         goto err;
192                     }
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                         }
201                     /*
202                      * This can't overflow because |len+want| didn't
203                      * overflow.
204                      */
205                         len += i;
206                         chunk -= i;
207                     }
208                     if (chunk_max < INT_MAX/2)
209                         chunk_max *= 2;
210                 }
211             }
212             if (off + slen < off) {
213                 ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
214                 goto err;
215             }
216             off += slen;
217             if (eos == 0) {
218                 break;
219             } else
220                 want = HEADER_SIZE;
221         }
222     }
223 
224     if (off > INT_MAX) {
225         ASN1err(ASN1_F_ASN1_D2I_READ_BIO, ASN1_R_TOO_LONG);
226         goto err;
227     }
228 
229     *pb = b;
230     return off;
231  err:
232     BUF_MEM_free(b);
233     return -1;
234 }
235