1 /* kdcrep.c --- Key distribution (AS/TGS) Reply functions.
2 * Copyright (C) 2002, 2003, 2004, 2006, 2007 Simon Josefsson
4 * This file is part of Shishi.
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.
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.
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
25 /* Get _shishi_print_armored_data, etc. */
28 #define SHISHI_KDCREP_DEFAULT_PVNO "5"
29 #define SHISHI_KDCREP_DEFAULT_PVNO_LEN 0
30 #define SHISHI_AS_REP_DEFAULT_MSG_TYPE "11"
31 #define SHISHI_AS_REP_DEFAULT_MSG_TYPE_LEN 0
32 #define SHISHI_TGS_REP_DEFAULT_MSG_TYPE "13"
33 #define SHISHI_TGS_REP_DEFAULT_MSG_TYPE_LEN 0
36 _shishi_kdcrep (Shishi
* handle
, int as
)
42 node
= shishi_asn1_asrep (handle
);
44 node
= shishi_asn1_tgsrep (handle
);
48 res
= shishi_asn1_write (handle
, node
, "pvno",
49 SHISHI_KDCREP_DEFAULT_PVNO
,
50 SHISHI_KDCREP_DEFAULT_PVNO_LEN
);
55 res
= shishi_asn1_write (handle
, node
, "msg-type",
56 SHISHI_AS_REP_DEFAULT_MSG_TYPE
,
57 SHISHI_AS_REP_DEFAULT_MSG_TYPE_LEN
);
59 res
= shishi_asn1_write (handle
, node
, "msg-type",
60 SHISHI_TGS_REP_DEFAULT_MSG_TYPE
,
61 SHISHI_TGS_REP_DEFAULT_MSG_TYPE_LEN
);
68 shishi_asn1_done (handle
, node
);
74 * @handle: shishi handle as allocated by shishi_init().
76 * This function creates a new AS-REP, populated with some default
79 * Return value: Returns the AS-REP or NULL on failure.
82 shishi_asrep (Shishi
* handle
)
84 return _shishi_kdcrep (handle
, 1);
89 * @handle: shishi handle as allocated by shishi_init().
91 * This function creates a new TGS-REP, populated with some default
94 * Return value: Returns the TGS-REP or NULL on failure.
97 shishi_tgsrep (Shishi
* handle
)
99 return _shishi_kdcrep (handle
, 0);
104 * shishi_kdcrep_print:
105 * @handle: shishi handle as allocated by shishi_init().
106 * @fh: file handle open for writing.
107 * @kdcrep: KDC-REP to print.
109 * Print ASCII armored DER encoding of KDC-REP to file.
111 * Return value: Returns SHISHI_OK iff successful.
114 shishi_kdcrep_print (Shishi
* handle
, FILE * fh
, Shishi_asn1 kdcrep
)
116 return _shishi_print_armored_data (handle
, fh
, kdcrep
, "KDC-REP", NULL
);
120 * shishi_kdcrep_save:
121 * @handle: shishi handle as allocated by shishi_init().
122 * @fh: file handle open for writing.
123 * @kdcrep: KDC-REP to save.
125 * Print DER encoding of KDC-REP to file.
127 * Return value: Returns SHISHI_OK iff successful.
130 shishi_kdcrep_save (Shishi
* handle
, FILE * fh
, Shishi_asn1 kdcrep
)
132 return _shishi_save_data (handle
, fh
, kdcrep
, "KDC-REP");
136 * shishi_kdcrep_to_file:
137 * @handle: shishi handle as allocated by shishi_init().
138 * @kdcrep: KDC-REP to save.
139 * @filetype: input variable specifying type of file to be written,
140 * see Shishi_filetype.
141 * @filename: input variable with filename to write to.
143 * Write KDC-REP to file in specified TYPE. The file will be truncated
146 * Return value: Returns SHISHI_OK iff successful.
149 shishi_kdcrep_to_file (Shishi
* handle
, Shishi_asn1 kdcrep
,
150 int filetype
, const char *filename
)
155 if (VERBOSE (handle
))
156 printf (_("Writing KDC-REP to %s...\n"), filename
);
158 fh
= fopen (filename
, "w");
160 return SHISHI_FOPEN_ERROR
;
162 if (VERBOSE (handle
))
163 printf (_("Writing KDC-REP in %s format...\n"),
164 filetype
== SHISHI_FILETYPE_TEXT
? "TEXT" : "DER");
166 if (filetype
== SHISHI_FILETYPE_TEXT
)
167 res
= shishi_kdcrep_print (handle
, fh
, kdcrep
);
169 res
= shishi_kdcrep_save (handle
, fh
, kdcrep
);
170 if (res
!= SHISHI_OK
)
175 return SHISHI_IO_ERROR
;
177 if (VERBOSE (handle
))
178 printf (_("Writing KDC-REP to %s...done\n"), filename
);
184 * shishi_kdcrep_parse:
185 * @handle: shishi handle as allocated by shishi_init().
186 * @fh: file handle open for reading.
187 * @kdcrep: output variable with newly allocated KDC-REP.
189 * Read ASCII armored DER encoded KDC-REP from file and populate given
192 * Return value: Returns SHISHI_OK iff successful.
195 shishi_kdcrep_parse (Shishi
* handle
, FILE * fh
, Shishi_asn1
* kdcrep
)
197 return _shishi_kdcrep_input (handle
, fh
, kdcrep
, 0);
201 * shishi_kdcrep_read:
202 * @handle: shishi handle as allocated by shishi_init().
203 * @fh: file handle open for reading.
204 * @kdcrep: output variable with newly allocated KDC-REP.
206 * Read DER encoded KDC-REP from file and populate given variable.
208 * Return value: Returns SHISHI_OK iff successful.
211 shishi_kdcrep_read (Shishi
* handle
, FILE * fh
, Shishi_asn1
* kdcrep
)
213 return _shishi_kdcrep_input (handle
, fh
, kdcrep
, 1);
217 * shishi_kdcrep_from_file:
218 * @handle: shishi handle as allocated by shishi_init().
219 * @kdcrep: output variable with newly allocated KDC-REP.
220 * @filetype: input variable specifying type of file to be read,
221 * see Shishi_filetype.
222 * @filename: input variable with filename to read from.
224 * Read KDC-REP from file in specified TYPE.
226 * Return value: Returns SHISHI_OK iff successful.
229 shishi_kdcrep_from_file (Shishi
* handle
, Shishi_asn1
* kdcrep
,
230 int filetype
, const char *filename
)
235 if (VERBOSE (handle
))
236 printf (_("Reading KDC-REP from %s...\n"), filename
);
238 fh
= fopen (filename
, "r");
240 return SHISHI_FOPEN_ERROR
;
242 if (VERBOSE (handle
))
243 printf (_("Reading KDC-REP in %s format...\n"),
244 filetype
== SHISHI_FILETYPE_TEXT
? "TEXT" : "DER");
246 if (filetype
== SHISHI_FILETYPE_TEXT
)
247 res
= shishi_kdcrep_parse (handle
, fh
, kdcrep
);
249 res
= shishi_kdcrep_read (handle
, fh
, kdcrep
);
250 if (res
!= SHISHI_OK
)
255 return SHISHI_IO_ERROR
;
257 if (VERBOSE (handle
))
258 printf (_("Reading KDC-REP from %s...done\n"), filename
);
264 * shishi_kdcrep_crealm_set:
265 * @handle: shishi handle as allocated by shishi_init().
266 * @kdcrep: Kdcrep variable to set realm field in.
267 * @crealm: input array with name of realm.
269 * Set the client realm field in the KDC-REP.
271 * Return value: Returns SHISHI_OK iff successful.
274 shishi_kdcrep_crealm_set (Shishi
* handle
,
275 Shishi_asn1 kdcrep
, const char *crealm
)
279 res
= shishi_asn1_write (handle
, kdcrep
, "crealm", crealm
, 0);
280 if (res
!= SHISHI_OK
)
287 * shishi_kdcrep_cname_set:
288 * @handle: shishi handle as allocated by shishi_init().
289 * @kdcrep: Kdcrep variable to set server name field in.
290 * @name_type: type of principial, see Shishi_name_type, usually
292 * @cname: input array with principal name.
294 * Set the server name field in the KDC-REP.
296 * Return value: Returns SHISHI_OK iff successful.
299 shishi_kdcrep_cname_set (Shishi
* handle
,
301 Shishi_name_type name_type
, const char *cname
[])
305 res
= shishi_principal_name_set (handle
, kdcrep
, "cname", name_type
, cname
);
306 if (res
!= SHISHI_OK
)
313 * shishi_kdcrep_client_set:
314 * @handle: shishi handle as allocated by shishi_init().
315 * @kdcrep: Kdcrep variable to set server name field in.
316 * @client: zero-terminated string with principal name on RFC 1964 form.
318 * Set the client name field in the KDC-REP.
320 * Return value: Returns SHISHI_OK iff successful.
323 shishi_kdcrep_client_set (Shishi
* handle
,
324 Shishi_asn1 kdcrep
, const char *client
)
328 res
= shishi_principal_set (handle
, kdcrep
, "cname", client
);
329 if (res
!= SHISHI_OK
)
336 shishi_kdcrep_crealmserver_set (Shishi
* handle
,
338 const char *crealm
, const char *client
)
342 res
= shishi_kdcrep_crealm_set (handle
, kdcrep
, crealm
);
343 if (res
!= SHISHI_OK
)
346 res
= shishi_kdcrep_client_set (handle
, kdcrep
, client
);
347 if (res
!= SHISHI_OK
)
354 * shishi_kdcrep_get_enc_part_etype:
355 * @handle: shishi handle as allocated by shishi_init().
356 * @kdcrep: KDC-REP variable to get value from.
357 * @etype: output variable that holds the value.
359 * Extract KDC-REP.enc-part.etype.
361 * Return value: Returns SHISHI_OK iff successful.
364 shishi_kdcrep_get_enc_part_etype (Shishi
* handle
,
365 Shishi_asn1 kdcrep
, int32_t * etype
)
367 return shishi_asn1_read_int32 (handle
, kdcrep
, "enc-part.etype", etype
);
371 * shishi_kdcrep_get_ticket:
372 * @handle: shishi handle as allocated by shishi_init().
373 * @kdcrep: KDC-REP variable to get ticket from.
374 * @ticket: output variable to hold extracted ticket.
376 * Extract ticket from KDC-REP.
378 * Return value: Returns SHISHI_OK iff successful.
381 shishi_kdcrep_get_ticket (Shishi
* handle
,
382 Shishi_asn1 kdcrep
, Shishi_asn1
* ticket
)
390 /* there's GOT to be an easier way to do this */
392 *ticket
= shishi_ticket (handle
);
394 return SHISHI_ASN1_ERROR
;
396 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.tkt-vno", &buf
, &buflen
);
397 if (res
!= SHISHI_OK
)
400 res
= shishi_asn1_write (handle
, *ticket
, "tkt-vno", buf
, buflen
);
402 if (res
!= SHISHI_OK
)
405 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.realm", &buf
, &buflen
);
406 if (res
!= SHISHI_OK
)
409 res
= shishi_asn1_write (handle
, *ticket
, "realm", buf
, buflen
);
411 if (res
!= SHISHI_OK
)
414 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.sname.name-type",
416 if (res
!= SHISHI_OK
)
419 res
= shishi_asn1_write (handle
, *ticket
, "sname.name-type", buf
, buflen
);
421 if (res
!= SHISHI_OK
)
424 res
= shishi_asn1_number_of_elements (handle
, kdcrep
,
425 "ticket.sname.name-string", &n
);
426 if (res
!= SHISHI_OK
)
429 for (i
= 1; i
<= n
; i
++)
431 res
= shishi_asn1_write (handle
, *ticket
, "sname.name-string",
433 if (res
!= SHISHI_OK
)
436 format
= xasprintf ("ticket.sname.name-string.?%d", i
);
437 res
= shishi_asn1_read (handle
, kdcrep
, format
, &buf
, &buflen
);
439 if (res
!= SHISHI_OK
)
442 format
= xasprintf ("sname.name-string.?%d", i
);
443 res
= shishi_asn1_write (handle
, *ticket
, format
, buf
, buflen
);
446 if (res
!= SHISHI_OK
)
450 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.enc-part.etype",
452 if (res
!= SHISHI_OK
)
455 res
= shishi_asn1_write (handle
, *ticket
, "enc-part.etype", buf
, buflen
);
457 if (res
!= SHISHI_OK
)
460 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.enc-part.kvno",
462 if (res
!= SHISHI_OK
&& res
!= SHISHI_ASN1_NO_ELEMENT
)
465 if (res
== SHISHI_ASN1_NO_ELEMENT
)
466 res
= shishi_asn1_write (handle
, *ticket
, "enc-part.kvno", NULL
, 0);
469 res
= shishi_asn1_write (handle
, *ticket
, "enc-part.kvno", buf
, buflen
);
472 if (res
!= SHISHI_OK
)
475 res
= shishi_asn1_read (handle
, kdcrep
, "ticket.enc-part.cipher",
477 if (res
!= SHISHI_OK
)
480 res
= shishi_asn1_write (handle
, *ticket
, "enc-part.cipher", buf
, buflen
);
482 if (res
!= SHISHI_OK
)
488 shishi_asn1_done (handle
, *ticket
);
493 * shishi_kdcrep_set_ticket:
494 * @handle: shishi handle as allocated by shishi_init().
495 * @kdcrep: KDC-REP to add ticket field to.
496 * @ticket: input ticket to copy into KDC-REP ticket field.
498 * Copy ticket into KDC-REP.
500 * Return value: Returns SHISHI_OK iff successful.
503 shishi_kdcrep_set_ticket (Shishi
* handle
, Shishi_asn1 kdcrep
,
512 res
= shishi_asn1_read (handle
, ticket
, "tkt-vno", &buf
, &buflen
);
513 if (res
!= SHISHI_OK
)
516 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.tkt-vno", buf
, buflen
);
518 if (res
!= SHISHI_OK
)
521 res
= shishi_asn1_read (handle
, ticket
, "realm", &buf
, &buflen
);
522 if (res
!= SHISHI_OK
)
525 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.realm", buf
, buflen
);
527 if (res
!= SHISHI_OK
)
530 res
= shishi_asn1_read (handle
, ticket
, "sname.name-type", &buf
, &buflen
);
531 if (res
!= SHISHI_OK
)
534 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.sname.name-type",
537 if (res
!= SHISHI_OK
)
540 res
= shishi_asn1_number_of_elements (handle
, ticket
,
541 "sname.name-string", &n
);
542 if (res
!= SHISHI_OK
)
545 for (i
= 1; i
<= n
; i
++)
547 res
= shishi_asn1_write (handle
, kdcrep
,
548 "ticket.sname.name-string", "NEW", 1);
549 if (res
!= SHISHI_OK
)
552 format
= xasprintf ("sname.name-string.?%d", i
);
553 res
= shishi_asn1_read (handle
, ticket
, format
, &buf
, &buflen
);
555 if (res
!= SHISHI_OK
)
558 format
= xasprintf ("ticket.sname.name-string.?%d", i
);
559 res
= shishi_asn1_write (handle
, kdcrep
, format
, buf
, buflen
);
562 if (res
!= SHISHI_OK
)
566 res
= shishi_asn1_read (handle
, ticket
, "enc-part.etype", &buf
, &buflen
);
567 if (res
!= SHISHI_OK
)
570 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.enc-part.etype",
573 if (res
!= SHISHI_OK
)
576 res
= shishi_asn1_read (handle
, ticket
, "enc-part.kvno", &buf
, &buflen
);
577 if (res
!= SHISHI_OK
)
578 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.enc-part.kvno", NULL
, 0);
581 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.enc-part.kvno",
585 if (res
!= SHISHI_OK
)
588 res
= shishi_asn1_read (handle
, ticket
, "enc-part.cipher", &buf
, &buflen
);
589 if (res
!= SHISHI_OK
)
592 res
= shishi_asn1_write (handle
, kdcrep
, "ticket.enc-part.cipher",
595 if (res
!= SHISHI_OK
)
602 * shishi_kdcrep_set_enc_part:
603 * @handle: shishi handle as allocated by shishi_init().
604 * @kdcrep: KDC-REP to add enc-part field to.
605 * @etype: encryption type used to encrypt enc-part.
606 * @kvno: key version number.
607 * @buf: input array with encrypted enc-part.
608 * @buflen: size of input array with encrypted enc-part.
610 * Set the encrypted enc-part field in the KDC-REP. The encrypted
611 * data is usually created by calling shishi_encrypt() on the DER
612 * encoded enc-part. To save time, you may want to use
613 * shishi_kdcrep_add_enc_part() instead, which calculates the
614 * encrypted data and calls this function in one step.
616 * Return value: Returns SHISHI_OK iff successful.
619 shishi_kdcrep_set_enc_part (Shishi
* handle
,
621 int32_t etype
, uint32_t kvno
,
622 const char *buf
, size_t buflen
)
626 res
= shishi_asn1_write (handle
, kdcrep
, "enc-part.cipher", buf
, buflen
);
627 if (res
!= SHISHI_OK
)
630 res
= shishi_asn1_write_int32 (handle
, kdcrep
, "enc-part.etype", etype
);
631 if (res
!= SHISHI_OK
)
634 if (kvno
== UINT32_MAX
)
635 res
= shishi_asn1_write (handle
, kdcrep
, "enc-part.kvno", NULL
, 0);
637 res
= shishi_asn1_write_uint32 (handle
, kdcrep
, "enc-part.kvno", kvno
);
638 if (res
!= SHISHI_OK
)
645 * shishi_kdcrep_add_enc_part:
646 * @handle: shishi handle as allocated by shishi_init().
647 * @kdcrep: KDC-REP to add enc-part field to.
648 * @key: key used to encrypt enc-part.
649 * @keyusage: key usage to use, normally SHISHI_KEYUSAGE_ENCASREPPART,
650 * SHISHI_KEYUSAGE_ENCTGSREPPART_SESSION_KEY or
651 * SHISHI_KEYUSAGE_ENCTGSREPPART_AUTHENTICATOR_KEY.
652 * @enckdcreppart: EncKDCRepPart to add.
654 * Encrypts DER encoded EncKDCRepPart using key and stores it in the
657 * Return value: Returns SHISHI_OK iff successful.
660 shishi_kdcrep_add_enc_part (Shishi
* handle
,
663 int keyusage
, Shishi_asn1 enckdcreppart
)
671 res
= shishi_asn1_to_der (handle
, enckdcreppart
, &der
, &derlen
);
672 if (res
!= SHISHI_OK
)
674 shishi_error_printf (handle
, "Could not DER encode enckdcreppart: %s\n",
675 shishi_strerror (res
));
676 return SHISHI_ASN1_ERROR
;
679 res
= shishi_encrypt (handle
, key
, keyusage
, der
, derlen
, &buf
, &buflen
);
683 if (res
!= SHISHI_OK
)
685 shishi_error_printf (handle
, "Cannot encrypt EncKDCRepPart\n");
689 res
= shishi_kdcrep_set_enc_part (handle
, kdcrep
, shishi_key_type (key
),
690 shishi_key_version (key
), buf
, buflen
);
698 shishi_kdcrep_decrypt (Shishi
* handle
,
701 int keyusage
, Shishi_asn1
* enckdcreppart
)
711 res
= shishi_kdcrep_get_enc_part_etype (handle
, kdcrep
, &etype
);
712 if (res
!= SHISHI_OK
)
715 if (etype
!= shishi_key_type (key
))
716 return SHISHI_KDCREP_BAD_KEYTYPE
;
718 res
= shishi_asn1_read (handle
, kdcrep
, "enc-part.cipher",
719 &cipher
, &cipherlen
);
720 if (res
!= SHISHI_OK
)
723 res
= shishi_decrypt (handle
, key
, keyusage
,
724 cipher
, cipherlen
, &buf
, &buflen
);
726 if (res
!= SHISHI_OK
)
728 shishi_error_printf (handle
,
729 "KDCRep decryption failed, wrong password?");
733 /* The crypto is so 1980; no length indicator. Trim off pad bytes
734 until we can parse it. */
735 for (i
= 0; i
< 8; i
++)
737 if (VERBOSEASN1 (handle
))
738 printf ("Trying with %d pad in enckdcrep...\n", i
);
740 *enckdcreppart
= shishi_der2asn1_encasreppart (handle
, &buf
[0],
742 if (*enckdcreppart
!= NULL
)
745 *enckdcreppart
= shishi_der2asn1_enctgsreppart (handle
, &buf
[0],
747 if (*enckdcreppart
!= NULL
)
750 *enckdcreppart
= shishi_der2asn1_enckdcreppart (handle
, &buf
[0],
752 if (*enckdcreppart
!= NULL
)
758 if (*enckdcreppart
== NULL
)
760 shishi_error_printf (handle
, "Could not DER decode EncKDCRepPart. "
761 "Password probably correct (decrypt ok) though\n");
762 return SHISHI_ASN1_ERROR
;
769 * shishi_kdcrep_clear_padata:
770 * @handle: shishi handle as allocated by shishi_init().
771 * @kdcrep: KDC-REP to remove PA-DATA from.
773 * Remove the padata field from KDC-REP.
775 * Return value: Returns SHISHI_OK iff successful.
778 shishi_kdcrep_clear_padata (Shishi
* handle
, Shishi_asn1 kdcrep
)
782 res
= shishi_asn1_write (handle
, kdcrep
, "padata", NULL
, 0);
783 if (res
!= SHISHI_OK
)