1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * src/lib/krb5/asn.1/asn1_k_encode.c
5  *
6  * Copyright 1994 by the Massachusetts Institute of Technology.
7  * All Rights Reserved.
8  *
9  * Export of this software from the United States of America may
10  *   require a specific license from the United States Government.
11  *   It is the responsibility of any person or organization contemplating
12  *   export to obtain such a license before exporting.
13  *
14  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15  * distribute this software and its documentation for any purpose and
16  * without fee is hereby granted, provided that the above copyright
17  * notice appear in all copies and that both that copyright notice and
18  * this permission notice appear in supporting documentation, and that
19  * the name of M.I.T. not be used in advertising or publicity pertaining
20  * to distribution of the software without specific, written prior
21  * permission.  Furthermore if you modify this software you must label
22  * your software as modified software and not distribute it in such a
23  * fashion that it might be confused with the original M.I.T. software.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is" without express
26  * or implied warranty.
27  */
28 
29 #include "asn1_k_encode.h"
30 #include "asn1_make.h"
31 #include "asn1_encode.h"
32 #include <assert.h>
33 
34 /**** asn1 macros ****/
35 #if 0
36    How to write an asn1 encoder function using these macros:
37 
38    asn1_error_code asn1_encode_krb5_substructure(asn1buf *buf,
39                                                  const krb5_type *val,
40                                                  int *retlen)
41    {
42      asn1_setup();
43 
44      asn1_addfield(val->last_field, n, asn1_type);
45      asn1_addfield(rep->next_to_last_field, n-1, asn1_type);
46      ...
47 
48      /* for OPTIONAL fields */
49      if(rep->field_i == should_not_be_omitted)
50        asn1_addfield(rep->field_i, i, asn1_type);
51 
52      /* for string fields (these encoders take an additional argument,
53 	the length of the string) */
54      addlenfield(rep->field_length, rep->field, i-1, asn1_type);
55 
56      /* if you really have to do things yourself... */
57      retval = asn1_encode_asn1_type(buf,rep->field,&length);
58      if(retval) return retval;
59      sum += length;
60      retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, tag_number, length,
61 			     &length);
62      if(retval) return retval;
63      sum += length;
64 
65      ...
66      asn1_addfield(rep->second_field, 1, asn1_type);
67      asn1_addfield(rep->first_field, 0, asn1_type);
68      asn1_makeseq();
69 
70      asn1_cleanup();
71    }
72 #endif
73 
74 /* setup() -- create and initialize bookkeeping variables
75      retval: stores error codes returned from subroutines
76      length: length of the most-recently produced encoding
77      sum: cumulative length of the entire encoding */
78 #define asn1_setup()\
79   asn1_error_code retval;\
80   unsigned int length, sum=0
81 
82 /* asn1_addfield -- add a field, or component, to the encoding */
83 #define asn1_addfield(value,tag,encoder)\
84 { retval = encoder(buf,value,&length);\
85   if(retval){\
86     asn1buf_destroy(&buf);\
87     return retval; }\
88   sum += length;\
89   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
90   if(retval){\
91     asn1buf_destroy(&buf);\
92     return retval; }\
93   sum += length; }
94 
95 /* asn1_addlenfield -- add a field whose length must be separately specified */
96 #define asn1_addlenfield(len,value,tag,encoder)\
97 { retval = encoder(buf,len,value,&length);\
98   if(retval){\
99     asn1buf_destroy(&buf);\
100     return retval; }\
101   sum += length;\
102   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,tag,length,&length);\
103   if(retval){\
104     asn1buf_destroy(&buf);\
105     return retval; }\
106   sum += length; }
107 
108 /* form a sequence (by adding a sequence header to the current encoding) */
109 #define asn1_makeseq()\
110   retval = asn1_make_sequence(buf,sum,&length);\
111   if(retval){\
112     asn1buf_destroy(&buf);\
113     return retval; }\
114   sum += length
115 
116 /* add an APPLICATION class tag to the current encoding */
117 #define asn1_apptag(num)\
118   retval = asn1_make_etag(buf,APPLICATION,num,sum,&length);\
119   if(retval){\
120     asn1buf_destroy(&buf);\
121     return retval; }\
122   sum += length
123 
124 /* produce the final output and clean up the workspace */
125 #define asn1_cleanup()\
126   *retlen = sum;\
127   return 0
128 
129 asn1_error_code asn1_encode_ui_4(asn1buf *buf, const krb5_ui_4 val, unsigned int *retlen)
130 {
131   return asn1_encode_unsigned_integer(buf,val,retlen);
132 }
133 
134 
135 asn1_error_code asn1_encode_realm(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
136 {
137   if (val == NULL ||
138       (val->realm.length && val->realm.data == NULL))
139 	  return ASN1_MISSING_FIELD;
140   return asn1_encode_generalstring(buf,val->realm.length,val->realm.data,
141 				   retlen);
142 }
143 
144 asn1_error_code asn1_encode_principal_name(asn1buf *buf, const krb5_principal val, unsigned int *retlen)
145 {
146   asn1_setup();
147   int n;
148 
149   if (val == NULL || val->data == NULL) return ASN1_MISSING_FIELD;
150 
151   for(n = (int) ((val->length)-1); n >= 0; n--){
152     if (val->data[n].length &&
153 	val->data[n].data == NULL)
154 	    return ASN1_MISSING_FIELD;
155     retval = asn1_encode_generalstring(buf,
156 				       (val->data)[n].length,
157 				       (val->data)[n].data,
158 				       &length);
159     if(retval) return retval;
160     sum += length;
161   }
162   asn1_makeseq();
163   retval = asn1_make_etag(buf,CONTEXT_SPECIFIC,1,sum,&length);
164   if(retval) return retval;
165   sum += length;
166 
167   asn1_addfield(val->type,0,asn1_encode_integer);
168 
169   asn1_makeseq();
170 
171   asn1_cleanup();
172 }
173 
174 asn1_error_code asn1_encode_kerberos_time(asn1buf *buf, const krb5_timestamp val, unsigned int *retlen)
175 {
176   return asn1_encode_generaltime(buf,val,retlen);
177 }
178 
179 asn1_error_code asn1_encode_host_address(asn1buf *buf, const krb5_address *val, unsigned int *retlen)
180 {
181   asn1_setup();
182 
183   if (val == NULL || val->contents == NULL) return ASN1_MISSING_FIELD;
184 
185   asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
186   asn1_addfield(val->addrtype,0,asn1_encode_integer);
187   asn1_makeseq();
188 
189   asn1_cleanup();
190 }
191 
192 asn1_error_code asn1_encode_host_addresses(asn1buf *buf, const krb5_address **val, unsigned int *retlen)
193 {
194   asn1_setup();
195   int i;
196 
197   if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
198 
199   for(i=0; val[i] != NULL; i++); /* go to end of array */
200   for(i--; i>=0; i--){
201     retval = asn1_encode_host_address(buf,val[i],&length);
202     if(retval) return retval;
203     sum += length;
204   }
205   asn1_makeseq();
206 
207   asn1_cleanup();
208 }
209 
210 asn1_error_code asn1_encode_encrypted_data(asn1buf *buf, const krb5_enc_data *val, unsigned int *retlen)
211 {
212   asn1_setup();
213 
214   if(val == NULL ||
215      (val->ciphertext.length && val->ciphertext.data == NULL))
216 	  return ASN1_MISSING_FIELD;
217 
218   asn1_addlenfield(val->ciphertext.length,val->ciphertext.data,2,asn1_encode_charstring);
219   /* krb5_kvno should be int */
220   if(val->kvno)
221     asn1_addfield((int) val->kvno,1,asn1_encode_integer);
222   asn1_addfield(val->enctype,0,asn1_encode_integer);
223 
224   asn1_makeseq();
225 
226   asn1_cleanup();
227 }
228 
229 asn1_error_code asn1_encode_krb5_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
230 {
231   asn1_setup();
232   krb5_flags valcopy = val;
233   int i;
234 
235   for(i=0; i<4; i++){
236     retval = asn1buf_insert_octet(buf,(asn1_octet) (valcopy&0xFF));
237     if(retval) return retval;
238     valcopy >>= 8;
239   }
240   retval = asn1buf_insert_octet(buf,0);	/* 0 padding bits */
241   if(retval) return retval;
242   sum = 5;
243 
244   retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_BITSTRING,sum,
245 			 &length);
246   if(retval) return retval;
247   sum += length;
248 
249   *retlen = sum;
250   return 0;
251 }
252 
253 asn1_error_code asn1_encode_ap_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
254 {
255   return asn1_encode_krb5_flags(buf,val,retlen);
256 }
257 
258 asn1_error_code asn1_encode_ticket_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
259 {
260   return asn1_encode_krb5_flags(buf,val,retlen);
261 }
262 
263 asn1_error_code asn1_encode_kdc_options(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
264 {
265   return asn1_encode_krb5_flags(buf,val,retlen);
266 }
267 
268 asn1_error_code asn1_encode_authorization_data(asn1buf *buf, const krb5_authdata **val, unsigned int *retlen)
269 {
270   asn1_setup();
271   int i;
272 
273   if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
274 
275   for(i=0; val[i] != NULL; i++); /* get to the end of the array */
276   for(i--; i>=0; i--){
277     retval = asn1_encode_krb5_authdata_elt(buf,val[i],&length);
278     if(retval) return retval;
279     sum += length;
280   }
281   asn1_makeseq();
282 
283   asn1_cleanup();
284 }
285 
286 asn1_error_code asn1_encode_krb5_authdata_elt(asn1buf *buf, const krb5_authdata *val, unsigned int *retlen)
287 {
288   asn1_setup();
289 
290   if (val == NULL ||
291      (val->length && val->contents == NULL))
292 	  return ASN1_MISSING_FIELD;
293 
294   /* ad-data[1]		OCTET STRING */
295   asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
296   /* ad-type[0]		INTEGER */
297   asn1_addfield(val->ad_type,0,asn1_encode_integer);
298   /* SEQUENCE */
299   asn1_makeseq();
300 
301   asn1_cleanup();
302 }
303 
304 asn1_error_code asn1_encode_kdc_rep(int msg_type, asn1buf *buf, const krb5_kdc_rep *val, unsigned int *retlen)
305 {
306   asn1_setup();
307 
308   if(val == NULL) return ASN1_MISSING_FIELD;
309 
310   asn1_addfield(&(val->enc_part),6,asn1_encode_encrypted_data);
311   asn1_addfield(val->ticket,5,asn1_encode_ticket);
312   asn1_addfield(val->client,4,asn1_encode_principal_name);
313   asn1_addfield(val->client,3,asn1_encode_realm);
314   if(val->padata != NULL && val->padata[0] != NULL)
315     asn1_addfield((const krb5_pa_data**)val->padata,2,asn1_encode_sequence_of_pa_data);
316   if (msg_type != KRB5_AS_REP && msg_type != KRB5_TGS_REP)
317 	  return KRB5_BADMSGTYPE;
318   asn1_addfield(msg_type,1,asn1_encode_integer);
319   asn1_addfield(KVNO,0,asn1_encode_integer);
320   asn1_makeseq();
321 
322   asn1_cleanup();
323 }
324 
325 asn1_error_code asn1_encode_enc_kdc_rep_part(asn1buf *buf, const krb5_enc_kdc_rep_part *val, unsigned int *retlen)
326 {
327   asn1_setup();
328 
329   if(val == NULL) return ASN1_MISSING_FIELD;
330 
331   /* caddr[11]		HostAddresses OPTIONAL */
332   if(val->caddrs != NULL && val->caddrs[0] != NULL)
333     asn1_addfield((const krb5_address**)(val->caddrs),11,asn1_encode_host_addresses);
334 
335   /* sname[10]		PrincipalName */
336   asn1_addfield(val->server,10,asn1_encode_principal_name);
337 
338   /* srealm[9]		Realm */
339   asn1_addfield(val->server,9,asn1_encode_realm);
340 
341   /* renew-till[8]	KerberosTime OPTIONAL */
342   if(val->flags & TKT_FLG_RENEWABLE)
343     asn1_addfield(val->times.renew_till,8,asn1_encode_kerberos_time);
344 
345   /* endtime[7]		KerberosTime */
346   asn1_addfield(val->times.endtime,7,asn1_encode_kerberos_time);
347 
348   /* starttime[6]	KerberosTime OPTIONAL */
349   if(val->times.starttime)
350     asn1_addfield(val->times.starttime,6,asn1_encode_kerberos_time);
351 
352   /* authtime[5]	KerberosTime */
353   asn1_addfield(val->times.authtime,5,asn1_encode_kerberos_time);
354 
355   /* flags[4]		TicketFlags */
356   asn1_addfield(val->flags,4,asn1_encode_ticket_flags);
357 
358   /* key-expiration[3]	KerberosTime OPTIONAL */
359   if(val->key_exp)
360     asn1_addfield(val->key_exp,3,asn1_encode_kerberos_time);
361 
362   /* nonce[2]		INTEGER */
363   asn1_addfield(val->nonce,2,asn1_encode_integer);
364 
365   /* last-req[1]	LastReq */
366   asn1_addfield((const krb5_last_req_entry**)val->last_req,1,asn1_encode_last_req);
367 
368   /* key[0]		EncryptionKey */
369   asn1_addfield(val->session,0,asn1_encode_encryption_key);
370 
371   /* EncKDCRepPart ::= SEQUENCE */
372   asn1_makeseq();
373 
374   asn1_cleanup();
375 }
376 
377 asn1_error_code asn1_encode_sequence_of_checksum(asn1buf *buf, const krb5_checksum ** val, unsigned int *retlen)
378 {
379   asn1_setup();
380   int i;
381 
382   if(val == NULL) return ASN1_MISSING_FIELD;
383 
384   for (i=0; val[i] != NULL; i++);
385   for (i--; i>=0; i--){
386     retval = asn1_encode_checksum(buf,val[i],&length);
387     if(retval) return retval;
388     sum += length;
389   }
390   asn1_makeseq();
391 
392   asn1_cleanup();
393 }
394 
395 asn1_error_code asn1_encode_kdc_req_body(asn1buf *buf, const krb5_kdc_req *rep, unsigned int *retlen)
396 {
397   asn1_setup();
398 
399   if(rep == NULL) return ASN1_MISSING_FIELD;
400 
401   /* additional-tickets[11]	SEQUENCE OF Ticket OPTIONAL */
402   if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL)
403     asn1_addfield((const krb5_ticket**)rep->second_ticket,
404 		  11,asn1_encode_sequence_of_ticket);
405 
406   /* enc-authorization-data[10]	EncryptedData OPTIONAL, */
407   /* 				-- Encrypted AuthorizationData encoding */
408   if(rep->authorization_data.ciphertext.data != NULL)
409     asn1_addfield(&(rep->authorization_data),10,asn1_encode_encrypted_data);
410 
411   /* addresses[9]		HostAddresses OPTIONAL, */
412   if(rep->addresses != NULL && rep->addresses[0] != NULL)
413     asn1_addfield((const krb5_address**)rep->addresses,9,asn1_encode_host_addresses);
414 
415   /* etype[8]			SEQUENCE OF INTEGER, -- EncryptionType, */
416   /* 				-- in preference order */
417   asn1_addlenfield(rep->nktypes,rep->ktype,8,asn1_encode_sequence_of_enctype);
418 
419   /* nonce[7]			INTEGER, */
420   asn1_addfield(rep->nonce,7,asn1_encode_integer);
421 
422   /* rtime[6]			KerberosTime OPTIONAL, */
423   if(rep->rtime)
424     asn1_addfield(rep->rtime,6,asn1_encode_kerberos_time);
425 
426   /* till[5]			KerberosTime, */
427   asn1_addfield(rep->till,5,asn1_encode_kerberos_time);
428 
429   /* from[4]			KerberosTime OPTIONAL, */
430   if(rep->from)
431   asn1_addfield(rep->from,4,asn1_encode_kerberos_time);
432 
433   /* sname[3]			PrincipalName OPTIONAL, */
434   if(rep->server != NULL)
435     asn1_addfield(rep->server,3,asn1_encode_principal_name);
436 
437   /* realm[2]			Realm, -- Server's realm */
438   /* 				-- Also client's in AS-REQ */
439   if(rep->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY){
440     if(rep->second_ticket != NULL && rep->second_ticket[0] != NULL){
441       asn1_addfield(rep->second_ticket[0]->server,2,asn1_encode_realm)
442     } else return ASN1_MISSING_FIELD;
443   }else if(rep->server != NULL){
444     asn1_addfield(rep->server,2,asn1_encode_realm);
445   }else return ASN1_MISSING_FIELD;
446 
447   /* cname[1]			PrincipalName OPTIONAL, */
448   /* 				-- Used only in AS-REQ */
449   if(rep->client != NULL)
450     asn1_addfield(rep->client,1,asn1_encode_principal_name);
451 
452   /* kdc-options[0]		KDCOptions, */
453   asn1_addfield(rep->kdc_options,0,asn1_encode_kdc_options);
454 
455   /* KDC-REQ-BODY ::= SEQUENCE */
456   asn1_makeseq();
457 
458   asn1_cleanup();
459 }
460 
461 asn1_error_code asn1_encode_encryption_key(asn1buf *buf, const krb5_keyblock *val, unsigned int *retlen)
462 {
463   asn1_setup();
464 
465   if (val == NULL ||
466       (val->length && val->contents == NULL))
467 	  return ASN1_MISSING_FIELD;
468 
469   asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
470   asn1_addfield(val->enctype,0,asn1_encode_integer);
471   asn1_makeseq();
472 
473   asn1_cleanup();
474 }
475 
476 asn1_error_code asn1_encode_checksum(asn1buf *buf, const krb5_checksum *val, unsigned int *retlen)
477 {
478   asn1_setup();
479 
480   if (val == NULL ||
481      (val->length && val->contents == NULL))
482 	  return ASN1_MISSING_FIELD;
483 
484   asn1_addlenfield(val->length,val->contents,1,asn1_encode_octetstring);
485   asn1_addfield(val->checksum_type,0,asn1_encode_integer);
486   asn1_makeseq();
487 
488   asn1_cleanup();
489 }
490 
491 asn1_error_code asn1_encode_transited_encoding(asn1buf *buf, const krb5_transited *val, unsigned int *retlen)
492 {
493   asn1_setup();
494 
495   if(val == NULL ||
496      (val->tr_contents.length != 0 && val->tr_contents.data == NULL))
497     return ASN1_MISSING_FIELD;
498 
499   asn1_addlenfield(val->tr_contents.length,val->tr_contents.data,
500 		   1,asn1_encode_charstring);
501   asn1_addfield(val->tr_type,0,asn1_encode_integer);
502   asn1_makeseq();
503 
504   asn1_cleanup();
505 }
506 
507 asn1_error_code asn1_encode_last_req(asn1buf *buf, const krb5_last_req_entry **val, unsigned int *retlen)
508 {
509   asn1_setup();
510   int i;
511 
512   if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
513 
514   for(i=0; val[i] != NULL; i++); /* go to end of array */
515   for(i--; i>=0; i--){
516     retval = asn1_encode_last_req_entry(buf,val[i],&length);
517     if(retval) return retval;
518     sum += length;
519   }
520   asn1_makeseq();
521 
522   asn1_cleanup();
523 }
524 
525 asn1_error_code asn1_encode_last_req_entry(asn1buf *buf, const krb5_last_req_entry *val, unsigned int *retlen)
526 {
527   asn1_setup();
528 
529   if(val == NULL) return ASN1_MISSING_FIELD;
530 
531   asn1_addfield(val->value,1,asn1_encode_kerberos_time);
532   asn1_addfield(val->lr_type,0,asn1_encode_integer);
533   asn1_makeseq();
534 
535   asn1_cleanup();
536 }
537 
538 asn1_error_code asn1_encode_sequence_of_pa_data(asn1buf *buf, const krb5_pa_data **val, unsigned int *retlen)
539 {
540   asn1_setup();
541   int i;
542 
543   if (val == NULL) return ASN1_MISSING_FIELD;
544 
545   for(i=0; val[i] != NULL; i++);
546   for(i--; i>=0; i--){
547     retval = asn1_encode_pa_data(buf,val[i],&length);
548     if(retval) return retval;
549     sum += length;
550   }
551   asn1_makeseq();
552 
553   asn1_cleanup();
554 }
555 
556 asn1_error_code asn1_encode_pa_data(asn1buf *buf, const krb5_pa_data *val, unsigned int *retlen)
557 {
558   asn1_setup();
559 
560   if(val == NULL || (val->length != 0 && val->contents == NULL))
561      return ASN1_MISSING_FIELD;
562 
563   asn1_addlenfield(val->length,val->contents,2,asn1_encode_octetstring);
564   asn1_addfield(val->pa_type,1,asn1_encode_integer);
565   asn1_makeseq();
566 
567   asn1_cleanup();
568 }
569 
570 asn1_error_code asn1_encode_sequence_of_ticket(asn1buf *buf, const krb5_ticket **val, unsigned int *retlen)
571 {
572   asn1_setup();
573   int i;
574 
575   if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
576 
577   for(i=0; val[i] != NULL; i++);
578   for(i--; i>=0; i--){
579     retval = asn1_encode_ticket(buf,val[i],&length);
580     if(retval) return retval;
581     sum += length;
582   }
583   asn1_makeseq();
584 
585   asn1_cleanup();
586 }
587 
588 asn1_error_code asn1_encode_ticket(asn1buf *buf, const krb5_ticket *val, unsigned int *retlen)
589 {
590   asn1_setup();
591 
592   if(val == NULL) return ASN1_MISSING_FIELD;
593 
594   asn1_addfield(&(val->enc_part),3,asn1_encode_encrypted_data);
595   asn1_addfield(val->server,2,asn1_encode_principal_name);
596   asn1_addfield(val->server,1,asn1_encode_realm);
597   asn1_addfield(KVNO,0,asn1_encode_integer);
598   asn1_makeseq();
599   asn1_apptag(1);
600 
601   asn1_cleanup();
602 }
603 
604 asn1_error_code asn1_encode_sequence_of_enctype(asn1buf *buf, const int len, const krb5_enctype *val, unsigned int *retlen)
605 {
606   asn1_setup();
607   int i;
608 
609   if(val == NULL) return ASN1_MISSING_FIELD;
610 
611   for(i=len-1; i>=0; i--){
612     retval = asn1_encode_integer(buf,val[i],&length);
613     if(retval) return retval;
614     sum += length;
615   }
616   asn1_makeseq();
617 
618   asn1_cleanup();
619 }
620 
621 asn1_error_code asn1_encode_kdc_req(int msg_type, asn1buf *buf, const krb5_kdc_req *val, unsigned int *retlen)
622 {
623   asn1_setup();
624 
625   if(val == NULL) return ASN1_MISSING_FIELD;
626 
627   asn1_addfield(val,4,asn1_encode_kdc_req_body);
628   if(val->padata != NULL && val->padata[0] != NULL)
629     asn1_addfield((const krb5_pa_data**)val->padata,3,asn1_encode_sequence_of_pa_data);
630   if (msg_type != KRB5_AS_REQ && msg_type != KRB5_TGS_REQ)
631 	  return KRB5_BADMSGTYPE;
632   asn1_addfield(msg_type,2,asn1_encode_integer);
633   asn1_addfield(KVNO,1,asn1_encode_integer);
634   asn1_makeseq();
635 
636   asn1_cleanup();
637 }
638 
639 asn1_error_code asn1_encode_krb_safe_body(asn1buf *buf, const krb5_safe *val, unsigned int *retlen)
640 {
641   asn1_setup();
642 
643   if(val == NULL) return ASN1_MISSING_FIELD;
644 
645   if(val->r_address != NULL)
646     asn1_addfield(val->r_address,5,asn1_encode_host_address);
647   asn1_addfield(val->s_address,4,asn1_encode_host_address);
648   if(val->seq_number)
649     asn1_addfield(val->seq_number,3,asn1_encode_unsigned_integer);
650   if(val->timestamp){
651     asn1_addfield(val->usec,2,asn1_encode_integer);
652     asn1_addfield(val->timestamp,1,asn1_encode_kerberos_time);
653   }
654   if (val->user_data.length && val->user_data.data == NULL)
655 	  return ASN1_MISSING_FIELD;
656   asn1_addlenfield(val->user_data.length,val->user_data.data,0,asn1_encode_charstring)
657 ;
658 
659   asn1_makeseq();
660   asn1_cleanup();
661 }
662 
663 asn1_error_code asn1_encode_sequence_of_krb_cred_info(asn1buf *buf, const krb5_cred_info **val, unsigned int *retlen)
664 {
665   asn1_setup();
666   int i;
667 
668   if(val == NULL) return ASN1_MISSING_FIELD;
669 
670   for(i=0; val[i] != NULL; i++);
671   for(i--; i>=0; i--){
672     retval = asn1_encode_krb_cred_info(buf,val[i],&length);
673     if(retval) return retval;
674     sum += length;
675   }
676   asn1_makeseq();
677 
678   asn1_cleanup();
679 }
680 
681 asn1_error_code asn1_encode_krb_cred_info(asn1buf *buf, const krb5_cred_info *val, unsigned int *retlen)
682 {
683   asn1_setup();
684 
685   if(val == NULL) return ASN1_MISSING_FIELD;
686 
687   if(val->caddrs != NULL && val->caddrs[0] != NULL)
688     asn1_addfield((const krb5_address**)val->caddrs,10,asn1_encode_host_addresses);
689   if(val->server != NULL){
690     asn1_addfield(val->server,9,asn1_encode_principal_name);
691     asn1_addfield(val->server,8,asn1_encode_realm);
692   }
693   if(val->times.renew_till)
694     asn1_addfield(val->times.renew_till,7,asn1_encode_kerberos_time);
695   if(val->times.endtime)
696     asn1_addfield(val->times.endtime,6,asn1_encode_kerberos_time);
697   if(val->times.starttime)
698     asn1_addfield(val->times.starttime,5,asn1_encode_kerberos_time);
699   if(val->times.authtime)
700     asn1_addfield(val->times.authtime,4,asn1_encode_kerberos_time);
701   if(val->flags)
702     asn1_addfield(val->flags,3,asn1_encode_ticket_flags);
703   if(val->client != NULL){
704     asn1_addfield(val->client,2,asn1_encode_principal_name);
705     asn1_addfield(val->client,1,asn1_encode_realm);
706   }
707   asn1_addfield(val->session,0,asn1_encode_encryption_key);
708 
709   asn1_makeseq();
710 
711   asn1_cleanup();
712 }
713 
714 asn1_error_code asn1_encode_etype_info_entry(asn1buf *buf, const krb5_etype_info_entry *val,
715 					     unsigned int *retlen, int etype_info2)
716 {
717   asn1_setup();
718 
719   assert(val->s2kparams.data == NULL || etype_info2);
720   if(val == NULL || (val->length > 0 && val->length != KRB5_ETYPE_NO_SALT &&
721 		     val->salt == NULL))
722      return ASN1_MISSING_FIELD;
723   if(val->s2kparams.data != NULL)
724       asn1_addlenfield(val->s2kparams.length, (const uchar_t *)val->s2kparams.data, 2,
725 		       asn1_encode_octetstring);
726   if (val->length >= 0 && val->length != KRB5_ETYPE_NO_SALT){
727       if (etype_info2)
728 	  asn1_addlenfield(val->length, (const char *)val->salt,1,
729 			   asn1_encode_generalstring)
730       else 	  asn1_addlenfield(val->length,val->salt,1,
731 				   asn1_encode_octetstring);
732   }
733 asn1_addfield(val->etype,0,asn1_encode_integer);
734   asn1_makeseq();
735 
736   asn1_cleanup();
737 }
738 
739 asn1_error_code asn1_encode_etype_info(asn1buf *buf, const krb5_etype_info_entry **val,
740 				       unsigned int *retlen, int etype_info2)
741 {
742     asn1_setup();
743     int i;
744 
745     if (val == NULL) return ASN1_MISSING_FIELD;
746 
747     for(i=0; val[i] != NULL; i++); /* get to the end of the array */
748     for(i--; i>=0; i--){
749 	retval = asn1_encode_etype_info_entry(buf,val[i],&length, etype_info2);
750 	if(retval) return retval;
751 	sum += length;
752     }
753     asn1_makeseq();
754     asn1_cleanup();
755 }
756 
757 asn1_error_code asn1_encode_sequence_of_passwdsequence(asn1buf *buf, const passwd_phrase_element **val, unsigned int *retlen)
758 {
759   asn1_setup();
760   int i;
761 
762   if(val == NULL || val[0] == NULL) return ASN1_MISSING_FIELD;
763 
764   for(i=0; val[i] != NULL; i++); /* get to the end of the array */
765   for(i--; i>=0; i--){
766     retval = asn1_encode_passwdsequence(buf,val[i],&length);
767     if(retval) return retval;
768     sum += length;
769   }
770   asn1_makeseq();
771   asn1_cleanup();
772 }
773 
774 asn1_error_code asn1_encode_passwdsequence(asn1buf *buf, const passwd_phrase_element *val, unsigned int *retlen)
775 {
776   asn1_setup();
777   asn1_addlenfield(val->phrase->length,val->phrase->data,1,asn1_encode_charstring);
778   asn1_addlenfield(val->passwd->length,val->passwd->data,0,asn1_encode_charstring);
779   asn1_makeseq();
780   asn1_cleanup();
781 }
782 
783 asn1_error_code asn1_encode_sam_flags(asn1buf *buf, const krb5_flags val, unsigned int *retlen)
784 {
785   return asn1_encode_krb5_flags(buf,val,retlen);
786 }
787 
788 #define add_optstring(val,n,fn) \
789      if ((val).length > 0) {asn1_addlenfield((val).length,(val).data,n,fn);}
790 
791 asn1_error_code asn1_encode_sam_challenge(asn1buf *buf, const krb5_sam_challenge *val, unsigned int *retlen)
792 {
793   asn1_setup();
794   /* possibly wrong */
795   if (val->sam_cksum.length)
796     asn1_addfield(&(val->sam_cksum),9,asn1_encode_checksum);
797 
798   if (val->sam_nonce)
799     asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
800 
801   add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
802   add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
803   add_optstring(val->sam_challenge,5,asn1_encode_charstring);
804   add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
805   add_optstring(val->sam_track_id,3,asn1_encode_charstring);
806   add_optstring(val->sam_type_name,2,asn1_encode_charstring);
807 
808   asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
809   asn1_addfield(val->sam_type,0,asn1_encode_integer);
810 
811   asn1_makeseq();
812   asn1_cleanup();
813 }
814 
815 asn1_error_code asn1_encode_sam_challenge_2(asn1buf *buf, const krb5_sam_challenge_2 *val, unsigned int *retlen)
816 {
817   asn1_setup();
818   if ( (!val) || (!val->sam_cksum) || (!val->sam_cksum[0]))
819       return ASN1_MISSING_FIELD;
820 
821   asn1_addfield((const krb5_checksum **) val->sam_cksum, 1, asn1_encode_sequence_of_checksum);
822   retval = asn1buf_insert_octetstring(buf, val->sam_challenge_2_body.length,
823 				      (unsigned char *)val->sam_challenge_2_body.data);
824   if(retval){
825 	  asn1buf_destroy(&buf);
826 	  return retval;
827   }
828   sum += val->sam_challenge_2_body.length;
829   retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0,
830 			  val->sam_challenge_2_body.length, &length);
831   if(retval) {
832 	  asn1buf_destroy(&buf);
833 	  return retval;
834   }
835   sum += length;
836 
837   asn1_makeseq();
838   asn1_cleanup();
839 }
840 
841 asn1_error_code asn1_encode_sam_challenge_2_body(asn1buf *buf, const krb5_sam_challenge_2_body *val, unsigned int *retlen)
842 {
843   asn1_setup();
844 
845   asn1_addfield(val->sam_etype, 9, asn1_encode_integer);
846   asn1_addfield(val->sam_nonce,8,asn1_encode_integer);
847   add_optstring(val->sam_pk_for_sad,7,asn1_encode_charstring);
848   add_optstring(val->sam_response_prompt,6,asn1_encode_charstring);
849   add_optstring(val->sam_challenge,5,asn1_encode_charstring);
850   add_optstring(val->sam_challenge_label,4,asn1_encode_charstring);
851   add_optstring(val->sam_track_id,3,asn1_encode_charstring);
852   add_optstring(val->sam_type_name,2,asn1_encode_charstring);
853 
854   asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
855   asn1_addfield(val->sam_type,0,asn1_encode_integer);
856 
857   asn1_makeseq();
858   asn1_cleanup();
859 }
860 
861 asn1_error_code asn1_encode_sam_key(asn1buf *buf, const krb5_sam_key *val, unsigned int *retlen)
862 {
863   asn1_setup();
864   asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
865 
866   asn1_makeseq();
867 
868   asn1_cleanup();
869 }
870 
871 
872 asn1_error_code asn1_encode_enc_sam_response_enc(asn1buf *buf, const krb5_enc_sam_response_enc *val, unsigned int *retlen)
873 {
874   asn1_setup();
875   add_optstring(val->sam_sad,3,asn1_encode_charstring);
876   asn1_addfield(val->sam_usec,2,asn1_encode_integer);
877   asn1_addfield(val->sam_timestamp,1,asn1_encode_kerberos_time);
878   asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
879 
880   asn1_makeseq();
881 
882   asn1_cleanup();
883 }
884 
885 asn1_error_code asn1_encode_enc_sam_response_enc_2(asn1buf *buf, const krb5_enc_sam_response_enc_2 *val, unsigned int *retlen)
886 {
887   asn1_setup();
888   add_optstring(val->sam_sad,1,asn1_encode_charstring);
889   asn1_addfield(val->sam_nonce,0,asn1_encode_integer);
890 
891   asn1_makeseq();
892 
893   asn1_cleanup();
894 }
895 
896 asn1_error_code asn1_encode_sam_response(asn1buf *buf, const krb5_sam_response *val, unsigned int *retlen)
897 {
898   asn1_setup();
899 
900   if (val->sam_patimestamp)
901     asn1_addfield(val->sam_patimestamp,6,asn1_encode_kerberos_time);
902   if (val->sam_nonce)
903     asn1_addfield(val->sam_nonce,5,asn1_encode_integer);
904   asn1_addfield(&(val->sam_enc_nonce_or_ts),4,asn1_encode_encrypted_data);
905   if (val->sam_enc_key.ciphertext.length)
906     asn1_addfield(&(val->sam_enc_key),3,asn1_encode_encrypted_data);
907   add_optstring(val->sam_track_id,2,asn1_encode_charstring);
908   asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
909   asn1_addfield(val->sam_type,0,asn1_encode_integer);
910 
911   asn1_makeseq();
912 
913   asn1_cleanup();
914 }
915 
916 asn1_error_code asn1_encode_sam_response_2(asn1buf *buf, const krb5_sam_response_2 *val, unsigned int *retlen)
917 {
918   asn1_setup();
919 
920   asn1_addfield(val->sam_nonce,4,asn1_encode_integer);
921   asn1_addfield(&(val->sam_enc_nonce_or_sad),3,asn1_encode_encrypted_data);
922   add_optstring(val->sam_track_id,2,asn1_encode_charstring);
923   asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
924   asn1_addfield(val->sam_type,0,asn1_encode_integer);
925 
926   asn1_makeseq();
927 
928   asn1_cleanup();
929 }
930 
931 asn1_error_code asn1_encode_predicted_sam_response(asn1buf *buf, const krb5_predicted_sam_response *val, unsigned int *retlen)
932 {
933   asn1_setup();
934 
935   add_optstring(val->msd,6,asn1_encode_charstring);
936   asn1_addfield(val->client,5,asn1_encode_principal_name);
937   asn1_addfield(val->client,4,asn1_encode_realm);
938   asn1_addfield(val->susec,3,asn1_encode_integer);
939   asn1_addfield(val->stime,2,asn1_encode_kerberos_time);
940   asn1_addfield(val->sam_flags,1,asn1_encode_sam_flags);
941   asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);
942 
943   asn1_makeseq();
944 
945   asn1_cleanup();
946 }
947 
948 /*
949  * Do some ugliness to insert a raw pre-encoded KRB-SAFE-BODY.
950  */
951 asn1_error_code asn1_encode_krb_saved_safe_body(asn1buf *buf, const krb5_data *body, unsigned int *retlen)
952 {
953   asn1_error_code retval;
954 
955   retval = asn1buf_insert_octetstring(buf, body->length,
956 				      (krb5_octet *)body->data);
957   if (retval){
958     asn1buf_destroy(&buf);
959     return retval;
960   }
961   *retlen = body->length;
962   return 0;
963 }
964