xref: /freebsd/crypto/heimdal/lib/asn1/der_put.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
1 /*
2  * Copyright (c) 1997 - 2001 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 
36 RCSID("$Id: der_put.c,v 1.24 2001/01/29 08:31:27 assar Exp $");
37 
38 /*
39  * All encoding functions take a pointer `p' to first position in
40  * which to write, from the right, `len' which means the maximum
41  * number of characters we are able to write and return an int
42  * indicating how many actually got written, or <0 in case of errors.
43  */
44 
45 static int
46 der_put_unsigned (unsigned char *p, size_t len, unsigned val, size_t *size)
47 {
48     unsigned char *base = p;
49 
50     if (val) {
51 	while (len > 0 && val) {
52 	    *p-- = val % 256;
53 	    val /= 256;
54 	    --len;
55 	}
56 	if (val != 0)
57 	    return ASN1_OVERFLOW;
58 	else {
59 	    *size = base - p;
60 	    return 0;
61 	}
62     } else if (len < 1)
63 	return ASN1_OVERFLOW;
64     else {
65 	*p    = 0;
66 	*size = 1;
67 	return 0;
68     }
69 }
70 
71 int
72 der_put_int (unsigned char *p, size_t len, int val, size_t *size)
73 {
74     unsigned char *base = p;
75 
76     if(val >= 0) {
77 	do {
78 	    if(len < 1)
79 		return ASN1_OVERFLOW;
80 	    *p-- = val % 256;
81 	    len--;
82 	    val /= 256;
83 	} while(val);
84 	if(p[1] >= 128) {
85 	    if(len < 1)
86 		return ASN1_OVERFLOW;
87 	    *p-- = 0;
88 	    len--;
89 	}
90     } else {
91 	val = ~val;
92 	do {
93 	    if(len < 1)
94 		return ASN1_OVERFLOW;
95 	    *p-- = ~(val % 256);
96 	    len--;
97 	    val /= 256;
98 	} while(val);
99 	if(p[1] < 128) {
100 	    if(len < 1)
101 		return ASN1_OVERFLOW;
102 	    *p-- = 0xff;
103 	    len--;
104 	}
105     }
106     *size = base - p;
107     return 0;
108 }
109 
110 
111 int
112 der_put_length (unsigned char *p, size_t len, size_t val, size_t *size)
113 {
114     if (val < 128) {
115 	if (len < 1)
116 	    return ASN1_OVERFLOW;
117 	else {
118 	    *p = val;
119 	    *size = 1;
120 	    return 0;
121 	}
122     } else {
123 	size_t l;
124 	int e;
125 
126 	e = der_put_unsigned (p, len - 1, val, &l);
127 	if (e)
128 	    return e;
129 	p -= l;
130 	*p = 0x80 | l;
131 	*size = l + 1;
132 	return 0;
133     }
134 }
135 
136 int
137 der_put_general_string (unsigned char *p, size_t len,
138 			const general_string *str, size_t *size)
139 {
140     size_t slen = strlen(*str);
141 
142     if (len < slen)
143 	return ASN1_OVERFLOW;
144     p -= slen;
145     len -= slen;
146     memcpy (p+1, *str, slen);
147     *size = slen;
148     return 0;
149 }
150 
151 int
152 der_put_octet_string (unsigned char *p, size_t len,
153 		      const octet_string *data, size_t *size)
154 {
155     if (len < data->length)
156 	return ASN1_OVERFLOW;
157     p -= data->length;
158     len -= data->length;
159     memcpy (p+1, data->data, data->length);
160     *size = data->length;
161     return 0;
162 }
163 
164 int
165 der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
166 	     int tag, size_t *size)
167 {
168     if (len < 1)
169 	return ASN1_OVERFLOW;
170     *p = (class << 6) | (type << 5) | tag; /* XXX */
171     *size = 1;
172     return 0;
173 }
174 
175 int
176 der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val,
177 			Der_class class, Der_type type, int tag, size_t *size)
178 {
179     size_t ret = 0;
180     size_t l;
181     int e;
182 
183     e = der_put_length (p, len, len_val, &l);
184     if(e)
185 	return e;
186     p -= l;
187     len -= l;
188     ret += l;
189     e = der_put_tag (p, len, class, type, tag, &l);
190     if(e)
191 	return e;
192     p -= l;
193     len -= l;
194     ret += l;
195     *size = ret;
196     return 0;
197 }
198 
199 int
200 encode_integer (unsigned char *p, size_t len, const int *data, size_t *size)
201 {
202     int num = *data;
203     size_t ret = 0;
204     size_t l;
205     int e;
206 
207     e = der_put_int (p, len, num, &l);
208     if(e)
209 	return e;
210     p -= l;
211     len -= l;
212     ret += l;
213     e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_Integer, &l);
214     if (e)
215 	return e;
216     p -= l;
217     len -= l;
218     ret += l;
219     *size = ret;
220     return 0;
221 }
222 
223 int
224 encode_unsigned (unsigned char *p, size_t len, const unsigned *data,
225 		 size_t *size)
226 {
227     unsigned num = *data;
228     size_t ret = 0;
229     size_t l;
230     int e;
231 
232     e = der_put_unsigned (p, len, num, &l);
233     if(e)
234 	return e;
235     p -= l;
236     len -= l;
237     ret += l;
238     e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_Integer, &l);
239     if (e)
240 	return e;
241     p -= l;
242     len -= l;
243     ret += l;
244     *size = ret;
245     return 0;
246 }
247 
248 int
249 encode_general_string (unsigned char *p, size_t len,
250 		       const general_string *data, size_t *size)
251 {
252     size_t ret = 0;
253     size_t l;
254     int e;
255 
256     e = der_put_general_string (p, len, data, &l);
257     if (e)
258 	return e;
259     p -= l;
260     len -= l;
261     ret += l;
262     e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_GeneralString, &l);
263     if (e)
264 	return e;
265     p -= l;
266     len -= l;
267     ret += l;
268     *size = ret;
269     return 0;
270 }
271 
272 int
273 encode_octet_string (unsigned char *p, size_t len,
274 		     const octet_string *k, size_t *size)
275 {
276     size_t ret = 0;
277     size_t l;
278     int e;
279 
280     e = der_put_octet_string (p, len, k, &l);
281     if (e)
282 	return e;
283     p -= l;
284     len -= l;
285     ret += l;
286     e = der_put_length_and_tag (p, len, l, UNIV, PRIM, UT_OctetString, &l);
287     if (e)
288 	return e;
289     p -= l;
290     len -= l;
291     ret += l;
292     *size = ret;
293     return 0;
294 }
295 
296 int
297 time2generalizedtime (time_t t, octet_string *s)
298 {
299      struct tm *tm;
300 
301      s->data = malloc(16);
302      if (s->data == NULL)
303 	 return ENOMEM;
304      s->length = 15;
305      tm = gmtime (&t);
306      sprintf (s->data, "%04d%02d%02d%02d%02d%02dZ", tm->tm_year + 1900,
307 	      tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
308 	      tm->tm_sec);
309      return 0;
310 }
311 
312 int
313 encode_generalized_time (unsigned char *p, size_t len,
314 			 const time_t *t, size_t *size)
315 {
316     size_t ret = 0;
317     size_t l;
318     octet_string k;
319     int e;
320 
321     e = time2generalizedtime (*t, &k);
322     if (e)
323 	return e;
324     e = der_put_octet_string (p, len, &k, &l);
325     free (k.data);
326     if (e)
327 	return e;
328     p -= l;
329     len -= l;
330     ret += l;
331     e = der_put_length_and_tag (p, len, k.length, UNIV, PRIM,
332 				UT_GeneralizedTime, &l);
333     if (e)
334 	return e;
335     p -= l;
336     len -= l;
337     ret += l;
338     *size = ret;
339     return 0;
340 }
341