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