1/* $OpenBSD: auxil.c,v 1.12 2022/01/14 09:08:03 tb 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 <ctype.h> 25#include <limits.h> 26#include <regex.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30 31#include <openssl/dsa.h> 32#include <openssl/rsa.h> 33 34#include "keynote.h" 35#include "assertion.h" 36#include "signature.h" 37 38/* 39 * Get some sort of key-hash for hash table indexing purposes. 40 */ 41static int 42keynote_keyhash(void *key, int alg) 43{ 44 struct keynote_binary *bn; 45 unsigned int res = 0, i; 46 DSA *dsa; 47 RSA *rsa; 48 49 if (key == NULL) 50 return 0; 51 52 switch (alg) 53 { 54 case KEYNOTE_ALGORITHM_DSA: 55 dsa = (DSA *) key; 56 res += BN_mod_word(DSA_get0_p(dsa), HASHTABLESIZE); 57 res += BN_mod_word(DSA_get0_q(dsa), HASHTABLESIZE); 58 res += BN_mod_word(DSA_get0_g(dsa), HASHTABLESIZE); 59 res += BN_mod_word(DSA_get0_pub_key(dsa), HASHTABLESIZE); 60 return res % HASHTABLESIZE; 61 62 case KEYNOTE_ALGORITHM_RSA: 63 rsa = (RSA *) key; 64 res += BN_mod_word(RSA_get0_n(rsa), HASHTABLESIZE); 65 res += BN_mod_word(RSA_get0_e(rsa), HASHTABLESIZE); 66 return res % HASHTABLESIZE; 67 68 case KEYNOTE_ALGORITHM_X509: /* RSA-specific */ 69 rsa = (RSA *) key; 70 res += BN_mod_word(RSA_get0_n(rsa), HASHTABLESIZE); 71 res += BN_mod_word(RSA_get0_e(rsa), HASHTABLESIZE); 72 return res % HASHTABLESIZE; 73 74 case KEYNOTE_ALGORITHM_BINARY: 75 bn = (struct keynote_binary *) key; 76 for (i = 0; i < bn->bn_len; i++) 77 res = (res + ((unsigned char) bn->bn_key[i])) % HASHTABLESIZE; 78 79 return res; 80 81 case KEYNOTE_ALGORITHM_NONE: 82 return keynote_stringhash(key, HASHTABLESIZE); 83 84 default: 85 return 0; 86 } 87} 88 89/* 90 * Return RESULT_TRUE if key appears in the action authorizers. 91 */ 92int 93keynote_in_action_authorizers(void *key, int algorithm) 94{ 95 struct keylist *kl, *kl2; 96 void *s; 97 int alg; 98 99 if (algorithm == KEYNOTE_ALGORITHM_UNSPEC) 100 { 101 kl2 = keynote_keylist_find(keynote_current_assertion->as_keylist, key); 102 if (kl2 == NULL) 103 return RESULT_FALSE; /* Shouldn't ever happen */ 104 105 s = kl2->key_key; 106 alg = kl2->key_alg; 107 } 108 else 109 { 110 s = key; 111 alg = algorithm; 112 } 113 114 for (kl = keynote_current_session->ks_action_authorizers; 115 kl != NULL; 116 kl = kl->key_next) 117 if ((kl->key_alg == alg) || 118 ((kl->key_alg == KEYNOTE_ALGORITHM_RSA) && 119 (alg == KEYNOTE_ALGORITHM_X509)) || 120 ((kl->key_alg == KEYNOTE_ALGORITHM_X509) && 121 (alg == KEYNOTE_ALGORITHM_RSA))) 122 if (kn_keycompare(kl->key_key, s, alg) == RESULT_TRUE) 123 return RESULT_TRUE; 124 125 return RESULT_FALSE; 126} 127 128/* 129 * Add a key to the keylist. Return RESULT_TRUE on success, -1 (and set 130 * keynote_errno) otherwise. We are not supposed to make a copy of the 131 * argument. 132 */ 133int 134keynote_keylist_add(struct keylist **keylist, char *key) 135{ 136 struct keynote_deckey dc; 137 struct keylist *kl; 138 139 if (keylist == NULL) 140 { 141 keynote_errno = ERROR_MEMORY; 142 return -1; 143 } 144 145 kl = calloc(1, sizeof(struct keylist)); 146 if (kl == NULL) 147 { 148 keynote_errno = ERROR_MEMORY; 149 return -1; 150 } 151 152 if (kn_decode_key(&dc, key, KEYNOTE_PUBLIC_KEY) != 0) 153 { 154 free(kl); 155 return -1; 156 } 157 158 kl->key_key = dc.dec_key; 159 kl->key_alg = dc.dec_algorithm; 160 kl->key_stringkey = key; 161 kl->key_next = *keylist; 162 *keylist = kl; 163 return RESULT_TRUE; 164} 165 166/* 167 * Remove an action authorizer. 168 */ 169int 170kn_remove_authorizer(int sessid, char *key) 171{ 172 struct keynote_session *ks; 173 struct keylist *kl, *kl2; 174 175 keynote_errno = 0; 176 if ((keynote_current_session == NULL) || 177 (keynote_current_session->ks_id != sessid)) 178 { 179 keynote_current_session = keynote_find_session(sessid); 180 if (keynote_current_session == NULL) 181 { 182 keynote_errno = ERROR_NOTFOUND; 183 return -1; 184 } 185 } 186 187 ks = keynote_current_session; 188 189 /* If no action authorizers present */ 190 if ((kl = ks->ks_action_authorizers) == NULL) 191 { 192 keynote_errno = ERROR_NOTFOUND; 193 return -1; 194 } 195 196 /* First in list */ 197 if (!strcmp(kl->key_stringkey, key)) 198 { 199 ks->ks_action_authorizers = kl->key_next; 200 kl->key_next = NULL; 201 keynote_keylist_free(kl); 202 return 0; 203 } 204 205 for (; kl->key_next != NULL; kl = kl->key_next) 206 if (!strcmp(kl->key_next->key_stringkey, key)) 207 { 208 kl2 = kl->key_next; 209 kl->key_next = kl2->key_next; 210 kl2->key_next = NULL; 211 keynote_keylist_free(kl2); 212 return 0; 213 } 214 215 keynote_errno = ERROR_NOTFOUND; 216 return -1; 217} 218 219/* 220 * Add an action authorizer. 221 */ 222int 223kn_add_authorizer(int sessid, char *key) 224{ 225 char *stringkey; 226 227 keynote_errno = 0; 228 if ((keynote_current_session == NULL) || 229 (keynote_current_session->ks_id != sessid)) 230 { 231 keynote_current_session = keynote_find_session(sessid); 232 if (keynote_current_session == NULL) 233 { 234 keynote_errno = ERROR_NOTFOUND; 235 return -1; 236 } 237 } 238 239 stringkey = strdup(key); 240 if (stringkey == NULL) 241 { 242 keynote_errno = ERROR_MEMORY; 243 return -1; 244 } 245 246 if (keynote_keylist_add(&(keynote_current_session->ks_action_authorizers), 247 stringkey) == -1) 248 { 249 free(stringkey); 250 return -1; 251 } 252 253 return 0; 254} 255 256/* 257 * Find a keylist entry based on the key_stringkey entry. 258 */ 259struct keylist * 260keynote_keylist_find(struct keylist *kl, char *s) 261{ 262 for (; kl != NULL; kl = kl->key_next) 263 if (!strcmp(kl->key_stringkey, s)) 264 return kl; 265 266 return kl; 267} 268 269/* 270 * Free keylist list. 271 */ 272void 273keynote_keylist_free(struct keylist *kl) 274{ 275 struct keylist *kl2; 276 277 while (kl != NULL) 278 { 279 kl2 = kl->key_next; 280 free(kl->key_stringkey); 281 keynote_free_key(kl->key_key, kl->key_alg); 282 free(kl); 283 kl = kl2; 284 } 285} 286 287/* 288 * Free a key. 289 */ 290void 291kn_free_key(struct keynote_deckey *dc) 292{ 293 if (dc) 294 keynote_free_key(dc->dec_key, dc->dec_algorithm); 295} 296 297/* 298 * Find the num-th assertion given the authorizer. Return NULL if not found. 299 */ 300struct assertion * 301keynote_find_assertion(void *authorizer, int num, int algorithm) 302{ 303 struct assertion *as; 304 unsigned int h; 305 306 if (authorizer == NULL) 307 return NULL; 308 309 h = keynote_keyhash(authorizer, algorithm); 310 for (as = keynote_current_session->ks_assertion_table[h]; 311 as != NULL; 312 as = as->as_next) 313 if ((as->as_authorizer != NULL) && 314 ((as->as_signeralgorithm == algorithm) || 315 ((as->as_signeralgorithm == KEYNOTE_ALGORITHM_RSA) && 316 (algorithm == KEYNOTE_ALGORITHM_X509)) || 317 ((as->as_signeralgorithm == KEYNOTE_ALGORITHM_X509) && 318 (algorithm == KEYNOTE_ALGORITHM_RSA)))) 319 if (kn_keycompare(authorizer, as->as_authorizer, algorithm) == 320 RESULT_TRUE) 321 if (num-- == 0) 322 return as; 323 324 return NULL; 325} 326 327/* 328 * Add an assertion to the hash table. Return RESULT_TRUE on success, 329 * ERROR_MEMORY for memory failure, ERROR_SYNTAX if some problem with 330 * the assertion is detected. 331 */ 332int 333keynote_add_htable(struct assertion *as, int which) 334{ 335 char *hashname; 336 unsigned int i; 337 338 if (as == NULL) 339 { 340 keynote_errno = ERROR_MEMORY; 341 return -1; 342 } 343 344 if (!which) 345 hashname = as->as_authorizer_string_s; 346 else 347 hashname = as->as_authorizer; 348 349 if (hashname == NULL) 350 { 351 keynote_errno = ERROR_SYNTAX; 352 return -1; 353 } 354 355 i = keynote_keyhash(hashname, as->as_signeralgorithm); 356 as->as_next = keynote_current_session->ks_assertion_table[i]; 357 keynote_current_session->ks_assertion_table[i] = as; 358 return RESULT_TRUE; 359} 360 361/* 362 * Parse and store an assertion in the internal hash table. 363 * Return the result of the evaluation, if doing early evaluation. 364 * If an error was encountered, set keynote_errno. 365 */ 366int 367kn_add_assertion(int sessid, char *asrt, int len, int assertion_flags) 368{ 369 struct assertion *as; 370 371 keynote_errno = 0; 372 if ((keynote_current_session == NULL) || 373 (keynote_current_session->ks_id != sessid)) 374 { 375 keynote_current_session = keynote_find_session(sessid); 376 if (keynote_current_session == NULL) 377 { 378 keynote_errno = ERROR_NOTFOUND; 379 return -1; 380 } 381 } 382 383 as = keynote_parse_assertion(asrt, len, assertion_flags); 384 if ((as == NULL) || (keynote_errno != 0)) 385 { 386 if (keynote_errno == 0) 387 keynote_errno = ERROR_SYNTAX; 388 389 return -1; 390 } 391 392 as->as_id = keynote_current_session->ks_assertioncounter++; 393 394 /* Check for wrap around...there has to be a better solution to this */ 395 if (keynote_current_session->ks_assertioncounter < 0) 396 { 397 keynote_free_assertion(as); 398 keynote_errno = ERROR_SYNTAX; 399 return -1; 400 } 401 402 if (keynote_add_htable(as, 0) != RESULT_TRUE) 403 { 404 keynote_free_assertion(as); 405 return -1; 406 } 407 408 as->as_internalflags |= ASSERT_IFLAG_NEEDPROC; 409 return as->as_id; 410} 411 412/* 413 * Remove an assertion from the hash table. 414 */ 415static int 416keynote_remove_assertion(int sessid, int assertid, int deleteflag) 417{ 418 struct assertion *ht, *ht2; 419 int i; 420 421 if ((keynote_current_session == NULL) || 422 (keynote_current_session->ks_id != sessid)) 423 { 424 keynote_current_session = keynote_find_session(sessid); 425 if (keynote_current_session == NULL) 426 { 427 keynote_errno = ERROR_NOTFOUND; 428 return -1; 429 } 430 } 431 432 for (i = 0; i < HASHTABLESIZE; i++) 433 { 434 ht = keynote_current_session->ks_assertion_table[i]; 435 if (ht == NULL) 436 continue; 437 438 /* If first entry in bucket */ 439 if (ht->as_id == assertid) 440 { 441 keynote_current_session->ks_assertion_table[i] = ht->as_next; 442 if (deleteflag) 443 keynote_free_assertion(ht); 444 return 0; 445 } 446 447 for (; ht->as_next != NULL; ht = ht->as_next) 448 if (ht->as_next->as_id == assertid) /* Got it */ 449 { 450 ht2 = ht->as_next; 451 ht->as_next = ht2->as_next; 452 if (deleteflag) 453 keynote_free_assertion(ht2); 454 return 0; 455 } 456 } 457 458 keynote_errno = ERROR_NOTFOUND; 459 return -1; 460} 461 462/* 463 * API wrapper for deleting assertions. 464 */ 465int 466kn_remove_assertion(int sessid, int assertid) 467{ 468 keynote_errno = 0; 469 return keynote_remove_assertion(sessid, assertid, 1); 470} 471 472/* 473 * Internally-used wrapper for removing but not deleting assertions. 474 */ 475int 476keynote_sremove_assertion(int sessid, int assertid) 477{ 478 return keynote_remove_assertion(sessid, assertid, 0); 479} 480 481/* 482 * Free an assertion structure. 483 */ 484void 485keynote_free_assertion(struct assertion *as) 486{ 487 if (as == NULL) 488 return; 489 490 free(as->as_buf); 491 492 free(as->as_signature); 493 494 if (as->as_env != NULL) 495 keynote_env_cleanup(&(as->as_env), 1); 496 497 if (as->as_keylist != NULL) 498 keynote_keylist_free(as->as_keylist); 499 500 if (as->as_authorizer != NULL) 501 keynote_free_key(as->as_authorizer, as->as_signeralgorithm); 502 503 free(as); 504} 505 506unsigned int 507keynote_stringhash(char *name, unsigned int size) 508{ 509 unsigned int hash_val = 0; 510 unsigned int i; 511 512 if ((size == 0) || (size == 1)) 513 return 0; 514 515 for (; *name; name++) 516 { 517 hash_val = (hash_val << 2) + *name; 518 if ((i = hash_val & 0x3fff) != 0) 519 hash_val = ((hash_val ^ (i >> 12)) & 0x3fff); 520 } 521 522 return hash_val % size; 523} 524