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