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 */
584 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
586 return SILC_SKE_STATUS_OK;
589 silc_ske_payload_ke_free(payload);
590 ske->ke2_payload = NULL;
592 silc_mp_uninit(ske->KEY);
596 if (status == SILC_SKE_STATUS_OK)
597 return SILC_SKE_STATUS_ERROR;
599 ske->status = status;
603 /* Starts Key Exchange protocol for responder. Responder receives
604 Key Exchange Start Payload from initiator consisting of all the
605 security properties the initiator supports. This function decodes
606 the payload and parses the payload further and selects the right
607 security properties. */
609 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
610 SilcSocketConnection sock,
612 SilcBuffer start_payload,
615 SilcSKEStatus status = SILC_SKE_STATUS_OK;
616 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
618 SILC_LOG_DEBUG(("Start"));
623 /* Decode the payload */
624 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
625 if (status != SILC_SKE_STATUS_OK) {
626 ske->status = status;
630 /* Take a copy of the payload buffer for future use. It is used to
631 compute the HASH value. */
632 ske->start_payload_copy = silc_buffer_copy(start_payload);
634 /* Force the mutual authentication flag if we want to do it. */
636 SILC_LOG_DEBUG(("Force mutual authentication"));
637 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
640 /* Parse and select the security properties from the payload */
641 payload = silc_calloc(1, sizeof(*payload));
642 status = silc_ske_select_security_properties(ske, version,
643 payload, remote_payload);
644 if (status != SILC_SKE_STATUS_OK)
647 ske->start_payload = payload;
649 /* Call the callback function. */
650 if (ske->callbacks->payload_receive)
651 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
657 silc_ske_payload_start_free(remote_payload);
661 if (status == SILC_SKE_STATUS_OK)
662 return SILC_SKE_STATUS_ERROR;
664 ske->status = status;
668 /* The selected security properties from the initiator payload is now
669 encoded into Key Exchange Start Payload and sent to the initiator. */
671 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
672 SilcSKEStartPayload *start_payload)
674 SilcSKEStatus status = SILC_SKE_STATUS_OK;
675 SilcBuffer payload_buf;
676 SilcSKESecurityProperties prop;
677 SilcSKEDiffieHellmanGroup group = NULL;
679 SILC_LOG_DEBUG(("Start"));
681 /* Allocate security properties from the payload. These are allocated
682 only for this negotiation and will be free'd after KE is over. */
683 ske->prop = prop = silc_calloc(1, sizeof(*prop));
684 prop->flags = start_payload->flags;
685 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
686 if (status != SILC_SKE_STATUS_OK)
691 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
692 &prop->pkcs) == FALSE) {
693 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
697 if (silc_cipher_alloc(start_payload->enc_alg_list,
698 &prop->cipher) == FALSE) {
699 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
703 if (silc_hash_alloc(start_payload->hash_alg_list,
704 &prop->hash) == FALSE) {
705 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
709 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
710 &prop->hmac) == FALSE) {
711 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
715 /* Encode the payload */
716 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
717 if (status != SILC_SKE_STATUS_OK)
720 /* Send the packet. */
721 if (ske->callbacks->send_packet)
722 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
723 ske->callbacks->context);
725 silc_buffer_free(payload_buf);
734 silc_pkcs_free(prop->pkcs);
736 silc_cipher_free(prop->cipher);
738 silc_hash_free(prop->hash);
740 silc_hmac_free(prop->hmac);
744 if (status == SILC_SKE_STATUS_OK)
745 return SILC_SKE_STATUS_ERROR;
747 ske->status = status;
751 /* An responder phase 2 final callback that is called to indicate that
752 the SKE protocol may continue. */
754 static void silc_ske_responder_phase2_final(SilcSKE ske,
755 SilcSKEStatus status,
758 SilcSKEKEPayload *recv_payload, *send_payload;
761 /* If the SKE was freed during the async call then free it really now,
762 otherwise just decrement the reference counter. */
763 if (ske->status == SILC_SKE_STATUS_FREED) {
768 /* If the caller returns PENDING status SKE library will assume that
769 the caller will re-call this callback when it is not anymore in
771 if (status == SILC_SKE_STATUS_PENDING)
775 recv_payload = ske->ke1_payload;
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 */
938 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
940 return SILC_SKE_STATUS_OK;
943 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
944 value to be signed and sent to the other end. This then encodes Key
945 Exchange Payload and sends it to the other end. */
947 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
948 SilcPublicKey public_key,
949 SilcPrivateKey private_key,
950 SilcSKEPKType pk_type)
952 SilcSKEStatus status = SILC_SKE_STATUS_OK;
953 SilcBuffer payload_buf;
955 unsigned char hash[32], sign[1024], *pk;
956 uint32 hash_len, sign_len, pk_len;
958 SILC_LOG_DEBUG(("Start"));
960 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
962 /* Compute the shared secret key */
963 KEY = silc_calloc(1, sizeof(*KEY));
965 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
966 &ske->prop->group->group);
969 if (public_key && private_key) {
970 SILC_LOG_DEBUG(("Getting public key"));
972 /* Get the public key */
973 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
975 status = SILC_SKE_STATUS_ERROR;
978 ske->ke2_payload->pk_data = pk;
979 ske->ke2_payload->pk_len = pk_len;
981 SILC_LOG_DEBUG(("Computing HASH value"));
983 /* Compute the hash value */
984 memset(hash, 0, sizeof(hash));
985 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
986 if (status != SILC_SKE_STATUS_OK)
989 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
990 memcpy(ske->hash, hash, hash_len);
991 ske->hash_len = hash_len;
993 SILC_LOG_DEBUG(("Signing HASH value"));
995 /* Sign the hash value */
996 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
997 private_key->prv_len);
998 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
999 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
1000 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1001 memset(sign, 0, sizeof(sign));
1002 ske->ke2_payload->sign_len = sign_len;
1004 ske->ke2_payload->pk_type = pk_type;
1006 /* Encode the Key Exchange Payload */
1007 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1009 if (status != SILC_SKE_STATUS_OK)
1012 /* Send the packet. */
1013 if (ske->callbacks->send_packet)
1014 (*ske->callbacks->send_packet)(ske, payload_buf,
1015 SILC_PACKET_KEY_EXCHANGE_2,
1016 ske->callbacks->context);
1018 silc_buffer_free(payload_buf);
1023 silc_mp_uninit(ske->KEY);
1024 silc_free(ske->KEY);
1026 silc_ske_payload_ke_free(ske->ke2_payload);
1028 if (status == SILC_SKE_STATUS_OK)
1029 return SILC_SKE_STATUS_ERROR;
1031 ske->status = status;
1035 /* The Key Exchange protocol is ended by calling this function. This
1036 must not be called until the keys are processed like the protocol
1037 defines. This function is for both initiator and responder. */
1039 SilcSKEStatus silc_ske_end(SilcSKE ske)
1043 SILC_LOG_DEBUG(("Start"));
1045 packet = silc_buffer_alloc(4);
1046 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1047 silc_buffer_format(packet,
1048 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1051 if (ske->callbacks->send_packet)
1052 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1053 ske->callbacks->context);
1055 silc_buffer_free(packet);
1057 return SILC_SKE_STATUS_OK;
1060 /* Aborts the Key Exchange protocol. This is called if error occurs
1061 while performing the protocol. The status argument is the error
1062 status and it is sent to the remote end. */
1064 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1068 SILC_LOG_DEBUG(("Start"));
1070 packet = silc_buffer_alloc(4);
1071 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1072 silc_buffer_format(packet,
1073 SILC_STR_UI_INT((uint32)status),
1076 if (ske->callbacks->send_packet)
1077 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1078 ske->callbacks->context);
1080 silc_buffer_free(packet);
1082 return SILC_SKE_STATUS_OK;
1085 /* Assembles security properties to Key Exchange Start Payload to be
1086 sent to the remote end. This checks system wide (SILC system, that is)
1087 settings and chooses from those. However, if other properties
1088 should be used this function is easy to replace by another function,
1089 as, this function is called by the caller of the protocol and not
1090 by the protocol itself. */
1093 silc_ske_assemble_security_properties(SilcSKE ske,
1094 unsigned char flags,
1096 SilcSKEStartPayload **return_payload)
1098 SilcSKEStartPayload *rp;
1101 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1103 rp = silc_calloc(1, sizeof(*rp));
1108 /* Set random cookie */
1109 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1110 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1111 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1112 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1115 rp->version = strdup(version);
1116 rp->version_len = strlen(version);
1118 /* Get supported Key Exhange groups */
1119 rp->ke_grp_list = silc_ske_get_supported_groups();
1120 rp->ke_grp_len = strlen(rp->ke_grp_list);
1122 /* Get supported PKCS algorithms */
1123 rp->pkcs_alg_list = silc_pkcs_get_supported();
1124 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1126 /* Get supported encryption algorithms */
1127 rp->enc_alg_list = silc_cipher_get_supported();
1128 rp->enc_alg_len = strlen(rp->enc_alg_list);
1130 /* Get supported hash algorithms */
1131 rp->hash_alg_list = silc_hash_get_supported();
1132 rp->hash_alg_len = strlen(rp->hash_alg_list);
1134 /* Get supported HMACs */
1135 rp->hmac_alg_list = silc_hmac_get_supported();
1136 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1139 /* Get supported compression algorithms */
1140 rp->comp_alg_list = strdup("");
1141 rp->comp_alg_len = 0;
1143 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1144 2 + rp->version_len +
1145 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1146 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1147 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1149 *return_payload = rp;
1151 return SILC_SKE_STATUS_OK;
1154 /* Selects the supported security properties from the remote end's Key
1155 Exchange Start Payload. */
1158 silc_ske_select_security_properties(SilcSKE ske,
1160 SilcSKEStartPayload *payload,
1161 SilcSKEStartPayload *remote_payload)
1163 SilcSKEStatus status;
1164 SilcSKEStartPayload *rp;
1168 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1170 rp = remote_payload;
1172 /* Check version string */
1173 if (ske->callbacks->check_version) {
1174 status = ske->callbacks->check_version(ske, rp->version,
1176 ske->callbacks->context);
1177 if (status != SILC_SKE_STATUS_OK) {
1178 ske->status = status;
1183 /* Flags are returned unchanged. */
1184 payload->flags = rp->flags;
1186 /* Take cookie, we must return it to sender unmodified. */
1187 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1188 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1189 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1191 /* Put our version to our reply */
1192 payload->version = strdup(version);
1193 payload->version_len = strlen(version);
1195 /* Get supported Key Exchange groups */
1196 cp = rp->ke_grp_list;
1197 if (cp && strchr(cp, ',')) {
1201 len = strcspn(cp, ",");
1202 item = silc_calloc(len + 1, sizeof(char));
1203 memcpy(item, cp, len);
1205 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1207 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1208 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1210 payload->ke_grp_len = len;
1211 payload->ke_grp_list = item;
1216 if (strlen(cp) == 0)
1225 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1226 SILC_LOG_DEBUG(("Could not find supported KE group"));
1228 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1232 if (!rp->ke_grp_len) {
1233 SILC_LOG_DEBUG(("KE group not defined in payload"));
1235 return SILC_SKE_STATUS_BAD_PAYLOAD;
1238 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1239 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1241 payload->ke_grp_len = rp->ke_grp_len;
1242 payload->ke_grp_list = strdup(rp->ke_grp_list);
1245 /* Get supported PKCS algorithms */
1246 cp = rp->pkcs_alg_list;
1247 if (cp && strchr(cp, ',')) {
1251 len = strcspn(cp, ",");
1252 item = silc_calloc(len + 1, sizeof(char));
1253 memcpy(item, cp, len);
1255 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1257 if (silc_pkcs_is_supported(item) == TRUE) {
1258 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1260 payload->pkcs_alg_len = len;
1261 payload->pkcs_alg_list = item;
1266 if (strlen(cp) == 0)
1275 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1276 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1277 silc_free(payload->ke_grp_list);
1279 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1283 if (!rp->pkcs_alg_len) {
1284 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1285 silc_free(payload->ke_grp_list);
1287 return SILC_SKE_STATUS_BAD_PAYLOAD;
1290 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1291 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1293 payload->pkcs_alg_len = rp->pkcs_alg_len;
1294 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1297 /* Get supported encryption algorithms */
1298 cp = rp->enc_alg_list;
1299 if (cp && strchr(cp, ',')) {
1303 len = strcspn(cp, ",");
1304 item = silc_calloc(len + 1, sizeof(char));
1305 memcpy(item, cp, len);
1307 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1309 if (silc_cipher_is_supported(item) == TRUE) {
1310 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1312 payload->enc_alg_len = len;
1313 payload->enc_alg_list = item;
1318 if (strlen(cp) == 0)
1327 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1328 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1329 silc_free(payload->ke_grp_list);
1330 silc_free(payload->pkcs_alg_list);
1332 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1336 if (!rp->enc_alg_len) {
1337 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1338 silc_free(payload->ke_grp_list);
1339 silc_free(payload->pkcs_alg_list);
1341 return SILC_SKE_STATUS_BAD_PAYLOAD;
1344 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1347 payload->enc_alg_len = rp->enc_alg_len;
1348 payload->enc_alg_list = strdup(rp->enc_alg_list);
1351 /* Get supported hash algorithms */
1352 cp = rp->hash_alg_list;
1353 if (cp && strchr(cp, ',')) {
1357 len = strcspn(cp, ",");
1358 item = silc_calloc(len + 1, sizeof(char));
1359 memcpy(item, cp, len);
1361 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1363 if (silc_hash_is_supported(item) == TRUE) {
1364 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1366 payload->hash_alg_len = len;
1367 payload->hash_alg_list = item;
1372 if (strlen(cp) == 0)
1381 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1382 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1383 silc_free(payload->ke_grp_list);
1384 silc_free(payload->pkcs_alg_list);
1385 silc_free(payload->enc_alg_list);
1387 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1391 if (!rp->hash_alg_len) {
1392 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1393 silc_free(payload->ke_grp_list);
1394 silc_free(payload->pkcs_alg_list);
1395 silc_free(payload->enc_alg_list);
1397 return SILC_SKE_STATUS_BAD_PAYLOAD;
1400 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1401 rp->hash_alg_list));
1403 payload->hash_alg_len = rp->hash_alg_len;
1404 payload->hash_alg_list = strdup(rp->hash_alg_list);
1407 /* Get supported HMACs */
1408 cp = rp->hmac_alg_list;
1409 if (cp && strchr(cp, ',')) {
1413 len = strcspn(cp, ",");
1414 item = silc_calloc(len + 1, sizeof(char));
1415 memcpy(item, cp, len);
1417 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1419 if (silc_hmac_is_supported(item) == TRUE) {
1420 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1422 payload->hmac_alg_len = len;
1423 payload->hmac_alg_list = item;
1428 if (strlen(cp) == 0)
1437 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1438 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1439 silc_free(payload->ke_grp_list);
1440 silc_free(payload->pkcs_alg_list);
1441 silc_free(payload->enc_alg_list);
1442 silc_free(payload->hash_alg_list);
1444 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1448 if (!rp->hmac_alg_len) {
1449 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1450 silc_free(payload->ke_grp_list);
1451 silc_free(payload->pkcs_alg_list);
1452 silc_free(payload->enc_alg_list);
1453 silc_free(payload->hash_alg_list);
1455 return SILC_SKE_STATUS_BAD_PAYLOAD;
1458 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1459 rp->hmac_alg_list));
1461 payload->hmac_alg_len = rp->hmac_alg_len;
1462 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1466 /* Get supported compression algorithms */
1467 cp = rp->hash_alg_list;
1468 if (cp && strchr(cp, ',')) {
1472 len = strcspn(cp, ",");
1473 item = silc_calloc(len + 1, sizeof(char));
1474 memcpy(item, cp, len);
1476 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1478 if (silc_hash_is_supported(item) == TRUE) {
1479 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1481 payload->hash_alg_len = len;
1482 payload->hash_alg_list = item;
1487 if (strlen(cp) == 0)
1496 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1497 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1498 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1499 silc_free(payload->ke_grp_list);
1500 silc_free(payload->pkcs_alg_list);
1501 silc_free(payload->enc_alg_list);
1510 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1511 2 + payload->version_len +
1512 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1513 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1514 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1516 return SILC_SKE_STATUS_OK;
1519 /* Creates random number such that 1 < rnd < n and at most length
1520 of len bits. The rnd sent as argument must be initialized. */
1522 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
1526 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1527 unsigned char *string;
1529 SILC_LOG_DEBUG(("Creating random number"));
1531 /* Get the random number as string */
1532 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1534 return SILC_SKE_STATUS_ERROR;
1536 /* Decode the string into a MP integer */
1537 silc_mp_bin2mp(string, (len / 8), rnd);
1538 silc_mp_mod_2exp(rnd, rnd, len);
1541 if (silc_mp_cmp_ui(rnd, 1) < 0)
1542 status = SILC_SKE_STATUS_ERROR;
1544 if (silc_mp_cmp(rnd, n) >= 0)
1545 status = SILC_SKE_STATUS_ERROR;
1547 memset(string, 'F', (len / 8));
1553 /* Creates a hash value HASH as defined in the SKE protocol. If the
1554 `initiator' is TRUE then this function is used to create the HASH_i
1555 hash value defined in the protocol. If it is FALSE then this is used
1556 to create the HASH value defined by the protocol. */
1558 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1559 unsigned char *return_hash,
1560 uint32 *return_hash_len,
1563 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1565 unsigned char *e, *f, *KEY;
1566 uint32 e_len, f_len, KEY_len;
1569 SILC_LOG_DEBUG(("Start"));
1571 if (initiator == FALSE) {
1572 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1573 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1574 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1576 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1577 ske->ke2_payload->pk_len + e_len +
1579 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1581 /* Format the buffer used to compute the hash value */
1583 silc_buffer_format(buf,
1584 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1585 ske->start_payload_copy->len),
1586 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1587 ske->ke2_payload->pk_len),
1588 SILC_STR_UI_XNSTRING(e, e_len),
1589 SILC_STR_UI_XNSTRING(f, f_len),
1590 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1593 silc_buffer_free(buf);
1594 memset(e, 0, e_len);
1595 memset(f, 0, f_len);
1596 memset(KEY, 0, KEY_len);
1600 return SILC_SKE_STATUS_ERROR;
1603 memset(e, 0, e_len);
1604 memset(f, 0, f_len);
1605 memset(KEY, 0, KEY_len);
1610 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1612 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1613 ske->ke1_payload->pk_len + e_len);
1614 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1616 /* Format the buffer used to compute the hash value */
1618 silc_buffer_format(buf,
1619 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1620 ske->start_payload_copy->len),
1621 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1622 ske->ke1_payload->pk_len),
1623 SILC_STR_UI_XNSTRING(e, e_len),
1626 silc_buffer_free(buf);
1627 memset(e, 0, e_len);
1629 return SILC_SKE_STATUS_ERROR;
1632 memset(e, 0, e_len);
1637 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1638 *return_hash_len = ske->prop->hash->hash->hash_len;
1640 if (initiator == FALSE) {
1641 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1643 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1646 silc_buffer_free(buf);
1651 /* Processes the provided key material `data' as the SILC protocol
1652 specification defines. */
1655 silc_ske_process_key_material_data(unsigned char *data,
1658 uint32 req_enc_key_len,
1659 uint32 req_hmac_key_len,
1661 SilcSKEKeyMaterial *key)
1664 unsigned char hashd[32];
1665 uint32 hash_len = req_hmac_key_len;
1666 uint32 enc_key_len = req_enc_key_len / 8;
1668 SILC_LOG_DEBUG(("Start"));
1670 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1671 return SILC_SKE_STATUS_ERROR;
1673 buf = silc_buffer_alloc(1 + data_len);
1674 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1675 silc_buffer_format(buf,
1676 SILC_STR_UI_CHAR(0),
1677 SILC_STR_UI_XNSTRING(data, data_len),
1681 memset(hashd, 0, sizeof(hashd));
1683 silc_hash_make(hash, buf->data, buf->len, hashd);
1684 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1685 memcpy(key->send_iv, hashd, req_iv_len);
1686 memset(hashd, 0, sizeof(hashd));
1688 silc_hash_make(hash, buf->data, buf->len, hashd);
1689 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1690 memcpy(key->receive_iv, hashd, req_iv_len);
1691 key->iv_len = req_iv_len;
1693 /* Take the encryption keys. If requested key size is more than
1694 the size of hash length we will distribute more key material
1695 as protocol defines. */
1697 if (enc_key_len > hash_len) {
1699 unsigned char k1[32], k2[32], k3[32];
1700 unsigned char *dtmp;
1703 if (enc_key_len > (3 * hash_len))
1704 return SILC_SKE_STATUS_ERROR;
1706 /* Take first round */
1707 memset(k1, 0, sizeof(k1));
1708 silc_hash_make(hash, buf->data, buf->len, k1);
1710 /* Take second round */
1711 dist = silc_buffer_alloc(data_len + hash_len);
1712 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1713 silc_buffer_format(dist,
1714 SILC_STR_UI_XNSTRING(data, data_len),
1715 SILC_STR_UI_XNSTRING(k1, hash_len),
1717 memset(k2, 0, sizeof(k2));
1718 silc_hash_make(hash, dist->data, dist->len, k2);
1720 /* Take third round */
1721 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1722 silc_buffer_pull_tail(dist, hash_len);
1723 silc_buffer_pull(dist, data_len + hash_len);
1724 silc_buffer_format(dist,
1725 SILC_STR_UI_XNSTRING(k2, hash_len),
1727 silc_buffer_push(dist, data_len + hash_len);
1728 memset(k3, 0, sizeof(k3));
1729 silc_hash_make(hash, dist->data, dist->len, k3);
1731 /* Then, save the keys */
1732 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1733 memcpy(dtmp, k1, hash_len);
1734 memcpy(dtmp + hash_len, k2, hash_len);
1735 memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1737 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1738 memcpy(key->send_enc_key, dtmp, enc_key_len);
1739 key->enc_key_len = req_enc_key_len;
1741 memset(dtmp, 0, (3 * hash_len));
1742 memset(k1, 0, sizeof(k1));
1743 memset(k2, 0, sizeof(k2));
1744 memset(k3, 0, sizeof(k3));
1746 silc_buffer_free(dist);
1748 /* Take normal hash as key */
1749 memset(hashd, 0, sizeof(hashd));
1750 silc_hash_make(hash, buf->data, buf->len, hashd);
1751 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1752 memcpy(key->send_enc_key, hashd, enc_key_len);
1753 key->enc_key_len = req_enc_key_len;
1757 if (enc_key_len > hash_len) {
1759 unsigned char k1[32], k2[32], k3[32];
1760 unsigned char *dtmp;
1763 if (enc_key_len > (3 * hash_len))
1764 return SILC_SKE_STATUS_ERROR;
1766 /* Take first round */
1767 memset(k1, 0, sizeof(k1));
1768 silc_hash_make(hash, buf->data, buf->len, k1);
1770 /* Take second round */
1771 dist = silc_buffer_alloc(data_len + hash_len);
1772 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1773 silc_buffer_format(dist,
1774 SILC_STR_UI_XNSTRING(data, data_len),
1775 SILC_STR_UI_XNSTRING(k1, hash_len),
1777 memset(k2, 0, sizeof(k2));
1778 silc_hash_make(hash, dist->data, dist->len, k2);
1780 /* Take third round */
1781 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1782 silc_buffer_pull_tail(dist, hash_len);
1783 silc_buffer_pull(dist, data_len + hash_len);
1784 silc_buffer_format(dist,
1785 SILC_STR_UI_XNSTRING(k2, hash_len),
1787 silc_buffer_push(dist, data_len + hash_len);
1788 memset(k3, 0, sizeof(k3));
1789 silc_hash_make(hash, dist->data, dist->len, k3);
1791 /* Then, save the keys */
1792 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1793 memcpy(dtmp, k1, hash_len);
1794 memcpy(dtmp + hash_len, k2, hash_len);
1795 memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1797 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1798 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1799 key->enc_key_len = req_enc_key_len;
1801 memset(dtmp, 0, (3 * hash_len));
1802 memset(k1, 0, sizeof(k1));
1803 memset(k2, 0, sizeof(k2));
1804 memset(k3, 0, sizeof(k3));
1806 silc_buffer_free(dist);
1808 /* Take normal hash as key */
1809 memset(hashd, 0, sizeof(hashd));
1810 silc_hash_make(hash, buf->data, buf->len, hashd);
1811 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1812 memcpy(key->receive_enc_key, hashd, enc_key_len);
1813 key->enc_key_len = req_enc_key_len;
1816 /* Take HMAC keys */
1817 memset(hashd, 0, sizeof(hashd));
1819 silc_hash_make(hash, buf->data, buf->len, hashd);
1820 key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1821 memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
1822 memset(hashd, 0, sizeof(hashd));
1824 silc_hash_make(hash, buf->data, buf->len, hashd);
1825 key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1826 memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
1827 key->hmac_key_len = req_hmac_key_len;
1828 memset(hashd, 0, sizeof(hashd));
1830 silc_buffer_free(buf);
1832 return SILC_SKE_STATUS_OK;
1835 /* Processes negotiated key material as protocol specifies. This returns
1836 the actual keys to be used in the SILC. */
1838 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1840 uint32 req_enc_key_len,
1841 uint32 req_hmac_key_len,
1842 SilcSKEKeyMaterial *key)
1844 SilcSKEStatus status;
1846 unsigned char *tmpbuf;
1849 /* Encode KEY to binary data */
1850 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1852 buf = silc_buffer_alloc(klen + ske->hash_len);
1853 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1854 silc_buffer_format(buf,
1855 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1856 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1859 /* Process the key material */
1860 status = silc_ske_process_key_material_data(buf->data, buf->len,
1861 req_iv_len, req_enc_key_len,
1863 ske->prop->hash, key);
1865 /* Backwards support for old MAC keys */
1866 /* XXX Remove in 0.7.x */
1867 if (ske->backward_version == 1) {
1868 silc_free(key->receive_hmac_key);
1869 key->receive_hmac_key = silc_calloc(1, sizeof(*key->receive_hmac_key));
1870 memcpy(key->receive_hmac_key, key->send_hmac_key, key->hmac_key_len);
1873 memset(tmpbuf, 0, klen);
1875 silc_buffer_free(buf);
1880 /* Free key material structure */
1882 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1888 silc_free(key->send_iv);
1889 if (key->receive_iv)
1890 silc_free(key->receive_iv);
1891 if (key->send_enc_key) {
1892 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1893 silc_free(key->send_enc_key);
1895 if (key->receive_enc_key) {
1896 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1897 silc_free(key->receive_enc_key);
1899 if (key->send_hmac_key) {
1900 memset(key->send_hmac_key, 0, key->hmac_key_len);
1901 silc_free(key->send_hmac_key);
1903 if (key->receive_hmac_key) {
1904 memset(key->receive_hmac_key, 0, key->hmac_key_len);
1905 silc_free(key->receive_hmac_key);
1910 const char *silc_ske_status_string[] =
1914 "Unkown error occurred",
1915 "Bad payload in packet",
1916 "Unsupported group",
1917 "Unsupported cipher",
1919 "Unsupported hash function",
1921 "Unsupported public key (or certificate)",
1922 "Incorrect signature",
1923 "Bad or unsupported version",
1928 "Remote did not provide public key",
1929 "Key exchange protocol is not active",
1930 "Bad reserved field in packet",
1931 "Bad payload length in packet",
1937 /* Maps status to readable string and returns the string. If string is not
1938 found and empty character string ("") is returned. */
1940 const char *silc_ske_map_status(SilcSKEStatus status)
1944 for (i = 0; silc_ske_status_string[i]; i++)
1946 return silc_ske_status_string[i];