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