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 */
41 static int
keynote_keyhash(void * key,int alg)42 keynote_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 */
92 int
keynote_in_action_authorizers(void * key,int algorithm)93 keynote_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 */
133 int
keynote_keylist_add(struct keylist ** keylist,char * key)134 keynote_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 */
169 int
kn_remove_authorizer(int sessid,char * key)170 kn_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 */
222 int
kn_add_authorizer(int sessid,char * key)223 kn_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 */
259 struct keylist *
keynote_keylist_find(struct keylist * kl,char * s)260 keynote_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 */
272 void
keynote_keylist_free(struct keylist * kl)273 keynote_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 */
290 void
kn_free_key(struct keynote_deckey * dc)291 kn_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 */
300 struct assertion *
keynote_find_assertion(void * authorizer,int num,int algorithm)301 keynote_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 */
332 int
keynote_add_htable(struct assertion * as,int which)333 keynote_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 */
366 int
kn_add_assertion(int sessid,char * asrt,int len,int assertion_flags)367 kn_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 */
415 static int
keynote_remove_assertion(int sessid,int assertid,int deleteflag)416 keynote_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 */
465 int
kn_remove_assertion(int sessid,int assertid)466 kn_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 */
475 int
keynote_sremove_assertion(int sessid,int assertid)476 keynote_sremove_assertion(int sessid, int assertid)
477 {
478 return keynote_remove_assertion(sessid, assertid, 0);
479 }
480
481 /*
482 * Free an assertion structure.
483 */
484 void
keynote_free_assertion(struct assertion * as)485 keynote_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
506 unsigned int
keynote_stringhash(char * name,unsigned int size)507 keynote_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