3 * $Id: keyexch.c,v 1.1 2001/02/03 20:26:37 mdw Exp $
5 * Key exchange protocol
7 * (c) 2001 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Trivial IP Encryption (TrIPE).
14 * TrIPE is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * TrIPE is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with TrIPE; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.1 2001/02/03 20:26:37 mdw
37 /*----- Header files ------------------------------------------------------*/
41 /*----- Tunable parameters ------------------------------------------------*/
43 #define T_VALID MIN(2)
44 #define T_QUIET SEC(5)
45 #define T_RETRY SEC(10)
46 #define T_NEWCHAL SEC(5)
48 /*----- Handy macros ------------------------------------------------------*/
50 #define FREECTX(kx) do { \
51 keyexch *_kkx = (kx); \
52 if (_kkx->f & KXF_INIT) { \
53 mp_drop(_kkx->my_x); mp_drop(_kkx->my_gx); mp_drop(_kkx->my_gxy); \
54 mp_drop(_kkx->your_gx); mp_drop(_kkx->your_gxy); \
58 #define INITCTX(kx, now) do { \
59 keyexch *_kx = (kx); \
60 time_t _now = (now); \
62 kx->my_x = kx->my_gx = kx->my_gxy = 0; \
63 kx->your_gx = kx->your_gxy = 0; \
64 kx->t_valid = _now + T_VALID; \
65 kx->t_qchal = kx->t_qresp = 0; \
67 kx->f = (kx->f | KXF_INIT) & ~(KXF_MYH | KXF_YOURH | \
68 KXF_REPLY | KXF_DONE); \
71 #define NEWCHAL(kx) do { \
72 kx->f &= ~(KXF_YOURH | KXF_MYH); \
73 mp_drop(kx->your_gx); kx->your_gx = 0; \
74 mp_drop(kx->your_gxy); kx->your_gxy = 0; \
77 #define ISVALID(kx, now) ((kx)->t_valid > (now))
78 #define ISQ_CHAL(kx, now) ((kx)->t_qchal > (now))
79 #define ISQ_RESP(kx, now) ((kx)->t_qresp > (now))
80 #define ISNEWCHAL(kx, now) ((kx)->t_newchal > (now))
82 /*----- Main code ---------------------------------------------------------*/
86 * Arguments: @rmd160_ctx *r@ = pointer to hash context
87 * @mp *m@ = pointer to multiprecision integer
91 * Use: Adds the hash of a multiprecision integer to the context.
95 static void hashmp(rmd160_ctx
*r
, mp
*m
)
98 buf_init(&b
, buf_o
, sizeof(buf_o
));
101 rmd160_hash(r
, BBASE(&b
), BLEN(&b
));
106 * Arguments: @struct timeval *tv@ = the current time
107 * @void *v@ = pointer to key exchange context
111 * Use: Acts when the key exchange timer goes off.
114 static void timer(struct timeval
*tv
, void *v
)
118 T( trace(T_KEYEXCH
, "keyexch: timer has popped"); )
122 /* --- @settimer@ --- *
124 * Arguments: @keyexch *kx@ = pointer to key exchange context
125 * @time_t t@ = when to set the timer for
129 * Use: Sets the timer for the next key exchange attempt.
132 static void settimer(keyexch
*kx
, time_t t
)
135 if (kx
->f
& KXF_TIMER
)
139 sel_addtimer(&sel
, &kx
->t
, &tv
, timer
, kx
);
143 /* --- @update@ --- *
145 * Arguments: @keyexch *kx@ = pointer to key exchange context
149 * Use: Updates the information in the key exchange context. Call
150 * this after new information has arrived. Expects that the
151 * context is actually valid. Doesn't send any packets.
152 * Assumes that everything in the context is known to be
156 static void update(keyexch
*kx
)
159 octet h
[RMD160_HASHSZ
];
163 /* --- Give up if there's nothing more to do --- */
165 if (kx
->f
& KXF_DONE
)
168 /* --- If we've just started, generate a new challenge --- */
171 T( trace(T_KEYEXCH
, "keyexch: generating new challenge"); )
172 kx
->my_x
= mprand_range(MP_NEWSEC
, kx
->kpub
.dp
.q
, &rand_global
, 0);
173 kx
->my_gx
= mpmont_exp(&mg
, MP_NEW
, kx
->kpub
.dp
.g
, kx
->my_x
);
174 kx
->my_gxy
= mpmont_exp(&mg
, MP_NEW
, kx
->kpub
.y
, kx
->my_x
);
175 IF_TRACING(T_KEYEXCH
, IF_TRACING(T_CRYPTO
, {
176 trace(T_CRYPTO
, "crypto: secret = %s", mpstr(kx
->my_x
));
177 trace(T_CRYPTO
, "crypto: public value = %s", mpstr(kx
->my_gx
));
178 trace(T_CRYPTO
, "crypto: expected reply = %s", mpstr(kx
->my_gxy
));
182 /* --- If I don't have your challenge, I can't do anything more --- */
187 /* --- If I've not computed my hash, I should do that --- */
189 if (!(kx
->f
& KXF_MYH
)) {
190 T( trace(T_KEYEXCH
, "keyexch: computing my hash"); )
192 hashmp(&r
, kx
->my_gx
);
193 hashmp(&r
, kx
->your_gx
);
194 hashmp(&r
, kx
->my_gxy
);
195 rmd160_done(&r
, kx
->my_h
);
196 IF_TRACING(T_KEYEXCH
, trace_block(T_CRYPTO
, "crypto: my hash",
197 kx
->my_h
, sizeof(kx
->my_h
)); )
201 /* --- If I've received a full challenge, answer it --- *
203 * If it turns out to be wrong, clear the appropriate bits of data.
206 if ((kx
->f
& KXF_YOURH
) && !kx
->your_gxy
) {
207 kx
->your_gxy
= mpmont_exp(&mg
, MP_NEW
, kx
->your_gx
, kpriv
.x
);
209 hashmp(&r
, kx
->your_gx
);
210 hashmp(&r
, kx
->my_gx
);
211 hashmp(&r
, kx
->your_gxy
);
213 IF_TRACING(T_KEYEXCH
, trace_block(T_CRYPTO
, "crypto: computed hash",
215 if (memcmp(h
, kx
->your_h
, sizeof(h
)) != 0) {
216 IF_TRACING(T_KEYEXCH
, {
217 trace_block(T_CRYPTO
, "crypto: expected hash",
218 kx
->your_h
, sizeof(kx
->your_h
));
219 trace(T_KEYEXCH
, "keyexch: hashes don't match: botched");
226 /* --- If I have a good reply, compute a shared key --- */
228 if ((kx
->f
& KXF_YOURH
) && (kx
->f
& KXF_REPLY
)) {
229 k_shared
= mpmont_exp(&mg
, MP_NEW
, kx
->your_gx
, kx
->my_x
);
230 IF_TRACING(T_KEYEXCH
, {
231 trace(T_KEYEXCH
, "keyexch: computed shared key");
232 trace(T_CRYPTO
, "crypto: shared key = %s", mpstr(k_shared
));
234 buf_init(&b
, buf_o
, sizeof(buf_o
));
235 buf_putmp(&b
, k_shared
); assert(BOK(&b
));
236 settimer(kx
, ks_gen(kx
->ks
, BBASE(&b
), BLEN(&b
)));
243 /* --- @resend_chal@, @resent_resp@ --- *
245 * Arguments: @keyexch *kx@ = pointer to key exchange context
246 * @time_t now@ = the time right now
250 * Use: Sends packets to the remote host, according to the various
251 * timers and information available.
254 void resend_chal(keyexch
*kx
, time_t now
)
258 if (kx
->f
& KXF_DONE
)
260 if (ISQ_CHAL(kx
, now
)) {
261 T( trace(T_KEYEXCH
, "keyexch: not sending a new challenge yet"); )
265 T( trace(T_KEYEXCH
, "keyexch: sending prechallenge"); )
266 b
= p_txstart(kx
->p
, MSG_PRECHALLENGE
);
268 T( trace(T_KEYEXCH
, "keyexch: sending challenge"); )
269 b
= p_txstart(kx
->p
, MSG_CHALLENGE
);
270 buf_put(b
, kx
->my_h
, sizeof(kx
->my_h
));
272 buf_putmp(b
, kx
->my_gx
);
274 kx
->t_qchal
= now
+ T_QUIET
;
275 settimer(kx
, now
+ T_RETRY
);
278 void resend_resp(keyexch
*kx
, time_t now
)
284 if (ISQ_RESP(kx
, now
)) {
285 T( trace(T_KEYEXCH
, "keyexch: not sending a new response yet"); )
288 T( trace(T_KEYEXCH
, "keyexch: sending response"); )
289 b
= p_txstart(kx
->p
, MSG_RESPONSE
);
290 buf_putmp(b
, kx
->your_gxy
);
292 kx
->t_qresp
= now
+ T_QUIET
;
295 /* --- @kx_start@ --- *
297 * Arguments: @keyexch *kx@ = pointer to key exchange context
301 * Use: Stimulates a key exchange. If a key exchage is in progress,
302 * a new challenge is sent (unless the quiet timer forbids
303 * this); if no exchange is in progress, one is commenced.
306 void kx_start(keyexch
*kx
)
308 time_t now
= time(0);
310 if (!ISVALID(kx
, now
))
313 resend_chal(kx
, now
);
316 /* --- @dochallenge@ --- *
318 * Arguments: @keyexch *kx@ = pointer to key exchange context
319 * @time_t now@ = the current time
320 * @mp *m@ = new challenge received
321 * @const octet *h@ = challenge hash (if any)
325 * Use: Common code for handling challenge messages. The caller
326 * should have successfullly unpacked the challenge structure.
329 static void dochallenge(keyexch
*kx
, time_t now
, mp
*m
, const octet
*h
)
334 #define f_new (f_newchal | f_newhash)
336 #define f_good (f_new | f_match)
339 #define f_change (f_new | f_reset)
341 /* --- Restart the process if necessary --- */
343 if (!ISVALID(kx
, now
))
345 if (!ISNEWCHAL(kx
, now
))
348 /* --- Sort out what to actually do --- */
354 } else if (mp_eq(kx
->your_gx
, m
)) {
355 if (!h
|| memcmp(h
, kx
->your_h
, sizeof(kx
->your_h
)) == 0)
357 else if (!(kx
->f
& KXF_YOURH
))
361 /* --- Update the values in the context --- */
365 else if (!(f
& f_ignore
)) {
369 if (f
& (f_newchal
| f_reset
))
370 kx
->your_gx
= MP_COPY(m
);
371 if (f
& (f_newhash
| f_reset
)) {
372 memcpy(kx
->your_h
, h
, sizeof(kx
->your_h
));
379 a_warn("%s nonmatching challenge from `%s'",
380 (f
& f_ignore
) ?
"rejecting" : "accepting", p_name(kx
->p
));
382 T( trace(T_KEYEXCH
, "keyexch: good challenge (%s, %s) from `%s'",
383 (f
& f_newchal
) ?
"new gxy" : "match gxy",
384 (f
& f_newhash
) ?
"new hash" : "match hash", p_name(kx
->p
)); )
390 resend_chal(kx
, now
);
400 /* --- @kx_prechallenge@, @kx_challenge@ --- *
402 * Arguments: @keyexch *kx@ = pointer to key exhange context
403 * @buf *b@ = pointer to buffer containing the packet
407 * Use: Handle prechallenges and challenges.
410 void kx_prechallenge(keyexch
*kx
, buf
*b
)
412 time_t now
= time(0);
415 if ((m
= buf_getmp(b
, MP_NEW
)) == 0 || BLEFT(b
)) {
416 a_warn("malformed prechallenge from `%s'", p_name(kx
->p
));
419 dochallenge(kx
, now
, m
, 0);
424 void kx_challenge(keyexch
*kx
, buf
*b
)
426 time_t now
= time(0);
430 if (buf_ensure(b
, RMD160_HASHSZ
) ||
431 (h
= BCUR(b
), BSTEP(b
, RMD160_HASHSZ
),
432 (m
= buf_getmp(b
, MP_NEW
)) == 0 || BLEFT(b
))) {
433 a_warn("malformed challenge from `%s'", p_name(kx
->p
));
436 dochallenge(kx
, now
, m
, h
);
437 resend_resp(kx
, now
);
442 /* --- @kx_response@ --- *
444 * Arguments: @keyexch *kx@ = pointer to key exchange context
445 * @buf *b@ = a buffer containing the packet to read
449 * Use: Reads a response from the buffer and handles it.
452 void kx_response(keyexch
*kx
, buf
*b
)
454 time_t now
= time(0);
457 if ((m
= buf_getmp(b
, MP_NEW
)) == 0 || BLEFT(b
)) {
458 a_warn("malformed response from `%s'", p_name(kx
->p
));
461 if (!ISVALID(kx
, now
))
463 if (!(kx
->f
& KXF_MYH
)) {
464 a_warn("premature response from `%s'", p_name(kx
->p
));
467 if (!mp_eq(m
, kx
->my_gxy
)) {
468 a_warn("incorrect response from `%s'", p_name(kx
->p
));
471 T( trace(T_KEYEXCH
, "keyexch: valid response from `%s'", p_name(kx
->p
)); )
479 /* --- @kx_free@ --- *
481 * Arguments: @keyexch *kx@ = pointer to key exchange context
485 * Use: Frees everything in a key exchange context.
488 void kx_free(keyexch
*kx
)
490 if (kx
->f
& KXF_TIMER
)
493 dh_pubfree(&kx
->kpub
);
496 /* --- @kx_newkeys@ --- *
498 * Arguments: @keyexch *kx@ = pointer to key exchange context
502 * Use: Informs the key exchange module that its keys may have
503 * changed. If fetching the new keys fails, the peer will be
504 * destroyed, we log messages and struggle along with the old
508 void kx_newkeys(keyexch
*kx
)
512 if (km_getpubkey(p_name(kx
->p
), &dp
))
514 dh_pubfree(&kx
->kpub
);
516 if (!(kx
->f
& KXF_DONE
)) {
517 T( trace(T_KEYEXCH
, "keyexch: restarting key negotiation with `%s'",
519 INITCTX(kx
, time(0));
523 /* --- @kx_init@ --- *
525 * Arguments: @keyexch *kx@ = pointer to key exchange context
526 * @peer *p@ = pointer to peer context
527 * @keyset **ks@ = pointer to keyset list
529 * Returns: Zero if OK, nonzero if it failed.
531 * Use: Initializes a key exchange module. The module currently
532 * contains no keys, and will attempt to initiate a key
536 int kx_init(keyexch
*kx
, peer
*p
, keyset
**ks
)
541 if (km_getpubkey(p_name(p
), &kx
->kpub
))
548 /*----- That's all, folks -------------------------------------------------*/