sample-app.c revision 1.6
1/* $OpenBSD: sample-app.c,v 1.6 2004/06/25 05:06:49 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 <regex.h>
26#include "keynote.h"
27
28#include "header.h"
29
30char 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
57char 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
80char 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
94char *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
109int
110main(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