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