server/: Replace the Diffie--Hellman group abstraction.
[tripe] / server / keymgmt.c
CommitLineData
410c8acf 1/* -*-c-*-
2 *
410c8acf 3 * Key loading and storing
4 *
5 * (c) 2001 Straylight/Edgeware
6 */
7
e04c2d50 8/*----- Licensing notice --------------------------------------------------*
410c8acf 9 *
10 * This file is part of Trivial IP Encryption (TrIPE).
11 *
12 * TrIPE is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
e04c2d50 16 *
410c8acf 17 * TrIPE is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
e04c2d50 21 *
410c8acf 22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
410c8acf 27/*----- Header files ------------------------------------------------------*/
28
29#include "tripe.h"
30
b5c45da1 31/*----- Algswitch stuff ---------------------------------------------------*/
32
33/* --- @algs_get@ --- *
34 *
35 * Arguments: @algswitch *a@ = where to put the algorithms
4998da61 36 * @dstr *e@ = where to write error tokens
4d36660a 37 * @key_file *kf@ = key file
b5c45da1 38 * @key *k@ = key to inspect
39 *
4d36660a 40 * Returns: Zero if OK; nonzero on error.
b5c45da1 41 *
42 * Use: Extracts an algorithm choice from a key.
43 */
44
4d36660a 45static int algs_get(algswitch *a, dstr *e, key_file *kf, key *k)
b5c45da1 46{
47 const char *p;
c70a7c5c 48 const bulkops *bops;
b87bffcb 49 dstr d = DSTR_INIT, dd = DSTR_INIT;
4d36660a 50 int rc = -1;
b5c45da1 51
4d36660a
MW
52 /* --- Hash function --- */
53
54 if ((p = key_getattr(kf, k, "hash")) == 0) p = "rmd160";
55 if ((a->h = ghash_byname(p)) == 0) {
56 a_format(e, "unknown-hash", "%s", p, A_END);
57 goto done;
58 }
b5c45da1 59
4d36660a 60 /* --- Symmetric encryption for key derivation --- */
b5c45da1 61
74ee77cb 62 if ((p = key_getattr(kf, k, "mgf")) == 0) {
b5c45da1 63 dstr_reset(&d);
74ee77cb 64 dstr_putf(&d, "%s-mgf", a->h->name);
b5c45da1 65 p = d.buf;
66 }
4d36660a
MW
67 if ((a->mgf = gcipher_byname(p)) == 0) {
68 a_format(e, "unknown-mgf-cipher", "%s", p, A_END);
69 goto done;
70 }
71
a93aacce 72 /* --- Bulk crypto transform --- */
b5c45da1 73
a93aacce 74 if ((p = key_getattr(kf, k, "bulk")) == 0) p = "v0";
c70a7c5c
MW
75 for (bops = bulktab; bops->name && strcmp(p, bops->name) != 0; bops++);
76 if (!bops->name) {
a93aacce
MW
77 a_format(e, "unknown-bulk-transform", "%s", p, A_END);
78 goto done;
79 }
c70a7c5c
MW
80 if ((a->bulk = bops->getalgs(a, e, kf, k)) == 0) goto done;
81 a->bulk->ops = bops;
b5c45da1 82
a93aacce
MW
83 /* --- All done --- */
84
4d36660a 85 rc = 0;
b5c45da1 86done:
87 dstr_destroy(&d);
b87bffcb 88 dstr_destroy(&dd);
4d36660a 89 return (rc);
b5c45da1 90}
91
92/* --- @algs_check@ --- *
93 *
94 * Arguments: @algswitch *a@ = a choice of algorithms
4d36660a 95 * @dstr *e@ = where to write error tokens
5b9f3d37 96 * @const dhgrp *grp@ = the group we're working in
b5c45da1 97 *
4d36660a 98 * Returns: Zero if OK; nonzero on error.
b5c45da1 99 *
100 * Use: Checks an algorithm choice for sensibleness. This also
101 * derives some useful information from the choices, and you
102 * must call this before committing the algorithm selection
103 * for use by @keyset@ functions.
104 */
105
5b9f3d37 106static int algs_check(algswitch *a, dstr *e, const dhgrp *grp)
b5c45da1 107{
b5c45da1 108 a->hashsz = a->h->hashsz;
b5c45da1 109
4d36660a
MW
110 if (keysz(a->hashsz, a->mgf->keysz) != a->hashsz) {
111 a_format(e, "mgf", "%s", a->mgf->name,
112 "restrictive-key-schedule",
113 A_END);
114 return (-1);
115 }
b5c45da1 116
c70a7c5c 117 if (a->bulk->ops->checkalgs(a->bulk, a, e)) return (-1);
b5c45da1 118
119 return (0);
120}
121
799e58b9 122/* --- @km_samealgsp@ --- *
b5c45da1 123 *
799e58b9 124 * Arguments: @const kdata *kdx, *kdy@ = two key data objects
b5c45da1 125 *
799e58b9 126 * Returns: Nonzero if their two algorithm selections are the same.
b5c45da1 127 *
128 * Use: Checks sameness of algorithm selections: used to ensure that
129 * peers are using sensible algorithms.
130 */
131
799e58b9 132int km_samealgsp(const kdata *kdx, const kdata *kdy)
b5c45da1 133{
799e58b9
MW
134 const algswitch *a = &kdx->algs, *aa = &kdy->algs;
135
5b9f3d37
MW
136 return (kdx->grp->ops == kdy->grp->ops &&
137 kdx->grp->ops->samegrpp(kdx->grp, kdy->grp) &&
799e58b9 138 a->mgf == aa->mgf && a->h == aa->h &&
c70a7c5c
MW
139 a->bulk->ops == aa->bulk->ops &&
140 a->bulk->ops->samealgsp(a->bulk, aa->bulk));
b5c45da1 141}
142
799e58b9
MW
143/*----- Key data and key nodes --------------------------------------------*/
144
145typedef struct keyhalf {
146 const char *kind;
5b9f3d37
MW
147 int (*load)(key_file *, key *, key_data *,
148 const dhops *, kdata *, dstr *, dstr *);
799e58b9
MW
149 const char *kr;
150 key_file *kf;
151 fwatch w;
152 sym_table tab;
153} keyhalf;
154
155/* --- @kh_loadpub@, @kh_loadpriv@ --- *
156 *
5b9f3d37
MW
157 * Arguments: @const dhops *dh@ = Diffie--Hellman operations for key type
158 * @key_file *kf@ = key file from which the key was loaded
159 * @key *k@ = the key object we're loading
160 * @key_data *d@ = the key data to load
799e58b9
MW
161 * @kdata *kd@ = our key-data object to fill in
162 * @dstr *t@ = the key tag name
163 * @dstr *e@ = a string to write error tokens to
164 *
165 * Returns: Zero on success, @-1@ on error.
166 *
167 * Use: These functions handle the main difference between public and
5b9f3d37
MW
168 * private key halves. They are responsible for setting @grp@,
169 * @k@ and @K@ appropriately in all keys, handling the mismatch
170 * between the largely half-indifferent calling code and the
171 * group-specific loading functions.
799e58b9
MW
172 *
173 * The function @kh_loadpriv@ is also responsible for checking
174 * the group for goodness. We don't bother checking public
175 * keys, because each public key we actually end up using must
176 * share a group with a private key which we'll already have
177 * checked.
178 */
179
5b9f3d37
MW
180static int kh_loadpub(key_file *kf, key *k, key_data *d,
181 const dhops *dh, kdata *kd, dstr *t, dstr *e)
799e58b9
MW
182{
183 int rc;
184
5b9f3d37 185 if ((rc = dh->ldpub(kf, k, d, kd, t, e)) != 0)
799e58b9 186 goto fail_0;
5b9f3d37
MW
187 kd->grp->ops = dh;
188 if (kd->grp->ops->checkge(kd->grp, kd->K)) {
73174919 189 a_format(e, "bad-public-group-element", A_END);
799e58b9
MW
190 goto fail_1;
191 }
799e58b9
MW
192 return (0);
193
194fail_1:
5b9f3d37
MW
195 kd->grp->ops->freege(kd->grp, kd->K);
196 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
197fail_0:
198 return (-1);
199}
200
5b9f3d37
MW
201static int kh_loadpriv(key_file *kf, key *k, key_data *d,
202 const dhops *dh, kdata *kd, dstr *t, dstr *e)
799e58b9
MW
203{
204 int rc;
205 const char *err;
206
5b9f3d37 207 if ((rc = dh->ldpriv(kf, k, d, kd, t, e)) != 0)
799e58b9 208 goto fail_0;
5b9f3d37
MW
209 kd->grp->ops = dh;
210 if ((err = kd->grp->ops->checkgrp(kd->grp)) != 0) {
799e58b9
MW
211 a_format(e, "bad-group", "%s", err, A_END);
212 goto fail_1;
213 }
799e58b9
MW
214 return (0);
215
216fail_1:
5b9f3d37
MW
217 kd->grp->ops->freesc(kd->grp, kd->k);
218 kd->grp->ops->freege(kd->grp, kd->K);
219 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
220fail_0:
221 return (-1);
222}
223
224static struct keyhalf
225 priv = { "private", kh_loadpriv },
226 pub = { "public", kh_loadpub };
410c8acf 227
228/* --- @keymoan@ --- *
229 *
56814747 230 * Arguments: @const char *file@ = name of the file
e04c2d50
MW
231 * @int line@ = line number in file
232 * @const char *msg@ = error message
4d36660a 233 * @void *p@ = argument pointer (indicates which keyring)
410c8acf 234 *
e04c2d50 235 * Returns: ---
410c8acf 236 *
e04c2d50 237 * Use: Reports an error message about loading a key file.
410c8acf 238 */
239
240static void keymoan(const char *file, int line, const char *msg, void *p)
f43df819 241{
799e58b9 242 keyhalf *kh = p;
4d36660a
MW
243
244 if (!line) {
799e58b9 245 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", file,
4d36660a
MW
246 "io-error", "?ERRNO", A_END);
247 } else {
799e58b9 248 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", file, "line", "%d", line,
4d36660a
MW
249 "%s", msg, A_END);
250 }
f43df819 251}
410c8acf 252
799e58b9 253/* --- @kh_reopen@ --- *
fc5f4823 254 *
799e58b9 255 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure
fc5f4823 256 *
799e58b9 257 * Returns: Zero on success, @-1@ on error.
fc5f4823 258 *
799e58b9
MW
259 * Use: Reopens the key file for the appropriate key half. If this
260 * fails, everything is left as it was; if it succeeds, then the
261 * old file is closed (if it was non-null) and the new one put
262 * in its place.
fc5f4823
MW
263 */
264
799e58b9 265static int kh_reopen(keyhalf *kh)
fc5f4823 266{
799e58b9 267 key_file *kf = CREATE(key_file);
fc5f4823 268
799e58b9
MW
269 if (key_open(kf, kh->kr, KOPEN_READ, keymoan, kh)) {
270 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", kh->kr,
7f81b1b4 271 "io-error", "?ERRNO", A_END);
799e58b9
MW
272 DESTROY(kf);
273 return (-1);
274 } else {
275 if (kh->kf) {
276 key_close(kh->kf);
277 DESTROY(kh->kf);
278 }
279 kh->kf = kf;
280 return (0);
281 }
282}
fc5f4823 283
799e58b9
MW
284/* --- @kh_init@ --- *
285 *
286 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure to set up
287 * @const char *kr@ = name of the keyring file
288 *
289 * Returns: ---
290 *
291 * Use: Initialize a keyhalf structure, maintaining the private or
292 * public keys. Intended to be called during initialization:
293 * exits if there's some kind of problem.
294 */
fc5f4823 295
799e58b9
MW
296static void kh_init(keyhalf *kh, const char *kr)
297{
298 kh->kr = kr;
299 fwatch_init(&kh->w, kr);
300 sym_create(&kh->tab);
301 kh->kf = 0;
302
303 if (kh_reopen(kh))
304 die(EXIT_FAILURE, "failed to load %s keyring `%s'", kh->kind, kr);
fc5f4823
MW
305}
306
799e58b9 307/* --- @kh_load@ --- *
410c8acf 308 *
799e58b9
MW
309 * Arguments: @keyhalf *kh@ = pointer to keyhalf
310 * @const char *tag@ = key tag to be loaded
311 * @int complainp@ = whether to complain about missing keys
410c8acf 312 *
799e58b9
MW
313 * Returns: Pointer to a @kdata@ structure if successful, or null on
314 * failure.
410c8acf 315 *
799e58b9
MW
316 * Use: Attempts to load a key from the current key file. This
317 * function always reads data from the file: it's used when
318 * there's a cache miss from @kh_find@, and when refreshing the
319 * known keys in @kh_refresh@. The returned kdata has a
320 * reference count of exactly 1, and has no home knode.
410c8acf 321 */
322
799e58b9 323static kdata *kh_load(keyhalf *kh, const char *tag, int complainp)
410c8acf 324{
52c03a2a 325 dstr t = DSTR_INIT;
4d36660a 326 dstr e = DSTR_INIT;
799e58b9
MW
327 key *k;
328 key_data **d;
329 kdata *kd;
330 const char *ty;
5b9f3d37
MW
331 const dhops *dh;
332 T( const dhgrp *g; )
52c03a2a 333
799e58b9 334 /* --- Find the key and grab its tag --- */
52c03a2a 335
799e58b9
MW
336 if (key_qtag(kh->kf, tag, &t, &k, &d)) {
337 if (complainp) {
338 a_warn("KEYMGMT", "%s-keyring", kh->kind, "%s", kh->kr,
339 "key-not-found", "%s", tag, A_END);
340 }
341 goto fail_0;
52c03a2a 342 }
343
799e58b9
MW
344 /* --- Find the key's group type and the appropriate operations --- *
345 *
346 * There are several places to look for the key type. The most obvious is
347 * the `kx-group' key attribute. But there's also the key type itself, for
348 * compatibility reasons.
349 */
52c03a2a 350
799e58b9
MW
351 ty = key_getattr(kh->kf, k, "kx-group");
352 if (!ty && strncmp(k->type, "tripe-", 6) == 0) ty = k->type + 6;
353 if (!ty) ty = "dh";
52c03a2a 354
5b9f3d37
MW
355 for (dh = dhtab; dh->name; dh++)
356 if (strcmp(dh->name, ty) == 0) goto founddh;
799e58b9
MW
357 a_warn("KEYMGMT", "%s-keyring", kh->kind,
358 "%s", kh->kr, "key", "%s", t.buf,
359 "unknown-group-type", "%s", ty, A_END);
360 goto fail_0;
361
5b9f3d37 362founddh:
799e58b9 363 kd = CREATE(kdata);
5b9f3d37 364 if (kh->load(kh->kf, k, *d, dh, kd, &t, &e)) {
799e58b9 365 a_warn("KEYMGMT", "%s-keyring", kh->kind,
01d12d8f 366 "%s", kh->kr, "key", "%s", t.buf,
4d36660a 367 "*%s", e.buf, A_END);
799e58b9 368 goto fail_1;
52c03a2a 369 }
370
799e58b9 371 if (algs_get(&kd->algs, &e, kh->kf, k) ||
5b9f3d37 372 (kd->k && algs_check(&kd->algs, &e, kd->grp))) {
799e58b9
MW
373 a_warn("KEYMGMT", "%s-keyring", kh->kind,
374 "%s", kh->kr, "key", "%s", t.buf,
4d36660a 375 "*%s", e.buf, A_END);
799e58b9 376 goto fail_2;
410c8acf 377 }
52c03a2a 378
799e58b9 379 kd->tag = xstrdup(t.buf);
799e58b9
MW
380 kd->ref = 1;
381 kd->kn = 0;
382 kd->t_exp = k->exp;
52c03a2a 383
384 IF_TRACING(T_KEYMGMT, {
799e58b9 385 trace(T_KEYMGMT, "keymgmt: loaded %s key `%s'", kh->kind, t.buf);
52c03a2a 386 IF_TRACING(T_CRYPTO, {
5b9f3d37
MW
387 g = kd->grp;
388 g->ops->tracegrp(g);
389 if (kd->k)
390 trace(T_CRYPTO, "crypto: k = %s", g->ops->scstr(g, kd->k));
391 trace(T_CRYPTO, "crypto: K = %s", g->ops->gestr(g, kd->K));
c70a7c5c 392 kd->algs.bulk->ops->tracealgs(kd->algs.bulk);
52c03a2a 393 })
394 })
395
799e58b9 396 goto done;
52c03a2a 397
799e58b9 398fail_2:
5b9f3d37
MW
399 if (kd->k) kd->grp->ops->freesc(kd->grp, kd->k);
400 kd->grp->ops->freege(kd->grp, kd->K);
401 kd->grp->ops->freegrp(kd->grp);
799e58b9
MW
402fail_1:
403 DESTROY(kd);
404fail_0:
405 kd = 0;
406done:
52c03a2a 407 dstr_destroy(&t);
4d36660a 408 dstr_destroy(&e);
799e58b9 409 return (kd);
410c8acf 410}
411
799e58b9 412/* --- @kh_find@ --- *
410c8acf 413 *
799e58b9
MW
414 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
415 * @const char *tag@ = key to be obtained
416 * @int complainp@ = whether to complain about missing keys
410c8acf 417 *
799e58b9 418 * Returns: A pointer to the kdata, or null on error.
410c8acf 419 *
799e58b9
MW
420 * Use: Obtains kdata, maybe from the cache. This won't update a
421 * stale cache entry, though @kh_refresh@ ought to have done
422 * that already. The returned kdata object may be shared with
423 * other users. (One of this function's responsibilities, over
424 * @kh_load@, is to set the home knode of a freshly loaded
425 * kdata.)
410c8acf 426 */
427
799e58b9 428static kdata *kh_find(keyhalf *kh, const char *tag, int complainp)
410c8acf 429{
799e58b9
MW
430 knode *kn;
431 kdata *kd;
432 unsigned f;
410c8acf 433
799e58b9
MW
434 kn = sym_find(&kh->tab, tag, -1, sizeof(knode), &f);
435
436 if (f) {
437 if (kn->f & KNF_BROKEN) {
438 T( if (complainp)
439 trace(T_KEYMGMT, "keymgmt: key `%s' marked as broken", tag); )
440 return (0);
441 }
442
443 kd = kn->kd;
444 if (kd) kd->ref++;
445 T( trace(T_KEYMGMT, "keymgmt: %scache hit for key `%s'",
446 kd ? "" : "negative ", tag); )
447 return (kd);
448 } else {
449 kd = kh_load(kh, tag, complainp);
450 kn->kd = kd;
451 kn->kh = kh;
452 kn->f = 0;
453 if (!kd)
454 kn->f |= KNF_BROKEN;
455 else {
456 kd->kn = kn;
457 kd->ref++;
458 }
459 return (kd);
410c8acf 460 }
410c8acf 461}
462
799e58b9 463/* --- @kh_refresh@ --- *
410c8acf 464 *
799e58b9 465 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
410c8acf 466 *
799e58b9
MW
467 * Returns: Zero if nothing needs to be done; nonzero if peers should
468 * refresh their keys.
410c8acf 469 *
799e58b9
MW
470 * Use: Refreshes cached keys from files.
471 *
472 * Each active knode is examined to see if a new key is
473 * available: the return value is nonzero if any new keys are.
474 * A key is considered new if its algorithms, public key, or
475 * expiry time are/is different.
476 *
477 * Stub knodes (with no kdata attached) are removed, so that a
478 * later retry can succeed if the file has been fixed. (This
479 * doesn't count as a change, since no peers should be relying
480 * on a nonexistent key.)
410c8acf 481 */
482
799e58b9 483static int kh_refresh(keyhalf *kh)
410c8acf 484{
799e58b9
MW
485 knode *kn;
486 kdata *kd;
487 sym_iter i;
488 int changep = 0;
489
490 if (!fwatch_update(&kh->w, kh->kr) || kh_reopen(kh))
491 return (0);
492
493 T( trace(T_KEYMGMT, "keymgmt: rescan %s keyring `%s'", kh->kind, kh->kr); )
494 for (sym_mkiter(&i, &kh->tab); (kn = sym_next(&i)) != 0; ) {
495 if (!kn->kd) {
496 T( trace(T_KEYMGMT, "keymgmt: discard stub entry for key `%s'",
497 SYM_NAME(kn)); )
498 sym_remove(&kh->tab, kn);
499 continue;
500 }
501 if ((kd = kh_load(kh, SYM_NAME(kn), 1)) == 0) {
502 if (!(kn->f & KNF_BROKEN)) {
503 T( trace(T_KEYMGMT, "keymgmt: failed to load new key `%s': "
504 "marking it as broken",
505 SYM_NAME(kn)); )
506 kn->f |= KNF_BROKEN;
507 }
508 continue;
509 }
510 kn->f &= ~KNF_BROKEN;
511 if (kd->t_exp == kn->kd->t_exp &&
512 km_samealgsp(kd, kn->kd) &&
5b9f3d37 513 kd->grp->ops->eq(kd->grp, kd->K, kn->kd->K)) {
799e58b9
MW
514 T( trace(T_KEYMGMT, "keymgmt: key `%s' unchanged", SYM_NAME(kn)); )
515 continue;
516 }
517 T( trace(T_KEYMGMT, "keymgmt: loaded new version of key `%s'",
518 SYM_NAME(kn)); )
519 km_unref(kn->kd);
520 kd->kn = kn;
521 kn->kd = kd;
522 changep = 1;
523 }
410c8acf 524
799e58b9
MW
525 return (changep);
526}
410c8acf 527
799e58b9 528/*----- Main code ---------------------------------------------------------*/
410c8acf 529
799e58b9
MW
530const char *tag_priv;
531kdata *master;
410c8acf 532
410c8acf 533/* --- @km_init@ --- *
534 *
799e58b9
MW
535 * Arguments: @const char *privkr@ = private keyring file
536 * @const char *pubkr@ = public keyring file
537 * @const char *ptag@ = default private-key tag
410c8acf 538 *
539 * Returns: ---
540 *
799e58b9
MW
541 * Use: Initializes the key-management machinery, loading the
542 * keyrings and so on.
410c8acf 543 */
544
799e58b9 545void km_init(const char *privkr, const char *pubkr, const char *ptag)
410c8acf 546{
b5c45da1 547 const gchash *const *hh;
410c8acf 548
b5c45da1 549 for (hh = ghashtab; *hh; hh++) {
550 if ((*hh)->hashsz > MAXHASHSZ) {
551 die(EXIT_FAILURE, "INTERNAL ERROR: %s hash length %lu > MAXHASHSZ %d",
552 (*hh)->name, (unsigned long)(*hh)->hashsz, MAXHASHSZ);
553 }
554 }
555
799e58b9
MW
556 kh_init(&priv, privkr);
557 kh_init(&pub, pubkr);
558
559 tag_priv = ptag;
560 if ((master = km_findpriv(ptag)) == 0) exit(EXIT_FAILURE);
410c8acf 561}
562
799e58b9 563/* --- @km_reload@ --- *
410c8acf 564 *
799e58b9 565 * Arguments: ---
410c8acf 566 *
799e58b9 567 * Returns: Zero if OK, nonzero to force reloading of keys.
410c8acf 568 *
799e58b9 569 * Use: Checks the keyrings to see if they need reloading.
410c8acf 570 */
571
799e58b9 572int km_reload(void)
410c8acf 573{
799e58b9
MW
574 int changep = 0;
575 kdata *kd;
576
577 if (kh_refresh(&priv)) {
578 changep = 1;
579 kd = master->kn->kd;
35c8b547 580 if (kd != master) {
799e58b9
MW
581 km_unref(master);
582 km_ref(kd);
583 master = kd;
584 }
585 }
586 if (kh_refresh(&pub))
587 changep = 1;
588 return (changep);
589}
52c03a2a 590
799e58b9
MW
591/* --- @km_findpub@, @km_findpriv@ --- *
592 *
593 * Arguments: @const char *tag@ = key tag to load
594 *
595 * Returns: Pointer to the kdata object if successful, or null on error.
596 *
597 * Use: Fetches a public or private key from the keyring.
598 */
52c03a2a 599
799e58b9 600kdata *km_findpub(const char *tag) { return (kh_find(&pub, tag, 1)); }
410c8acf 601
799e58b9
MW
602kdata *km_findpriv(const char *tag)
603{
604 kdata *kd;
52c03a2a 605
799e58b9
MW
606 /* Unpleasantness for the sake of compatibility. */
607 if (!tag && (kd = kh_find(&priv, "tripe", 0)) != 0) return (kd);
608 else return (kh_find(&priv, tag ? tag : "tripe-dh", 1));
609}
52c03a2a 610
799e58b9
MW
611/* --- @km_tag@ --- *
612 *
613 * Arguments: @kdata *kd@ - pointer to the kdata object
614 *
615 * Returns: A pointer to the short tag by which the kdata was loaded.
616 */
52c03a2a 617
799e58b9 618const char *km_tag(kdata *kd) { return (SYM_NAME(kd->kn)); }
52c03a2a 619
799e58b9
MW
620/* --- @km_ref@ --- *
621 *
622 * Arguments: @kdata *kd@ = pointer to the kdata object
623 *
624 * Returns: ---
625 *
626 * Use: Claim a new reference to a kdata object.
627 */
52c03a2a 628
799e58b9 629void km_ref(kdata *kd) { kd->ref++; }
52c03a2a 630
799e58b9
MW
631/* --- @km_unref@ --- *
632 *
633 * Arguments: @kdata *kd@ = pointer to the kdata object
634 *
635 * Returns: ---
636 *
637 * Use: Releases a reference to a kdata object.
638 */
52c03a2a 639
799e58b9
MW
640void km_unref(kdata *kd)
641{
642 if (--kd->ref) return;
5b9f3d37
MW
643 if (kd->k) kd->grp->ops->freesc(kd->grp, kd->k);
644 kd->grp->ops->freege(kd->grp, kd->K);
645 kd->grp->ops->freegrp(kd->grp);
799e58b9 646 xfree(kd->tag);
5290b9d5 647 DESTROY(kd);
799e58b9
MW
648}
649
410c8acf 650/*----- That's all, folks -------------------------------------------------*/