Parse timestamp in keytab conversion.
[shishi.git] / lib / kdcreq.c
1 /* kdcreq.c --- Key distribution (AS/TGS) request functions.
2  * Copyright (C) 2002-2013 Simon Josefsson
3  *
4  * This file is part of Shishi.
5  *
6  * Shishi is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Shishi is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Shishi; if not, see http://www.gnu.org/licenses or write
18  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
19  * Floor, Boston, MA 02110-1301, USA
20  *
21  */
22
23 #include "internal.h"
24
25 /* Get _shishi_print_armored_data, etc. */
26 #include "diskio.h"
27
28 #define SHISHI_KDCREQ_DEFAULT_PVNO      "5"
29 #define SHISHI_KDCREQ_DEFAULT_PVNO_LEN  0
30 #define SHISHI_AS_REQ_DEFAULT_MSG_TYPE      "10"
31 #define SHISHI_AS_REQ_DEFAULT_MSG_TYPE_LEN  0
32 #define SHISHI_TGS_REQ_DEFAULT_MSG_TYPE      "12"
33 #define SHISHI_TGS_REQ_DEFAULT_MSG_TYPE_LEN  0
34 #define SHISHI_KDCREQ_DEFAULT_REQ_BODY_KDC_OPTIONS      "\x00\x00\x00\x00"
35 #define SHISHI_KDCREQ_DEFAULT_REQ_BODY_KDC_OPTIONS_LEN  32
36 #define SHISHI_KDCREQ_DEFAULT_REQ_BODY_SNAME_NAME_TYPE "1"      /* SHISHI_NT_PRINCIPAL */
37 #define SHISHI_KDCREQ_DEFAULT_REQ_BODY_SNAME_NAME_TYPE_LEN 0
38
39 static Shishi_asn1
40 _shishi_kdcreq (Shishi * handle, int as)
41 {
42   int res;
43   Shishi_asn1 node;
44   const char *servicebuf[3];
45   uint32_t nonce;
46
47   if (as)
48     node = shishi_asn1_asreq (handle);
49   else
50     node = shishi_asn1_tgsreq (handle);
51   if (!node)
52     return NULL;
53
54   res = shishi_asn1_write (handle, node, "pvno",
55                            SHISHI_KDCREQ_DEFAULT_PVNO,
56                            SHISHI_KDCREQ_DEFAULT_PVNO_LEN);
57   if (res != SHISHI_OK)
58     goto error;
59
60   if (as)
61     res = shishi_asn1_write (handle, node, "msg-type",
62                              SHISHI_AS_REQ_DEFAULT_MSG_TYPE,
63                              SHISHI_AS_REQ_DEFAULT_MSG_TYPE_LEN);
64   else
65     res = shishi_asn1_write (handle, node, "msg-type",
66                              SHISHI_TGS_REQ_DEFAULT_MSG_TYPE,
67                              SHISHI_TGS_REQ_DEFAULT_MSG_TYPE_LEN);
68   if (res != SHISHI_OK)
69     goto error;
70
71   res = shishi_asn1_write (handle, node, "req-body.kdc-options",
72                            SHISHI_KDCREQ_DEFAULT_REQ_BODY_KDC_OPTIONS,
73                            SHISHI_KDCREQ_DEFAULT_REQ_BODY_KDC_OPTIONS_LEN);
74   if (res != SHISHI_OK)
75     goto error;
76
77   if (as)
78     res = shishi_kdcreq_set_cname (handle, node, SHISHI_NT_PRINCIPAL,
79                                    shishi_principal_default (handle));
80   else
81     res = shishi_asn1_write (handle, node, "req-body.cname", NULL, 0);
82   if (res != SHISHI_OK)
83     goto error;
84
85   res = shishi_kdcreq_set_realm (handle, node, shishi_realm_default (handle));
86   if (res != SHISHI_OK)
87     goto error;
88
89   servicebuf[0] = "krbtgt";
90   servicebuf[1] = shishi_realm_default (handle);
91   servicebuf[2] = NULL;
92   res = shishi_kdcreq_set_sname (handle, node,
93                                  SHISHI_NT_PRINCIPAL, servicebuf);
94   if (res != SHISHI_OK)
95     goto error;
96
97   res = shishi_asn1_write (handle, node, "req-body.sname.name-type",
98                            SHISHI_KDCREQ_DEFAULT_REQ_BODY_SNAME_NAME_TYPE,
99                            SHISHI_KDCREQ_DEFAULT_REQ_BODY_SNAME_NAME_TYPE_LEN);
100   if (res != SHISHI_OK)
101     goto error;
102
103   res = shishi_asn1_write (handle, node, "req-body.till",
104                            shishi_generalize_time (handle,
105                                                    time (NULL) +
106                                                    handle->ticketlife), 0);
107   if (res != SHISHI_OK)
108     goto error;
109
110   shishi_randomize (handle, 0, &nonce, sizeof (nonce));
111   nonce &= 0x7FFFFFFF;          /* XXX fix _libtasn1_convert_integer. */
112   res = shishi_kdcreq_nonce_set (handle, node, nonce);
113   if (res != SHISHI_OK)
114     goto error;
115
116   res = shishi_kdcreq_set_etype (handle, node, handle->clientkdcetypes,
117                                  handle->nclientkdcetypes);
118   if (res != SHISHI_OK)
119     goto error;
120
121   res = shishi_asn1_write (handle, node, "req-body.addresses", NULL, 0);
122   if (res != SHISHI_OK)
123     goto error;
124
125   res = shishi_asn1_write (handle, node,
126                            "req-body.enc-authorization-data", NULL, 0);
127   if (res != SHISHI_OK)
128     goto error;
129
130   res =
131     shishi_asn1_write (handle, node, "req-body.additional-tickets", NULL, 0);
132   if (res != SHISHI_OK)
133     goto error;
134
135   return node;
136
137 error:
138   shishi_asn1_done (handle, node);
139   return NULL;
140 }
141
142 /**
143  * shishi_asreq:
144  * @handle: shishi handle as allocated by shishi_init().
145  *
146  * This function creates a new AS-REQ, populated with some default
147  * values.
148  *
149  * Return value: Returns the AS-REQ or NULL on failure.
150  **/
151 Shishi_asn1
152 shishi_asreq (Shishi * handle)
153 {
154   return _shishi_kdcreq (handle, 1);
155 }
156
157 /**
158  * shishi_tgsreq:
159  * @handle: shishi handle as allocated by shishi_init().
160  *
161  * This function creates a new TGS-REQ, populated with some default
162  * values.
163  *
164  * Return value: Returns the TGS-REQ or NULL on failure.
165  **/
166 Shishi_asn1
167 shishi_tgsreq (Shishi * handle)
168 {
169   return _shishi_kdcreq (handle, 0);
170 }
171
172 /**
173  * shishi_kdcreq_print:
174  * @handle: shishi handle as allocated by shishi_init().
175  * @fh: file handle open for writing.
176  * @kdcreq: KDC-REQ to print.
177  *
178  * Print ASCII armored DER encoding of KDC-REQ to file.
179  *
180  * Return value: Returns SHISHI_OK iff successful.
181  **/
182 int
183 shishi_kdcreq_print (Shishi * handle, FILE * fh, Shishi_asn1 kdcreq)
184 {
185   return _shishi_print_armored_data (handle, fh, kdcreq, "KDC-REQ", NULL);
186 }
187
188 /**
189  * shishi_kdcreq_save:
190  * @handle: shishi handle as allocated by shishi_init().
191  * @fh: file handle open for writing.
192  * @kdcreq: KDC-REQ to save.
193  *
194  * Print DER encoding of KDC-REQ to file.
195  *
196  * Return value: Returns SHISHI_OK iff successful.
197  **/
198 int
199 shishi_kdcreq_save (Shishi * handle, FILE * fh, Shishi_asn1 kdcreq)
200 {
201   return _shishi_save_data (handle, fh, kdcreq, "KDC-REQ");
202 }
203
204 /**
205  * shishi_kdcreq_to_file:
206  * @handle: shishi handle as allocated by shishi_init().
207  * @kdcreq: KDC-REQ to save.
208  * @filetype: input variable specifying type of file to be written,
209  *            see Shishi_filetype.
210  * @filename: input variable with filename to write to.
211  *
212  * Write KDC-REQ to file in specified TYPE.  The file will be truncated
213  * if it exists.
214  *
215  * Return value: Returns SHISHI_OK iff successful.
216  **/
217 int
218 shishi_kdcreq_to_file (Shishi * handle, Shishi_asn1 kdcreq,
219                        int filetype, const char *filename)
220 {
221   FILE *fh;
222   int res;
223
224   if (VERBOSE (handle))
225     printf (_("Writing KDC-REQ to %s...\n"), filename);
226
227   fh = fopen (filename, "w");
228   if (fh == NULL)
229     return SHISHI_FOPEN_ERROR;
230
231   if (VERBOSE (handle))
232     printf (_("Writing KDC-REQ in %s format...\n"),
233             filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
234
235   if (filetype == SHISHI_FILETYPE_TEXT)
236     res = shishi_kdcreq_print (handle, fh, kdcreq);
237   else
238     res = shishi_kdcreq_save (handle, fh, kdcreq);
239   if (res != SHISHI_OK)
240     return res;
241
242   res = fclose (fh);
243   if (res != 0)
244     return SHISHI_IO_ERROR;
245
246   if (VERBOSE (handle))
247     printf (_("Writing KDC-REQ to %s...done\n"), filename);
248
249   return SHISHI_OK;
250 }
251
252 /**
253  * shishi_kdcreq_parse:
254  * @handle: shishi handle as allocated by shishi_init().
255  * @fh: file handle open for reading.
256  * @kdcreq: output variable with newly allocated KDC-REQ.
257  *
258  * Read ASCII armored DER encoded KDC-REQ from file and populate given
259  * variable.
260  *
261  * Return value: Returns SHISHI_OK iff successful.
262  **/
263 int
264 shishi_kdcreq_parse (Shishi * handle, FILE * fh, Shishi_asn1 * kdcreq)
265 {
266   return _shishi_kdcreq_input (handle, fh, kdcreq, 0);
267 }
268
269 /**
270  * shishi_kdcreq_read:
271  * @handle: shishi handle as allocated by shishi_init().
272  * @fh: file handle open for reading.
273  * @kdcreq: output variable with newly allocated KDC-REQ.
274  *
275  * Read DER encoded KDC-REQ from file and populate given variable.
276  *
277  * Return value: Returns SHISHI_OK iff successful.
278  **/
279 int
280 shishi_kdcreq_read (Shishi * handle, FILE * fh, Shishi_asn1 * kdcreq)
281 {
282   return _shishi_kdcreq_input (handle, fh, kdcreq, 1);
283 }
284
285 /**
286  * shishi_kdcreq_from_file:
287  * @handle: shishi handle as allocated by shishi_init().
288  * @kdcreq: output variable with newly allocated KDC-REQ.
289  * @filetype: input variable specifying type of file to be read,
290  *            see Shishi_filetype.
291  * @filename: input variable with filename to read from.
292  *
293  * Read KDC-REQ from file in specified TYPE.
294  *
295  * Return value: Returns SHISHI_OK iff successful.
296  **/
297 int
298 shishi_kdcreq_from_file (Shishi * handle, Shishi_asn1 * kdcreq,
299                          int filetype, const char *filename)
300 {
301   int res;
302   FILE *fh;
303
304   if (VERBOSE (handle))
305     printf (_("Reading KDC-REQ from %s...\n"), filename);
306
307   fh = fopen (filename, "r");
308   if (fh == NULL)
309     return SHISHI_FOPEN_ERROR;
310
311   if (VERBOSE (handle))
312     printf (_("Reading KDC-REQ in %s format...\n"),
313             filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
314
315   if (filetype == SHISHI_FILETYPE_TEXT)
316     res = shishi_kdcreq_parse (handle, fh, kdcreq);
317   else
318     res = shishi_kdcreq_read (handle, fh, kdcreq);
319   if (res != SHISHI_OK)
320     return res;
321
322   res = fclose (fh);
323   if (res != 0)
324     return SHISHI_IO_ERROR;
325
326   if (VERBOSE (handle))
327     printf (_("Reading KDC-REQ from %s...done\n"), filename);
328
329   return SHISHI_OK;
330 }
331
332 int
333 shishi_kdcreq_nonce (Shishi * handle, Shishi_asn1 kdcreq, uint32_t * nonce)
334 {
335   int res;
336
337   res = shishi_asn1_read_uint32 (handle, kdcreq, "req-body.nonce", nonce);
338   if (res != SHISHI_OK)
339     return res;
340
341   return SHISHI_OK;
342 }
343
344 /**
345  * shishi_kdcreq_nonce_set:
346  * @handle: shishi handle as allocated by shishi_init().
347  * @kdcreq: KDC-REQ variable to set client name field in.
348  * @nonce: integer nonce to store in KDC-REQ.
349  *
350  * Store nonce number field in KDC-REQ.
351  *
352  * Return value: Returns %SHISHI_OK iff successful.
353  **/
354 int
355 shishi_kdcreq_nonce_set (Shishi * handle, Shishi_asn1 kdcreq, uint32_t nonce)
356 {
357   int res;
358
359   res = shishi_asn1_write_uint32 (handle, kdcreq, "req-body.nonce", nonce);
360   if (res != SHISHI_OK)
361     return res;
362
363   return SHISHI_OK;
364 }
365
366 /**
367  * shishi_kdcreq_set_cname:
368  * @handle: shishi handle as allocated by shishi_init().
369  * @kdcreq: KDC-REQ variable to set client name field in.
370  * @name_type: type of principial, see Shishi_name_type, usually
371  *             SHISHI_NT_UNKNOWN.
372  * @principal: input array with principal name.
373  *
374  * Set the client name field in the KDC-REQ.
375  *
376  * Return value: Returns SHISHI_OK iff successful.
377  **/
378 int
379 shishi_kdcreq_set_cname (Shishi * handle,
380                          Shishi_asn1 kdcreq,
381                          Shishi_name_type name_type, const char *principal)
382 {
383   int res;
384
385   res = shishi_principal_set (handle, kdcreq, "req-body.cname", principal);
386   if (res != SHISHI_OK)
387     return res;
388
389   return SHISHI_OK;
390 }
391
392 /**
393  * shishi_kdcreq_client:
394  * @handle: Shishi library handle create by shishi_init().
395  * @kdcreq: KDC-REQ variable to get client name from.
396  * @client: pointer to newly allocated zero terminated string containing
397  *   principal name.  May be %NULL (to only populate @clientlen).
398  * @clientlen: pointer to length of @client on output, excluding terminating
399  *   zero.  May be %NULL (to only populate @client).
400  *
401  * Represent client principal name in KDC-REQ as zero-terminated
402  * string.  The string is allocate by this function, and it is the
403  * responsibility of the caller to deallocate it.  Note that the
404  * output length @clientlen does not include the terminating zero.
405  *
406  * Return value: Returns SHISHI_OK iff successful.
407  **/
408 int
409 shishi_kdcreq_client (Shishi * handle, Shishi_asn1 kdcreq,
410                       char **client, size_t * clientlen)
411 {
412   return shishi_principal_name (handle, kdcreq, "req-body.cname",
413                                 client, clientlen);
414 }
415
416 /**
417  * shishi_asreq_clientrealm:
418  * @handle: Shishi library handle create by shishi_init().
419  * @asreq: AS-REQ variable to get client name and realm from.
420  * @client: pointer to newly allocated zero terminated string containing
421  *   principal name and realm.  May be %NULL (to only populate @clientlen).
422  * @clientlen: pointer to length of @client on output, excluding terminating
423  *   zero.  May be %NULL (to only populate @client).
424  *
425  * Convert cname and realm fields from AS-REQ to printable principal
426  * name format.  The string is allocate by this function, and it is
427  * the responsibility of the caller to deallocate it.  Note that the
428  * output length @clientlen does not include the terminating zero.
429  *
430  * Return value: Returns SHISHI_OK iff successful.
431  **/
432 int
433 shishi_asreq_clientrealm (Shishi * handle,
434                           Shishi_asn1 asreq,
435                           char **client, size_t * clientlen)
436 {
437   return shishi_principal_name_realm (handle,
438                                       asreq, "req-body.cname",
439                                       asreq, "req-body.realm",
440                                       client, clientlen);
441 }
442
443 /**
444  * shishi_kdcreq_realm:
445  * @handle: Shishi library handle create by shishi_init().
446  * @kdcreq: KDC-REQ variable to get client name from.
447  * @realm: pointer to newly allocated zero terminated string containing
448  *   realm.  May be %NULL (to only populate @realmlen).
449  * @realmlen: pointer to length of @realm on output, excluding terminating
450  *   zero.  May be %NULL (to only populate @realmlen).
451  *
452  * Get realm field in KDC-REQ as zero-terminated string.  The string
453  * is allocate by this function, and it is the responsibility of the
454  * caller to deallocate it.  Note that the output length @realmlen
455  * does not include the terminating zero.
456  *
457  * Return value: Returns SHISHI_OK iff successful.
458  **/
459 int
460 shishi_kdcreq_realm (Shishi * handle, Shishi_asn1 kdcreq,
461                      char **realm, size_t * realmlen)
462 {
463   return shishi_asn1_read_optional (handle, kdcreq, "req-body.realm",
464                                     realm, realmlen);
465 }
466
467 int
468 shishi_kdcreq_realm_get (Shishi * handle, Shishi_asn1 kdcreq,
469                          char **realm, size_t * realmlen)
470 {
471   return shishi_asn1_read_optional (handle, kdcreq, "req-body.realm",
472                                     realm, realmlen);
473 }
474
475 /**
476  * shishi_kdcreq_set_realm:
477  * @handle: shishi handle as allocated by shishi_init().
478  * @kdcreq: KDC-REQ variable to set realm field in.
479  * @realm: input array with name of realm.
480  *
481  * Set the realm field in the KDC-REQ.
482  *
483  * Return value: Returns SHISHI_OK iff successful.
484  **/
485 int
486 shishi_kdcreq_set_realm (Shishi * handle, Shishi_asn1 kdcreq,
487                          const char *realm)
488 {
489   int res;
490
491   res = shishi_asn1_write (handle, kdcreq, "req-body.realm", realm, 0);
492   if (res != SHISHI_OK)
493     return res;
494
495   return SHISHI_OK;
496 }
497
498 /**
499  * shishi_kdcreq_server:
500  * @handle: Shishi library handle create by shishi_init().
501  * @kdcreq: KDC-REQ variable to get server name from.
502  * @server: pointer to newly allocated zero terminated string containing
503  *   principal name.  May be %NULL (to only populate @serverlen).
504  * @serverlen: pointer to length of @server on output, excluding terminating
505  *   zero.  May be %NULL (to only populate @server).
506  *
507  * Represent server principal name in KDC-REQ as zero-terminated
508  * string.  The string is allocate by this function, and it is the
509  * responsibility of the caller to deallocate it.  Note that the
510  * output length @serverlen does not include the terminating zero.
511  *
512  * Return value: Returns SHISHI_OK iff successful.
513  **/
514 int
515 shishi_kdcreq_server (Shishi * handle, Shishi_asn1 kdcreq,
516                       char **server, size_t * serverlen)
517 {
518   return shishi_principal_name (handle, kdcreq, "req-body.sname",
519                                 server, serverlen);
520 }
521
522 /**
523  * shishi_kdcreq_set_sname:
524  * @handle: shishi handle as allocated by shishi_init().
525  * @kdcreq: KDC-REQ variable to set server name field in.
526  * @name_type: type of principial, see Shishi_name_type, usually
527  *             SHISHI_NT_UNKNOWN.
528  * @sname: input array with principal name.
529  *
530  * Set the server name field in the KDC-REQ.
531  *
532  * Return value: Returns SHISHI_OK iff successful.
533  **/
534 int
535 shishi_kdcreq_set_sname (Shishi * handle,
536                          Shishi_asn1 kdcreq,
537                          Shishi_name_type name_type, const char *sname[])
538 {
539   int res;
540
541   res = shishi_principal_name_set (handle, kdcreq, "req-body.sname",
542                                    name_type, sname);
543   if (res != SHISHI_OK)
544     return res;
545
546   return SHISHI_OK;
547 }
548
549 int
550 shishi_kdcreq_set_server (Shishi * handle, Shishi_asn1 req,
551                           const char *server)
552 {
553   int res;
554
555   res = shishi_principal_set (handle, req, "req-body.sname", server);
556   if (res != SHISHI_OK)
557     return res;
558
559   return SHISHI_OK;
560 }
561
562 int
563 shishi_kdcreq_set_realmserver (Shishi * handle,
564                                Shishi_asn1 req, char *realm, char *server)
565 {
566   int res;
567
568   res = shishi_kdcreq_set_realm (handle, req, realm);
569   if (res != SHISHI_OK)
570     return res;
571
572   res = shishi_kdcreq_set_server (handle, req, server);
573   if (res != SHISHI_OK)
574     return res;
575
576   return SHISHI_OK;
577 }
578
579 /**
580  * shishi_kdcreq_till:
581  * @handle: Shishi library handle created by shishi_init().
582  * @kdcreq: KDC-REQ variable to get endtime from.
583  * @till: pointer to newly allocated null terminated string containing
584  *   "till" field with generalized time.  May be passed as %NULL
585  *   to only populate @tilllen.
586  * @tilllen: pointer to length of @till for output, excluding the
587  *   terminating null.  Set to %NULL, only @till is populated.
588  *
589  * Get "till" field, i.e., "endtime", in KDC-REQ as a null-terminated
590  * string.  The string is typically 15 characters long and is
591  * allocated by this function. It is the responsibility of the
592  * caller to deallocate it.  Note that the output length @tilllen
593  * does not include the terminating zero.
594  *
595  * Return value: Returns SHISHI_OK iff successful.
596  **/
597 int
598 shishi_kdcreq_till (Shishi * handle, Shishi_asn1 kdcreq,
599                     char **till, size_t * tilllen)
600 {
601   return shishi_asn1_read (handle, kdcreq, "req-body.till", till, tilllen);
602 }
603
604 /**
605  * shishi_kdcreq_tillc:
606  * @handle: Shishi library handle created by shishi_init().
607  * @kdcreq: KDC-REQ variable to get "till" field from.
608  *
609  * Extract C time corresponding to the "till" field.
610  *
611  * Return value: Returns the C time interpretation of the "till"
612  * field in KDC-REQ.
613  **/
614 time_t
615 shishi_kdcreq_tillc (Shishi * handle, Shishi_asn1 kdcreq)
616 {
617   char *till;
618   size_t tilllen;
619   time_t t = (time_t) - 1;
620   int res;
621
622   res = shishi_kdcreq_till (handle, kdcreq, &till, &tilllen);
623   if (res != SHISHI_OK)
624     return t;
625
626   if (tilllen == SHISHI_GENERALIZEDTIME_LENGTH + 1)     /* XXX why +1 ? */
627     t = shishi_generalize_ctime (handle, till);
628
629   free (till);
630
631   return t;
632 }
633
634 /**
635  * shishi_kdcreq_etype:
636  * @handle: shishi handle as allocated by shishi_init().
637  * @kdcreq: KDC-REQ variable to get etype field from.
638  * @etype: output encryption type.
639  * @netype: element number to return.
640  *
641  * Return the netype:th encryption type from KDC-REQ.  The first etype
642  * is number 1.
643  *
644  * Return value: Returns SHISHI_OK iff etype successful set.
645  **/
646 int
647 shishi_kdcreq_etype (Shishi * handle,
648                      Shishi_asn1 kdcreq, int32_t * etype, int netype)
649 {
650   char *buf;
651   int res;
652
653   asprintf (&buf, "req-body.etype.?%d", netype);
654   res = shishi_asn1_read_int32 (handle, kdcreq, buf, etype);
655   if (res != SHISHI_OK)
656     return res;
657
658   return SHISHI_OK;
659 }
660
661 /**
662  * shishi_kdcreq_set_etype:
663  * @handle: shishi handle as allocated by shishi_init().
664  * @kdcreq: KDC-REQ variable to set etype field in.
665  * @etype: input array with encryption types.
666  * @netype: number of elements in input array with encryption types.
667  *
668  * Set the list of supported or wanted encryption types in the
669  * request.  The list should be sorted in priority order.
670  *
671  * Return value: Returns SHISHI_OK iff successful.
672  **/
673 int
674 shishi_kdcreq_set_etype (Shishi * handle,
675                          Shishi_asn1 kdcreq, int32_t * etype, int netype)
676 {
677   int res;
678   char *buf;
679   int i;
680
681   res = shishi_asn1_write (handle, kdcreq, "req-body.etype", NULL, 0);
682   if (res != SHISHI_OK)
683     return res;
684
685   for (i = 1; i <= netype; i++)
686     {
687       res = shishi_asn1_write (handle, kdcreq, "req-body.etype", "NEW", 1);
688       if (res != SHISHI_OK)
689         return res;
690
691       asprintf (&buf, "req-body.etype.?%d", i);
692       res = shishi_asn1_write_int32 (handle, kdcreq, buf, etype[i - 1]);
693       free (buf);
694       if (res != SHISHI_OK)
695         return res;
696     }
697
698   return SHISHI_OK;
699 }
700
701 /**
702  * shishi_kdcreq_options:
703  * @handle: shishi handle as allocated by shishi_init().
704  * @kdcreq: KDC-REQ variable to get kdc-options field from.
705  * @flags: pointer to output integer with flags.
706  *
707  * Extract KDC-Options from KDC-REQ.
708  *
709  * Return value: Returns SHISHI_OK iff successful.
710  **/
711 int
712 shishi_kdcreq_options (Shishi * handle, Shishi_asn1 kdcreq, uint32_t * flags)
713 {
714   return shishi_asn1_read_bitstring (handle, kdcreq,
715                                      "req-body.kdc-options", flags);
716 }
717
718 /**
719  * shishi_kdcreq_forwardable_p:
720  * @handle: shishi handle as allocated by shishi_init().
721  * @kdcreq: KDC-REQ variable to get kdc-options field from.
722  *
723  * Determine if KDC-Option forwardable flag is set.
724  *
725  * The FORWARDABLE option indicates that the ticket to be issued is to
726  * have its forwardable flag set. It may only be set on the initial
727  * request, or in a subsequent request if the ticket-granting ticket
728  * on which it is based is also forwardable.
729  *
730  * Return value: Returns non-0 iff forwardable flag is set in KDC-REQ.
731  **/
732 int
733 shishi_kdcreq_forwardable_p (Shishi * handle, Shishi_asn1 kdcreq)
734 {
735   uint32_t options = 0;
736
737   shishi_kdcreq_options (handle, kdcreq, &options);
738
739   return options & SHISHI_KDCOPTIONS_FORWARDABLE;
740 }
741
742 /**
743  * shishi_kdcreq_forwarded_p:
744  * @handle: shishi handle as allocated by shishi_init().
745  * @kdcreq: KDC-REQ variable to get kdc-options field from.
746  *
747  * Determine if KDC-Option forwarded flag is set.
748  *
749  * The FORWARDED option is only specified in a request to the
750  * ticket-granting server and will only be honored if the
751  * ticket-granting ticket in the request has its FORWARDABLE bit
752  * set. This option indicates that this is a request for
753  * forwarding. The address(es) of the host from which the resulting
754  * ticket is to be valid are included in the addresses field of the
755  * request.
756  *
757  * Return value: Returns non-0 iff forwarded flag is set in KDC-REQ.
758  **/
759 int
760 shishi_kdcreq_forwarded_p (Shishi * handle, Shishi_asn1 kdcreq)
761 {
762   uint32_t options = 0;
763
764   shishi_kdcreq_options (handle, kdcreq, &options);
765
766   return options & SHISHI_KDCOPTIONS_FORWARDED;
767 }
768
769 /**
770  * shishi_kdcreq_proxiable_p:
771  * @handle: shishi handle as allocated by shishi_init().
772  * @kdcreq: KDC-REQ variable to get kdc-options field from.
773  *
774  * Determine if KDC-Option proxiable flag is set.
775  *
776  * The PROXIABLE option indicates that the ticket to be issued is to
777  * have its proxiable flag set. It may only be set on the initial
778  * request, or in a subsequent request if the ticket-granting ticket
779  * on which it is based is also proxiable.
780  *
781  * Return value: Returns non-0 iff proxiable flag is set in KDC-REQ.
782  **/
783 int
784 shishi_kdcreq_proxiable_p (Shishi * handle, Shishi_asn1 kdcreq)
785 {
786   uint32_t options = 0;
787
788   shishi_kdcreq_options (handle, kdcreq, &options);
789
790   return options & SHISHI_KDCOPTIONS_PROXIABLE;
791 }
792
793 /**
794  * shishi_kdcreq_proxy_p:
795  * @handle: shishi handle as allocated by shishi_init().
796  * @kdcreq: KDC-REQ variable to get kdc-options field from.
797  *
798  * Determine if KDC-Option proxy flag is set.
799  *
800  * The PROXY option indicates that this is a request for a proxy. This
801  * option will only be honored if the ticket-granting ticket in the
802  * request has its PROXIABLE bit set.  The address(es) of the host
803  * from which the resulting ticket is to be valid are included in the
804  * addresses field of the request.
805  *
806  * Return value: Returns non-0 iff proxy flag is set in KDC-REQ.
807  **/
808 int
809 shishi_kdcreq_proxy_p (Shishi * handle, Shishi_asn1 kdcreq)
810 {
811   uint32_t options = 0;
812
813   shishi_kdcreq_options (handle, kdcreq, &options);
814
815   return options & SHISHI_KDCOPTIONS_PROXY;
816 }
817
818 /**
819  * shishi_kdcreq_allow_postdate_p:
820  * @handle: shishi handle as allocated by shishi_init().
821  * @kdcreq: KDC-REQ variable to get kdc-options field from.
822  *
823  * Determine if KDC-Option allow-postdate flag is set.
824  *
825  * The ALLOW-POSTDATE option indicates that the ticket to be issued is
826  * to have its MAY-POSTDATE flag set. It may only be set on the
827  * initial request, or in a subsequent request if the ticket-granting
828  * ticket on which it is based also has its MAY-POSTDATE flag set.
829  *
830  * Return value: Returns non-0 iff allow-postdate flag is set in KDC-REQ.
831  **/
832 int
833 shishi_kdcreq_allow_postdate_p (Shishi * handle, Shishi_asn1 kdcreq)
834 {
835   uint32_t options = 0;
836
837   shishi_kdcreq_options (handle, kdcreq, &options);
838
839   return options & SHISHI_KDCOPTIONS_ALLOW_POSTDATE;
840 }
841
842 /**
843  * shishi_kdcreq_postdated_p:
844  * @handle: shishi handle as allocated by shishi_init().
845  * @kdcreq: KDC-REQ variable to get kdc-options field from.
846  *
847  * Determine if KDC-Option postdated flag is set.
848  *
849  * The POSTDATED option indicates that this is a request for a
850  * postdated ticket. This option will only be honored if the
851  * ticket-granting ticket on which it is based has its MAY-POSTDATE
852  * flag set. The resulting ticket will also have its INVALID flag set,
853  * and that flag may be reset by a subsequent request to the KDC after
854  * the starttime in the ticket has been reached.
855  *
856  * Return value: Returns non-0 iff postdated flag is set in KDC-REQ.
857  **/
858 int
859 shishi_kdcreq_postdated_p (Shishi * handle, Shishi_asn1 kdcreq)
860 {
861   uint32_t options = 0;
862
863   shishi_kdcreq_options (handle, kdcreq, &options);
864
865   return options & SHISHI_KDCOPTIONS_POSTDATED;
866 }
867
868 /**
869  * shishi_kdcreq_renewable_p:
870  * @handle: shishi handle as allocated by shishi_init().
871  * @kdcreq: KDC-REQ variable to get kdc-options field from.
872  *
873  * Determine if KDC-Option renewable flag is set.
874  *
875  * The RENEWABLE option indicates that the ticket to be issued is to
876  * have its RENEWABLE flag set. It may only be set on the initial
877  * request, or when the ticket-granting ticket on which the request is
878  * based is also renewable. If this option is requested, then the
879  * rtime field in the request contains the desired absolute expiration
880  * time for the ticket.
881  *
882  * Return value: Returns non-0 iff renewable flag is set in KDC-REQ.
883  **/
884 int
885 shishi_kdcreq_renewable_p (Shishi * handle, Shishi_asn1 kdcreq)
886 {
887   uint32_t options = 0;
888
889   shishi_kdcreq_options (handle, kdcreq, &options);
890
891   return options & SHISHI_KDCOPTIONS_RENEWABLE;
892 }
893
894 /**
895  * shishi_kdcreq_disable_transited_check_p:
896  * @handle: shishi handle as allocated by shishi_init().
897  * @kdcreq: KDC-REQ variable to get kdc-options field from.
898  *
899  * Determine if KDC-Option disable-transited-check flag is set.
900  *
901  * By default the KDC will check the transited field of a
902  * ticket-granting-ticket against the policy of the local realm before
903  * it will issue derivative tickets based on the ticket-granting
904  * ticket. If this flag is set in the request, checking of the
905  * transited field is disabled. Tickets issued without the performance
906  * of this check will be noted by the reset (0) value of the
907  * TRANSITED-POLICY-CHECKED flag, indicating to the application server
908  * that the tranisted field must be checked locally. KDCs are
909  * encouraged but not required to honor the DISABLE-TRANSITED-CHECK
910  * option.
911  *
912  * This flag is new since RFC 1510
913  *
914  * Return value: Returns non-0 iff disable-transited-check flag is set
915  *   in KDC-REQ.
916  **/
917 int
918 shishi_kdcreq_disable_transited_check_p (Shishi * handle, Shishi_asn1 kdcreq)
919 {
920   uint32_t options = 0;
921
922   shishi_kdcreq_options (handle, kdcreq, &options);
923
924   return options & SHISHI_KDCOPTIONS_DISABLE_TRANSITED_CHECK;
925 }
926
927 /**
928  * shishi_kdcreq_renewable_ok_p:
929  * @handle: shishi handle as allocated by shishi_init().
930  * @kdcreq: KDC-REQ variable to get kdc-options field from.
931  *
932  * Determine if KDC-Option renewable-ok flag is set.
933  *
934  * The RENEWABLE-OK option indicates that a renewable ticket will be
935  * acceptable if a ticket with the requested life cannot otherwise be
936  * provided. If a ticket with the requested life cannot be provided,
937  * then a renewable ticket may be issued with a renew-till equal to
938  * the requested endtime. The value of the renew-till field may still
939  * be limited by local limits, or limits selected by the individual
940  * principal or server.
941  *
942  * Return value: Returns non-0 iff renewable-ok flag is set in KDC-REQ.
943  **/
944 int
945 shishi_kdcreq_renewable_ok_p (Shishi * handle, Shishi_asn1 kdcreq)
946 {
947   uint32_t options = 0;
948
949   shishi_kdcreq_options (handle, kdcreq, &options);
950
951   return options & SHISHI_KDCOPTIONS_RENEWABLE_OK;
952 }
953
954 /**
955  * shishi_kdcreq_enc_tkt_in_skey_p:
956  * @handle: shishi handle as allocated by shishi_init().
957  * @kdcreq: KDC-REQ variable to get kdc-options field from.
958  *
959  * Determine if KDC-Option enc-tkt-in-skey flag is set.
960  *
961  * This option is used only by the ticket-granting service. The
962  * ENC-TKT-IN-SKEY option indicates that the ticket for the end server
963  * is to be encrypted in the session key from the additional
964  * ticket-granting ticket provided.
965  *
966  * Return value: Returns non-0 iff enc-tkt-in-skey flag is set in KDC-REQ.
967  **/
968 int
969 shishi_kdcreq_enc_tkt_in_skey_p (Shishi * handle, Shishi_asn1 kdcreq)
970 {
971   uint32_t options = 0;
972
973   shishi_kdcreq_options (handle, kdcreq, &options);
974
975   return options & SHISHI_KDCOPTIONS_ENC_TKT_IN_SKEY;
976 }
977
978 /**
979  * shishi_kdcreq_renew_p:
980  * @handle: shishi handle as allocated by shishi_init().
981  * @kdcreq: KDC-REQ variable to get kdc-options field from.
982  *
983  * Determine if KDC-Option renew flag is set.
984  *
985  * This option is used only by the ticket-granting service. The RENEW
986  * option indicates that the present request is for a renewal. The
987  * ticket provided is encrypted in the secret key for the server on
988  * which it is valid. This option will only be honored if the ticket
989  * to be renewed has its RENEWABLE flag set and if the time in its
990  * renew-till field has not passed. The ticket to be renewed is passed
991  * in the padata field as part of the authentication header.
992  *
993  * Return value: Returns non-0 iff renew flag is set in KDC-REQ.
994  **/
995 int
996 shishi_kdcreq_renew_p (Shishi * handle, Shishi_asn1 kdcreq)
997 {
998   uint32_t options = 0;
999
1000   shishi_kdcreq_options (handle, kdcreq, &options);
1001
1002   return options & SHISHI_KDCOPTIONS_RENEW;
1003 }
1004
1005 /**
1006  * shishi_kdcreq_validate_p:
1007  * @handle: shishi handle as allocated by shishi_init().
1008  * @kdcreq: KDC-REQ variable to get kdc-options field from.
1009  *
1010  * Determine if KDC-Option validate flag is set.
1011  *
1012  * This option is used only by the ticket-granting service. The
1013  * VALIDATE option indicates that the request is to validate a
1014  * postdated ticket. It will only be honored if the ticket presented
1015  * is postdated, presently has its INVALID flag set, and would be
1016  * otherwise usable at this time. A ticket cannot be validated before
1017  * its starttime. The ticket presented for validation is encrypted in
1018  * the key of the server for which it is valid and is passed in the
1019  * padata field as part of the authentication header.
1020  *
1021  * Return value: Returns non-0 iff validate flag is set in KDC-REQ.
1022  **/
1023 int
1024 shishi_kdcreq_validate_p (Shishi * handle, Shishi_asn1 kdcreq)
1025 {
1026   uint32_t options = 0;
1027
1028   shishi_kdcreq_options (handle, kdcreq, &options);
1029
1030   return options & SHISHI_KDCOPTIONS_VALIDATE;
1031 }
1032
1033 /**
1034  * shishi_kdcreq_options_set:
1035  * @handle: shishi handle as allocated by shishi_init().
1036  * @kdcreq: KDC-REQ variable to set etype field in.
1037  * @options: integer with flags to store in KDC-REQ.
1038  *
1039  * Set options in KDC-REQ.  Note that this reset any already existing
1040  * flags.
1041  *
1042  * Return value: Returns SHISHI_OK iff successful.
1043  **/
1044 int
1045 shishi_kdcreq_options_set (Shishi * handle,
1046                            Shishi_asn1 kdcreq, uint32_t options)
1047 {
1048   int res;
1049
1050   res = shishi_asn1_write_bitstring (handle, kdcreq,
1051                                      "req-body.kdc-options", options);
1052   if (res != SHISHI_OK)
1053     return res;
1054
1055   return SHISHI_OK;
1056 }
1057
1058 /**
1059  * shishi_kdcreq_options_add:
1060  * @handle: shishi handle as allocated by shishi_init().
1061  * @kdcreq: KDC-REQ variable to set etype field in.
1062  * @option: integer with options to add in KDC-REQ.
1063  *
1064  * Add KDC-Option to KDC-REQ.  This preserves all existing options.
1065  *
1066  * Return value: Returns SHISHI_OK iff successful.
1067  **/
1068 int
1069 shishi_kdcreq_options_add (Shishi * handle,
1070                            Shishi_asn1 kdcreq, uint32_t option)
1071 {
1072   uint32_t options;
1073   int res;
1074
1075   res = shishi_kdcreq_options (handle, kdcreq, &options);
1076   if (res != SHISHI_OK)
1077     return res;
1078
1079   options |= option;
1080
1081   res = shishi_kdcreq_options_set (handle, kdcreq, options);
1082   if (res != SHISHI_OK)
1083     return res;
1084
1085   return SHISHI_OK;
1086 }
1087
1088 /**
1089  * shishi_kdcreq_clear_padata:
1090  * @handle: shishi handle as allocated by shishi_init().
1091  * @kdcreq: KDC-REQ to remove PA-DATA from.
1092  *
1093  * Remove the padata field from KDC-REQ.
1094  *
1095  * Return value: Returns SHISHI_OK iff successful.
1096  **/
1097 int
1098 shishi_kdcreq_clear_padata (Shishi * handle, Shishi_asn1 kdcreq)
1099 {
1100   int res;
1101
1102   res = shishi_asn1_write (handle, kdcreq, "padata", NULL, 0);
1103   if (res != SHISHI_OK)
1104     return res;
1105
1106   return SHISHI_OK;
1107 }
1108
1109 /**
1110  * shishi_kdcreq_get_padata:
1111  * @handle: shishi handle as allocated by shishi_init().
1112  * @kdcreq: KDC-REQ to get PA-DATA from.
1113  * @padatatype: type of PA-DATA, see Shishi_padata_type.
1114  * @out: output array with newly allocated PA-DATA value.
1115  * @outlen: size of output array with PA-DATA value.
1116  *
1117  * Get pre authentication data (PA-DATA) from KDC-REQ.  Pre
1118  * authentication data is used to pass various information to KDC,
1119  * such as in case of a SHISHI_PA_TGS_REQ padatatype the AP-REQ that
1120  * authenticates the user to get the ticket.
1121  *
1122  * Return value: Returns SHISHI_OK iff successful.
1123  **/
1124 int
1125 shishi_kdcreq_get_padata (Shishi * handle,
1126                           Shishi_asn1 kdcreq,
1127                           Shishi_padata_type padatatype,
1128                           char **out, size_t * outlen)
1129 {
1130   char *format;
1131   int res;
1132   size_t i, n;
1133
1134   res = shishi_asn1_number_of_elements (handle, kdcreq, "padata", &n);
1135   if (res != SHISHI_OK)
1136     return res;
1137
1138   *out = NULL;
1139   *outlen = 0;
1140
1141   for (i = 1; i <= n; i++)
1142     {
1143       int32_t patype;
1144
1145       asprintf (&format, "padata.?%d.padata-type", i);
1146       res = shishi_asn1_read_int32 (handle, kdcreq, format, &patype);
1147       free (format);
1148       if (res != SHISHI_OK)
1149         return res;
1150
1151       if (patype == (int32_t) padatatype)
1152         {
1153           asprintf (&format, "padata.?%d.padata-value", i);
1154           res = shishi_asn1_read (handle, kdcreq, format, out, outlen);
1155           free (format);
1156           if (res != SHISHI_OK)
1157             return res;
1158           break;
1159         }
1160     }
1161
1162   return SHISHI_OK;
1163 }
1164
1165 /**
1166  * shishi_kdcreq_get_padata_tgs:
1167  * @handle: shishi handle as allocated by shishi_init().
1168  * @kdcreq: KDC-REQ to get PA-TGS-REQ from.
1169  * @apreq: Output variable with newly allocated AP-REQ.
1170  *
1171  * Extract TGS pre-authentication data from KDC-REQ.  The data is an
1172  * AP-REQ that authenticates the request.  This function call
1173  * shishi_kdcreq_get_padata() with a SHISHI_PA_TGS_REQ padatatype and
1174  * DER decode the result (if any).
1175  *
1176  * Return value: Returns SHISHI_OK iff successful.
1177  **/
1178 int
1179 shishi_kdcreq_get_padata_tgs (Shishi * handle,
1180                               Shishi_asn1 kdcreq, Shishi_asn1 * apreq)
1181 {
1182   char *der;
1183   size_t derlen;
1184   int rc;
1185
1186   if (VERBOSE (handle))
1187     printf ("Extracting AP-REQ from KDC-REQ...\n");
1188
1189   rc = shishi_kdcreq_get_padata (handle, kdcreq, SHISHI_PA_TGS_REQ,
1190                                  &der, &derlen);
1191   if (rc != SHISHI_OK)
1192     return rc;
1193
1194   *apreq = shishi_der2asn1_apreq (handle, der, derlen);
1195   if (!*apreq)
1196     return SHISHI_ASN1_ERROR;
1197
1198   if (VERBOSEASN1 (handle))
1199     shishi_apreq_print (handle, stdout, *apreq);
1200
1201   return SHISHI_OK;
1202 }
1203
1204 /**
1205  * shishi_kdcreq_add_padata:
1206  * @handle: shishi handle as allocated by shishi_init().
1207  * @kdcreq: KDC-REQ to add PA-DATA to.
1208  * @padatatype: type of PA-DATA, see Shishi_padata_type.
1209  * @data: input array with PA-DATA value.
1210  * @datalen: size of input array with PA-DATA value.
1211  *
1212  * Add new pre authentication data (PA-DATA) to KDC-REQ.  This is used
1213  * to pass various information to KDC, such as in case of a
1214  * SHISHI_PA_TGS_REQ padatatype the AP-REQ that authenticates the user
1215  * to get the ticket.  (But also see shishi_kdcreq_add_padata_tgs()
1216  * which takes an AP-REQ directly.)
1217  *
1218  * Return value: Returns SHISHI_OK iff successful.
1219  **/
1220 int
1221 shishi_kdcreq_add_padata (Shishi * handle,
1222                           Shishi_asn1 kdcreq,
1223                           int padatatype, const char *data, size_t datalen)
1224 {
1225   char *format;
1226   int res;
1227   size_t i;
1228
1229   res = shishi_asn1_write (handle, kdcreq, "padata", "NEW", 1);
1230   if (res != SHISHI_OK)
1231     return res;
1232
1233   res = shishi_asn1_number_of_elements (handle, kdcreq, "padata", &i);
1234   if (res != SHISHI_OK)
1235     return res;
1236
1237   asprintf (&format, "padata.?%d.padata-value", i);
1238   res = shishi_asn1_write (handle, kdcreq, format, data, datalen);
1239   free (format);
1240   if (res != SHISHI_OK)
1241     return res;
1242
1243   asprintf (&format, "padata.?%d.padata-type", i);
1244   res = shishi_asn1_write_uint32 (handle, kdcreq, format, padatatype);
1245   free (format);
1246   if (res != SHISHI_OK)
1247     return res;
1248
1249   return SHISHI_OK;
1250 }
1251
1252 /**
1253  * shishi_kdcreq_add_padata_tgs:
1254  * @handle: shishi handle as allocated by shishi_init().
1255  * @kdcreq: KDC-REQ to add PA-DATA to.
1256  * @apreq: AP-REQ to add as PA-DATA.
1257  *
1258  * Add TGS pre-authentication data to KDC-REQ.  The data is an AP-REQ
1259  * that authenticates the request.  This functions simply DER encodes
1260  * the AP-REQ and calls shishi_kdcreq_add_padata() with a
1261  * SHISHI_PA_TGS_REQ padatatype.
1262  *
1263  * Return value: Returns SHISHI_OK iff successful.
1264  **/
1265 int
1266 shishi_kdcreq_add_padata_tgs (Shishi * handle,
1267                               Shishi_asn1 kdcreq, Shishi_asn1 apreq)
1268 {
1269   int res;
1270   char *data;
1271   size_t datalen;
1272
1273   res = shishi_asn1_to_der (handle, apreq, &data, &datalen);
1274   if (res != SHISHI_OK)
1275     {
1276       shishi_error_printf (handle, "Could not DER encode AP-REQ: %s\n",
1277                            shishi_strerror (res));
1278       return res;
1279     }
1280
1281   res = shishi_kdcreq_add_padata (handle, kdcreq,
1282                                   SHISHI_PA_TGS_REQ, data, datalen);
1283   free (data);
1284   if (res != SHISHI_OK)
1285     return res;
1286
1287   return res;
1288 }
1289
1290 /**
1291  * shishi_kdcreq_add_padata_preauth:
1292  * @handle: shishi handle as allocated by shishi_init().
1293  * @kdcreq: KDC-REQ to add pre-authentication data to.
1294  * @key: Key used to encrypt pre-auth data.
1295  *
1296  * Add pre-authentication data to KDC-REQ.
1297  *
1298  * Return value: Returns SHISHI_OK iff successful.
1299  **/
1300 int
1301 shishi_kdcreq_add_padata_preauth (Shishi * handle,
1302                                   Shishi_asn1 kdcreq, Shishi_key * key)
1303 {
1304   char *der, *data;
1305   size_t derlen, datalen;
1306   Shishi_asn1 pa;
1307   struct timeval tv;
1308   int rc;
1309   Shishi_asn1 ed;
1310
1311   pa = shishi_asn1_pa_enc_ts_enc (handle);
1312   if (!pa)
1313     return SHISHI_ASN1_ERROR;
1314
1315   rc = gettimeofday (&tv, NULL);
1316   if (rc != 0)
1317     return SHISHI_GETTIMEOFDAY_ERROR;
1318
1319   rc = shishi_asn1_write (handle, pa, "patimestamp",
1320                           shishi_generalize_time (handle, tv.tv_sec),
1321                           SHISHI_GENERALIZEDTIME_LENGTH);
1322   if (rc != SHISHI_OK)
1323     return rc;
1324
1325   rc = shishi_asn1_write_integer (handle, pa, "pausec", tv.tv_usec);
1326   if (rc != SHISHI_OK)
1327     return rc;
1328
1329   rc = shishi_asn1_to_der (handle, pa, &der, &derlen);
1330   if (rc != SHISHI_OK)
1331     return rc;
1332
1333   rc = shishi_encrypt (handle, key, SHISHI_KEYUSAGE_ASREQ_PA_ENC_TIMESTAMP,
1334                        der, derlen, &data, &datalen);
1335   free (der);
1336   if (rc != SHISHI_OK)
1337     return rc;
1338
1339   ed = shishi_asn1_encrypteddata (handle);
1340   if (!ed)
1341     return SHISHI_ASN1_ERROR;
1342
1343   rc = shishi_asn1_write_integer (handle, ed, "etype", shishi_key_type (key));
1344   if (rc != SHISHI_OK)
1345     return rc;
1346
1347   rc = shishi_asn1_write (handle, ed, "cipher", data, datalen);
1348   if (rc != SHISHI_OK)
1349     return rc;
1350
1351   rc = shishi_asn1_write (handle, ed, "kvno", NULL, 0);
1352   if (rc != SHISHI_OK)
1353     return rc;
1354
1355   rc = shishi_asn1_to_der (handle, ed, &der, &derlen);
1356   free (data);
1357   if (rc != SHISHI_OK)
1358     return rc;
1359
1360   rc = shishi_kdcreq_add_padata (handle, kdcreq, SHISHI_PA_ENC_TIMESTAMP,
1361                                  der, derlen);
1362   free (der);
1363   if (rc != SHISHI_OK)
1364     return rc;
1365
1366   return rc;
1367 }
1368
1369 int
1370 shishi_kdcreq_build (Shishi * handle, Shishi_asn1 kdcreq)
1371 {
1372   int res;
1373   size_t n;
1374   int msgtype;
1375
1376   shishi_verbose (handle, "Building KDC-REQ...");
1377
1378   if (shishi_asn1_empty_p (handle, kdcreq, "req-body.rtime"))
1379     {
1380       res = shishi_asn1_write (handle, kdcreq, "req-body.rtime", NULL, 0);
1381       if (res != SHISHI_OK)
1382         {
1383           shishi_error_printf (handle, "Could not write rtime\n");
1384           return res;
1385         }
1386     }
1387
1388   if (shishi_asn1_empty_p (handle, kdcreq, "req-body.from"))
1389     {
1390       res = shishi_asn1_write (handle, kdcreq, "req-body.from", NULL, 0);
1391       if (res != SHISHI_OK)
1392         {
1393           shishi_error_printf (handle, "Could not write from\n");
1394           return res;
1395         }
1396     }
1397
1398   res = shishi_asn1_read_integer (handle, kdcreq, "msg-type", &msgtype);
1399   if (res != SHISHI_OK)
1400     return res;
1401   if (msgtype == SHISHI_MSGTYPE_AS_REQ)
1402     {
1403       res = shishi_asn1_number_of_elements (handle, kdcreq, "padata", &n);
1404       if (res == SHISHI_OK && n == 0)
1405         {
1406           res = shishi_kdcreq_clear_padata (handle, kdcreq);
1407           if (res != SHISHI_OK)
1408             {
1409               shishi_error_printf (handle, "Could not write padata\n");
1410               return res;
1411             }
1412         }
1413     }
1414
1415   return SHISHI_OK;
1416 }