1 /*
2  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 /*
8  * src/lib/krb5/asn.1/asn1_k_decode.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 #include "asn1_k_decode.h"
34 #include "asn1_decode.h"
35 #include "asn1_get.h"
36 #include "asn1_misc.h"
37 
38 /* Declare useful decoder variables. */
39 #define setup()					\
40   asn1_error_code retval;			\
41   asn1_class asn1class;				\
42   asn1_construction construction;		\
43   asn1_tagnum tagnum;				\
44   unsigned int length, taglen
45 
46 #define unused_var(x) if (0) { x = 0; x = x - x; }
47 
48 /* This is used for prefetch of next tag in sequence. */
49 #define next_tag()								\
50 { taginfo t2;									\
51   retval = asn1_get_tag_2(&subbuf, &t2);					\
52   if (retval) return retval;							\
53   /* Copy out to match previous functionality, until better integrated.  */	\
54   asn1class = t2.asn1class;							\
55   construction = t2.construction;						\
56   tagnum = t2.tagnum;								\
57   taglen = t2.length;								\
58   indef = t2.indef;								\
59 }
60 
61 /* Force check for EOC tag. */
62 #define get_eoc()									\
63     {											\
64 	taginfo t3;									\
65 	retval = asn1_get_tag_2(&subbuf, &t3);						\
66 	if(retval) return retval;							\
67         if (t3.asn1class != UNIVERSAL || t3.tagnum || t3.indef)				\
68 	    return ASN1_MISSING_EOC;							\
69         /* Copy out to match previous functionality, until better integrated.  */	\
70 	asn1class = t3.asn1class;							\
71 	construction = t3.construction;							\
72 	tagnum = t3.tagnum;								\
73 	taglen = t3.length;								\
74 	indef = t3.indef;								\
75     }
76 
77 #define alloc_field(var, type)			\
78   var = (type*)calloc(1, sizeof(type));		\
79   if ((var) == NULL) return ENOMEM
80 
81 /* Fetch an expected APPLICATION class tag and verify. */
82 #define apptag(tagexpect)								\
83   {											\
84       taginfo t1;									\
85       retval = asn1_get_tag_2(buf, &t1);						\
86       if (retval) return retval;						   	\
87       if (t1.asn1class != APPLICATION || t1.construction != CONSTRUCTED ||	   	\
88 	  t1.tagnum != (tagexpect)) return ASN1_BAD_ID;					\
89       /* Copy out to match previous functionality, until better integrated.  */		\
90       asn1class = t1.asn1class;								\
91       construction = t1.construction;							\
92       tagnum = t1.tagnum;								\
93       applen = t1.length;								\
94   }
95 
96 /**** normal fields ****/
97 
98 /*
99  * get_field_body
100  *
101  * Get bare field.  This also prefetches the next tag.  The call to
102  * get_eoc() assumes that any values fetched by this macro are
103  * enclosed in a context-specific tag.
104  */
105 #define get_field_body(var, decoder)		\
106   retval = decoder(&subbuf, &(var));		\
107   if (retval) return retval;			\
108   if (!taglen && indef) { get_eoc(); }		\
109   next_tag()
110 
111 /*
112  * get_field
113  *
114  * Get field having an expected context specific tag.  This assumes
115  * that context-specific tags are monotonically increasing in its
116  * verification of tag numbers.
117  */
118 #define get_field(var, tagexpect, decoder)				\
119   if (tagnum > (tagexpect)) return ASN1_MISSING_FIELD;			\
120   if (tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;		\
121   if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
122       && (tagnum || taglen || asn1class != UNIVERSAL))			\
123     return ASN1_BAD_ID;							\
124   get_field_body(var,decoder)
125 
126 /*
127  * opt_field
128  *
129  * Get an optional field with an expected context specific tag.
130  * Assumes that OPTVAL will have the default value, thus failing to
131  * distinguish between absent optional values and present optional
132  * values that happen to have the value of OPTVAL.
133  */
134 #define opt_field(var, tagexpect, decoder, optvalue)			\
135   if (asn1buf_remains(&subbuf, seqindef)) {				\
136     if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
137 	&& (tagnum || taglen || asn1class != UNIVERSAL))		\
138       return ASN1_BAD_ID;						\
139     if (tagnum == (tagexpect)) {					\
140       get_field_body(var, decoder);					\
141     } else var = optvalue;						\
142   }
143 
144 /**** fields w/ length ****/
145 
146 /* similar to get_field_body */
147 #define get_lenfield_body(len, var, decoder)	\
148   retval = decoder(&subbuf, &(len), &(var));	\
149   if (retval) return retval;			\
150   if (!taglen && indef) { get_eoc(); }		\
151   next_tag()
152 
153 /* similar to get_field_body */
154 #define get_lenfield(len, var, tagexpect, decoder)			\
155   if (tagnum > (tagexpect)) return ASN1_MISSING_FIELD;			\
156   if (tagnum < (tagexpect)) return ASN1_MISPLACED_FIELD;		\
157   if ((asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)	\
158       && (tagnum || taglen || asn1class != UNIVERSAL))			\
159     return ASN1_BAD_ID;							\
160   get_lenfield_body(len, var, decoder)
161 
162 /* similar to opt_field */
163 #define opt_lenfield(len, var, tagexpect, decoder)	\
164   if (tagnum == (tagexpect)) {				\
165     get_lenfield_body(len, var, decoder);		\
166   } else { len = 0; var = 0; }
167 
168 /*
169  * begin_structure
170  *
171  * Declares some variables for decoding SEQUENCE types.  This is meant
172  * to be called in an inner block that ends with a call to
173  * end_structure().
174  */
175 #define begin_structure()					\
176   asn1buf subbuf;						\
177   int seqindef;							\
178   int indef;							\
179   retval = asn1_get_sequence(buf, &length, &seqindef);		\
180   if (retval) return retval;					\
181   retval = asn1buf_imbed(&subbuf, buf, length, seqindef);	\
182   if (retval) return retval;					\
183   next_tag()
184 
185 /* skip trailing garbage */
186 #define end_structure()						\
187   retval = asn1buf_sync(buf, &subbuf, asn1class, tagnum,	\
188 			length, indef, seqindef);		\
189   if (retval) return retval
190 
191 /*
192  * sequence_of
193  *
194  * Declares some variables for decoding SEQUENCE OF types.  This is
195  * meant to be called in an inner block that ends with a call to
196  * end_sequence_of().
197  */
198 #define sequence_of(buf)			\
199   unsigned int length, taglen;			\
200   asn1_class asn1class;				\
201   asn1_construction construction;		\
202   asn1_tagnum tagnum;				\
203   int indef;					\
204   sequence_of_common(buf)
205 
206 /*
207  * sequence_of_no_tagvars
208  *
209  * This is meant for use inside decoder functions that have an outer
210  * sequence structure and thus declares variables of different names
211  * than does sequence_of() to avoid shadowing.
212  */
213 #define sequence_of_no_tagvars(buf)		\
214   asn1_class eseqclass;				\
215   asn1_construction eseqconstr;			\
216   asn1_tagnum eseqnum;				\
217   unsigned int eseqlen;				\
218   int eseqindef;				\
219   sequence_of_common(buf)
220 
221 /*
222  * sequence_of_common
223  *
224  * Fetches the outer SEQUENCE OF length info into {length,seqofindef}
225  * and imbeds an inner buffer seqbuf.  Unlike begin_structure(), it
226  * does not prefetch the next tag.
227  */
228 #define sequence_of_common(buf)					\
229   int size = 0;							\
230   asn1buf seqbuf;						\
231   int seqofindef;						\
232   retval = asn1_get_sequence(buf, &length, &seqofindef);	\
233   if (retval) return retval;					\
234   retval = asn1buf_imbed(&seqbuf, buf, length, seqofindef);	\
235   if (retval) return retval
236 
237 /*
238  * end_sequence_of
239  *
240  * Attempts to fetch an EOC tag, if any, and to sync over trailing
241  * garbage, if any.
242  */
243 #define end_sequence_of(buf)							\
244   {										\
245       taginfo t4;								\
246       retval = asn1_get_tag_2(&seqbuf, &t4);					\
247       if (retval) return retval;						\
248       /* Copy out to match previous functionality, until better integrated.  */	\
249       asn1class = t4.asn1class;							\
250       construction = t4.construction;						\
251       tagnum = t4.tagnum;							\
252       taglen = t4.length;							\
253       indef = t4.indef;								\
254   }										\
255   retval = asn1buf_sync(buf, &seqbuf, asn1class, tagnum,			\
256 			length, indef, seqofindef);				\
257   if (retval) return retval;
258 
259 /*
260  * end_sequence_of_no_tagvars
261  *
262  * Like end_sequence_of(), but uses the different (non-shadowing)
263  * variable names.
264  */
265 #define end_sequence_of_no_tagvars(buf)						\
266   {										\
267       taginfo t5;								\
268       retval = asn1_get_tag_2(&seqbuf, &t5);					\
269       if (retval) return retval;						\
270       /* Copy out to match previous functionality, until better integrated.  */	\
271       eseqclass = t5.asn1class;							\
272       eseqconstr = t5.construction;						\
273       eseqnum = t5.tagnum;							\
274       eseqlen = t5.length;							\
275       eseqindef = t5.indef;							\
276   }										\
277   retval = asn1buf_sync(buf, &seqbuf, eseqclass, eseqnum,			\
278 			eseqlen, eseqindef, seqofindef);			\
279   if (retval) return retval;
280 
281 #define cleanup()				\
282   return 0
283 
284 /* scalars */
285 asn1_error_code asn1_decode_kerberos_time(asn1buf *buf, krb5_timestamp *val)
286 {
287     time_t	t;
288     asn1_error_code retval;
289 
290     retval =  asn1_decode_generaltime(buf,&t);
291     if (retval)
292 	return retval;
293 
294     *val = t;
295     return 0;
296 }
297 
298 #define integer_convert(fname,ktype)\
299 asn1_error_code fname(asn1buf * buf, ktype * val)\
300 {\
301   asn1_error_code retval;\
302   long n;\
303   retval = asn1_decode_integer(buf,&n);\
304   if(retval) return retval;\
305   *val = (ktype)n;\
306   return 0;\
307 }
308 #define unsigned_integer_convert(fname,ktype)\
309 asn1_error_code fname(asn1buf * buf, ktype * val)\
310 {\
311   asn1_error_code retval;\
312   unsigned long n;\
313   retval = asn1_decode_unsigned_integer(buf,&n);\
314   if(retval) return retval;\
315   *val = (ktype)n;\
316   return 0;\
317 }
318 integer_convert(asn1_decode_int,int)
319 integer_convert(asn1_decode_int32,krb5_int32)
320 integer_convert(asn1_decode_kvno,krb5_kvno)
321 integer_convert(asn1_decode_enctype,krb5_enctype)
322 integer_convert(asn1_decode_cksumtype,krb5_cksumtype)
323 integer_convert(asn1_decode_octet,krb5_octet)
324 integer_convert(asn1_decode_addrtype,krb5_addrtype)
325 integer_convert(asn1_decode_authdatatype,krb5_authdatatype)
326 unsigned_integer_convert(asn1_decode_ui_2,krb5_ui_2)
327 unsigned_integer_convert(asn1_decode_ui_4,krb5_ui_4)
328 
329 asn1_error_code asn1_decode_seqnum(asn1buf *buf, krb5_ui_4 *val)
330 {
331   asn1_error_code retval;
332   unsigned long n;
333 
334   retval = asn1_decode_maybe_unsigned(buf, &n);
335   if (retval) return retval;
336   *val = (krb5_ui_4)n & 0xffffffff;
337   return 0;
338 }
339 
340 asn1_error_code asn1_decode_msgtype(asn1buf *buf, krb5_msgtype *val)
341 {
342   asn1_error_code retval;
343   unsigned long n;
344 
345   retval = asn1_decode_unsigned_integer(buf,&n);
346   if(retval) return retval;
347 
348   *val = (krb5_msgtype) n;
349   return 0;
350 }
351 
352 
353 /* structures */
354 asn1_error_code asn1_decode_realm(asn1buf *buf, krb5_principal *val)
355 {
356   return asn1_decode_generalstring(buf,
357 				   &((*val)->realm.length),
358 				   &((*val)->realm.data));
359 }
360 
361 asn1_error_code asn1_decode_principal_name(asn1buf *buf, krb5_principal *val)
362 {
363   setup();
364   { begin_structure();
365     get_field((*val)->type,0,asn1_decode_int32);
366 
367     { sequence_of_no_tagvars(&subbuf);
368       while(asn1buf_remains(&seqbuf,seqofindef) > 0){
369 	size++;
370 	if ((*val)->data == NULL)
371 	  (*val)->data = (krb5_data*)malloc(size*sizeof(krb5_data));
372 	else
373 	  (*val)->data = (krb5_data*)realloc((*val)->data,
374 					     size*sizeof(krb5_data));
375 	if((*val)->data == NULL) return ENOMEM;
376 	retval = asn1_decode_generalstring(&seqbuf,
377 					   &((*val)->data[size-1].length),
378 			   &((*val)->data[size-1].data));
379 	if(retval) return retval;
380       }
381       (*val)->length = size;
382       end_sequence_of_no_tagvars(&subbuf);
383     }
384     if (indef) {
385 	get_eoc();
386     }
387     next_tag();
388     end_structure();
389     (*val)->magic = KV5M_PRINCIPAL;
390   }
391   cleanup();
392 }
393 
394 asn1_error_code asn1_decode_checksum(asn1buf *buf, krb5_checksum *val)
395 {
396   setup();
397   { begin_structure();
398     get_field(val->checksum_type,0,asn1_decode_cksumtype);
399     get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
400     end_structure();
401     val->magic = KV5M_CHECKSUM;
402   }
403   cleanup();
404 }
405 
406 asn1_error_code asn1_decode_encryption_key(asn1buf *buf, krb5_keyblock *val)
407 {
408   setup();
409   { begin_structure();
410     get_field(val->enctype,0,asn1_decode_enctype);
411     get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
412     end_structure();
413     val->magic = KV5M_KEYBLOCK;
414   }
415   cleanup();
416 }
417 
418 asn1_error_code asn1_decode_encrypted_data(asn1buf *buf, krb5_enc_data *val)
419 {
420   setup();
421   { begin_structure();
422     get_field(val->enctype,0,asn1_decode_enctype);
423     opt_field(val->kvno,1,asn1_decode_kvno,0);
424     get_lenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_decode_charstring);
425     end_structure();
426     val->magic = KV5M_ENC_DATA;
427   }
428   cleanup();
429 }
430 
431 asn1_error_code asn1_decode_krb5_flags(asn1buf *buf, krb5_flags *val)
432 {
433   asn1_error_code retval;
434   asn1_octet unused, o;
435   taginfo t;
436   int i;
437   krb5_flags f=0;
438   unsigned int length;
439 
440   retval = asn1_get_tag_2(buf, &t);
441   if (retval) return retval;
442   if (t.asn1class != UNIVERSAL || t.construction != PRIMITIVE ||
443       t.tagnum != ASN1_BITSTRING)
444       return ASN1_BAD_ID;
445   length = t.length;
446 
447   retval = asn1buf_remove_octet(buf,&unused); /* # of padding bits */
448   if(retval) return retval;
449 
450   /* Number of unused bits must be between 0 and 7. */
451   if (unused > 7) return ASN1_BAD_FORMAT;
452   length--;
453 
454   for(i = 0; i < length; i++) {
455     retval = asn1buf_remove_octet(buf,&o);
456     if(retval) return retval;
457     /* ignore bits past number 31 */
458     if (i < 4)
459       f = (f<<8) | ((krb5_flags)o&0xFF);
460   }
461   if (length <= 4) {
462     /* Mask out unused bits, but only if necessary. */
463     f &= ~(krb5_flags)0 << unused;
464   }
465   /* left-justify */
466   if (length < 4)
467     f <<= (4 - length) * 8;
468   *val = f;
469   return 0;
470 }
471 
472 asn1_error_code asn1_decode_ticket_flags(asn1buf *buf, krb5_flags *val)
473 { return asn1_decode_krb5_flags(buf,val); }
474 
475 asn1_error_code asn1_decode_ap_options(asn1buf *buf, krb5_flags *val)
476 { return asn1_decode_krb5_flags(buf,val); }
477 
478 asn1_error_code asn1_decode_kdc_options(asn1buf *buf, krb5_flags *val)
479 { return asn1_decode_krb5_flags(buf,val); }
480 
481 asn1_error_code asn1_decode_transited_encoding(asn1buf *buf, krb5_transited *val)
482 {
483   setup();
484   { begin_structure();
485     get_field(val->tr_type,0,asn1_decode_octet);
486     get_lenfield(val->tr_contents.length,val->tr_contents.data,1,asn1_decode_charstring);
487     end_structure();
488     val->magic = KV5M_TRANSITED;
489   }
490   cleanup();
491 }
492 
493 asn1_error_code asn1_decode_enc_kdc_rep_part(asn1buf *buf, krb5_enc_kdc_rep_part *val)
494 {
495   setup();
496   { begin_structure();
497     alloc_field(val->session,krb5_keyblock);
498     get_field(*(val->session),0,asn1_decode_encryption_key);
499     get_field(val->last_req,1,asn1_decode_last_req);
500     get_field(val->nonce,2,asn1_decode_int32);
501     opt_field(val->key_exp,3,asn1_decode_kerberos_time,0);
502     get_field(val->flags,4,asn1_decode_ticket_flags);
503     get_field(val->times.authtime,5,asn1_decode_kerberos_time);
504     /* Set to authtime if missing */
505     opt_field(val->times.starttime,6,asn1_decode_kerberos_time,val->times.authtime);
506     get_field(val->times.endtime,7,asn1_decode_kerberos_time);
507     opt_field(val->times.renew_till,8,asn1_decode_kerberos_time,0);
508     alloc_field(val->server,krb5_principal_data);
509     get_field(val->server,9,asn1_decode_realm);
510     get_field(val->server,10,asn1_decode_principal_name);
511     opt_field(val->caddrs,11,asn1_decode_host_addresses,NULL);
512     end_structure();
513     val->magic = KV5M_ENC_KDC_REP_PART;
514   }
515   cleanup();
516 }
517 
518 asn1_error_code asn1_decode_ticket(asn1buf *buf, krb5_ticket *val)
519 {
520   setup();
521   unsigned int applen;
522   apptag(1);
523   { begin_structure();
524     { krb5_kvno vno;
525       get_field(vno,0,asn1_decode_kvno);
526       if(vno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
527     alloc_field(val->server,krb5_principal_data);
528     get_field(val->server,1,asn1_decode_realm);
529     get_field(val->server,2,asn1_decode_principal_name);
530     get_field(val->enc_part,3,asn1_decode_encrypted_data);
531     end_structure();
532     val->magic = KV5M_TICKET;
533   }
534   if (!applen) {
535       taginfo t;
536       retval = asn1_get_tag_2(buf, &t);
537       if (retval) return retval;
538       }
539   cleanup();
540 }
541 
542 asn1_error_code asn1_decode_kdc_req(asn1buf *buf, krb5_kdc_req *val)
543 {
544   setup();
545   { begin_structure();
546     { krb5_kvno kvno;
547       get_field(kvno,1,asn1_decode_kvno);
548       if(kvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
549     get_field(val->msg_type,2,asn1_decode_msgtype);
550     opt_field(val->padata,3,asn1_decode_sequence_of_pa_data,NULL);
551     get_field(*val,4,asn1_decode_kdc_req_body);
552     end_structure();
553     val->magic = KV5M_KDC_REQ;
554   }
555   cleanup();
556 }
557 
558 asn1_error_code asn1_decode_kdc_req_body(asn1buf *buf, krb5_kdc_req *val)
559 {
560   setup();
561   {
562     krb5_principal psave;
563     begin_structure();
564     get_field(val->kdc_options,0,asn1_decode_kdc_options);
565     if(tagnum == 1){ alloc_field(val->client,krb5_principal_data); }
566     opt_field(val->client,1,asn1_decode_principal_name,NULL);
567     alloc_field(val->server,krb5_principal_data);
568     get_field(val->server,2,asn1_decode_realm);
569     if(val->client != NULL){
570       retval = asn1_krb5_realm_copy(val->client,val->server);
571       if(retval) return retval; }
572 
573     /* If opt_field server is missing, memory reference to server is
574        lost and results in memory leak */
575     psave = val->server;
576     opt_field(val->server,3,asn1_decode_principal_name,NULL);
577     if(val->server == NULL){
578       if(psave->realm.data) {
579 	free(psave->realm.data);
580 	psave->realm.data = NULL;
581 	psave->realm.length=0;
582       }
583       free(psave);
584     }
585     opt_field(val->from,4,asn1_decode_kerberos_time,0);
586     get_field(val->till,5,asn1_decode_kerberos_time);
587     opt_field(val->rtime,6,asn1_decode_kerberos_time,0);
588     get_field(val->nonce,7,asn1_decode_int32);
589     get_lenfield(val->nktypes,val->ktype,8,asn1_decode_sequence_of_enctype);
590     opt_field(val->addresses,9,asn1_decode_host_addresses,0);
591     if(tagnum == 10){
592       get_field(val->authorization_data,10,asn1_decode_encrypted_data); }
593     else{
594       val->authorization_data.magic = KV5M_ENC_DATA;
595       val->authorization_data.enctype = 0;
596       val->authorization_data.kvno = 0;
597       val->authorization_data.ciphertext.data = NULL;
598       val->authorization_data.ciphertext.length = 0;
599     }
600     opt_field(val->second_ticket,11,asn1_decode_sequence_of_ticket,NULL);
601     end_structure();
602     val->magic = KV5M_KDC_REQ;
603   }
604   cleanup();
605 }
606 
607 asn1_error_code asn1_decode_krb_safe_body(asn1buf *buf, krb5_safe *val)
608 {
609   setup();
610   { begin_structure();
611     get_lenfield(val->user_data.length,val->user_data.data,0,asn1_decode_charstring);
612     opt_field(val->timestamp,1,asn1_decode_kerberos_time,0);
613     opt_field(val->usec,2,asn1_decode_int32,0);
614     opt_field(val->seq_number,3,asn1_decode_seqnum,0);
615     alloc_field(val->s_address,krb5_address);
616     get_field(*(val->s_address),4,asn1_decode_host_address);
617     if(tagnum == 5){
618       alloc_field(val->r_address,krb5_address);
619       get_field(*(val->r_address),5,asn1_decode_host_address);
620     } else val->r_address = NULL;
621     end_structure();
622     val->magic = KV5M_SAFE;
623   }
624   cleanup();
625 }
626 
627 asn1_error_code asn1_decode_host_address(asn1buf *buf, krb5_address *val)
628 {
629   setup();
630   { begin_structure();
631     get_field(val->addrtype,0,asn1_decode_addrtype);
632     get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
633     end_structure();
634     val->magic = KV5M_ADDRESS;
635   }
636   cleanup();
637 }
638 
639 asn1_error_code asn1_decode_kdc_rep(asn1buf *buf, krb5_kdc_rep *val)
640 {
641   setup();
642   { begin_structure();
643     { krb5_kvno pvno;
644       get_field(pvno,0,asn1_decode_kvno);
645       if(pvno != KVNO) return KRB5KDC_ERR_BAD_PVNO; }
646     get_field(val->msg_type,1,asn1_decode_msgtype);
647     opt_field(val->padata,2,asn1_decode_sequence_of_pa_data,NULL);
648     alloc_field(val->client,krb5_principal_data);
649     get_field(val->client,3,asn1_decode_realm);
650     get_field(val->client,4,asn1_decode_principal_name);
651     alloc_field(val->ticket,krb5_ticket);
652     get_field(*(val->ticket),5,asn1_decode_ticket);
653     get_field(val->enc_part,6,asn1_decode_encrypted_data);
654     end_structure();
655     val->magic = KV5M_KDC_REP;
656   }
657   cleanup();
658 }
659 
660 
661 /* arrays */
662 #define get_element(element,decoder)\
663 retval = decoder(&seqbuf,element);\
664 if(retval) return retval
665 
666 #define array_append(array,size,element,type)\
667 size++;\
668 if (*(array) == NULL)\
669      *(array) = (type**)malloc((size+1)*sizeof(type*));\
670 else\
671   *(array) = (type**)realloc(*(array),\
672 			     (size+1)*sizeof(type*));\
673 if(*(array) == NULL) return ENOMEM;\
674 (*(array))[(size)-1] = elt
675 
676 #define decode_array_body(type,decoder)\
677   asn1_error_code retval;\
678   type *elt;\
679 \
680   { sequence_of(buf);\
681     while(asn1buf_remains(&seqbuf,seqofindef) > 0){\
682       alloc_field(elt,type);\
683       get_element(elt,decoder);\
684       array_append(val,size,elt,type);\
685     }\
686     if (*val == NULL)\
687 	*val = (type **)malloc(sizeof(type*));\
688     (*val)[size] = NULL;\
689     end_sequence_of(buf);\
690   }\
691   cleanup()
692 
693 
694 asn1_error_code asn1_decode_authorization_data(asn1buf *buf, krb5_authdata ***val)
695 {
696   decode_array_body(krb5_authdata,asn1_decode_authdata_elt);
697 }
698 
699 asn1_error_code asn1_decode_authdata_elt(asn1buf *buf, krb5_authdata *val)
700 {
701   setup();
702   { begin_structure();
703     get_field(val->ad_type,0,asn1_decode_authdatatype);
704     get_lenfield(val->length,val->contents,1,asn1_decode_octetstring);
705     end_structure();
706     val->magic = KV5M_AUTHDATA;
707   }
708   cleanup();
709 }
710 
711 asn1_error_code asn1_decode_host_addresses(asn1buf *buf, krb5_address ***val)
712 {
713   decode_array_body(krb5_address,asn1_decode_host_address);
714 }
715 
716 asn1_error_code asn1_decode_sequence_of_ticket(asn1buf *buf, krb5_ticket ***val)
717 {
718   decode_array_body(krb5_ticket,asn1_decode_ticket);
719 }
720 
721 asn1_error_code asn1_decode_sequence_of_krb_cred_info(asn1buf *buf, krb5_cred_info ***val)
722 {
723   decode_array_body(krb5_cred_info,asn1_decode_krb_cred_info);
724 }
725 
726 asn1_error_code asn1_decode_krb_cred_info(asn1buf *buf, krb5_cred_info *val)
727 {
728   setup();
729   { begin_structure();
730     alloc_field(val->session,krb5_keyblock);
731     get_field(*(val->session),0,asn1_decode_encryption_key);
732     if(tagnum == 1){
733       alloc_field(val->client,krb5_principal_data);
734       opt_field(val->client,1,asn1_decode_realm,NULL);
735       opt_field(val->client,2,asn1_decode_principal_name,NULL); }
736     opt_field(val->flags,3,asn1_decode_ticket_flags,0);
737     opt_field(val->times.authtime,4,asn1_decode_kerberos_time,0);
738     opt_field(val->times.starttime,5,asn1_decode_kerberos_time,0);
739     opt_field(val->times.endtime,6,asn1_decode_kerberos_time,0);
740     opt_field(val->times.renew_till,7,asn1_decode_kerberos_time,0);
741     if(tagnum == 8){
742       alloc_field(val->server,krb5_principal_data);
743       opt_field(val->server,8,asn1_decode_realm,NULL);
744       opt_field(val->server,9,asn1_decode_principal_name,NULL); }
745     opt_field(val->caddrs,10,asn1_decode_host_addresses,NULL);
746     end_structure();
747     val->magic = KV5M_CRED_INFO;
748   }
749   cleanup();
750 }
751 
752 asn1_error_code asn1_decode_sequence_of_pa_data(asn1buf *buf, krb5_pa_data ***val)
753 {
754   decode_array_body(krb5_pa_data,asn1_decode_pa_data);
755 }
756 
757 asn1_error_code asn1_decode_pa_data(asn1buf *buf, krb5_pa_data *val)
758 {
759   setup();
760   { begin_structure();
761     get_field(val->pa_type,1,asn1_decode_int32);
762     get_lenfield(val->length,val->contents,2,asn1_decode_octetstring);
763     end_structure();
764     val->magic = KV5M_PA_DATA;
765   }
766   cleanup();
767 }
768 
769 asn1_error_code asn1_decode_last_req(asn1buf *buf, krb5_last_req_entry ***val)
770 {
771   decode_array_body(krb5_last_req_entry,asn1_decode_last_req_entry);
772 }
773 
774 asn1_error_code asn1_decode_last_req_entry(asn1buf *buf, krb5_last_req_entry *val)
775 {
776   setup();
777   { begin_structure();
778     get_field(val->lr_type,0,asn1_decode_int32);
779     get_field(val->value,1,asn1_decode_kerberos_time);
780     end_structure();
781     val->magic = KV5M_LAST_REQ_ENTRY;
782 #ifdef KRB5_GENEROUS_LR_TYPE
783     /* If we are only a single byte wide and negative - fill in the
784        other bits */
785     if((val->lr_type & 0xffffff80U) == 0x80) val->lr_type |= 0xffffff00U;
786 #endif
787   }
788   cleanup();
789 }
790 
791 asn1_error_code asn1_decode_sequence_of_enctype(asn1buf *buf, int *num, krb5_enctype **val)
792 {
793   asn1_error_code retval;
794   { sequence_of(buf);
795     while(asn1buf_remains(&seqbuf,seqofindef) > 0){
796       size++;
797       if (*val == NULL)
798         *val = (krb5_enctype*)malloc(size*sizeof(krb5_enctype));
799       else
800         *val = (krb5_enctype*)realloc(*val,size*sizeof(krb5_enctype));
801       if(*val == NULL) return ENOMEM;
802       retval = asn1_decode_enctype(&seqbuf,&((*val)[size-1]));
803       if(retval) return retval;
804     }
805     *num = size;
806     end_sequence_of(buf);
807   }
808   cleanup();
809 }
810 
811 asn1_error_code asn1_decode_sequence_of_checksum(asn1buf *buf, krb5_checksum ***val)
812 {
813   decode_array_body(krb5_checksum, asn1_decode_checksum);
814 }
815 
816 static asn1_error_code asn1_decode_etype_info2_entry(asn1buf *buf, krb5_etype_info_entry *val )
817 {
818   /*
819    * Solaris Kerberos:
820    * Use a temporary char* (tmpp) in place of val->salt when calling
821    * get_lenfield(). val->salt cannot be cast to a char* as casting will not
822    * produce an lvalue. Use the new value pointed to by tmpp as the value for
823    * val->salt.
824    */
825   char *tmpp;
826   setup();
827   { begin_structure();
828     get_field(val->etype,0,asn1_decode_enctype);
829     if (tagnum == 1) {
830       get_lenfield(val->length,tmpp,1,asn1_decode_generalstring);
831       val->salt = (krb5_octet*)tmpp;	/* SUNW14resync hack */
832     } else {
833 	    val->length = KRB5_ETYPE_NO_SALT;
834 	    val->salt = 0;
835     }
836     if ( tagnum ==2) {
837       krb5_octet *params ;
838       get_lenfield( val->s2kparams.length, params,
839 		      2, asn1_decode_octetstring);
840       val->s2kparams.data = ( char *) params;
841     } else {
842 	val->s2kparams.data = NULL;
843 	val->s2kparams.length = 0;
844     }
845     end_structure();
846     val->magic = KV5M_ETYPE_INFO_ENTRY;
847   }
848   cleanup();
849 }
850 
851 static asn1_error_code asn1_decode_etype_info2_entry_1_3(asn1buf *buf, krb5_etype_info_entry *val )
852 {
853   setup();
854   { begin_structure();
855     get_field(val->etype,0,asn1_decode_enctype);
856     if (tagnum == 1) {
857 	    get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
858     } else {
859 	    val->length = KRB5_ETYPE_NO_SALT;
860 	    val->salt = 0;
861     }
862     if ( tagnum ==2) {
863       krb5_octet *params ;
864       get_lenfield( val->s2kparams.length, params,
865 		      2, asn1_decode_octetstring);
866       val->s2kparams.data = ( char *) params;
867     } else {
868 	val->s2kparams.data = NULL;
869 	val->s2kparams.length = 0;
870     }
871     end_structure();
872     val->magic = KV5M_ETYPE_INFO_ENTRY;
873   }
874   cleanup();
875 }
876 
877 
878 static asn1_error_code asn1_decode_etype_info_entry(asn1buf *buf, krb5_etype_info_entry *val )
879 {
880   setup();
881   { begin_structure();
882     get_field(val->etype,0,asn1_decode_enctype);
883     if (tagnum == 1) {
884 	    get_lenfield(val->length,val->salt,1,asn1_decode_octetstring);
885     } else {
886 	    val->length = KRB5_ETYPE_NO_SALT;
887 	    val->salt = 0;
888     }
889     val->s2kparams.data = NULL;
890     val->s2kparams.length = 0;
891 
892     end_structure();
893     val->magic = KV5M_ETYPE_INFO_ENTRY;
894   }
895   cleanup();
896 }
897 
898 asn1_error_code asn1_decode_etype_info(asn1buf *buf, krb5_etype_info_entry ***val )
899 {
900   decode_array_body(krb5_etype_info_entry,asn1_decode_etype_info_entry);
901 }
902 
903 asn1_error_code asn1_decode_etype_info2(asn1buf *buf, krb5_etype_info_entry ***val ,
904 					krb5_boolean v1_3_behavior)
905 {
906     if (v1_3_behavior) {
907 	decode_array_body(krb5_etype_info_entry,
908 			  asn1_decode_etype_info2_entry_1_3);
909     } else {
910 	decode_array_body(krb5_etype_info_entry,
911 			  asn1_decode_etype_info2_entry);
912     }
913 }
914 
915 asn1_error_code asn1_decode_passwdsequence(asn1buf *buf, passwd_phrase_element *val)
916 {
917   setup();
918   { begin_structure();
919     alloc_field(val->passwd,krb5_data);
920     get_lenfield(val->passwd->length,val->passwd->data,
921 		 0,asn1_decode_charstring);
922     val->passwd->magic = KV5M_DATA;
923     alloc_field(val->phrase,krb5_data);
924     get_lenfield(val->phrase->length,val->phrase->data,
925 		 1,asn1_decode_charstring);
926     val->phrase->magic = KV5M_DATA;
927     end_structure();
928     val->magic = KV5M_PASSWD_PHRASE_ELEMENT;
929   }
930   cleanup();
931 }
932 
933 asn1_error_code asn1_decode_sequence_of_passwdsequence(asn1buf *buf, passwd_phrase_element ***val)
934 {
935   decode_array_body(passwd_phrase_element,asn1_decode_passwdsequence);
936 }
937 
938 asn1_error_code asn1_decode_sam_flags(asn1buf *buf, krb5_flags *val)
939 { return asn1_decode_krb5_flags(buf,val); }
940 
941 #define opt_string(val,n,fn) opt_lenfield((val).length,(val).data,n,fn)
942 #define opt_cksum(var,tagexpect,decoder)\
943 if(tagnum == (tagexpect)){\
944   get_field_body(var,decoder); }\
945 else var.length = 0
946 
947 asn1_error_code asn1_decode_sam_challenge(asn1buf *buf, krb5_sam_challenge *val)
948 {
949   setup();
950   { begin_structure();
951     get_field(val->sam_type,0,asn1_decode_int32);
952     get_field(val->sam_flags,1,asn1_decode_sam_flags);
953     opt_string(val->sam_type_name,2,asn1_decode_charstring);
954     opt_string(val->sam_track_id,3,asn1_decode_charstring);
955     opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
956     opt_string(val->sam_challenge,5,asn1_decode_charstring);
957     opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
958     opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
959     opt_field(val->sam_nonce,8,asn1_decode_int32,0);
960     opt_cksum(val->sam_cksum,9,asn1_decode_checksum);
961     end_structure();
962     val->magic = KV5M_SAM_CHALLENGE;
963   }
964   cleanup();
965 }
966 asn1_error_code asn1_decode_sam_challenge_2(asn1buf *buf, krb5_sam_challenge_2 *val)
967 {
968   setup();
969   { char *save, *end;
970     size_t alloclen;
971     begin_structure();
972     if (tagnum != 0) return ASN1_MISSING_FIELD;
973     if (asn1class != CONTEXT_SPECIFIC || construction != CONSTRUCTED)
974       return ASN1_BAD_ID;
975     save = subbuf.next;
976     { sequence_of_no_tagvars(&subbuf);
977       unused_var(size);
978       end_sequence_of_no_tagvars(&subbuf);
979     }
980     end = subbuf.next;
981     alloclen = end - save;
982     if ((val->sam_challenge_2_body.data = (char *) malloc(alloclen)) == NULL)
983       return ENOMEM;
984     val->sam_challenge_2_body.length = alloclen;
985     memcpy(val->sam_challenge_2_body.data, save, alloclen);
986     next_tag();
987     get_field(val->sam_cksum, 1, asn1_decode_sequence_of_checksum);
988     end_structure();
989   }
990   cleanup();
991 }
992 asn1_error_code asn1_decode_sam_challenge_2_body(asn1buf *buf, krb5_sam_challenge_2_body *val)
993 {
994   setup();
995   { begin_structure();
996     get_field(val->sam_type,0,asn1_decode_int32);
997     get_field(val->sam_flags,1,asn1_decode_sam_flags);
998     opt_string(val->sam_type_name,2,asn1_decode_charstring);
999     opt_string(val->sam_track_id,3,asn1_decode_charstring);
1000     opt_string(val->sam_challenge_label,4,asn1_decode_charstring);
1001     opt_string(val->sam_challenge,5,asn1_decode_charstring);
1002     opt_string(val->sam_response_prompt,6,asn1_decode_charstring);
1003     opt_string(val->sam_pk_for_sad,7,asn1_decode_charstring);
1004     get_field(val->sam_nonce,8,asn1_decode_int32);
1005     get_field(val->sam_etype, 9, asn1_decode_int32);
1006     end_structure();
1007     val->magic = KV5M_SAM_CHALLENGE;
1008   }
1009   cleanup();
1010 }
1011 asn1_error_code asn1_decode_enc_sam_key(asn1buf *buf, krb5_sam_key *val)
1012 {
1013   setup();
1014   { begin_structure();
1015     /* alloc_field(val->sam_key,krb5_keyblock); */
1016     get_field(val->sam_key,0,asn1_decode_encryption_key);
1017     end_structure();
1018     val->magic = KV5M_SAM_KEY;
1019   }
1020   cleanup();
1021 }
1022 
1023 asn1_error_code asn1_decode_enc_sam_response_enc(asn1buf *buf, krb5_enc_sam_response_enc *val)
1024 {
1025   setup();
1026   { begin_structure();
1027     opt_field(val->sam_nonce,0,asn1_decode_int32,0);
1028     opt_field(val->sam_timestamp,1,asn1_decode_kerberos_time,0);
1029     opt_field(val->sam_usec,2,asn1_decode_int32,0);
1030     opt_string(val->sam_sad,3,asn1_decode_charstring);
1031     end_structure();
1032     val->magic = KV5M_ENC_SAM_RESPONSE_ENC;
1033   }
1034   cleanup();
1035 }
1036 
1037 asn1_error_code asn1_decode_enc_sam_response_enc_2(asn1buf *buf, krb5_enc_sam_response_enc_2 *val)
1038 {
1039   setup();
1040   { begin_structure();
1041     get_field(val->sam_nonce,0,asn1_decode_int32);
1042     opt_string(val->sam_sad,1,asn1_decode_charstring);
1043     end_structure();
1044     val->magic = KV5M_ENC_SAM_RESPONSE_ENC_2;
1045   }
1046   cleanup();
1047 }
1048 
1049 #define opt_encfield(fld,tag,fn) \
1050     if(tagnum == tag){ \
1051       get_field(fld,tag,fn); } \
1052     else{\
1053       fld.magic = 0;\
1054       fld.enctype = 0;\
1055       fld.kvno = 0;\
1056       fld.ciphertext.data = NULL;\
1057       fld.ciphertext.length = 0;\
1058     }
1059 
1060 asn1_error_code asn1_decode_sam_response(asn1buf *buf, krb5_sam_response *val)
1061 {
1062   setup();
1063   { begin_structure();
1064     get_field(val->sam_type,0,asn1_decode_int32);
1065     get_field(val->sam_flags,1,asn1_decode_sam_flags);
1066     opt_string(val->sam_track_id,2,asn1_decode_charstring);
1067     opt_encfield(val->sam_enc_key,3,asn1_decode_encrypted_data);
1068     get_field(val->sam_enc_nonce_or_ts,4,asn1_decode_encrypted_data);
1069     opt_field(val->sam_nonce,5,asn1_decode_int32,0);
1070     opt_field(val->sam_patimestamp,6,asn1_decode_kerberos_time,0);
1071     end_structure();
1072     val->magic = KV5M_SAM_RESPONSE;
1073   }
1074   cleanup();
1075 }
1076 
1077 asn1_error_code asn1_decode_sam_response_2(asn1buf *buf, krb5_sam_response_2 *val)
1078 {
1079   setup();
1080   { begin_structure();
1081     get_field(val->sam_type,0,asn1_decode_int32);
1082     get_field(val->sam_flags,1,asn1_decode_sam_flags);
1083     opt_string(val->sam_track_id,2,asn1_decode_charstring);
1084     get_field(val->sam_enc_nonce_or_sad,3,asn1_decode_encrypted_data);
1085     get_field(val->sam_nonce,4,asn1_decode_int32);
1086     end_structure();
1087     val->magic = KV5M_SAM_RESPONSE;
1088   }
1089   cleanup();
1090 }
1091 
1092 
1093 asn1_error_code asn1_decode_predicted_sam_response(asn1buf *buf, krb5_predicted_sam_response *val)
1094 {
1095   setup();
1096   { begin_structure();
1097     get_field(val->sam_key,0,asn1_decode_encryption_key);
1098     get_field(val->sam_flags,1,asn1_decode_sam_flags);
1099     get_field(val->stime,2,asn1_decode_kerberos_time);
1100     get_field(val->susec,3,asn1_decode_int32);
1101     alloc_field(val->client,krb5_principal_data);
1102     get_field(val->client,4,asn1_decode_realm);
1103     get_field(val->client,5,asn1_decode_principal_name);
1104     opt_string(val->msd,6,asn1_decode_charstring); /* should be octet */
1105     end_structure();
1106     val->magic = KV5M_PREDICTED_SAM_RESPONSE;
1107   }
1108   cleanup();
1109 }
1110