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