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
_shishi_kdcreq(Shishi * handle,int as)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
shishi_asreq(Shishi * handle)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
shishi_tgsreq(Shishi * handle)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
shishi_kdcreq_print(Shishi * handle,FILE * fh,Shishi_asn1 kdcreq)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
shishi_kdcreq_save(Shishi * handle,FILE * fh,Shishi_asn1 kdcreq)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
shishi_kdcreq_to_file(Shishi * handle,Shishi_asn1 kdcreq,int filetype,const char * filename)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
shishi_kdcreq_parse(Shishi * handle,FILE * fh,Shishi_asn1 * kdcreq)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
shishi_kdcreq_read(Shishi * handle,FILE * fh,Shishi_asn1 * kdcreq)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
shishi_kdcreq_from_file(Shishi * handle,Shishi_asn1 * kdcreq,int filetype,const char * filename)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
shishi_kdcreq_nonce(Shishi * handle,Shishi_asn1 kdcreq,uint32_t * nonce)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
shishi_kdcreq_nonce_set(Shishi * handle,Shishi_asn1 kdcreq,uint32_t nonce)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
shishi_kdcreq_set_cname(Shishi * handle,Shishi_asn1 kdcreq,Shishi_name_type name_type,const char * principal)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
shishi_kdcreq_client(Shishi * handle,Shishi_asn1 kdcreq,char ** client,size_t * clientlen)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
shishi_asreq_clientrealm(Shishi * handle,Shishi_asn1 asreq,char ** client,size_t * clientlen)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
shishi_kdcreq_realm(Shishi * handle,Shishi_asn1 kdcreq,char ** realm,size_t * realmlen)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
shishi_kdcreq_realm_get(Shishi * handle,Shishi_asn1 kdcreq,char ** realm,size_t * realmlen)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
shishi_kdcreq_set_realm(Shishi * handle,Shishi_asn1 kdcreq,const char * realm)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
shishi_kdcreq_server(Shishi * handle,Shishi_asn1 kdcreq,char ** server,size_t * serverlen)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
shishi_kdcreq_set_sname(Shishi * handle,Shishi_asn1 kdcreq,Shishi_name_type name_type,const char * sname[])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
shishi_kdcreq_set_server(Shishi * handle,Shishi_asn1 req,const char * server)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
shishi_kdcreq_set_realmserver(Shishi * handle,Shishi_asn1 req,char * realm,char * server)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 create by shishi_init().
582  * @kdcreq: KDC-REQ variable to get client name from.
583  * @till: pointer to newly allocated zero terminated string containing
584  *   "till" field with generalized time.  May be %NULL (to only
585  *   populate @realmlen).
586  * @tilllen: pointer to length of @till on output, excluding
587  *   terminating zero.  May be %NULL (to only populate @tilllen).
588  *
589  * Get "till" field (i.e. "endtime") in KDC-REQ, as zero-terminated
590  * string.  The string is typically 15 characters long.  The string is
591  * allocated by this function, and it is the responsibility of the
592  * caller to deallocate it.  Note that the output length @realmlen
593  * does not include the terminating zero.
594  *
595  * Return value: Returns SHISHI_OK iff successful.
596  **/
597 int
shishi_kdcreq_till(Shishi * handle,Shishi_asn1 kdcreq,char ** till,size_t * tilllen)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 create 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 C time interpretation of the "till" field in
612  * KDC-REQ.
613  **/
614 time_t
shishi_kdcreq_tillc(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_etype(Shishi * handle,Shishi_asn1 kdcreq,int32_t * etype,int netype)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
shishi_kdcreq_set_etype(Shishi * handle,Shishi_asn1 kdcreq,int32_t * etype,int netype)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
shishi_kdcreq_options(Shishi * handle,Shishi_asn1 kdcreq,uint32_t * flags)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
shishi_kdcreq_forwardable_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_forwarded_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_proxiable_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_proxy_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_allow_postdate_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_postdated_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_renewable_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_disable_transited_check_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_renewable_ok_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_enc_tkt_in_skey_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_renew_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_validate_p(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_options_set(Shishi * handle,Shishi_asn1 kdcreq,uint32_t options)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
shishi_kdcreq_options_add(Shishi * handle,Shishi_asn1 kdcreq,uint32_t option)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
shishi_kdcreq_clear_padata(Shishi * handle,Shishi_asn1 kdcreq)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
shishi_kdcreq_get_padata(Shishi * handle,Shishi_asn1 kdcreq,Shishi_padata_type padatatype,char ** out,size_t * outlen)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
shishi_kdcreq_get_padata_tgs(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 * apreq)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
shishi_kdcreq_add_padata(Shishi * handle,Shishi_asn1 kdcreq,int padatatype,const char * data,size_t datalen)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
shishi_kdcreq_add_padata_tgs(Shishi * handle,Shishi_asn1 kdcreq,Shishi_asn1 apreq)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
shishi_kdcreq_add_padata_preauth(Shishi * handle,Shishi_asn1 kdcreq,Shishi_key * key)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
shishi_kdcreq_build(Shishi * handle,Shishi_asn1 kdcreq)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 }
1417