diff options
Diffstat (limited to 'lib/libkeynote/auxil.c')
-rw-r--r-- | lib/libkeynote/auxil.c | 528 |
1 files changed, 528 insertions, 0 deletions
diff --git a/lib/libkeynote/auxil.c b/lib/libkeynote/auxil.c new file mode 100644 index 00000000000..e301cb24171 --- /dev/null +++ b/lib/libkeynote/auxil.c @@ -0,0 +1,528 @@ +/* $OpenBSD: auxil.c,v 1.1 2000/01/25 09:08:11 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include <sys/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +#if STDC_HEADERS +#include <string.h> +#endif /* STDC_HEADERS */ + +#if HAVE_LIMITS_H +#include <limits.h> +#endif /* HAVE_LIMITS_H */ + +#include "header.h" +#include "keynote.h" +#include "assertion.h" +#include "signature.h" + +/* + * Get some sort of key-hash for hash table indexing purposes. + */ +static int +keynote_keyhash(void *key, int alg) +{ + struct keynote_binary *bn; + unsigned int res = 0, i; +#ifdef CRYPTO + DSA *dsa; + RSA *rsa; +#endif /* CRYPTO */ + + if (key == (void *) NULL) + return 0; + + switch (alg) + { +#ifdef CRYPTO + case KEYNOTE_ALGORITHM_DSA: + dsa = (DSA *) key; + res += BN_mod_word(dsa->p, HASHTABLESIZE); + res += BN_mod_word(dsa->q, HASHTABLESIZE); + res += BN_mod_word(dsa->g, HASHTABLESIZE); + res += BN_mod_word(dsa->pub_key, HASHTABLESIZE); + return res % HASHTABLESIZE; + + case KEYNOTE_ALGORITHM_RSA: + rsa = (RSA *) key; + res += BN_mod_word(rsa->n, HASHTABLESIZE); + res += BN_mod_word(rsa->e, HASHTABLESIZE); + return res % HASHTABLESIZE; + + case KEYNOTE_ALGORITHM_X509: /* RSA-specific */ + rsa = (RSA *) key; + res += BN_mod_word(rsa->n, HASHTABLESIZE); + res += BN_mod_word(rsa->e, HASHTABLESIZE); + return res % HASHTABLESIZE; +#endif /* CRYPTO */ + + case KEYNOTE_ALGORITHM_BINARY: + bn = (struct keynote_binary *) key; + for (i = 0; i < bn->bn_len; i++) + res = (res + ((unsigned char) bn->bn_key[i])) % HASHTABLESIZE; + + return res; + + case KEYNOTE_ALGORITHM_NONE: + return keynote_stringhash(key, HASHTABLESIZE); + + default: + return 0; + } +} + +/* + * Return RESULT_TRUE if key appears in the action authorizers. + */ +int +keynote_in_action_authorizers(void *key, int algorithm) +{ + struct keylist *kl, *kl2; + void *s; + int alg; + + if (algorithm == KEYNOTE_ALGORITHM_UNSPEC) + { + kl2 = keynote_keylist_find(keynote_current_assertion->as_keylist, key); + if (kl2 == (struct keylist *) NULL) + return RESULT_FALSE; /* Shouldn't ever happen */ + + s = kl2->key_key; + alg = kl2->key_alg; + } + else + { + s = key; + alg = algorithm; + } + + for (kl = keynote_current_session->ks_action_authorizers; + kl != (struct keylist *) NULL; + kl = kl->key_next) + if ((kl->key_alg == alg) || + ((kl->key_alg == KEYNOTE_ALGORITHM_RSA) && + (alg = KEYNOTE_ALGORITHM_X509)) || + ((kl->key_alg == KEYNOTE_ALGORITHM_X509) && + (alg = KEYNOTE_ALGORITHM_RSA))) + if (kn_keycompare(kl->key_key, s, alg) == RESULT_TRUE) + return RESULT_TRUE; + + return RESULT_FALSE; +} + +/* + * Add a key to the keylist. Return RESULT_TRUE on success, -1 (and set + * keynote_errno) otherwise. We are not supposed to make a copy of the + * argument. + */ +int +keynote_keylist_add(struct keylist **keylist, char *key) +{ + struct keynote_deckey dc; + struct keylist *kl; + + if (keylist == (struct keylist **) NULL) + { + keynote_errno = ERROR_MEMORY; + return -1; + } + + kl = (struct keylist *) calloc(1, sizeof(struct keylist)); + if (kl == (struct keylist *) NULL) + { + keynote_errno = ERROR_MEMORY; + return -1; + } + + if (kn_decode_key(&dc, key, KEYNOTE_PUBLIC_KEY) != 0) + { + free(kl); + return -1; + } + + kl->key_key = dc.dec_key; + kl->key_alg = dc.dec_algorithm; + kl->key_stringkey = key; + kl->key_next = *keylist; + *keylist = kl; + return RESULT_TRUE; +} + +/* + * Remove an action authorizer. + */ +int +kn_remove_authorizer(int sessid, char *key) +{ + struct keynote_session *ks; + struct keylist *kl, *kl2; + + keynote_errno = 0; + if ((keynote_current_session == (struct keynote_session *) NULL) || + (keynote_current_session->ks_id != sessid)) + { + keynote_current_session = keynote_find_session(sessid); + if (keynote_current_session == (struct keynote_session *) NULL) + { + keynote_errno = ERROR_NOTFOUND; + return -1; + } + } + + ks = keynote_current_session; + + /* If no action authorizers present */ + if ((kl = ks->ks_action_authorizers) == (struct keylist *) NULL) + { + keynote_errno = ERROR_NOTFOUND; + return -1; + } + + /* First in list */ + if (!strcmp(kl->key_stringkey, key)) + { + ks->ks_action_authorizers = kl->key_next; + kl->key_next = (struct keylist *) NULL; + keynote_keylist_free(kl); + return 0; + } + + for (; kl->key_next != (struct keylist *) NULL; kl = kl->key_next) + if (!strcmp(kl->key_stringkey, key)) + { + kl2 = kl->key_next; + kl->key_next = kl2->key_next; + kl2->key_next = (struct keylist *) NULL; + keynote_keylist_free(kl2); + return 0; + } + + keynote_errno = ERROR_NOTFOUND; + return -1; +} + +/* + * Add an action authorizer. + */ +int +kn_add_authorizer(int sessid, char *key) +{ + char *stringkey; + + keynote_errno = 0; + if ((keynote_current_session == (struct keynote_session *) NULL) || + (keynote_current_session->ks_id != sessid)) + { + keynote_current_session = keynote_find_session(sessid); + if (keynote_current_session == (struct keynote_session *) NULL) + { + keynote_errno = ERROR_NOTFOUND; + return -1; + } + } + + stringkey = strdup((char *) key); + if (stringkey == (char *) NULL) + { + keynote_errno = ERROR_MEMORY; + return -1; + } + + if (keynote_keylist_add(&(keynote_current_session->ks_action_authorizers), + stringkey) == -1) + { + free(stringkey); + return -1; + } + + return 0; +} + +/* + * Find a keylist entry based on the key_stringkey entry. + */ +struct keylist * +keynote_keylist_find(struct keylist *kl, char *s) +{ + for (; kl != (struct keylist *) NULL; kl = kl->key_next) + if (!strcmp(kl->key_stringkey, s)) + return kl; + + return kl; +} + +/* + * Free keylist list. + */ +void +keynote_keylist_free(struct keylist *kl) +{ + struct keylist *kl2; + + while (kl != (struct keylist *) NULL) + { + kl2 = kl->key_next; + free(kl->key_stringkey); + keynote_free_key(kl->key_key, kl->key_alg); + free(kl); + kl = kl2; + } +} + +/* + * Find the num-th assertion given the authorizer. Return NULL if not found. + */ +struct assertion * +keynote_find_assertion(void *authorizer, int num, int algorithm) +{ + struct assertion *as; + unsigned int h; + + if (authorizer == (char *) NULL) + return (struct assertion *) NULL; + + h = keynote_keyhash(authorizer, algorithm); + for (as = keynote_current_session->ks_assertion_table[h]; + as != (struct assertion *) NULL; + as = as->as_next) + if ((as->as_authorizer != (void *) NULL) && + ((as->as_signeralgorithm == algorithm) || + ((as->as_signeralgorithm == KEYNOTE_ALGORITHM_RSA) && + (algorithm == KEYNOTE_ALGORITHM_X509)) || + ((as->as_signeralgorithm == KEYNOTE_ALGORITHM_X509) && + (algorithm == KEYNOTE_ALGORITHM_RSA)))) + if (kn_keycompare(authorizer, as->as_authorizer, algorithm) == + RESULT_TRUE) + if (num-- == 0) + return as; + + return (struct assertion *) NULL; +} + +/* + * Add an assertion to the hash table. Return RESULT_TRUE on success, + * ERROR_MEMORY for memory failure, ERROR_SYNTAX if some problem with + * the assertion is detected. + */ +int +keynote_add_htable(struct assertion *as, int which) +{ + char *hashname; + u_int i; + + if (as == (struct assertion *) NULL) + { + keynote_errno = ERROR_MEMORY; + return -1; + } + + if (!which) + hashname = as->as_authorizer_string_s; + else + hashname = as->as_authorizer; + + if (hashname == (char *) NULL) + { + keynote_errno = ERROR_SYNTAX; + return -1; + } + + i = keynote_keyhash(hashname, as->as_signeralgorithm); + as->as_next = keynote_current_session->ks_assertion_table[i]; + keynote_current_session->ks_assertion_table[i] = as; + return RESULT_TRUE; +} + +/* + * Parse and store an assertion in the internal hash table. + * Return the result of the evaluation, if doing early evaluation. + * If an error was encountered, set keynote_errno. + */ +int +kn_add_assertion(int sessid, char *asrt, int len, int assertion_flags) +{ + struct assertion *as; + + keynote_errno = 0; + if ((keynote_current_session == (struct keynote_session *) NULL) || + (keynote_current_session->ks_id != sessid)) + { + keynote_current_session = keynote_find_session(sessid); + if (keynote_current_session == (struct keynote_session *) NULL) + { + keynote_errno = ERROR_NOTFOUND; + return -1; + } + } + + as = keynote_parse_assertion(asrt, len, assertion_flags); + if ((as == (struct assertion *) NULL) || (keynote_errno != 0)) + { + if (keynote_errno == 0) + keynote_errno = ERROR_SYNTAX; + + return -1; + } + + as->as_id = keynote_current_session->ks_assertioncounter++; + + /* Check for wrap around...there has to be a better solution to this */ + if (keynote_current_session->ks_assertioncounter < 0) + { + keynote_free_assertion(as); + keynote_errno = ERROR_SYNTAX; + return -1; + } + + if (keynote_add_htable(as, 0) != RESULT_TRUE) + { + keynote_free_assertion(as); + return -1; + } + + as->as_internalflags |= ASSERT_IFLAG_NEEDPROC; + return as->as_id; +} + +/* + * Remove an assertion from the hash table. + */ +static int +keynote_remove_assertion(int sessid, int assertid, int deleteflag) +{ + struct assertion *ht, *ht2; + int i; + + if ((keynote_current_session == (struct keynote_session *) NULL) || + (keynote_current_session->ks_id != sessid)) + { + keynote_current_session = keynote_find_session(sessid); + if (keynote_current_session == (struct keynote_session *) NULL) + { + keynote_errno = ERROR_NOTFOUND; + return -1; + } + } + + for (i = 0; i < HASHTABLESIZE; i++) + { + ht = keynote_current_session->ks_assertion_table[i]; + if (ht == (struct assertion *) NULL) + continue; + + /* If first entry in bucket */ + if (ht->as_id == assertid) + { + keynote_current_session->ks_assertion_table[i] = ht->as_next; + if (deleteflag) + keynote_free_assertion(ht); + return 0; + } + + for (; ht->as_next != (struct assertion *) NULL; ht = ht->as_next) + if (ht->as_next->as_id == assertid) /* Got it */ + { + ht2 = ht->as_next; + ht->as_next = ht2->as_next; + if (deleteflag) + keynote_free_assertion(ht2); + return 0; + } + } + + keynote_errno = ERROR_NOTFOUND; + return -1; +} + +/* + * API wrapper for deleting assertions. + */ +int +kn_remove_assertion(int sessid, int assertid) +{ + keynote_errno = 0; + return keynote_remove_assertion(sessid, assertid, 1); +} + +/* + * Internally-used wrapper for removing but not deleting assertions. + */ +int +keynote_sremove_assertion(int sessid, int assertid) +{ + return keynote_remove_assertion(sessid, assertid, 0); +} + +/* + * Free an assertion structure. + */ +void +keynote_free_assertion(struct assertion *as) +{ + if (as == (struct assertion *) NULL) + return; + + if (as->as_buf != (char *) NULL) + free(as->as_buf); + + if (as->as_signature != (char *) NULL) + free(as->as_signature); + + if (as->as_env != (struct environment *) NULL) + keynote_env_cleanup(&(as->as_env), 1); + + if (as->as_keylist != (struct keylist *) NULL) + keynote_keylist_free(as->as_keylist); + + if (as->as_authorizer != (void *) NULL) + keynote_free_key(as->as_authorizer, as->as_signeralgorithm); + + free(as); +} + +/* + * Taken from "Compiler Design in C" by Aho. + */ +u_int +keynote_stringhash(char *name, u_int size) +{ + unsigned int hash_val = 0; + unsigned int i; + + if ((size == 0) || (size == 1)) + return 0; + + for (; *name; name++) + { + hash_val = (hash_val << 2) + *name; + if ((i = hash_val & 0x3fff)) + hash_val = ((hash_val ^ (i >> 12)) & ~0x3fff); + } + + return hash_val % size; +} |