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"
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;
222 /* Check that the cookie is returned unmodified */
223 if (memcmp(ske->start_payload->cookie, payload->cookie,
224 ske->start_payload->cookie_len)) {
225 SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
226 ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
227 silc_ske_payload_start_free(ske->start_payload);
231 /* Free our KE Start Payload context, we don't need it anymore. */
232 silc_ske_payload_start_free(ske->start_payload);
234 /* Take the selected security properties into use while doing
235 the key exchange. This is used only while doing the key
236 exchange. The same data is returned to upper levels by calling
237 the callback function. */
238 ske->prop = prop = silc_calloc(1, sizeof(*prop));
239 prop->flags = payload->flags;
240 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
241 if (status != SILC_SKE_STATUS_OK)
246 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
247 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
251 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
252 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
256 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
257 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
261 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
262 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
266 /* Save remote's KE Start Payload */
267 ske->start_payload = payload;
269 /* Return the received payload by calling the callback function. */
270 if (ske->callbacks->payload_receive)
271 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
277 silc_ske_payload_start_free(payload);
282 silc_pkcs_free(prop->pkcs);
284 silc_cipher_free(prop->cipher);
286 silc_hash_free(prop->hash);
288 silc_hmac_free(prop->hmac);
292 if (status == SILC_SKE_STATUS_OK)
293 return SILC_SKE_STATUS_ERROR;
295 ske->status = status;
299 /* This function creates random number x, such that 1 < x < q and
300 computes e = g ^ x mod p and sends the result to the remote end in
301 Key Exchange Payload. */
303 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
304 SilcPublicKey public_key,
305 SilcPrivateKey private_key)
307 SilcSKEStatus status = SILC_SKE_STATUS_OK;
308 SilcBuffer payload_buf;
310 SilcSKEKEPayload *payload;
313 SILC_LOG_DEBUG(("Start"));
315 /* Create the random number x, 1 < x < q. */
316 x = silc_calloc(1, sizeof(*x));
319 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
320 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
322 if (status != SILC_SKE_STATUS_OK) {
325 ske->status = status;
329 /* Encode the result to Key Exchange Payload. */
331 payload = silc_calloc(1, sizeof(*payload));
332 ske->ke1_payload = payload;
334 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
336 /* Do the Diffie Hellman computation, e = g ^ x mod p */
337 silc_mp_init(&payload->x);
338 silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
339 &ske->prop->group->group);
343 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
344 if (!payload->pk_data) {
347 silc_mp_uninit(&payload->x);
349 ske->status = SILC_SKE_STATUS_OK;
352 payload->pk_len = pk_len;
354 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
356 /* Compute signature data if we are doing mutual authentication */
357 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
358 unsigned char hash[32], sign[1024];
359 uint32 hash_len, sign_len;
361 SILC_LOG_DEBUG(("We are doing mutual authentication"));
362 SILC_LOG_DEBUG(("Computing HASH_i value"));
364 /* Compute the hash value */
365 memset(hash, 0, sizeof(hash));
366 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
368 SILC_LOG_DEBUG(("Signing HASH_i value"));
370 /* Sign the hash value */
371 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
372 private_key->prv_len);
373 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
374 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
375 memcpy(payload->sign_data, sign, sign_len);
376 memset(sign, 0, sizeof(sign));
377 payload->sign_len = sign_len;
380 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
381 if (status != SILC_SKE_STATUS_OK) {
384 silc_mp_uninit(&payload->x);
385 silc_free(payload->pk_data);
387 ske->status = status;
393 /* Send the packet. */
394 if (ske->callbacks->send_packet)
395 (*ske->callbacks->send_packet)(ske, payload_buf,
396 SILC_PACKET_KEY_EXCHANGE_1,
397 ske->callbacks->context);
399 silc_buffer_free(payload_buf);
404 /* An initiator finish final callback that is called to indicate that
405 the SKE protocol may continue. */
407 static void silc_ske_initiator_finish_final(SilcSKE ske,
408 SilcSKEStatus status,
411 SilcSKEKEPayload *payload;
412 unsigned char hash[32];
414 SilcPublicKey public_key = NULL;
416 /* If the SKE was freed during the async call then free it really now,
417 otherwise just decrement the reference counter. */
418 if (ske->status == SILC_SKE_STATUS_FREED) {
425 payload = ske->ke2_payload;
427 /* If the caller returns PENDING status SKE library will assume that
428 the caller will re-call this callback when it is not anymore in
430 if (status == SILC_SKE_STATUS_PENDING)
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) {
769 recv_payload = ske->ke1_payload;
771 /* If the caller returns PENDING status SKE library will assume that
772 the caller will re-call this callback when it is not anymore in
774 if (status == SILC_SKE_STATUS_PENDING)
777 /* If the status is an error then the public key that was verified
778 by the caller is not authentic. */
779 if (status != SILC_SKE_STATUS_OK) {
780 ske->status = status;
781 if (ske->callbacks->proto_continue)
782 ske->callbacks->proto_continue(ske, ske->callbacks->context);
786 /* The public key verification was performed only if the Mutual
787 Authentication flag is set. */
788 if (ske->start_payload &&
789 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
790 SilcPublicKey public_key = NULL;
791 unsigned char hash[32];
794 /* Decode the public key */
795 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
796 recv_payload->pk_len,
798 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
799 if (ske->callbacks->proto_continue)
800 ske->callbacks->proto_continue(ske, ske->callbacks->context);
804 SILC_LOG_DEBUG(("Public key is authentic"));
806 /* Compute the hash value */
807 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
808 if (status != SILC_SKE_STATUS_OK) {
809 ske->status = status;
810 if (ske->callbacks->proto_continue)
811 ske->callbacks->proto_continue(ske, ske->callbacks->context);
815 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
817 /* Verify signature */
818 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
819 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
820 recv_payload->sign_len, hash, hash_len) == FALSE) {
822 SILC_LOG_DEBUG(("Signature don't match"));
824 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
825 if (ske->callbacks->proto_continue)
826 ske->callbacks->proto_continue(ske, ske->callbacks->context);
830 SILC_LOG_DEBUG(("Signature is Ok"));
832 silc_pkcs_public_key_free(public_key);
833 memset(hash, 'F', hash_len);
836 /* Create the random number x, 1 < x < q. */
837 x = silc_calloc(1, sizeof(*x));
840 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
841 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
843 if (status != SILC_SKE_STATUS_OK) {
846 ske->status = status;
847 if (ske->callbacks->proto_continue)
848 ske->callbacks->proto_continue(ske, ske->callbacks->context);
852 /* Save the results for later processing */
853 send_payload = silc_calloc(1, sizeof(*send_payload));
855 ske->ke2_payload = send_payload;
857 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
859 /* Do the Diffie Hellman computation, f = g ^ x mod p */
860 silc_mp_init(&send_payload->x);
861 silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
862 &ske->prop->group->group);
864 /* Call the callback. The caller may now continue with the SKE protocol. */
865 ske->status = SILC_SKE_STATUS_OK;
866 if (ske->callbacks->proto_continue)
867 ske->callbacks->proto_continue(ske, ske->callbacks->context);
870 /* This function receives the Key Exchange Payload from the initiator.
871 This also performs the mutual authentication if required. Then, this
872 function first generated a random number x, such that 1 < x < q
873 and computes f = g ^ x mod p. This then puts the result f to a Key
876 The `callback' will be called to indicate that the caller may
877 continue with the SKE protocol. The caller must not continue
878 before the SKE libary has called that callback. If this function
879 returns an error the callback will not be called. It is called
880 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
881 However, note that when the library calls the callback the ske->status
884 This calls the `verify_key' callback to verify the received public
885 key or certificate if the Mutual Authentication flag is set. If the
886 `verify_key' is provided then the remote must send public key and it
887 is considered to be an error if remote does not send its public key. */
889 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
890 SilcBuffer ke_payload)
892 SilcSKEStatus status = SILC_SKE_STATUS_OK;
893 SilcSKEKEPayload *recv_payload;
895 SILC_LOG_DEBUG(("Start"));
897 /* Decode Key Exchange Payload */
898 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
899 if (status != SILC_SKE_STATUS_OK) {
900 ske->status = status;
904 ske->ke1_payload = recv_payload;
906 /* Verify the received public key and verify the signature if we are
907 doing mutual authentication. */
908 if (ske->start_payload &&
909 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
911 SILC_LOG_DEBUG(("We are doing mutual authentication"));
913 if (!recv_payload->pk_data && ske->callbacks->verify_key) {
914 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
915 "certificate), even though we require it"));
916 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
920 if (recv_payload->pk_data && ske->callbacks->verify_key) {
921 SILC_LOG_DEBUG(("Verifying public key"));
924 (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
925 recv_payload->pk_len,
926 recv_payload->pk_type,
927 ske->callbacks->context,
928 silc_ske_responder_phase2_final, NULL);
930 /* We will continue to the final state after the public key has
931 been verified by the caller. */
932 return SILC_SKE_STATUS_PENDING;
936 /* Continue to final state */
937 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
939 return SILC_SKE_STATUS_OK;
942 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
943 value to be signed and sent to the other end. This then encodes Key
944 Exchange Payload and sends it to the other end. */
946 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
947 SilcPublicKey public_key,
948 SilcPrivateKey private_key,
949 SilcSKEPKType pk_type)
951 SilcSKEStatus status = SILC_SKE_STATUS_OK;
952 SilcBuffer payload_buf;
954 unsigned char hash[32], sign[1024], *pk;
955 uint32 hash_len, sign_len, pk_len;
957 SILC_LOG_DEBUG(("Start"));
959 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
961 /* Compute the shared secret key */
962 KEY = silc_calloc(1, sizeof(*KEY));
964 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
965 &ske->prop->group->group);
968 if (public_key && private_key) {
969 SILC_LOG_DEBUG(("Getting public key"));
971 /* Get the public key */
972 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
974 status = SILC_SKE_STATUS_ERROR;
977 ske->ke2_payload->pk_data = pk;
978 ske->ke2_payload->pk_len = pk_len;
980 SILC_LOG_DEBUG(("Computing HASH value"));
982 /* Compute the hash value */
983 memset(hash, 0, sizeof(hash));
984 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
985 if (status != SILC_SKE_STATUS_OK)
988 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
989 memcpy(ske->hash, hash, hash_len);
990 ske->hash_len = hash_len;
992 SILC_LOG_DEBUG(("Signing HASH value"));
994 /* Sign the hash value */
995 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
996 private_key->prv_len);
997 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
998 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
999 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1000 memset(sign, 0, sizeof(sign));
1001 ske->ke2_payload->sign_len = sign_len;
1003 ske->ke2_payload->pk_type = pk_type;
1005 /* Encode the Key Exchange Payload */
1006 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1008 if (status != SILC_SKE_STATUS_OK)
1011 /* Send the packet. */
1012 if (ske->callbacks->send_packet)
1013 (*ske->callbacks->send_packet)(ske, payload_buf,
1014 SILC_PACKET_KEY_EXCHANGE_2,
1015 ske->callbacks->context);
1017 silc_buffer_free(payload_buf);
1022 silc_mp_uninit(ske->KEY);
1023 silc_free(ske->KEY);
1025 silc_ske_payload_ke_free(ske->ke2_payload);
1027 if (status == SILC_SKE_STATUS_OK)
1028 return SILC_SKE_STATUS_ERROR;
1030 ske->status = status;
1034 /* The Key Exchange protocol is ended by calling this function. This
1035 must not be called until the keys are processed like the protocol
1036 defines. This function is for both initiator and responder. */
1038 SilcSKEStatus silc_ske_end(SilcSKE ske)
1042 SILC_LOG_DEBUG(("Start"));
1044 packet = silc_buffer_alloc(4);
1045 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1046 silc_buffer_format(packet,
1047 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1050 if (ske->callbacks->send_packet)
1051 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1052 ske->callbacks->context);
1054 silc_buffer_free(packet);
1056 return SILC_SKE_STATUS_OK;
1059 /* Aborts the Key Exchange protocol. This is called if error occurs
1060 while performing the protocol. The status argument is the error
1061 status and it is sent to the remote end. */
1063 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1067 SILC_LOG_DEBUG(("Start"));
1069 packet = silc_buffer_alloc(4);
1070 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1071 silc_buffer_format(packet,
1072 SILC_STR_UI_INT((uint32)status),
1075 if (ske->callbacks->send_packet)
1076 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1077 ske->callbacks->context);
1079 silc_buffer_free(packet);
1081 return SILC_SKE_STATUS_OK;
1084 /* Assembles security properties to Key Exchange Start Payload to be
1085 sent to the remote end. This checks system wide (SILC system, that is)
1086 settings and chooses from those. However, if other properties
1087 should be used this function is easy to replace by another function,
1088 as, this function is called by the caller of the protocol and not
1089 by the protocol itself. */
1092 silc_ske_assemble_security_properties(SilcSKE ske,
1093 unsigned char flags,
1095 SilcSKEStartPayload **return_payload)
1097 SilcSKEStartPayload *rp;
1100 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1102 rp = silc_calloc(1, sizeof(*rp));
1107 /* Set random cookie */
1108 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1109 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1110 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1111 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1114 rp->version = strdup(version);
1115 rp->version_len = strlen(version);
1117 /* Get supported Key Exhange groups */
1118 rp->ke_grp_list = silc_ske_get_supported_groups();
1119 rp->ke_grp_len = strlen(rp->ke_grp_list);
1121 /* Get supported PKCS algorithms */
1122 rp->pkcs_alg_list = silc_pkcs_get_supported();
1123 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1125 /* Get supported encryption algorithms */
1126 rp->enc_alg_list = silc_cipher_get_supported();
1127 rp->enc_alg_len = strlen(rp->enc_alg_list);
1129 /* Get supported hash algorithms */
1130 rp->hash_alg_list = silc_hash_get_supported();
1131 rp->hash_alg_len = strlen(rp->hash_alg_list);
1133 /* Get supported HMACs */
1134 rp->hmac_alg_list = silc_hmac_get_supported();
1135 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1138 /* Get supported compression algorithms */
1139 rp->comp_alg_list = strdup("");
1140 rp->comp_alg_len = 0;
1142 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1143 2 + rp->version_len +
1144 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1145 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1146 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1148 *return_payload = rp;
1150 return SILC_SKE_STATUS_OK;
1153 /* Selects the supported security properties from the remote end's Key
1154 Exchange Start Payload. */
1157 silc_ske_select_security_properties(SilcSKE ske,
1159 SilcSKEStartPayload *payload,
1160 SilcSKEStartPayload *remote_payload)
1162 SilcSKEStatus status;
1163 SilcSKEStartPayload *rp;
1167 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1169 rp = remote_payload;
1171 /* Check version string */
1172 if (ske->callbacks->check_version) {
1173 status = ske->callbacks->check_version(ske, rp->version,
1175 ske->callbacks->context);
1176 if (status != SILC_SKE_STATUS_OK) {
1177 ske->status = status;
1182 /* Flags are returned unchanged. */
1183 payload->flags = rp->flags;
1185 /* Take cookie, we must return it to sender unmodified. */
1186 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1187 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1188 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1190 /* Put our version to our reply */
1191 payload->version = strdup(version);
1192 payload->version_len = strlen(version);
1194 /* Get supported Key Exchange groups */
1195 cp = rp->ke_grp_list;
1196 if (cp && strchr(cp, ',')) {
1200 len = strcspn(cp, ",");
1201 item = silc_calloc(len + 1, sizeof(char));
1202 memcpy(item, cp, len);
1204 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1206 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1207 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1209 payload->ke_grp_len = len;
1210 payload->ke_grp_list = item;
1215 if (strlen(cp) == 0)
1224 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1225 SILC_LOG_DEBUG(("Could not find supported KE group"));
1227 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1231 if (!rp->ke_grp_len) {
1232 SILC_LOG_DEBUG(("KE group not defined in payload"));
1234 return SILC_SKE_STATUS_BAD_PAYLOAD;
1237 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1238 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1240 payload->ke_grp_len = rp->ke_grp_len;
1241 payload->ke_grp_list = strdup(rp->ke_grp_list);
1244 /* Get supported PKCS algorithms */
1245 cp = rp->pkcs_alg_list;
1246 if (cp && strchr(cp, ',')) {
1250 len = strcspn(cp, ",");
1251 item = silc_calloc(len + 1, sizeof(char));
1252 memcpy(item, cp, len);
1254 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1256 if (silc_pkcs_is_supported(item) == TRUE) {
1257 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1259 payload->pkcs_alg_len = len;
1260 payload->pkcs_alg_list = item;
1265 if (strlen(cp) == 0)
1274 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1275 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1276 silc_free(payload->ke_grp_list);
1278 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1282 if (!rp->pkcs_alg_len) {
1283 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1284 silc_free(payload->ke_grp_list);
1286 return SILC_SKE_STATUS_BAD_PAYLOAD;
1289 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1290 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1292 payload->pkcs_alg_len = rp->pkcs_alg_len;
1293 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1296 /* Get supported encryption algorithms */
1297 cp = rp->enc_alg_list;
1298 if (cp && strchr(cp, ',')) {
1302 len = strcspn(cp, ",");
1303 item = silc_calloc(len + 1, sizeof(char));
1304 memcpy(item, cp, len);
1306 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1308 if (silc_cipher_is_supported(item) == TRUE) {
1309 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1311 payload->enc_alg_len = len;
1312 payload->enc_alg_list = item;
1317 if (strlen(cp) == 0)
1326 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1327 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1328 silc_free(payload->ke_grp_list);
1329 silc_free(payload->pkcs_alg_list);
1331 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1335 if (!rp->enc_alg_len) {
1336 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1337 silc_free(payload->ke_grp_list);
1338 silc_free(payload->pkcs_alg_list);
1340 return SILC_SKE_STATUS_BAD_PAYLOAD;
1343 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1346 payload->enc_alg_len = rp->enc_alg_len;
1347 payload->enc_alg_list = strdup(rp->enc_alg_list);
1350 /* Get supported hash algorithms */
1351 cp = rp->hash_alg_list;
1352 if (cp && strchr(cp, ',')) {
1356 len = strcspn(cp, ",");
1357 item = silc_calloc(len + 1, sizeof(char));
1358 memcpy(item, cp, len);
1360 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1362 if (silc_hash_is_supported(item) == TRUE) {
1363 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1365 payload->hash_alg_len = len;
1366 payload->hash_alg_list = item;
1371 if (strlen(cp) == 0)
1380 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1381 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1382 silc_free(payload->ke_grp_list);
1383 silc_free(payload->pkcs_alg_list);
1384 silc_free(payload->enc_alg_list);
1386 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1390 if (!rp->hash_alg_len) {
1391 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1392 silc_free(payload->ke_grp_list);
1393 silc_free(payload->pkcs_alg_list);
1394 silc_free(payload->enc_alg_list);
1396 return SILC_SKE_STATUS_BAD_PAYLOAD;
1399 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1400 rp->hash_alg_list));
1402 payload->hash_alg_len = rp->hash_alg_len;
1403 payload->hash_alg_list = strdup(rp->hash_alg_list);
1406 /* Get supported HMACs */
1407 cp = rp->hmac_alg_list;
1408 if (cp && strchr(cp, ',')) {
1412 len = strcspn(cp, ",");
1413 item = silc_calloc(len + 1, sizeof(char));
1414 memcpy(item, cp, len);
1416 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1418 if (silc_hmac_is_supported(item) == TRUE) {
1419 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1421 payload->hmac_alg_len = len;
1422 payload->hmac_alg_list = item;
1427 if (strlen(cp) == 0)
1436 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1437 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1438 silc_free(payload->ke_grp_list);
1439 silc_free(payload->pkcs_alg_list);
1440 silc_free(payload->enc_alg_list);
1441 silc_free(payload->hash_alg_list);
1443 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1447 if (!rp->hmac_alg_len) {
1448 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1449 silc_free(payload->ke_grp_list);
1450 silc_free(payload->pkcs_alg_list);
1451 silc_free(payload->enc_alg_list);
1452 silc_free(payload->hash_alg_list);
1454 return SILC_SKE_STATUS_BAD_PAYLOAD;
1457 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1458 rp->hmac_alg_list));
1460 payload->hmac_alg_len = rp->hmac_alg_len;
1461 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1465 /* Get supported compression algorithms */
1466 cp = rp->hash_alg_list;
1467 if (cp && strchr(cp, ',')) {
1471 len = strcspn(cp, ",");
1472 item = silc_calloc(len + 1, sizeof(char));
1473 memcpy(item, cp, len);
1475 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1477 if (silc_hash_is_supported(item) == TRUE) {
1478 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1480 payload->hash_alg_len = len;
1481 payload->hash_alg_list = item;
1486 if (strlen(cp) == 0)
1495 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1496 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1497 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1498 silc_free(payload->ke_grp_list);
1499 silc_free(payload->pkcs_alg_list);
1500 silc_free(payload->enc_alg_list);
1509 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1510 2 + payload->version_len +
1511 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1512 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1513 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1515 return SILC_SKE_STATUS_OK;
1518 /* Creates random number such that 1 < rnd < n and at most length
1519 of len bits. The rnd sent as argument must be initialized. */
1521 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
1525 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1526 unsigned char *string;
1528 SILC_LOG_DEBUG(("Creating random number"));
1530 /* Get the random number as string */
1531 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1533 return SILC_SKE_STATUS_ERROR;
1535 /* Decode the string into a MP integer */
1536 silc_mp_bin2mp(string, (len / 8), rnd);
1537 silc_mp_mod_2exp(rnd, rnd, len);
1540 if (silc_mp_cmp_ui(rnd, 1) < 0)
1541 status = SILC_SKE_STATUS_ERROR;
1543 if (silc_mp_cmp(rnd, n) >= 0)
1544 status = SILC_SKE_STATUS_ERROR;
1546 memset(string, 'F', (len / 8));
1552 /* Creates a hash value HASH as defined in the SKE protocol. If the
1553 `initiator' is TRUE then this function is used to create the HASH_i
1554 hash value defined in the protocol. If it is FALSE then this is used
1555 to create the HASH value defined by the protocol. */
1557 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1558 unsigned char *return_hash,
1559 uint32 *return_hash_len,
1562 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1564 unsigned char *e, *f, *KEY;
1565 uint32 e_len, f_len, KEY_len;
1568 SILC_LOG_DEBUG(("Start"));
1570 if (initiator == FALSE) {
1571 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1572 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1573 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1575 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1576 ske->ke2_payload->pk_len + e_len +
1578 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1580 /* Format the buffer used to compute the hash value */
1582 silc_buffer_format(buf,
1583 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1584 ske->start_payload_copy->len),
1585 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1586 ske->ke2_payload->pk_len),
1587 SILC_STR_UI_XNSTRING(e, e_len),
1588 SILC_STR_UI_XNSTRING(f, f_len),
1589 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1592 silc_buffer_free(buf);
1593 memset(e, 0, e_len);
1594 memset(f, 0, f_len);
1595 memset(KEY, 0, KEY_len);
1599 return SILC_SKE_STATUS_ERROR;
1602 memset(e, 0, e_len);
1603 memset(f, 0, f_len);
1604 memset(KEY, 0, KEY_len);
1609 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1611 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1612 ske->ke1_payload->pk_len + e_len);
1613 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1615 /* Format the buffer used to compute the hash value */
1617 silc_buffer_format(buf,
1618 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1619 ske->start_payload_copy->len),
1620 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1621 ske->ke1_payload->pk_len),
1622 SILC_STR_UI_XNSTRING(e, e_len),
1625 silc_buffer_free(buf);
1626 memset(e, 0, e_len);
1628 return SILC_SKE_STATUS_ERROR;
1631 memset(e, 0, e_len);
1636 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1637 *return_hash_len = ske->prop->hash->hash->hash_len;
1639 if (initiator == FALSE) {
1640 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1642 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1645 silc_buffer_free(buf);
1650 /* Processes the provided key material `data' as the SILC protocol
1651 specification defines. */
1654 silc_ske_process_key_material_data(unsigned char *data,
1657 uint32 req_enc_key_len,
1658 uint32 req_hmac_key_len,
1660 SilcSKEKeyMaterial *key)
1663 unsigned char hashd[32];
1664 uint32 hash_len = req_hmac_key_len;
1665 uint32 enc_key_len = req_enc_key_len / 8;
1667 SILC_LOG_DEBUG(("Start"));
1669 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1670 return SILC_SKE_STATUS_ERROR;
1672 buf = silc_buffer_alloc(1 + data_len);
1673 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1674 silc_buffer_format(buf,
1675 SILC_STR_UI_CHAR(0),
1676 SILC_STR_UI_XNSTRING(data, data_len),
1680 memset(hashd, 0, sizeof(hashd));
1682 silc_hash_make(hash, buf->data, buf->len, hashd);
1683 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1684 memcpy(key->send_iv, hashd, req_iv_len);
1685 memset(hashd, 0, sizeof(hashd));
1687 silc_hash_make(hash, buf->data, buf->len, hashd);
1688 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1689 memcpy(key->receive_iv, hashd, req_iv_len);
1690 key->iv_len = req_iv_len;
1692 /* Take the encryption keys. If requested key size is more than
1693 the size of hash length we will distribute more key material
1694 as protocol defines. */
1696 if (enc_key_len > hash_len) {
1698 unsigned char k1[32], k2[32], k3[32];
1699 unsigned char *dtmp;
1702 if (enc_key_len > (3 * hash_len))
1703 return SILC_SKE_STATUS_ERROR;
1705 /* Take first round */
1706 memset(k1, 0, sizeof(k1));
1707 silc_hash_make(hash, buf->data, buf->len, k1);
1709 /* Take second round */
1710 dist = silc_buffer_alloc(data_len + hash_len);
1711 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1712 silc_buffer_format(dist,
1713 SILC_STR_UI_XNSTRING(data, data_len),
1714 SILC_STR_UI_XNSTRING(k1, hash_len),
1716 memset(k2, 0, sizeof(k2));
1717 silc_hash_make(hash, dist->data, dist->len, k2);
1719 /* Take third round */
1720 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1721 silc_buffer_pull_tail(dist, hash_len);
1722 silc_buffer_pull(dist, data_len + hash_len);
1723 silc_buffer_format(dist,
1724 SILC_STR_UI_XNSTRING(k2, hash_len),
1726 silc_buffer_push(dist, data_len + hash_len);
1727 memset(k3, 0, sizeof(k3));
1728 silc_hash_make(hash, dist->data, dist->len, k3);
1730 /* Then, save the keys */
1731 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1732 memcpy(dtmp, k1, hash_len);
1733 memcpy(dtmp + hash_len, k2, hash_len);
1734 memcpy(dtmp + hash_len, k3, hash_len);
1736 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1737 memcpy(key->send_enc_key, dtmp, enc_key_len);
1738 key->enc_key_len = req_enc_key_len;
1740 memset(dtmp, 0, (3 * hash_len));
1741 memset(k1, 0, sizeof(k1));
1742 memset(k2, 0, sizeof(k2));
1743 memset(k3, 0, sizeof(k3));
1745 silc_buffer_free(dist);
1747 /* Take normal hash as key */
1748 memset(hashd, 0, sizeof(hashd));
1749 silc_hash_make(hash, buf->data, buf->len, hashd);
1750 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1751 memcpy(key->send_enc_key, hashd, enc_key_len);
1752 key->enc_key_len = req_enc_key_len;
1756 if (enc_key_len > hash_len) {
1758 unsigned char k1[32], k2[32], k3[32];
1759 unsigned char *dtmp;
1762 if (enc_key_len > (3 * hash_len))
1763 return SILC_SKE_STATUS_ERROR;
1765 /* Take first round */
1766 memset(k1, 0, sizeof(k1));
1767 silc_hash_make(hash, buf->data, buf->len, k1);
1769 /* Take second round */
1770 dist = silc_buffer_alloc(data_len + hash_len);
1771 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1772 silc_buffer_format(dist,
1773 SILC_STR_UI_XNSTRING(data, data_len),
1774 SILC_STR_UI_XNSTRING(k1, hash_len),
1776 memset(k2, 0, sizeof(k2));
1777 silc_hash_make(hash, dist->data, dist->len, k2);
1779 /* Take third round */
1780 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1781 silc_buffer_pull_tail(dist, hash_len);
1782 silc_buffer_pull(dist, data_len + hash_len);
1783 silc_buffer_format(dist,
1784 SILC_STR_UI_XNSTRING(k2, hash_len),
1786 silc_buffer_push(dist, data_len + hash_len);
1787 memset(k3, 0, sizeof(k3));
1788 silc_hash_make(hash, dist->data, dist->len, k3);
1790 /* Then, save the keys */
1791 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1792 memcpy(dtmp, k1, hash_len);
1793 memcpy(dtmp + hash_len, k2, hash_len);
1794 memcpy(dtmp + hash_len, k3, hash_len);
1796 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1797 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1798 key->enc_key_len = req_enc_key_len;
1800 memset(dtmp, 0, (3 * hash_len));
1801 memset(k1, 0, sizeof(k1));
1802 memset(k2, 0, sizeof(k2));
1803 memset(k3, 0, sizeof(k3));
1805 silc_buffer_free(dist);
1807 /* Take normal hash as key */
1808 memset(hashd, 0, sizeof(hashd));
1809 silc_hash_make(hash, buf->data, buf->len, hashd);
1810 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1811 memcpy(key->receive_enc_key, hashd, enc_key_len);
1812 key->enc_key_len = req_enc_key_len;
1816 memset(hashd, 0, sizeof(hashd));
1818 silc_hash_make(hash, buf->data, buf->len, hashd);
1819 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1820 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1821 key->hmac_key_len = req_hmac_key_len;
1823 silc_buffer_free(buf);
1825 return SILC_SKE_STATUS_OK;
1828 /* Processes negotiated key material as protocol specifies. This returns
1829 the actual keys to be used in the SILC. */
1831 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1833 uint32 req_enc_key_len,
1834 uint32 req_hmac_key_len,
1835 SilcSKEKeyMaterial *key)
1837 SilcSKEStatus status;
1839 unsigned char *tmpbuf;
1842 /* Encode KEY to binary data */
1843 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1845 buf = silc_buffer_alloc(klen + ske->hash_len);
1846 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1847 silc_buffer_format(buf,
1848 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1849 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1852 /* Process the key material */
1853 status = silc_ske_process_key_material_data(buf->data, buf->len,
1854 req_iv_len, req_enc_key_len,
1856 ske->prop->hash, key);
1858 memset(tmpbuf, 0, klen);
1860 silc_buffer_free(buf);
1865 /* Free key material structure */
1867 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1873 silc_free(key->send_iv);
1874 if (key->receive_iv)
1875 silc_free(key->receive_iv);
1876 if (key->send_enc_key) {
1877 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1878 silc_free(key->send_enc_key);
1880 if (key->receive_enc_key) {
1881 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1882 silc_free(key->receive_enc_key);
1884 if (key->hmac_key) {
1885 memset(key->hmac_key, 0, key->hmac_key_len);
1886 silc_free(key->hmac_key);