Fix.
[shishi.git] / lib / priv.c
blob58c30cf87c3c47a4234eb64d6e5a8bedd797331d
1 /* priv.c Application data privacy protection.
2 * Copyright (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "internal.h"
24 struct Shishi_priv
26 Shishi *handle;
27 Shishi_key *key;
28 Shishi_asn1 priv;
29 Shishi_asn1 encprivpart;
30 unsigned long seqnumber;
33 /**
34 * shishi_priv:
35 * @handle: shishi handle as allocated by shishi_init().
36 * @priv: pointer to new structure that holds information about PRIV exchange
38 * Create a new PRIV exchange.
40 * Return value: Returns SHISHI_OK iff successful.
41 **/
42 int
43 shishi_priv (Shishi * handle, Shishi_priv ** priv)
45 Shishi_priv *lpriv;
46 struct timeval tv;
47 struct timezone tz;
48 char *usec;
49 int rc;
51 *priv = xcalloc (1, sizeof (**priv));
52 lpriv = *priv;
54 lpriv->handle = handle;
55 rc = shishi_key (handle, &lpriv->key);
56 if (rc != SHISHI_OK)
57 return rc;
59 lpriv->priv = shishi_asn1_priv (handle);
60 if (lpriv->priv == NULL)
61 return SHISHI_ASN1_ERROR;
63 rc = shishi_asn1_write (handle, lpriv->priv, "pvno", "5", 0);
64 if (rc != SHISHI_OK)
65 return rc;
67 rc = shishi_asn1_write (handle, lpriv->priv, "msg-type", "21", 0);
68 if (rc != SHISHI_OK)
69 return rc;
71 rc = shishi_asn1_write (handle, lpriv->priv, "enc-part.kvno", "0", 0);
72 if (rc != SHISHI_OK)
73 return rc;
75 lpriv->encprivpart = shishi_asn1_encprivpart (handle);
76 if (lpriv->priv == NULL)
77 return SHISHI_ASN1_ERROR;
79 rc = shishi_asn1_write (handle, lpriv->encprivpart, "timestamp",
80 shishi_generalize_time (handle, time (NULL)), 0);
81 if (rc != SHISHI_OK)
82 return rc;
84 gettimeofday (&tv, &tz);
85 asprintf (&usec, "%ld", tv.tv_usec % 1000000);
86 rc = shishi_asn1_write (handle, lpriv->encprivpart, "usec", usec, 0);
87 free (usec);
88 if (rc != SHISHI_OK)
89 return rc;
91 rc = shishi_asn1_write (handle, lpriv->encprivpart, "seq-number", NULL, 0);
92 if (rc != SHISHI_OK)
93 return rc;
95 rc = shishi_asn1_write (handle, lpriv->encprivpart, "s-address.addr-type",
96 /* directional */
97 "3", 0);
98 if (rc != SHISHI_OK)
99 return rc;
101 rc = shishi_asn1_write (handle, lpriv->encprivpart, "s-address.address",
102 /* sender */
103 "\x00\x00\x00\x00", 4);
104 if (rc != SHISHI_OK)
105 return rc;
107 rc = shishi_asn1_write (handle, lpriv->encprivpart, "r-address",
108 NULL, 0);
109 if (rc != SHISHI_OK)
110 return rc;
112 return SHISHI_OK;
116 * shishi_priv_done:
117 * @priv: structure that holds information about PRIV exchange
119 * Deallocate resources associated with PRIV exchange. This should be
120 * called by the application when it no longer need to utilize the
121 * PRIV exchange handle.
123 void
124 shishi_priv_done (Shishi_priv * priv)
126 shishi_asn1_done (priv->handle, priv->priv);
127 shishi_asn1_done (priv->handle, priv->encprivpart);
128 shishi_key_done (priv->key);
129 free (priv);
133 * shishi_priv_key:
134 * @priv: structure that holds information about PRIV exchange
136 * Return value: Returns the key used in the PRIV exchange, or NULL if
137 * not yet set or an error occured.
139 Shishi_key *
140 shishi_priv_key (Shishi_priv * priv)
142 return priv->key;
146 * shishi_priv_key_set:
147 * @priv: structure that holds information about PRIV exchange
148 * @key: key to store in PRIV.
150 * Set the Key in the PRIV exchange.
152 void
153 shishi_priv_key_set (Shishi_priv * priv, Shishi_key * key)
155 shishi_key_copy (priv->key, key);
159 * shishi_priv_priv:
160 * @priv: structure that holds information about PRIV exchange
162 * Return value: Returns the ASN.1 priv in the PRIV exchange, or NULL if
163 * not yet set or an error occured.
165 Shishi_asn1
166 shishi_priv_priv (Shishi_priv * priv)
168 return priv->priv;
172 * shishi_priv_priv_set:
173 * @priv: structure that holds information about PRIV exchange
174 * @asn1priv: KRB-PRIV to store in PRIV exchange.
176 * Set the KRB-PRIV in the PRIV exchange.
178 void
179 shishi_priv_priv_set (Shishi_priv * priv, Shishi_asn1 asn1priv)
181 if (priv->priv)
182 shishi_asn1_done (priv->handle, priv->priv);
183 priv->priv = asn1priv;
187 * shishi_priv_priv_der:
188 * @priv: priv as allocated by shishi_priv().
189 * @out: output array with newly allocated DER encoding of PRIV.
190 * @outlen: length of output array with DER encoding of PRIV.
192 * DER encode PRIV structure. Typically shishi_priv_build() is used
193 * to build the PRIV structure first. @out is allocated by this
194 * function, and it is the responsibility of caller to deallocate it.
196 * Return value: Returns SHISHI_OK iff successful.
199 shishi_priv_priv_der (Shishi_priv * priv, char **out, size_t * outlen)
201 int rc;
203 rc = shishi_new_a2d (priv->handle, priv->priv, out, outlen);
204 if (rc != SHISHI_OK)
205 return rc;
207 return SHISHI_OK;
211 * shishi_priv_priv_der_set:
212 * @priv: priv as allocated by shishi_priv().
213 * @der: input array with DER encoded KRB-PRIV.
214 * @derlen: length of input array with DER encoded KRB-PRIV.
216 * DER decode KRB-PRIV and set it PRIV exchange. If decoding fails, the
217 * KRB-PRIV in the PRIV exchange remains.
219 * Return value: Returns SHISHI_OK.
222 shishi_priv_priv_der_set (Shishi_priv * priv, char *der, size_t derlen)
224 Shishi_asn1 asn1priv;
226 asn1priv = shishi_der2asn1_priv (priv->handle, der, derlen);
228 if (asn1priv == NULL)
229 return SHISHI_ASN1_ERROR;
231 shishi_priv_priv_set (priv, asn1priv);
233 return SHISHI_OK;
237 * shishi_priv_encprivpart:
238 * @priv: structure that holds information about PRIV exchange
240 * Return value: Returns the ASN.1 encprivpart in the PRIV exchange, or NULL if
241 * not yet set or an error occured.
243 Shishi_asn1
244 shishi_priv_encprivpart (Shishi_priv * priv)
246 return priv->encprivpart;
250 * shishi_priv_encprivpart_set:
251 * @priv: structure that holds information about PRIV exchange
252 * @asn1encprivpart: ENCPRIVPART to store in PRIV exchange.
254 * Set the ENCPRIVPART in the PRIV exchange.
256 void
257 shishi_priv_encprivpart_set (Shishi_priv * priv, Shishi_asn1 asn1encprivpart)
259 if (priv->encprivpart)
260 shishi_asn1_done (priv->handle, priv->encprivpart);
261 priv->encprivpart = asn1encprivpart;
265 * shishi_priv_encprivpart_der:
266 * @priv: priv as allocated by shishi_priv().
267 * @out: output array with newly allocated DER encoding of ENCPRIVPART.
268 * @outlen: length of output array with DER encoding of ENCPRIVPART.
270 * DER encode ENCPRIVPART structure. Typically
271 * shishi_encprivpart_build() is used to build the ENCPRIVPART
272 * structure first. @out is allocated by this function, and it is the
273 * responsibility of caller to deallocate it.
275 * Return value: Returns SHISHI_OK iff successful.
278 shishi_priv_encprivpart_der (Shishi_priv * priv, char **out, size_t * outlen)
280 int rc;
282 rc = shishi_new_a2d (priv->handle, priv->encprivpart, out, outlen);
283 if (rc != SHISHI_OK)
284 return rc;
286 return SHISHI_OK;
290 * shishi_priv_encprivpart_der_set:
291 * @priv: priv as allocated by shishi_priv().
292 * @der: input array with DER encoded ENCPRIVPART.
293 * @derlen: length of input array with DER encoded ENCPRIVPART.
295 * DER decode ENCPRIVPART and set it PRIV exchange. If decoding
296 * fails, the ENCPRIVPART in the PRIV exchange remains.
298 * Return value: Returns SHISHI_OK.
301 shishi_priv_encprivpart_der_set (Shishi_priv * priv, char *der, size_t derlen)
303 Shishi_asn1 asn1encprivpart;
305 asn1encprivpart = shishi_der2asn1_encprivpart (priv->handle, der, derlen);
307 if (asn1encprivpart == NULL)
308 return SHISHI_ASN1_ERROR;
310 shishi_priv_encprivpart_set (priv, asn1encprivpart);
312 return SHISHI_OK;
316 * shishi_priv_print:
317 * @handle: shishi handle as allocated by shishi_init().
318 * @fh: file handle open for writing.
319 * @priv: PRIV to print.
321 * Print ASCII armored DER encoding of PRIV to file.
323 * Return value: Returns SHISHI_OK iff successful.
326 shishi_priv_print (Shishi * handle, FILE * fh, Shishi_asn1 priv)
328 return _shishi_print_armored_data (handle, fh, priv, "KRB-PRIV", NULL);
332 * shishi_priv_save:
333 * @handle: shishi handle as allocated by shishi_init().
334 * @fh: file handle open for writing.
335 * @priv: PRIV to save.
337 * Save DER encoding of PRIV to file.
339 * Return value: Returns SHISHI_OK iff successful.
342 shishi_priv_save (Shishi * handle, FILE * fh, Shishi_asn1 priv)
344 return _shishi_save_data (handle, fh, priv, "PRIV");
348 * shishi_priv_to_file:
349 * @handle: shishi handle as allocated by shishi_init().
350 * @priv: PRIV to save.
351 * @filetype: input variable specifying type of file to be written,
352 * see Shishi_filetype.
353 * @filename: input variable with filename to write to.
355 * Write PRIV to file in specified TYPE. The file will be
356 * truncated if it exists.
358 * Return value: Returns SHISHI_OK iff successful.
361 shishi_priv_to_file (Shishi * handle, Shishi_asn1 priv,
362 int filetype, char *filename)
364 FILE *fh;
365 int res;
367 if (VERBOSE (handle))
368 printf (_("Writing PRIV to %s...\n"), filename);
370 fh = fopen (filename, "w");
371 if (fh == NULL)
372 return SHISHI_FOPEN_ERROR;
374 if (VERBOSE (handle))
375 printf (_("Writing PRIV in %s format...\n"),
376 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
378 if (filetype == SHISHI_FILETYPE_TEXT)
379 res = shishi_priv_print (handle, fh, priv);
380 else
381 res = shishi_priv_save (handle, fh, priv);
382 if (res != SHISHI_OK)
383 return res;
385 res = fclose (fh);
386 if (res != 0)
387 return SHISHI_FCLOSE_ERROR;
389 if (VERBOSE (handle))
390 printf (_("Writing PRIV to %s...done\n"), filename);
392 return SHISHI_OK;
396 * shishi_priv_parse:
397 * @handle: shishi handle as allocated by shishi_init().
398 * @fh: file handle open for reading.
399 * @priv: output variable with newly allocated PRIV.
401 * Read ASCII armored DER encoded PRIV from file and populate given
402 * variable.
404 * Return value: Returns SHISHI_OK iff successful.
407 shishi_priv_parse (Shishi * handle, FILE * fh, Shishi_asn1 * priv)
409 return _shishi_priv_input (handle, fh, priv, 0);
413 * shishi_priv_read:
414 * @handle: shishi handle as allocated by shishi_init().
415 * @fh: file handle open for reading.
416 * @priv: output variable with newly allocated PRIV.
418 * Read DER encoded PRIV from file and populate given variable.
420 * Return value: Returns SHISHI_OK iff successful.
423 shishi_priv_read (Shishi * handle, FILE * fh, Shishi_asn1 * priv)
425 return _shishi_priv_input (handle, fh, priv, 1);
429 * shishi_priv_from_file:
430 * @handle: shishi handle as allocated by shishi_init().
431 * @priv: output variable with newly allocated PRIV.
432 * @filetype: input variable specifying type of file to be read,
433 * see Shishi_filetype.
434 * @filename: input variable with filename to read from.
436 * Read PRIV from file in specified TYPE.
438 * Return value: Returns SHISHI_OK iff successful.
441 shishi_priv_from_file (Shishi * handle, Shishi_asn1 * priv,
442 int filetype, const char *filename)
444 int res;
445 FILE *fh;
447 if (VERBOSE (handle))
448 printf (_("Reading PRIV from %s...\n"), filename);
450 fh = fopen (filename, "r");
451 if (fh == NULL)
452 return SHISHI_FOPEN_ERROR;
454 if (VERBOSE (handle))
455 printf (_("Reading PRIV in %s format...\n"),
456 filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
458 if (filetype == SHISHI_FILETYPE_TEXT)
459 res = shishi_priv_parse (handle, fh, priv);
460 else
461 res = shishi_priv_read (handle, fh, priv);
462 if (res != SHISHI_OK)
463 return res;
465 res = fclose (fh);
466 if (res != 0)
467 return SHISHI_FCLOSE_ERROR;
469 if (VERBOSE (handle))
470 printf (_("Reading PRIV from %s...done\n"), filename);
472 return SHISHI_OK;
476 * shishi_priv_enc_part_etype:
477 * @handle: shishi handle as allocated by shishi_init().
478 * @priv: PRIV variable to get value from.
479 * @etype: output variable that holds the value.
481 * Extract PRIV.enc-part.etype.
483 * Return value: Returns SHISHI_OK iff successful.
486 shishi_priv_enc_part_etype (Shishi * handle,
487 Shishi_asn1 priv,
488 int32_t * etype)
490 return shishi_asn1_read_int32 (handle, priv, "enc-part.etype", etype);
494 * shishi_priv_set_enc_part:
495 * @handle: shishi handle as allocated by shishi_init().
496 * @priv: priv as allocated by shishi_priv().
497 * @etype: input encryption type to store in PRIV.
498 * @encpart: input encrypted data to store in PRIV.
499 * @encpartlen: size of input encrypted data to store in PRIV.
501 * Store encrypted data in PRIV. The encrypted data is usually
502 * created by calling shishi_encrypt() on some application specific
503 * data using the key from the ticket that is being used. To save
504 * time, you may want to use shishi_priv_build() instead, which
505 * encryptes the data and calls this function in one step.
507 * Return value: Returns SHISHI_OK iff successful.
510 shishi_priv_set_enc_part (Shishi * handle,
511 Shishi_asn1 priv,
512 int32_t etype,
513 const char *encpart, size_t encpartlen)
515 int res;
517 res = shishi_asn1_write_integer (handle, priv, "enc-part.etype", etype);
518 if (res != SHISHI_OK)
519 return res;
521 res = shishi_asn1_write (handle, priv, "enc-part.cipher",
522 encpart, encpartlen);
523 if (res != SHISHI_OK)
524 return res;
526 return SHISHI_OK;
530 * shishi_encprivpart_user_data:
531 * @handle: shishi handle as allocated by shishi_init().
532 * @encprivpart: encprivpart as allocated by shishi_priv().
533 * @userdata: output array with newly allocated user data from KRB-PRIV.
534 * @userdatalen: output size of output user data buffer.
536 * Read user data value from KRB-PRIV. @userdata is allocated by this
537 * function, and it is the responsibility of caller to deallocate it.
539 * Return value: Returns SHISHI_OK iff successful.
542 shishi_encprivpart_user_data (Shishi * handle,
543 Shishi_asn1 encprivpart,
544 char **userdata, size_t * userdatalen)
546 int res;
548 res = shishi_asn1_read2 (handle, encprivpart, "user-data",
549 userdata, userdatalen);
550 if (res != SHISHI_OK)
551 return res;
553 return SHISHI_OK;
557 * shishi_encprivpart_set_user_data:
558 * @handle: shishi handle as allocated by shishi_init().
559 * @encprivpart: encprivpart as allocated by shishi_priv().
560 * @userdata: input user application to store in PRIV.
561 * @userdatalen: size of input user application to store in PRIV.
563 * Set the application data in PRIV.
565 * Return value: Returns SHISHI_OK iff successful.
568 shishi_encprivpart_set_user_data (Shishi * handle,
569 Shishi_asn1 encprivpart,
570 const char *userdata, size_t userdatalen)
572 int res;
574 res = shishi_asn1_write (handle, encprivpart, "user-data",
575 userdata, userdatalen);
576 if (res != SHISHI_OK)
577 return res;
579 return SHISHI_OK;
583 * shishi_priv_build:
584 * @priv: priv as allocated by shishi_priv().
585 * @key: key for session, used to encrypt data.
587 * Build checksum and set it in KRB-PRIV. Note that this follows RFC
588 * 1510bis and is incompatible with RFC 1510, although presumably few
589 * implementations use the RFC1510 algorithm.
591 * Return value: Returns SHISHI_OK iff successful.
594 shishi_priv_build (Shishi_priv * priv, Shishi_key * key)
596 int res;
597 char *buf;
598 size_t buflen;
599 char *der;
600 size_t derlen;
602 res = shishi_new_a2d (priv->handle, priv->encprivpart, &der, &derlen);
603 if (res != SHISHI_OK)
605 shishi_error_printf (priv->handle,
606 "Could not DER encode EncPrivPart: %s\n",
607 shishi_strerror (res));
608 return res;
611 res = shishi_encrypt (priv->handle, key, SHISHI_KEYUSAGE_KRB_PRIV,
612 der, derlen, &buf, &buflen);
614 free (der);
616 if (res != SHISHI_OK)
618 shishi_error_printf (priv->handle, "Cannot encrypt EncPrivPart.\n");
619 return res;
622 res = shishi_priv_set_enc_part (priv->handle, priv->priv,
623 shishi_key_type (key),
624 buf, buflen);
625 if (res != SHISHI_OK)
626 return res;
628 return SHISHI_OK;
632 * shishi_priv_process:
633 * @priv: priv as allocated by shishi_priv().
634 * @key: key to use to decrypt EncPrivPart.
636 * Decrypt encrypted data in KRB-PRIV and set the EncPrivPart in the
637 * PRIV exchange.
639 * Return value: Returns SHISHI_OK iff successful,
640 * SHISHI_PRIV_BAD_KEYTYPE if an incompatible key type is used, or
641 * SHISHI_CRYPTO_ERROR if the actual decryption failed.
644 shishi_priv_process (Shishi_priv * priv, Shishi_key * key)
646 int res;
647 int i;
648 char *buf;
649 size_t buflen;
650 char *cipher;
651 size_t cipherlen;
652 int32_t etype;
654 res = shishi_priv_enc_part_etype (priv->handle, priv->priv, &etype);
655 if (res != SHISHI_OK)
656 return res;
658 if (etype != shishi_key_type (key))
659 return SHISHI_PRIV_BAD_KEYTYPE;
661 res = shishi_asn1_read2 (priv->handle, priv->priv, "enc-part.cipher",
662 &cipher, &cipherlen);
663 if (res != SHISHI_OK)
664 return res;
666 res = shishi_decrypt (priv->handle, key, SHISHI_KEYUSAGE_KRB_PRIV,
667 cipher, cipherlen, &buf, &buflen);
668 free (cipher);
669 if (res != SHISHI_OK)
671 shishi_error_printf (priv->handle, "PRIV decryption failed, bad key?\n");
672 return res;
675 /* The crypto is so 1980; no length indicator. Trim off pad bytes
676 until we can parse it. */
677 for (i = 0; i < 8; i++)
679 if (VERBOSEASN1 (priv->handle))
680 printf ("Trying with %d pad in enckdcrep...\n", i);
682 priv->encprivpart = shishi_der2asn1_encprivpart (priv->handle, &buf[0],
683 buflen - i);
684 if (priv->encprivpart != NULL)
685 break;
688 free (buf);
690 if (priv->encprivpart == NULL)
692 shishi_error_printf (priv->handle, "Could not DER decode EncPrivPart. "
693 "Key probably correct (decrypt ok) though\n");
694 return SHISHI_ASN1_ERROR;
697 return SHISHI_OK;