1 /* ticket.c --- Low-level ASN.1 Ticket handling.
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 #define SHISHI_TICKET_DEFAULT_TKTVNO "5"
26 #define SHISHI_TICKET_DEFAULT_TKTVNO_LEN 0
27
28 /**
29 * shishi_ticket:
30 * @handle: shishi handle as allocated by shishi_init().
31 *
32 * This function creates a new ASN.1 Ticket, populated with some
33 * default values.
34 *
35 * Return value: Returns the ticket or NULL on failure.
36 **/
37 Shishi_asn1
shishi_ticket(Shishi * handle)38 shishi_ticket (Shishi * handle)
39 {
40 Shishi_asn1 node = NULL;
41 int rc;
42
43 node = shishi_asn1_ticket (handle);
44 if (!node)
45 return NULL;
46
47 rc = shishi_asn1_write (handle, node, "tkt-vno",
48 SHISHI_TICKET_DEFAULT_TKTVNO,
49 SHISHI_TICKET_DEFAULT_TKTVNO_LEN);
50 if (rc != SHISHI_OK)
51 goto error;
52
53 return node;
54
55 error:
56 shishi_asn1_done (handle, node);
57 return NULL;
58 }
59
60 /**
61 * shishi_ticket_realm_get:
62 * @handle: shishi handle as allocated by shishi_init().
63 * @ticket: input variable with ticket info.
64 * @realm: output array with newly allocated name of realm in ticket.
65 * @realmlen: size of output array.
66 *
67 * Extract realm from ticket.
68 *
69 * Return value: Returns SHISHI_OK iff successful.
70 **/
71 int
shishi_ticket_realm_get(Shishi * handle,Shishi_asn1 ticket,char ** realm,size_t * realmlen)72 shishi_ticket_realm_get (Shishi * handle,
73 Shishi_asn1 ticket, char **realm, size_t * realmlen)
74 {
75 return shishi_asn1_read (handle, ticket, "realm", realm, realmlen);
76 }
77
78 /**
79 * shishi_ticket_realm_set:
80 * @handle: shishi handle as allocated by shishi_init().
81 * @ticket: input variable with ticket info.
82 * @realm: input array with name of realm.
83 *
84 * Set the realm field in the Ticket.
85 *
86 * Return value: Returns SHISHI_OK iff successful.
87 **/
88 int
shishi_ticket_realm_set(Shishi * handle,Shishi_asn1 ticket,const char * realm)89 shishi_ticket_realm_set (Shishi * handle, Shishi_asn1 ticket,
90 const char *realm)
91 {
92 int res;
93
94 res = shishi_asn1_write (handle, ticket, "realm", realm, 0);
95 if (res != SHISHI_OK)
96 return res;
97
98 return SHISHI_OK;
99 }
100
101 /**
102 * shishi_ticket_server:
103 * @handle: Shishi library handle create by shishi_init().
104 * @ticket: ASN.1 Ticket variable to get server name from.
105 * @server: pointer to newly allocated zero terminated string containing
106 * principal name. May be %NULL (to only populate @serverlen).
107 * @serverlen: pointer to length of @server on output, excluding terminating
108 * zero. May be %NULL (to only populate @server).
109 *
110 * Represent server principal name in Ticket as zero-terminated
111 * string. The string is allocate by this function, and it is the
112 * responsibility of the caller to deallocate it. Note that the
113 * output length @serverlen does not include the terminating zero.
114 *
115 * Return value: Returns SHISHI_OK iff successful.
116 **/
117 int
shishi_ticket_server(Shishi * handle,Shishi_asn1 ticket,char ** server,size_t * serverlen)118 shishi_ticket_server (Shishi * handle, Shishi_asn1 ticket,
119 char **server, size_t * serverlen)
120 {
121 return shishi_principal_name (handle, ticket, "sname", server, serverlen);
122 }
123
124 /**
125 * shishi_ticket_sname_set:
126 * @handle: shishi handle as allocated by shishi_init().
127 * @ticket: Ticket variable to set server name field in.
128 * @name_type: type of principial, see Shishi_name_type, usually
129 * SHISHI_NT_UNKNOWN.
130 * @sname: input array with principal name.
131 *
132 * Set the server name field in the Ticket.
133 *
134 * Return value: Returns SHISHI_OK iff successful.
135 **/
136 int
shishi_ticket_sname_set(Shishi * handle,Shishi_asn1 ticket,Shishi_name_type name_type,char * sname[])137 shishi_ticket_sname_set (Shishi * handle,
138 Shishi_asn1 ticket,
139 Shishi_name_type name_type, char *sname[])
140 {
141 int res = SHISHI_OK;
142 char *buf;
143 int i;
144
145 asprintf (&buf, "%d", name_type);
146 res = shishi_asn1_write (handle, ticket, "sname.name-type", buf, 0);
147 free (buf);
148 if (res != SHISHI_OK)
149 return res;
150
151 res = shishi_asn1_write (handle, ticket, "sname.name-string", NULL, 0);
152 if (res != SHISHI_OK)
153 return res;
154
155 i = 1;
156 while (sname[i - 1])
157 {
158 res = shishi_asn1_write (handle, ticket, "sname.name-string", "NEW", 1);
159 if (res != SHISHI_OK)
160 return res;
161
162 asprintf (&buf, "sname.name-string.?%d", i);
163 res = shishi_asn1_write (handle, ticket, buf, sname[i - 1], 0);
164 free (buf);
165 if (res != SHISHI_OK)
166 return res;
167
168 i++;
169 }
170
171 return SHISHI_OK;
172 }
173
174 int
shishi_ticket_set_server(Shishi * handle,Shishi_asn1 ticket,const char * server)175 shishi_ticket_set_server (Shishi * handle,
176 Shishi_asn1 ticket, const char *server)
177 {
178 char *tmpserver;
179 char **serverbuf;
180 char *tokptr = NULL;
181 int res;
182 int i;
183
184 tmpserver = xstrdup (server);
185 serverbuf = xmalloc (sizeof (*serverbuf));
186
187 for (i = 0;
188 (serverbuf[i] = strtok_r (i == 0 ? tmpserver : NULL, "/", &tokptr));
189 i++)
190 {
191 serverbuf = xrealloc (serverbuf, (i + 2) * sizeof (*serverbuf));
192 }
193 res = shishi_ticket_sname_set (handle, ticket,
194 SHISHI_NT_PRINCIPAL, serverbuf);
195 if (res != SHISHI_OK)
196 {
197 fprintf (stderr, _("Could not set sname: %s\n"), shishi_error (handle));
198 return res;
199 }
200 free (serverbuf);
201 free (tmpserver);
202
203 return SHISHI_OK;
204 }
205
206 int
shishi_ticket_srealmserver_set(Shishi * handle,Shishi_asn1 ticket,const char * realm,const char * server)207 shishi_ticket_srealmserver_set (Shishi * handle,
208 Shishi_asn1 ticket,
209 const char *realm, const char *server)
210 {
211 int res;
212
213 res = shishi_ticket_realm_set (handle, ticket, realm);
214 if (res != SHISHI_OK)
215 return res;
216
217 res = shishi_ticket_set_server (handle, ticket, server);
218 if (res != SHISHI_OK)
219 return res;
220
221 return SHISHI_OK;
222 }
223
224 /**
225 * shishi_ticket_get_enc_part_etype:
226 * @handle: shishi handle as allocated by shishi_init().
227 * @ticket: Ticket variable to get value from.
228 * @etype: output variable that holds the value.
229 *
230 * Extract Ticket.enc-part.etype.
231 *
232 * Return value: Returns SHISHI_OK iff successful.
233 **/
234 int
shishi_ticket_get_enc_part_etype(Shishi * handle,Shishi_asn1 ticket,int32_t * etype)235 shishi_ticket_get_enc_part_etype (Shishi * handle,
236 Shishi_asn1 ticket, int32_t * etype)
237 {
238 int res;
239
240 res = shishi_asn1_read_int32 (handle, ticket, "enc-part.etype", etype);
241
242 return res;
243 }
244
245 int
shishi_ticket_decrypt(Shishi * handle,Shishi_asn1 ticket,Shishi_key * key,Shishi_asn1 * encticketpart)246 shishi_ticket_decrypt (Shishi * handle,
247 Shishi_asn1 ticket,
248 Shishi_key * key, Shishi_asn1 * encticketpart)
249 {
250 int res;
251 int i;
252 char *buf;
253 size_t buflen;
254 char *cipher;
255 size_t cipherlen;
256 int etype;
257
258 res = shishi_ticket_get_enc_part_etype (handle, ticket, &etype);
259 if (res != SHISHI_OK)
260 return res;
261
262 if (etype != shishi_key_type (key))
263 return SHISHI_TICKET_BAD_KEYTYPE;
264
265 res = shishi_asn1_read (handle, ticket, "enc-part.cipher",
266 &cipher, &cipherlen);
267 if (res != SHISHI_OK)
268 return res;
269
270 res = shishi_decrypt (handle, key, SHISHI_KEYUSAGE_ENCTICKETPART,
271 cipher, cipherlen, &buf, &buflen);
272 free (cipher);
273 if (res != SHISHI_OK)
274 {
275 shishi_error_printf (handle,
276 "Ticket decrypt failed, wrong password?\n");
277 return SHISHI_TICKET_DECRYPT_FAILED;
278 }
279
280 /* The crypto is so 1980; no length indicator. Trim off pad bytes
281 until we can parse it. */
282 for (i = 0; i < 8; i++)
283 {
284 if (VERBOSEASN1 (handle))
285 printf ("Trying with %d pad in enckdcrep...\n", i);
286
287 *encticketpart = shishi_der2asn1_encticketpart (handle, &buf[0],
288 buflen - i);
289 if (*encticketpart != NULL)
290 break;
291 }
292
293 if (*encticketpart == NULL)
294 {
295 shishi_error_printf (handle, "Could not DER decode EncTicketPart. "
296 "Password probably correct (decrypt ok) though\n");
297 return SHISHI_ASN1_ERROR;
298 }
299
300 return SHISHI_OK;
301 }
302
303 /**
304 * shishi_ticket_set_enc_part:
305 * @handle: shishi handle as allocated by shishi_init().
306 * @ticket: Ticket to add enc-part field to.
307 * @etype: encryption type used to encrypt enc-part.
308 * @kvno: key version number.
309 * @buf: input array with encrypted enc-part.
310 * @buflen: size of input array with encrypted enc-part.
311 *
312 * Set the encrypted enc-part field in the Ticket. The encrypted data
313 * is usually created by calling shishi_encrypt() on the DER encoded
314 * enc-part. To save time, you may want to use
315 * shishi_ticket_add_enc_part() instead, which calculates the
316 * encrypted data and calls this function in one step.
317 *
318 * Return value: Returns SHISHI_OK iff successful.
319 **/
320 int
shishi_ticket_set_enc_part(Shishi * handle,Shishi_asn1 ticket,int32_t etype,uint32_t kvno,const char * buf,size_t buflen)321 shishi_ticket_set_enc_part (Shishi * handle,
322 Shishi_asn1 ticket,
323 int32_t etype, uint32_t kvno,
324 const char *buf, size_t buflen)
325 {
326 int res = SHISHI_OK;
327
328 res = shishi_asn1_write (handle, ticket, "enc-part.cipher", buf, buflen);
329 if (res != SHISHI_OK)
330 return res;
331
332 res = shishi_asn1_write_int32 (handle, ticket, "enc-part.etype", etype);
333 if (res != SHISHI_OK)
334 return res;
335
336 if (kvno == UINT32_MAX)
337 res = shishi_asn1_write (handle, ticket, "enc-part.kvno", NULL, 0);
338 else
339 res = shishi_asn1_write_uint32 (handle, ticket, "enc-part.kvno", kvno);
340 if (res != SHISHI_OK)
341 return res;
342
343 return SHISHI_OK;
344 }
345
346 /**
347 * shishi_ticket_add_enc_part:
348 * @handle: shishi handle as allocated by shishi_init().
349 * @ticket: Ticket to add enc-part field to.
350 * @key: key used to encrypt enc-part.
351 * @encticketpart: EncTicketPart to add.
352 *
353 * Encrypts DER encoded EncTicketPart using key and stores it in the
354 * Ticket.
355 *
356 * Return value: Returns SHISHI_OK iff successful.
357 **/
358 int
shishi_ticket_add_enc_part(Shishi * handle,Shishi_asn1 ticket,Shishi_key * key,Shishi_asn1 encticketpart)359 shishi_ticket_add_enc_part (Shishi * handle,
360 Shishi_asn1 ticket,
361 Shishi_key * key, Shishi_asn1 encticketpart)
362 {
363 int res = SHISHI_OK;
364 char *buf;
365 size_t buflen;
366 char *der;
367 size_t derlen;
368
369 res = shishi_asn1_to_der (handle, encticketpart, &der, &derlen);
370 if (res != SHISHI_OK)
371 {
372 shishi_error_printf (handle, "Could not DER encode encticketpart: %s\n",
373 shishi_strerror (res));
374 return res;
375 }
376
377 res = shishi_encrypt (handle, key, SHISHI_KEYUSAGE_ENCTICKETPART,
378 der, derlen, &buf, &buflen);
379
380 free (der);
381
382 if (res != SHISHI_OK)
383 {
384 shishi_error_printf (handle,
385 "Cannot encrypt encrypted part of ticket\n");
386 return res;
387 }
388
389 res = shishi_ticket_set_enc_part (handle, ticket, shishi_key_type (key),
390 shishi_key_version (key), buf, buflen);
391
392 free (buf);
393
394 return res;
395 }
396