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