xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/asn1/der_put.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /*	$NetBSD: der_put.c,v 1.3 2023/06/19 21:41:42 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "der_locl.h"
37 
38 __RCSID("$NetBSD: der_put.c,v 1.3 2023/06/19 21:41:42 christos Exp $");
39 
40 /*
41  * All encoding functions take a pointer `p' to first position in
42  * which to write, from the right, `len' which means the maximum
43  * number of characters we are able to write.  The function returns
44  * the number of characters written in `size' (if non-NULL).
45  * The return value is 0 or an error.
46  */
47 
48 int
der_put_unsigned(unsigned char * p,size_t len,const unsigned * v,size_t * size)49 der_put_unsigned (unsigned char *p, size_t len, const unsigned *v, size_t *size)
50 {
51     unsigned char *base = p;
52     unsigned val = *v;
53 
54     if (val) {
55 	while (len > 0 && val) {
56 	    *p-- = val % 256;
57 	    val /= 256;
58 	    --len;
59 	}
60 	if (val != 0)
61 	    return ASN1_OVERFLOW;
62 	else {
63 	    if(p[1] >= 128) {
64 		if(len < 1)
65 		    return ASN1_OVERFLOW;
66 		*p-- = 0;
67 	    }
68 	    *size = base - p;
69 	    return 0;
70 	}
71     } else if (len < 1)
72 	return ASN1_OVERFLOW;
73     else {
74 	*p    = 0;
75 	*size = 1;
76 	return 0;
77     }
78 }
79 
80 int
der_put_unsigned64(unsigned char * p,size_t len,const uint64_t * v,size_t * size)81 der_put_unsigned64 (unsigned char *p, size_t len, const uint64_t *v, size_t *size)
82 {
83     unsigned char *base = p;
84     uint64_t val = *v;
85 
86     if (val) {
87        while (len > 0 && val) {
88            *p-- = val % 256;
89            val /= 256;
90            --len;
91        }
92        if (val != 0)
93            return ASN1_OVERFLOW;
94        else {
95            if(p[1] >= 128) {
96                if(len < 1)
97                    return ASN1_OVERFLOW;
98                *p-- = 0;
99            }
100            *size = base - p;
101            return 0;
102        }
103     } else if (len < 1)
104        return ASN1_OVERFLOW;
105     else {
106        *p    = 0;
107        *size = 1;
108        return 0;
109     }
110 }
111 
112 int
der_put_integer(unsigned char * p,size_t len,const int * v,size_t * size)113 der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size)
114 {
115     unsigned char *base = p;
116     int val = *v;
117 
118     if(val >= 0) {
119 	do {
120 	    if(len < 1)
121 		return ASN1_OVERFLOW;
122 	    *p-- = val % 256;
123 	    len--;
124 	    val /= 256;
125 	} while(val);
126 	if(p[1] >= 128) {
127 	    if(len < 1)
128 		return ASN1_OVERFLOW;
129 	    *p-- = 0;
130 	    len--;
131 	}
132     } else {
133 	val = ~val;
134 	do {
135 	    if(len < 1)
136 		return ASN1_OVERFLOW;
137 	    *p-- = ~(val % 256);
138 	    len--;
139 	    val /= 256;
140 	} while(val);
141 	if(p[1] < 128) {
142 	    if(len < 1)
143 		return ASN1_OVERFLOW;
144 	    *p-- = 0xff;
145 	    len--;
146 	}
147     }
148     *size = base - p;
149     return 0;
150 }
151 
152 int
der_put_integer64(unsigned char * p,size_t len,const int64_t * v,size_t * size)153 der_put_integer64 (unsigned char *p, size_t len, const int64_t *v, size_t *size)
154 {
155     unsigned char *base = p;
156     int64_t val = *v;
157 
158     if(val >= 0) {
159        do {
160            if(len < 1)
161                return ASN1_OVERFLOW;
162            *p-- = val % 256;
163            len--;
164            val /= 256;
165        } while(val);
166        if(p[1] >= 128) {
167            if(len < 1)
168                return ASN1_OVERFLOW;
169            *p-- = 0;
170            len--;
171        }
172     } else {
173        val = ~val;
174        do {
175            if(len < 1)
176                return ASN1_OVERFLOW;
177            *p-- = ~(val % 256);
178            len--;
179            val /= 256;
180        } while(val);
181        if(p[1] < 128) {
182            if(len < 1)
183                return ASN1_OVERFLOW;
184            *p-- = 0xff;
185            len--;
186        }
187     }
188     *size = base - p;
189     return 0;
190 }
191 
192 
193 int
der_put_length(unsigned char * p,size_t len,size_t val,size_t * size)194 der_put_length (unsigned char *p, size_t len, size_t val, size_t *size)
195 {
196     if (len < 1)
197 	return ASN1_OVERFLOW;
198 
199     if (val < 128) {
200 	*p = val;
201 	*size = 1;
202     } else {
203 	size_t l = 0;
204 
205 	while(val > 0) {
206 	    if(len < 2)
207 		return ASN1_OVERFLOW;
208 	    *p-- = val % 256;
209 	    val /= 256;
210 	    len--;
211 	    l++;
212 	}
213 	*p = 0x80 | l;
214 	if(size)
215 	    *size = l + 1;
216     }
217     return 0;
218 }
219 
220 int
der_put_boolean(unsigned char * p,size_t len,const int * data,size_t * size)221 der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size)
222 {
223     if(len < 1)
224 	return ASN1_OVERFLOW;
225     if(*data != 0)
226 	*p = 0xff;
227     else
228 	*p = 0;
229     *size = 1;
230     return 0;
231 }
232 
233 int
der_put_general_string(unsigned char * p,size_t len,const heim_general_string * str,size_t * size)234 der_put_general_string (unsigned char *p, size_t len,
235 			const heim_general_string *str, size_t *size)
236 {
237     size_t slen = strlen(*str);
238 
239     if (len < slen)
240 	return ASN1_OVERFLOW;
241     p -= slen;
242     memcpy (p+1, *str, slen);
243     *size = slen;
244     return 0;
245 }
246 
247 int
der_put_utf8string(unsigned char * p,size_t len,const heim_utf8_string * str,size_t * size)248 der_put_utf8string (unsigned char *p, size_t len,
249 		    const heim_utf8_string *str, size_t *size)
250 {
251     return der_put_general_string(p, len, str, size);
252 }
253 
254 int
der_put_printable_string(unsigned char * p,size_t len,const heim_printable_string * str,size_t * size)255 der_put_printable_string (unsigned char *p, size_t len,
256 			  const heim_printable_string *str, size_t *size)
257 {
258     return der_put_octet_string(p, len, str, size);
259 }
260 
261 int
der_put_ia5_string(unsigned char * p,size_t len,const heim_ia5_string * str,size_t * size)262 der_put_ia5_string (unsigned char *p, size_t len,
263 		    const heim_ia5_string *str, size_t *size)
264 {
265     return der_put_octet_string(p, len, str, size);
266 }
267 
268 int
der_put_bmp_string(unsigned char * p,size_t len,const heim_bmp_string * data,size_t * size)269 der_put_bmp_string (unsigned char *p, size_t len,
270 		    const heim_bmp_string *data, size_t *size)
271 {
272     size_t i;
273     if (len / 2 < data->length)
274 	return ASN1_OVERFLOW;
275     p -= data->length * 2;
276     for (i = 0; i < data->length; i++) {
277 	p[1] = (data->data[i] >> 8) & 0xff;
278 	p[2] = data->data[i] & 0xff;
279 	p += 2;
280     }
281     if (size) *size = data->length * 2;
282     return 0;
283 }
284 
285 int
der_put_universal_string(unsigned char * p,size_t len,const heim_universal_string * data,size_t * size)286 der_put_universal_string (unsigned char *p, size_t len,
287 			  const heim_universal_string *data, size_t *size)
288 {
289     size_t i;
290     if (len / 4 < data->length)
291 	return ASN1_OVERFLOW;
292     p -= data->length * 4;
293     for (i = 0; i < data->length; i++) {
294 	p[1] = (data->data[i] >> 24) & 0xff;
295 	p[2] = (data->data[i] >> 16) & 0xff;
296 	p[3] = (data->data[i] >> 8) & 0xff;
297 	p[4] = data->data[i] & 0xff;
298 	p += 4;
299     }
300     if (size) *size = data->length * 4;
301     return 0;
302 }
303 
304 int
der_put_visible_string(unsigned char * p,size_t len,const heim_visible_string * str,size_t * size)305 der_put_visible_string (unsigned char *p, size_t len,
306 			 const heim_visible_string *str, size_t *size)
307 {
308     return der_put_general_string(p, len, str, size);
309 }
310 
311 int
der_put_octet_string(unsigned char * p,size_t len,const heim_octet_string * data,size_t * size)312 der_put_octet_string (unsigned char *p, size_t len,
313 		      const heim_octet_string *data, size_t *size)
314 {
315     if (len < data->length)
316 	return ASN1_OVERFLOW;
317     p -= data->length;
318     if (data->length)
319         memcpy(p+1, data->data, data->length);
320     *size = data->length;
321     return 0;
322 }
323 
324 int
der_put_heim_integer(unsigned char * p,size_t len,const heim_integer * data,size_t * size)325 der_put_heim_integer (unsigned char *p, size_t len,
326 		     const heim_integer *data, size_t *size)
327 {
328     unsigned char *buf = data->data;
329     int hibitset = 0;
330 
331     if (data->length == 0) {
332 	if (len < 1)
333 	    return ASN1_OVERFLOW;
334 	*p-- = 0;
335 	if (size)
336 	    *size = 1;
337 	return 0;
338     }
339     if (len < data->length)
340 	return ASN1_OVERFLOW;
341 
342     len -= data->length;
343 
344     if (data->negative) {
345 	ssize_t i;
346 	int carry;
347 
348         /*
349          * We represent the parsed integer as a positive value with a
350          * negativity flag.  But we need to put it on the wire as the shortest
351          * twos-complement byte sequence possible.  So we're going to negate
352          * the number as go.
353          */
354         if (data->length == 1 && *(unsigned char *)data->data == 1) {
355             *(p--) = 0xff;
356         } else {
357             for (i = data->length - 1, carry = 1; i >= 0; i--) {
358                 *p = buf[i] ^ 0xff;
359                 if (carry)
360                     carry = !++*p;
361                 p--;
362             }
363             if (p[1] < 128) {
364                 if (len < 1)
365                     return ASN1_OVERFLOW;
366                 *p-- = 0xff;
367                 len--;
368                 hibitset = 1;
369             }
370         }
371     } else {
372 	p -= data->length;
373 	memcpy(p + 1, buf, data->length);
374 
375 	if (p[1] >= 128) {
376 	    if (len < 1)
377 		return ASN1_OVERFLOW;
378 	    p[0] = 0;
379 	    len--;
380 	    hibitset = 1;
381 	}
382     }
383     if (size)
384 	*size = data->length + hibitset;
385     return 0;
386 }
387 
388 int
der_put_generalized_time(unsigned char * p,size_t len,const time_t * data,size_t * size)389 der_put_generalized_time (unsigned char *p, size_t len,
390 			  const time_t *data, size_t *size)
391 {
392     heim_octet_string k;
393     size_t l;
394     int e;
395 
396     e = _heim_time2generalizedtime (*data, &k, 1);
397     if (e)
398 	return e;
399     e = der_put_octet_string(p, len, &k, &l);
400     free(k.data);
401     if(e)
402 	return e;
403     if(size)
404 	*size = l;
405     return 0;
406 }
407 
408 int
der_put_utctime(unsigned char * p,size_t len,const time_t * data,size_t * size)409 der_put_utctime (unsigned char *p, size_t len,
410 		 const time_t *data, size_t *size)
411 {
412     heim_octet_string k;
413     size_t l;
414     int e;
415 
416     e = _heim_time2generalizedtime (*data, &k, 0);
417     if (e)
418 	return e;
419     e = der_put_octet_string(p, len, &k, &l);
420     free(k.data);
421     if(e)
422 	return e;
423     if(size)
424 	*size = l;
425     return 0;
426 }
427 
428 int
der_put_oid(unsigned char * p,size_t len,const heim_oid * data,size_t * size)429 der_put_oid (unsigned char *p, size_t len,
430 	     const heim_oid *data, size_t *size)
431 {
432     unsigned char *base = p;
433     size_t n;
434 
435     for (n = data->length - 1; n >= 2; --n) {
436 	unsigned u = data->components[n];
437 
438 	if (len < 1)
439 	    return ASN1_OVERFLOW;
440 	*p-- = u % 128;
441 	u /= 128;
442 	--len;
443 	while (u > 0) {
444 	    if (len < 1)
445 		return ASN1_OVERFLOW;
446 	    *p-- = 128 + u % 128;
447 	    u /= 128;
448 	    --len;
449 	}
450     }
451     if (len < 1)
452 	return ASN1_OVERFLOW;
453     *p-- = 40 * data->components[0] + data->components[1];
454     *size = base - p;
455     return 0;
456 }
457 
458 int
der_put_tag(unsigned char * p,size_t len,Der_class class,Der_type type,unsigned int tag,size_t * size)459 der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
460 	     unsigned int tag, size_t *size)
461 {
462     if (tag <= 30) {
463 	if (len < 1)
464 	    return ASN1_OVERFLOW;
465 	*p = MAKE_TAG(class, type, tag);
466 	*size = 1;
467     } else {
468 	size_t ret = 0;
469 	unsigned int continuation = 0;
470 
471 	do {
472 	    if (len < 1)
473 		return ASN1_OVERFLOW;
474 	    *p-- = tag % 128 | continuation;
475 	    len--;
476 	    ret++;
477 	    tag /= 128;
478 	    continuation = 0x80;
479 	} while(tag > 0);
480 	if (len < 1)
481 	    return ASN1_OVERFLOW;
482 	*p-- = MAKE_TAG(class, type, 0x1f);
483 	ret++;
484 	*size = ret;
485     }
486     return 0;
487 }
488 
489 int
der_put_length_and_tag(unsigned char * p,size_t len,size_t len_val,Der_class class,Der_type type,unsigned int tag,size_t * size)490 der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val,
491 			Der_class class, Der_type type,
492 			unsigned int tag, size_t *size)
493 {
494     size_t ret = 0;
495     size_t l;
496     int e;
497 
498     e = der_put_length (p, len, len_val, &l);
499     if(e)
500 	return e;
501     p -= l;
502     len -= l;
503     ret += l;
504     e = der_put_tag (p, len, class, type, tag, &l);
505     if(e)
506 	return e;
507 
508     ret += l;
509     *size = ret;
510     return 0;
511 }
512 
513 int
_heim_time2generalizedtime(time_t t,heim_octet_string * s,int gtimep)514 _heim_time2generalizedtime (time_t t, heim_octet_string *s, int gtimep)
515 {
516      struct tm tm;
517      const size_t len = gtimep ? 15 : 13;
518 
519      s->data = NULL;
520      s->length = 0;
521      if (_der_gmtime(t, &tm) == NULL)
522 	 return ASN1_BAD_TIMEFORMAT;
523      s->data = malloc(len + 1);
524      if (s->data == NULL)
525 	 return ENOMEM;
526      s->length = len;
527      if (gtimep)
528 	 snprintf (s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ",
529 		   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
530 		   tm.tm_hour, tm.tm_min, tm.tm_sec);
531      else
532 	 snprintf (s->data, len + 1, "%02d%02d%02d%02d%02d%02dZ",
533 		   tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday,
534 		   tm.tm_hour, tm.tm_min, tm.tm_sec);
535 
536      return 0;
537 }
538 
539 int
der_put_bit_string(unsigned char * p,size_t len,const heim_bit_string * data,size_t * size)540 der_put_bit_string (unsigned char *p, size_t len,
541 		    const heim_bit_string *data, size_t *size)
542 {
543     size_t data_size = (data->length + 7) / 8;
544     if (len < data_size + 1)
545 	return ASN1_OVERFLOW;
546     p -= data_size + 1;
547 
548     memcpy (p+2, data->data, data_size);
549     if (data->length && (data->length % 8) != 0)
550 	p[1] = 8 - (data->length % 8);
551     else
552 	p[1] = 0;
553     *size = data_size + 1;
554     return 0;
555 }
556 
557 int
_heim_der_set_sort(const void * a1,const void * a2)558 _heim_der_set_sort(const void *a1, const void *a2)
559 {
560     const heim_octet_string *s1 = a1, *s2 = a2;
561     int ret;
562 
563     ret = memcmp(s1->data, s2->data,
564 		 s1->length < s2->length ? s1->length : s2->length);
565     if(ret)
566 	return ret;
567     return (int)(s1->length - s2->length);
568 }
569