xref: /aosp_15_r20/external/cronet/third_party/boringssl/src/crypto/asn1/tasn_enc.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Copyright (C) 1995-1998 Eric Young ([email protected])
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young ([email protected]).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson ([email protected]).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young ([email protected])"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson ([email protected])"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/asn1.h>
58 
59 #include <assert.h>
60 #include <limits.h>
61 #include <string.h>
62 
63 #include <openssl/asn1t.h>
64 #include <openssl/mem.h>
65 
66 #include "../internal.h"
67 #include "internal.h"
68 
69 
70 static int asn1_item_ex_i2d_opt(ASN1_VALUE **pval, unsigned char **out,
71                                 const ASN1_ITEM *it, int tag, int aclass,
72                                 int optional);
73 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
74                                  const ASN1_ITEM *it, int tag, int aclass,
75                                  int optional);
76 static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *out_omit,
77                        int *putype, const ASN1_ITEM *it);
78 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
79                             int skcontlen, const ASN1_ITEM *item, int do_sort);
80 static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
81                                 const ASN1_TEMPLATE *tt, int tag, int aclass,
82                                 int optional);
83 
84 // Top level i2d equivalents
85 
ASN1_item_i2d(ASN1_VALUE * val,unsigned char ** out,const ASN1_ITEM * it)86 int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) {
87   if (out && !*out) {
88     unsigned char *p, *buf;
89     int len = ASN1_item_ex_i2d(&val, NULL, it, /*tag=*/-1, /*aclass=*/0);
90     if (len <= 0) {
91       return len;
92     }
93     buf = OPENSSL_malloc(len);
94     if (!buf) {
95       return -1;
96     }
97     p = buf;
98     int len2 = ASN1_item_ex_i2d(&val, &p, it, /*tag=*/-1, /*aclass=*/0);
99     if (len2 <= 0) {
100       OPENSSL_free(buf);
101       return len2;
102     }
103     assert(len == len2);
104     *out = buf;
105     return len;
106   }
107 
108   return ASN1_item_ex_i2d(&val, out, it, /*tag=*/-1, /*aclass=*/0);
109 }
110 
111 // Encode an item, taking care of IMPLICIT tagging (if any). This function
112 // performs the normal item handling: it can be used in external types.
113 
ASN1_item_ex_i2d(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_ITEM * it,int tag,int aclass)114 int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
115                      const ASN1_ITEM *it, int tag, int aclass) {
116   int ret = asn1_item_ex_i2d_opt(pval, out, it, tag, aclass, /*optional=*/0);
117   assert(ret != 0);
118   return ret;
119 }
120 
121 // asn1_item_ex_i2d_opt behaves like |ASN1_item_ex_i2d| but, if |optional| is
122 // non-zero and |*pval| is omitted, it returns zero and writes no bytes.
asn1_item_ex_i2d_opt(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_ITEM * it,int tag,int aclass,int optional)123 int asn1_item_ex_i2d_opt(ASN1_VALUE **pval, unsigned char **out,
124                          const ASN1_ITEM *it, int tag, int aclass,
125                          int optional) {
126   const ASN1_TEMPLATE *tt = NULL;
127   int i, seqcontlen, seqlen;
128 
129   // Historically, |aclass| was repurposed to pass additional flags into the
130   // encoding process.
131   assert((aclass & ASN1_TFLG_TAG_CLASS) == aclass);
132   // If not overridding the tag, |aclass| is ignored and should be zero.
133   assert(tag != -1 || aclass == 0);
134 
135   // All fields are pointers, except for boolean |ASN1_ITYPE_PRIMITIVE|s.
136   // Optional primitives are handled later.
137   if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) {
138     if (optional) {
139       return 0;
140     }
141     OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
142     return -1;
143   }
144 
145   switch (it->itype) {
146     case ASN1_ITYPE_PRIMITIVE:
147       if (it->templates) {
148         // This is an |ASN1_ITEM_TEMPLATE|.
149         if (it->templates->flags & ASN1_TFLG_OPTIONAL) {
150           OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
151           return -1;
152         }
153         return asn1_template_ex_i2d(pval, out, it->templates, tag, aclass,
154                                     optional);
155       }
156       return asn1_i2d_ex_primitive(pval, out, it, tag, aclass, optional);
157 
158     case ASN1_ITYPE_MSTRING:
159       // It never makes sense for multi-strings to have implicit tagging, so
160       // if tag != -1, then this looks like an error in the template.
161       if (tag != -1) {
162         OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
163         return -1;
164       }
165       return asn1_i2d_ex_primitive(pval, out, it, -1, 0, optional);
166 
167     case ASN1_ITYPE_CHOICE: {
168       // It never makes sense for CHOICE types to have implicit tagging, so if
169       // tag != -1, then this looks like an error in the template.
170       if (tag != -1) {
171         OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
172         return -1;
173       }
174       i = asn1_get_choice_selector(pval, it);
175       if (i < 0 || i >= it->tcount) {
176         OPENSSL_PUT_ERROR(ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE);
177         return -1;
178       }
179       const ASN1_TEMPLATE *chtt = it->templates + i;
180       if (chtt->flags & ASN1_TFLG_OPTIONAL) {
181         OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
182         return -1;
183       }
184       ASN1_VALUE **pchval = asn1_get_field_ptr(pval, chtt);
185       return asn1_template_ex_i2d(pchval, out, chtt, -1, 0, /*optional=*/0);
186     }
187 
188     case ASN1_ITYPE_EXTERN: {
189       // We don't support implicit tagging with external types.
190       if (tag != -1) {
191         OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
192         return -1;
193       }
194       const ASN1_EXTERN_FUNCS *ef = it->funcs;
195       int ret = ef->asn1_ex_i2d(pval, out, it);
196       if (ret == 0) {
197         // |asn1_ex_i2d| should never return zero. We have already checked
198         // for optional values generically, and |ASN1_ITYPE_EXTERN| fields
199         // must be pointers.
200         OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
201         return -1;
202       }
203       return ret;
204     }
205 
206     case ASN1_ITYPE_SEQUENCE: {
207       i = asn1_enc_restore(&seqcontlen, out, pval, it);
208       // An error occurred
209       if (i < 0) {
210         return -1;
211       }
212       // We have a valid cached encoding...
213       if (i > 0) {
214         return seqcontlen;
215       }
216       // Otherwise carry on
217       seqcontlen = 0;
218       // If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL
219       if (tag == -1) {
220         tag = V_ASN1_SEQUENCE;
221         aclass = V_ASN1_UNIVERSAL;
222       }
223       // First work out sequence content length
224       for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
225         const ASN1_TEMPLATE *seqtt;
226         ASN1_VALUE **pseqval;
227         int tmplen;
228         seqtt = asn1_do_adb(pval, tt, 1);
229         if (!seqtt) {
230           return -1;
231         }
232         pseqval = asn1_get_field_ptr(pval, seqtt);
233         tmplen =
234             asn1_template_ex_i2d(pseqval, NULL, seqtt, -1, 0, /*optional=*/0);
235         if (tmplen == -1 || (tmplen > INT_MAX - seqcontlen)) {
236           return -1;
237         }
238         seqcontlen += tmplen;
239       }
240 
241       seqlen = ASN1_object_size(/*constructed=*/1, seqcontlen, tag);
242       if (!out || seqlen == -1) {
243         return seqlen;
244       }
245       // Output SEQUENCE header
246       ASN1_put_object(out, /*constructed=*/1, seqcontlen, tag, aclass);
247       for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) {
248         const ASN1_TEMPLATE *seqtt;
249         ASN1_VALUE **pseqval;
250         seqtt = asn1_do_adb(pval, tt, 1);
251         if (!seqtt) {
252           return -1;
253         }
254         pseqval = asn1_get_field_ptr(pval, seqtt);
255         if (asn1_template_ex_i2d(pseqval, out, seqtt, -1, 0, /*optional=*/0) <
256             0) {
257           return -1;
258         }
259       }
260       return seqlen;
261     }
262 
263     default:
264       OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
265       return -1;
266   }
267 }
268 
269 // asn1_template_ex_i2d behaves like |asn1_item_ex_i2d_opt| but uses an
270 // |ASN1_TEMPLATE| instead of an |ASN1_ITEM|. An |ASN1_TEMPLATE| wraps an
271 // |ASN1_ITEM| with modifiers such as tagging, SEQUENCE or SET, etc.
asn1_template_ex_i2d(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_TEMPLATE * tt,int tag,int iclass,int optional)272 static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out,
273                                 const ASN1_TEMPLATE *tt, int tag, int iclass,
274                                 int optional) {
275   int i, ret, ttag, tclass;
276   size_t j;
277   uint32_t flags = tt->flags;
278 
279   // Historically, |iclass| was repurposed to pass additional flags into the
280   // encoding process.
281   assert((iclass & ASN1_TFLG_TAG_CLASS) == iclass);
282   // If not overridding the tag, |iclass| is ignored and should be zero.
283   assert(tag != -1 || iclass == 0);
284 
285   // Work out tag and class to use: tagging may come either from the
286   // template or the arguments, not both because this would create
287   // ambiguity.
288   if (flags & ASN1_TFLG_TAG_MASK) {
289     // Error if argument and template tagging
290     if (tag != -1) {
291       OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_TEMPLATE);
292       return -1;
293     }
294     // Get tagging from template
295     ttag = tt->tag;
296     tclass = flags & ASN1_TFLG_TAG_CLASS;
297   } else if (tag != -1) {
298     // No template tagging, get from arguments
299     ttag = tag;
300     tclass = iclass & ASN1_TFLG_TAG_CLASS;
301   } else {
302     ttag = -1;
303     tclass = 0;
304   }
305 
306   // The template may itself by marked as optional, or this may be the template
307   // of an |ASN1_ITEM_TEMPLATE| type which was contained inside an outer
308   // optional template. (They cannot both be true because the
309   // |ASN1_ITEM_TEMPLATE| codepath rejects optional templates.)
310   assert(!optional || (flags & ASN1_TFLG_OPTIONAL) == 0);
311   optional = optional || (flags & ASN1_TFLG_OPTIONAL) != 0;
312 
313   // At this point 'ttag' contains the outer tag to use, and 'tclass' is the
314   // class.
315 
316   if (flags & ASN1_TFLG_SK_MASK) {
317     // SET OF, SEQUENCE OF
318     STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval;
319     int isset, sktag, skaclass;
320     int skcontlen, sklen;
321     ASN1_VALUE *skitem;
322 
323     if (!*pval) {
324       if (optional) {
325         return 0;
326       }
327       OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
328       return -1;
329     }
330 
331     if (flags & ASN1_TFLG_SET_OF) {
332       isset = 1;
333       // Historically, types with both bits set were mutated when
334       // serialized to apply the sort. We no longer support this.
335       assert((flags & ASN1_TFLG_SEQUENCE_OF) == 0);
336     } else {
337       isset = 0;
338     }
339 
340     // Work out inner tag value: if EXPLICIT or no tagging use underlying
341     // type.
342     if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) {
343       sktag = ttag;
344       skaclass = tclass;
345     } else {
346       skaclass = V_ASN1_UNIVERSAL;
347       if (isset) {
348         sktag = V_ASN1_SET;
349       } else {
350         sktag = V_ASN1_SEQUENCE;
351       }
352     }
353 
354     // Determine total length of items
355     skcontlen = 0;
356     for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) {
357       int tmplen;
358       skitem = sk_ASN1_VALUE_value(sk, j);
359       tmplen = ASN1_item_ex_i2d(&skitem, NULL, ASN1_ITEM_ptr(tt->item), -1, 0);
360       if (tmplen == -1 || (skcontlen > INT_MAX - tmplen)) {
361         return -1;
362       }
363       skcontlen += tmplen;
364     }
365     sklen = ASN1_object_size(/*constructed=*/1, skcontlen, sktag);
366     if (sklen == -1) {
367       return -1;
368     }
369     // If EXPLICIT need length of surrounding tag
370     if (flags & ASN1_TFLG_EXPTAG) {
371       ret = ASN1_object_size(/*constructed=*/1, sklen, ttag);
372     } else {
373       ret = sklen;
374     }
375 
376     if (!out || ret == -1) {
377       return ret;
378     }
379 
380     // Now encode this lot...
381     // EXPLICIT tag
382     if (flags & ASN1_TFLG_EXPTAG) {
383       ASN1_put_object(out, /*constructed=*/1, sklen, ttag, tclass);
384     }
385     // SET or SEQUENCE and IMPLICIT tag
386     ASN1_put_object(out, /*constructed=*/1, skcontlen, sktag, skaclass);
387     // And the stuff itself
388     if (!asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), isset)) {
389       return -1;
390     }
391     return ret;
392   }
393 
394   if (flags & ASN1_TFLG_EXPTAG) {
395     // EXPLICIT tagging
396     // Find length of tagged item
397     i = asn1_item_ex_i2d_opt(pval, NULL, ASN1_ITEM_ptr(tt->item), -1, 0,
398                              optional);
399     if (i <= 0) {
400       return i;
401     }
402     // Find length of EXPLICIT tag
403     ret = ASN1_object_size(/*constructed=*/1, i, ttag);
404     if (out && ret != -1) {
405       // Output tag and item
406       ASN1_put_object(out, /*constructed=*/1, i, ttag, tclass);
407       if (ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), -1, 0) < 0) {
408         return -1;
409       }
410     }
411     return ret;
412   }
413 
414   // Either normal or IMPLICIT tagging
415   return asn1_item_ex_i2d_opt(pval, out, ASN1_ITEM_ptr(tt->item), ttag, tclass,
416                               optional);
417 }
418 
419 // Temporary structure used to hold DER encoding of items for SET OF
420 
421 typedef struct {
422   unsigned char *data;
423   int length;
424 } DER_ENC;
425 
der_cmp(const void * a,const void * b)426 static int der_cmp(const void *a, const void *b) {
427   const DER_ENC *d1 = a, *d2 = b;
428   int cmplen, i;
429   cmplen = (d1->length < d2->length) ? d1->length : d2->length;
430   i = OPENSSL_memcmp(d1->data, d2->data, cmplen);
431   if (i) {
432     return i;
433   }
434   return d1->length - d2->length;
435 }
436 
437 // asn1_set_seq_out writes |sk| to |out| under the i2d output convention,
438 // excluding the tag and length. It returns one on success and zero on error.
439 // |skcontlen| must be the total encoded size. If |do_sort| is non-zero, the
440 // elements are sorted for a SET OF type. Each element of |sk| has type
441 // |item|.
asn1_set_seq_out(STACK_OF (ASN1_VALUE)* sk,unsigned char ** out,int skcontlen,const ASN1_ITEM * item,int do_sort)442 static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out,
443                             int skcontlen, const ASN1_ITEM *item, int do_sort) {
444   // No need to sort if there are fewer than two items.
445   if (!do_sort || sk_ASN1_VALUE_num(sk) < 2) {
446     for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
447       ASN1_VALUE *skitem = sk_ASN1_VALUE_value(sk, i);
448       if (ASN1_item_ex_i2d(&skitem, out, item, -1, 0) < 0) {
449         return 0;
450       }
451     }
452     return 1;
453   }
454 
455   int ret = 0;
456   unsigned char *const buf = OPENSSL_malloc(skcontlen);
457   DER_ENC *encoded = OPENSSL_calloc(sk_ASN1_VALUE_num(sk), sizeof(*encoded));
458   if (encoded == NULL || buf == NULL) {
459     goto err;
460   }
461 
462   // Encode all the elements into |buf| and populate |encoded|.
463   unsigned char *p = buf;
464   for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
465     ASN1_VALUE *skitem = sk_ASN1_VALUE_value(sk, i);
466     encoded[i].data = p;
467     encoded[i].length = ASN1_item_ex_i2d(&skitem, &p, item, -1, 0);
468     if (encoded[i].length < 0) {
469       goto err;
470     }
471     assert(p - buf <= skcontlen);
472   }
473 
474   qsort(encoded, sk_ASN1_VALUE_num(sk), sizeof(*encoded), der_cmp);
475 
476   // Output the elements in sorted order.
477   p = *out;
478   for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) {
479     OPENSSL_memcpy(p, encoded[i].data, encoded[i].length);
480     p += encoded[i].length;
481   }
482   *out = p;
483 
484   ret = 1;
485 
486 err:
487   OPENSSL_free(encoded);
488   OPENSSL_free(buf);
489   return ret;
490 }
491 
492 // asn1_i2d_ex_primitive behaves like |ASN1_item_ex_i2d| but |item| must be a
493 // a PRIMITIVE or MSTRING type that is not an |ASN1_ITEM_TEMPLATE|.
asn1_i2d_ex_primitive(ASN1_VALUE ** pval,unsigned char ** out,const ASN1_ITEM * it,int tag,int aclass,int optional)494 static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out,
495                                  const ASN1_ITEM *it, int tag, int aclass,
496                                  int optional) {
497   // Get length of content octets and maybe find out the underlying type.
498   int omit;
499   int utype = it->utype;
500   int len = asn1_ex_i2c(pval, NULL, &omit, &utype, it);
501   if (len < 0) {
502     return -1;
503   }
504   if (omit) {
505     if (optional) {
506       return 0;
507     }
508     OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE);
509     return -1;
510   }
511 
512   // If SEQUENCE, SET or OTHER then header is included in pseudo content
513   // octets so don't include tag+length. We need to check here because the
514   // call to asn1_ex_i2c() could change utype.
515   int usetag =
516       utype != V_ASN1_SEQUENCE && utype != V_ASN1_SET && utype != V_ASN1_OTHER;
517 
518   // If not implicitly tagged get tag from underlying type
519   if (tag == -1) {
520     tag = utype;
521   }
522 
523   // Output tag+length followed by content octets
524   if (out) {
525     if (usetag) {
526       ASN1_put_object(out, /*constructed=*/0, len, tag, aclass);
527     }
528     int len2 = asn1_ex_i2c(pval, *out, &omit, &utype, it);
529     if (len2 < 0) {
530       return -1;
531     }
532     assert(len == len2);
533     assert(!omit);
534     *out += len;
535   }
536 
537   if (usetag) {
538     return ASN1_object_size(/*constructed=*/0, len, tag);
539   }
540   return len;
541 }
542 
543 // asn1_ex_i2c writes the |*pval| to |cout| under the i2d output convention,
544 // excluding the tag and length. It returns the number of bytes written,
545 // possibly zero, on success or -1 on error. If |*pval| should be omitted, it
546 // returns zero and sets |*out_omit| to true.
547 //
548 // If |it| is an MSTRING or ANY type, it gets the underlying type from |*pval|,
549 // which must be an |ASN1_STRING| or |ASN1_TYPE|, respectively. It then updates
550 // |*putype| with the tag number of type used, or |V_ASN1_OTHER| if it was not a
551 // universal type. If |*putype| is set to |V_ASN1_SEQUENCE|, |V_ASN1_SET|, or
552 // |V_ASN1_OTHER|, it additionally outputs the tag and length, so the caller
553 // must not do so.
554 //
555 // Otherwise, |*putype| must contain |it->utype|.
556 //
557 // WARNING: Unlike most functions in this file, |asn1_ex_i2c| can return zero
558 // without omitting the element. ASN.1 values may have empty contents.
asn1_ex_i2c(ASN1_VALUE ** pval,unsigned char * cout,int * out_omit,int * putype,const ASN1_ITEM * it)559 static int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *out_omit,
560                        int *putype, const ASN1_ITEM *it) {
561   ASN1_BOOLEAN *tbool = NULL;
562   ASN1_STRING *strtmp;
563   ASN1_OBJECT *otmp;
564   int utype;
565   const unsigned char *cont;
566   unsigned char c;
567   int len;
568 
569   // Historically, |it->funcs| for primitive types contained an
570   // |ASN1_PRIMITIVE_FUNCS| table of callbacks.
571   assert(it->funcs == NULL);
572 
573   *out_omit = 0;
574 
575   // Should type be omitted?
576   if ((it->itype != ASN1_ITYPE_PRIMITIVE) || (it->utype != V_ASN1_BOOLEAN)) {
577     if (!*pval) {
578       *out_omit = 1;
579       return 0;
580     }
581   }
582 
583   if (it->itype == ASN1_ITYPE_MSTRING) {
584     // If MSTRING type set the underlying type
585     strtmp = (ASN1_STRING *)*pval;
586     utype = strtmp->type;
587     if (utype < 0 && utype != V_ASN1_OTHER) {
588       // MSTRINGs can have type -1 when default-constructed.
589       OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TYPE);
590       return -1;
591     }
592     // Negative INTEGER and ENUMERATED values use |ASN1_STRING| type values
593     // that do not match their corresponding utype values. INTEGERs cannot
594     // participate in MSTRING types, but ENUMERATEDs can.
595     //
596     // TODO(davidben): Is this a bug? Although arguably one of the MSTRING
597     // types should contain more values, rather than less. See
598     // https://crbug.com/boringssl/412. But it is not possible to fit all
599     // possible ANY values into an |ASN1_STRING|, so matching the spec here
600     // is somewhat hopeless.
601     if (utype == V_ASN1_NEG_INTEGER) {
602       utype = V_ASN1_INTEGER;
603     } else if (utype == V_ASN1_NEG_ENUMERATED) {
604       utype = V_ASN1_ENUMERATED;
605     }
606     *putype = utype;
607   } else if (it->utype == V_ASN1_ANY) {
608     // If ANY set type and pointer to value
609     ASN1_TYPE *typ;
610     typ = (ASN1_TYPE *)*pval;
611     utype = typ->type;
612     if (utype < 0 && utype != V_ASN1_OTHER) {
613       // |ASN1_TYPE|s can have type -1 when default-constructed.
614       OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TYPE);
615       return -1;
616     }
617     *putype = utype;
618     pval = &typ->value.asn1_value;
619   } else {
620     utype = *putype;
621   }
622 
623   switch (utype) {
624     case V_ASN1_OBJECT:
625       otmp = (ASN1_OBJECT *)*pval;
626       cont = otmp->data;
627       len = otmp->length;
628       if (len == 0) {
629         // Some |ASN1_OBJECT|s do not have OIDs and cannot be serialized.
630         OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT);
631         return -1;
632       }
633       break;
634 
635     case V_ASN1_NULL:
636       cont = NULL;
637       len = 0;
638       break;
639 
640     case V_ASN1_BOOLEAN:
641       tbool = (ASN1_BOOLEAN *)pval;
642       if (*tbool == ASN1_BOOLEAN_NONE) {
643         *out_omit = 1;
644         return 0;
645       }
646       if (it->utype != V_ASN1_ANY) {
647         // Default handling if value == size field then omit
648         if ((*tbool && (it->size > 0)) || (!*tbool && !it->size)) {
649           *out_omit = 1;
650           return 0;
651         }
652       }
653       c = *tbool ? 0xff : 0x00;
654       cont = &c;
655       len = 1;
656       break;
657 
658     case V_ASN1_BIT_STRING: {
659       int ret =
660           i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, cout ? &cout : NULL);
661       // |i2c_ASN1_BIT_STRING| returns zero on error instead of -1.
662       return ret <= 0 ? -1 : ret;
663     }
664 
665     case V_ASN1_INTEGER:
666     case V_ASN1_ENUMERATED: {
667       // |i2c_ASN1_INTEGER| also handles ENUMERATED.
668       int ret = i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, cout ? &cout : NULL);
669       // |i2c_ASN1_INTEGER| returns zero on error instead of -1.
670       return ret <= 0 ? -1 : ret;
671     }
672 
673     case V_ASN1_OCTET_STRING:
674     case V_ASN1_NUMERICSTRING:
675     case V_ASN1_PRINTABLESTRING:
676     case V_ASN1_T61STRING:
677     case V_ASN1_VIDEOTEXSTRING:
678     case V_ASN1_IA5STRING:
679     case V_ASN1_UTCTIME:
680     case V_ASN1_GENERALIZEDTIME:
681     case V_ASN1_GRAPHICSTRING:
682     case V_ASN1_VISIBLESTRING:
683     case V_ASN1_GENERALSTRING:
684     case V_ASN1_UNIVERSALSTRING:
685     case V_ASN1_BMPSTRING:
686     case V_ASN1_UTF8STRING:
687     case V_ASN1_SEQUENCE:
688     case V_ASN1_SET:
689     // This is not a valid |ASN1_ITEM| type, but it appears in |ASN1_TYPE|.
690     case V_ASN1_OTHER:
691     // TODO(crbug.com/boringssl/412): This default case should be removed, now
692     // that we've resolved https://crbug.com/boringssl/561. However, it is still
693     // needed to support some edge cases in |ASN1_PRINTABLE|. |ASN1_PRINTABLE|
694     // broadly doesn't tolerate unrecognized universal tags, but except for
695     // eight values that map to |B_ASN1_UNKNOWN| instead of zero. See the
696     // X509Test.NameAttributeValues test.
697     default:
698       // All based on ASN1_STRING and handled the same
699       strtmp = (ASN1_STRING *)*pval;
700       cont = strtmp->data;
701       len = strtmp->length;
702       break;
703   }
704   if (cout && len) {
705     OPENSSL_memcpy(cout, cont, len);
706   }
707   return len;
708 }
709