542 lines
16 KiB
C
542 lines
16 KiB
C
/* $OpenBSD: sample-app.c,v 1.7 2004/06/29 11:35:56 msf Exp $ */
|
|
/*
|
|
* The author of this code is Angelos D. Keromytis (angelos@dsl.cis.upenn.edu)
|
|
*
|
|
* This code was written by Angelos D. Keromytis in Philadelphia, PA, USA,
|
|
* in April-May 1998
|
|
*
|
|
* Copyright (C) 1998, 1999 by Angelos D. Keromytis.
|
|
*
|
|
* Permission to use, copy, and modify this software with or without fee
|
|
* is hereby granted, provided that this entire notice is included in
|
|
* all copies of any software which is or includes a copy or
|
|
* modification of this software.
|
|
*
|
|
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTY. IN PARTICULAR, THE AUTHORS MAKES NO
|
|
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
|
|
* MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
|
|
* PURPOSE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <regex.h>
|
|
#include <keynote.h>
|
|
|
|
|
|
char policy_assertions[] =
|
|
"Authorizer: \"POLICY\"\n" \
|
|
"Licensees: \"rsa-hex:3048024100d15d08ce7d2103d93ef21a87330361\\\n" \
|
|
" ff123096b14330f9f0936e8f2064ef815ffdaabbb7d3ba47b\\\n" \
|
|
" 49fac090cf44818af7ac7d66c2910f32d8d5eb261328558e1\\\n" \
|
|
" 0203010001\"\n" \
|
|
"Comment: This is our first policy assertion\n" \
|
|
"Conditions: app_domain == \"test application\" -> \"true\";\n" \
|
|
"\n" \
|
|
"Authorizer: \"POLICY\"\n" \
|
|
"Licensees: KEY1 || KEY2\n" \
|
|
"Local-Constants: \n" \
|
|
" KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
|
|
" vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
|
|
" DS2EVzAgMBAAE=\"\n" \
|
|
" KEY2 = \"dsa-base64:MIHfAkEAhRzwrvhbRXIJH+nGfQB/tRp3ueF0j\\\n" \
|
|
" 4OqVU4GmC6eIlrmlKxR+Me6tjqtWJr5gf/AEOnzoQAPRIlpiP\\\n" \
|
|
" VJX1mRjwJBAKHTpHS7M938wVr+lIMjq0H0Aav5T4jlxS2rphI\\\n" \
|
|
" 4fbc7tJm6wPW9p2KyHbe9GaZgzYK1OdnNXdanM/AkLW4OKz0C\\\n" \
|
|
" FQDF69A/EHKoQC1H6DxCi0L3HfW9uwJANCLE6ViRxnv4Jj0gV\\\n" \
|
|
" 8aO/b5AD+uA63+0EXUxO0Hqp91lzhDg/61BusMxFq7mQI0CLv\\\n" \
|
|
" S+dlCGShsYyB+VjSub7Q==\"\n" \
|
|
"Comment: A slightly more complicated policy\n" \
|
|
"Conditions: app_domain == \"test application\" && @some_num == 1 && \n" \
|
|
" (some_var == \"some value\" || \n" \
|
|
" some_var == \"some other value\") -> \"true\";";
|
|
|
|
char credential_assertions[] =
|
|
"KeyNote-Version: 2\n"\
|
|
"Authorizer: KEY1\n"
|
|
"Local-Constants: \n" \
|
|
" KEY1 = \"rsa-base64:MEgCQQCzxWCi619s3Bqf8QOZTREBFelqWvljw\\\n" \
|
|
" vCwktO7/5zufcz+P0UBRBFNtasWgkP6/tAIK8MnLMUnejGsye\\\n" \
|
|
" DS2EVzAgMBAAE=\"\n" \
|
|
"Licensees: \"dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d\\\n" \
|
|
" d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0\\\n" \
|
|
" 9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1\\\n" \
|
|
" 024100a60b7e77f317e156566b388aaa32c3866a086831649\\\n" \
|
|
" 1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d\\\n" \
|
|
" d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a\\\n" \
|
|
" 4937f198fe893be6c63a7d627f13a385b02405811292c9949\\\n" \
|
|
" 7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf\\\n" \
|
|
" 11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db\\\n" \
|
|
" 0507f5cffe74ed4f1a\"\n" \
|
|
"Conditions: app_domain == \"test application\" && \n" \
|
|
" another_var == \"foo\" -> \"true\";\n" \
|
|
"Signature: \"sig-rsa-sha1-base64:E2OhrczI0LtAYAoJ6fSlqvlQDA4r\\\n" \
|
|
" GiIX73T6p9eExpyHZbfjxPxXEIf6tbBre6x2Y26wBQCx/yCj5\\\n" \
|
|
" 4IS3tuY2w==\"\n";
|
|
|
|
char action_authorizer[] =
|
|
"dsa-hex:3081de02402121e160209f7ecef1b6866c907e8d" \
|
|
"d65e9a67ef0fbd6ece7760b7c8bb0d9a0b71a0dd921b949f0" \
|
|
"9a16092eb3f50e33892bc3e9f1c8409f5298de40461493ef1" \
|
|
"024100a60b7e77f317e156566b388aaa32c3866a086831649" \
|
|
"1a55ab6fb8e57f7ade4a2a31e43017c383ab2a3e54f49688d" \
|
|
"d66a326b7362beb974f2f1fb7dd573dd1bdf021500909807a" \
|
|
"4937f198fe893be6c63a7d627f13a385b02405811292c9949" \
|
|
"7aa80911c781a0ff51a5843423b9b4d03ad7e708ae2bfacaf" \
|
|
"11477f4f197dbba534194f8afd1e0b73261bb0a2c04af35db" \
|
|
"0507f5cffe74ed4f1a";
|
|
|
|
#define NUM_RETURN_VALUES 2
|
|
|
|
char *returnvalues[NUM_RETURN_VALUES];
|
|
|
|
/*
|
|
* Sample application. We do the following:
|
|
* - create a session
|
|
* - read a "file" with our KeyNote policy assertions
|
|
* - obtain a credential
|
|
* - obtain the requester's public key
|
|
* - construct an action attribute set
|
|
* - do the query
|
|
*
|
|
* Since this is a sample application, we won't be actually reading any
|
|
* real files or sockets. See the comments in the code below.
|
|
*/
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int sessionid, num, i, j;
|
|
char **decomposed;
|
|
|
|
/*
|
|
* We are creating a new KeyNote session here. A session may be temporary
|
|
* (we create it, add policies, credentials, authorizers, action set, do
|
|
* the query, and then we destroy it), or it may be persistent (if, for
|
|
* example, policies remain the same for a while).
|
|
*
|
|
* In this example, we'll just assume the session is temporary, but there
|
|
* will be comments as to what to do if this were a persistent session.
|
|
*/
|
|
sessionid = kn_init();
|
|
if (sessionid == -1)
|
|
{
|
|
fprintf(stderr, "Failed to create a new session.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Assume we have read a file, or somehow securely acquired our policy
|
|
* assertions, and we have stored them in policy_assertions.
|
|
*/
|
|
|
|
/* Let's find how many policies we just "read". */
|
|
decomposed = kn_read_asserts(policy_assertions, strlen(policy_assertions),
|
|
&num);
|
|
if (decomposed == NULL)
|
|
{
|
|
fprintf(stderr, "Failed to allocate memory for policy assertions.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* If there were no assertions in the first argument to kn_read_asserts,
|
|
* we'll get a valid pointer back, which we need to free. Note that this
|
|
* is an error; we always MUST have at least one policy assertion.
|
|
*/
|
|
if (num == 0)
|
|
{
|
|
free(decomposed);
|
|
fprintf(stderr, "No policy assertions provided.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* We no longer need a copy of policy_assertions, so we could
|
|
* free it here.
|
|
*/
|
|
|
|
/*
|
|
* decomposed now contains num pointers to strings, each containing a
|
|
* single assertion. We now add them all to the session. Note that
|
|
* we must provide the ASSERT_FLAG_LOCAL flag to indicate that these
|
|
* are policy assertions and thus do not have a signature field.
|
|
*/
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
j = kn_add_assertion(sessionid, decomposed[i],
|
|
strlen(decomposed[i]), ASSERT_FLAG_LOCAL);
|
|
if (j == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory, trying to add policy "
|
|
"assertion %d.\n", j);
|
|
break;
|
|
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Syntax error parsing policy "
|
|
"assertion %d.\n", j);
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding "
|
|
"policy assertion %d.\n", sessionid, j);
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding policy assertion %d.\n",
|
|
keynote_errno, j);
|
|
break;
|
|
}
|
|
|
|
/* We don't need the assertion any more. */
|
|
free(decomposed[i]);
|
|
}
|
|
}
|
|
|
|
/* Now free decomposed itself. */
|
|
free(decomposed);
|
|
|
|
/*
|
|
* Now, assume we have somehow acquired (through some application-dependent
|
|
* means) one or more KeyNote credentials, and the key of the action
|
|
* authorizer. For example, if this were an HTTP authorization application,
|
|
* we would have acquired the credential(s) and the key after completing
|
|
* an SSL protocol exchange.
|
|
*
|
|
* So, we have some credentials in credential_assertions, and a key
|
|
* in action_authorizer.
|
|
*/
|
|
|
|
/* Let's find how many credentials we just "received". */
|
|
decomposed = kn_read_asserts(credential_assertions,
|
|
strlen(credential_assertions), &num);
|
|
if (decomposed == NULL)
|
|
{
|
|
fprintf(stderr, "Failed to allocate memory for credential "
|
|
"assertions.\n");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* If there were no assertions in the first argument to kn_read_asserts,
|
|
* we'll get a valid pointer back, which we need to free. Note that
|
|
* it is legal to have zero credentials.
|
|
*/
|
|
if (num == 0)
|
|
{
|
|
free(decomposed);
|
|
fprintf(stderr, "No credential assertions provided.\n");
|
|
}
|
|
|
|
/*
|
|
* We no longer need a copy of credential_assertions, so we could
|
|
* free it here.
|
|
*/
|
|
|
|
/*
|
|
* decomposed now contains num pointers to strings, each containing a
|
|
* single assertion. We now add them all to the session. Note that here
|
|
* we must NOT provide the ASSERT_FLAG_LOCAL flag, since these are
|
|
* all credential assertions and need to be cryptographically verified.
|
|
*/
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
/*
|
|
* The value returned by kn_add_assertion() is an ID for that
|
|
* assertion (unless it's a -1, which indicates an error). We could
|
|
* use this ID to remove the assertion from the session in the future,
|
|
* if we needed to. We would need to store the IDs somewhere of
|
|
* course.
|
|
*
|
|
* If this were a persistent session, it may make sense to delete
|
|
* the credentials we just added after we are done with the query,
|
|
* simply to conserve memory. On the other hand, we could just leave
|
|
* them in the session; this has no security implications.
|
|
*
|
|
* Also note that we could do the same with policy assertions.
|
|
* However, if we want to delete policy assertions, it usually then
|
|
* makes sense to just destroy the whole session via kn_close(),
|
|
* which frees all allocated resources.
|
|
*/
|
|
j = kn_add_assertion(sessionid, decomposed[i],
|
|
strlen(decomposed[i]), 0);
|
|
if (j == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory, trying to add credential "
|
|
"assertion %d.\n", j);
|
|
break;
|
|
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Syntax error parsing credential "
|
|
"assertion %d.\n", j);
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding "
|
|
"credential assertion %d.\n", sessionid, j);
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding credential assertion %d.\n",
|
|
keynote_errno, j);
|
|
break;
|
|
}
|
|
|
|
/* We don't need the assertion any more. */
|
|
free(decomposed[i]);
|
|
}
|
|
}
|
|
|
|
/* No longer needed. */
|
|
free(decomposed);
|
|
|
|
/*
|
|
* Now add the action authorizer. If we have more than one, just
|
|
* repeat. Note that the value returned here is just a success or
|
|
* failure indicator. If we want to later on delete an authorizer from
|
|
* the session (which we MUST do if this is a persistent session),
|
|
* we must keep a copy of the key.
|
|
*/
|
|
if (kn_add_authorizer(sessionid, action_authorizer) == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory while adding action "
|
|
"authorizer.\n");
|
|
break;
|
|
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Malformed action authorizer.\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding action "
|
|
"authorizer.\n", sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error while adding action "
|
|
"authorizer.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we don't need action_authorizer any more (i.e., this is a temporary
|
|
* session), we could free it now.
|
|
*/
|
|
|
|
/*
|
|
* Now we need to construct the action set. In a real application, we
|
|
* would be gathering the relevant information. Here, we just construct
|
|
* a fixed action set.
|
|
*/
|
|
|
|
/*
|
|
* Add the relevant action attributes. Flags is zero, since we are not
|
|
* using any callback functions (ENVIRONMENT_FLAG_FUNC) or a regular
|
|
* expression for action attribute names (ENVIRONMENT_FLAG_REGEX).
|
|
*/
|
|
if (kn_add_action(sessionid, "app_domain", "test application", 0) == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Invalid name action attribute name "
|
|
"[app_domain]\n");
|
|
break;
|
|
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory adding action attribute "
|
|
"[app_domain = \"test application\"]\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding action "
|
|
"attribute [app_domain = \"test application\"]\n",
|
|
sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding action attribute [app_domain = "
|
|
"\"test application\"]\n", keynote_errno);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (kn_add_action(sessionid, "some_num", "1", 0) == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Invalid name action attribute name "
|
|
"[some_num]\n");
|
|
break;
|
|
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory adding action attribute "
|
|
"[some_num = \"1\"]\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding action "
|
|
"attribute [some_num = \"1\"]\n", sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding action attribute [some_num = \"1\"]",
|
|
keynote_errno);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (kn_add_action(sessionid, "some_var", "some other value", 0) == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Invalid name action attribute name "
|
|
"[some_var]\n");
|
|
break;
|
|
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory adding action attribute "
|
|
"[some_var = \"some other value\"]\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding action "
|
|
"attribute [some_var = \"some other value\"]\n",
|
|
sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding action attribute [some_var = "
|
|
"\"some other value\"]\n", keynote_errno);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (kn_add_action(sessionid, "another_var", "foo", 0) == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_SYNTAX:
|
|
fprintf(stderr, "Invalid name action attribute name "
|
|
"[another_var]\n");
|
|
break;
|
|
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory adding action attribute "
|
|
"[another_var = \"foo\"]\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while adding action "
|
|
"attribute [another_var = \"foo\"]\n", sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while adding action attribute [another_var = "
|
|
"\"foo\"]\n", keynote_errno);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Set the return values for this application -- just "false" and "true" */
|
|
returnvalues[0] = "false";
|
|
returnvalues[1] = "true";
|
|
|
|
/* Just do the query. */
|
|
j = kn_do_query(sessionid, returnvalues, NUM_RETURN_VALUES);
|
|
if (j == -1)
|
|
{
|
|
switch (keynote_errno)
|
|
{
|
|
case ERROR_MEMORY:
|
|
fprintf(stderr, "Out of memory while performing authorization "
|
|
"query.\n");
|
|
break;
|
|
|
|
case ERROR_NOTFOUND:
|
|
fprintf(stderr, "Session %d not found while performing "
|
|
"authorization query.\n", sessionid);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "Unspecified error %d (shouldn't happen) "
|
|
"while performing authorization query.\n",
|
|
keynote_errno);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, "Return value is [%s]\n", returnvalues[j]);
|
|
}
|
|
|
|
/*
|
|
* Once the query is done, we can find what assertions failed in what way.
|
|
* One way is just going through the list of assertions, as shown here
|
|
* for assertions that failed due to memory exhaustion.
|
|
*/
|
|
j = 0;
|
|
|
|
do
|
|
{
|
|
i = kn_get_failed(sessionid, KEYNOTE_ERROR_MEMORY, j++);
|
|
if (i != -1)
|
|
fprintf(stderr, "Assertion %d failed due to memory exhaustion.\n",
|
|
i);
|
|
} while (i != -1);
|
|
|
|
/*
|
|
* Another way is to go through the list of failed assertions by deleting
|
|
* the "first" one.
|
|
*/
|
|
do
|
|
{
|
|
i = kn_get_failed(sessionid, KEYNOTE_ERROR_SYNTAX, 0);
|
|
if (i != -1)
|
|
{
|
|
fprintf(stderr, "Assertion %d failed due to some syntax error.\n",
|
|
i);
|
|
kn_remove_assertion(sessionid, i); /* Delete assertion */
|
|
}
|
|
} while (i != -1);
|
|
|
|
/*
|
|
* Signature failures, another way.
|
|
*/
|
|
for (j = 0, i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, 0);
|
|
i != -1; i = kn_get_failed(sessionid, KEYNOTE_ERROR_SIGNATURE, j++))
|
|
fprintf(stderr, "Failed to verify signature on assertion %d.\n", i);
|
|
|
|
/*
|
|
* Here's how to find all errors.
|
|
*/
|
|
for (i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0); i != -1;
|
|
i = kn_get_failed(sessionid, KEYNOTE_ERROR_ANY, 0))
|
|
{
|
|
fprintf(stderr, "Unspecified error in processing assertion %d.\n", i);
|
|
kn_remove_assertion(sessionid, i);
|
|
}
|
|
|
|
/* Destroy the session, freeing all allocated memory. */
|
|
kn_close(sessionid);
|
|
|
|
exit(0);
|
|
}
|