diff options
author | 1999-05-23 22:11:03 +0000 | |
---|---|---|
committer | 1999-05-23 22:11:03 +0000 | |
commit | 983e9580c78bcbd602dac2064d50cd87f7355afc (patch) | |
tree | 85cb7bfcc6cf3e2a2f850af799674ce96a33d14a /lib/libkeynote/parse_assertion.c | |
parent | xircom ethernet fits! (diff) | |
download | wireguard-openbsd-983e9580c78bcbd602dac2064d50cd87f7355afc.tar.xz wireguard-openbsd-983e9580c78bcbd602dac2064d50cd87f7355afc.zip |
KeyNote version 2 trust-management system (security policy handling).
Utilities to follow.
Diffstat (limited to 'lib/libkeynote/parse_assertion.c')
-rw-r--r-- | lib/libkeynote/parse_assertion.c | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/lib/libkeynote/parse_assertion.c b/lib/libkeynote/parse_assertion.c new file mode 100644 index 00000000000..90c49a12e13 --- /dev/null +++ b/lib/libkeynote/parse_assertion.c @@ -0,0 +1,623 @@ +/* $OpenBSD: parse_assertion.c,v 1.1.1.1 1999/05/23 22:11:06 angelos 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 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 <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> +#include "assertion.h" +#include "environment.h" +#include "signature.h" + +/* Globals */ +struct assertion *keynote_current_assertion = (struct assertion *) NULL; +int keynote_errno = 0; + +extern int keynote_in_action_authorizers(void *, int); + +/* + * Recurse on graph discovery. + */ +static int +rec_evaluate_query(struct assertion *as) +{ + struct assertion *ast; + struct keylist *kl; + int i, s; + + as->as_kresult = KRESULT_IN_PROGRESS; + + /* + * If we get the minimum result or an error from evaluating this + * assertion, we don't need to recurse. + */ + keynote_evaluate_assertion(as); + if (keynote_errno != 0) + { + as->as_kresult = KRESULT_DONE; + if (keynote_errno) + as->as_error = keynote_errno; + if (keynote_errno == ERROR_MEMORY) + return -1; + else + { + keynote_errno = 0; /* Ignore syntax errors for now */ + return 0; + } + } + + if (as->as_result == 0) + { + as->as_kresult = KRESULT_DONE; + return as->as_result; + } + + for (kl = as->as_keylist; + kl != (struct keylist *) NULL; + kl = kl->key_next) + { + switch (keynote_in_action_authorizers(kl->key_key, kl->key_alg)) + { + case -1: + as->as_kresult = KRESULT_DONE; + if (keynote_errno == ERROR_MEMORY) + { + as->as_error = ERROR_MEMORY; + return -1; + } + else + { + keynote_errno = 0; /* Reset */ + continue; + } + + case RESULT_FALSE: /* Not there, check for assertions instead */ + break; + + case RESULT_TRUE: /* Ok, don't bother with assertions */ + keynote_current_assertion = (struct assertion *) NULL; + continue; + } + + for (i = 0;; i++) + { + ast = keynote_find_assertion(kl->key_key, i, kl->key_alg); + if (ast == (struct assertion *) NULL) + break; + + if (ast->as_kresult == KRESULT_IN_PROGRESS) /* Cycle detected */ + continue; + + if (ast->as_kresult == KRESULT_UNTOUCHED) /* Recurse if needed */ + rec_evaluate_query(ast); + + /* Check for errors */ + if (keynote_errno == ERROR_MEMORY) + { + as->as_error = ERROR_MEMORY; + as->as_kresult = KRESULT_DONE; + return -1; + } + else + keynote_errno = 0; /* Reset */ + } + } + + keynote_current_assertion = as; + s = keynote_parse_keypred(as, 0); + keynote_current_assertion = (struct assertion *) NULL; + + if (keynote_errno == ERROR_MEMORY) + { + as->as_error = ERROR_MEMORY; + as->as_kresult = KRESULT_DONE; + return -1; + } + else + if (keynote_errno) + { + keynote_errno = 0; + s = 0; + } + + /* Keep lower of two */ + as->as_result = (as->as_result < s ? as->as_result : s); + + /* Check the signature now if we haven't done so already */ + if (as->as_sigresult == SIGRESULT_UNTOUCHED) + { + if (!(as->as_flags & ASSERT_FLAG_LOCAL)) + as->as_sigresult = keynote_sigverify_assertion(as); + else + as->as_sigresult = SIGRESULT_TRUE; /* Trusted assertion */ + } + + if (as->as_sigresult != SIGRESULT_TRUE) + { + as->as_result = 0; + as->as_sigresult = SIGRESULT_FALSE; + if (keynote_errno != ERROR_MEMORY) + keynote_errno = 0; /* Reset */ + else + { + as->as_error = ERROR_MEMORY; + as->as_kresult = KRESULT_DONE; + return -1; + } + } + + as->as_kresult = KRESULT_DONE; + return as->as_result; +} + +/* + * Fix the Authorizer/Licencees/Signature fields. If the first argument is + * empty, fix all assertions. The second argument specifies whether the + * Signature field should be parsed or not. + */ +static int +keynote_fix_fields(struct assertion *ast, int sigfield) +{ + struct assertion *as; + int i; + + /* Signature generation/verification handling, no need to eval Licensees */ + if (ast != (struct assertion *) NULL) + { + /* Authorizer */ + if (keynote_evaluate_authorizer(ast, 1) != RESULT_TRUE) + return -1; + + /* Signature */ + if ((sigfield) && (ast->as_signature_string_s != (char *) NULL)) + if (keynote_evaluate_authorizer(ast, 0) != RESULT_TRUE) + return -1; + + return RESULT_TRUE; + } + + for (i = 0; i < HASHTABLESIZE; i++) + for (as = keynote_current_session->ks_assertion_table[i]; + as != (struct assertion *) NULL; + as = as->as_next) + { + if (!(as->as_internalflags & ASSERT_IFLAG_NEEDPROC) && + !(as->as_internalflags & ASSERT_IFLAG_WEIRDLICS) && + !(as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) && + !(as->as_internalflags & ASSERT_IFLAG_WEIRDSIG)) + continue; + + /* Parse the Signature field */ + if (((as->as_internalflags & ASSERT_IFLAG_WEIRDSIG) || + (as->as_internalflags & ASSERT_IFLAG_NEEDPROC)) && + (as->as_signature_string_s != (char *) NULL)) + if (keynote_evaluate_authorizer(as, 0) == -1) + { + if (keynote_errno) + as->as_error = keynote_errno; + if (keynote_errno == ERROR_MEMORY) + return -1; + else + keynote_errno = 0; + } + + /* Parse the Licensees field */ + if ((as->as_internalflags & ASSERT_IFLAG_WEIRDLICS) || + (as->as_internalflags & ASSERT_IFLAG_NEEDPROC)) + if (keynote_parse_keypred(as, 1) == -1) + { + if (keynote_errno) + as->as_error = keynote_errno; + if (keynote_errno == ERROR_MEMORY) + return -1; + else + keynote_errno = 0; + } + + /* Parse the Authorizer field */ + if ((as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) || + (as->as_internalflags & ASSERT_IFLAG_NEEDPROC)) + if (keynote_evaluate_authorizer(as, 1) == -1) + { + if (keynote_errno) + as->as_error = keynote_errno; + if (keynote_errno == ERROR_MEMORY) + return -1; + else + keynote_errno = 0; + } + } + + /* Reposition if necessary */ + for (i = 0; i < HASHTABLESIZE; i++) + for (as = keynote_current_session->ks_assertion_table[i]; + as != (struct assertion *) NULL; + as = as->as_next) + if (((as->as_internalflags & ASSERT_IFLAG_WEIRDAUTH) && + !(as->as_internalflags & ASSERT_IFLAG_PROCESSED)) || + (as->as_internalflags & ASSERT_IFLAG_NEEDPROC)) + { + as->as_internalflags &= ~ASSERT_IFLAG_NEEDPROC; + as->as_internalflags |= ASSERT_IFLAG_PROCESSED; + keynote_sremove_assertion(keynote_current_session->ks_id, + as->as_id); + + if (keynote_add_htable(as, 1) != RESULT_TRUE) + return -1; + + /* Point to begining of the previous list. */ + i--; + break; + } + + return RESULT_TRUE; +} + +/* + * Find the trust graph. This is a depth-first search, starting at + * POLICY assertions. + */ +int +keynote_evaluate_query(void) +{ + struct assertion *as; + int p, prev; + int i; + + /* Fix the authorizer/licensees/signature fields */ + if (keynote_fix_fields((struct assertion *) NULL, 0) != RESULT_TRUE) + return -1; + + /* Find POLICY assertions and try to evaluate the query. */ + for (i = 0, prev = 0; i < HASHTABLESIZE; i++) + for (as = keynote_current_session->ks_assertion_table[i]; + as != (struct assertion *) NULL; + as = as->as_next) + if ((as->as_authorizer != (void *) NULL) && /* Paranoid */ + (as->as_signeralgorithm == KEYNOTE_ALGORITHM_NONE)) + if ((!strcmp("POLICY", as->as_authorizer)) && + (as->as_flags & ASSERT_FLAG_LOCAL)) + { + if ((p = rec_evaluate_query(as)) == -1) + { + if (keynote_errno) + as->as_error = keynote_errno; + if (keynote_errno == ERROR_MEMORY) + return -1; + else + { + keynote_errno = 0; + continue; + } + } + + if (p > prev) + prev = p; + + /* If we get the highest possible return value, just return */ + if (prev == (keynote_current_session->ks_values_num - 1)) + return prev; + } + + return prev; +} + +/* + * Return keyword type. + */ +static int +whichkeyword(char *start, char *end) +{ + int len = (end - start); + + if (len <= 0) + { + keynote_errno = ERROR_MEMORY; + return -1; + } + + if (!strncasecmp("keynote-version:", start, len)) + return KEYWORD_VERSION; + + if (!strncasecmp("local-constants:", start, len)) + return KEYWORD_LOCALINIT; + + if (!strncasecmp("authorizer:", start, len)) + return KEYWORD_AUTHORIZER; + + if (!strncasecmp("licensees:", start, len)) + return KEYWORD_LICENSEES; + + if (!strncasecmp("conditions:", start, len)) + return KEYWORD_CONDITIONS; + + if (!strncasecmp("signature:", start, len)) + return KEYWORD_SIGNATURE; + + if (!strncasecmp("comment:", start, len)) + return KEYWORD_COMMENT; + + keynote_errno = ERROR_SYNTAX; + return -1; +} + +/* + * Parse an assertion. Set keynote_errno to ERROR_SYNTAX if parsing + * failed due to certificate badness, and ERROR_MEMORY if memory + * problem. If more than one assertions have been passed in the + * buffer, they will be linked. + */ +struct assertion * +keynote_parse_assertion(char *buf, int len, int assertion_flags) +{ + int i, j, seen_field = 0, ver = 0, end_of_assertion = 0; + char *ks, *ke, *ts, *te = (char *) NULL; + struct assertion *as; + + /* Allocate memory for assertion */ + as = (struct assertion *) calloc(1, sizeof(struct assertion)); + if (as == (struct assertion *) NULL) + { + keynote_errno = ERROR_MEMORY; + return (struct assertion *) NULL; + } + + /* Keep a copy of the assertion around */ + as->as_buf = strdup(buf); + if (as->as_buf == (char *) NULL) + { + keynote_errno = ERROR_MEMORY; + keynote_free_assertion(as); + return (struct assertion *) NULL; + } + + as->as_flags = assertion_flags & ~(ASSERT_FLAG_SIGGEN | + ASSERT_FLAG_SIGVER); + + /* Skip any leading whitespace */ + for (i = 0, j = len; i < j && isspace(as->as_buf[i]); i++) + ; + + /* Keyword must start at begining of buffer or line */ + if ((i >= j) || ((i != 0) && (as->as_buf[i - 1] != '\n'))) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + while (i < j) /* Decomposition loop */ + { + ks = as->as_buf + i; + + /* Mark begining of assertion for signature purposes */ + if (as->as_startofsignature == (char *) NULL) + as->as_startofsignature = ks; + + if (as->as_buf[i] == '#') /* Comment */ + { + seen_field = 1; + + /* Skip until the end of line */ + while ((i< j) && as->as_buf[++i] != '\n') + ; + + continue; /* Loop */ + } + + /* Advance until we find a keyword separator */ + for (; (as->as_buf[i] != ':') && (i < j); i++) + ; + + if (i + 1 > j) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + /* ks points at begining of keyword, ke points at end */ + ke = as->as_buf + i; + + /* ts points at begining of value field */ + ts = as->as_buf + i + 1; /* Skip ':' */ + + /* + * Find the end of the field -- means end of buffer, + * a newline followed by a non-whitespace character, + * or two newlines. + */ + while (++i <= j) + { + /* If end of buffer, we're at the end of the field */ + if (i == j) + { + end_of_assertion = 1; + te = as->as_buf + i; + break; + } + + /* If two newlines, end of assertion */ + if ((as->as_buf[i] == '\n') && (i + 1 < j) && + (as->as_buf[i + 1] == '\n')) + { + end_of_assertion = 1; + te = as->as_buf + i; + break; + } + + /* If newline followed by non-whitespace or comment character */ + if ((as->as_buf[i] == '\n') && + (!isspace(as->as_buf[i + 1])) && (as->as_buf[i + 1] != '#')) + { + te = as->as_buf + i; + break; + } + } + + i++; + + /* + * On each of the cases (except the first), we check that: + * - we've already seen a keynote-version field (and that + * it's the first one that appears in the assertion) + * - the signature field, if present, is the last one + * - no field appears more than once + */ + switch (whichkeyword(ks, ke)) + { + case -1: + keynote_free_assertion(as); + return (struct assertion *) NULL; + + case KEYWORD_VERSION: + if ((ver == 1) || (seen_field == 1)) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + /* Test for version correctness */ + keynote_get_envlist(ts, te, 1); + if (keynote_errno != 0) + { + keynote_free_assertion(as); + return (struct assertion *) NULL; + } + + ver = 1; + break; + + case KEYWORD_LOCALINIT: + if (as->as_env != (struct environment *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + as->as_env = keynote_get_envlist(ts, te, 0); + if (keynote_errno != 0) + { + keynote_free_assertion(as); + return (struct assertion *) NULL; + } + break; + + case KEYWORD_AUTHORIZER: + if (as->as_authorizer_string_s != (void *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + as->as_authorizer_string_s = ts; + as->as_authorizer_string_e = te; + break; + + case KEYWORD_LICENSEES: + if (as->as_keypred_s != (char *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + as->as_keypred_s = ts; + as->as_keypred_e = te; + break; + + case KEYWORD_CONDITIONS: + if (as->as_conditions_s != (char *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + as->as_conditions_s = ts; + as->as_conditions_e = te; + break; + + case KEYWORD_SIGNATURE: + if (as->as_signature_string_s != (char *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + end_of_assertion = 1; + as->as_allbutsignature = ks; + as->as_signature_string_s = ts; + as->as_signature_string_e = te; + break; + + case KEYWORD_COMMENT: + if (as->as_comment_s != (char *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + as->as_comment_s = ts; + as->as_comment_e = te; + break; + } + + seen_field = 1; + if (end_of_assertion == 1) + break; + } + + /* Check that the basic fields are there */ + if (as->as_authorizer_string_s == (char *) NULL) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return (struct assertion *) NULL; + } + + /* Signature generation/verification handling */ + if (assertion_flags & ASSERT_FLAG_SIGGEN) + { + if (keynote_fix_fields(as, 0) != RESULT_TRUE) + { + keynote_free_assertion(as); + return (struct assertion *) NULL; + } + } + else + if (assertion_flags & ASSERT_FLAG_SIGVER) + if (keynote_fix_fields(as, 1) != RESULT_TRUE) + { + keynote_free_assertion(as); + return (struct assertion *) NULL; + } + + return as; +} |