1 /*	$NetBSD: der_put.c,v 1.1.1.2 2014/04/24 12:45:28 pettai 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");
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_integer(unsigned char * p,size_t len,const int * v,size_t * size)81 der_put_integer (unsigned char *p, size_t len, const int *v, size_t *size)
82 {
83     unsigned char *base = p;
84     int val = *v;
85 
86     if(val >= 0) {
87 	do {
88 	    if(len < 1)
89 		return ASN1_OVERFLOW;
90 	    *p-- = val % 256;
91 	    len--;
92 	    val /= 256;
93 	} while(val);
94 	if(p[1] >= 128) {
95 	    if(len < 1)
96 		return ASN1_OVERFLOW;
97 	    *p-- = 0;
98 	    len--;
99 	}
100     } else {
101 	val = ~val;
102 	do {
103 	    if(len < 1)
104 		return ASN1_OVERFLOW;
105 	    *p-- = ~(val % 256);
106 	    len--;
107 	    val /= 256;
108 	} while(val);
109 	if(p[1] < 128) {
110 	    if(len < 1)
111 		return ASN1_OVERFLOW;
112 	    *p-- = 0xff;
113 	    len--;
114 	}
115     }
116     *size = base - p;
117     return 0;
118 }
119 
120 
121 int
der_put_length(unsigned char * p,size_t len,size_t val,size_t * size)122 der_put_length (unsigned char *p, size_t len, size_t val, size_t *size)
123 {
124     if (len < 1)
125 	return ASN1_OVERFLOW;
126 
127     if (val < 128) {
128 	*p = val;
129 	*size = 1;
130     } else {
131 	size_t l = 0;
132 
133 	while(val > 0) {
134 	    if(len < 2)
135 		return ASN1_OVERFLOW;
136 	    *p-- = val % 256;
137 	    val /= 256;
138 	    len--;
139 	    l++;
140 	}
141 	*p = 0x80 | l;
142 	if(size)
143 	    *size = l + 1;
144     }
145     return 0;
146 }
147 
148 int
der_put_boolean(unsigned char * p,size_t len,const int * data,size_t * size)149 der_put_boolean(unsigned char *p, size_t len, const int *data, size_t *size)
150 {
151     if(len < 1)
152 	return ASN1_OVERFLOW;
153     if(*data != 0)
154 	*p = 0xff;
155     else
156 	*p = 0;
157     *size = 1;
158     return 0;
159 }
160 
161 int
der_put_general_string(unsigned char * p,size_t len,const heim_general_string * str,size_t * size)162 der_put_general_string (unsigned char *p, size_t len,
163 			const heim_general_string *str, size_t *size)
164 {
165     size_t slen = strlen(*str);
166 
167     if (len < slen)
168 	return ASN1_OVERFLOW;
169     p -= slen;
170     memcpy (p+1, *str, slen);
171     *size = slen;
172     return 0;
173 }
174 
175 int
der_put_utf8string(unsigned char * p,size_t len,const heim_utf8_string * str,size_t * size)176 der_put_utf8string (unsigned char *p, size_t len,
177 		    const heim_utf8_string *str, size_t *size)
178 {
179     return der_put_general_string(p, len, str, size);
180 }
181 
182 int
der_put_printable_string(unsigned char * p,size_t len,const heim_printable_string * str,size_t * size)183 der_put_printable_string (unsigned char *p, size_t len,
184 			  const heim_printable_string *str, size_t *size)
185 {
186     return der_put_octet_string(p, len, str, size);
187 }
188 
189 int
der_put_ia5_string(unsigned char * p,size_t len,const heim_ia5_string * str,size_t * size)190 der_put_ia5_string (unsigned char *p, size_t len,
191 		    const heim_ia5_string *str, size_t *size)
192 {
193     return der_put_octet_string(p, len, str, size);
194 }
195 
196 int
der_put_bmp_string(unsigned char * p,size_t len,const heim_bmp_string * data,size_t * size)197 der_put_bmp_string (unsigned char *p, size_t len,
198 		    const heim_bmp_string *data, size_t *size)
199 {
200     size_t i;
201     if (len / 2 < data->length)
202 	return ASN1_OVERFLOW;
203     p -= data->length * 2;
204     for (i = 0; i < data->length; i++) {
205 	p[1] = (data->data[i] >> 8) & 0xff;
206 	p[2] = data->data[i] & 0xff;
207 	p += 2;
208     }
209     if (size) *size = data->length * 2;
210     return 0;
211 }
212 
213 int
der_put_universal_string(unsigned char * p,size_t len,const heim_universal_string * data,size_t * size)214 der_put_universal_string (unsigned char *p, size_t len,
215 			  const heim_universal_string *data, size_t *size)
216 {
217     size_t i;
218     if (len / 4 < data->length)
219 	return ASN1_OVERFLOW;
220     p -= data->length * 4;
221     for (i = 0; i < data->length; i++) {
222 	p[1] = (data->data[i] >> 24) & 0xff;
223 	p[2] = (data->data[i] >> 16) & 0xff;
224 	p[3] = (data->data[i] >> 8) & 0xff;
225 	p[4] = data->data[i] & 0xff;
226 	p += 4;
227     }
228     if (size) *size = data->length * 4;
229     return 0;
230 }
231 
232 int
der_put_visible_string(unsigned char * p,size_t len,const heim_visible_string * str,size_t * size)233 der_put_visible_string (unsigned char *p, size_t len,
234 			 const heim_visible_string *str, size_t *size)
235 {
236     return der_put_general_string(p, len, str, size);
237 }
238 
239 int
der_put_octet_string(unsigned char * p,size_t len,const heim_octet_string * data,size_t * size)240 der_put_octet_string (unsigned char *p, size_t len,
241 		      const heim_octet_string *data, size_t *size)
242 {
243     if (len < data->length)
244 	return ASN1_OVERFLOW;
245     p -= data->length;
246     memcpy (p+1, data->data, data->length);
247     *size = data->length;
248     return 0;
249 }
250 
251 int
der_put_heim_integer(unsigned char * p,size_t len,const heim_integer * data,size_t * size)252 der_put_heim_integer (unsigned char *p, size_t len,
253 		     const heim_integer *data, size_t *size)
254 {
255     unsigned char *buf = data->data;
256     int hibitset = 0;
257 
258     if (data->length == 0) {
259 	if (len < 1)
260 	    return ASN1_OVERFLOW;
261 	*p-- = 0;
262 	if (size)
263 	    *size = 1;
264 	return 0;
265     }
266     if (len < data->length)
267 	return ASN1_OVERFLOW;
268 
269     len -= data->length;
270 
271     if (data->negative) {
272 	int i, carry;
273 	for (i = data->length - 1, carry = 1; i >= 0; i--) {
274 	    *p = buf[i] ^ 0xff;
275 	    if (carry)
276 		carry = !++*p;
277 	    p--;
278 	}
279 	if (p[1] < 128) {
280 	    if (len < 1)
281 		return ASN1_OVERFLOW;
282 	    *p-- = 0xff;
283 	    len--;
284 	    hibitset = 1;
285 	}
286     } else {
287 	p -= data->length;
288 	memcpy(p + 1, buf, data->length);
289 
290 	if (p[1] >= 128) {
291 	    if (len < 1)
292 		return ASN1_OVERFLOW;
293 	    p[0] = 0;
294 	    len--;
295 	    hibitset = 1;
296 	}
297     }
298     if (size)
299 	*size = data->length + hibitset;
300     return 0;
301 }
302 
303 int
der_put_generalized_time(unsigned char * p,size_t len,const time_t * data,size_t * size)304 der_put_generalized_time (unsigned char *p, size_t len,
305 			  const time_t *data, size_t *size)
306 {
307     heim_octet_string k;
308     size_t l;
309     int e;
310 
311     e = _heim_time2generalizedtime (*data, &k, 1);
312     if (e)
313 	return e;
314     e = der_put_octet_string(p, len, &k, &l);
315     free(k.data);
316     if(e)
317 	return e;
318     if(size)
319 	*size = l;
320     return 0;
321 }
322 
323 int
der_put_utctime(unsigned char * p,size_t len,const time_t * data,size_t * size)324 der_put_utctime (unsigned char *p, size_t len,
325 		 const time_t *data, size_t *size)
326 {
327     heim_octet_string k;
328     size_t l;
329     int e;
330 
331     e = _heim_time2generalizedtime (*data, &k, 0);
332     if (e)
333 	return e;
334     e = der_put_octet_string(p, len, &k, &l);
335     free(k.data);
336     if(e)
337 	return e;
338     if(size)
339 	*size = l;
340     return 0;
341 }
342 
343 int
der_put_oid(unsigned char * p,size_t len,const heim_oid * data,size_t * size)344 der_put_oid (unsigned char *p, size_t len,
345 	     const heim_oid *data, size_t *size)
346 {
347     unsigned char *base = p;
348     int n;
349 
350     for (n = data->length - 1; n >= 2; --n) {
351 	unsigned u = data->components[n];
352 
353 	if (len < 1)
354 	    return ASN1_OVERFLOW;
355 	*p-- = u % 128;
356 	u /= 128;
357 	--len;
358 	while (u > 0) {
359 	    if (len < 1)
360 		return ASN1_OVERFLOW;
361 	    *p-- = 128 + u % 128;
362 	    u /= 128;
363 	    --len;
364 	}
365     }
366     if (len < 1)
367 	return ASN1_OVERFLOW;
368     *p-- = 40 * data->components[0] + data->components[1];
369     *size = base - p;
370     return 0;
371 }
372 
373 int
der_put_tag(unsigned char * p,size_t len,Der_class class,Der_type type,unsigned int tag,size_t * size)374 der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
375 	     unsigned int tag, size_t *size)
376 {
377     if (tag <= 30) {
378 	if (len < 1)
379 	    return ASN1_OVERFLOW;
380 	*p = MAKE_TAG(class, type, tag);
381 	*size = 1;
382     } else {
383 	size_t ret = 0;
384 	unsigned int continuation = 0;
385 
386 	do {
387 	    if (len < 1)
388 		return ASN1_OVERFLOW;
389 	    *p-- = tag % 128 | continuation;
390 	    len--;
391 	    ret++;
392 	    tag /= 128;
393 	    continuation = 0x80;
394 	} while(tag > 0);
395 	if (len < 1)
396 	    return ASN1_OVERFLOW;
397 	*p-- = MAKE_TAG(class, type, 0x1f);
398 	ret++;
399 	*size = ret;
400     }
401     return 0;
402 }
403 
404 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)405 der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val,
406 			Der_class class, Der_type type,
407 			unsigned int tag, size_t *size)
408 {
409     size_t ret = 0;
410     size_t l;
411     int e;
412 
413     e = der_put_length (p, len, len_val, &l);
414     if(e)
415 	return e;
416     p -= l;
417     len -= l;
418     ret += l;
419     e = der_put_tag (p, len, class, type, tag, &l);
420     if(e)
421 	return e;
422 
423     ret += l;
424     *size = ret;
425     return 0;
426 }
427 
428 int
_heim_time2generalizedtime(time_t t,heim_octet_string * s,int gtimep)429 _heim_time2generalizedtime (time_t t, heim_octet_string *s, int gtimep)
430 {
431      struct tm tm;
432      const size_t len = gtimep ? 15 : 13;
433 
434      s->data = malloc(len + 1);
435      if (s->data == NULL)
436 	 return ENOMEM;
437      s->length = len;
438      if (_der_gmtime(t, &tm) == NULL)
439 	 return ASN1_BAD_TIMEFORMAT;
440      if (gtimep)
441 	 snprintf (s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ",
442 		   tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
443 		   tm.tm_hour, tm.tm_min, tm.tm_sec);
444      else
445 	 snprintf (s->data, len + 1, "%02d%02d%02d%02d%02d%02dZ",
446 		   tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday,
447 		   tm.tm_hour, tm.tm_min, tm.tm_sec);
448 
449      return 0;
450 }
451 
452 int
der_put_bit_string(unsigned char * p,size_t len,const heim_bit_string * data,size_t * size)453 der_put_bit_string (unsigned char *p, size_t len,
454 		    const heim_bit_string *data, size_t *size)
455 {
456     size_t data_size = (data->length + 7) / 8;
457     if (len < data_size + 1)
458 	return ASN1_OVERFLOW;
459     p -= data_size + 1;
460 
461     memcpy (p+2, data->data, data_size);
462     if (data->length && (data->length % 8) != 0)
463 	p[1] = 8 - (data->length % 8);
464     else
465 	p[1] = 0;
466     *size = data_size + 1;
467     return 0;
468 }
469 
470 int
_heim_der_set_sort(const void * a1,const void * a2)471 _heim_der_set_sort(const void *a1, const void *a2)
472 {
473     const struct heim_octet_string *s1 = a1, *s2 = a2;
474     int ret;
475 
476     ret = memcmp(s1->data, s2->data,
477 		 s1->length < s2->length ? s1->length : s2->length);
478     if(ret)
479 	return ret;
480     return s1->length - s2->length;
481 }
482