xref: /openbsd/lib/libkeynote/auxil.c (revision 76d0caae)
1 /* $OpenBSD: auxil.c,v 1.11 2015/12/14 03:35:40 mmcc 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
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->p, HASHTABLESIZE);
57 	    res += BN_mod_word(dsa->q, HASHTABLESIZE);
58 	    res += BN_mod_word(dsa->g, HASHTABLESIZE);
59 	    res += BN_mod_word(dsa->pub_key, HASHTABLESIZE);
60 	    return res % HASHTABLESIZE;
61 
62         case KEYNOTE_ALGORITHM_RSA:
63 	    rsa = (RSA *) key;
64             res += BN_mod_word(rsa->n, HASHTABLESIZE);
65             res += BN_mod_word(rsa->e, HASHTABLESIZE);
66 	    return res % HASHTABLESIZE;
67 
68 	case KEYNOTE_ALGORITHM_X509: /* RSA-specific */
69 	    rsa = (RSA *) key;
70             res += BN_mod_word(rsa->n, HASHTABLESIZE);
71             res += BN_mod_word(rsa->e, 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
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
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
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
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 *
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
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
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 *
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
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
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
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
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
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
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
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