1 /* aprep.c --- AP-REP 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 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 but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * 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 #define SHISHI_APREP_DEFAULT_PVNO "5"
29 #define SHISHI_APREP_DEFAULT_PVNO_LEN 0
30 #define SHISHI_APREP_DEFAULT_MSG_TYPE      "15"	/* KRB_AP_REP */
31 #define SHISHI_APREP_DEFAULT_MSG_TYPE_LEN  0
32 #define SHISHI_APREP_DEFAULT_ENC_PART_ETYPE "0"
33 #define SHISHI_APREP_DEFAULT_ENC_PART_ETYPE_LEN 0
34 #define SHISHI_APREP_DEFAULT_ENC_PART_KVNO "0"
35 #define SHISHI_APREP_DEFAULT_ENC_PART_KVNO_LEN 0
36 #define SHISHI_APREP_DEFAULT_ENC_PART_CIPHER ""
37 #define SHISHI_APREP_DEFAULT_ENC_PART_CIPHER_LEN 0
38 
39 /**
40  * shishi_aprep:
41  * @handle: shishi handle as allocated by shishi_init().
42  *
43  * This function creates a new AP-REP, populated with some default
44  * values.
45  *
46  * Return value: Returns the authenticator or NULL on
47  * failure.
48  **/
49 Shishi_asn1
shishi_aprep(Shishi * handle)50 shishi_aprep (Shishi * handle)
51 {
52   Shishi_asn1 node;
53   int res;
54 
55   node = shishi_asn1_aprep (handle);
56   if (!node)
57     return NULL;
58 
59   res = shishi_asn1_write (handle, node, "pvno",
60 			   SHISHI_APREP_DEFAULT_PVNO,
61 			   SHISHI_APREP_DEFAULT_PVNO_LEN);
62   if (res != SHISHI_OK)
63     goto error;
64 
65   res = shishi_asn1_write (handle, node, "msg-type",
66 			   SHISHI_APREP_DEFAULT_MSG_TYPE,
67 			   SHISHI_APREP_DEFAULT_MSG_TYPE_LEN);
68   if (res != SHISHI_OK)
69     goto error;
70 
71   res = shishi_asn1_write (handle, node, "enc-part.etype",
72 			   SHISHI_APREP_DEFAULT_ENC_PART_ETYPE,
73 			   SHISHI_APREP_DEFAULT_ENC_PART_ETYPE_LEN);
74   if (res != SHISHI_OK)
75     goto error;
76 
77   res = shishi_asn1_write (handle, node, "enc-part.kvno",
78 			   SHISHI_APREP_DEFAULT_ENC_PART_KVNO,
79 			   SHISHI_APREP_DEFAULT_ENC_PART_KVNO_LEN);
80   if (res != SHISHI_OK)
81     goto error;
82 
83   res = shishi_asn1_write (handle, node, "enc-part.cipher",
84 			   SHISHI_APREP_DEFAULT_ENC_PART_CIPHER,
85 			   SHISHI_APREP_DEFAULT_ENC_PART_CIPHER_LEN);
86   if (res != SHISHI_OK)
87     goto error;
88 
89   return node;
90 
91 error:
92   shishi_asn1_done (handle, node);
93   return NULL;
94 }
95 
96 /**
97  * shishi_aprep_print:
98  * @handle: shishi handle as allocated by shishi_init().
99  * @fh: file handle open for writing.
100  * @aprep: AP-REP to print.
101  *
102  * Print ASCII armored DER encoding of AP-REP to file.
103  *
104  * Return value: Returns SHISHI_OK iff successful.
105  **/
106 int
shishi_aprep_print(Shishi * handle,FILE * fh,Shishi_asn1 aprep)107 shishi_aprep_print (Shishi * handle, FILE * fh, Shishi_asn1 aprep)
108 {
109   return _shishi_print_armored_data (handle, fh, aprep, "AP-REP", NULL);
110 }
111 
112 /**
113  * shishi_aprep_save:
114  * @handle: shishi handle as allocated by shishi_init().
115  * @fh: file handle open for writing.
116  * @aprep: AP-REP to save.
117  *
118  * Save DER encoding of AP-REP to file.
119  *
120  * Return value: Returns SHISHI_OK iff successful.
121  **/
122 int
shishi_aprep_save(Shishi * handle,FILE * fh,Shishi_asn1 aprep)123 shishi_aprep_save (Shishi * handle, FILE * fh, Shishi_asn1 aprep)
124 {
125   return _shishi_save_data (handle, fh, aprep, "AP-REP");
126 }
127 
128 /**
129  * shishi_aprep_to_file:
130  * @handle: shishi handle as allocated by shishi_init().
131  * @aprep: AP-REP to save.
132  * @filetype: input variable specifying type of file to be written,
133  *            see Shishi_filetype.
134  * @filename: input variable with filename to write to.
135  *
136  * Write AP-REP to file in specified TYPE.  The file will be
137  * truncated if it exists.
138  *
139  * Return value: Returns SHISHI_OK iff successful.
140  **/
141 int
shishi_aprep_to_file(Shishi * handle,Shishi_asn1 aprep,int filetype,const char * filename)142 shishi_aprep_to_file (Shishi * handle, Shishi_asn1 aprep,
143 		      int filetype, const char *filename)
144 {
145   FILE *fh;
146   int res;
147 
148   if (VERBOSE (handle))
149     printf (_("Writing AP-REP to %s...\n"), filename);
150 
151   fh = fopen (filename, "w");
152   if (fh == NULL)
153     return SHISHI_FOPEN_ERROR;
154 
155   if (VERBOSE (handle))
156     printf (_("Writing AP-REP in %s format...\n"),
157 	    filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
158 
159   if (filetype == SHISHI_FILETYPE_TEXT)
160     res = shishi_aprep_print (handle, fh, aprep);
161   else
162     res = shishi_aprep_save (handle, fh, aprep);
163   if (res != SHISHI_OK)
164     return res;
165 
166   res = fclose (fh);
167   if (res != 0)
168     return SHISHI_IO_ERROR;
169 
170   if (VERBOSE (handle))
171     printf (_("Writing AP-REP to %s...done\n"), filename);
172 
173   return SHISHI_OK;
174 }
175 
176 /**
177  * shishi_aprep_parse:
178  * @handle: shishi handle as allocated by shishi_init().
179  * @fh: file handle open for reading.
180  * @aprep: output variable with newly allocated AP-REP.
181  *
182  * Read ASCII armored DER encoded AP-REP from file and populate given
183  * variable.
184  *
185  * Return value: Returns SHISHI_OK iff successful.
186  **/
187 int
shishi_aprep_parse(Shishi * handle,FILE * fh,Shishi_asn1 * aprep)188 shishi_aprep_parse (Shishi * handle, FILE * fh, Shishi_asn1 * aprep)
189 {
190   return _shishi_aprep_input (handle, fh, aprep, 0);
191 }
192 
193 /**
194  * shishi_aprep_read:
195  * @handle: shishi handle as allocated by shishi_init().
196  * @fh: file handle open for reading.
197  * @aprep: output variable with newly allocated AP-REP.
198  *
199  * Read DER encoded AP-REP from file and populate given variable.
200  *
201  * Return value: Returns SHISHI_OK iff successful.
202  **/
203 int
shishi_aprep_read(Shishi * handle,FILE * fh,Shishi_asn1 * aprep)204 shishi_aprep_read (Shishi * handle, FILE * fh, Shishi_asn1 * aprep)
205 {
206   return _shishi_aprep_input (handle, fh, aprep, 1);
207 }
208 
209 /**
210  * shishi_aprep_from_file:
211  * @handle: shishi handle as allocated by shishi_init().
212  * @aprep: output variable with newly allocated AP-REP.
213  * @filetype: input variable specifying type of file to be read,
214  *            see Shishi_filetype.
215  * @filename: input variable with filename to read from.
216  *
217  * Read AP-REP from file in specified TYPE.
218  *
219  * Return value: Returns SHISHI_OK iff successful.
220  **/
221 int
shishi_aprep_from_file(Shishi * handle,Shishi_asn1 * aprep,int filetype,const char * filename)222 shishi_aprep_from_file (Shishi * handle, Shishi_asn1 * aprep,
223 			int filetype, const char *filename)
224 {
225   int res;
226   FILE *fh;
227 
228   if (VERBOSE (handle))
229     printf (_("Reading AP-REP from %s...\n"), filename);
230 
231   fh = fopen (filename, "r");
232   if (fh == NULL)
233     return SHISHI_FOPEN_ERROR;
234 
235   if (VERBOSE (handle))
236     printf (_("Reading AP-REP in %s format...\n"),
237 	    filetype == SHISHI_FILETYPE_TEXT ? "TEXT" : "DER");
238 
239   if (filetype == SHISHI_FILETYPE_TEXT)
240     res = shishi_aprep_parse (handle, fh, aprep);
241   else
242     res = shishi_aprep_read (handle, fh, aprep);
243   if (res != SHISHI_OK)
244     return res;
245 
246   res = fclose (fh);
247   if (res != 0)
248     return SHISHI_IO_ERROR;
249 
250   if (VERBOSE (handle))
251     printf (_("Reading AP-REP from %s...done\n"), filename);
252 
253   return SHISHI_OK;
254 }
255 
256 int
shishi_aprep_enc_part_set(Shishi * handle,Shishi_asn1 aprep,int etype,const char * buf,size_t buflen)257 shishi_aprep_enc_part_set (Shishi * handle,
258 			   Shishi_asn1 aprep,
259 			   int etype, const char *buf, size_t buflen)
260 {
261   int res;
262 
263   res = shishi_asn1_write (handle, aprep, "enc-part.cipher", buf, buflen);
264   if (res != SHISHI_OK)
265     return res;
266 
267   res = shishi_asn1_write_integer (handle, aprep, "enc-part.etype", etype);
268   if (res != SHISHI_OK)
269     return res;
270 
271   return SHISHI_OK;
272 }
273 
274 int
shishi_aprep_enc_part_add(Shishi * handle,Shishi_asn1 aprep,Shishi_asn1 encticketpart,Shishi_asn1 encapreppart)275 shishi_aprep_enc_part_add (Shishi * handle,
276 			   Shishi_asn1 aprep,
277 			   Shishi_asn1 encticketpart,
278 			   Shishi_asn1 encapreppart)
279 {
280   int res;
281   char *buf;
282   size_t buflen;
283   char *der;
284   size_t derlen;
285   Shishi_key *key;
286 
287   res = shishi_encticketpart_get_key (handle, encticketpart, &key);
288   if (res != SHISHI_OK)
289     return res;
290 
291   res = shishi_asn1_to_der (handle, encapreppart, &der, &derlen);
292   if (res != SHISHI_OK)
293     {
294       shishi_error_printf (handle, "Could not DER encode authenticator: %s\n",
295 			   shishi_strerror (res));
296       return !SHISHI_OK;
297     }
298 
299   der = xrealloc (der, derlen + 8);
300 
301   while ((derlen % 8) != 0)
302     {
303       der[derlen] = '\0';
304       derlen++;
305     }
306 
307   res = shishi_encrypt (handle, key, SHISHI_KEYUSAGE_ENCAPREPPART,
308 			der, derlen, &buf, &buflen);
309 
310   free (der);
311 
312   if (res != SHISHI_OK)
313     {
314       shishi_error_printf (handle, "APRep encryption failed\n");
315       return res;
316     }
317 
318   res = shishi_aprep_enc_part_set (handle, aprep, shishi_key_type (key),
319 				   buf, buflen);
320 
321   free (buf);
322 
323   return res;
324 }
325 
326 int
shishi_aprep_enc_part_make(Shishi * handle,Shishi_asn1 aprep,Shishi_asn1 encapreppart,Shishi_asn1 authenticator,Shishi_asn1 encticketpart)327 shishi_aprep_enc_part_make (Shishi * handle,
328 			    Shishi_asn1 aprep,
329 			    Shishi_asn1 encapreppart,
330 			    Shishi_asn1 authenticator,
331 			    Shishi_asn1 encticketpart)
332 {
333   int res;
334 
335   res = shishi_encapreppart_time_copy (handle, encapreppart, authenticator);
336   if (res != SHISHI_OK)
337     {
338       shishi_error_printf (handle, "Could not copy time: %s\n",
339 			   shishi_error (handle));
340       return res;
341     }
342 
343   res = shishi_aprep_enc_part_add (handle, aprep, encticketpart,
344 				   encapreppart);
345   if (res != SHISHI_OK)
346     {
347       shishi_error_printf (handle, "Could not add encapreppart: %s\n",
348 			   shishi_error (handle));
349       return res;
350     }
351 
352   return SHISHI_OK;
353 }
354 
355 /**
356  * shishi_aprep_get_enc_part_etype:
357  * @handle: shishi handle as allocated by shishi_init().
358  * @aprep: AP-REP variable to get value from.
359  * @etype: output variable that holds the value.
360  *
361  * Extract AP-REP.enc-part.etype.
362  *
363  * Return value: Returns SHISHI_OK iff successful.
364  **/
365 int
shishi_aprep_get_enc_part_etype(Shishi * handle,Shishi_asn1 aprep,int32_t * etype)366 shishi_aprep_get_enc_part_etype (Shishi * handle,
367 				 Shishi_asn1 aprep, int32_t * etype)
368 {
369   return shishi_asn1_read_int32 (handle, aprep, "enc-part.etype", etype);
370 }
371 
372 int
shishi_aprep_decrypt(Shishi * handle,Shishi_asn1 aprep,Shishi_key * key,int keyusage,Shishi_asn1 * encapreppart)373 shishi_aprep_decrypt (Shishi * handle,
374 		      Shishi_asn1 aprep,
375 		      Shishi_key * key,
376 		      int keyusage, Shishi_asn1 * encapreppart)
377 {
378   int res;
379   int i;
380   char *buf;
381   size_t buflen;
382   char *cipher;
383   size_t cipherlen;
384   int etype;
385 
386   res = shishi_aprep_get_enc_part_etype (handle, aprep, &etype);
387   if (res != SHISHI_OK)
388     return res;
389 
390   if (etype != shishi_key_type (key))
391     return SHISHI_APREP_BAD_KEYTYPE;
392 
393   res = shishi_asn1_read (handle, aprep, "enc-part.cipher",
394 			  &cipher, &cipherlen);
395   if (res != SHISHI_OK)
396     return res;
397 
398   res = shishi_decrypt (handle, key, keyusage, cipher, cipherlen,
399 			&buf, &buflen);
400   free (cipher);
401   if (res != SHISHI_OK)
402     {
403       shishi_error_printf (handle,
404 			   "APRep decryption failed, wrong password?\n");
405       return res;
406     }
407 
408   /* The crypto is so 1980; no length indicator. Trim off pad bytes
409      until we can parse it. */
410   for (i = 0; i < 8; i++)
411     {
412       if (VERBOSEASN1 (handle))
413 	printf ("Trying with %d pad in enckdcrep...\n", i);
414 
415       *encapreppart = shishi_der2asn1_encapreppart (handle, &buf[0],
416 						    buflen - i);
417       if (*encapreppart != NULL)
418 	break;
419     }
420 
421   if (*encapreppart == NULL)
422     {
423       shishi_error_printf (handle, "Could not DER decode EncAPRepPart. "
424 			   "Password probably correct (decrypt ok) though\n");
425       return SHISHI_ASN1_ERROR;
426     }
427 
428   return SHISHI_OK;
429 }
430 
431 int
shishi_aprep_verify(Shishi * handle,Shishi_asn1 authenticator,Shishi_asn1 encapreppart)432 shishi_aprep_verify (Shishi * handle,
433 		     Shishi_asn1 authenticator, Shishi_asn1 encapreppart)
434 {
435   char *authenticatorctime;
436   char *encapreppartctime;
437   uint32_t authenticatorcusec, encapreppartcusec;
438   int res;
439   int different;
440 
441   /*
442      3.2.5. Receipt of KRB_AP_REP message
443 
444      If a KRB_AP_REP message is returned, the client uses the session key from
445      the credentials obtained for the server[3.10] to decrypt the message, and
446      verifies that the timestamp and microsecond fields match those in the
447      Authenticator it sent to the server. If they match, then the client is
448      assured that the server is genuine. The sequence number and subkey (if
449      present) are retained for later use.
450 
451    */
452 
453   res = shishi_authenticator_ctime (handle, authenticator,
454 				    &authenticatorctime);
455   if (res != SHISHI_OK)
456     return res;
457 
458   res = shishi_authenticator_cusec_get (handle, authenticator,
459 					&authenticatorcusec);
460   if (res != SHISHI_OK)
461     return res;
462 
463   res = shishi_encapreppart_ctime (handle, encapreppart, &encapreppartctime);
464   if (res != SHISHI_OK)
465     return res;
466 
467   res = shishi_encapreppart_cusec_get (handle, encapreppart,
468 				       &encapreppartcusec);
469   if (res != SHISHI_OK)
470     return res;
471 
472   if (VERBOSE (handle))
473     {
474       printf ("authenticator cusec %08x ctime %s\n", authenticatorcusec,
475 	      authenticatorctime);
476       printf ("encapreppart cusec %08x ctime %s\n", encapreppartcusec,
477 	      encapreppartctime);
478     }
479 
480   different = authenticatorcusec != encapreppartcusec ||
481     strcmp (authenticatorctime, encapreppartctime) != 0;
482 
483   free (authenticatorctime);
484   free (encapreppartctime);
485 
486   if (different)
487     return SHISHI_APREP_VERIFY_FAILED;
488 
489   return SHISHI_OK;
490 }
491