]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/asn1/tasn_utl.c
e_os.h removal from other headers and source files.
[thirdparty/openssl.git] / crypto / asn1 / tasn_utl.c
CommitLineData
0f113f3e 1/*
677963e5 2 * Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
9d6b1ce6 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
9d6b1ce6
DSH
8 */
9
9d6b1ce6 10#include <stddef.h>
3ebac273 11#include <string.h>
5f8dd0f8 12#include "internal/cryptlib.h"
677963e5 13#include "e_os.h"
9d6b1ce6
DSH
14#include <openssl/asn1.h>
15#include <openssl/asn1t.h>
16#include <openssl/objects.h>
17#include <openssl/err.h>
c1ee50aa 18#include "asn1_locl.h"
9d6b1ce6
DSH
19
20/* Utility functions for manipulating fields and offsets */
21
22/* Add 'offset' to 'addr' */
23#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset)
24
0f113f3e
MC
25/*
26 * Given an ASN1_ITEM CHOICE type return the selector value
9d6b1ce6
DSH
27 */
28
29int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it)
0f113f3e
MC
30{
31 int *sel = offset2ptr(*pval, it->utype);
32 return *sel;
33}
9d6b1ce6 34
0f113f3e
MC
35/*
36 * Given an ASN1_ITEM CHOICE type set the selector value, return old value.
9d6b1ce6
DSH
37 */
38
0f113f3e
MC
39int asn1_set_choice_selector(ASN1_VALUE **pval, int value,
40 const ASN1_ITEM *it)
41{
42 int *sel, ret;
43 sel = offset2ptr(*pval, it->utype);
44 ret = *sel;
45 *sel = value;
46 return ret;
47}
9d6b1ce6 48
0f113f3e 49/*
687b4868
F
50 * Do atomic reference counting. The value 'op' decides what to do.
51 * If it is +1 then the count is incremented.
52 * If |op| is 0, lock is initialised and count is set to 1.
53 * If |op| is -1, count is decremented and the return value is the current
54 * reference count or 0 if no reference count is active.
55 * It returns -1 on initialisation error.
56 * Used by ASN1_SEQUENCE construct of X509, X509_REQ, X509_CRL objects
9d6b1ce6 57 */
9d6b1ce6 58int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it)
0f113f3e
MC
59{
60 const ASN1_AUX *aux;
61 int *lck, ret;
c001ce33 62 CRYPTO_RWLOCK **lock;
0f113f3e
MC
63 if ((it->itype != ASN1_ITYPE_SEQUENCE)
64 && (it->itype != ASN1_ITYPE_NDEF_SEQUENCE))
65 return 0;
66 aux = it->funcs;
67 if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT))
68 return 0;
69 lck = offset2ptr(*pval, aux->ref_offset);
c001ce33 70 lock = offset2ptr(*pval, aux->ref_lock);
0f113f3e
MC
71 if (op == 0) {
72 *lck = 1;
c001ce33 73 *lock = CRYPTO_THREAD_lock_new();
b2b361f6 74 if (*lock == NULL) {
687b4868
F
75 ASN1err(ASN1_F_ASN1_DO_LOCK, ERR_R_MALLOC_FAILURE);
76 return -1;
b2b361f6 77 }
0f113f3e
MC
78 return 1;
79 }
687b4868
F
80 if (CRYPTO_atomic_add(lck, op, &ret, *lock) < 0)
81 return -1; /* failed */
9d6b1ce6 82#ifdef REF_PRINT
f3f1cf84 83 fprintf(stderr, "%p:%4d:%s\n", it, *lck, it->sname);
9d6b1ce6 84#endif
f3f1cf84 85 REF_ASSERT_ISNT(ret < 0);
687b4868 86 if (ret == 0) {
c001ce33 87 CRYPTO_THREAD_lock_free(*lock);
687b4868
F
88 *lock = NULL;
89 }
0f113f3e
MC
90 return ret;
91}
9d6b1ce6
DSH
92
93static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it)
0f113f3e
MC
94{
95 const ASN1_AUX *aux;
96 if (!pval || !*pval)
97 return NULL;
98 aux = it->funcs;
99 if (!aux || !(aux->flags & ASN1_AFLG_ENCODING))
100 return NULL;
101 return offset2ptr(*pval, aux->enc_offset);
102}
9d6b1ce6
DSH
103
104void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it)
0f113f3e
MC
105{
106 ASN1_ENCODING *enc;
107 enc = asn1_get_enc_ptr(pval, it);
108 if (enc) {
109 enc->enc = NULL;
110 enc->len = 0;
111 enc->modified = 1;
112 }
113}
9d6b1ce6
DSH
114
115void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it)
0f113f3e
MC
116{
117 ASN1_ENCODING *enc;
118 enc = asn1_get_enc_ptr(pval, it);
119 if (enc) {
b548a1f1 120 OPENSSL_free(enc->enc);
0f113f3e
MC
121 enc->enc = NULL;
122 enc->len = 0;
123 enc->modified = 1;
124 }
125}
9d6b1ce6 126
f3f52d7f 127int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
0f113f3e
MC
128 const ASN1_ITEM *it)
129{
130 ASN1_ENCODING *enc;
131 enc = asn1_get_enc_ptr(pval, it);
132 if (!enc)
133 return 1;
134
b548a1f1 135 OPENSSL_free(enc->enc);
0f113f3e 136 enc->enc = OPENSSL_malloc(inlen);
90945fa3 137 if (enc->enc == NULL)
0f113f3e
MC
138 return 0;
139 memcpy(enc->enc, in, inlen);
140 enc->len = inlen;
141 enc->modified = 0;
9d6b1ce6 142
0f113f3e
MC
143 return 1;
144}
9d6b1ce6 145
f3f52d7f 146int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval,
0f113f3e
MC
147 const ASN1_ITEM *it)
148{
149 ASN1_ENCODING *enc;
150 enc = asn1_get_enc_ptr(pval, it);
151 if (!enc || enc->modified)
152 return 0;
153 if (out) {
154 memcpy(*out, enc->enc, enc->len);
155 *out += enc->len;
156 }
157 if (len)
158 *len = enc->len;
159 return 1;
160}
9d6b1ce6
DSH
161
162/* Given an ASN1_TEMPLATE get a pointer to a field */
0f113f3e
MC
163ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt)
164{
165 ASN1_VALUE **pvaltmp;
0f113f3e
MC
166 pvaltmp = offset2ptr(*pval, tt->offset);
167 /*
168 * NOTE for BOOLEAN types the field is just a plain int so we can't
169 * return int **, so settle for (int *).
170 */
171 return pvaltmp;
172}
9d6b1ce6 173
0f113f3e
MC
174/*
175 * Handle ANY DEFINED BY template, find the selector, look up the relevant
176 * ASN1_TEMPLATE in the table and return it.
9d6b1ce6
DSH
177 */
178
f3f52d7f 179const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt,
0f113f3e
MC
180 int nullerr)
181{
182 const ASN1_ADB *adb;
183 const ASN1_ADB_TABLE *atbl;
184 long selector;
185 ASN1_VALUE **sfld;
186 int i;
187 if (!(tt->flags & ASN1_TFLG_ADB_MASK))
188 return tt;
189
190 /* Else ANY DEFINED BY ... get the table */
191 adb = ASN1_ADB_ptr(tt->item);
9d6b1ce6 192
0f113f3e
MC
193 /* Get the selector field */
194 sfld = offset2ptr(*pval, adb->offset);
9d6b1ce6 195
0f113f3e 196 /* Check if NULL */
7c46746b 197 if (*sfld == NULL) {
0f113f3e
MC
198 if (!adb->null_tt)
199 goto err;
200 return adb->null_tt;
201 }
9d6b1ce6 202
0f113f3e
MC
203 /*
204 * Convert type to a long: NB: don't check for NID_undef here because it
205 * might be a legitimate value in the table
206 */
207 if (tt->flags & ASN1_TFLG_ADB_OID)
208 selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld);
209 else
210 selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld);
9d6b1ce6 211
5b70372d
DSH
212 /* Let application callback translate value */
213 if (adb->adb_cb != NULL && adb->adb_cb(&selector) == 0) {
214 ASN1err(ASN1_F_ASN1_DO_ADB, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
215 return NULL;
216 }
217
0f113f3e
MC
218 /*
219 * Try to find matching entry in table Maybe should check application
220 * types first to allow application override? Might also be useful to
221 * have a flag which indicates table is sorted and we can do a binary
222 * search. For now stick to a linear search.
223 */
9d6b1ce6 224
0f113f3e
MC
225 for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++)
226 if (atbl->value == selector)
227 return &atbl->tt;
9d6b1ce6 228
0f113f3e 229 /* FIXME: need to search application table too */
9d6b1ce6 230
0f113f3e
MC
231 /* No match, return default type */
232 if (!adb->default_tt)
233 goto err;
234 return adb->default_tt;
9d6b1ce6 235
0f113f3e
MC
236 err:
237 /* FIXME: should log the value or OID of unsupported type */
238 if (nullerr)
239 ASN1err(ASN1_F_ASN1_DO_ADB, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE);
240 return NULL;
241}