Line data Source code
1 : /*
2 : * Copyright (c) 2019 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include "der_locl.h"
35 : #include <hex.h>
36 :
37 : #include "cms_asn1.h"
38 : #include "crmf_asn1.h"
39 : #include "digest_asn1.h"
40 : #include "krb5_asn1.h"
41 : #include "kx509_asn1.h"
42 : #include "ocsp_asn1.h"
43 : #include "pkcs10_asn1.h"
44 : #include "pkcs12_asn1.h"
45 : #include "pkcs8_asn1.h"
46 : #include "pkcs9_asn1.h"
47 : #include "pkinit_asn1.h"
48 : #include "rfc2459_asn1.h"
49 : #include "rfc4108_asn1.h"
50 :
51 :
52 : struct sym_oid {
53 : const char *sym;
54 : const heim_oid *oid;
55 : };
56 :
57 : #ifndef WIN32
58 : #define DEFINE_OID_WITH_NAME(sym) \
59 : { #sym, &asn1_oid_ ## sym },
60 :
61 : static const struct sym_oid sym_oids[] = {
62 : #include "cms_asn1_oids.c"
63 : #include "crmf_asn1_oids.c"
64 : #include "digest_asn1_oids.c"
65 : #include "krb5_asn1_oids.c"
66 : #include "kx509_asn1_oids.c"
67 : #include "ocsp_asn1_oids.c"
68 : #include "pkcs10_asn1_oids.c"
69 : #include "pkcs12_asn1_oids.c"
70 : #include "pkcs8_asn1_oids.c"
71 : #include "pkcs9_asn1_oids.c"
72 : #include "pkinit_asn1_oids.c"
73 : #include "rfc2459_asn1_oids.c"
74 : #include "rfc4108_asn1_oids.c"
75 : };
76 :
77 : static size_t num_sym_oids = sizeof(sym_oids) / sizeof(sym_oids[0]);
78 :
79 : #undef DEFINE_OID_WITH_NAME
80 :
81 : #define init_sym_oids()
82 :
83 : #else
84 :
85 : /*
86 : * We can't use C99 non-literal initializers for static objects in the Windows
87 : * build...
88 : */
89 :
90 : static struct sym_oid *sym_oids;
91 : static size_t num_sym_oids;
92 :
93 : #define DEFINE_OID_WITH_NAME(sym) (c++);
94 : static size_t
95 : count_sym_oids(void)
96 : {
97 : size_t c = 0;
98 : #include "cms_asn1_oids.c"
99 : #include "crmf_asn1_oids.c"
100 : #include "digest_asn1_oids.c"
101 : #include "krb5_asn1_oids.c"
102 : #include "kx509_asn1_oids.c"
103 : #include "ocsp_asn1_oids.c"
104 : #include "pkcs10_asn1_oids.c"
105 : #include "pkcs12_asn1_oids.c"
106 : #include "pkcs8_asn1_oids.c"
107 : #include "pkcs9_asn1_oids.c"
108 : #include "pkinit_asn1_oids.c"
109 : #include "rfc2459_asn1_oids.c"
110 : return c;
111 : }
112 : #undef DEFINE_OID_WITH_NAME
113 :
114 : #define DEFINE_OID_WITH_NAME(s) \
115 : tmp[i].sym = #s; \
116 : tmp[i++].oid = &asn1_oid_ ## s;
117 :
118 : static void
119 : init_sym_oids(void)
120 : {
121 : static struct sym_oid *tmp;
122 : size_t i = 0;
123 : size_t c;
124 :
125 : if (!sym_oids &&
126 : (c = count_sym_oids()) &&
127 : (tmp = calloc(c, sizeof(tmp[0])))) {
128 : #include "cms_asn1_oids.c"
129 : #include "crmf_asn1_oids.c"
130 : #include "digest_asn1_oids.c"
131 : #include "krb5_asn1_oids.c"
132 : #include "kx509_asn1_oids.c"
133 : #include "ocsp_asn1_oids.c"
134 : #include "pkcs10_asn1_oids.c"
135 : #include "pkcs12_asn1_oids.c"
136 : #include "pkcs8_asn1_oids.c"
137 : #include "pkcs9_asn1_oids.c"
138 : #include "pkinit_asn1_oids.c"
139 : #include "rfc2459_asn1_oids.c"
140 : num_sym_oids = c;
141 : sym_oids = tmp;
142 : }
143 : }
144 : #undef DEFINE_OID_WITH_NAME
145 :
146 : #endif
147 :
148 : static struct sym_oid *sym_oids_sorted_by_name;
149 : static struct sym_oid *sym_oids_sorted_by_oid;
150 :
151 : static int
152 0 : sym_cmp_name(const void *va, const void *vb)
153 : {
154 0 : const struct sym_oid *a = va;
155 0 : const struct sym_oid *b = vb;
156 :
157 0 : return (strcmp(a->sym, b->sym));
158 : }
159 :
160 : static int
161 0 : sym_cmp_oid(const void *va, const void *vb)
162 : {
163 0 : const struct sym_oid *a = va;
164 0 : const struct sym_oid *b = vb;
165 :
166 0 : return der_heim_oid_cmp(a->oid, b->oid);
167 : }
168 :
169 : static struct sym_oid *
170 0 : sort_sym_oids(int (*cmp)(const void *, const void *))
171 : {
172 0 : struct sym_oid *tmp;
173 :
174 0 : init_sym_oids();
175 0 : if ((tmp = calloc(num_sym_oids, sizeof(tmp[0]))) == NULL)
176 0 : return NULL;
177 :
178 0 : memcpy(tmp, sym_oids, num_sym_oids * sizeof(tmp[0]));
179 0 : qsort(tmp, num_sym_oids, sizeof(struct sym_oid), cmp);
180 0 : return tmp;
181 : }
182 :
183 : static int
184 0 : fix_oid_name(const char **namep, char **freeme)
185 : {
186 0 : char *dash = strchr(*namep, '-');
187 :
188 0 : *freeme = NULL;
189 0 : if (dash == NULL)
190 0 : return 0;
191 0 : if ((*freeme = strdup(*namep)) == NULL)
192 0 : return ENOMEM;
193 0 : *namep = *freeme;
194 0 : for (dash = strchr(*namep, '-'); dash; dash = strchr(dash, '-'))
195 0 : *dash = '_';
196 0 : return 0;
197 : }
198 :
199 : int ASN1CALL
200 0 : der_find_heim_oid_by_name(const char *str, const heim_oid **oid)
201 : {
202 0 : size_t right = num_sym_oids - 1;
203 0 : size_t left = 0;
204 0 : char *s = NULL;
205 0 : int ret;
206 :
207 0 : *oid = NULL;
208 0 : if (sym_oids_sorted_by_name == NULL &&
209 0 : (sym_oids_sorted_by_name = sort_sym_oids(sym_cmp_name)) == NULL)
210 0 : return ENOMEM;
211 :
212 0 : if ((ret = fix_oid_name(&str, &s)))
213 0 : return ret;
214 :
215 0 : while (left <= right) {
216 0 : size_t mid = left + (right - left) / 2;
217 0 : int cmp;
218 :
219 0 : cmp = strcmp(str, sym_oids_sorted_by_name[mid].sym);
220 0 : if (cmp == 0) {
221 0 : *oid = sym_oids_sorted_by_name[mid].oid;
222 0 : free(s);
223 0 : return 0;
224 : }
225 0 : if (cmp < 0 && mid > 0) {/* avoid underflow */
226 0 : right = mid - 1;
227 0 : } else if (cmp < 0) {
228 0 : free(s);
229 0 : return -1;
230 : } else {
231 0 : left = mid + 1;
232 : }
233 : }
234 0 : free(s);
235 0 : return -1;
236 : }
237 :
238 : int ASN1CALL
239 0 : der_find_or_parse_heim_oid(const char *str, const char *sep, heim_oid *oid)
240 : {
241 0 : const heim_oid *found = NULL;
242 :
243 0 : switch (der_find_heim_oid_by_name(str, &found)) {
244 0 : case 0: return der_copy_oid(found, oid);
245 0 : case -1: return der_parse_heim_oid(str, sep, oid);
246 0 : default: return ENOMEM;
247 : }
248 : }
249 :
250 : int ASN1CALL
251 0 : der_find_heim_oid_by_oid(const heim_oid *oid, const char **name)
252 : {
253 0 : size_t right = num_sym_oids;
254 0 : size_t left = 0;
255 :
256 0 : *name = NULL;
257 0 : if (sym_oids_sorted_by_oid == NULL &&
258 0 : (sym_oids_sorted_by_oid = sort_sym_oids(sym_cmp_oid)) == NULL)
259 0 : return ENOMEM;
260 :
261 0 : while (left <= right) {
262 0 : size_t mid = (left + right) >> 1;
263 0 : int cmp;
264 :
265 0 : cmp = der_heim_oid_cmp(oid, sym_oids_sorted_by_oid[mid].oid);
266 0 : if (cmp == 0) {
267 0 : *name = sym_oids_sorted_by_oid[mid].sym;
268 0 : return 0;
269 : }
270 0 : if (cmp < 0 && mid)
271 0 : right = mid - 1;
272 0 : else if (cmp < 0)
273 0 : return -1;
274 0 : else if (mid < num_sym_oids - 1)
275 0 : left = mid + 1;
276 : else
277 0 : return -1;
278 : }
279 0 : return -1;
280 : }
281 :
282 : int ASN1CALL
283 0 : der_match_heim_oid_by_name(const char *str, int *c, const heim_oid **oid)
284 : {
285 0 : size_t i;
286 0 : char *s = NULL;
287 0 : int ret;
288 :
289 0 : if ((ret = fix_oid_name(&str, &s)))
290 0 : return ret;
291 :
292 0 : if (*c < 0)
293 0 : *c = 0;
294 :
295 0 : init_sym_oids();
296 0 : for (i = (size_t)*c; i < num_sym_oids; i++) {
297 : /*
298 : * XXX We need a lib/roken strcasestr(), or maybe we should support
299 : * globbing here.
300 : */
301 0 : if (strstr(sym_oids[i].sym, str)) {
302 0 : *oid = sym_oids[i].oid;
303 0 : free(s);
304 0 : if (i >= INT_MAX)
305 0 : return -1;
306 0 : *c = i + 1; /* num_sym_oids is much less than INT_MAX */
307 0 : return 0;
308 : }
309 : }
310 0 : free(s);
311 0 : return -1;
312 : }
313 :
314 : /* Warning: der_print_heim_oid_sym() will not round-trip */
315 :
316 : int ASN1CALL
317 0 : der_print_heim_oid_sym(const heim_oid *oid, char delim, char **strp)
318 : {
319 0 : const char *sym;
320 0 : char *s1 = NULL;
321 0 : char *s2 = NULL;
322 0 : char *p;
323 0 : int ret;
324 :
325 0 : if (der_find_heim_oid_by_oid(oid, &sym))
326 0 : return der_print_heim_oid(oid, delim, strp);
327 :
328 0 : if ((ret = der_print_heim_oid(oid, delim, &s1)))
329 0 : return ret;
330 0 : if (asprintf(&s2, "%s (%s)", s1, sym) == -1 || s2 == NULL) {
331 0 : *strp = s1;
332 0 : return 0;
333 : }
334 0 : for (p = s2 + strlen(s1) + 1; *p; p++) {
335 0 : if (*p == '_')
336 0 : *p = '-';
337 : }
338 0 : *strp = s2;
339 0 : free(s1);
340 0 : return 0;
341 : }
|