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