Fix no-stdio build
[openssl.git] / crypto / asn1 / tasn_utl.c
1 /* tasn_utl.c */
2 /*
3  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4  * 2000.
5  */
6 /* ====================================================================
7  * Copyright (c) 2000-2004 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This product includes cryptographic software written by Eric Young
55  * (eay@cryptsoft.com).  This product includes software written by Tim
56  * Hudson (tjh@cryptsoft.com).
57  *
58  */
59
60 #include <stddef.h>
61 #include <string.h>
62 #include <internal/cryptlib.h>
63 #include <openssl/asn1.h>
64 #include <openssl/asn1t.h>
65 #include <openssl/objects.h>
66 #include <openssl/err.h>
67 #include "asn1_locl.h"
68
69 /* Utility functions for manipulating fields and offsets */
70
71 /* Add 'offset' to 'addr' */
72 #define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
73
74 /*
75  * Given an ASN1_ITEM CHOICE type return the selector value
76  */
77
78 int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it)
79 {
80     int *sel = offset2ptr(*pval, it->utype);
81     return *sel;
82 }
83
84 /*
85  * Given an ASN1_ITEM CHOICE type set the selector value, return old value.
86  */
87
88 int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
89                              const ASN1_ITEM *it)
90 {
91     int *sel, ret;
92     sel = offset2ptr(*pval, it->utype);
93     ret = *sel;
94     *sel = value;
95     return ret;
96 }
97
98 /*
99  * Do reference counting. The value 'op' decides what to do. if it is +1
100  * then the count is incremented. If op is 0 count is set to 1. If op is -1
101  * count is decremented and the return value is the current reference count
102  * or 0 if no reference count exists.
103  */
104
105 int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it)
106 {
107     const ASN1_AUX *aux;
108     int *lck, ret;
109     if ((it->itype != ASN1_ITYPE_SEQUENCE)
110         && (it->itype != ASN1_ITYPE_NDEF_SEQUENCE))
111         return 0;
112     aux = it->funcs;
113     if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT))
114         return 0;
115     lck = offset2ptr(*pval, aux->ref_offset);
116     if (op == 0) {
117         *lck = 1;
118         return 1;
119     }
120     ret = CRYPTO_add(lck, op, aux->ref_lock);
121 #ifdef REF_PRINT
122     fprintf(stderr, "%s: Reference Count: %d\n", it->sname, *lck);
123 #endif
124 #ifdef REF_CHECK
125     if (ret < 0)
126         fprintf(stderr, "%s, bad reference count\n", it->sname);
127 #endif
128     return ret;
129 }
130
131 static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it)
132 {
133     const ASN1_AUX *aux;
134     if (!pval || !*pval)
135         return NULL;
136     aux = it->funcs;
137     if (!aux || !(aux->flags & ASN1_AFLG_ENCODING))
138         return NULL;
139     return offset2ptr(*pval, aux->enc_offset);
140 }
141
142 void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it)
143 {
144     ASN1_ENCODING *enc;
145     enc = asn1_get_enc_ptr(pval, it);
146     if (enc) {
147         enc->enc = NULL;
148         enc->len = 0;
149         enc->modified = 1;
150     }
151 }
152
153 void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
154 {
155     ASN1_ENCODING *enc;
156     enc = asn1_get_enc_ptr(pval, it);
157     if (enc) {
158         OPENSSL_free(enc->enc);
159         enc->enc = NULL;
160         enc->len = 0;
161         enc->modified = 1;
162     }
163 }
164
165 int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
166                   const ASN1_ITEM *it)
167 {
168     ASN1_ENCODING *enc;
169     enc = asn1_get_enc_ptr(pval, it);
170     if (!enc)
171         return 1;
172
173     OPENSSL_free(enc->enc);
174     enc->enc = OPENSSL_malloc(inlen);
175     if (!enc->enc)
176         return 0;
177     memcpy(enc->enc, in, inlen);
178     enc->len = inlen;
179     enc->modified = 0;
180
181     return 1;
182 }
183
184 int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
185                      const ASN1_ITEM *it)
186 {
187     ASN1_ENCODING *enc;
188     enc = asn1_get_enc_ptr(pval, it);
189     if (!enc || enc->modified)
190         return 0;
191     if (out) {
192         memcpy(*out, enc->enc, enc->len);
193         *out += enc->len;
194     }
195     if (len)
196         *len = enc->len;
197     return 1;
198 }
199
200 /* Given an ASN1_TEMPLATE get a pointer to a field */
201 ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
202 {
203     ASN1_VALUE **pvaltmp;
204     pvaltmp = offset2ptr(*pval, tt->offset);
205     /*
206      * NOTE for BOOLEAN types the field is just a plain int so we can't
207      * return int **, so settle for (int *).
208      */
209     return pvaltmp;
210 }
211
212 /*
213  * Handle ANY DEFINED BY template, find the selector, look up the relevant
214  * ASN1_TEMPLATE in the table and return it.
215  */
216
217 const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
218                                  int nullerr)
219 {
220     const ASN1_ADB *adb;
221     const ASN1_ADB_TABLE *atbl;
222     long selector;
223     ASN1_VALUE **sfld;
224     int i;
225     if (!(tt->flags & ASN1_TFLG_ADB_MASK))
226         return tt;
227
228     /* Else ANY DEFINED BY ... get the table */
229     adb = ASN1_ADB_ptr(tt->item);
230
231     /* Get the selector field */
232     sfld = offset2ptr(*pval, adb->offset);
233
234     /* Check if NULL */
235     if (!sfld) {
236         if (!adb->null_tt)
237             goto err;
238         return adb->null_tt;
239     }
240
241     /*
242      * Convert type to a long: NB: don't check for NID_undef here because it
243      * might be a legitimate value in the table
244      */
245     if (tt->flags & ASN1_TFLG_ADB_OID)
246         selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld);
247     else
248         selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld);
249
250     /*
251      * Try to find matching entry in table Maybe should check application
252      * types first to allow application override? Might also be useful to
253      * have a flag which indicates table is sorted and we can do a binary
254      * search. For now stick to a linear search.
255      */
256
257     for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++)
258         if (atbl->value == selector)
259             return &atbl->tt;
260
261     /* FIXME: need to search application table too */
262
263     /* No match, return default type */
264     if (!adb->default_tt)
265         goto err;
266     return adb->default_tt;
267
268  err:
269     /* FIXME: should log the value or OID of unsupported type */
270     if (nullerr)
271         ASN1err(ASN1_F_ASN1_DO_ADB, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
272     return NULL;
273 }