1 /* safe.c --- Application data integrity protection.
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 struct Shishi_safe
29 {
30 Shishi *handle;
31 Shishi_key *key;
32 Shishi_asn1 safe;
33 unsigned long seqnumber;
34 };
35
36 /**
37 * shishi_safe:
38 * @handle: shishi handle as allocated by shishi_init().
39 * @safe: pointer to new structure that holds information about SAFE exchange
40 *
41 * Create a new SAFE exchange.
42 *
43 * Return value: Returns SHISHI_OK iff successful.
44 **/
45 int
shishi_safe(Shishi * handle,Shishi_safe ** safe)46 shishi_safe (Shishi * handle, Shishi_safe ** safe)
47 {
48 Shishi_safe *lsafe;
49 struct timeval tv;
50 char *usec;
51 int rc;
52
53 *safe = xcalloc (1, sizeof (**safe));
54 lsafe = *safe;
55
56 lsafe->handle = handle;
57 rc = shishi_key (handle, &lsafe->key);
58 if (rc != SHISHI_OK)
59 return rc;
60
61 lsafe->safe = shishi_asn1_krbsafe (handle);
62 if (lsafe->safe == NULL)
63 return SHISHI_ASN1_ERROR;
64
65 rc = shishi_asn1_write (handle, lsafe->safe, "pvno", "5", 0);
66 if (rc != SHISHI_OK)
67 return rc;
68
69 rc = shishi_asn1_write (handle, lsafe->safe, "msg-type", "20", 0);
70 if (rc != SHISHI_OK)
71 return rc;
72
73 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.seq-number",
74 NULL, 0);
75 if (rc != SHISHI_OK)
76 return rc;
77
78 rc = gettimeofday (&tv, NULL);
79 if (rc != 0)
80 return SHISHI_GETTIMEOFDAY_ERROR;
81
82 asprintf (&usec, "%ld", tv.tv_usec % 1000000);
83 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.usec", usec, 0);
84 free (usec);
85 if (rc != SHISHI_OK)
86 return rc;
87
88 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.timestamp",
89 shishi_generalize_time (handle, time (NULL)), 0);
90 if (rc != SHISHI_OK)
91 return rc;
92
93 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.s-address.addr-type", "3", 0); /* directional */
94 if (rc != SHISHI_OK)
95 return rc;
96
97 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.s-address.address", "\x00\x00\x00\x00", 4); /* sender */
98 if (rc != SHISHI_OK)
99 return rc;
100
101 rc = shishi_asn1_write (handle, lsafe->safe, "safe-body.r-address",
102 NULL, 0);
103 if (rc != SHISHI_OK)
104 return rc;
105
106 return SHISHI_OK;
107 }
108
109 /**
110 * shishi_safe_done:
111 * @safe: structure that holds information about SAFE exchange
112 *
113 * Deallocate resources associated with SAFE exchange. This should be
114 * called by the application when it no longer need to utilize the
115 * SAFE exchange handle.
116 **/
117 void
shishi_safe_done(Shishi_safe * safe)118 shishi_safe_done (Shishi_safe * safe)
119 {
120 shishi_asn1_done (safe->handle, safe->safe);
121 shishi_key_done (safe->key);
122 free (safe);
123 }
124
125 /**
126 * shishi_safe_key:
127 * @safe: structure that holds information about SAFE exchange
128 *
129 * Get key structured from SAFE exchange.
130 *
131 * Return value: Returns the key used in the SAFE exchange, or NULL if
132 * not yet set or an error occured.
133 **/
134 Shishi_key *
shishi_safe_key(Shishi_safe * safe)135 shishi_safe_key (Shishi_safe * safe)
136 {
137 return safe->key;
138 }
139
140 /**
141 * shishi_safe_key_set:
142 * @safe: structure that holds information about SAFE exchange
143 * @key: key to store in SAFE.
144 *
145 * Set the Key in the SAFE exchange.
146 **/
147 void
shishi_safe_key_set(Shishi_safe * safe,Shishi_key * key)148 shishi_safe_key_set (Shishi_safe * safe, Shishi_key * key)
149 {
150 shishi_key_copy (safe->key, key);
151 }
152
153 /**
154 * shishi_safe_safe:
155 * @safe: structure that holds information about SAFE exchange
156 *
157 * Get ASN.1 SAFE structured from SAFE exchange.
158 *
159 * Return value: Returns the ASN.1 safe in the SAFE exchange, or NULL if
160 * not yet set or an error occured.
161 **/
162 Shishi_asn1
shishi_safe_safe(Shishi_safe * safe)163 shishi_safe_safe (Shishi_safe * safe)
164 {
165 return safe->safe;
166 }
167
168 /**
169 * shishi_safe_safe_set:
170 * @safe: structure that holds information about SAFE exchange
171 * @asn1safe: KRB-SAFE to store in SAFE exchange.
172 *
173 * Set the KRB-SAFE in the SAFE exchange.
174 **/
175 void
shishi_safe_safe_set(Shishi_safe * safe,Shishi_asn1 asn1safe)176 shishi_safe_safe_set (Shishi_safe * safe, Shishi_asn1 asn1safe)
177 {
178 if (safe->safe)
179 shishi_asn1_done (safe->handle, safe->safe);
180 safe->safe = asn1safe;
181 }
182
183 /**
184 * shishi_safe_safe_der:
185 * @safe: safe as allocated by shishi_safe().
186 * @out: output array with newly allocated DER encoding of SAFE.
187 * @outlen: length of output array with DER encoding of SAFE.
188 *
189 * DER encode SAFE structure. Typically shishi_safe_build() is used
190 * to build the SAFE structure first. @out is allocated by this
191 * function, and it is the responsibility of caller to deallocate it.
192 *
193 * Return value: Returns SHISHI_OK iff successful.
194 **/
195 int
shishi_safe_safe_der(Shishi_safe * safe,char ** out,size_t * outlen)196 shishi_safe_safe_der (Shishi_safe * safe, char **out, size_t * outlen)
197 {
198 int rc;
199
200 rc = shishi_asn1_to_der (safe->handle, safe->safe, out, outlen);
201 if (rc != SHISHI_OK)
202 return rc;
203
204 return SHISHI_OK;
205 }
206
207 /**
208 * shishi_safe_safe_der_set:
209 * @safe: safe as allocated by shishi_safe().
210 * @der: input array with DER encoded KRB-SAFE.
211 * @derlen: length of input array with DER encoded KRB-SAFE.
212 *
213 * DER decode KRB-SAFE and set it SAFE exchange. If decoding fails, the
214 * KRB-SAFE in the SAFE exchange remains.
215 *
216 * Return value: Returns SHISHI_OK.
217 **/
218 int
shishi_safe_safe_der_set(Shishi_safe * safe,char * der,size_t derlen)219 shishi_safe_safe_der_set (Shishi_safe * safe, char *der, size_t derlen)
220 {
221 Shishi_asn1 asn1safe;
222
223 asn1safe = shishi_der2asn1_krbsafe (safe->handle, der, derlen);
224
225 if (asn1safe == NULL)
226 return SHISHI_ASN1_ERROR;
227
228 shishi_safe_safe_set (safe, asn1safe);
229
230 return SHISHI_OK;
231 }
232
233 /**
234 * shishi_safe_print:
235 * @handle: shishi handle as allocated by shishi_init().
236 * @fh: file handle open for writing.
237 * @safe: SAFE to print.
238 *
239 * Print ASCII armored DER encoding of SAFE to file.
240 *
241 * Return value: Returns SHISHI_OK iff successful.
242 **/
243 int
shishi_safe_print(Shishi * handle,FILE * fh,Shishi_asn1 safe)244 shishi_safe_print (Shishi * handle, FILE * fh, Shishi_asn1 safe)
245 {
246 return _shishi_print_armored_data (handle, fh, safe, "KRB-SAFE", NULL);
247 }
248
249 /**
250 * shishi_safe_save:
251 * @handle: shishi handle as allocated by shishi_init().
252 * @fh: file handle open for writing.
253 * @safe: SAFE to save.
254 *
255 * Save DER encoding of SAFE to file.
256 *
257 * Return value: Returns SHISHI_OK iff successful.
258 **/
259 int
shishi_safe_save(Shishi * handle,FILE * fh,Shishi_asn1 safe)260 shishi_safe_save (Shishi * handle, FILE * fh, Shishi_asn1 safe)
261 {
262 return _shishi_save_data (handle, fh, safe, "SAFE");
263 }
264
265 /**
266 * shishi_safe_to_file:
267 * @handle: shishi handle as allocated by shishi_init().
268 * @safe: SAFE to save.
269 * @filetype: input variable specifying type of file to be written,
270 * see Shishi_filetype.
271 * @filename: input variable with filename to write to.
272 *
273 * Write SAFE to file in specified TYPE. The file will be
274 * truncated if it exists.
275 *
276 * Return value: Returns SHISHI_OK iff successful.
277 **/
278 int
shishi_safe_to_file(Shishi * handle,Shishi_asn1 safe,int filetype,const char * filename)279 shishi_safe_to_file (Shishi * handle, Shishi_asn1 safe,
280 int filetype, const char *filename)
281 {
282 FILE *fh;
283 int res;
284
285 if (VERBOSE (handle))
286 printf (_("Writing SAFE to %s...\n"), filename);
287
288 fh = fopen (filename, "w");
289 if (fh == NULL)
290 return SHISHI_FOPEN_ERROR;
291
292 if (VERBOSE (handle))
293 printf (_("Writing SAFE in %s format...\n"),
294 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
295
296 if (filetype == SHISHI_FILETYPE_TEXT)
297 res = shishi_safe_print (handle, fh, safe);
298 else
299 res = shishi_safe_save (handle, fh, safe);
300 if (res != SHISHI_OK)
301 return res;
302
303 res = fclose (fh);
304 if (res != 0)
305 return SHISHI_IO_ERROR;
306
307 if (VERBOSE (handle))
308 printf (_("Writing SAFE to %s...done\n"), filename);
309
310 return SHISHI_OK;
311 }
312
313 /**
314 * shishi_safe_parse:
315 * @handle: shishi handle as allocated by shishi_init().
316 * @fh: file handle open for reading.
317 * @safe: output variable with newly allocated SAFE.
318 *
319 * Read ASCII armored DER encoded SAFE from file and populate given
320 * variable.
321 *
322 * Return value: Returns SHISHI_OK iff successful.
323 **/
324 int
shishi_safe_parse(Shishi * handle,FILE * fh,Shishi_asn1 * safe)325 shishi_safe_parse (Shishi * handle, FILE * fh, Shishi_asn1 * safe)
326 {
327 return _shishi_safe_input (handle, fh, safe, 0);
328 }
329
330 /**
331 * shishi_safe_read:
332 * @handle: shishi handle as allocated by shishi_init().
333 * @fh: file handle open for reading.
334 * @safe: output variable with newly allocated SAFE.
335 *
336 * Read DER encoded SAFE from file and populate given variable.
337 *
338 * Return value: Returns SHISHI_OK iff successful.
339 **/
340 int
shishi_safe_read(Shishi * handle,FILE * fh,Shishi_asn1 * safe)341 shishi_safe_read (Shishi * handle, FILE * fh, Shishi_asn1 * safe)
342 {
343 return _shishi_safe_input (handle, fh, safe, 1);
344 }
345
346 /**
347 * shishi_safe_from_file:
348 * @handle: shishi handle as allocated by shishi_init().
349 * @safe: output variable with newly allocated SAFE.
350 * @filetype: input variable specifying type of file to be read,
351 * see Shishi_filetype.
352 * @filename: input variable with filename to read from.
353 *
354 * Read SAFE from file in specified TYPE.
355 *
356 * Return value: Returns SHISHI_OK iff successful.
357 **/
358 int
shishi_safe_from_file(Shishi * handle,Shishi_asn1 * safe,int filetype,const char * filename)359 shishi_safe_from_file (Shishi * handle, Shishi_asn1 * safe,
360 int filetype, const char *filename)
361 {
362 int res;
363 FILE *fh;
364
365 if (VERBOSE (handle))
366 printf (_("Reading SAFE from %s...\n"), filename);
367
368 fh = fopen (filename, "r");
369 if (fh == NULL)
370 return SHISHI_FOPEN_ERROR;
371
372 if (VERBOSE (handle))
373 printf (_("Reading SAFE in %s format...\n"),
374 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
375
376 if (filetype == SHISHI_FILETYPE_TEXT)
377 res = shishi_safe_parse (handle, fh, safe);
378 else
379 res = shishi_safe_read (handle, fh, safe);
380 if (res != SHISHI_OK)
381 return res;
382
383 res = fclose (fh);
384 if (res != 0)
385 return SHISHI_IO_ERROR;
386
387 if (VERBOSE (handle))
388 printf (_("Reading SAFE from %s...done\n"), filename);
389
390 return SHISHI_OK;
391 }
392
393 /**
394 * shishi_safe_cksum:
395 * @handle: shishi handle as allocated by shishi_init().
396 * @safe: safe as allocated by shishi_safe().
397 * @cksumtype: output checksum type.
398 * @cksum: output array with newly allocated checksum data from SAFE.
399 * @cksumlen: output size of output checksum data buffer.
400 *
401 * Read checksum value from KRB-SAFE. @cksum is allocated by this
402 * function, and it is the responsibility of caller to deallocate it.
403 *
404 * Return value: Returns SHISHI_OK iff successful.
405 **/
406 int
shishi_safe_cksum(Shishi * handle,Shishi_asn1 safe,int32_t * cksumtype,char ** cksum,size_t * cksumlen)407 shishi_safe_cksum (Shishi * handle,
408 Shishi_asn1 safe,
409 int32_t * cksumtype, char **cksum, size_t * cksumlen)
410 {
411 int res;
412
413 res = shishi_asn1_read_int32 (handle, safe, "cksum.cksumtype", cksumtype);
414 if (res != SHISHI_OK)
415 return res;
416
417 res = shishi_asn1_read (handle, safe, "cksum.checksum", cksum, cksumlen);
418 if (res != SHISHI_OK)
419 return res;
420
421 return SHISHI_OK;
422 }
423
424 /**
425 * shishi_safe_set_cksum:
426 * @handle: shishi handle as allocated by shishi_init().
427 * @safe: safe as allocated by shishi_safe().
428 * @cksumtype: input checksum type to store in SAFE.
429 * @cksum: input checksum data to store in SAFE.
430 * @cksumlen: size of input checksum data to store in SAFE.
431 *
432 * Store checksum value in SAFE. A checksum is usually created by
433 * calling shishi_checksum() on some application specific data using
434 * the key from the ticket that is being used. To save time, you may
435 * want to use shishi_safe_build() instead, which calculates the
436 * checksum and calls this function in one step.
437 *
438 * Return value: Returns SHISHI_OK iff successful.
439 **/
440 int
shishi_safe_set_cksum(Shishi * handle,Shishi_asn1 safe,int32_t cksumtype,const char * cksum,size_t cksumlen)441 shishi_safe_set_cksum (Shishi * handle,
442 Shishi_asn1 safe,
443 int32_t cksumtype, const char *cksum, size_t cksumlen)
444 {
445 int res;
446
447 res = shishi_asn1_write_int32 (handle, safe, "cksum.cksumtype", cksumtype);
448 if (res != SHISHI_OK)
449 return res;
450
451 res = shishi_asn1_write (handle, safe, "cksum.checksum", cksum, cksumlen);
452 if (res != SHISHI_OK)
453 return res;
454
455 return SHISHI_OK;
456 }
457
458 /**
459 * shishi_safe_user_data:
460 * @handle: shishi handle as allocated by shishi_init().
461 * @safe: safe as allocated by shishi_safe().
462 * @userdata: output array with newly allocated user data from KRB-SAFE.
463 * @userdatalen: output size of output user data buffer.
464 *
465 * Read user data value from KRB-SAFE. @userdata is allocated by this
466 * function, and it is the responsibility of caller to deallocate it.
467 *
468 * Return value: Returns SHISHI_OK iff successful.
469 **/
470 int
shishi_safe_user_data(Shishi * handle,Shishi_asn1 safe,char ** userdata,size_t * userdatalen)471 shishi_safe_user_data (Shishi * handle,
472 Shishi_asn1 safe, char **userdata,
473 size_t * userdatalen)
474 {
475 int res;
476
477 res = shishi_asn1_read (handle, safe, "safe-body.user-data",
478 userdata, userdatalen);
479 if (res != SHISHI_OK)
480 return res;
481
482 return SHISHI_OK;
483 }
484
485 /**
486 * shishi_safe_set_user_data:
487 * @handle: shishi handle as allocated by shishi_init().
488 * @safe: safe as allocated by shishi_safe().
489 * @userdata: input user application to store in SAFE.
490 * @userdatalen: size of input user application to store in SAFE.
491 *
492 * Set the application data in SAFE.
493 *
494 * Return value: Returns SHISHI_OK iff successful.
495 **/
496 int
shishi_safe_set_user_data(Shishi * handle,Shishi_asn1 safe,const char * userdata,size_t userdatalen)497 shishi_safe_set_user_data (Shishi * handle,
498 Shishi_asn1 safe,
499 const char *userdata, size_t userdatalen)
500 {
501 int res;
502
503 res = shishi_asn1_write (handle, safe, "safe-body.user-data",
504 userdata, userdatalen);
505 if (res != SHISHI_OK)
506 return res;
507
508 return SHISHI_OK;
509 }
510
511 /**
512 * shishi_safe_build:
513 * @safe: safe as allocated by shishi_safe().
514 * @key: key for session, used to compute checksum.
515 *
516 * Build checksum and set it in KRB-SAFE. Note that this follows RFC
517 * 1510bis and is incompatible with RFC 1510, although presumably few
518 * implementations use the RFC1510 algorithm.
519 *
520 * Return value: Returns SHISHI_OK iff successful.
521 **/
522 int
shishi_safe_build(Shishi_safe * safe,Shishi_key * key)523 shishi_safe_build (Shishi_safe * safe, Shishi_key * key)
524 {
525 int rc;
526 char *buffer;
527 size_t buflen;
528 char *cksum;
529 size_t cksumlen;
530 int cksumtype = shishi_cipher_defaultcksumtype (shishi_key_type (key));
531
532 rc = shishi_safe_set_cksum (safe->handle, safe->safe, 0, "", 0);
533 if (rc != SHISHI_OK)
534 return rc;
535
536 rc = shishi_safe_safe_der (safe, &buffer, &buflen);
537 if (rc != SHISHI_OK)
538 return rc;
539
540 /* XXX check if keytype/cksumtype is suitable for SAFE */
541
542 if (VERBOSEASN1 (safe->handle))
543 shishi_key_print (safe->handle, stdout, key);
544
545 rc = shishi_checksum (safe->handle, key, SHISHI_KEYUSAGE_KRB_SAFE,
546 cksumtype, buffer, buflen, &cksum, &cksumlen);
547 free (buffer);
548 if (rc != SHISHI_OK)
549 return rc;
550
551 rc = shishi_safe_set_cksum (safe->handle, safe->safe,
552 cksumtype, cksum, cksumlen);
553 if (rc != SHISHI_OK)
554 return rc;
555
556 return SHISHI_OK;
557 }
558
559 /**
560 * shishi_safe_verify:
561 * @safe: safe as allocated by shishi_safe().
562 * @key: key for session, used to verify checksum.
563 *
564 * Verify checksum in KRB-SAFE. Note that this follows RFC 1510bis
565 * and is incompatible with RFC 1510, although presumably few
566 * implementations use the RFC1510 algorithm.
567 *
568 * Return value: Returns SHISHI_OK iff successful,
569 * SHISHI_SAFE_BAD_KEYTYPE if an incompatible key type is used, or
570 * SHISHI_SAFE_VERIFY_FAILED if the actual verification failed.
571 **/
572 int
shishi_safe_verify(Shishi_safe * safe,Shishi_key * key)573 shishi_safe_verify (Shishi_safe * safe, Shishi_key * key)
574 {
575 char *cksum = NULL;
576 size_t cksumlen;
577 int cksumtype;
578 char *safeder = NULL;
579 size_t safederlen;
580 int rc;
581
582 rc = shishi_safe_cksum (safe->handle, safe->safe,
583 &cksumtype, &cksum, &cksumlen);
584 if (rc != SHISHI_OK)
585 goto done;
586
587 rc = shishi_safe_set_cksum (safe->handle, safe->safe, 0, "", 0);
588 if (rc != SHISHI_OK)
589 goto done;
590
591 rc = shishi_safe_safe_der (safe, &safeder, &safederlen);
592 if (rc != SHISHI_OK)
593 goto done;
594
595 rc = shishi_verify (safe->handle, key, SHISHI_KEYUSAGE_KRB_SAFE,
596 cksumtype, safeder, safederlen, cksum, cksumlen);
597 if (rc != SHISHI_OK)
598 goto done;
599
600 rc = SHISHI_OK;
601
602 done:
603 free (cksum);
604 free (safeder);
605 return rc;
606 }
607