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