/* $OpenBSD: auxil.c,v 1.12 2022/01/14 09:08:03 tb 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 #include #include #include #include #include #include #include #include #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; DSA *dsa; RSA *rsa; if (key == NULL) return 0; switch (alg) { case KEYNOTE_ALGORITHM_DSA: dsa = (DSA *) key; res += BN_mod_word(DSA_get0_p(dsa), HASHTABLESIZE); res += BN_mod_word(DSA_get0_q(dsa), HASHTABLESIZE); res += BN_mod_word(DSA_get0_g(dsa), HASHTABLESIZE); res += BN_mod_word(DSA_get0_pub_key(dsa), HASHTABLESIZE); return res % HASHTABLESIZE; case KEYNOTE_ALGORITHM_RSA: rsa = (RSA *) key; res += BN_mod_word(RSA_get0_n(rsa), HASHTABLESIZE); res += BN_mod_word(RSA_get0_e(rsa), HASHTABLESIZE); return res % HASHTABLESIZE; case KEYNOTE_ALGORITHM_X509: /* RSA-specific */ rsa = (RSA *) key; res += BN_mod_word(RSA_get0_n(rsa), HASHTABLESIZE); res += BN_mod_word(RSA_get0_e(rsa), HASHTABLESIZE); return res % HASHTABLESIZE; 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 == 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 != 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 == NULL) { keynote_errno = ERROR_MEMORY; return -1; } kl = calloc(1, sizeof(struct keylist)); if (kl == 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 == NULL) || (keynote_current_session->ks_id != sessid)) { keynote_current_session = keynote_find_session(sessid); if (keynote_current_session == NULL) { keynote_errno = ERROR_NOTFOUND; return -1; } } ks = keynote_current_session; /* If no action authorizers present */ if ((kl = ks->ks_action_authorizers) == 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 = NULL; keynote_keylist_free(kl); return 0; } for (; kl->key_next != NULL; kl = kl->key_next) if (!strcmp(kl->key_next->key_stringkey, key)) { kl2 = kl->key_next; kl->key_next = kl2->key_next; kl2->key_next = 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 == NULL) || (keynote_current_session->ks_id != sessid)) { keynote_current_session = keynote_find_session(sessid); if (keynote_current_session == NULL) { keynote_errno = ERROR_NOTFOUND; return -1; } } stringkey = strdup(key); if (stringkey == 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 != 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 != NULL) { kl2 = kl->key_next; free(kl->key_stringkey); keynote_free_key(kl->key_key, kl->key_alg); free(kl); kl = kl2; } } /* * Free a key. */ void kn_free_key(struct keynote_deckey *dc) { if (dc) keynote_free_key(dc->dec_key, dc->dec_algorithm); } /* * 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 == NULL) return NULL; h = keynote_keyhash(authorizer, algorithm); for (as = keynote_current_session->ks_assertion_table[h]; as != NULL; as = as->as_next) if ((as->as_authorizer != 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 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; unsigned int i; if (as == NULL) { keynote_errno = ERROR_MEMORY; return -1; } if (!which) hashname = as->as_authorizer_string_s; else hashname = as->as_authorizer; if (hashname == 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 == NULL) || (keynote_current_session->ks_id != sessid)) { keynote_current_session = keynote_find_session(sessid); if (keynote_current_session == NULL) { keynote_errno = ERROR_NOTFOUND; return -1; } } as = keynote_parse_assertion(asrt, len, assertion_flags); if ((as == 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 == NULL) || (keynote_current_session->ks_id != sessid)) { keynote_current_session = keynote_find_session(sessid); if (keynote_current_session == NULL) { keynote_errno = ERROR_NOTFOUND; return -1; } } for (i = 0; i < HASHTABLESIZE; i++) { ht = keynote_current_session->ks_assertion_table[i]; if (ht == 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 != 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 == NULL) return; free(as->as_buf); free(as->as_signature); if (as->as_env != NULL) keynote_env_cleanup(&(as->as_env), 1); if (as->as_keylist != NULL) keynote_keylist_free(as->as_keylist); if (as->as_authorizer != NULL) keynote_free_key(as->as_authorizer, as->as_signeralgorithm); free(as); } unsigned int keynote_stringhash(char *name, unsigned 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) != 0) hash_val = ((hash_val ^ (i >> 12)) & 0x3fff); } return hash_val % size; }