1 /*
2  * The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
3  *
4  * This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
5  * in April-May 1998
6  *
7  * Copyright (C) 1998, 1999 by Angelos D. Keromytis.
8  *
9  * Permission to use, copy, and modify this software without fee
10  * is hereby granted, provided that this entire notice is included in
11  * all copies of any software which is or includes a copy or
12  * modification of this software.
13  *
14  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
16  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
17  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
18  * PURPOSE.
19  */
20 #include <sys/types.h>
21 #include <stdio.h>
22 #include <regex.h>
23 #include "keynote.h"
24 
25 /* These is only needed to pull in the SSL include files */
26 #if HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 
30 #include "header.h"
31 
32 char policy_assertions[] =
33 "Authorizer: \"POLICY\"\n" \
34 "Licensees: \"rsa-hex:3048024100d15d08ce7d2103d93ef21a87330361\\\n" \
35 "             ff123096b14330f9f0936e8f2064ef815ffdaabbb7d3ba47b\\\n" \
36 "             49fac090cf44818af7ac7d66c2910f32d8d5eb261328558e1\\\n" \
37 "             0203010001\"\n" \
38 "Comment: This is our first policy assertion\n" \
39 "Conditions: app_domain == \"test application\" -> \"true\";\n" \
40 "\n" \
41 "Authorizer: \"POLICY\"\n" \
42 "Licensees: KEY1 || KEY2\n" \
43 "Local-Constants: \n" \
44 "     KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
45 "              vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
46 "              DS2EVzAgMBAAE=\"\n" \
47 "     KEY2 = \"dsa-base64:MIHfAkEAhRzwrvhbRXIJH+nGfQB/tRp3ueF0j\\\n" \
48 "              4OqVU4GmC6eIlrmlKxR+Me6tjqtWJr5gf/AEOnzoQAPRIlpiP\\\n" \
49 "              VJX1mRjwJBAKHTpHS7M938wVr+lIMjq0H0Aav5T4jlxS2rphI\\\n" \
50 "              4fbc7tJm6wPW9p2KyHbe9GaZgzYK1OdnNXdanM/AkLW4OKz0C\\\n" \
51 "              FQDF69A/EHKoQC1H6DxCi0L3HfW9uwJANCLE6ViRxnv4Jj0gV\\\n" \
52 "              8aO/b5AD+uA63+0EXUxO0Hqp91lzhDg/61BusMxFq7mQI0CLv\\\n" \
53 "              S+dlCGShsYyB+VjSub7Q==\"\n" \
54 "Comment: A slightly more complicated policy\n" \
55 "Conditions: app_domain == \"test application\" && @some_num == 1 && \n" \
56 "            (some_var == \"some value\" || \n" \
57 "             some_var == \"some other value\") -> \"true\";";
58 
59 char credential_assertions[] =
60 "KeyNote-Version: 2\n"\
61 "Authorizer: KEY1\n"
62 "Local-Constants: \n" \
63 "     KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
64 "              vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
65 "              DS2EVzAgMBAAE=\"\n" \
66 "Licensees: \"dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d\\\n" \
67 "             d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0\\\n" \
68 "             9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1\\\n" \
69 "             024100a60b7e77f317e156566b388aaa32c3866a086831649\\\n" \
70 "             1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d\\\n" \
71 "             d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a\\\n" \
72 "             4937f198fe893be6c63a7d627f13a385b02405811292c9949\\\n" \
73 "             7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf\\\n" \
74 "             11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db\\\n" \
75 "             0507f5cffe74ed4f1a\"\n" \
76 "Conditions: app_domain == \"test application\" && \n" \
77 "            another_var == \"foo\" -> \"true\";\n" \
78 "Signature: \"sig-rsa-sha1-base64:E2OhrczI0LtAYAoJ6fSlqvlQDA4r\\\n" \
79 "            GiIX73T6p9eExpyHZbfjxPxXEIf6tbBre6x2Y26wBQCx/yCj5\\\n" \
80 "            4IS3tuY2w==\"\n";
81 
82 char action_authorizer[] =
83 "dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d" \
84 "d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0" \
85 "9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1" \
86 "024100a60b7e77f317e156566b388aaa32c3866a086831649" \
87 "1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d" \
88 "d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a" \
89 "4937f198fe893be6c63a7d627f13a385b02405811292c9949" \
90 "7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf" \
91 "11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db" \
92 "0507f5cffe74ed4f1a";
93 
94 #define NUM_RETURN_VALUES 2
95 
96 char *returnvalues[NUM_RETURN_VALUES];
97 
98 /*
99  * Sample application. We do the following:
100  * - create a session
101  * - read a "file" with our KeyNote policy assertions
102  * - obtain a credential
103  * - obtain the requester's public key
104  * - construct an action attribute set
105  * - do the query
106  *
107  * Since this is a sample application, we won't be actually reading any
108  * real files or sockets. See the comments in the code below.
109  */
110 
111 int
main(int argc,char ** argv)112 main(int argc, char **argv)
113 {
114     int sessionid, num, i, j;
115     char **decomposed;
116 
117     /*
118      * We are creating a new KeyNote session here. A session may be temporary
119      * (we create it, add policies, credentials, authorizers, action set, do
120      *  the query, and then we destroy it), or it may be persistent (if, for
121      * example, policies remain the same for a while).
122      *
123      * In this example, we'll just assume the session is temporary, but there
124      * will be comments as to what to do if this were a persistent session.
125      */
126     sessionid = kn_init();
127     if (sessionid == -1)
128     {
129 	fprintf(stderr, "Failed to create a new session.\n");
130 	exit(-1);
131     }
132 
133     /*
134      * Assume we have read a file, or somehow securely acquired our policy
135      * assertions, and we have stored them in policy_assertions.
136      */
137 
138     /* Let's find how many policies we just "read". */
139     decomposed = kn_read_asserts(policy_assertions, strlen(policy_assertions),
140 				 &num);
141     if (decomposed == NULL)
142     {
143 	fprintf(stderr, "Failed to allocate memory for policy assertions.\n");
144 	exit(-1);
145     }
146 
147     /*
148      * If there were no assertions in the first argument to kn_read_asserts,
149      * we'll get a valid pointer back, which we need to free. Note that this
150      * is an error; we always MUST have at least one policy assertion.
151      */
152     if (num == 0)
153     {
154 	free(decomposed);
155 	fprintf(stderr, "No policy assertions provided.\n");
156 	exit(-1);
157     }
158 
159     /*
160      * We no longer need a copy of policy_assertions, so we could
161      * free it here.
162      */
163 
164     /*
165      * decomposed now contains num pointers to strings, each containing a
166      * single assertion. We now add them all to the session. Note that
167      * we must provide the ASSERT_FLAG_LOCAL flag to indicate that these
168      * are policy assertions and thus do not have a signature field.
169      */
170     for (i = 0; i < num; i++)
171     {
172 	j = kn_add_assertion(sessionid, decomposed[i],
173 			     strlen(decomposed[i]), ASSERT_FLAG_LOCAL);
174 	if (j == -1)
175 	{
176 	    switch (keynote_errno)
177 	    {
178 		case ERROR_MEMORY:
179 		    fprintf(stderr, "Out of memory, trying to add policy "
180 			    "assertion %d.\n", j);
181 		    break;
182 
183 		case ERROR_SYNTAX:
184 		    fprintf(stderr, "Syntax error parsing policy "
185 			    "assertion %d.\n", j);
186 		    break;
187 
188 		case ERROR_NOTFOUND:
189 		    fprintf(stderr, "Session %d not found while adding "
190 			    "policy assertion %d.\n", sessionid, j);
191 		default:
192 		    fprintf(stderr, "Unspecified error %d (shouldn't happen) "
193 			    "while adding policy assertion %d.\n",
194 			    keynote_errno, j);
195 		    break;
196 	    }
197 
198 	    /* We don't need the assertion any more. */
199 	    free(decomposed[i]);
200 	}
201     }
202 
203     /* Now free decomposed itself. */
204     free(decomposed);
205 
206     /*
207      * Now, assume we have somehow acquired (through some application-dependent
208      * means) one or more KeyNote credentials, and the key of the action
209      * authorizer. For example, if this were an HTTP authorization application,
210      * we would have acquired the credential(s) and the key after completing
211      * an SSL protocol exchange.
212      *
213      * So, we have some credentials in credential_assertions, and a key
214      * in action_authorizer.
215      */
216 
217     /* Let's find how many credentials we just "received". */
218     decomposed = kn_read_asserts(credential_assertions,
219 				 strlen(credential_assertions), &num);
220     if (decomposed == NULL)
221     {
222 	fprintf(stderr, "Failed to allocate memory for credential "
223 		"assertions.\n");
224 	exit(-1);
225     }
226 
227     /*
228      * If there were no assertions in the first argument to kn_read_asserts,
229      * we'll get a valid pointer back, which we need to free. Note that
230      * it is legal to have zero credentials.
231      */
232     if (num == 0)
233     {
234 	free(decomposed);
235 	fprintf(stderr, "No credential assertions provided.\n");
236     }
237 
238     /*
239      * We no longer need a copy of credential_assertions, so we could
240      * free it here.
241      */
242 
243     /*
244      * decomposed now contains num pointers to strings, each containing a
245      * single assertion. We now add them all to the session. Note that here
246      * we must NOT provide the ASSERT_FLAG_LOCAL flag, since these are
247      * all credential assertions and need to be cryptographically verified.
248      */
249     for (i = 0; i < num; i++)
250     {
251 	/*
252 	 * The value returned by kn_add_assertion() is an ID for that
253 	 * assertion (unless it's a -1, which indicates an error). We could
254 	 * use this ID to remove the assertion from the session in the future,
255 	 * if we needed to. We would need to store the IDs somewhere of
256 	 * course.
257 	 *
258 	 * If this were a persistent session, it may make sense to delete
259 	 * the credentials we just added after we are done with the query,
260 	 * simply to conserve memory. On the other hand, we could just leave
261 	 * them in the session; this has no security implications.
262 	 *
263 	 * Also note that we could do the same with policy assertions.
264 	 * However, if we want to delete policy assertions, it usually then
265 	 * makes sense to just destroy the whole session via kn_close(),
266 	 * which frees all allocated resources.
267 	 */
268 	j = kn_add_assertion(sessionid, decomposed[i],
269 			     strlen(decomposed[i]), 0);
270 	if (j == -1)
271 	{
272 	    switch (keynote_errno)
273 	    {
274 		case ERROR_MEMORY:
275 		    fprintf(stderr, "Out of memory, trying to add credential "
276 			    "assertion %d.\n", j);
277 		    break;
278 
279 		case ERROR_SYNTAX:
280 		    fprintf(stderr, "Syntax error parsing credential "
281 			    "assertion %d.\n", j);
282 		    break;
283 
284 		case ERROR_NOTFOUND:
285 		    fprintf(stderr, "Session %d not found while adding "
286 			    "credential assertion %d.\n", sessionid, j);
287 		default:
288 		    fprintf(stderr, "Unspecified error %d (shouldn't happen) "
289 			    "while adding credential assertion %d.\n",
290 			    keynote_errno, j);
291 		    break;
292 	    }
293 
294 	    /* We don't need the assertion any more. */
295 	    free(decomposed[i]);
296 	}
297     }
298 
299     /* No longer needed. */
300     free(decomposed);
301 
302     /*
303      * Now add the action authorizer. If we have more than one, just
304      * repeat. Note that the value returned here is just a success or
305      * failure indicator. If we want to later on delete an authorizer from
306      * the session (which we MUST do if this is a persistent session),
307      * we must keep a copy of the key.
308      */
309     if (kn_add_authorizer(sessionid, action_authorizer) == -1)
310     {
311 	switch (keynote_errno)
312 	{
313 	    case ERROR_MEMORY:
314 		fprintf(stderr, "Out of memory while adding action "
315 			"authorizer.\n");
316 		break;
317 
318 	    case ERROR_SYNTAX:
319 		fprintf(stderr, "Malformed action authorizer.\n");
320 		break;
321 
322 	    case ERROR_NOTFOUND:
323 		fprintf(stderr, "Session %d not found while adding action "
324 			"authorizer.\n", sessionid);
325 		break;
326 
327 	    default:
328 		fprintf(stderr, "Unspecified error while adding action "
329 			"authorizer.\n");
330 		break;
331 	}
332     }
333 
334     /*
335      * If we don't need action_authorizer any more (i.e., this is a temporary
336      * session), we could free it now.
337      */
338 
339     /*
340      * Now we need to construct the action set. In a real application, we
341      * would be gathering the relevant information. Here, we just construct
342      * a fixed action set.
343      */
344 
345     /*
346      * Add the relevant action attributes. Flags is zero, since we are not
347      * using any callback functions (ENVIRONMENT_FLAG_FUNC) or a regular
348      * expression for action attribute names (ENVIRONMENT_FLAG_REGEX).
349      */
350     if (kn_add_action(sessionid, "app_domain", "test application", 0) == -1)
351     {
352 	switch (keynote_errno)
353 	{
354 	    case ERROR_SYNTAX:
355 		fprintf(stderr, "Invalid name action attribute name "
356 			"[app_domain]\n");
357 		break;
358 
359 	    case ERROR_MEMORY:
360 		fprintf(stderr, "Out of memory adding action attribute "
361 			"[app_domain = \"test application\"]\n");
362 		break;
363 
364 	    case ERROR_NOTFOUND:
365 		fprintf(stderr, "Session %d not found while addiing action "
366 			"attribute [app_domain = \"test application\"]\n",
367 			sessionid);
368 		break;
369 
370 	    default:
371 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
372 			"while adding action attribute [app_domain = "
373 			"\"test application\"]\n", keynote_errno);
374 		break;
375 	}
376     }
377 
378     if (kn_add_action(sessionid, "some_num", "1", 0) == -1)
379     {
380 	switch (keynote_errno)
381 	{
382 	    case ERROR_SYNTAX:
383 		fprintf(stderr, "Invalid name action attribute name "
384 			"[some_num]\n");
385 		break;
386 
387 	    case ERROR_MEMORY:
388 		fprintf(stderr, "Out of memory adding action attribute "
389 			"[some_num = \"1\"]\n");
390 		break;
391 
392 	    case ERROR_NOTFOUND:
393 		fprintf(stderr, "Session %d not found while addiing action "
394 			"attribute [some_num = \"1\"]\n", sessionid);
395 		break;
396 
397 	    default:
398 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
399 			"while adding action attribute [some_num = \"1\"]",
400 			keynote_errno);
401 		break;
402 	}
403     }
404 
405     if (kn_add_action(sessionid, "some_var", "some other value", 0) == -1)
406     {
407 	switch (keynote_errno)
408 	{
409 	    case ERROR_SYNTAX:
410 		fprintf(stderr, "Invalid name action attribute name "
411 			"[some_var]\n");
412 		break;
413 
414 	    case ERROR_MEMORY:
415 		fprintf(stderr, "Out of memory adding action attribute "
416 			"[some_var = \"some other value\"]\n");
417 		break;
418 
419 	    case ERROR_NOTFOUND:
420 		fprintf(stderr, "Session %d not found while addiing action "
421 			"attribute [some_var = \"some other value\"]\n",
422 			sessionid);
423 		break;
424 
425 	    default:
426 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
427 			"while adding action attribute [some_var = "
428 			"\"some other value\"]\n", keynote_errno);
429 		break;
430 	}
431     }
432 
433     if (kn_add_action(sessionid, "another_var", "foo", 0) == -1)
434     {
435 	switch (keynote_errno)
436 	{
437 	    case ERROR_SYNTAX:
438 		fprintf(stderr, "Invalid name action attribute name "
439 			"[another_var]\n");
440 		break;
441 
442 	    case ERROR_MEMORY:
443 		fprintf(stderr, "Out of memory adding action attribute "
444 			"[another_var = \"foo\"]\n");
445 		break;
446 
447 	    case ERROR_NOTFOUND:
448 		fprintf(stderr, "Session %d not found while addiing action "
449 			"attribute [another_var = \"foo\"]\n", sessionid);
450 		break;
451 
452 	    default:
453 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
454 			"while adding action attribute [another_var = "
455 			"\"foo\"]\n", keynote_errno);
456 		break;
457 	}
458     }
459 
460     /* Set the return values for this application -- just "false" and "true" */
461     returnvalues[0] = "false";
462     returnvalues[1] = "true";
463 
464     /* Just do the query. */
465     j = kn_do_query(sessionid, returnvalues, NUM_RETURN_VALUES);
466     if (j == -1)
467     {
468 	switch (j)
469 	{
470 	    case ERROR_MEMORY:
471 		fprintf(stderr, "Out of memory while performing authorization "
472 			"query.\n");
473 		break;
474 
475 	    case ERROR_NOTFOUND:
476 		fprintf(stderr, "Session %d not found while performing "
477 			"authorization query.\n", sessionid);
478 		break;
479 
480 	    default:
481 		fprintf(stderr, "Unspecified error %d (shouldn't happen) "
482 			"while performing authorization query.\n",
483 			keynote_errno);
484 		break;
485 	}
486     }
487     else
488     {
489 	fprintf(stdout, "Return value is [%s]\n", returnvalues[j]);
490     }
491 
492     /*
493      * Once the query is done, we can find what assertions failed in what way.
494      * One way is just going through the list of assertions, as shown here
495      * for assertions that failed due to memory exhaustion.
496      */
497     j = 0;
498 
499     do
500     {
501 	i = kn_get_failed(sessionid, KEYNOTE_ERROR_MEMORY, j++);
502 	if (i != -1)
503 	  fprintf(stderr, "Assertion %d failed due to memory exhaustion.\n",
504 		  i);
505     } while (i != -1);
506 
507     /*
508      * Another way is to go through the list of failed assertions by deleting
509      * the "first" one.
510      */
511     do
512     {
513 	i = kn_get_failed(sessionid, KEYNOTE_ERROR_SYNTAX, 0);
514 	if (i != -1)
515 	{
516 	    fprintf(stderr, "Assertion %d failed due to some syntax error.\n",
517 		    i);
518 	    kn_remove_assertion(sessionid, i);  /* Delete assertion */
519 	}
520     } while (i != -1);
521 
522     /*
523      * Signature failures, another way.
524      */
525     for (j = 0, i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, 0);
526 	 i != -1; i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, j++))
527       fprintf(stderr, "Failed to verify signature on assertion %d.\n", i);
528 
529     /*
530      * Here's how to find all errors.
531      */
532     for (i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0); i != -1;
533 	 i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0))
534     {
535 	fprintf(stderr, "Unspecified error in processing assertion %d.\n", i);
536 	kn_remove_assertion(sessionid, i);
537     }
538 
539     /* Destroy the session, freeing all allocated memory. */
540     kn_close(sessionid);
541 
542     exit(0);
543 }
544