3 * Key loading and storing
5 * (c) 2001 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
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.
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.
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.
27 /*----- Header files ------------------------------------------------------*/
31 /*----- Algswitch stuff ---------------------------------------------------*/
33 /* --- @algs_get@ --- *
35 * Arguments: @algswitch *a@ = where to put the algorithms
36 * @dstr *e@ = where to write error tokens
37 * @key_file *kf@ = key file
38 * @key *k@ = key to inspect
40 * Returns: Zero if OK; nonzero on error.
42 * Use: Extracts an algorithm choice from a key.
45 static int algs_get(algswitch
*a
, dstr
*e
, key_file
*kf
, key
*k
)
49 dstr d
= DSTR_INIT
, dd
= DSTR_INIT
;
52 /* --- Hash function --- */
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
);
60 /* --- Symmetric encryption for key derivation --- */
62 if ((p
= key_getattr(kf
, k
, "mgf")) == 0) {
64 dstr_putf(&d
, "%s-mgf", a
->h
->name
);
67 if ((a
->mgf
= gcipher_byname(p
)) == 0) {
68 a_format(e
, "unknown-mgf-cipher", "%s", p
, A_END
);
72 /* --- Bulk crypto transform --- */
74 if ((p
= key_getattr(kf
, k
, "bulk")) == 0) p
= "v0";
75 for (bops
= bulktab
; bops
->name
&& strcmp(p
, bops
->name
) != 0; bops
++);
77 a_format(e
, "unknown-bulk-transform", "%s", p
, A_END
);
80 if ((a
->bulk
= bops
->getalgs(a
, e
, kf
, k
)) == 0) goto done
;
83 /* --- All done --- */
92 /* --- @algs_check@ --- *
94 * Arguments: @algswitch *a@ = a choice of algorithms
95 * @dstr *e@ = where to write error tokens
96 * @const dhgrp *grp@ = the group we're working in
98 * Returns: Zero if OK; nonzero on error.
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.
106 static int algs_check(algswitch
*a
, dstr
*e
, const dhgrp
*grp
)
108 a
->hashsz
= a
->h
->hashsz
;
110 if (keysz(a
->hashsz
, a
->mgf
->keysz
) != a
->hashsz
) {
111 a_format(e
, "mgf", "%s", a
->mgf
->name
,
112 "restrictive-key-schedule",
117 if (a
->bulk
->ops
->checkalgs(a
->bulk
, a
, e
)) return (-1);
122 /* --- @km_samealgsp@ --- *
124 * Arguments: @const kdata *kdx, *kdy@ = two key data objects
126 * Returns: Nonzero if their two algorithm selections are the same.
128 * Use: Checks sameness of algorithm selections: used to ensure that
129 * peers are using sensible algorithms.
132 int km_samealgsp(const kdata
*kdx
, const kdata
*kdy
)
134 const algswitch
*a
= &kdx
->algs
, *aa
= &kdy
->algs
;
136 return (kdx
->grp
->ops
== kdy
->grp
->ops
&&
137 kdx
->grp
->ops
->samegrpp(kdx
->grp
, kdy
->grp
) &&
138 a
->mgf
== aa
->mgf
&& a
->h
== aa
->h
&&
139 a
->bulk
->ops
== aa
->bulk
->ops
&&
140 a
->bulk
->ops
->samealgsp(a
->bulk
, aa
->bulk
));
143 /*----- Key data and key nodes --------------------------------------------*/
145 typedef struct keyhalf
{
147 int (*load
)(key_file
*, key
*, key_data
*,
148 const dhops
*, kdata
*, dstr
*, dstr
*);
155 /* --- @kh_loadpub@, @kh_loadpriv@ --- *
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
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
165 * Returns: Zero on success, @-1@ on error.
167 * Use: These functions handle the main difference between public and
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.
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
180 static int kh_loadpub(key_file
*kf
, key
*k
, key_data
*d
,
181 const dhops
*dh
, kdata
*kd
, dstr
*t
, dstr
*e
)
185 if ((rc
= dh
->ldpub(kf
, k
, d
, kd
, t
, e
)) != 0)
188 if (kd
->grp
->ops
->checkge(kd
->grp
, kd
->K
)) {
189 a_format(e
, "bad-public-group-element", A_END
);
195 kd
->grp
->ops
->freege(kd
->grp
, kd
->K
);
196 kd
->grp
->ops
->freegrp(kd
->grp
);
201 static int kh_loadpriv(key_file
*kf
, key
*k
, key_data
*d
,
202 const dhops
*dh
, kdata
*kd
, dstr
*t
, dstr
*e
)
209 if ((rc
= dh
->ldpriv(kf
, k
, d
, kd
, t
, e
)) != 0)
212 if ((err
= kd
->grp
->ops
->checkgrp(kd
->grp
)) != 0) {
213 a_format(e
, "bad-group", "%s", err
, A_END
);
216 K
= kd
->grp
->ops
->mul(kd
->grp
, kd
->k
, 0);
217 ok
= kd
->grp
->ops
->eq(kd
->grp
, kd
->K
, K
);
218 kd
->grp
->ops
->freege(kd
->grp
, K
);
220 a_format(e
, "incorrect-public-key", A_END
);
226 kd
->grp
->ops
->freesc(kd
->grp
, kd
->k
);
227 kd
->grp
->ops
->freege(kd
->grp
, kd
->K
);
228 kd
->grp
->ops
->freegrp(kd
->grp
);
233 static struct keyhalf
234 priv
= { "private", kh_loadpriv
},
235 pub
= { "public", kh_loadpub
};
237 /* --- @keymoan@ --- *
239 * Arguments: @const char *file@ = name of the file
240 * @int line@ = line number in file
241 * @const char *msg@ = error message
242 * @void *p@ = argument pointer (indicates which keyring)
246 * Use: Reports an error message about loading a key file.
249 static void keymoan(const char *file
, int line
, const char *msg
, void *p
)
254 a_warn("KEYMGMT", "%s-keyring", kh
->kind
, "%s", file
,
255 "io-error", "?ERRNO", A_END
);
257 a_warn("KEYMGMT", "%s-keyring", kh
->kind
, "%s", file
, "line", "%d", line
,
262 /* --- @kh_reopen@ --- *
264 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure
266 * Returns: Zero on success, @-1@ on error.
268 * Use: Reopens the key file for the appropriate key half. If this
269 * fails, everything is left as it was; if it succeeds, then the
270 * old file is closed (if it was non-null) and the new one put
274 static int kh_reopen(keyhalf
*kh
)
276 key_file
*kf
= CREATE(key_file
);
278 if (key_open(kf
, kh
->kr
, KOPEN_READ
, keymoan
, kh
)) {
279 a_warn("KEYMGMT", "%s-keyring", kh
->kind
, "%s", kh
->kr
,
280 "io-error", "?ERRNO", A_END
);
293 /* --- @kh_init@ --- *
295 * Arguments: @keyhalf *kh@ = pointer to keyhalf structure to set up
296 * @const char *kr@ = name of the keyring file
300 * Use: Initialize a keyhalf structure, maintaining the private or
301 * public keys. Intended to be called during initialization:
302 * exits if there's some kind of problem.
305 static void kh_init(keyhalf
*kh
, const char *kr
)
308 fwatch_init(&kh
->w
, kr
);
309 sym_create(&kh
->tab
);
313 die(EXIT_FAILURE
, "failed to load %s keyring `%s'", kh
->kind
, kr
);
316 /* --- @kh_load@ --- *
318 * Arguments: @keyhalf *kh@ = pointer to keyhalf
319 * @const char *tag@ = key tag to be loaded
320 * @int complainp@ = whether to complain about missing keys
322 * Returns: Pointer to a @kdata@ structure if successful, or null on
325 * Use: Attempts to load a key from the current key file. This
326 * function always reads data from the file: it's used when
327 * there's a cache miss from @kh_find@, and when refreshing the
328 * known keys in @kh_refresh@. The returned kdata has a
329 * reference count of exactly 1, and has no home knode.
332 static kdata
*kh_load(keyhalf
*kh
, const char *tag
, int complainp
)
343 /* --- Find the key and grab its tag --- */
345 if (key_qtag(kh
->kf
, tag
, &t
, &k
, &d
)) {
347 a_warn("KEYMGMT", "%s-keyring", kh
->kind
, "%s", kh
->kr
,
348 "key-not-found", "%s", tag
, A_END
);
353 /* --- Find the key's group type and the appropriate operations --- *
355 * There are several places to look for the key type. The most obvious is
356 * the `kx-group' key attribute. But there's also the key type itself, for
357 * compatibility reasons.
360 ty
= key_getattr(kh
->kf
, k
, "kx-group");
361 if (!ty
&& strncmp(k
->type
, "tripe-", 6) == 0) ty
= k
->type
+ 6;
364 for (dh
= dhtab
; dh
->name
; dh
++)
365 if (strcmp(dh
->name
, ty
) == 0) goto founddh
;
366 a_warn("KEYMGMT", "%s-keyring", kh
->kind
,
367 "%s", kh
->kr
, "key", "%s", t
.buf
,
368 "unknown-group-type", "%s", ty
, A_END
);
373 if (kh
->load(kh
->kf
, k
, *d
, dh
, kd
, &t
, &e
)) {
374 a_warn("KEYMGMT", "%s-keyring", kh
->kind
,
375 "%s", kh
->kr
, "key", "%s", t
.buf
,
376 "*%s", e
.buf
, A_END
);
380 if (algs_get(&kd
->algs
, &e
, kh
->kf
, k
) ||
381 (kd
->k
&& algs_check(&kd
->algs
, &e
, kd
->grp
))) {
382 a_warn("KEYMGMT", "%s-keyring", kh
->kind
,
383 "%s", kh
->kr
, "key", "%s", t
.buf
,
384 "*%s", e
.buf
, A_END
);
388 kd
->tag
= xstrdup(t
.buf
);
393 IF_TRACING(T_KEYMGMT
, {
394 trace(T_KEYMGMT
, "keymgmt: loaded %s key `%s'", kh
->kind
, t
.buf
);
395 IF_TRACING(T_CRYPTO
, {
399 trace(T_CRYPTO
, "crypto: k = %s", g
->ops
->scstr(g
, kd
->k
));
400 trace(T_CRYPTO
, "crypto: K = %s", g
->ops
->gestr(g
, kd
->K
));
401 kd
->algs
.bulk
->ops
->tracealgs(kd
->algs
.bulk
);
408 if (kd
->k
) kd
->grp
->ops
->freesc(kd
->grp
, kd
->k
);
409 kd
->grp
->ops
->freege(kd
->grp
, kd
->K
);
410 kd
->grp
->ops
->freegrp(kd
->grp
);
421 /* --- @kh_find@ --- *
423 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
424 * @const char *tag@ = key to be obtained
425 * @int complainp@ = whether to complain about missing keys
427 * Returns: A pointer to the kdata, or null on error.
429 * Use: Obtains kdata, maybe from the cache. This won't update a
430 * stale cache entry, though @kh_refresh@ ought to have done
431 * that already. The returned kdata object may be shared with
432 * other users. (One of this function's responsibilities, over
433 * @kh_load@, is to set the home knode of a freshly loaded
437 static kdata
*kh_find(keyhalf
*kh
, const char *tag
, int complainp
)
443 kn
= sym_find(&kh
->tab
, tag
, -1, sizeof(knode
), &f
);
446 if (kn
->f
& KNF_BROKEN
) {
448 trace(T_KEYMGMT
, "keymgmt: key `%s' marked as broken", tag
); )
454 T( trace(T_KEYMGMT
, "keymgmt: %scache hit for key `%s'",
455 kd ?
"" : "negative ", tag
); )
458 kd
= kh_load(kh
, tag
, complainp
);
472 /* --- @kh_refresh@ --- *
474 * Arguments: @keyhalf *kh@ = pointer to the keyhalf
476 * Returns: Zero if nothing needs to be done; nonzero if peers should
477 * refresh their keys.
479 * Use: Refreshes cached keys from files.
481 * Each active knode is examined to see if a new key is
482 * available: the return value is nonzero if any new keys are.
483 * A key is considered new if its algorithms, public key, or
484 * expiry time are/is different.
486 * Stub knodes (with no kdata attached) are removed, so that a
487 * later retry can succeed if the file has been fixed. (This
488 * doesn't count as a change, since no peers should be relying
489 * on a nonexistent key.)
492 static int kh_refresh(keyhalf
*kh
)
499 if (!fwatch_update(&kh
->w
, kh
->kr
) || kh_reopen(kh
))
502 T( trace(T_KEYMGMT
, "keymgmt: rescan %s keyring `%s'", kh
->kind
, kh
->kr
); )
503 for (sym_mkiter(&i
, &kh
->tab
); (kn
= sym_next(&i
)) != 0; ) {
505 T( trace(T_KEYMGMT
, "keymgmt: discard stub entry for key `%s'",
507 sym_remove(&kh
->tab
, kn
);
510 if ((kd
= kh_load(kh
, SYM_NAME(kn
), 1)) == 0) {
511 if (!(kn
->f
& KNF_BROKEN
)) {
512 T( trace(T_KEYMGMT
, "keymgmt: failed to load new key `%s': "
513 "marking it as broken",
519 kn
->f
&= ~KNF_BROKEN
;
520 if (kd
->t_exp
== kn
->kd
->t_exp
&&
521 km_samealgsp(kd
, kn
->kd
) &&
522 kd
->grp
->ops
->eq(kd
->grp
, kd
->K
, kn
->kd
->K
)) {
523 T( trace(T_KEYMGMT
, "keymgmt: key `%s' unchanged", SYM_NAME(kn
)); )
526 T( trace(T_KEYMGMT
, "keymgmt: loaded new version of key `%s'",
537 /*----- Main code ---------------------------------------------------------*/
539 const char *tag_priv
;
542 /* --- @km_init@ --- *
544 * Arguments: @const char *privkr@ = private keyring file
545 * @const char *pubkr@ = public keyring file
546 * @const char *ptag@ = default private-key tag
550 * Use: Initializes the key-management machinery, loading the
551 * keyrings and so on.
554 void km_init(const char *privkr
, const char *pubkr
, const char *ptag
)
556 const gchash
*const *hh
;
558 for (hh
= ghashtab
; *hh
; hh
++) {
559 if ((*hh
)->hashsz
> MAXHASHSZ
) {
560 die(EXIT_FAILURE
, "INTERNAL ERROR: %s hash length %lu > MAXHASHSZ %d",
561 (*hh
)->name
, (unsigned long)(*hh
)->hashsz
, MAXHASHSZ
);
565 kh_init(&priv
, privkr
);
566 kh_init(&pub
, pubkr
);
569 if ((master
= km_findpriv(ptag
)) == 0) exit(EXIT_FAILURE
);
572 /* --- @km_reload@ --- *
576 * Returns: Zero if OK, nonzero to force reloading of keys.
578 * Use: Checks the keyrings to see if they need reloading.
586 if (kh_refresh(&priv
)) {
595 if (kh_refresh(&pub
))
600 /* --- @km_findpub@, @km_findpriv@ --- *
602 * Arguments: @const char *tag@ = key tag to load
604 * Returns: Pointer to the kdata object if successful, or null on error.
606 * Use: Fetches a public or private key from the keyring.
609 kdata
*km_findpub(const char *tag
) { return (kh_find(&pub
, tag
, 1)); }
611 kdata
*km_findpriv(const char *tag
)
615 /* Unpleasantness for the sake of compatibility. */
616 if (!tag
&& (kd
= kh_find(&priv
, "tripe", 0)) != 0) return (kd
);
617 else return (kh_find(&priv
, tag ? tag
: "tripe-dh", 1));
620 /* --- @km_tag@ --- *
622 * Arguments: @kdata *kd@ - pointer to the kdata object
624 * Returns: A pointer to the short tag by which the kdata was loaded.
627 const char *km_tag(kdata
*kd
) { return (SYM_NAME(kd
->kn
)); }
629 /* --- @km_ref@ --- *
631 * Arguments: @kdata *kd@ = pointer to the kdata object
635 * Use: Claim a new reference to a kdata object.
638 void km_ref(kdata
*kd
) { kd
->ref
++; }
640 /* --- @km_unref@ --- *
642 * Arguments: @kdata *kd@ = pointer to the kdata object
646 * Use: Releases a reference to a kdata object.
649 void km_unref(kdata
*kd
)
651 if (--kd
->ref
) return;
652 if (kd
->k
) kd
->grp
->ops
->freesc(kd
->grp
, kd
->k
);
653 kd
->grp
->ops
->freege(kd
->grp
, kd
->K
);
654 kd
->grp
->ops
->freegrp(kd
->grp
);
659 /*----- That's all, folks -------------------------------------------------*/