xref: /dragonfly/crypto/libressl/crypto/asn1/a_object.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1 /* $OpenBSD: a_object.c,v 1.48 2022/05/13 16:32:10 tb Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <limits.h>
60 #include <stdio.h>
61 #include <string.h>
62 
63 #include <openssl/asn1.h>
64 #include <openssl/asn1t.h>
65 #include <openssl/err.h>
66 #include <openssl/buffer.h>
67 #include <openssl/objects.h>
68 
69 #include "asn1_locl.h"
70 
71 const ASN1_ITEM ASN1_OBJECT_it = {
72           .itype = ASN1_ITYPE_PRIMITIVE,
73           .utype = V_ASN1_OBJECT,
74           .sname = "ASN1_OBJECT",
75 };
76 
77 ASN1_OBJECT *
ASN1_OBJECT_new(void)78 ASN1_OBJECT_new(void)
79 {
80           ASN1_OBJECT *a;
81 
82           if ((a = calloc(1, sizeof(ASN1_OBJECT))) == NULL) {
83                     ASN1error(ERR_R_MALLOC_FAILURE);
84                     return (NULL);
85           }
86           a->flags = ASN1_OBJECT_FLAG_DYNAMIC;
87 
88           return a;
89 }
90 
91 void
ASN1_OBJECT_free(ASN1_OBJECT * a)92 ASN1_OBJECT_free(ASN1_OBJECT *a)
93 {
94           if (a == NULL)
95                     return;
96           if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) {
97                     free((void *)a->sn);
98                     free((void *)a->ln);
99                     a->sn = a->ln = NULL;
100           }
101           if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) {
102                     freezero((void *)a->data, a->length);
103                     a->data = NULL;
104                     a->length = 0;
105           }
106           if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC)
107                     free(a);
108 }
109 
110 ASN1_OBJECT *
ASN1_OBJECT_create(int nid,unsigned char * data,int len,const char * sn,const char * ln)111 ASN1_OBJECT_create(int nid, unsigned char *data, int len,
112     const char *sn, const char *ln)
113 {
114           ASN1_OBJECT o;
115 
116           o.sn = sn;
117           o.ln = ln;
118           o.data = data;
119           o.nid = nid;
120           o.length = len;
121           o.flags = ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
122               ASN1_OBJECT_FLAG_DYNAMIC_DATA;
123           return (OBJ_dup(&o));
124 }
125 
126 static int
oid_add_arc(CBB * cbb,uint64_t arc)127 oid_add_arc(CBB *cbb, uint64_t arc)
128 {
129           int started = 0;
130           uint8_t val;
131           int i;
132 
133           for (i = (sizeof(arc) * 8) / 7; i >= 0; i--) {
134                     val = (arc >> (i * 7)) & 0x7f;
135                     if (!started && i != 0 && val == 0)
136                               continue;
137                     if (i > 0)
138                               val |= 0x80;
139                     if (!CBB_add_u8(cbb, val))
140                               return 0;
141                     started = 1;
142           }
143 
144           return 1;
145 }
146 
147 static int
oid_parse_arc(CBS * cbs,uint64_t * out_arc)148 oid_parse_arc(CBS *cbs, uint64_t *out_arc)
149 {
150           uint64_t arc = 0;
151           uint8_t val;
152 
153           do {
154                     if (!CBS_get_u8(cbs, &val))
155                               return 0;
156                     if (arc == 0 && val == 0x80)
157                               return 0;
158                     if (out_arc != NULL && arc > (UINT64_MAX >> 7))
159                               return 0;
160                     arc = (arc << 7) | (val & 0x7f);
161           } while (val & 0x80);
162 
163           if (out_arc != NULL)
164                     *out_arc = arc;
165 
166           return 1;
167 }
168 
169 static int
oid_add_arc_txt(CBB * cbb,uint64_t arc,int first)170 oid_add_arc_txt(CBB *cbb, uint64_t arc, int first)
171 {
172           const char *fmt = ".%llu";
173           char s[22]; /* Digits in decimal representation of 2^64-1, plus '.' and NUL. */
174           int n;
175 
176           if (first)
177                     fmt = "%llu";
178           n = snprintf(s, sizeof(s), fmt, (unsigned long long)arc);
179           if (n < 0 || (size_t)n >= sizeof(s))
180                     return 0;
181           if (!CBB_add_bytes(cbb, s, n))
182                     return 0;
183 
184           return 1;
185 }
186 
187 static int
oid_parse_arc_txt(CBS * cbs,uint64_t * out_arc,char * separator,int first)188 oid_parse_arc_txt(CBS *cbs, uint64_t *out_arc, char *separator, int first)
189 {
190           uint64_t arc = 0;
191           int digits = 0;
192           uint8_t val;
193 
194           if (!first) {
195                     if (!CBS_get_u8(cbs, &val))
196                               return 0;
197                     if ((*separator == 0 && val != '.' && val != ' ') ||
198                         (*separator != 0 && val != *separator)) {
199                               ASN1error(ASN1_R_INVALID_SEPARATOR);
200                               return 0;
201                     }
202                     *separator = val;
203           }
204 
205           while (CBS_len(cbs) > 0) {
206                     if (!CBS_peek_u8(cbs, &val))
207                               return 0;
208                     if (val == '.' || val == ' ')
209                               break;
210 
211                     if (!CBS_get_u8(cbs, &val))
212                               return 0;
213                     if (val < '0' || val > '9') {
214                               /* For the first arc we treat this as the separator. */
215                               if (first) {
216                                         ASN1error(ASN1_R_INVALID_SEPARATOR);
217                                         return 0;
218                               }
219                               ASN1error(ASN1_R_INVALID_DIGIT);
220                               return 0;
221                     }
222                     val -= '0';
223 
224                     if (digits > 0 && arc == 0 && val == 0) {
225                               ASN1error(ASN1_R_INVALID_NUMBER);
226                               return 0;
227                     }
228                     digits++;
229 
230                     if (arc > UINT64_MAX / 10) {
231                               ASN1error(ASN1_R_TOO_LONG);
232                               return 0;
233                     }
234                     arc = arc * 10 + val;
235           }
236 
237           if (digits < 1) {
238                     ASN1error(ASN1_R_INVALID_NUMBER);
239                     return 0;
240           }
241 
242           *out_arc = arc;
243 
244           return 1;
245 }
246 
247 static int
a2c_ASN1_OBJECT_internal(CBB * cbb,CBS * cbs)248 a2c_ASN1_OBJECT_internal(CBB *cbb, CBS *cbs)
249 {
250           uint64_t arc, si1, si2;
251           char separator = 0;
252 
253           if (!oid_parse_arc_txt(cbs, &si1, &separator, 1))
254                     return 0;
255 
256           if (CBS_len(cbs) == 0) {
257                     ASN1error(ASN1_R_MISSING_SECOND_NUMBER);
258                     return 0;
259           }
260 
261           if (!oid_parse_arc_txt(cbs, &si2, &separator, 0))
262                     return 0;
263 
264           /*
265            * X.690 section 8.19 - the first two subidentifiers are encoded as
266            * (x * 40) + y, with x being limited to [0,1,2]. The second
267            * subidentifier cannot exceed 39 for x < 2.
268            */
269           if (si1 > 2) {
270                     ASN1error(ASN1_R_FIRST_NUM_TOO_LARGE);
271                     return 0;
272           }
273           if ((si1 < 2 && si2 >= 40) || si2 > UINT64_MAX - si1 * 40) {
274                     ASN1error(ASN1_R_SECOND_NUMBER_TOO_LARGE);
275                     return 0;
276           }
277           arc = si1 * 40 + si2;
278 
279           if (!oid_add_arc(cbb, arc))
280                     return 0;
281 
282           while (CBS_len(cbs) > 0) {
283                     if (!oid_parse_arc_txt(cbs, &arc, &separator, 0))
284                               return 0;
285                     if (!oid_add_arc(cbb, arc))
286                               return 0;
287           }
288 
289           return 1;
290 }
291 
292 static int
c2a_ASN1_OBJECT(CBS * cbs,CBB * cbb)293 c2a_ASN1_OBJECT(CBS *cbs, CBB *cbb)
294 {
295           uint64_t arc, si1, si2;
296 
297           /*
298            * X.690 section 8.19 - the first two subidentifiers are encoded as
299            * (x * 40) + y, with x being limited to [0,1,2].
300            */
301           if (!oid_parse_arc(cbs, &arc))
302                     return 0;
303           if ((si1 = arc / 40) > 2)
304                     si1 = 2;
305           si2 = arc - si1 * 40;
306 
307           if (!oid_add_arc_txt(cbb, si1, 1))
308                     return 0;
309           if (!oid_add_arc_txt(cbb, si2, 0))
310                     return 0;
311 
312           while (CBS_len(cbs) > 0) {
313                     if (!oid_parse_arc(cbs, &arc))
314                               return 0;
315                     if (!oid_add_arc_txt(cbb, arc, 0))
316                               return 0;
317           }
318 
319           /* NUL terminate. */
320           if (!CBB_add_u8(cbb, 0))
321                     return 0;
322 
323           return 1;
324 }
325 
326 int
a2d_ASN1_OBJECT(unsigned char * out,int out_len,const char * in,int in_len)327 a2d_ASN1_OBJECT(unsigned char *out, int out_len, const char *in, int in_len)
328 {
329           uint8_t *data = NULL;
330           size_t data_len;
331           CBS cbs;
332           CBB cbb;
333           int ret = 0;
334 
335           memset(&cbb, 0, sizeof(cbb));
336 
337           if (in_len == -1)
338                     in_len = strlen(in);
339           if (in_len <= 0)
340                     goto err;
341 
342           CBS_init(&cbs, in, in_len);
343 
344           if (!CBB_init(&cbb, 0))
345                     goto err;
346           if (!a2c_ASN1_OBJECT_internal(&cbb, &cbs))
347                     goto err;
348           if (!CBB_finish(&cbb, &data, &data_len))
349                     goto err;
350 
351           if (data_len > INT_MAX)
352                     goto err;
353 
354           if (out != NULL) {
355                     if (out_len <= 0 || (size_t)out_len < data_len) {
356                               ASN1error(ASN1_R_BUFFER_TOO_SMALL);
357                               goto err;
358                     }
359                     memcpy(out, data, data_len);
360           }
361 
362           ret = (int)data_len;
363 
364  err:
365           CBB_cleanup(&cbb);
366           free(data);
367 
368           return ret;
369 }
370 
371 static int
i2t_ASN1_OBJECT_oid(const ASN1_OBJECT * aobj,CBB * cbb)372 i2t_ASN1_OBJECT_oid(const ASN1_OBJECT *aobj, CBB *cbb)
373 {
374           CBS cbs;
375 
376           CBS_init(&cbs, aobj->data, aobj->length);
377 
378           return c2a_ASN1_OBJECT(&cbs, cbb);
379 }
380 
381 static int
i2t_ASN1_OBJECT_name(const ASN1_OBJECT * aobj,CBB * cbb,const char ** out_name)382 i2t_ASN1_OBJECT_name(const ASN1_OBJECT *aobj, CBB *cbb, const char **out_name)
383 {
384           const char *name;
385           int nid;
386 
387           *out_name = NULL;
388 
389           if ((nid = OBJ_obj2nid(aobj)) == NID_undef)
390                     return 0;
391 
392           if ((name = OBJ_nid2ln(nid)) == NULL)
393                     name = OBJ_nid2sn(nid);
394           if (name == NULL)
395                     return 0;
396 
397           *out_name = name;
398 
399           if (!CBB_add_bytes(cbb, name, strlen(name)))
400                     return 0;
401 
402           /* NUL terminate. */
403           if (!CBB_add_u8(cbb, 0))
404                     return 0;
405 
406           return 1;
407 }
408 
409 static int
i2t_ASN1_OBJECT_cbb(const ASN1_OBJECT * aobj,CBB * cbb,int no_name)410 i2t_ASN1_OBJECT_cbb(const ASN1_OBJECT *aobj, CBB *cbb, int no_name)
411 {
412           const char *name;
413 
414           if (!no_name) {
415                     if (i2t_ASN1_OBJECT_name(aobj, cbb, &name))
416                               return 1;
417                     if (name != NULL)
418                               return 0;
419           }
420           return i2t_ASN1_OBJECT_oid(aobj, cbb);
421 }
422 
423 int
i2t_ASN1_OBJECT_internal(const ASN1_OBJECT * aobj,char * buf,int buf_len,int no_name)424 i2t_ASN1_OBJECT_internal(const ASN1_OBJECT *aobj, char *buf, int buf_len, int no_name)
425 {
426           uint8_t *data = NULL;
427           size_t data_len;
428           CBB cbb;
429           int ret = 0;
430 
431           if (buf_len < 0)
432                     return 0;
433           if (buf_len > 0)
434                     buf[0] = '\0';
435 
436           if (!CBB_init(&cbb, 0))
437                     goto err;
438           if (!i2t_ASN1_OBJECT_cbb(aobj, &cbb, no_name))
439                     goto err;
440           if (!CBB_finish(&cbb, &data, &data_len))
441                     goto err;
442 
443           ret = strlcpy(buf, data, buf_len);
444  err:
445           CBB_cleanup(&cbb);
446           free(data);
447 
448           return ret;
449 }
450 
451 int
i2t_ASN1_OBJECT(char * buf,int buf_len,const ASN1_OBJECT * aobj)452 i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *aobj)
453 {
454           return i2t_ASN1_OBJECT_internal(aobj, buf, buf_len, 0);
455 }
456 
457 ASN1_OBJECT *
t2i_ASN1_OBJECT_internal(const char * oid)458 t2i_ASN1_OBJECT_internal(const char *oid)
459 {
460           ASN1_OBJECT *aobj = NULL;
461           uint8_t *data = NULL;
462           size_t data_len;
463           CBB cbb;
464           CBS cbs;
465 
466           memset(&cbb, 0, sizeof(cbb));
467 
468           CBS_init(&cbs, oid, strlen(oid));
469 
470           if (!CBB_init(&cbb, 0))
471                     goto err;
472           if (!a2c_ASN1_OBJECT_internal(&cbb, &cbs))
473                     goto err;
474           if (!CBB_finish(&cbb, &data, &data_len))
475                     goto err;
476 
477           if (data_len > INT_MAX)
478                     goto err;
479 
480           if ((aobj = ASN1_OBJECT_new()) == NULL)
481                     goto err;
482 
483           aobj->data = data;
484           aobj->length = (int)data_len;
485           aobj->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
486           data = NULL;
487 
488  err:
489           CBB_cleanup(&cbb);
490           free(data);
491 
492           return aobj;
493 }
494 
495 int
i2a_ASN1_OBJECT(BIO * bp,const ASN1_OBJECT * aobj)496 i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *aobj)
497 {
498           uint8_t *data = NULL;
499           size_t data_len;
500           CBB cbb;
501           int ret = -1;
502 
503           if (aobj == NULL || aobj->data == NULL)
504                     return BIO_write(bp, "NULL", 4);
505 
506           if (!CBB_init(&cbb, 0))
507                     goto err;
508           if (!i2t_ASN1_OBJECT_cbb(aobj, &cbb, 0)) {
509                     ret = BIO_write(bp, "<INVALID>", 9);
510                     goto err;
511           }
512           if (!CBB_finish(&cbb, &data, &data_len))
513                     goto err;
514 
515           ret = BIO_write(bp, data, strlen(data));
516 
517  err:
518           CBB_cleanup(&cbb);
519           free(data);
520 
521           return ret;
522 }
523 
524 int
c2i_ASN1_OBJECT_cbs(ASN1_OBJECT ** out_aobj,CBS * content)525 c2i_ASN1_OBJECT_cbs(ASN1_OBJECT **out_aobj, CBS *content)
526 {
527           ASN1_OBJECT *aobj = NULL;
528           uint8_t *data = NULL;
529           size_t data_len;
530           CBS cbs;
531 
532           if (out_aobj == NULL)
533                     goto err;
534 
535           if (*out_aobj != NULL) {
536                     ASN1_OBJECT_free(*out_aobj);
537                     *out_aobj = NULL;
538           }
539 
540           /* Parse and validate OID encoding per X.690 8.19.2. */
541           CBS_dup(content, &cbs);
542           if (CBS_len(&cbs) == 0) {
543                     ASN1error(ASN1_R_INVALID_OBJECT_ENCODING);
544                     goto err;
545           }
546           while (CBS_len(&cbs) > 0) {
547                     if (!oid_parse_arc(&cbs, NULL)) {
548                               ASN1error(ASN1_R_INVALID_OBJECT_ENCODING);
549                               goto err;
550                     }
551           }
552 
553           if (!CBS_stow(content, &data, &data_len))
554                     goto err;
555 
556           if (data_len > INT_MAX)
557                     goto err;
558 
559           if ((aobj = ASN1_OBJECT_new()) == NULL)
560                     goto err;
561 
562           aobj->data = data;
563           aobj->length = (int)data_len; /* XXX - change length to size_t. */
564           aobj->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
565 
566           *out_aobj = aobj;
567 
568           return 1;
569 
570  err:
571           ASN1_OBJECT_free(aobj);
572           free(data);
573 
574           return 0;
575 }
576 
577 ASN1_OBJECT *
c2i_ASN1_OBJECT(ASN1_OBJECT ** out_aobj,const unsigned char ** pp,long len)578 c2i_ASN1_OBJECT(ASN1_OBJECT **out_aobj, const unsigned char **pp, long len)
579 {
580           ASN1_OBJECT *aobj = NULL;
581           CBS content;
582 
583           if (out_aobj != NULL) {
584                     ASN1_OBJECT_free(*out_aobj);
585                     *out_aobj = NULL;
586           }
587 
588           if (len < 0) {
589                     ASN1error(ASN1_R_LENGTH_ERROR);
590                     return NULL;
591           }
592 
593           CBS_init(&content, *pp, len);
594 
595           if (!c2i_ASN1_OBJECT_cbs(&aobj, &content))
596                     return NULL;
597 
598           *pp = CBS_data(&content);
599 
600           if (out_aobj != NULL)
601                     *out_aobj = aobj;
602 
603           return aobj;
604 }
605 
606 int
i2d_ASN1_OBJECT(const ASN1_OBJECT * a,unsigned char ** pp)607 i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
608 {
609           unsigned char *p;
610           int objsize;
611 
612           if ((a == NULL) || (a->data == NULL))
613                     return (0);
614 
615           objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
616           if (pp == NULL)
617                     return objsize;
618 
619           p = *pp;
620           ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
621           memcpy(p, a->data, a->length);
622           p += a->length;
623 
624           *pp = p;
625           return (objsize);
626 }
627 
628 ASN1_OBJECT *
d2i_ASN1_OBJECT(ASN1_OBJECT ** out_aobj,const unsigned char ** pp,long length)629 d2i_ASN1_OBJECT(ASN1_OBJECT **out_aobj, const unsigned char **pp, long length)
630 {
631           ASN1_OBJECT *aobj = NULL;
632           uint32_t tag_number;
633           CBS cbs, content;
634 
635           if (out_aobj != NULL) {
636                     ASN1_OBJECT_free(*out_aobj);
637                     *out_aobj = NULL;
638           }
639 
640           if (length < 0) {
641                     ASN1error(ASN1_R_LENGTH_ERROR);
642                     return NULL;
643           }
644 
645           CBS_init(&cbs, *pp, length);
646 
647           if (!asn1_get_primitive(&cbs, 0, &tag_number, &content)) {
648                     ASN1error(ASN1_R_BAD_OBJECT_HEADER);
649                     return NULL;
650           }
651           if (tag_number != V_ASN1_OBJECT) {
652                     ASN1error(ASN1_R_EXPECTING_AN_OBJECT);
653                     return NULL;
654           }
655 
656           if (!c2i_ASN1_OBJECT_cbs(&aobj, &content))
657                     return NULL;
658 
659           *pp = CBS_data(&cbs);
660 
661           if (out_aobj != NULL)
662                     *out_aobj = aobj;
663 
664           return aobj;
665 }
666