1 /* as.c --- High level client AS 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 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 but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * 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 struct Shishi_as
26 {
27   Shishi *handle;
28   Shishi_asn1 asreq;
29   Shishi_asn1 asrep;
30   Shishi_asn1 krberror;
31   Shishi_tkt *tkt;
32 };
33 
34 /**
35  * shishi_as:
36  * @handle: shishi handle as allocated by shishi_init().
37  * @as: holds pointer to newly allocate Shishi_as structure.
38  *
39  * Allocate a new AS exchange variable.
40  *
41  * Return value: Returns SHISHI_OK iff successful.
42  **/
43 int
shishi_as(Shishi * handle,Shishi_as ** as)44 shishi_as (Shishi * handle, Shishi_as ** as)
45 {
46   Shishi_as *las;
47   int res;
48 
49   *as = xmalloc (sizeof (**as));
50   las = *as;
51   memset (las, 0, sizeof (*las));
52 
53   las->handle = handle;
54 
55   las->asreq = shishi_asreq (handle);
56   if (las->asreq == NULL)
57     {
58       shishi_error_printf (handle, "Could not create AS-REQ: %s\n",
59 			   shishi_error (handle));
60       return SHISHI_ASN1_ERROR;
61     }
62 
63   las->asrep = shishi_asrep (handle);
64   if (las->asrep == NULL)
65     {
66       shishi_error_printf (handle, "Could not create AS-REP: %s\n",
67 			   shishi_error (handle));
68       return SHISHI_ASN1_ERROR;
69     }
70 
71   las->krberror = shishi_krberror (handle);
72   if (las->krberror == NULL)
73     {
74       shishi_error_printf (handle, "Could not create KRB-ERROR: %s\n",
75 			   shishi_error (handle));
76       return SHISHI_ASN1_ERROR;
77     }
78 
79   res = shishi_tkt (handle, &las->tkt);
80   if (res != SHISHI_OK)
81     return res;
82 
83   res = shishi_tkt_flags_set (las->tkt, SHISHI_TICKETFLAGS_INITIAL);
84   if (res != SHISHI_OK)
85     return res;
86 
87   return SHISHI_OK;
88 }
89 
90 /**
91  * shishi_as_done:
92  * @as: structure that holds information about AS exchange
93  *
94  * Deallocate resources associated with AS exchange.  This should be
95  * called by the application when it no longer need to utilize the AS
96  * exchange handle.
97  **/
98 void
shishi_as_done(Shishi_as * as)99 shishi_as_done (Shishi_as * as)
100 {
101   shishi_asn1_done (as->handle, as->asreq);
102   shishi_asn1_done (as->handle, as->asrep);
103   shishi_asn1_done (as->handle, as->krberror);
104   shishi_tkt_done (as->tkt);
105   free (as);
106 }
107 
108 /* TODO: add shishi_as_clientserver(h,p,a,client,server) and make the
109    shishi_as_cnamerealmsname function take real cname/sname pointer
110    arrays. */
111 
112 /**
113  * shishi_as_req:
114  * @as: structure that holds information about AS exchange
115  *
116  * Get ASN.1 AS-REQ structure from AS exchange.
117  *
118  * Return value: Returns the generated AS-REQ packet from the AS
119  *               exchange, or NULL if not yet set or an error occured.
120  **/
121 Shishi_asn1
shishi_as_req(Shishi_as * as)122 shishi_as_req (Shishi_as * as)
123 {
124   return as->asreq;
125 }
126 
127 /**
128  * shishi_as_req_build:
129  * @as: structure that holds information about AS exchange
130  *
131  * Possibly remove unset fields (e.g., rtime).
132  *
133  * Return value: Returns SHISHI_OK iff successful.
134  **/
135 int
shishi_as_req_build(Shishi_as * as)136 shishi_as_req_build (Shishi_as * as)
137 {
138   int res;
139 
140   res = shishi_kdcreq_build (as->handle, as->asreq);
141   if (res != SHISHI_OK)
142     return res;
143 
144   return SHISHI_OK;
145 }
146 
147 /**
148  * shishi_as_req_set:
149  * @as: structure that holds information about AS exchange
150  * @asreq: asreq to store in AS.
151  *
152  * Set the AS-REQ in the AS exchange.
153  **/
154 void
shishi_as_req_set(Shishi_as * as,Shishi_asn1 asreq)155 shishi_as_req_set (Shishi_as * as, Shishi_asn1 asreq)
156 {
157   if (as->asreq)
158     shishi_asn1_done (as->handle, as->asreq);
159   as->asreq = asreq;
160 }
161 
162 /**
163  * shishi_as_req_der:
164  * @as: structure that holds information about AS exchange
165  * @out: output array with newly allocated DER encoding of AS-REQ.
166  * @outlen: length of output array with DER encoding of AS-REQ.
167  *
168  * DER encode AS-REQ.  @out is allocated by this function, and it is
169  * the responsibility of caller to deallocate it.
170  *
171  * Return value: Returns SHISHI_OK iff successful.
172  **/
173 int
shishi_as_req_der(Shishi_as * as,char ** out,size_t * outlen)174 shishi_as_req_der (Shishi_as * as, char **out, size_t * outlen)
175 {
176   int rc;
177 
178   rc = shishi_asn1_to_der (as->handle, as->asreq, out, outlen);
179   if (rc != SHISHI_OK)
180     return rc;
181 
182   return SHISHI_OK;
183 }
184 
185 /**
186  * shishi_as_req_der_set:
187  * @as: structure that holds information about AS exchange
188  * @der: input array with DER encoded AP-REQ.
189  * @derlen: length of input array with DER encoded AP-REQ.
190  *
191  * DER decode AS-REQ and set it AS exchange.  If decoding fails, the
192  * AS-REQ in the AS exchange remains.
193  *
194  * Return value: Returns SHISHI_OK.
195  **/
196 int
shishi_as_req_der_set(Shishi_as * as,char * der,size_t derlen)197 shishi_as_req_der_set (Shishi_as * as, char *der, size_t derlen)
198 {
199   Shishi_asn1 asreq;
200 
201   asreq = shishi_der2asn1_asreq (as->handle, der, derlen);
202 
203   if (asreq == NULL)
204     return SHISHI_ASN1_ERROR;
205 
206   as->asreq = asreq;
207 
208   return SHISHI_OK;
209 }
210 
211 /**
212  * shishi_as_rep:
213  * @as: structure that holds information about AS exchange
214  *
215  * Get ASN.1 AS-REP structure from AS exchange.
216  *
217  * Return value: Returns the received AS-REP packet from the AS
218  *               exchange, or NULL if not yet set or an error occured.
219  **/
220 Shishi_asn1
shishi_as_rep(Shishi_as * as)221 shishi_as_rep (Shishi_as * as)
222 {
223   return as->asrep;
224 }
225 
226 /**
227  * shishi_as_rep_process:
228  * @as: structure that holds information about AS exchange
229  * @key: user's key, used to encrypt the encrypted part of the AS-REP.
230  * @password: user's password, used if key is NULL.
231  *
232  * Process new AS-REP and set ticket.  The key is used to decrypt the
233  * AP-REP.  If both key and password is NULL, the user is queried for
234  * it.
235  *
236  * Return value: Returns SHISHI_OK iff successful.
237  **/
238 int
shishi_as_rep_process(Shishi_as * as,Shishi_key * key,const char * password)239 shishi_as_rep_process (Shishi_as * as, Shishi_key * key, const char *password)
240 {
241   Shishi_asn1 ticket, kdcreppart;
242   int res;
243 
244   if (VERBOSE (as->handle))
245     printf ("Processing AS-REQ and AS-REP...\n");
246 
247   if (VERBOSEASN1 (as->handle))
248     shishi_kdcreq_print (as->handle, stdout, as->asreq);
249 
250   if (VERBOSEASN1 (as->handle))
251     shishi_kdcrep_print (as->handle, stdout, as->asrep);
252 
253   if (key == NULL && password == NULL)
254     {
255       char *passwd;
256       char *user;
257       size_t userlen;
258 
259       res = shishi_asreq_clientrealm (as->handle, as->asreq, &user, &userlen);
260       if (res != SHISHI_OK)
261 	{
262 	  shishi_error_printf (as->handle, "Could not extract cname and "
263 			       "realm from AS-REQ: %s\n",
264 			       shishi_strerror (res));
265 	  return res;
266 	}
267 
268       res = shishi_prompt_password (as->handle, &passwd,
269 				    "Enter password for `%s': ", user);
270       free (user);
271       if (res != SHISHI_OK)
272 	{
273 	  shishi_error_printf (as->handle, "Reading password failed: %s\n",
274 			       shishi_strerror (res));
275 	  return res;
276 	}
277 
278       res = shishi_as_process (as->handle, as->asreq, as->asrep,
279 			       passwd, &kdcreppart);
280       free (passwd);
281     }
282   else if (key == NULL)
283     res = shishi_as_process (as->handle, as->asreq, as->asrep,
284 			     password, &kdcreppart);
285   else
286     res = shishi_kdc_process (as->handle, as->asreq, as->asrep, key,
287 			      SHISHI_KEYUSAGE_ENCASREPPART, &kdcreppart);
288   if (res != SHISHI_OK)
289     return res;
290 
291   if (VERBOSE (as->handle))
292     printf ("Got EncKDCRepPart...\n");
293 
294   if (VERBOSEASN1 (as->handle))
295     shishi_enckdcreppart_print (as->handle, stdout, kdcreppart);
296 
297   res = shishi_kdcrep_get_ticket (as->handle, as->asrep, &ticket);
298   if (res != SHISHI_OK)
299     {
300       shishi_error_printf (as->handle,
301 			   "Could not extract ticket from AS-REP: %s",
302 			   shishi_error (as->handle));
303       return res;
304     }
305 
306   if (VERBOSE (as->handle))
307     printf ("Got Ticket...\n");
308 
309   if (VERBOSEASN1 (as->handle))
310     shishi_ticket_print (as->handle, stdout, ticket);
311 
312   /* XXX */
313   as->tkt = shishi_tkt2 (as->handle, ticket, kdcreppart, as->asrep);
314 
315   return SHISHI_OK;
316 }
317 
318 /**
319  * shishi_as_rep_build:
320  * @as: structure that holds information about AS exchange
321  * @key: user's key, used to encrypt the encrypted part of the AS-REP.
322  *
323  * Build AS-REP.
324  *
325  * Return value: Returns SHISHI_OK iff successful.
326  **/
327 int
shishi_as_rep_build(Shishi_as * as,Shishi_key * key)328 shishi_as_rep_build (Shishi_as * as, Shishi_key * key)
329 {
330   int rc;
331 
332   /* XXX there are reasons for having padata in AS-REP */
333   rc = shishi_kdcrep_clear_padata (as->handle, as->asrep);
334   if (rc != SHISHI_OK)
335     return rc;
336 
337   rc = shishi_enckdcreppart_populate_encticketpart
338     (as->handle, shishi_tkt_enckdcreppart (as->tkt),
339      shishi_tkt_encticketpart (as->tkt));
340   if (rc != SHISHI_OK)
341     return rc;
342 
343   rc = shishi_kdc_copy_nonce (as->handle, as->asreq,
344 			      shishi_tkt_enckdcreppart (as->tkt));
345   if (rc != SHISHI_OK)
346     return rc;
347 
348   rc = shishi_kdcrep_add_enc_part (as->handle,
349 				   as->asrep,
350 				   key,
351 				   SHISHI_KEYUSAGE_ENCASREPPART,
352 				   shishi_tkt_enckdcreppart (as->tkt));
353   if (rc != SHISHI_OK)
354     return rc;
355 
356   rc = shishi_kdcrep_set_ticket (as->handle, as->asrep,
357 				 shishi_tkt_ticket (as->tkt));
358   if (rc != SHISHI_OK)
359     return rc;
360 
361   rc = shishi_kdc_copy_crealm (as->handle, as->asrep,
362 			       shishi_tkt_encticketpart (as->tkt));
363   if (rc != SHISHI_OK)
364     return rc;
365 
366   rc = shishi_kdc_copy_cname (as->handle, as->asrep,
367 			      shishi_tkt_encticketpart (as->tkt));
368   if (rc != SHISHI_OK)
369     return rc;
370 
371   return SHISHI_OK;
372 }
373 
374 /**
375  * shishi_as_rep_der:
376  * @as: structure that holds information about AS exchange
377  * @out: output array with newly allocated DER encoding of AS-REP.
378  * @outlen: length of output array with DER encoding of AS-REP.
379  *
380  * DER encode AS-REP. @out is allocated by this function, and it is
381  * the responsibility of caller to deallocate it.
382  *
383  * Return value: Returns SHISHI_OK iff successful.
384  **/
385 int
shishi_as_rep_der(Shishi_as * as,char ** out,size_t * outlen)386 shishi_as_rep_der (Shishi_as * as, char **out, size_t * outlen)
387 {
388   int rc;
389 
390   rc = shishi_asn1_to_der (as->handle, as->asrep, out, outlen);
391   if (rc != SHISHI_OK)
392     return rc;
393 
394   return SHISHI_OK;
395 }
396 
397 /**
398  * shishi_as_rep_set:
399  * @as: structure that holds information about AS exchange
400  * @asrep: asrep to store in AS.
401  *
402  * Set the AS-REP in the AS exchange.
403  **/
404 void
shishi_as_rep_set(Shishi_as * as,Shishi_asn1 asrep)405 shishi_as_rep_set (Shishi_as * as, Shishi_asn1 asrep)
406 {
407   if (as->asrep)
408     shishi_asn1_done (as->handle, as->asrep);
409   as->asrep = asrep;
410 }
411 
412 /**
413  * shishi_as_rep_der_set:
414  * @as: structure that holds information about AS exchange
415  * @der: input array with DER encoded AP-REP.
416  * @derlen: length of input array with DER encoded AP-REP.
417  *
418  * DER decode AS-REP and set it AS exchange.  If decoding fails, the
419  * AS-REP in the AS exchange remains.
420  *
421  * Return value: Returns SHISHI_OK.
422  **/
423 int
shishi_as_rep_der_set(Shishi_as * as,char * der,size_t derlen)424 shishi_as_rep_der_set (Shishi_as * as, char *der, size_t derlen)
425 {
426   Shishi_asn1 asrep;
427 
428   asrep = shishi_der2asn1_asrep (as->handle, der, derlen);
429 
430   if (asrep == NULL)
431     return SHISHI_ASN1_ERROR;
432 
433   as->asrep = asrep;
434 
435   return SHISHI_OK;
436 }
437 
438 /**
439  * shishi_as_krberror:
440  * @as: structure that holds information about AS exchange
441  *
442  * Get ASN.1 KRB-ERROR structure from AS exchange.
443  *
444  * Return value: Returns the received KRB-ERROR packet from the AS
445  *               exchange, or NULL if not yet set or an error occured.
446  **/
447 Shishi_asn1
shishi_as_krberror(Shishi_as * as)448 shishi_as_krberror (Shishi_as * as)
449 {
450   return as->krberror;
451 }
452 
453 /**
454  * shishi_as_krberror_der:
455  * @as: structure that holds information about AS exchange
456  * @out: output array with newly allocated DER encoding of KRB-ERROR.
457  * @outlen: length of output array with DER encoding of KRB-ERROR.
458  *
459  * DER encode KRB-ERROR. @out is allocated by this function, and it is
460  * the responsibility of caller to deallocate it.
461  *
462  * Return value: Returns SHISHI_OK iff successful.
463  **/
464 int
shishi_as_krberror_der(Shishi_as * as,char ** out,size_t * outlen)465 shishi_as_krberror_der (Shishi_as * as, char **out, size_t * outlen)
466 {
467   int rc;
468 
469   rc = shishi_krberror_der (as->handle, as->krberror, out, outlen);
470   if (rc != SHISHI_OK)
471     return rc;
472 
473   return SHISHI_OK;
474 }
475 
476 /**
477  * shishi_as_krberror_set:
478  * @as: structure that holds information about AS exchange
479  * @krberror: krberror to store in AS.
480  *
481  * Set the KRB-ERROR in the AS exchange.
482  **/
483 void
shishi_as_krberror_set(Shishi_as * as,Shishi_asn1 krberror)484 shishi_as_krberror_set (Shishi_as * as, Shishi_asn1 krberror)
485 {
486   if (as->krberror)
487     shishi_asn1_done (as->handle, as->krberror);
488   as->krberror = krberror;
489 }
490 
491 /**
492  * shishi_as_tkt:
493  * @as: structure that holds information about AS exchange
494  *
495  * Get Ticket in AS exchange.
496  *
497  * Return value: Returns the newly acquired tkt from the AS
498  *               exchange, or NULL if not yet set or an error occured.
499  **/
500 Shishi_tkt *
shishi_as_tkt(Shishi_as * as)501 shishi_as_tkt (Shishi_as * as)
502 {
503   return as->tkt;
504 }
505 
506 /**
507  * shishi_as_tkt_set:
508  * @as: structure that holds information about AS exchange
509  * @tkt: tkt to store in AS.
510  *
511  * Set the Tkt in the AS exchange.
512  **/
513 void
shishi_as_tkt_set(Shishi_as * as,Shishi_tkt * tkt)514 shishi_as_tkt_set (Shishi_as * as, Shishi_tkt * tkt)
515 {
516   as->tkt = tkt;
517 }
518 
519 /**
520  * shishi_as_sendrecv_hint:
521  * @as: structure that holds information about AS exchange
522  * @hint: additional parameters that modify connection behaviour, or %NULL.
523  *
524  * Send AS-REQ and receive AS-REP or KRB-ERROR.  This is the initial
525  * authentication, usually used to acquire a Ticket Granting Ticket.
526  * The @hint structure can be used to set, e.g., parameters for TLS
527  * authentication.
528  *
529  * Return value: Returns SHISHI_OK iff successful.
530  **/
531 int
shishi_as_sendrecv_hint(Shishi_as * as,Shishi_tkts_hint * hint)532 shishi_as_sendrecv_hint (Shishi_as * as, Shishi_tkts_hint * hint)
533 {
534   int res;
535 
536   if (VERBOSE (as->handle))
537     printf ("Sending AS-REQ...\n");
538 
539   if (VERBOSEASN1 (as->handle))
540     shishi_kdcreq_print (as->handle, stdout, as->asreq);
541 
542   res = shishi_kdcreq_sendrecv_hint (as->handle, as->asreq, &as->asrep, hint);
543   if (res == SHISHI_GOT_KRBERROR)
544     {
545       as->krberror = as->asrep;
546       as->asrep = NULL;
547 
548       if (VERBOSE (as->handle))
549 	printf ("Received KRB-ERROR...\n");
550       if (VERBOSEASN1 (as->handle))
551 	shishi_krberror_print (as->handle, stdout, as->krberror);
552       if (VERBOSEASN1 (as->handle))
553 	shishi_krberror_pretty_print (as->handle, stdout, as->krberror);
554     }
555   if (res != SHISHI_OK)
556     return res;
557 
558   if (VERBOSE (as->handle))
559     printf ("Received AS-REP...\n");
560 
561   if (VERBOSEASN1 (as->handle))
562     shishi_kdcrep_print (as->handle, stdout, as->asrep);
563 
564   return SHISHI_OK;
565 }
566 
567 /**
568  * shishi_as_sendrecv:
569  * @as: structure that holds information about AS exchange
570  *
571  * Send AS-REQ and receive AS-REP or KRB-ERROR.  This is the initial
572  * authentication, usually used to acquire a Ticket Granting Ticket.
573  *
574  * Return value: Returns SHISHI_OK iff successful.
575  **/
576 int
shishi_as_sendrecv(Shishi_as * as)577 shishi_as_sendrecv (Shishi_as * as)
578 {
579   return shishi_as_sendrecv_hint (as, NULL);
580 }
581