5 Author: Pekka Riikonen <priikone@silcnet.org>
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"
24 #include "groups_internal.h"
26 /* Structure to hold all SKE callbacks. */
27 struct SilcSKECallbacksStruct {
28 SilcSKESendPacketCb send_packet;
29 SilcSKECb payload_receive;
30 SilcSKEVerifyCb verify_key;
31 SilcSKECb proto_continue;
32 SilcSKECheckVersion check_version;
36 /* Allocates new SKE object. */
38 SilcSKE silc_ske_alloc()
42 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
44 ske = silc_calloc(1, sizeof(*ske));
45 ske->status = SILC_SKE_STATUS_OK;
51 /* Free's SKE object. */
53 void silc_ske_free(SilcSKE ske)
57 SILC_LOG_DEBUG(("Key Exchange set to FREED status"));
58 ske->status = SILC_SKE_STATUS_FREED;
62 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
65 /* Free start payload */
66 if (ske->start_payload)
67 silc_ske_payload_start_free(ske->start_payload);
71 silc_ske_payload_ke_free(ske->ke1_payload);
76 silc_free(ske->prop->group);
78 silc_pkcs_free(ske->prop->pkcs);
79 if (ske->prop->cipher)
80 silc_cipher_free(ske->prop->cipher);
82 silc_hash_free(ske->prop->hash);
84 silc_hmac_free(ske->prop->hmac);
87 if (ske->start_payload_copy)
88 silc_buffer_free(ske->start_payload_copy);
90 silc_mp_uninit(ske->x);
94 silc_mp_uninit(ske->KEY);
103 /* Sets the callback functions for the SKE session.
105 The `send_packet' callback is a function that sends the packet to
106 network. The SKE library will call it at any time packet needs to
107 be sent to the remote host.
109 The `payload_receive' callback is called when the remote host's Key
110 Exchange Start Payload has been processed. The payload is saved
111 to ske->start_payload if the application would need it. The application
112 must also provide the payload to the next state of the SKE.
114 The `verify_key' callback is called to verify the received public key
115 or certificate. The verification process is most likely asynchronous.
116 That is why the application must call the completion callback when the
117 verification process has been completed. The library then calls the user
118 callback (`proto_continue'), if it is provided to indicate that the SKE
119 protocol may continue.
121 The `proto_continue' callback is called to indicate that it is
122 safe to continue the execution of the SKE protocol after executing
123 an asynchronous operation, such as calling the `verify_key' callback
124 function, which is asynchronous. The application should check the
125 ske->status in this function to check whether it is Ok to continue
126 the execution of the protocol.
128 The `check_version' callback is called to verify the remote host's
129 version. The application may check its own version against the remote
130 host's version and determine whether supporting the remote host
133 The `context' is passed as argument to all of the above callback
136 void silc_ske_set_callbacks(SilcSKE ske,
137 SilcSKESendPacketCb send_packet,
138 SilcSKECb payload_receive,
139 SilcSKEVerifyCb verify_key,
140 SilcSKECb proto_continue,
141 SilcSKECheckVersion check_version,
145 silc_free(ske->callbacks);
146 ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
147 ske->callbacks->send_packet = send_packet;
148 ske->callbacks->payload_receive = payload_receive;
149 ske->callbacks->verify_key = verify_key;
150 ske->callbacks->proto_continue = proto_continue;
151 ske->callbacks->check_version = check_version;
152 ske->callbacks->context = context;
155 /* Starts the SILC Key Exchange protocol for initiator. The connection
156 to the remote end must be established before calling this function
157 and the connecting socket must be sent as argument. This function
158 creates the Key Exchange Start Payload which includes all our
159 configured security properties. This payload is then sent to the
160 remote end for further processing. This payload must be sent as
161 argument to the function, however, it must not be encoded
162 already, it is done by this function. The caller must not free
163 the `start_payload' since the SKE library will save it.
165 The packet sending is done by calling a callback function. Caller
166 must provide a routine to send the packet. */
168 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
169 SilcSocketConnection sock,
170 SilcSKEStartPayload *start_payload)
172 SilcSKEStatus status = SILC_SKE_STATUS_OK;
173 SilcBuffer payload_buf;
175 SILC_LOG_DEBUG(("Start"));
180 /* Encode the payload */
181 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
182 if (status != SILC_SKE_STATUS_OK)
185 /* Take a copy of the payload buffer for future use. It is used to
186 compute the HASH value. */
187 ske->start_payload_copy = silc_buffer_copy(payload_buf);
188 ske->start_payload = start_payload;
190 /* Send the packet. */
191 if (ske->callbacks->send_packet)
192 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
193 ske->callbacks->context);
195 silc_buffer_free(payload_buf);
200 /* Function called after ske_initiator_start fuction. This receives
201 the remote ends Key Exchange Start payload which includes the
202 security properties selected by the responder from our payload
203 sent in the silc_ske_initiator_start function. */
205 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
206 SilcBuffer start_payload)
208 SilcSKEStatus status = SILC_SKE_STATUS_OK;
209 SilcSKEStartPayload *payload;
210 SilcSKESecurityProperties prop;
211 SilcSKEDiffieHellmanGroup group;
213 SILC_LOG_DEBUG(("Start"));
215 /* Decode the payload */
216 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
217 if (status != SILC_SKE_STATUS_OK) {
218 ske->status = status;
219 silc_ske_payload_start_free(ske->start_payload);
223 /* Check that the cookie is returned unmodified */
224 if (memcmp(ske->start_payload->cookie, payload->cookie,
225 ske->start_payload->cookie_len)) {
226 SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
227 ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
228 silc_ske_payload_start_free(ske->start_payload);
232 /* Free our KE Start Payload context, we don't need it anymore. */
233 silc_ske_payload_start_free(ske->start_payload);
235 /* Take the selected security properties into use while doing
236 the key exchange. This is used only while doing the key
237 exchange. The same data is returned to upper levels by calling
238 the callback function. */
239 ske->prop = prop = silc_calloc(1, sizeof(*prop));
240 prop->flags = payload->flags;
241 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
242 if (status != SILC_SKE_STATUS_OK)
247 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
248 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
252 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
253 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
257 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
258 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
262 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
263 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
267 /* Save remote's KE Start Payload */
268 ske->start_payload = payload;
270 /* Return the received payload by calling the callback function. */
271 if (ske->callbacks->payload_receive)
272 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
278 silc_ske_payload_start_free(payload);
283 silc_pkcs_free(prop->pkcs);
285 silc_cipher_free(prop->cipher);
287 silc_hash_free(prop->hash);
289 silc_hmac_free(prop->hmac);
293 if (status == SILC_SKE_STATUS_OK)
294 return SILC_SKE_STATUS_ERROR;
296 ske->status = status;
300 /* This function creates random number x, such that 1 < x < q and
301 computes e = g ^ x mod p and sends the result to the remote end in
302 Key Exchange Payload. */
304 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
305 SilcPublicKey public_key,
306 SilcPrivateKey private_key)
308 SilcSKEStatus status = SILC_SKE_STATUS_OK;
309 SilcBuffer payload_buf;
311 SilcSKEKEPayload *payload;
314 SILC_LOG_DEBUG(("Start"));
316 /* Create the random number x, 1 < x < q. */
317 x = silc_calloc(1, sizeof(*x));
320 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
321 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
323 if (status != SILC_SKE_STATUS_OK) {
326 ske->status = status;
330 /* Encode the result to Key Exchange Payload. */
332 payload = silc_calloc(1, sizeof(*payload));
333 ske->ke1_payload = payload;
335 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
337 /* Do the Diffie Hellman computation, e = g ^ x mod p */
338 silc_mp_init(&payload->x);
339 silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
340 &ske->prop->group->group);
344 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
345 if (!payload->pk_data) {
348 silc_mp_uninit(&payload->x);
350 ske->status = SILC_SKE_STATUS_OK;
353 payload->pk_len = pk_len;
355 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
357 /* Compute signature data if we are doing mutual authentication */
358 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
359 unsigned char hash[32], sign[1024];
360 uint32 hash_len, sign_len;
362 SILC_LOG_DEBUG(("We are doing mutual authentication"));
363 SILC_LOG_DEBUG(("Computing HASH_i value"));
365 /* Compute the hash value */
366 memset(hash, 0, sizeof(hash));
367 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
369 SILC_LOG_DEBUG(("Signing HASH_i value"));
371 /* Sign the hash value */
372 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
373 private_key->prv_len);
374 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
375 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
376 memcpy(payload->sign_data, sign, sign_len);
377 memset(sign, 0, sizeof(sign));
378 payload->sign_len = sign_len;
381 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
382 if (status != SILC_SKE_STATUS_OK) {
385 silc_mp_uninit(&payload->x);
386 silc_free(payload->pk_data);
388 ske->status = status;
394 /* Send the packet. */
395 if (ske->callbacks->send_packet)
396 (*ske->callbacks->send_packet)(ske, payload_buf,
397 SILC_PACKET_KEY_EXCHANGE_1,
398 ske->callbacks->context);
400 silc_buffer_free(payload_buf);
405 /* An initiator finish final callback that is called to indicate that
406 the SKE protocol may continue. */
408 static void silc_ske_initiator_finish_final(SilcSKE ske,
409 SilcSKEStatus status,
412 SilcSKEKEPayload *payload;
413 unsigned char hash[32];
415 SilcPublicKey public_key = NULL;
417 /* If the SKE was freed during the async call then free it really now,
418 otherwise just decrement the reference counter. */
419 if (ske->status == SILC_SKE_STATUS_FREED) {
424 /* If the caller returns PENDING status SKE library will assume that
425 the caller will re-call this callback when it is not anymore in
427 if (status == SILC_SKE_STATUS_PENDING)
431 payload = ske->ke2_payload;
433 /* If the status is an error then the public key that was verified
434 by the caller is not authentic. */
435 if (status != SILC_SKE_STATUS_OK) {
436 ske->status = status;
437 if (ske->callbacks->proto_continue)
438 ske->callbacks->proto_continue(ske, ske->callbacks->context);
442 if (payload->pk_data) {
443 /* Decode the public key */
444 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
446 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
447 if (ske->callbacks->proto_continue)
448 ske->callbacks->proto_continue(ske, ske->callbacks->context);
452 SILC_LOG_DEBUG(("Public key is authentic"));
454 /* Compute the hash value */
455 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
456 if (status != SILC_SKE_STATUS_OK)
459 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
460 memcpy(ske->hash, hash, hash_len);
461 ske->hash_len = hash_len;
463 SILC_LOG_DEBUG(("Verifying signature (HASH)"));
465 /* Verify signature */
466 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
467 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
468 payload->sign_len, hash, hash_len) == FALSE) {
470 SILC_LOG_DEBUG(("Signature don't match"));
472 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
476 SILC_LOG_DEBUG(("Signature is Ok"));
478 silc_pkcs_public_key_free(public_key);
479 memset(hash, 'F', hash_len);
482 ske->status = SILC_SKE_STATUS_OK;
484 /* Call the callback. The caller may now continue the SKE protocol. */
485 if (ske->callbacks->proto_continue)
486 ske->callbacks->proto_continue(ske, ske->callbacks->context);
491 memset(hash, 'F', sizeof(hash));
492 silc_ske_payload_ke_free(payload);
493 ske->ke2_payload = NULL;
495 silc_mp_uninit(ske->KEY);
500 silc_pkcs_public_key_free(public_key);
503 memset(ske->hash, 'F', hash_len);
504 silc_free(ske->hash);
508 if (status == SILC_SKE_STATUS_OK)
509 ske->status = SILC_SKE_STATUS_ERROR;
511 ske->status = status;
513 /* Call the callback. */
514 if (ske->callbacks->proto_continue)
515 ske->callbacks->proto_continue(ske, ske->callbacks->context);
518 /* Receives Key Exchange Payload from responder consisting responders
519 public key, f, and signature. This function verifies the public key,
520 computes the secret shared key and verifies the signature.
522 The `callback' will be called to indicate that the caller may
523 continue with the SKE protocol. The caller must not continue
524 before the SKE libary has called that callback. If this function
525 returns an error the callback will not be called. It is called
526 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
527 However, note that when the library calls the callback the ske->status
530 This calls the `verify_key' callback to verify the received public
531 key or certificate. If the `verify_key' is provided then the remote
532 must send public key and it is considered to be an error if remote
533 does not send its public key. If caller is performing a re-key with
534 SKE then the `verify_key' is usually not provided when it is not also
535 required for the remote to send its public key. */
537 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
538 SilcBuffer ke_payload)
540 SilcSKEStatus status = SILC_SKE_STATUS_OK;
541 SilcSKEKEPayload *payload;
544 SILC_LOG_DEBUG(("Start"));
546 /* Decode the payload */
547 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
548 if (status != SILC_SKE_STATUS_OK) {
549 ske->status = status;
552 ske->ke2_payload = payload;
554 if (!payload->pk_data && ske->callbacks->verify_key) {
555 SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
556 "even though we require it"));
557 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
561 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
563 /* Compute the shared secret key */
564 KEY = silc_calloc(1, sizeof(*KEY));
566 silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
569 if (payload->pk_data && ske->callbacks->verify_key) {
570 SILC_LOG_DEBUG(("Verifying public key"));
573 (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
574 payload->pk_type, ske->callbacks->context,
575 silc_ske_initiator_finish_final, NULL);
577 /* We will continue to the final state after the public key has
578 been verified by the caller. */
579 return SILC_SKE_STATUS_PENDING;
582 /* Continue to final state */
583 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
585 return SILC_SKE_STATUS_OK;
588 silc_ske_payload_ke_free(payload);
589 ske->ke2_payload = NULL;
591 silc_mp_uninit(ske->KEY);
595 if (status == SILC_SKE_STATUS_OK)
596 return SILC_SKE_STATUS_ERROR;
598 ske->status = status;
602 /* Starts Key Exchange protocol for responder. Responder receives
603 Key Exchange Start Payload from initiator consisting of all the
604 security properties the initiator supports. This function decodes
605 the payload and parses the payload further and selects the right
606 security properties. */
608 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
609 SilcSocketConnection sock,
611 SilcBuffer start_payload,
614 SilcSKEStatus status = SILC_SKE_STATUS_OK;
615 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
617 SILC_LOG_DEBUG(("Start"));
622 /* Decode the payload */
623 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
624 if (status != SILC_SKE_STATUS_OK) {
625 ske->status = status;
629 /* Take a copy of the payload buffer for future use. It is used to
630 compute the HASH value. */
631 ske->start_payload_copy = silc_buffer_copy(start_payload);
633 /* Force the mutual authentication flag if we want to do it. */
635 SILC_LOG_DEBUG(("Force mutual authentication"));
636 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
639 /* Parse and select the security properties from the payload */
640 payload = silc_calloc(1, sizeof(*payload));
641 status = silc_ske_select_security_properties(ske, version,
642 payload, remote_payload);
643 if (status != SILC_SKE_STATUS_OK)
646 ske->start_payload = payload;
648 /* Call the callback function. */
649 if (ske->callbacks->payload_receive)
650 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
656 silc_ske_payload_start_free(remote_payload);
660 if (status == SILC_SKE_STATUS_OK)
661 return SILC_SKE_STATUS_ERROR;
663 ske->status = status;
667 /* The selected security properties from the initiator payload is now
668 encoded into Key Exchange Start Payload and sent to the initiator. */
670 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
671 SilcSKEStartPayload *start_payload)
673 SilcSKEStatus status = SILC_SKE_STATUS_OK;
674 SilcBuffer payload_buf;
675 SilcSKESecurityProperties prop;
676 SilcSKEDiffieHellmanGroup group = NULL;
678 SILC_LOG_DEBUG(("Start"));
680 /* Allocate security properties from the payload. These are allocated
681 only for this negotiation and will be free'd after KE is over. */
682 ske->prop = prop = silc_calloc(1, sizeof(*prop));
683 prop->flags = start_payload->flags;
684 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
685 if (status != SILC_SKE_STATUS_OK)
690 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
691 &prop->pkcs) == FALSE) {
692 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
696 if (silc_cipher_alloc(start_payload->enc_alg_list,
697 &prop->cipher) == FALSE) {
698 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
702 if (silc_hash_alloc(start_payload->hash_alg_list,
703 &prop->hash) == FALSE) {
704 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
708 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
709 &prop->hmac) == FALSE) {
710 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
714 /* Encode the payload */
715 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
716 if (status != SILC_SKE_STATUS_OK)
719 /* Send the packet. */
720 if (ske->callbacks->send_packet)
721 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
722 ske->callbacks->context);
724 silc_buffer_free(payload_buf);
733 silc_pkcs_free(prop->pkcs);
735 silc_cipher_free(prop->cipher);
737 silc_hash_free(prop->hash);
739 silc_hmac_free(prop->hmac);
743 if (status == SILC_SKE_STATUS_OK)
744 return SILC_SKE_STATUS_ERROR;
746 ske->status = status;
750 /* An responder phase 2 final callback that is called to indicate that
751 the SKE protocol may continue. */
753 static void silc_ske_responder_phase2_final(SilcSKE ske,
754 SilcSKEStatus status,
757 SilcSKEKEPayload *recv_payload, *send_payload;
760 /* If the SKE was freed during the async call then free it really now,
761 otherwise just decrement the reference counter. */
762 if (ske->status == SILC_SKE_STATUS_FREED) {
767 /* If the caller returns PENDING status SKE library will assume that
768 the caller will re-call this callback when it is not anymore in
770 if (status == SILC_SKE_STATUS_PENDING)
774 recv_payload = ske->ke1_payload;
776 /* If the status is an error then the public key that was verified
777 by the caller is not authentic. */
778 if (status != SILC_SKE_STATUS_OK) {
779 ske->status = status;
780 if (ske->callbacks->proto_continue)
781 ske->callbacks->proto_continue(ske, ske->callbacks->context);
785 /* The public key verification was performed only if the Mutual
786 Authentication flag is set. */
787 if (ske->start_payload &&
788 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
789 SilcPublicKey public_key = NULL;
790 unsigned char hash[32];
793 /* Decode the public key */
794 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
795 recv_payload->pk_len,
797 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
798 if (ske->callbacks->proto_continue)
799 ske->callbacks->proto_continue(ske, ske->callbacks->context);
803 SILC_LOG_DEBUG(("Public key is authentic"));
805 /* Compute the hash value */
806 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
807 if (status != SILC_SKE_STATUS_OK) {
808 ske->status = status;
809 if (ske->callbacks->proto_continue)
810 ske->callbacks->proto_continue(ske, ske->callbacks->context);
814 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
816 /* Verify signature */
817 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
818 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
819 recv_payload->sign_len, hash, hash_len) == FALSE) {
821 SILC_LOG_DEBUG(("Signature don't match"));
823 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
824 if (ske->callbacks->proto_continue)
825 ske->callbacks->proto_continue(ske, ske->callbacks->context);
829 SILC_LOG_DEBUG(("Signature is Ok"));
831 silc_pkcs_public_key_free(public_key);
832 memset(hash, 'F', hash_len);
835 /* Create the random number x, 1 < x < q. */
836 x = silc_calloc(1, sizeof(*x));
839 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
840 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
842 if (status != SILC_SKE_STATUS_OK) {
845 ske->status = status;
846 if (ske->callbacks->proto_continue)
847 ske->callbacks->proto_continue(ske, ske->callbacks->context);
851 /* Save the results for later processing */
852 send_payload = silc_calloc(1, sizeof(*send_payload));
854 ske->ke2_payload = send_payload;
856 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
858 /* Do the Diffie Hellman computation, f = g ^ x mod p */
859 silc_mp_init(&send_payload->x);
860 silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
861 &ske->prop->group->group);
863 /* Call the callback. The caller may now continue with the SKE protocol. */
864 ske->status = SILC_SKE_STATUS_OK;
865 if (ske->callbacks->proto_continue)
866 ske->callbacks->proto_continue(ske, ske->callbacks->context);
869 /* This function receives the Key Exchange Payload from the initiator.
870 This also performs the mutual authentication if required. Then, this
871 function first generated a random number x, such that 1 < x < q
872 and computes f = g ^ x mod p. This then puts the result f to a Key
875 The `callback' will be called to indicate that the caller may
876 continue with the SKE protocol. The caller must not continue
877 before the SKE libary has called that callback. If this function
878 returns an error the callback will not be called. It is called
879 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
880 However, note that when the library calls the callback the ske->status
883 This calls the `verify_key' callback to verify the received public
884 key or certificate if the Mutual Authentication flag is set. If the
885 `verify_key' is provided then the remote must send public key and it
886 is considered to be an error if remote does not send its public key. */
888 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
889 SilcBuffer ke_payload)
891 SilcSKEStatus status = SILC_SKE_STATUS_OK;
892 SilcSKEKEPayload *recv_payload;
894 SILC_LOG_DEBUG(("Start"));
896 /* Decode Key Exchange Payload */
897 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
898 if (status != SILC_SKE_STATUS_OK) {
899 ske->status = status;
903 ske->ke1_payload = recv_payload;
905 /* Verify the received public key and verify the signature if we are
906 doing mutual authentication. */
907 if (ske->start_payload &&
908 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
910 SILC_LOG_DEBUG(("We are doing mutual authentication"));
912 if (!recv_payload->pk_data && ske->callbacks->verify_key) {
913 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
914 "certificate), even though we require it"));
915 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
919 if (recv_payload->pk_data && ske->callbacks->verify_key) {
920 SILC_LOG_DEBUG(("Verifying public key"));
923 (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
924 recv_payload->pk_len,
925 recv_payload->pk_type,
926 ske->callbacks->context,
927 silc_ske_responder_phase2_final, NULL);
929 /* We will continue to the final state after the public key has
930 been verified by the caller. */
931 return SILC_SKE_STATUS_PENDING;
935 /* Continue to final state */
936 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
938 return SILC_SKE_STATUS_OK;
941 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
942 value to be signed and sent to the other end. This then encodes Key
943 Exchange Payload and sends it to the other end. */
945 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
946 SilcPublicKey public_key,
947 SilcPrivateKey private_key,
948 SilcSKEPKType pk_type)
950 SilcSKEStatus status = SILC_SKE_STATUS_OK;
951 SilcBuffer payload_buf;
953 unsigned char hash[32], sign[1024], *pk;
954 uint32 hash_len, sign_len, pk_len;
956 SILC_LOG_DEBUG(("Start"));
958 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
960 /* Compute the shared secret key */
961 KEY = silc_calloc(1, sizeof(*KEY));
963 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
964 &ske->prop->group->group);
967 if (public_key && private_key) {
968 SILC_LOG_DEBUG(("Getting public key"));
970 /* Get the public key */
971 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
973 status = SILC_SKE_STATUS_ERROR;
976 ske->ke2_payload->pk_data = pk;
977 ske->ke2_payload->pk_len = pk_len;
979 SILC_LOG_DEBUG(("Computing HASH value"));
981 /* Compute the hash value */
982 memset(hash, 0, sizeof(hash));
983 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
984 if (status != SILC_SKE_STATUS_OK)
987 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
988 memcpy(ske->hash, hash, hash_len);
989 ske->hash_len = hash_len;
991 SILC_LOG_DEBUG(("Signing HASH value"));
993 /* Sign the hash value */
994 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
995 private_key->prv_len);
996 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
997 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
998 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
999 memset(sign, 0, sizeof(sign));
1000 ske->ke2_payload->sign_len = sign_len;
1002 ske->ke2_payload->pk_type = pk_type;
1004 /* Encode the Key Exchange Payload */
1005 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1007 if (status != SILC_SKE_STATUS_OK)
1010 /* Send the packet. */
1011 if (ske->callbacks->send_packet)
1012 (*ske->callbacks->send_packet)(ske, payload_buf,
1013 SILC_PACKET_KEY_EXCHANGE_2,
1014 ske->callbacks->context);
1016 silc_buffer_free(payload_buf);
1021 silc_mp_uninit(ske->KEY);
1022 silc_free(ske->KEY);
1024 silc_ske_payload_ke_free(ske->ke2_payload);
1026 if (status == SILC_SKE_STATUS_OK)
1027 return SILC_SKE_STATUS_ERROR;
1029 ske->status = status;
1033 /* The Key Exchange protocol is ended by calling this function. This
1034 must not be called until the keys are processed like the protocol
1035 defines. This function is for both initiator and responder. */
1037 SilcSKEStatus silc_ske_end(SilcSKE ske)
1041 SILC_LOG_DEBUG(("Start"));
1043 packet = silc_buffer_alloc(4);
1044 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1045 silc_buffer_format(packet,
1046 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1049 if (ske->callbacks->send_packet)
1050 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1051 ske->callbacks->context);
1053 silc_buffer_free(packet);
1055 return SILC_SKE_STATUS_OK;
1058 /* Aborts the Key Exchange protocol. This is called if error occurs
1059 while performing the protocol. The status argument is the error
1060 status and it is sent to the remote end. */
1062 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1066 SILC_LOG_DEBUG(("Start"));
1068 packet = silc_buffer_alloc(4);
1069 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1070 silc_buffer_format(packet,
1071 SILC_STR_UI_INT((uint32)status),
1074 if (ske->callbacks->send_packet)
1075 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1076 ske->callbacks->context);
1078 silc_buffer_free(packet);
1080 return SILC_SKE_STATUS_OK;
1083 /* Assembles security properties to Key Exchange Start Payload to be
1084 sent to the remote end. This checks system wide (SILC system, that is)
1085 settings and chooses from those. However, if other properties
1086 should be used this function is easy to replace by another function,
1087 as, this function is called by the caller of the protocol and not
1088 by the protocol itself. */
1091 silc_ske_assemble_security_properties(SilcSKE ske,
1092 unsigned char flags,
1094 SilcSKEStartPayload **return_payload)
1096 SilcSKEStartPayload *rp;
1099 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1101 rp = silc_calloc(1, sizeof(*rp));
1106 /* Set random cookie */
1107 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1108 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1109 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1110 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1113 rp->version = strdup(version);
1114 rp->version_len = strlen(version);
1116 /* Get supported Key Exhange groups */
1117 rp->ke_grp_list = silc_ske_get_supported_groups();
1118 rp->ke_grp_len = strlen(rp->ke_grp_list);
1120 /* Get supported PKCS algorithms */
1121 rp->pkcs_alg_list = silc_pkcs_get_supported();
1122 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1124 /* Get supported encryption algorithms */
1125 rp->enc_alg_list = silc_cipher_get_supported();
1126 rp->enc_alg_len = strlen(rp->enc_alg_list);
1128 /* Get supported hash algorithms */
1129 rp->hash_alg_list = silc_hash_get_supported();
1130 rp->hash_alg_len = strlen(rp->hash_alg_list);
1132 /* Get supported HMACs */
1133 rp->hmac_alg_list = silc_hmac_get_supported();
1134 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1137 /* Get supported compression algorithms */
1138 rp->comp_alg_list = strdup("");
1139 rp->comp_alg_len = 0;
1141 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1142 2 + rp->version_len +
1143 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1144 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1145 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1147 *return_payload = rp;
1149 return SILC_SKE_STATUS_OK;
1152 /* Selects the supported security properties from the remote end's Key
1153 Exchange Start Payload. */
1156 silc_ske_select_security_properties(SilcSKE ske,
1158 SilcSKEStartPayload *payload,
1159 SilcSKEStartPayload *remote_payload)
1161 SilcSKEStatus status;
1162 SilcSKEStartPayload *rp;
1166 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1168 rp = remote_payload;
1170 /* Check version string */
1171 if (ske->callbacks->check_version) {
1172 status = ske->callbacks->check_version(ske, rp->version,
1174 ske->callbacks->context);
1175 if (status != SILC_SKE_STATUS_OK) {
1176 ske->status = status;
1181 /* Flags are returned unchanged. */
1182 payload->flags = rp->flags;
1184 /* Take cookie, we must return it to sender unmodified. */
1185 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1186 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1187 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1189 /* Put our version to our reply */
1190 payload->version = strdup(version);
1191 payload->version_len = strlen(version);
1193 /* Get supported Key Exchange groups */
1194 cp = rp->ke_grp_list;
1195 if (cp && strchr(cp, ',')) {
1199 len = strcspn(cp, ",");
1200 item = silc_calloc(len + 1, sizeof(char));
1201 memcpy(item, cp, len);
1203 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1205 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1206 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1208 payload->ke_grp_len = len;
1209 payload->ke_grp_list = item;
1214 if (strlen(cp) == 0)
1223 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1224 SILC_LOG_DEBUG(("Could not find supported KE group"));
1226 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1230 if (!rp->ke_grp_len) {
1231 SILC_LOG_DEBUG(("KE group not defined in payload"));
1233 return SILC_SKE_STATUS_BAD_PAYLOAD;
1236 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1237 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1239 payload->ke_grp_len = rp->ke_grp_len;
1240 payload->ke_grp_list = strdup(rp->ke_grp_list);
1243 /* Get supported PKCS algorithms */
1244 cp = rp->pkcs_alg_list;
1245 if (cp && strchr(cp, ',')) {
1249 len = strcspn(cp, ",");
1250 item = silc_calloc(len + 1, sizeof(char));
1251 memcpy(item, cp, len);
1253 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1255 if (silc_pkcs_is_supported(item) == TRUE) {
1256 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1258 payload->pkcs_alg_len = len;
1259 payload->pkcs_alg_list = item;
1264 if (strlen(cp) == 0)
1273 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1274 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1275 silc_free(payload->ke_grp_list);
1277 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1281 if (!rp->pkcs_alg_len) {
1282 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1283 silc_free(payload->ke_grp_list);
1285 return SILC_SKE_STATUS_BAD_PAYLOAD;
1288 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1289 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1291 payload->pkcs_alg_len = rp->pkcs_alg_len;
1292 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1295 /* Get supported encryption algorithms */
1296 cp = rp->enc_alg_list;
1297 if (cp && strchr(cp, ',')) {
1301 len = strcspn(cp, ",");
1302 item = silc_calloc(len + 1, sizeof(char));
1303 memcpy(item, cp, len);
1305 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1307 if (silc_cipher_is_supported(item) == TRUE) {
1308 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1310 payload->enc_alg_len = len;
1311 payload->enc_alg_list = item;
1316 if (strlen(cp) == 0)
1325 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1326 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1327 silc_free(payload->ke_grp_list);
1328 silc_free(payload->pkcs_alg_list);
1330 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1334 if (!rp->enc_alg_len) {
1335 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1336 silc_free(payload->ke_grp_list);
1337 silc_free(payload->pkcs_alg_list);
1339 return SILC_SKE_STATUS_BAD_PAYLOAD;
1342 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1345 payload->enc_alg_len = rp->enc_alg_len;
1346 payload->enc_alg_list = strdup(rp->enc_alg_list);
1349 /* Get supported hash algorithms */
1350 cp = rp->hash_alg_list;
1351 if (cp && strchr(cp, ',')) {
1355 len = strcspn(cp, ",");
1356 item = silc_calloc(len + 1, sizeof(char));
1357 memcpy(item, cp, len);
1359 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1361 if (silc_hash_is_supported(item) == TRUE) {
1362 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1364 payload->hash_alg_len = len;
1365 payload->hash_alg_list = item;
1370 if (strlen(cp) == 0)
1379 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1380 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1381 silc_free(payload->ke_grp_list);
1382 silc_free(payload->pkcs_alg_list);
1383 silc_free(payload->enc_alg_list);
1385 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1389 if (!rp->hash_alg_len) {
1390 SILC_LOG_DEBUG(("Hash alg 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);
1395 return SILC_SKE_STATUS_BAD_PAYLOAD;
1398 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1399 rp->hash_alg_list));
1401 payload->hash_alg_len = rp->hash_alg_len;
1402 payload->hash_alg_list = strdup(rp->hash_alg_list);
1405 /* Get supported HMACs */
1406 cp = rp->hmac_alg_list;
1407 if (cp && strchr(cp, ',')) {
1411 len = strcspn(cp, ",");
1412 item = silc_calloc(len + 1, sizeof(char));
1413 memcpy(item, cp, len);
1415 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1417 if (silc_hmac_is_supported(item) == TRUE) {
1418 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1420 payload->hmac_alg_len = len;
1421 payload->hmac_alg_list = item;
1426 if (strlen(cp) == 0)
1435 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1436 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1437 silc_free(payload->ke_grp_list);
1438 silc_free(payload->pkcs_alg_list);
1439 silc_free(payload->enc_alg_list);
1440 silc_free(payload->hash_alg_list);
1442 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1446 if (!rp->hmac_alg_len) {
1447 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1448 silc_free(payload->ke_grp_list);
1449 silc_free(payload->pkcs_alg_list);
1450 silc_free(payload->enc_alg_list);
1451 silc_free(payload->hash_alg_list);
1453 return SILC_SKE_STATUS_BAD_PAYLOAD;
1456 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1457 rp->hmac_alg_list));
1459 payload->hmac_alg_len = rp->hmac_alg_len;
1460 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1464 /* Get supported compression algorithms */
1465 cp = rp->hash_alg_list;
1466 if (cp && strchr(cp, ',')) {
1470 len = strcspn(cp, ",");
1471 item = silc_calloc(len + 1, sizeof(char));
1472 memcpy(item, cp, len);
1474 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1476 if (silc_hash_is_supported(item) == TRUE) {
1477 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1479 payload->hash_alg_len = len;
1480 payload->hash_alg_list = item;
1485 if (strlen(cp) == 0)
1494 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1495 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1496 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1497 silc_free(payload->ke_grp_list);
1498 silc_free(payload->pkcs_alg_list);
1499 silc_free(payload->enc_alg_list);
1508 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1509 2 + payload->version_len +
1510 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1511 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1512 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1514 return SILC_SKE_STATUS_OK;
1517 /* Creates random number such that 1 < rnd < n and at most length
1518 of len bits. The rnd sent as argument must be initialized. */
1520 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
1524 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1525 unsigned char *string;
1527 SILC_LOG_DEBUG(("Creating random number"));
1529 /* Get the random number as string */
1530 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1532 return SILC_SKE_STATUS_ERROR;
1534 /* Decode the string into a MP integer */
1535 silc_mp_bin2mp(string, (len / 8), rnd);
1536 silc_mp_mod_2exp(rnd, rnd, len);
1539 if (silc_mp_cmp_ui(rnd, 1) < 0)
1540 status = SILC_SKE_STATUS_ERROR;
1542 if (silc_mp_cmp(rnd, n) >= 0)
1543 status = SILC_SKE_STATUS_ERROR;
1545 memset(string, 'F', (len / 8));
1551 /* Creates a hash value HASH as defined in the SKE protocol. If the
1552 `initiator' is TRUE then this function is used to create the HASH_i
1553 hash value defined in the protocol. If it is FALSE then this is used
1554 to create the HASH value defined by the protocol. */
1556 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1557 unsigned char *return_hash,
1558 uint32 *return_hash_len,
1561 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1563 unsigned char *e, *f, *KEY;
1564 uint32 e_len, f_len, KEY_len;
1567 SILC_LOG_DEBUG(("Start"));
1569 if (initiator == FALSE) {
1570 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1571 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1572 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1574 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1575 ske->ke2_payload->pk_len + e_len +
1577 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1579 /* Format the buffer used to compute the hash value */
1581 silc_buffer_format(buf,
1582 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1583 ske->start_payload_copy->len),
1584 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1585 ske->ke2_payload->pk_len),
1586 SILC_STR_UI_XNSTRING(e, e_len),
1587 SILC_STR_UI_XNSTRING(f, f_len),
1588 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1591 silc_buffer_free(buf);
1592 memset(e, 0, e_len);
1593 memset(f, 0, f_len);
1594 memset(KEY, 0, KEY_len);
1598 return SILC_SKE_STATUS_ERROR;
1601 memset(e, 0, e_len);
1602 memset(f, 0, f_len);
1603 memset(KEY, 0, KEY_len);
1608 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1610 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1611 ske->ke1_payload->pk_len + e_len);
1612 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1614 /* Format the buffer used to compute the hash value */
1616 silc_buffer_format(buf,
1617 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1618 ske->start_payload_copy->len),
1619 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1620 ske->ke1_payload->pk_len),
1621 SILC_STR_UI_XNSTRING(e, e_len),
1624 silc_buffer_free(buf);
1625 memset(e, 0, e_len);
1627 return SILC_SKE_STATUS_ERROR;
1630 memset(e, 0, e_len);
1635 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1636 *return_hash_len = ske->prop->hash->hash->hash_len;
1638 if (initiator == FALSE) {
1639 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1641 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1644 silc_buffer_free(buf);
1649 /* Processes the provided key material `data' as the SILC protocol
1650 specification defines. */
1653 silc_ske_process_key_material_data(unsigned char *data,
1656 uint32 req_enc_key_len,
1657 uint32 req_hmac_key_len,
1659 SilcSKEKeyMaterial *key)
1662 unsigned char hashd[32];
1663 uint32 hash_len = req_hmac_key_len;
1664 uint32 enc_key_len = req_enc_key_len / 8;
1666 SILC_LOG_DEBUG(("Start"));
1668 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1669 return SILC_SKE_STATUS_ERROR;
1671 buf = silc_buffer_alloc(1 + data_len);
1672 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1673 silc_buffer_format(buf,
1674 SILC_STR_UI_CHAR(0),
1675 SILC_STR_UI_XNSTRING(data, data_len),
1679 memset(hashd, 0, sizeof(hashd));
1681 silc_hash_make(hash, buf->data, buf->len, hashd);
1682 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1683 memcpy(key->send_iv, hashd, req_iv_len);
1684 memset(hashd, 0, sizeof(hashd));
1686 silc_hash_make(hash, buf->data, buf->len, hashd);
1687 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1688 memcpy(key->receive_iv, hashd, req_iv_len);
1689 key->iv_len = req_iv_len;
1691 /* Take the encryption keys. If requested key size is more than
1692 the size of hash length we will distribute more key material
1693 as protocol defines. */
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 + hash_len, k3, hash_len);
1735 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1736 memcpy(key->send_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->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1750 memcpy(key->send_enc_key, hashd, enc_key_len);
1751 key->enc_key_len = req_enc_key_len;
1755 if (enc_key_len > hash_len) {
1757 unsigned char k1[32], k2[32], k3[32];
1758 unsigned char *dtmp;
1761 if (enc_key_len > (3 * hash_len))
1762 return SILC_SKE_STATUS_ERROR;
1764 /* Take first round */
1765 memset(k1, 0, sizeof(k1));
1766 silc_hash_make(hash, buf->data, buf->len, k1);
1768 /* Take second round */
1769 dist = silc_buffer_alloc(data_len + hash_len);
1770 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1771 silc_buffer_format(dist,
1772 SILC_STR_UI_XNSTRING(data, data_len),
1773 SILC_STR_UI_XNSTRING(k1, hash_len),
1775 memset(k2, 0, sizeof(k2));
1776 silc_hash_make(hash, dist->data, dist->len, k2);
1778 /* Take third round */
1779 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1780 silc_buffer_pull_tail(dist, hash_len);
1781 silc_buffer_pull(dist, data_len + hash_len);
1782 silc_buffer_format(dist,
1783 SILC_STR_UI_XNSTRING(k2, hash_len),
1785 silc_buffer_push(dist, data_len + hash_len);
1786 memset(k3, 0, sizeof(k3));
1787 silc_hash_make(hash, dist->data, dist->len, k3);
1789 /* Then, save the keys */
1790 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1791 memcpy(dtmp, k1, hash_len);
1792 memcpy(dtmp + hash_len, k2, hash_len);
1793 memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1795 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1796 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1797 key->enc_key_len = req_enc_key_len;
1799 memset(dtmp, 0, (3 * hash_len));
1800 memset(k1, 0, sizeof(k1));
1801 memset(k2, 0, sizeof(k2));
1802 memset(k3, 0, sizeof(k3));
1804 silc_buffer_free(dist);
1806 /* Take normal hash as key */
1807 memset(hashd, 0, sizeof(hashd));
1808 silc_hash_make(hash, buf->data, buf->len, hashd);
1809 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1810 memcpy(key->receive_enc_key, hashd, enc_key_len);
1811 key->enc_key_len = req_enc_key_len;
1815 memset(hashd, 0, sizeof(hashd));
1817 silc_hash_make(hash, buf->data, buf->len, hashd);
1818 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1819 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1820 key->hmac_key_len = req_hmac_key_len;
1822 silc_buffer_free(buf);
1824 return SILC_SKE_STATUS_OK;
1827 /* Processes negotiated key material as protocol specifies. This returns
1828 the actual keys to be used in the SILC. */
1830 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1832 uint32 req_enc_key_len,
1833 uint32 req_hmac_key_len,
1834 SilcSKEKeyMaterial *key)
1836 SilcSKEStatus status;
1838 unsigned char *tmpbuf;
1841 /* Encode KEY to binary data */
1842 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1844 buf = silc_buffer_alloc(klen + ske->hash_len);
1845 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1846 silc_buffer_format(buf,
1847 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1848 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1851 /* Process the key material */
1852 status = silc_ske_process_key_material_data(buf->data, buf->len,
1853 req_iv_len, req_enc_key_len,
1855 ske->prop->hash, key);
1857 memset(tmpbuf, 0, klen);
1859 silc_buffer_free(buf);
1864 /* Free key material structure */
1866 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1872 silc_free(key->send_iv);
1873 if (key->receive_iv)
1874 silc_free(key->receive_iv);
1875 if (key->send_enc_key) {
1876 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1877 silc_free(key->send_enc_key);
1879 if (key->receive_enc_key) {
1880 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1881 silc_free(key->receive_enc_key);
1883 if (key->hmac_key) {
1884 memset(key->hmac_key, 0, key->hmac_key_len);
1885 silc_free(key->hmac_key);