Add.
[shishi.git] / lib / priv.c
blob41019d41a99738022c8184b8f0eba9bf83216f52
1 /* priv.c --- Application data privacy protection.
2 * Copyright (C) 2002, 2003, 2004, 2006 Simon Josefsson
4 * This file is part of Shishi.
6 * Shishi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Shishi is distributed in the hope that it will be useful,
12 * but 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "internal.h"
24 /* Get _shishi_print_armored_data, etc. */
25 #include "diskio.h"
27 struct Shishi_priv
29 Shishi *handle;
30 Shishi_key *key;
31 Shishi_asn1 priv;
32 Shishi_asn1 encprivpart;
33 unsigned long seqnumber;
36 /**
37 * shishi_priv:
38 * @handle: shishi handle as allocated by shishi_init().
39 * @priv: pointer to new structure that holds information about PRIV exchange
41 * Create a new PRIV exchange.
43 * Return value: Returns SHISHI_OK iff successful.
44 **/
45 int
46 shishi_priv (Shishi * handle, Shishi_priv ** priv)
48 Shishi_priv *lpriv;
49 struct timeval tv;
50 char *usec;
51 int rc;
53 *priv = xcalloc (1, sizeof (**priv));
54 lpriv = *priv;
56 lpriv->handle = handle;
57 rc = shishi_key (handle, &lpriv->key);
58 if (rc != SHISHI_OK)
59 return rc;
61 lpriv->priv = shishi_asn1_priv (handle);
62 if (lpriv->priv == NULL)
63 return SHISHI_ASN1_ERROR;
65 rc = shishi_asn1_write (handle, lpriv->priv, "pvno", "5", 0);
66 if (rc != SHISHI_OK)
67 return rc;
69 rc = shishi_asn1_write (handle, lpriv->priv, "msg-type", "21", 0);
70 if (rc != SHISHI_OK)
71 return rc;
73 rc = shishi_asn1_write (handle, lpriv->priv, "enc-part.kvno", "0", 0);
74 if (rc != SHISHI_OK)
75 return rc;
77 lpriv->encprivpart = shishi_asn1_encprivpart (handle);
78 if (lpriv->priv == NULL)
79 return SHISHI_ASN1_ERROR;
81 rc = shishi_asn1_write (handle, lpriv->encprivpart, "timestamp",
82 shishi_generalize_time (handle, time (NULL)), 0);
83 if (rc != SHISHI_OK)
84 return rc;
86 rc = gettimeofday (&tv, NULL);
87 if (rc != 0)
88 return SHISHI_GETTIMEOFDAY_ERROR;
89 usec = xasprintf ("%ld", tv.tv_usec % 1000000);
90 rc = shishi_asn1_write (handle, lpriv->encprivpart, "usec", usec, 0);
91 free (usec);
92 if (rc != SHISHI_OK)
93 return rc;
95 rc = shishi_asn1_write (handle, lpriv->encprivpart, "seq-number", NULL, 0);
96 if (rc != SHISHI_OK)
97 return rc;
99 rc = shishi_asn1_write (handle, lpriv->encprivpart, "s-address.addr-type",
100 /* directional */
101 "3", 0);
102 if (rc != SHISHI_OK)
103 return rc;
105 rc = shishi_asn1_write (handle, lpriv->encprivpart, "s-address.address",
106 /* sender */
107 "\x00\x00\x00\x00", 4);
108 if (rc != SHISHI_OK)
109 return rc;
111 rc = shishi_asn1_write (handle, lpriv->encprivpart, "r-address", NULL, 0);
112 if (rc != SHISHI_OK)
113 return rc;
115 return SHISHI_OK;
119 * shishi_priv_done:
120 * @priv: structure that holds information about PRIV exchange
122 * Deallocate resources associated with PRIV exchange. This should be
123 * called by the application when it no longer need to utilize the
124 * PRIV exchange handle.
126 void
127 shishi_priv_done (Shishi_priv * priv)
129 shishi_asn1_done (priv->handle, priv->priv);
130 shishi_asn1_done (priv->handle, priv->encprivpart);
131 shishi_key_done (priv->key);
132 free (priv);
136 * shishi_priv_key:
137 * @priv: structure that holds information about PRIV exchange
139 * Get key from PRIV exchange.
141 * Return value: Returns the key used in the PRIV exchange, or NULL if
142 * not yet set or an error occured.
144 Shishi_key *
145 shishi_priv_key (Shishi_priv * priv)
147 return priv->key;
151 * shishi_priv_key_set:
152 * @priv: structure that holds information about PRIV exchange
153 * @key: key to store in PRIV.
155 * Set the Key in the PRIV exchange.
157 void
158 shishi_priv_key_set (Shishi_priv * priv, Shishi_key * key)
160 shishi_key_copy (priv->key, key);
164 * shishi_priv_priv:
165 * @priv: structure that holds information about PRIV exchange
167 * Get ASN.1 PRIV structure in PRIV exchange.
169 * Return value: Returns the ASN.1 priv in the PRIV exchange, or NULL if
170 * not yet set or an error occured.
172 Shishi_asn1
173 shishi_priv_priv (Shishi_priv * priv)
175 return priv->priv;
179 * shishi_priv_priv_set:
180 * @priv: structure that holds information about PRIV exchange
181 * @asn1priv: KRB-PRIV to store in PRIV exchange.
183 * Set the KRB-PRIV in the PRIV exchange.
185 void
186 shishi_priv_priv_set (Shishi_priv * priv, Shishi_asn1 asn1priv)
188 if (priv->priv)
189 shishi_asn1_done (priv->handle, priv->priv);
190 priv->priv = asn1priv;
194 * shishi_priv_priv_der:
195 * @priv: priv as allocated by shishi_priv().
196 * @out: output array with newly allocated DER encoding of PRIV.
197 * @outlen: length of output array with DER encoding of PRIV.
199 * DER encode PRIV structure. Typically shishi_priv_build() is used
200 * to build the PRIV structure first. @out is allocated by this
201 * function, and it is the responsibility of caller to deallocate it.
203 * Return value: Returns SHISHI_OK iff successful.
206 shishi_priv_priv_der (Shishi_priv * priv, char **out, size_t * outlen)
208 int rc;
210 rc = shishi_asn1_to_der (priv->handle, priv->priv, out, outlen);
211 if (rc != SHISHI_OK)
212 return rc;
214 return SHISHI_OK;
218 * shishi_priv_priv_der_set:
219 * @priv: priv as allocated by shishi_priv().
220 * @der: input array with DER encoded KRB-PRIV.
221 * @derlen: length of input array with DER encoded KRB-PRIV.
223 * DER decode KRB-PRIV and set it PRIV exchange. If decoding fails, the
224 * KRB-PRIV in the PRIV exchange remains.
226 * Return value: Returns SHISHI_OK.
229 shishi_priv_priv_der_set (Shishi_priv * priv, char *der, size_t derlen)
231 Shishi_asn1 asn1priv;
233 asn1priv = shishi_der2asn1_priv (priv->handle, der, derlen);
235 if (asn1priv == NULL)
236 return SHISHI_ASN1_ERROR;
238 shishi_priv_priv_set (priv, asn1priv);
240 return SHISHI_OK;
244 * shishi_priv_encprivpart:
245 * @priv: structure that holds information about PRIV exchange
247 * Get ASN.1 EncPrivPart structure from PRIV exchange.
249 * Return value: Returns the ASN.1 encprivpart in the PRIV exchange, or NULL if
250 * not yet set or an error occured.
252 Shishi_asn1
253 shishi_priv_encprivpart (Shishi_priv * priv)
255 return priv->encprivpart;
259 * shishi_priv_encprivpart_set:
260 * @priv: structure that holds information about PRIV exchange
261 * @asn1encprivpart: ENCPRIVPART to store in PRIV exchange.
263 * Set the ENCPRIVPART in the PRIV exchange.
265 void
266 shishi_priv_encprivpart_set (Shishi_priv * priv, Shishi_asn1 asn1encprivpart)
268 if (priv->encprivpart)
269 shishi_asn1_done (priv->handle, priv->encprivpart);
270 priv->encprivpart = asn1encprivpart;
274 * shishi_priv_encprivpart_der:
275 * @priv: priv as allocated by shishi_priv().
276 * @out: output array with newly allocated DER encoding of ENCPRIVPART.
277 * @outlen: length of output array with DER encoding of ENCPRIVPART.
279 * DER encode ENCPRIVPART structure. Typically
280 * shishi_encprivpart_build() is used to build the ENCPRIVPART
281 * structure first. @out is allocated by this function, and it is the
282 * responsibility of caller to deallocate it.
284 * Return value: Returns SHISHI_OK iff successful.
287 shishi_priv_encprivpart_der (Shishi_priv * priv, char **out, size_t * outlen)
289 int rc;
291 rc = shishi_asn1_to_der (priv->handle, priv->encprivpart, out, outlen);
292 if (rc != SHISHI_OK)
293 return rc;
295 return SHISHI_OK;
299 * shishi_priv_encprivpart_der_set:
300 * @priv: priv as allocated by shishi_priv().
301 * @der: input array with DER encoded ENCPRIVPART.
302 * @derlen: length of input array with DER encoded ENCPRIVPART.
304 * DER decode ENCPRIVPART and set it PRIV exchange. If decoding
305 * fails, the ENCPRIVPART in the PRIV exchange remains.
307 * Return value: Returns SHISHI_OK.
310 shishi_priv_encprivpart_der_set (Shishi_priv * priv, char *der, size_t derlen)
312 Shishi_asn1 asn1encprivpart;
314 asn1encprivpart = shishi_der2asn1_encprivpart (priv->handle, der, derlen);
316 if (asn1encprivpart == NULL)
317 return SHISHI_ASN1_ERROR;
319 shishi_priv_encprivpart_set (priv, asn1encprivpart);
321 return SHISHI_OK;
325 * shishi_priv_print:
326 * @handle: shishi handle as allocated by shishi_init().
327 * @fh: file handle open for writing.
328 * @priv: PRIV to print.
330 * Print ASCII armored DER encoding of PRIV to file.
332 * Return value: Returns SHISHI_OK iff successful.
335 shishi_priv_print (Shishi * handle, FILE * fh, Shishi_asn1 priv)
337 return _shishi_print_armored_data (handle, fh, priv, "KRB-PRIV", NULL);
341 * shishi_priv_save:
342 * @handle: shishi handle as allocated by shishi_init().
343 * @fh: file handle open for writing.
344 * @priv: PRIV to save.
346 * Save DER encoding of PRIV to file.
348 * Return value: Returns SHISHI_OK iff successful.
351 shishi_priv_save (Shishi * handle, FILE * fh, Shishi_asn1 priv)
353 return _shishi_save_data (handle, fh, priv, "PRIV");
357 * shishi_priv_to_file:
358 * @handle: shishi handle as allocated by shishi_init().
359 * @priv: PRIV to save.
360 * @filetype: input variable specifying type of file to be written,
361 * see Shishi_filetype.
362 * @filename: input variable with filename to write to.
364 * Write PRIV to file in specified TYPE. The file will be
365 * truncated if it exists.
367 * Return value: Returns SHISHI_OK iff successful.
370 shishi_priv_to_file (Shishi * handle, Shishi_asn1 priv,
371 int filetype, const char *filename)
373 FILE *fh;
374 int res;
376 if (VERBOSE (handle))
377 printf (_("Writing PRIV to %s...\n"), filename);
379 fh = fopen (filename, "w");
380 if (fh == NULL)
381 return SHISHI_FOPEN_ERROR;
383 if (VERBOSE (handle))
384 printf (_("Writing PRIV in %s format...\n"),
385 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
387 if (filetype == SHISHI_FILETYPE_TEXT)
388 res = shishi_priv_print (handle, fh, priv);
389 else
390 res = shishi_priv_save (handle, fh, priv);
391 if (res != SHISHI_OK)
392 return res;
394 res = fclose (fh);
395 if (res != 0)
396 return SHISHI_IO_ERROR;
398 if (VERBOSE (handle))
399 printf (_("Writing PRIV to %s...done\n"), filename);
401 return SHISHI_OK;
405 * shishi_priv_parse:
406 * @handle: shishi handle as allocated by shishi_init().
407 * @fh: file handle open for reading.
408 * @priv: output variable with newly allocated PRIV.
410 * Read ASCII armored DER encoded PRIV from file and populate given
411 * variable.
413 * Return value: Returns SHISHI_OK iff successful.
416 shishi_priv_parse (Shishi * handle, FILE * fh, Shishi_asn1 * priv)
418 return _shishi_priv_input (handle, fh, priv, 0);
422 * shishi_priv_read:
423 * @handle: shishi handle as allocated by shishi_init().
424 * @fh: file handle open for reading.
425 * @priv: output variable with newly allocated PRIV.
427 * Read DER encoded PRIV from file and populate given variable.
429 * Return value: Returns SHISHI_OK iff successful.
432 shishi_priv_read (Shishi * handle, FILE * fh, Shishi_asn1 * priv)
434 return _shishi_priv_input (handle, fh, priv, 1);
438 * shishi_priv_from_file:
439 * @handle: shishi handle as allocated by shishi_init().
440 * @priv: output variable with newly allocated PRIV.
441 * @filetype: input variable specifying type of file to be read,
442 * see Shishi_filetype.
443 * @filename: input variable with filename to read from.
445 * Read PRIV from file in specified TYPE.
447 * Return value: Returns SHISHI_OK iff successful.
450 shishi_priv_from_file (Shishi * handle, Shishi_asn1 * priv,
451 int filetype, const char *filename)
453 int res;
454 FILE *fh;
456 if (VERBOSE (handle))
457 printf (_("Reading PRIV from %s...\n"), filename);
459 fh = fopen (filename, "r");
460 if (fh == NULL)
461 return SHISHI_FOPEN_ERROR;
463 if (VERBOSE (handle))
464 printf (_("Reading PRIV in %s format...\n"),
465 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
467 if (filetype == SHISHI_FILETYPE_TEXT)
468 res = shishi_priv_parse (handle, fh, priv);
469 else
470 res = shishi_priv_read (handle, fh, priv);
471 if (res != SHISHI_OK)
472 return res;
474 res = fclose (fh);
475 if (res != 0)
476 return SHISHI_IO_ERROR;
478 if (VERBOSE (handle))
479 printf (_("Reading PRIV from %s...done\n"), filename);
481 return SHISHI_OK;
485 * shishi_priv_enc_part_etype:
486 * @handle: shishi handle as allocated by shishi_init().
487 * @priv: PRIV variable to get value from.
488 * @etype: output variable that holds the value.
490 * Extract PRIV.enc-part.etype.
492 * Return value: Returns SHISHI_OK iff successful.
495 shishi_priv_enc_part_etype (Shishi * handle,
496 Shishi_asn1 priv, int32_t * etype)
498 return shishi_asn1_read_int32 (handle, priv, "enc-part.etype", etype);
502 * shishi_priv_set_enc_part:
503 * @handle: shishi handle as allocated by shishi_init().
504 * @priv: priv as allocated by shishi_priv().
505 * @etype: input encryption type to store in PRIV.
506 * @encpart: input encrypted data to store in PRIV.
507 * @encpartlen: size of input encrypted data to store in PRIV.
509 * Store encrypted data in PRIV. The encrypted data is usually
510 * created by calling shishi_encrypt() on some application specific
511 * data using the key from the ticket that is being used. To save
512 * time, you may want to use shishi_priv_build() instead, which
513 * encryptes the data and calls this function in one step.
515 * Return value: Returns SHISHI_OK iff successful.
518 shishi_priv_set_enc_part (Shishi * handle,
519 Shishi_asn1 priv,
520 int32_t etype,
521 const char *encpart, size_t encpartlen)
523 int res;
525 res = shishi_asn1_write_integer (handle, priv, "enc-part.etype", etype);
526 if (res != SHISHI_OK)
527 return res;
529 res = shishi_asn1_write (handle, priv, "enc-part.cipher",
530 encpart, encpartlen);
531 if (res != SHISHI_OK)
532 return res;
534 return SHISHI_OK;
538 * shishi_encprivpart_user_data:
539 * @handle: shishi handle as allocated by shishi_init().
540 * @encprivpart: encprivpart as allocated by shishi_priv().
541 * @userdata: output array with newly allocated user data from KRB-PRIV.
542 * @userdatalen: output size of output user data buffer.
544 * Read user data value from KRB-PRIV. @userdata is allocated by this
545 * function, and it is the responsibility of caller to deallocate it.
547 * Return value: Returns SHISHI_OK iff successful.
550 shishi_encprivpart_user_data (Shishi * handle,
551 Shishi_asn1 encprivpart,
552 char **userdata, size_t * userdatalen)
554 int res;
556 res = shishi_asn1_read (handle, encprivpart, "user-data",
557 userdata, userdatalen);
558 if (res != SHISHI_OK)
559 return res;
561 return SHISHI_OK;
565 * shishi_encprivpart_set_user_data:
566 * @handle: shishi handle as allocated by shishi_init().
567 * @encprivpart: encprivpart as allocated by shishi_priv().
568 * @userdata: input user application to store in PRIV.
569 * @userdatalen: size of input user application to store in PRIV.
571 * Set the application data in PRIV.
573 * Return value: Returns SHISHI_OK iff successful.
576 shishi_encprivpart_set_user_data (Shishi * handle,
577 Shishi_asn1 encprivpart,
578 const char *userdata, size_t userdatalen)
580 int res;
582 res = shishi_asn1_write (handle, encprivpart, "user-data",
583 userdata, userdatalen);
584 if (res != SHISHI_OK)
585 return res;
587 return SHISHI_OK;
591 * shishi_priv_build:
592 * @priv: priv as allocated by shishi_priv().
593 * @key: key for session, used to encrypt data.
595 * Build checksum and set it in KRB-PRIV. Note that this follows RFC
596 * 1510bis and is incompatible with RFC 1510, although presumably few
597 * implementations use the RFC1510 algorithm.
599 * Return value: Returns SHISHI_OK iff successful.
602 shishi_priv_build (Shishi_priv * priv, Shishi_key * key)
604 int res;
605 char *buf;
606 size_t buflen;
607 char *der;
608 size_t derlen;
610 res = shishi_asn1_to_der (priv->handle, priv->encprivpart, &der, &derlen);
611 if (res != SHISHI_OK)
613 shishi_error_printf (priv->handle,
614 "Could not DER encode EncPrivPart: %s\n",
615 shishi_strerror (res));
616 return res;
619 res = shishi_encrypt (priv->handle, key, SHISHI_KEYUSAGE_KRB_PRIV,
620 der, derlen, &buf, &buflen);
622 free (der);
624 if (res != SHISHI_OK)
626 shishi_error_printf (priv->handle, "Cannot encrypt EncPrivPart.\n");
627 return res;
630 res = shishi_priv_set_enc_part (priv->handle, priv->priv,
631 shishi_key_type (key), buf, buflen);
632 if (res != SHISHI_OK)
633 return res;
635 return SHISHI_OK;
639 * shishi_priv_process:
640 * @priv: priv as allocated by shishi_priv().
641 * @key: key to use to decrypt EncPrivPart.
643 * Decrypt encrypted data in KRB-PRIV and set the EncPrivPart in the
644 * PRIV exchange.
646 * Return value: Returns SHISHI_OK iff successful,
647 * SHISHI_PRIV_BAD_KEYTYPE if an incompatible key type is used, or
648 * SHISHI_CRYPTO_ERROR if the actual decryption failed.
651 shishi_priv_process (Shishi_priv * priv, Shishi_key * key)
653 int res;
654 int i;
655 char *buf;
656 size_t buflen;
657 char *cipher;
658 size_t cipherlen;
659 int32_t etype;
661 res = shishi_priv_enc_part_etype (priv->handle, priv->priv, &etype);
662 if (res != SHISHI_OK)
663 return res;
665 if (etype != shishi_key_type (key))
666 return SHISHI_PRIV_BAD_KEYTYPE;
668 res = shishi_asn1_read (priv->handle, priv->priv, "enc-part.cipher",
669 &cipher, &cipherlen);
670 if (res != SHISHI_OK)
671 return res;
673 res = shishi_decrypt (priv->handle, key, SHISHI_KEYUSAGE_KRB_PRIV,
674 cipher, cipherlen, &buf, &buflen);
675 free (cipher);
676 if (res != SHISHI_OK)
678 shishi_error_printf (priv->handle,
679 "PRIV decryption failed, bad key?\n");
680 return res;
683 /* The crypto is so 1980; no length indicator. Trim off pad bytes
684 until we can parse it. */
685 for (i = 0; i < 8; i++)
687 if (VERBOSEASN1 (priv->handle))
688 printf ("Trying with %d pad in enckdcrep...\n", i);
690 priv->encprivpart = shishi_der2asn1_encprivpart (priv->handle, &buf[0],
691 buflen - i);
692 if (priv->encprivpart != NULL)
693 break;
696 free (buf);
698 if (priv->encprivpart == NULL)
700 shishi_error_printf (priv->handle, "Could not DER decode EncPrivPart. "
701 "Key probably correct (decrypt ok) though\n");
702 return SHISHI_ASN1_ERROR;
705 return SHISHI_OK;