1 /* encapreppart.c --- Encrypted authentication reply part functions.
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 /**
29  * shishi_encapreppart:
30  * @handle: shishi handle as allocated by shishi_init().
31  *
32  * This function creates a new EncAPRepPart, populated with some
33  * default values.  It uses the current time as returned by the system
34  * for the ctime and cusec fields.
35  *
36  * Return value: Returns the encapreppart or NULL on failure.
37  **/
38 Shishi_asn1
shishi_encapreppart(Shishi * handle)39 shishi_encapreppart (Shishi * handle)
40 {
41   int res;
42   Shishi_asn1 node = NULL;
43   struct timeval tv;
44   uint32_t seqnr;
45 
46   res = gettimeofday (&tv, NULL);
47   if (res)
48     return NULL;
49 
50   node = shishi_asn1_encapreppart (handle);
51   if (!node)
52     return NULL;
53 
54   res = shishi_asn1_write (handle, node, "ctime",
55 			   shishi_generalize_time (handle, time (NULL)), 0);
56   if (res != SHISHI_OK)
57     goto error;
58 
59   res = shishi_encapreppart_cusec_set (handle, node, tv.tv_usec % 1000000);
60   if (res != SHISHI_OK)
61     goto error;
62 
63   res = shishi_asn1_write (handle, node, "subkey", NULL, 0);
64   if (res != SHISHI_OK)
65     goto error;
66 
67   /*
68    * For sequence numbers to adequately support the detection of
69    * replays they SHOULD be non-repeating, even across connection
70    * boundaries. The initial sequence number SHOULD be random and
71    * uniformly distributed across the full space of possible sequence
72    * numbers, so that it cannot be guessed by an attacker and so that
73    * it and the successive sequence numbers do not repeat other
74    * sequences.
75    */
76   shishi_randomize (handle, 0, &seqnr, sizeof (seqnr));
77 
78   /*
79    * Implementation note: as noted before, some implementations omit
80    * the optional sequence number when its value would be zero.
81    * Implementations MAY accept an omitted sequence number when
82    * expecting a value of zero, and SHOULD NOT transmit an
83    * Authenticator with a initial sequence number of zero.
84    */
85   if (seqnr == 0)
86     seqnr++;
87 
88   res = shishi_encapreppart_seqnumber_set (handle, node, seqnr);
89   if (res != SHISHI_OK)
90     goto error;
91 
92   return node;
93 
94 error:
95   shishi_asn1_done (handle, node);
96   return NULL;
97 }
98 
99 /**
100  * shishi_encapreppart_print:
101  * @handle: shishi handle as allocated by shishi_init().
102  * @fh: file handle open for writing.
103  * @encapreppart: EncAPRepPart to print.
104  *
105  * Print ASCII armored DER encoding of EncAPRepPart to file.
106  *
107  * Return value: Returns SHISHI_OK iff successful.
108  **/
109 int
shishi_encapreppart_print(Shishi * handle,FILE * fh,Shishi_asn1 encapreppart)110 shishi_encapreppart_print (Shishi * handle, FILE * fh,
111 			   Shishi_asn1 encapreppart)
112 {
113   return _shishi_print_armored_data (handle, fh, encapreppart,
114 				     "EncAPRepPart", NULL);
115 }
116 
117 /**
118  * shishi_encapreppart_save:
119  * @handle: shishi handle as allocated by shishi_init().
120  * @fh: file handle open for writing.
121  * @encapreppart: EncAPRepPart to save.
122  *
123  * Save DER encoding of EncAPRepPart to file.
124  *
125  * Return value: Returns SHISHI_OK iff successful.
126  **/
127 int
shishi_encapreppart_save(Shishi * handle,FILE * fh,Shishi_asn1 encapreppart)128 shishi_encapreppart_save (Shishi * handle, FILE * fh,
129 			  Shishi_asn1 encapreppart)
130 {
131   return _shishi_save_data (handle, fh, encapreppart, "EncAPRepPart");
132 }
133 
134 /**
135  * shishi_encapreppart_to_file:
136  * @handle: shishi handle as allocated by shishi_init().
137  * @encapreppart: EncAPRepPart to save.
138  * @filetype: input variable specifying type of file to be written,
139  *            see Shishi_filetype.
140  * @filename: input variable with filename to write to.
141  *
142  * Write EncAPRepPart to file in specified TYPE.  The file will be
143  * truncated if it exists.
144  *
145  * Return value: Returns SHISHI_OK iff successful.
146  **/
147 int
shishi_encapreppart_to_file(Shishi * handle,Shishi_asn1 encapreppart,int filetype,const char * filename)148 shishi_encapreppart_to_file (Shishi * handle, Shishi_asn1 encapreppart,
149 			     int filetype, const char *filename)
150 {
151   FILE *fh;
152   int res;
153 
154   if (VERBOSE (handle))
155     printf (_("Writing EncAPRepPart to %s...\n"), filename);
156 
157   fh = fopen (filename, "w");
158   if (fh == NULL)
159     return SHISHI_FOPEN_ERROR;
160 
161   if (VERBOSE (handle))
162     printf (_("Writing EncAPRepPart in %s format...\n"),
163 	    filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
164 
165   if (filetype == SHISHI_FILETYPE_TEXT)
166     res = shishi_encapreppart_print (handle, fh, encapreppart);
167   else
168     res = shishi_encapreppart_save (handle, fh, encapreppart);
169   if (res != SHISHI_OK)
170     return res;
171 
172   res = fclose (fh);
173   if (res != 0)
174     return SHISHI_IO_ERROR;
175 
176   if (VERBOSE (handle))
177     printf (_("Writing EncAPRepPart to %s...done\n"), filename);
178 
179   return SHISHI_OK;
180 }
181 
182 /**
183  * shishi_encapreppart_parse:
184  * @handle: shishi handle as allocated by shishi_init().
185  * @fh: file handle open for reading.
186  * @encapreppart: output variable with newly allocated EncAPRepPart.
187  *
188  * Read ASCII armored DER encoded EncAPRepPart from file and populate given
189  * variable.
190  *
191  * Return value: Returns SHISHI_OK iff successful.
192  **/
193 int
shishi_encapreppart_parse(Shishi * handle,FILE * fh,Shishi_asn1 * encapreppart)194 shishi_encapreppart_parse (Shishi * handle, FILE * fh,
195 			   Shishi_asn1 * encapreppart)
196 {
197   return _shishi_encapreppart_input (handle, fh, encapreppart, 0);
198 }
199 
200 /**
201  * shishi_encapreppart_read:
202  * @handle: shishi handle as allocated by shishi_init().
203  * @fh: file handle open for reading.
204  * @encapreppart: output variable with newly allocated EncAPRepPart.
205  *
206  * Read DER encoded EncAPRepPart from file and populate given variable.
207  *
208  * Return value: Returns SHISHI_OK iff successful.
209  **/
210 int
shishi_encapreppart_read(Shishi * handle,FILE * fh,Shishi_asn1 * encapreppart)211 shishi_encapreppart_read (Shishi * handle, FILE * fh,
212 			  Shishi_asn1 * encapreppart)
213 {
214   return _shishi_encapreppart_input (handle, fh, encapreppart, 1);
215 }
216 
217 /**
218  * shishi_encapreppart_from_file:
219  * @handle: shishi handle as allocated by shishi_init().
220  * @encapreppart: output variable with newly allocated EncAPRepPart.
221  * @filetype: input variable specifying type of file to be read,
222  *            see Shishi_filetype.
223  * @filename: input variable with filename to read from.
224  *
225  * Read EncAPRepPart from file in specified TYPE.
226  *
227  * Return value: Returns SHISHI_OK iff successful.
228  **/
229 int
shishi_encapreppart_from_file(Shishi * handle,Shishi_asn1 * encapreppart,int filetype,const char * filename)230 shishi_encapreppart_from_file (Shishi * handle, Shishi_asn1 * encapreppart,
231 			       int filetype, const char *filename)
232 {
233   int res;
234   FILE *fh;
235 
236   if (VERBOSE (handle))
237     printf (_("Reading EncAPRepPart from %s...\n"), filename);
238 
239   fh = fopen (filename, "r");
240   if (fh == NULL)
241     return SHISHI_FOPEN_ERROR;
242 
243   if (VERBOSE (handle))
244     printf (_("Reading EncAPRepPart in %s format...\n"),
245 	    filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
246 
247   if (filetype == SHISHI_FILETYPE_TEXT)
248     res = shishi_encapreppart_parse (handle, fh, encapreppart);
249   else
250     res = shishi_encapreppart_read (handle, fh, encapreppart);
251   if (res != SHISHI_OK)
252     return res;
253 
254   res = fclose (fh);
255   if (res != 0)
256     return SHISHI_IO_ERROR;
257 
258   if (VERBOSE (handle))
259     printf (_("Reading EncAPRepPart from %s...done\n"), filename);
260 
261   return SHISHI_OK;
262 }
263 
264 /**
265  * shishi_encapreppart_get_key:
266  * @handle: shishi handle as allocated by shishi_init().
267  * @encapreppart: input EncAPRepPart variable.
268  * @key: newly allocated key.
269  *
270  * Extract the subkey from the encrypted AP-REP part.
271  *
272  * Return value: Returns %SHISHI_OK iff successful.
273  **/
274 int
shishi_encapreppart_get_key(Shishi * handle,Shishi_asn1 encapreppart,Shishi_key ** key)275 shishi_encapreppart_get_key (Shishi * handle,
276 			     Shishi_asn1 encapreppart, Shishi_key ** key)
277 {
278   int res;
279   char *buf;
280   size_t buflen;
281   int32_t keytype;
282 
283   res = shishi_asn1_read_int32 (handle, encapreppart,
284 				"subkey.keytype", &keytype);
285   if (res != SHISHI_OK)
286     return res;
287 
288   res = shishi_asn1_read (handle, encapreppart, "subkey.keyvalue",
289 			  &buf, &buflen);
290   if (res != SHISHI_OK)
291     return res;
292 
293   if (shishi_cipher_keylen (keytype) != buflen)
294     return SHISHI_ENCAPREPPART_BAD_KEYTYPE;
295 
296   res = shishi_key_from_value (handle, keytype, buf, key);
297   free (buf);
298   if (res != SHISHI_OK)
299     return res;
300 
301   return SHISHI_OK;
302 }
303 
304 /**
305  * shishi_encapreppart_ctime:
306  * @handle: shishi handle as allocated by shishi_init().
307  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
308  * @t: newly allocated zero-terminated character array with client time.
309  *
310  * Extract client time from EncAPRepPart.
311  *
312  * Return value: Returns SHISHI_OK iff successful.
313  **/
314 int
shishi_encapreppart_ctime(Shishi * handle,Shishi_asn1 encapreppart,char ** t)315 shishi_encapreppart_ctime (Shishi * handle,
316 			   Shishi_asn1 encapreppart, char **t)
317 {
318   return shishi_time (handle, encapreppart, "ctime", t);
319 }
320 
321 /**
322  * shishi_encapreppart_ctime_set:
323  * @handle: shishi handle as allocated by shishi_init().
324  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
325  * @t: string with generalized time value to store in EncAPRepPart.
326  *
327  * Store client time in EncAPRepPart.
328  *
329  * Return value: Returns SHISHI_OK iff successful.
330  **/
331 int
shishi_encapreppart_ctime_set(Shishi * handle,Shishi_asn1 encapreppart,const char * t)332 shishi_encapreppart_ctime_set (Shishi * handle,
333 			       Shishi_asn1 encapreppart, const char *t)
334 {
335   int res;
336 
337   res = shishi_asn1_write (handle, encapreppart, "ctime",
338 			   t, SHISHI_GENERALIZEDTIME_LENGTH);
339   if (res != SHISHI_OK)
340     return res;
341 
342   return SHISHI_OK;
343 }
344 
345 /**
346  * shishi_encapreppart_cusec_get:
347  * @handle: shishi handle as allocated by shishi_init().
348  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
349  * @cusec: output integer with client microseconds field.
350  *
351  * Extract client microseconds field from EncAPRepPart.
352  *
353  * Return value: Returns SHISHI_OK iff successful.
354  **/
355 int
shishi_encapreppart_cusec_get(Shishi * handle,Shishi_asn1 encapreppart,uint32_t * cusec)356 shishi_encapreppart_cusec_get (Shishi * handle,
357 			       Shishi_asn1 encapreppart, uint32_t * cusec)
358 {
359   int res;
360 
361   res = shishi_asn1_read_uint32 (handle, encapreppart, "cusec", cusec);
362   if (res != SHISHI_OK)
363     return res;
364 
365   return res;
366 }
367 
368 /**
369  * shishi_encapreppart_cusec_set:
370  * @handle: shishi handle as allocated by shishi_init().
371  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
372  * @cusec: client microseconds to set in authenticator, 0-999999.
373  *
374  * Set the cusec field in the Authenticator.
375  *
376  * Return value: Returns SHISHI_OK iff successful.
377  **/
378 int
shishi_encapreppart_cusec_set(Shishi * handle,Shishi_asn1 encapreppart,uint32_t cusec)379 shishi_encapreppart_cusec_set (Shishi * handle,
380 			       Shishi_asn1 encapreppart, uint32_t cusec)
381 {
382   int res;
383 
384   res = shishi_asn1_write_integer (handle, encapreppart, "cusec", cusec);
385   if (res != SHISHI_OK)
386     return res;
387 
388   return SHISHI_OK;
389 }
390 
391 /**
392  * shishi_encapreppart_seqnumber_get:
393  * @handle: shishi handle as allocated by shishi_init().
394  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
395  * @seqnumber: output integer with sequence number field.
396  *
397  * Extract sequence number field from EncAPRepPart.
398  *
399  * Return value: Returns SHISHI_OK iff successful.
400  **/
401 int
shishi_encapreppart_seqnumber_get(Shishi * handle,Shishi_asn1 encapreppart,uint32_t * seqnumber)402 shishi_encapreppart_seqnumber_get (Shishi * handle,
403 				   Shishi_asn1 encapreppart,
404 				   uint32_t * seqnumber)
405 {
406   int res;
407 
408   res = shishi_asn1_read_uint32 (handle, encapreppart,
409 				 "seq-number", seqnumber);
410   if (res != SHISHI_OK)
411     return res;
412 
413   return res;
414 }
415 
416 /**
417  * shishi_encapreppart_seqnumber_remove:
418  * @handle: shishi handle as allocated by shishi_init().
419  * @encapreppart: encapreppart as allocated by shishi_encapreppart().
420  *
421  * Remove sequence number field in EncAPRepPart.
422  *
423  * Return value: Returns %SHISHI_OK iff successful.
424  **/
425 int
shishi_encapreppart_seqnumber_remove(Shishi * handle,Shishi_asn1 encapreppart)426 shishi_encapreppart_seqnumber_remove (Shishi * handle,
427 				      Shishi_asn1 encapreppart)
428 {
429   int res;
430 
431   res = shishi_asn1_write (handle, encapreppart, "seq-number", NULL, 0);
432   if (res != SHISHI_OK)
433     return res;
434 
435   return SHISHI_OK;
436 }
437 
438 /**
439  * shishi_encapreppart_seqnumber_set:
440  * @handle: shishi handle as allocated by shishi_init().
441  * @encapreppart: encapreppart as allocated by shishi_encapreppart().
442  * @seqnumber: integer with sequence number field to store in encapreppart.
443  *
444  * Store sequence number field in EncAPRepPart.
445  *
446  * Return value: Returns %SHISHI_OK iff successful.
447  **/
448 int
shishi_encapreppart_seqnumber_set(Shishi * handle,Shishi_asn1 encapreppart,uint32_t seqnumber)449 shishi_encapreppart_seqnumber_set (Shishi * handle,
450 				   Shishi_asn1 encapreppart,
451 				   uint32_t seqnumber)
452 {
453   int res;
454 
455   res = shishi_asn1_write_uint32 (handle, encapreppart,
456 				  "seq-number", seqnumber);
457   if (res != SHISHI_OK)
458     return res;
459 
460   return SHISHI_OK;
461 }
462 
463 /**
464  * shishi_encapreppart_time_copy:
465  * @handle: shishi handle as allocated by shishi_init().
466  * @encapreppart: EncAPRepPart as allocated by shishi_encapreppart().
467  * @authenticator: Authenticator to copy time fields from.
468  *
469  * Copy time fields from Authenticator into EncAPRepPart.
470  *
471  * Return value: Returns SHISHI_OK iff successful.
472  **/
473 int
shishi_encapreppart_time_copy(Shishi * handle,Shishi_asn1 encapreppart,Shishi_asn1 authenticator)474 shishi_encapreppart_time_copy (Shishi * handle,
475 			       Shishi_asn1 encapreppart,
476 			       Shishi_asn1 authenticator)
477 {
478   char *buf;
479   size_t buflen;
480   int res;
481 
482   res = shishi_asn1_read (handle, authenticator, "cusec", &buf, &buflen);
483   if (res != SHISHI_OK)
484     return res;
485 
486   res = shishi_asn1_write (handle, encapreppart, "cusec", buf, buflen);
487   free (buf);
488   if (res != SHISHI_OK)
489     return res;
490 
491   res = shishi_asn1_read (handle, authenticator, "ctime", &buf, &buflen);
492   if (res != SHISHI_OK)
493     return res;
494 
495   res = shishi_asn1_write (handle, encapreppart, "ctime", buf, buflen);
496   free (buf);
497   if (res != SHISHI_OK)
498     return res;
499 
500   return SHISHI_OK;
501 }
502