xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * src/lib/krb5/asn.1/asn1_encode.c
9  *
10  * Copyright 1994 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  */
32 
33 /* ASN.1 primitive encoders */
34 
35 #include "asn1_encode.h"
36 #include "asn1_make.h"
37 
38 static asn1_error_code asn1_encode_integer_internal(asn1buf *buf,  long val,
39 						    unsigned int *retlen)
40 {
41   asn1_error_code retval;
42   unsigned int length = 0;
43   long valcopy;
44   int digit;
45 
46   valcopy = val;
47   do {
48     digit = (int) (valcopy&0xFF);
49     retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
50     if(retval) return retval;
51     length++;
52     valcopy = valcopy >> 8;
53   } while (valcopy != 0 && valcopy != ~0);
54 
55   if((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
56     retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
57     if(retval) return retval;
58     length++;
59   }else if((val < 0) && ((digit&0x80) != 0x80)){
60     retval = asn1buf_insert_octet(buf,0xFF);
61     if(retval) return retval;
62     length++;
63   }
64 
65 
66   *retlen = length;
67   return 0;
68 }
69 
70 asn1_error_code asn1_encode_integer(asn1buf * buf,  long val,
71  unsigned int *retlen)
72 {
73   asn1_error_code retval;
74   unsigned int length = 0;
75   unsigned  int partlen;
76   retval = asn1_encode_integer_internal(buf, val, &partlen);
77   if (retval) return retval;
78 
79   length = partlen;
80     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
81   if(retval) return retval;
82   length += partlen;
83 
84   *retlen = length;
85   return 0;
86 }
87 
88 asn1_error_code
89 asn1_encode_enumerated(asn1buf * buf, const long val,
90 		       unsigned int *retlen)
91 {
92   asn1_error_code retval;
93   unsigned int length = 0;
94   unsigned  int partlen;
95   retval = asn1_encode_integer_internal(buf, val, &partlen);
96   if (retval) return retval;
97 
98   length = partlen;
99     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen);
100   if(retval) return retval;
101   length += partlen;
102 
103   *retlen = length;
104   return 0;
105 }
106 
107 asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, unsigned long val,
108 					     unsigned int *retlen)
109 {
110   asn1_error_code retval;
111   unsigned int length = 0;
112   unsigned int partlen;
113   unsigned long valcopy;
114   int digit;
115 
116   valcopy = val;
117   do {
118     digit = (int) (valcopy&0xFF);
119     retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
120     if(retval) return retval;
121     length++;
122     valcopy = valcopy >> 8;
123   } while (valcopy != 0 && valcopy != ~0);
124 
125   if(digit&0x80) {		          /* make sure the high bit is */
126     retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
127     if(retval) return retval;
128     length++;
129   }
130 
131   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
132   if(retval) return retval;
133   length += partlen;
134 
135   *retlen = length;
136   return 0;
137 }
138 
139 asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
140 				const asn1_octet *val,
141 				unsigned int *retlen)
142 {
143   asn1_error_code retval;
144   unsigned int length;
145 
146   retval = asn1buf_insert_octetstring(buf, len, val);
147   if (retval) return retval;
148   retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_OBJECTIDENTIFIER,
149 			 len, &length);
150   if (retval) return retval;
151 
152   *retlen = len + length;
153   return 0;
154 }
155 
156 asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
157 					const asn1_octet *val,
158 					unsigned int *retlen)
159 {
160   asn1_error_code retval;
161   unsigned int length;
162 
163   retval = asn1buf_insert_octetstring(buf,len,val);
164   if(retval) return retval;
165   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
166   if(retval) return retval;
167 
168   *retlen = len + length;
169   return 0;
170 }
171 
172 asn1_error_code asn1_encode_charstring(asn1buf *buf, unsigned int len,
173 				       const char *val, unsigned int *retlen)
174 {
175   asn1_error_code retval;
176   unsigned int length;
177 
178   retval = asn1buf_insert_charstring(buf,len,val);
179   if(retval) return retval;
180   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_OCTETSTRING,len,&length);
181   if(retval) return retval;
182 
183   *retlen = len + length;
184   return 0;
185 }
186 
187 asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen)
188 {
189   asn1_error_code retval;
190 
191   retval = asn1buf_insert_octet(buf,0x00);
192   if(retval) return retval;
193   retval = asn1buf_insert_octet(buf,0x05);
194   if(retval) return retval;
195 
196   *retlen = 2;
197   return 0;
198 }
199 
200 asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
201 					    const char *val, int *retlen)
202 {
203   asn1_error_code retval;
204   unsigned int length;
205 
206   retval = asn1buf_insert_charstring(buf,len,val);
207   if(retval) return retval;
208   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_PRINTABLESTRING,len,			 &length);
209   if(retval) return retval;
210 
211   *retlen = len + length;
212   return 0;
213 }
214 
215 asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
216 				      const char *val, int *retlen)
217 {
218   asn1_error_code retval;
219   unsigned int length;
220 
221   retval = asn1buf_insert_charstring(buf,len,val);
222   if(retval) return retval;
223   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_IA5STRING,len,			 &length);
224   if(retval) return retval;
225 
226   *retlen = len + length;
227   return 0;
228 }
229 
230 asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
231 					unsigned int *retlen)
232 {
233   asn1_error_code retval;
234   struct tm *gtime, gtimebuf;
235   char s[16], *sp;
236   unsigned int length, sum=0;
237   time_t gmt_time = val;
238 
239   /*
240    * Time encoding: YYYYMMDDhhmmssZ
241    */
242   if (gmt_time == 0) {
243       sp = "19700101000000Z";
244   } else {
245 
246       /*
247        * Sanity check this just to be paranoid, as gmtime can return NULL,
248        * and some bogus implementations might overrun on the sprintf.
249        */
250 #ifdef HAVE_GMTIME_R
251 # ifdef GMTIME_R_RETURNS_INT
252       if (gmtime_r(&gmt_time, &gtimebuf) != 0)
253 	  return ASN1_BAD_GMTIME;
254 # else
255       if (gmtime_r(&gmt_time, &gtimebuf) == NULL)
256 	  return ASN1_BAD_GMTIME;
257 # endif
258 #else
259       gtime = gmtime(&gmt_time);
260       if (gtime == NULL)
261 	  return ASN1_BAD_GMTIME;
262       memcpy(&gtimebuf, gtime, sizeof(gtimebuf));
263 #endif
264       gtime = &gtimebuf;
265 
266       if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
267 	  gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
268 	  gtime->tm_min > 59 || gtime->tm_sec > 59)
269 	  return ASN1_BAD_GMTIME;
270       sprintf(s, "%04d%02d%02d%02d%02d%02dZ",
271 	      1900+gtime->tm_year, gtime->tm_mon+1, gtime->tm_mday,
272 	      gtime->tm_hour, gtime->tm_min, gtime->tm_sec);
273       sp = s;
274   }
275 
276   retval = asn1buf_insert_charstring(buf,15,sp);
277   if(retval) return retval;
278   sum = 15;
279 
280   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALTIME,sum,&length);
281   if(retval) return retval;
282   sum += length;
283 
284   *retlen = sum;
285   return 0;
286 }
287 
288 asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len,
289 					  const char *val,
290 					  unsigned int *retlen)
291 {
292   asn1_error_code retval;
293   unsigned int length;
294 
295   retval = asn1buf_insert_charstring(buf,len,val);
296   if(retval) return retval;
297   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_GENERALSTRING,len,
298 			 &length);
299   if(retval) return retval;
300 
301   *retlen = len + length;
302   return 0;
303 }
304