5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
23 #include "payload_internal.h"
24 #include "groups_internal.h"
26 /* Allocates new SKE object. */
28 SilcSKE silc_ske_alloc()
32 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
34 ske = silc_calloc(1, sizeof(*ske));
35 ske->status = SILC_SKE_STATUS_OK;
40 /* Free's SKE object. */
42 void silc_ske_free(SilcSKE ske)
44 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
47 /* Free start payload */
48 if (ske->start_payload)
49 silc_ske_payload_start_free(ske->start_payload);
53 silc_ske_payload_ke_free(ske->ke1_payload);
58 silc_free(ske->prop->group);
60 silc_pkcs_free(ske->prop->pkcs);
61 if (ske->prop->cipher)
62 silc_cipher_free(ske->prop->cipher);
64 silc_hash_free(ske->prop->hash);
66 silc_hmac_free(ske->prop->hmac);
69 if (ske->start_payload_copy)
70 silc_buffer_free(ske->start_payload_copy);
74 silc_mp_clear(ske->x);
78 silc_mp_clear(ske->KEY);
87 /* Starts the SILC Key Exchange protocol for initiator. The connection
88 to the remote end must be established before calling this function
89 and the connecting socket must be sent as argument. This function
90 creates the Key Exchange Start Paload which includes all our
91 configured security properties. This payload is then sent to the
92 remote end for further processing. This payload must be sent as
93 argument to the function, however, it must not be encoded
94 already, it is done by this function.
96 The packet sending is done by calling a callback function. Caller
97 must provide a routine to send the packet. */
99 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
100 SilcSocketConnection sock,
101 SilcSKEStartPayload *start_payload,
102 SilcSKESendPacketCb send_packet,
105 SilcSKEStatus status = SILC_SKE_STATUS_OK;
106 SilcBuffer payload_buf;
108 SILC_LOG_DEBUG(("Start"));
113 /* Encode the payload */
114 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
115 if (status != SILC_SKE_STATUS_OK)
118 /* Take a copy of the payload buffer for future use. It is used to
119 compute the HASH value. */
120 ske->start_payload_copy = silc_buffer_copy(payload_buf);
122 /* Send the packet. */
124 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
126 silc_buffer_free(payload_buf);
131 /* Function called after ske_initiator_start fuction. This receives
132 the remote ends Key Exchange Start payload which includes the
133 security properties selected by the responder from our payload
134 sent in the silc_ske_initiator_start function. */
136 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
137 SilcBuffer start_payload,
141 SilcSKEStatus status = SILC_SKE_STATUS_OK;
142 SilcSKEStartPayload *payload;
143 SilcSKESecurityProperties prop;
144 SilcSKEDiffieHellmanGroup group;
146 SILC_LOG_DEBUG(("Start"));
148 /* Decode the payload */
149 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
150 if (status != SILC_SKE_STATUS_OK) {
151 ske->status = status;
155 /* Take the selected security properties into use while doing
156 the key exchange. This is used only while doing the key
157 exchange. The same data is returned to upper levels by calling
158 the callback function. */
159 ske->prop = prop = silc_calloc(1, sizeof(*prop));
160 prop->flags = payload->flags;
161 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
162 if (status != SILC_SKE_STATUS_OK)
167 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
168 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
172 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
173 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
177 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
178 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
182 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
183 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
187 ske->start_payload = payload;
189 /* Return the received payload by calling the callback function. */
191 (*callback)(ske, context);
197 silc_ske_payload_start_free(payload);
202 silc_pkcs_free(prop->pkcs);
204 silc_cipher_free(prop->cipher);
206 silc_hash_free(prop->hash);
208 silc_hmac_free(prop->hmac);
212 if (status == SILC_SKE_STATUS_OK)
213 return SILC_SKE_STATUS_ERROR;
215 ske->status = status;
219 /* This function creates random number x, such that 1 < x < q and
220 computes e = g ^ x mod p and sends the result to the remote end in
221 Key Exchange Payload. */
223 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
224 SilcPublicKey public_key,
225 SilcPrivateKey private_key,
226 SilcSKESendPacketCb send_packet,
229 SilcSKEStatus status = SILC_SKE_STATUS_OK;
230 SilcBuffer payload_buf;
232 SilcSKEKEPayload *payload;
235 SILC_LOG_DEBUG(("Start"));
237 /* Create the random number x, 1 < x < q. */
238 x = silc_calloc(1, sizeof(*x));
241 silc_ske_create_rnd(ske, ske->prop->group->group_order,
242 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
244 if (status != SILC_SKE_STATUS_OK) {
247 ske->status = status;
251 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
253 /* Do the Diffie Hellman computation, e = g ^ x mod p */
255 silc_mp_powm(&e, &ske->prop->group->generator, x,
256 &ske->prop->group->group);
258 /* Encode the result to Key Exchange Payload. */
260 payload = silc_calloc(1, sizeof(*payload));
261 ske->ke1_payload = payload;
267 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
268 if (!payload->pk_data) {
273 ske->status = SILC_SKE_STATUS_OK;
276 payload->pk_len = pk_len;
278 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
280 /* Compute signature data if we are doing mutual authentication */
281 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
282 unsigned char hash[32], sign[1024];
283 uint32 hash_len, sign_len;
285 SILC_LOG_DEBUG(("We are doing mutual authentication"));
286 SILC_LOG_DEBUG(("Computing HASH_i value"));
288 /* Compute the hash value */
289 memset(hash, 0, sizeof(hash));
290 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
292 SILC_LOG_DEBUG(("Signing HASH_i value"));
294 /* Sign the hash value */
295 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
296 private_key->prv_len);
297 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
298 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
299 memcpy(payload->sign_data, sign, sign_len);
300 memset(sign, 0, sizeof(sign));
301 payload->sign_len = sign_len;
304 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
305 if (status != SILC_SKE_STATUS_OK) {
309 silc_free(payload->pk_data);
311 ske->status = status;
317 /* Send the packet. */
319 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
321 silc_buffer_free(payload_buf);
326 /* An initiator finish final callback that is called to indicate that
327 the SKE protocol may continue. */
332 } *SKEInitiatorFinish;
334 static void silc_ske_initiator_finish_final(SilcSKE ske,
335 SilcSKEStatus status,
338 SKEInitiatorFinish finish = (SKEInitiatorFinish)context;
339 SilcSKEKEPayload *payload = ske->ke2_payload;
340 unsigned char hash[32];
342 SilcPublicKey public_key = NULL;
344 /* If the caller returns PENDING status SKE library will assume that
345 the caller will re-call this callback when it is not anymore in
347 if (status == SILC_SKE_STATUS_PENDING)
350 /* If the status is an error then the public key that was verified
351 by the caller is not authentic. */
352 if (status != SILC_SKE_STATUS_OK) {
353 ske->status = status;
354 if (finish->callback)
355 finish->callback(ske, finish->context);
360 /* Decode the public key */
361 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
363 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
364 if (finish->callback)
365 finish->callback(ske, finish->context);
370 SILC_LOG_DEBUG(("Public key is authentic"));
372 if (payload->pk_data) {
373 /* Compute the hash value */
374 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
375 if (status != SILC_SKE_STATUS_OK)
378 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
379 memcpy(ske->hash, hash, hash_len);
380 ske->hash_len = hash_len;
382 SILC_LOG_DEBUG(("Verifying signature (HASH)"));
384 /* Verify signature */
385 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
387 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
388 payload->sign_len, hash, hash_len) == FALSE) {
390 SILC_LOG_DEBUG(("Signature don't match"));
392 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
396 SILC_LOG_DEBUG(("Signature is Ok"));
398 silc_pkcs_public_key_free(public_key);
399 memset(hash, 'F', hash_len);
402 ske->status = SILC_SKE_STATUS_OK;
404 /* Call the callback. The caller may now continue the SKE protocol. */
405 if (finish->callback)
406 finish->callback(ske, finish->context);
412 memset(hash, 'F', sizeof(hash));
413 silc_ske_payload_ke_free(payload);
414 ske->ke2_payload = NULL;
416 silc_mp_clear(ske->KEY);
421 silc_pkcs_public_key_free(public_key);
424 memset(ske->hash, 'F', hash_len);
425 silc_free(ske->hash);
429 if (status == SILC_SKE_STATUS_OK)
430 ske->status = SILC_SKE_STATUS_ERROR;
432 ske->status = status;
434 /* Call the callback. */
435 if (finish->callback)
436 finish->callback(ske, finish->context);
440 /* Receives Key Exchange Payload from responder consisting responders
441 public key, f, and signature. This function verifies the public key,
442 computes the secret shared key and verifies the signature.
444 The `callback' will be called to indicate that the caller may
445 continue with the SKE protocol. The caller must not continue
446 before the SKE libary has called that callback. If this function
447 returns an error the callback will not be called. It is called
448 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
449 However, note that when the library calls the callback the ske->status
452 This calls the `verify_key' callback to verify the received public
453 key or certificate. If the `verify_key' is provided then the remote
454 must send public key and it is considered to be an error if remote
455 does not send its public key. If caller is performing a re-key with
456 SKE then the `verify_key' is usually not provided when it is not also
457 required for the remote to send its public key. */
459 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
460 SilcBuffer ke_payload,
461 SilcSKEVerifyCb verify_key,
462 void *verify_context,
466 SilcSKEStatus status = SILC_SKE_STATUS_OK;
467 SilcSKEKEPayload *payload;
469 SKEInitiatorFinish finish;
471 SILC_LOG_DEBUG(("Start"));
473 /* Decode the payload */
474 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
475 if (status != SILC_SKE_STATUS_OK) {
476 ske->status = status;
479 ske->ke2_payload = payload;
481 if (!payload->pk_data && verify_key) {
482 SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
483 "even though we require it"));
484 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
488 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
490 /* Compute the shared secret key */
491 KEY = silc_calloc(1, sizeof(*KEY));
493 silc_mp_powm(KEY, &payload->x, ske->x, &ske->prop->group->group);
496 finish = silc_calloc(1, sizeof(*finish));
497 finish->callback = callback;
498 finish->context = context;
501 SILC_LOG_DEBUG(("Verifying public key"));
503 (*verify_key)(ske, payload->pk_data, payload->pk_len,
504 payload->pk_type, verify_context,
505 silc_ske_initiator_finish_final, finish);
507 /* We will continue to the final state after the public key has
508 been verified by the caller. */
509 return SILC_SKE_STATUS_PENDING;
512 /* Continue to final state */
513 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, finish);
515 return SILC_SKE_STATUS_OK;
518 silc_ske_payload_ke_free(payload);
519 ske->ke2_payload = NULL;
521 silc_mp_clear(ske->KEY);
525 if (status == SILC_SKE_STATUS_OK)
526 return SILC_SKE_STATUS_ERROR;
528 ske->status = status;
532 /* Starts Key Exchange protocol for responder. Responder receives
533 Key Exchange Start Payload from initiator consisting of all the
534 security properties the initiator supports. This function decodes
535 the payload and parses the payload further and selects the right
536 security properties. */
538 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
539 SilcSocketConnection sock,
541 SilcBuffer start_payload,
546 SilcSKEStatus status = SILC_SKE_STATUS_OK;
547 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
549 SILC_LOG_DEBUG(("Start"));
554 /* Decode the payload */
555 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
556 if (status != SILC_SKE_STATUS_OK) {
557 ske->status = status;
561 /* Take a copy of the payload buffer for future use. It is used to
562 compute the HASH value. */
563 ske->start_payload_copy = silc_buffer_copy(start_payload);
565 /* Force the mutual authentication flag if we want to do it. */
567 SILC_LOG_DEBUG(("Force mutual authentication"));
568 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
571 /* Parse and select the security properties from the payload */
572 payload = silc_calloc(1, sizeof(*payload));
573 status = silc_ske_select_security_properties(ske, version,
574 payload, remote_payload);
575 if (status != SILC_SKE_STATUS_OK)
578 ske->start_payload = payload;
580 /* Call the callback function. */
582 (*callback)(ske, context);
588 silc_ske_payload_start_free(remote_payload);
592 if (status == SILC_SKE_STATUS_OK)
593 return SILC_SKE_STATUS_ERROR;
595 ske->status = status;
599 /* The selected security properties from the initiator payload is now
600 encoded into Key Exchange Start Payload and sent to the initiator. */
602 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
603 SilcSKEStartPayload *start_payload,
604 SilcSKESendPacketCb send_packet,
607 SilcSKEStatus status = SILC_SKE_STATUS_OK;
608 SilcBuffer payload_buf;
609 SilcSKESecurityProperties prop;
610 SilcSKEDiffieHellmanGroup group = NULL;
612 SILC_LOG_DEBUG(("Start"));
614 /* Allocate security properties from the payload. These are allocated
615 only for this negotiation and will be free'd after KE is over. */
616 ske->prop = prop = silc_calloc(1, sizeof(*prop));
617 prop->flags = start_payload->flags;
618 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
619 if (status != SILC_SKE_STATUS_OK)
624 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
625 &prop->pkcs) == FALSE) {
626 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
630 if (silc_cipher_alloc(start_payload->enc_alg_list,
631 &prop->cipher) == FALSE) {
632 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
636 if (silc_hash_alloc(start_payload->hash_alg_list,
637 &prop->hash) == FALSE) {
638 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
642 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
643 &prop->hmac) == FALSE) {
644 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
648 /* Encode the payload */
649 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
650 if (status != SILC_SKE_STATUS_OK)
653 /* Send the packet. */
655 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
657 silc_buffer_free(payload_buf);
666 silc_pkcs_free(prop->pkcs);
668 silc_cipher_free(prop->cipher);
670 silc_hash_free(prop->hash);
672 silc_hmac_free(prop->hmac);
676 if (status == SILC_SKE_STATUS_OK)
677 return SILC_SKE_STATUS_ERROR;
679 ske->status = status;
683 /* An responder phase 2 final callback that is called to indicate that
684 the SKE protocol may continue. */
689 } *SKEResponderPhaseII;
691 static void silc_ske_responder_phase2_final(SilcSKE ske,
692 SilcSKEStatus status,
695 SKEResponderPhaseII finish = (SKEResponderPhaseII)context;
696 SilcSKEKEPayload *recv_payload, *send_payload;
699 recv_payload = ske->ke1_payload;
701 /* If the caller returns PENDING status SKE library will assume that
702 the caller will re-call this callback when it is not anymore in
704 if (status == SILC_SKE_STATUS_PENDING)
707 /* If the status is an error then the public key that was verified
708 by the caller is not authentic. */
709 if (status != SILC_SKE_STATUS_OK) {
710 ske->status = status;
711 if (finish->callback)
712 finish->callback(ske, finish->context);
717 /* The public key verification was performed only if the Mutual
718 Authentication flag is set. */
719 if (ske->start_payload &&
720 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
721 SilcPublicKey public_key = NULL;
722 unsigned char hash[32];
725 /* Decode the public key */
726 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
727 recv_payload->pk_len,
729 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
730 if (finish->callback)
731 finish->callback(ske, finish->context);
736 SILC_LOG_DEBUG(("Public key is authentic"));
738 /* Compute the hash value */
739 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
740 if (status != SILC_SKE_STATUS_OK) {
741 ske->status = status;
742 if (finish->callback)
743 finish->callback(ske, finish->context);
748 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
750 /* Verify signature */
751 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
753 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
754 recv_payload->sign_len, hash, hash_len) == FALSE) {
756 SILC_LOG_DEBUG(("Signature don't match"));
758 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
759 if (finish->callback)
760 finish->callback(ske, finish->context);
765 SILC_LOG_DEBUG(("Signature is Ok"));
767 silc_pkcs_public_key_free(public_key);
768 memset(hash, 'F', hash_len);
771 /* Create the random number x, 1 < x < q. */
772 x = silc_calloc(1, sizeof(*x));
775 silc_ske_create_rnd(ske, ske->prop->group->group_order,
776 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
778 if (status != SILC_SKE_STATUS_OK) {
781 ske->status = status;
782 if (finish->callback)
783 finish->callback(ske, finish->context);
788 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
790 /* Do the Diffie Hellman computation, f = g ^ x mod p */
792 silc_mp_powm(&f, &ske->prop->group->generator, x,
793 &ske->prop->group->group);
795 /* Save the results for later processing */
796 send_payload = silc_calloc(1, sizeof(*send_payload));
799 ske->ke2_payload = send_payload;
801 /* Call the callback. The caller may now continue with the SKE protocol. */
802 ske->status = SILC_SKE_STATUS_OK;
803 if (finish->callback)
804 finish->callback(ske, finish->context);
808 /* This function receives the Key Exchange Payload from the initiator.
809 This also performs the mutual authentication if required. Then, this
810 function first generated a random number x, such that 1 < x < q
811 and computes f = g ^ x mod p. This then puts the result f to a Key
814 The `callback' will be called to indicate that the caller may
815 continue with the SKE protocol. The caller must not continue
816 before the SKE libary has called that callback. If this function
817 returns an error the callback will not be called. It is called
818 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
819 However, note that when the library calls the callback the ske->status
822 This calls the `verify_key' callback to verify the received public
823 key or certificate if the Mutual Authentication flag is set. If the
824 `verify_key' is provided then the remote must send public key and it
825 is considered to be an error if remote does not send its public key. */
827 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
828 SilcBuffer ke_payload,
829 SilcSKEVerifyCb verify_key,
830 void *verify_context,
834 SilcSKEStatus status = SILC_SKE_STATUS_OK;
835 SilcSKEKEPayload *recv_payload;
836 SKEResponderPhaseII finish;
838 SILC_LOG_DEBUG(("Start"));
840 /* Decode Key Exchange Payload */
841 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
842 if (status != SILC_SKE_STATUS_OK) {
843 ske->status = status;
847 ske->ke1_payload = recv_payload;
849 finish = silc_calloc(1, sizeof(*finish));
850 finish->callback = callback;
851 finish->context = context;
853 /* Verify the received public key and verify the signature if we are
854 doing mutual authentication. */
855 if (ske->start_payload &&
856 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
858 SILC_LOG_DEBUG(("We are doing mutual authentication"));
860 if (!recv_payload->pk_data && verify_key) {
861 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
862 "certificate), even though we require it"));
863 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
868 SILC_LOG_DEBUG(("Verifying public key"));
870 (*verify_key)(ske, recv_payload->pk_data, recv_payload->pk_len,
871 recv_payload->pk_type, verify_context,
872 silc_ske_responder_phase2_final, finish);
874 /* We will continue to the final state after the public key has
875 been verified by the caller. */
876 return SILC_SKE_STATUS_PENDING;
880 /* Continue to final state */
881 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, finish);
883 return SILC_SKE_STATUS_OK;
886 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
887 value to be signed and sent to the other end. This then encodes Key
888 Exchange Payload and sends it to the other end. */
890 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
891 SilcPublicKey public_key,
892 SilcPrivateKey private_key,
893 SilcSKEPKType pk_type,
894 SilcSKESendPacketCb send_packet,
897 SilcSKEStatus status = SILC_SKE_STATUS_OK;
898 SilcBuffer payload_buf;
900 unsigned char hash[32], sign[1024], *pk;
901 uint32 hash_len, sign_len, pk_len;
903 SILC_LOG_DEBUG(("Start"));
905 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
907 /* Compute the shared secret key */
908 KEY = silc_calloc(1, sizeof(*KEY));
910 silc_mp_powm(KEY, &ske->ke1_payload->x, ske->x,
911 &ske->prop->group->group);
914 if (public_key && private_key) {
915 SILC_LOG_DEBUG(("Getting public key"));
917 /* Get the public key */
918 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
920 status = SILC_SKE_STATUS_ERROR;
923 ske->ke2_payload->pk_data = pk;
924 ske->ke2_payload->pk_len = pk_len;
926 SILC_LOG_DEBUG(("Computing HASH value"));
928 /* Compute the hash value */
929 memset(hash, 0, sizeof(hash));
930 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
931 if (status != SILC_SKE_STATUS_OK)
934 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
935 memcpy(ske->hash, hash, hash_len);
936 ske->hash_len = hash_len;
938 SILC_LOG_DEBUG(("Signing HASH value"));
940 /* Sign the hash value */
941 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
942 private_key->prv_len);
943 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
944 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
945 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
946 memset(sign, 0, sizeof(sign));
947 ske->ke2_payload->sign_len = sign_len;
949 ske->ke2_payload->pk_type = pk_type;
951 /* Encode the Key Exchange Payload */
952 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
954 if (status != SILC_SKE_STATUS_OK)
957 /* Send the packet. */
959 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
961 silc_buffer_free(payload_buf);
966 silc_mp_clear(ske->KEY);
969 silc_ske_payload_ke_free(ske->ke2_payload);
971 if (status == SILC_SKE_STATUS_OK)
972 return SILC_SKE_STATUS_ERROR;
974 ske->status = status;
978 /* The Key Exchange protocol is ended by calling this function. This
979 must not be called until the keys are processed like the protocol
980 defines. This function is for both initiator and responder. */
982 SilcSKEStatus silc_ske_end(SilcSKE ske,
983 SilcSKESendPacketCb send_packet,
988 SILC_LOG_DEBUG(("Start"));
990 packet = silc_buffer_alloc(4);
991 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
992 silc_buffer_format(packet,
993 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
997 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
999 silc_buffer_free(packet);
1001 return SILC_SKE_STATUS_OK;
1004 /* Aborts the Key Exchange protocol. This is called if error occurs
1005 while performing the protocol. The status argument is the error
1006 status and it is sent to the remote end. */
1008 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
1009 SilcSKESendPacketCb send_packet,
1014 SILC_LOG_DEBUG(("Start"));
1016 packet = silc_buffer_alloc(4);
1017 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1018 silc_buffer_format(packet,
1019 SILC_STR_UI_INT((uint32)status),
1023 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
1025 silc_buffer_free(packet);
1027 return SILC_SKE_STATUS_OK;
1030 /* Assembles security properties to Key Exchange Start Payload to be
1031 sent to the remote end. This checks system wide (SILC system, that is)
1032 settings and chooses from those. However, if other properties
1033 should be used this function is easy to replace by another function,
1034 as, this function is called by the caller of the protocol and not
1035 by the protocol itself. */
1038 silc_ske_assemble_security_properties(SilcSKE ske,
1039 unsigned char flags,
1041 SilcSKEStartPayload **return_payload)
1043 SilcSKEStartPayload *rp;
1046 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1048 rp = silc_calloc(1, sizeof(*rp));
1053 /* Set random cookie */
1054 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1055 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1056 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1057 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1060 rp->version = strdup(version);
1061 rp->version_len = strlen(version);
1063 /* Get supported Key Exhange groups */
1064 rp->ke_grp_list = silc_ske_get_supported_groups();
1065 rp->ke_grp_len = strlen(rp->ke_grp_list);
1067 /* Get supported PKCS algorithms */
1068 rp->pkcs_alg_list = silc_pkcs_get_supported();
1069 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1071 /* Get supported encryption algorithms */
1072 rp->enc_alg_list = silc_cipher_get_supported();
1073 rp->enc_alg_len = strlen(rp->enc_alg_list);
1075 /* Get supported hash algorithms */
1076 rp->hash_alg_list = silc_hash_get_supported();
1077 rp->hash_alg_len = strlen(rp->hash_alg_list);
1079 /* Get supported HMACs */
1080 rp->hmac_alg_list = silc_hmac_get_supported();
1081 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1084 /* Get supported compression algorithms */
1085 rp->comp_alg_list = "";
1086 rp->comp_alg_len = 0;
1088 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1089 2 + rp->version_len +
1090 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1091 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1092 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1094 *return_payload = rp;
1096 return SILC_SKE_STATUS_OK;
1099 /* Selects the supported security properties from the remote end's Key
1100 Exchange Start Payload. */
1103 silc_ske_select_security_properties(SilcSKE ske,
1105 SilcSKEStartPayload *payload,
1106 SilcSKEStartPayload *remote_payload)
1108 SilcSKEStatus status;
1109 SilcSKEStartPayload *rp;
1113 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1115 rp = remote_payload;
1117 /* Check version string */
1118 status = silc_ske_check_version(ske, rp->version, rp->version_len);
1119 if (status != SILC_SKE_STATUS_OK) {
1120 ske->status = status;
1124 /* Flags are returned unchanged. */
1125 payload->flags = rp->flags;
1128 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1129 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1130 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1132 /* Put our version to our reply */
1133 payload->version = strdup(version);
1134 payload->version_len = strlen(version);
1136 /* Get supported Key Exchange groups */
1137 cp = rp->ke_grp_list;
1138 if (cp && strchr(cp, ',')) {
1142 len = strcspn(cp, ",");
1143 item = silc_calloc(len + 1, sizeof(char));
1144 memcpy(item, cp, len);
1146 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1148 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1149 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1151 payload->ke_grp_len = len;
1152 payload->ke_grp_list = item;
1157 if (strlen(cp) == 0)
1166 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1167 SILC_LOG_DEBUG(("Could not find supported KE group"));
1169 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1173 if (!rp->ke_grp_len) {
1174 SILC_LOG_DEBUG(("KE group not defined in payload"));
1176 return SILC_SKE_STATUS_BAD_PAYLOAD;
1179 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1180 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1182 payload->ke_grp_len = rp->ke_grp_len;
1183 payload->ke_grp_list = strdup(rp->ke_grp_list);
1186 /* Get supported PKCS algorithms */
1187 cp = rp->pkcs_alg_list;
1188 if (cp && strchr(cp, ',')) {
1192 len = strcspn(cp, ",");
1193 item = silc_calloc(len + 1, sizeof(char));
1194 memcpy(item, cp, len);
1196 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1198 if (silc_pkcs_is_supported(item) == TRUE) {
1199 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1201 payload->pkcs_alg_len = len;
1202 payload->pkcs_alg_list = item;
1207 if (strlen(cp) == 0)
1216 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1217 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1218 silc_free(payload->ke_grp_list);
1220 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1224 if (!rp->pkcs_alg_len) {
1225 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1226 silc_free(payload->ke_grp_list);
1228 return SILC_SKE_STATUS_BAD_PAYLOAD;
1231 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1232 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1234 payload->pkcs_alg_len = rp->pkcs_alg_len;
1235 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1238 /* Get supported encryption algorithms */
1239 cp = rp->enc_alg_list;
1240 if (cp && strchr(cp, ',')) {
1244 len = strcspn(cp, ",");
1245 item = silc_calloc(len + 1, sizeof(char));
1246 memcpy(item, cp, len);
1248 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1250 if (silc_cipher_is_supported(item) == TRUE) {
1251 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1253 payload->enc_alg_len = len;
1254 payload->enc_alg_list = item;
1259 if (strlen(cp) == 0)
1268 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1269 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1270 silc_free(payload->ke_grp_list);
1271 silc_free(payload->pkcs_alg_list);
1273 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1277 if (!rp->enc_alg_len) {
1278 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1279 silc_free(payload->ke_grp_list);
1280 silc_free(payload->pkcs_alg_list);
1282 return SILC_SKE_STATUS_BAD_PAYLOAD;
1285 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1288 payload->enc_alg_len = rp->enc_alg_len;
1289 payload->enc_alg_list = strdup(rp->enc_alg_list);
1292 /* Get supported hash algorithms */
1293 cp = rp->hash_alg_list;
1294 if (cp && strchr(cp, ',')) {
1298 len = strcspn(cp, ",");
1299 item = silc_calloc(len + 1, sizeof(char));
1300 memcpy(item, cp, len);
1302 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1304 if (silc_hash_is_supported(item) == TRUE) {
1305 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1307 payload->hash_alg_len = len;
1308 payload->hash_alg_list = item;
1313 if (strlen(cp) == 0)
1322 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1323 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1324 silc_free(payload->ke_grp_list);
1325 silc_free(payload->pkcs_alg_list);
1326 silc_free(payload->enc_alg_list);
1328 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1332 if (!rp->hash_alg_len) {
1333 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1334 silc_free(payload->ke_grp_list);
1335 silc_free(payload->pkcs_alg_list);
1336 silc_free(payload->enc_alg_list);
1338 return SILC_SKE_STATUS_BAD_PAYLOAD;
1341 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1342 rp->hash_alg_list));
1344 payload->hash_alg_len = rp->hash_alg_len;
1345 payload->hash_alg_list = strdup(rp->hash_alg_list);
1348 /* Get supported HMACs */
1349 cp = rp->hmac_alg_list;
1350 if (cp && strchr(cp, ',')) {
1354 len = strcspn(cp, ",");
1355 item = silc_calloc(len + 1, sizeof(char));
1356 memcpy(item, cp, len);
1358 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1360 if (silc_hmac_is_supported(item) == TRUE) {
1361 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1363 payload->hmac_alg_len = len;
1364 payload->hmac_alg_list = item;
1369 if (strlen(cp) == 0)
1378 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1379 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1380 silc_free(payload->ke_grp_list);
1381 silc_free(payload->pkcs_alg_list);
1382 silc_free(payload->enc_alg_list);
1383 silc_free(payload->hash_alg_list);
1385 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1389 if (!rp->hmac_alg_len) {
1390 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1391 silc_free(payload->ke_grp_list);
1392 silc_free(payload->pkcs_alg_list);
1393 silc_free(payload->enc_alg_list);
1394 silc_free(payload->hash_alg_list);
1396 return SILC_SKE_STATUS_BAD_PAYLOAD;
1399 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1400 rp->hmac_alg_list));
1402 payload->hmac_alg_len = rp->hmac_alg_len;
1403 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1407 /* Get supported compression algorithms */
1408 cp = rp->hash_alg_list;
1409 if (cp && strchr(cp, ',')) {
1413 len = strcspn(cp, ",");
1414 item = silc_calloc(len + 1, sizeof(char));
1415 memcpy(item, cp, len);
1417 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1419 if (silc_hash_is_supported(item) == TRUE) {
1420 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1422 payload->hash_alg_len = len;
1423 payload->hash_alg_list = item;
1428 if (strlen(cp) == 0)
1437 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1438 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1439 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1440 silc_free(payload->ke_grp_list);
1441 silc_free(payload->pkcs_alg_list);
1442 silc_free(payload->enc_alg_list);
1451 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1452 2 + payload->version_len +
1453 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1454 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1455 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1457 return SILC_SKE_STATUS_OK;
1460 /* Creates random number such that 1 < rnd < n and at most length
1461 of len bits. The rnd sent as argument must be initialized. */
1463 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1467 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1468 unsigned char *string;
1470 SILC_LOG_DEBUG(("Creating random number"));
1472 /* Get the random number as string */
1473 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1475 return SILC_SKE_STATUS_ERROR;
1477 /* Decode the string into a MP integer */
1478 silc_mp_bin2mp(string, (len / 8), rnd);
1479 silc_mp_mod_2exp(rnd, rnd, len);
1482 if (silc_mp_cmp_ui(rnd, 1) < 0)
1483 status = SILC_SKE_STATUS_ERROR;
1485 if (silc_mp_cmp(rnd, &n) >= 0)
1486 status = SILC_SKE_STATUS_ERROR;
1488 memset(string, 'F', (len / 8));
1494 /* Creates a hash value HASH as defined in the SKE protocol. If the
1495 `initiator' is TRUE then this function is used to create the HASH_i
1496 hash value defined in the protocol. If it is FALSE then this is used
1497 to create the HASH value defined by the protocol. */
1499 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1500 unsigned char *return_hash,
1501 uint32 *return_hash_len,
1504 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1506 unsigned char *e, *f, *KEY;
1507 uint32 e_len, f_len, KEY_len;
1510 SILC_LOG_DEBUG(("Start"));
1512 if (initiator == FALSE) {
1513 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1514 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1515 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1517 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1518 ske->pk_len + e_len + f_len + KEY_len);
1519 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1521 /* Format the buffer used to compute the hash value */
1523 silc_buffer_format(buf,
1524 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1525 ske->start_payload_copy->len),
1526 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1527 SILC_STR_UI_XNSTRING(e, e_len),
1528 SILC_STR_UI_XNSTRING(f, f_len),
1529 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1532 silc_buffer_free(buf);
1533 memset(e, 0, e_len);
1534 memset(f, 0, f_len);
1535 memset(KEY, 0, KEY_len);
1539 return SILC_SKE_STATUS_ERROR;
1542 memset(e, 0, e_len);
1543 memset(f, 0, f_len);
1544 memset(KEY, 0, KEY_len);
1549 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1551 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1552 ske->pk_len + e_len);
1553 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1555 /* Format the buffer used to compute the hash value */
1557 silc_buffer_format(buf,
1558 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1559 ske->start_payload_copy->len),
1560 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1561 SILC_STR_UI_XNSTRING(e, e_len),
1564 silc_buffer_free(buf);
1565 memset(e, 0, e_len);
1567 return SILC_SKE_STATUS_ERROR;
1570 memset(e, 0, e_len);
1575 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1576 *return_hash_len = ske->prop->hash->hash->hash_len;
1578 if (initiator == FALSE) {
1579 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1581 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1584 silc_buffer_free(buf);
1589 /* Processes the provided key material `data' as the SILC protocol
1590 specification specifies. */
1593 silc_ske_process_key_material_data(unsigned char *data,
1596 uint32 req_enc_key_len,
1597 uint32 req_hmac_key_len,
1599 SilcSKEKeyMaterial *key)
1602 unsigned char hashd[32];
1603 uint32 hash_len = req_hmac_key_len;
1604 uint32 enc_key_len = req_enc_key_len / 8;
1606 SILC_LOG_DEBUG(("Start"));
1608 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1609 return SILC_SKE_STATUS_ERROR;
1611 buf = silc_buffer_alloc(1 + data_len);
1612 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1613 silc_buffer_format(buf,
1614 SILC_STR_UI_CHAR(0),
1615 SILC_STR_UI_XNSTRING(data, data_len),
1619 memset(hashd, 0, sizeof(hashd));
1621 silc_hash_make(hash, buf->data, buf->len, hashd);
1622 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1623 memcpy(key->send_iv, hashd, req_iv_len);
1624 memset(hashd, 0, sizeof(hashd));
1626 silc_hash_make(hash, buf->data, buf->len, hashd);
1627 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1628 memcpy(key->receive_iv, hashd, req_iv_len);
1629 key->iv_len = req_iv_len;
1631 /* Take the encryption keys. If requested key size is more than
1632 the size of hash length we will distribute more key material
1633 as protocol defines. */
1635 if (enc_key_len > hash_len) {
1637 unsigned char k1[32], k2[32], k3[32];
1638 unsigned char *dtmp;
1641 if (enc_key_len > (3 * hash_len))
1642 return SILC_SKE_STATUS_ERROR;
1644 /* Take first round */
1645 memset(k1, 0, sizeof(k1));
1646 silc_hash_make(hash, buf->data, buf->len, k1);
1648 /* Take second round */
1649 dist = silc_buffer_alloc(data_len + hash_len);
1650 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1651 silc_buffer_format(dist,
1652 SILC_STR_UI_XNSTRING(data, data_len),
1653 SILC_STR_UI_XNSTRING(k1, hash_len),
1655 memset(k2, 0, sizeof(k2));
1656 silc_hash_make(hash, dist->data, dist->len, k2);
1658 /* Take third round */
1659 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1660 silc_buffer_pull_tail(dist, hash_len);
1661 silc_buffer_pull(dist, data_len + hash_len);
1662 silc_buffer_format(dist,
1663 SILC_STR_UI_XNSTRING(k2, hash_len),
1665 silc_buffer_push(dist, data_len + hash_len);
1666 memset(k3, 0, sizeof(k3));
1667 silc_hash_make(hash, dist->data, dist->len, k3);
1669 /* Then, save the keys */
1670 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1671 memcpy(dtmp, k1, hash_len);
1672 memcpy(dtmp + hash_len, k2, hash_len);
1673 memcpy(dtmp + hash_len, k3, hash_len);
1675 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1676 memcpy(key->send_enc_key, dtmp, enc_key_len);
1677 key->enc_key_len = req_enc_key_len;
1679 memset(dtmp, 0, (3 * hash_len));
1680 memset(k1, 0, sizeof(k1));
1681 memset(k2, 0, sizeof(k2));
1682 memset(k3, 0, sizeof(k3));
1684 silc_buffer_free(dist);
1686 /* Take normal hash as key */
1687 memset(hashd, 0, sizeof(hashd));
1688 silc_hash_make(hash, buf->data, buf->len, hashd);
1689 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1690 memcpy(key->send_enc_key, hashd, enc_key_len);
1691 key->enc_key_len = req_enc_key_len;
1695 if (enc_key_len > hash_len) {
1697 unsigned char k1[32], k2[32], k3[32];
1698 unsigned char *dtmp;
1701 if (enc_key_len > (3 * hash_len))
1702 return SILC_SKE_STATUS_ERROR;
1704 /* Take first round */
1705 memset(k1, 0, sizeof(k1));
1706 silc_hash_make(hash, buf->data, buf->len, k1);
1708 /* Take second round */
1709 dist = silc_buffer_alloc(data_len + hash_len);
1710 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1711 silc_buffer_format(dist,
1712 SILC_STR_UI_XNSTRING(data, data_len),
1713 SILC_STR_UI_XNSTRING(k1, hash_len),
1715 memset(k2, 0, sizeof(k2));
1716 silc_hash_make(hash, dist->data, dist->len, k2);
1718 /* Take third round */
1719 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1720 silc_buffer_pull_tail(dist, hash_len);
1721 silc_buffer_pull(dist, data_len + hash_len);
1722 silc_buffer_format(dist,
1723 SILC_STR_UI_XNSTRING(k2, hash_len),
1725 silc_buffer_push(dist, data_len + hash_len);
1726 memset(k3, 0, sizeof(k3));
1727 silc_hash_make(hash, dist->data, dist->len, k3);
1729 /* Then, save the keys */
1730 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1731 memcpy(dtmp, k1, hash_len);
1732 memcpy(dtmp + hash_len, k2, hash_len);
1733 memcpy(dtmp + hash_len, k3, hash_len);
1735 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1736 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1737 key->enc_key_len = req_enc_key_len;
1739 memset(dtmp, 0, (3 * hash_len));
1740 memset(k1, 0, sizeof(k1));
1741 memset(k2, 0, sizeof(k2));
1742 memset(k3, 0, sizeof(k3));
1744 silc_buffer_free(dist);
1746 /* Take normal hash as key */
1747 memset(hashd, 0, sizeof(hashd));
1748 silc_hash_make(hash, buf->data, buf->len, hashd);
1749 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1750 memcpy(key->receive_enc_key, hashd, enc_key_len);
1751 key->enc_key_len = req_enc_key_len;
1755 memset(hashd, 0, sizeof(hashd));
1757 silc_hash_make(hash, buf->data, buf->len, hashd);
1758 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1759 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1760 key->hmac_key_len = req_hmac_key_len;
1762 silc_buffer_free(buf);
1764 return SILC_SKE_STATUS_OK;
1767 /* Processes negotiated key material as protocol specifies. This returns
1768 the actual keys to be used in the SILC. */
1770 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1772 uint32 req_enc_key_len,
1773 uint32 req_hmac_key_len,
1774 SilcSKEKeyMaterial *key)
1776 SilcSKEStatus status;
1778 unsigned char *tmpbuf;
1781 /* Encode KEY to binary data */
1782 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1784 buf = silc_buffer_alloc(klen + ske->hash_len);
1785 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1786 silc_buffer_format(buf,
1787 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1788 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1791 /* Process the key material */
1792 status = silc_ske_process_key_material_data(buf->data, buf->len,
1793 req_iv_len, req_enc_key_len,
1795 ske->prop->hash, key);
1797 memset(tmpbuf, 0, klen);
1799 silc_buffer_free(buf);
1804 /* Free key material structure */
1806 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1812 silc_free(key->send_iv);
1813 if (key->receive_iv)
1814 silc_free(key->receive_iv);
1815 if (key->send_enc_key) {
1816 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1817 silc_free(key->send_enc_key);
1819 if (key->receive_enc_key) {
1820 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1821 silc_free(key->receive_enc_key);
1823 if (key->hmac_key) {
1824 memset(key->hmac_key, 0, key->hmac_key_len);
1825 silc_free(key->hmac_key);