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