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.
164 The packet sending is done by calling a callback function. Caller
165 must provide a routine to send the packet. */
167 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
168 SilcSocketConnection sock,
169 SilcSKEStartPayload *start_payload)
171 SilcSKEStatus status = SILC_SKE_STATUS_OK;
172 SilcBuffer payload_buf;
174 SILC_LOG_DEBUG(("Start"));
179 /* Encode the payload */
180 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
181 if (status != SILC_SKE_STATUS_OK)
184 /* Take a copy of the payload buffer for future use. It is used to
185 compute the HASH value. */
186 ske->start_payload_copy = silc_buffer_copy(payload_buf);
188 /* Send the packet. */
189 if (ske->callbacks->send_packet)
190 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
191 ske->callbacks->context);
193 silc_buffer_free(payload_buf);
198 /* Function called after ske_initiator_start fuction. This receives
199 the remote ends Key Exchange Start payload which includes the
200 security properties selected by the responder from our payload
201 sent in the silc_ske_initiator_start function. */
203 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
204 SilcBuffer start_payload)
206 SilcSKEStatus status = SILC_SKE_STATUS_OK;
207 SilcSKEStartPayload *payload;
208 SilcSKESecurityProperties prop;
209 SilcSKEDiffieHellmanGroup group;
211 SILC_LOG_DEBUG(("Start"));
213 /* Decode the payload */
214 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
215 if (status != SILC_SKE_STATUS_OK) {
216 ske->status = status;
220 /* Take the selected security properties into use while doing
221 the key exchange. This is used only while doing the key
222 exchange. The same data is returned to upper levels by calling
223 the callback function. */
224 ske->prop = prop = silc_calloc(1, sizeof(*prop));
225 prop->flags = payload->flags;
226 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
227 if (status != SILC_SKE_STATUS_OK)
232 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
233 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
237 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
238 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
242 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
243 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
247 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
248 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
252 ske->start_payload = payload;
254 /* Return the received payload by calling the callback function. */
255 if (ske->callbacks->payload_receive)
256 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
262 silc_ske_payload_start_free(payload);
267 silc_pkcs_free(prop->pkcs);
269 silc_cipher_free(prop->cipher);
271 silc_hash_free(prop->hash);
273 silc_hmac_free(prop->hmac);
277 if (status == SILC_SKE_STATUS_OK)
278 return SILC_SKE_STATUS_ERROR;
280 ske->status = status;
284 /* This function creates random number x, such that 1 < x < q and
285 computes e = g ^ x mod p and sends the result to the remote end in
286 Key Exchange Payload. */
288 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
289 SilcPublicKey public_key,
290 SilcPrivateKey private_key)
292 SilcSKEStatus status = SILC_SKE_STATUS_OK;
293 SilcBuffer payload_buf;
295 SilcSKEKEPayload *payload;
298 SILC_LOG_DEBUG(("Start"));
300 /* Create the random number x, 1 < x < q. */
301 x = silc_calloc(1, sizeof(*x));
304 silc_ske_create_rnd(ske, ske->prop->group->group_order,
305 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
307 if (status != SILC_SKE_STATUS_OK) {
310 ske->status = status;
314 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
316 /* Do the Diffie Hellman computation, e = g ^ x mod p */
318 silc_mp_pow_mod(&e, &ske->prop->group->generator, x,
319 &ske->prop->group->group);
321 /* Encode the result to Key Exchange Payload. */
323 payload = silc_calloc(1, sizeof(*payload));
324 ske->ke1_payload = payload;
330 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
331 if (!payload->pk_data) {
336 ske->status = SILC_SKE_STATUS_OK;
339 payload->pk_len = pk_len;
341 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
343 /* Compute signature data if we are doing mutual authentication */
344 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
345 unsigned char hash[32], sign[1024];
346 uint32 hash_len, sign_len;
348 SILC_LOG_DEBUG(("We are doing mutual authentication"));
349 SILC_LOG_DEBUG(("Computing HASH_i value"));
351 /* Compute the hash value */
352 memset(hash, 0, sizeof(hash));
353 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
355 SILC_LOG_DEBUG(("Signing HASH_i value"));
357 /* Sign the hash value */
358 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
359 private_key->prv_len);
360 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
361 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
362 memcpy(payload->sign_data, sign, sign_len);
363 memset(sign, 0, sizeof(sign));
364 payload->sign_len = sign_len;
367 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
368 if (status != SILC_SKE_STATUS_OK) {
372 silc_free(payload->pk_data);
374 ske->status = status;
380 /* Send the packet. */
381 if (ske->callbacks->send_packet)
382 (*ske->callbacks->send_packet)(ske, payload_buf,
383 SILC_PACKET_KEY_EXCHANGE_1,
384 ske->callbacks->context);
386 silc_buffer_free(payload_buf);
391 /* An initiator finish final callback that is called to indicate that
392 the SKE protocol may continue. */
394 static void silc_ske_initiator_finish_final(SilcSKE ske,
395 SilcSKEStatus status,
398 SilcSKEKEPayload *payload;
399 unsigned char hash[32];
401 SilcPublicKey public_key = NULL;
403 /* If the SKE was freed during the async call then free it really now,
404 otherwise just decrement the reference counter. */
405 if (ske->status == SILC_SKE_STATUS_FREED) {
412 payload = ske->ke2_payload;
414 /* If the caller returns PENDING status SKE library will assume that
415 the caller will re-call this callback when it is not anymore in
417 if (status == SILC_SKE_STATUS_PENDING)
420 /* If the status is an error then the public key that was verified
421 by the caller is not authentic. */
422 if (status != SILC_SKE_STATUS_OK) {
423 ske->status = status;
424 if (ske->callbacks->proto_continue)
425 ske->callbacks->proto_continue(ske, ske->callbacks->context);
429 if (payload->pk_data) {
430 /* Decode the public key */
431 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
433 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
434 if (ske->callbacks->proto_continue)
435 ske->callbacks->proto_continue(ske, ske->callbacks->context);
439 SILC_LOG_DEBUG(("Public key is authentic"));
441 /* Compute the hash value */
442 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
443 if (status != SILC_SKE_STATUS_OK)
446 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
447 memcpy(ske->hash, hash, hash_len);
448 ske->hash_len = hash_len;
450 SILC_LOG_DEBUG(("Verifying signature (HASH)"));
452 /* Verify signature */
453 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
454 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
455 payload->sign_len, hash, hash_len) == FALSE) {
457 SILC_LOG_DEBUG(("Signature don't match"));
459 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
463 SILC_LOG_DEBUG(("Signature is Ok"));
465 silc_pkcs_public_key_free(public_key);
466 memset(hash, 'F', hash_len);
469 ske->status = SILC_SKE_STATUS_OK;
471 /* Call the callback. The caller may now continue the SKE protocol. */
472 if (ske->callbacks->proto_continue)
473 ske->callbacks->proto_continue(ske, ske->callbacks->context);
478 memset(hash, 'F', sizeof(hash));
479 silc_ske_payload_ke_free(payload);
480 ske->ke2_payload = NULL;
482 silc_mp_uninit(ske->KEY);
487 silc_pkcs_public_key_free(public_key);
490 memset(ske->hash, 'F', hash_len);
491 silc_free(ske->hash);
495 if (status == SILC_SKE_STATUS_OK)
496 ske->status = SILC_SKE_STATUS_ERROR;
498 ske->status = status;
500 /* Call the callback. */
501 if (ske->callbacks->proto_continue)
502 ske->callbacks->proto_continue(ske, ske->callbacks->context);
505 /* Receives Key Exchange Payload from responder consisting responders
506 public key, f, and signature. This function verifies the public key,
507 computes the secret shared key and verifies the signature.
509 The `callback' will be called to indicate that the caller may
510 continue with the SKE protocol. The caller must not continue
511 before the SKE libary has called that callback. If this function
512 returns an error the callback will not be called. It is called
513 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
514 However, note that when the library calls the callback the ske->status
517 This calls the `verify_key' callback to verify the received public
518 key or certificate. If the `verify_key' is provided then the remote
519 must send public key and it is considered to be an error if remote
520 does not send its public key. If caller is performing a re-key with
521 SKE then the `verify_key' is usually not provided when it is not also
522 required for the remote to send its public key. */
524 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
525 SilcBuffer ke_payload)
527 SilcSKEStatus status = SILC_SKE_STATUS_OK;
528 SilcSKEKEPayload *payload;
531 SILC_LOG_DEBUG(("Start"));
533 /* Decode the payload */
534 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
535 if (status != SILC_SKE_STATUS_OK) {
536 ske->status = status;
539 ske->ke2_payload = payload;
541 if (!payload->pk_data && ske->callbacks->verify_key) {
542 SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
543 "even though we require it"));
544 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
548 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
550 /* Compute the shared secret key */
551 KEY = silc_calloc(1, sizeof(*KEY));
553 silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
556 if (payload->pk_data && ske->callbacks->verify_key) {
557 SILC_LOG_DEBUG(("Verifying public key"));
560 (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
561 payload->pk_type, ske->callbacks->context,
562 silc_ske_initiator_finish_final, NULL);
564 /* We will continue to the final state after the public key has
565 been verified by the caller. */
566 return SILC_SKE_STATUS_PENDING;
569 /* Continue to final state */
570 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
572 return SILC_SKE_STATUS_OK;
575 silc_ske_payload_ke_free(payload);
576 ske->ke2_payload = NULL;
578 silc_mp_uninit(ske->KEY);
582 if (status == SILC_SKE_STATUS_OK)
583 return SILC_SKE_STATUS_ERROR;
585 ske->status = status;
589 /* Starts Key Exchange protocol for responder. Responder receives
590 Key Exchange Start Payload from initiator consisting of all the
591 security properties the initiator supports. This function decodes
592 the payload and parses the payload further and selects the right
593 security properties. */
595 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
596 SilcSocketConnection sock,
598 SilcBuffer start_payload,
601 SilcSKEStatus status = SILC_SKE_STATUS_OK;
602 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
604 SILC_LOG_DEBUG(("Start"));
609 /* Decode the payload */
610 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
611 if (status != SILC_SKE_STATUS_OK) {
612 ske->status = status;
616 /* Take a copy of the payload buffer for future use. It is used to
617 compute the HASH value. */
618 ske->start_payload_copy = silc_buffer_copy(start_payload);
620 /* Force the mutual authentication flag if we want to do it. */
622 SILC_LOG_DEBUG(("Force mutual authentication"));
623 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
626 /* Parse and select the security properties from the payload */
627 payload = silc_calloc(1, sizeof(*payload));
628 status = silc_ske_select_security_properties(ske, version,
629 payload, remote_payload);
630 if (status != SILC_SKE_STATUS_OK)
633 ske->start_payload = payload;
635 /* Call the callback function. */
636 if (ske->callbacks->payload_receive)
637 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
643 silc_ske_payload_start_free(remote_payload);
647 if (status == SILC_SKE_STATUS_OK)
648 return SILC_SKE_STATUS_ERROR;
650 ske->status = status;
654 /* The selected security properties from the initiator payload is now
655 encoded into Key Exchange Start Payload and sent to the initiator. */
657 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
658 SilcSKEStartPayload *start_payload)
660 SilcSKEStatus status = SILC_SKE_STATUS_OK;
661 SilcBuffer payload_buf;
662 SilcSKESecurityProperties prop;
663 SilcSKEDiffieHellmanGroup group = NULL;
665 SILC_LOG_DEBUG(("Start"));
667 /* Allocate security properties from the payload. These are allocated
668 only for this negotiation and will be free'd after KE is over. */
669 ske->prop = prop = silc_calloc(1, sizeof(*prop));
670 prop->flags = start_payload->flags;
671 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
672 if (status != SILC_SKE_STATUS_OK)
677 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
678 &prop->pkcs) == FALSE) {
679 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
683 if (silc_cipher_alloc(start_payload->enc_alg_list,
684 &prop->cipher) == FALSE) {
685 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
689 if (silc_hash_alloc(start_payload->hash_alg_list,
690 &prop->hash) == FALSE) {
691 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
695 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
696 &prop->hmac) == FALSE) {
697 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
701 /* Encode the payload */
702 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
703 if (status != SILC_SKE_STATUS_OK)
706 /* Send the packet. */
707 if (ske->callbacks->send_packet)
708 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
709 ske->callbacks->context);
711 silc_buffer_free(payload_buf);
720 silc_pkcs_free(prop->pkcs);
722 silc_cipher_free(prop->cipher);
724 silc_hash_free(prop->hash);
726 silc_hmac_free(prop->hmac);
730 if (status == SILC_SKE_STATUS_OK)
731 return SILC_SKE_STATUS_ERROR;
733 ske->status = status;
737 /* An responder phase 2 final callback that is called to indicate that
738 the SKE protocol may continue. */
740 static void silc_ske_responder_phase2_final(SilcSKE ske,
741 SilcSKEStatus status,
744 SilcSKEKEPayload *recv_payload, *send_payload;
747 /* If the SKE was freed during the async call then free it really now,
748 otherwise just decrement the reference counter. */
749 if (ske->status == SILC_SKE_STATUS_FREED) {
756 recv_payload = ske->ke1_payload;
758 /* If the caller returns PENDING status SKE library will assume that
759 the caller will re-call this callback when it is not anymore in
761 if (status == SILC_SKE_STATUS_PENDING)
764 /* If the status is an error then the public key that was verified
765 by the caller is not authentic. */
766 if (status != SILC_SKE_STATUS_OK) {
767 ske->status = status;
768 if (ske->callbacks->proto_continue)
769 ske->callbacks->proto_continue(ske, ske->callbacks->context);
773 /* The public key verification was performed only if the Mutual
774 Authentication flag is set. */
775 if (ske->start_payload &&
776 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
777 SilcPublicKey public_key = NULL;
778 unsigned char hash[32];
781 /* Decode the public key */
782 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
783 recv_payload->pk_len,
785 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
786 if (ske->callbacks->proto_continue)
787 ske->callbacks->proto_continue(ske, ske->callbacks->context);
791 SILC_LOG_DEBUG(("Public key is authentic"));
793 /* Compute the hash value */
794 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
795 if (status != SILC_SKE_STATUS_OK) {
796 ske->status = status;
797 if (ske->callbacks->proto_continue)
798 ske->callbacks->proto_continue(ske, ske->callbacks->context);
802 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
804 /* Verify signature */
805 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
806 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
807 recv_payload->sign_len, hash, hash_len) == FALSE) {
809 SILC_LOG_DEBUG(("Signature don't match"));
811 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
812 if (ske->callbacks->proto_continue)
813 ske->callbacks->proto_continue(ske, ske->callbacks->context);
817 SILC_LOG_DEBUG(("Signature is Ok"));
819 silc_pkcs_public_key_free(public_key);
820 memset(hash, 'F', hash_len);
823 /* Create the random number x, 1 < x < q. */
824 x = silc_calloc(1, sizeof(*x));
827 silc_ske_create_rnd(ske, ske->prop->group->group_order,
828 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
830 if (status != SILC_SKE_STATUS_OK) {
833 ske->status = status;
834 if (ske->callbacks->proto_continue)
835 ske->callbacks->proto_continue(ske, ske->callbacks->context);
839 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
841 /* Do the Diffie Hellman computation, f = g ^ x mod p */
843 silc_mp_pow_mod(&f, &ske->prop->group->generator, x,
844 &ske->prop->group->group);
846 /* Save the results for later processing */
847 send_payload = silc_calloc(1, sizeof(*send_payload));
850 ske->ke2_payload = send_payload;
852 /* Call the callback. The caller may now continue with the SKE protocol. */
853 ske->status = SILC_SKE_STATUS_OK;
854 if (ske->callbacks->proto_continue)
855 ske->callbacks->proto_continue(ske, ske->callbacks->context);
858 /* This function receives the Key Exchange Payload from the initiator.
859 This also performs the mutual authentication if required. Then, this
860 function first generated a random number x, such that 1 < x < q
861 and computes f = g ^ x mod p. This then puts the result f to a Key
864 The `callback' will be called to indicate that the caller may
865 continue with the SKE protocol. The caller must not continue
866 before the SKE libary has called that callback. If this function
867 returns an error the callback will not be called. It is called
868 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
869 However, note that when the library calls the callback the ske->status
872 This calls the `verify_key' callback to verify the received public
873 key or certificate if the Mutual Authentication flag is set. If the
874 `verify_key' is provided then the remote must send public key and it
875 is considered to be an error if remote does not send its public key. */
877 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
878 SilcBuffer ke_payload)
880 SilcSKEStatus status = SILC_SKE_STATUS_OK;
881 SilcSKEKEPayload *recv_payload;
883 SILC_LOG_DEBUG(("Start"));
885 /* Decode Key Exchange Payload */
886 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
887 if (status != SILC_SKE_STATUS_OK) {
888 ske->status = status;
892 ske->ke1_payload = recv_payload;
894 /* Verify the received public key and verify the signature if we are
895 doing mutual authentication. */
896 if (ske->start_payload &&
897 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
899 SILC_LOG_DEBUG(("We are doing mutual authentication"));
901 if (!recv_payload->pk_data && ske->callbacks->verify_key) {
902 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
903 "certificate), even though we require it"));
904 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
908 if (recv_payload->pk_data && ske->callbacks->verify_key) {
909 SILC_LOG_DEBUG(("Verifying public key"));
912 (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
913 recv_payload->pk_len,
914 recv_payload->pk_type,
915 ske->callbacks->context,
916 silc_ske_responder_phase2_final, NULL);
918 /* We will continue to the final state after the public key has
919 been verified by the caller. */
920 return SILC_SKE_STATUS_PENDING;
924 /* Continue to final state */
925 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
927 return SILC_SKE_STATUS_OK;
930 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
931 value to be signed and sent to the other end. This then encodes Key
932 Exchange Payload and sends it to the other end. */
934 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
935 SilcPublicKey public_key,
936 SilcPrivateKey private_key,
937 SilcSKEPKType pk_type)
939 SilcSKEStatus status = SILC_SKE_STATUS_OK;
940 SilcBuffer payload_buf;
942 unsigned char hash[32], sign[1024], *pk;
943 uint32 hash_len, sign_len, pk_len;
945 SILC_LOG_DEBUG(("Start"));
947 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
949 /* Compute the shared secret key */
950 KEY = silc_calloc(1, sizeof(*KEY));
952 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
953 &ske->prop->group->group);
956 if (public_key && private_key) {
957 SILC_LOG_DEBUG(("Getting public key"));
959 /* Get the public key */
960 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
962 status = SILC_SKE_STATUS_ERROR;
965 ske->ke2_payload->pk_data = pk;
966 ske->ke2_payload->pk_len = pk_len;
968 SILC_LOG_DEBUG(("Computing HASH value"));
970 /* Compute the hash value */
971 memset(hash, 0, sizeof(hash));
972 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
973 if (status != SILC_SKE_STATUS_OK)
976 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
977 memcpy(ske->hash, hash, hash_len);
978 ske->hash_len = hash_len;
980 SILC_LOG_DEBUG(("Signing HASH value"));
982 /* Sign the hash value */
983 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
984 private_key->prv_len);
985 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
986 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
987 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
988 memset(sign, 0, sizeof(sign));
989 ske->ke2_payload->sign_len = sign_len;
991 ske->ke2_payload->pk_type = pk_type;
993 /* Encode the Key Exchange Payload */
994 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
996 if (status != SILC_SKE_STATUS_OK)
999 /* Send the packet. */
1000 if (ske->callbacks->send_packet)
1001 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2,
1002 ske->callbacks->context);
1004 silc_buffer_free(payload_buf);
1009 silc_mp_uninit(ske->KEY);
1010 silc_free(ske->KEY);
1012 silc_ske_payload_ke_free(ske->ke2_payload);
1014 if (status == SILC_SKE_STATUS_OK)
1015 return SILC_SKE_STATUS_ERROR;
1017 ske->status = status;
1021 /* The Key Exchange protocol is ended by calling this function. This
1022 must not be called until the keys are processed like the protocol
1023 defines. This function is for both initiator and responder. */
1025 SilcSKEStatus silc_ske_end(SilcSKE ske)
1029 SILC_LOG_DEBUG(("Start"));
1031 packet = silc_buffer_alloc(4);
1032 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1033 silc_buffer_format(packet,
1034 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1037 if (ske->callbacks->send_packet)
1038 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1039 ske->callbacks->context);
1041 silc_buffer_free(packet);
1043 return SILC_SKE_STATUS_OK;
1046 /* Aborts the Key Exchange protocol. This is called if error occurs
1047 while performing the protocol. The status argument is the error
1048 status and it is sent to the remote end. */
1050 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1054 SILC_LOG_DEBUG(("Start"));
1056 packet = silc_buffer_alloc(4);
1057 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1058 silc_buffer_format(packet,
1059 SILC_STR_UI_INT((uint32)status),
1062 if (ske->callbacks->send_packet)
1063 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1064 ske->callbacks->context);
1066 silc_buffer_free(packet);
1068 return SILC_SKE_STATUS_OK;
1071 /* Assembles security properties to Key Exchange Start Payload to be
1072 sent to the remote end. This checks system wide (SILC system, that is)
1073 settings and chooses from those. However, if other properties
1074 should be used this function is easy to replace by another function,
1075 as, this function is called by the caller of the protocol and not
1076 by the protocol itself. */
1079 silc_ske_assemble_security_properties(SilcSKE ske,
1080 unsigned char flags,
1082 SilcSKEStartPayload **return_payload)
1084 SilcSKEStartPayload *rp;
1087 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1089 rp = silc_calloc(1, sizeof(*rp));
1094 /* Set random cookie */
1095 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1096 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1097 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1098 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1101 rp->version = strdup(version);
1102 rp->version_len = strlen(version);
1104 /* Get supported Key Exhange groups */
1105 rp->ke_grp_list = silc_ske_get_supported_groups();
1106 rp->ke_grp_len = strlen(rp->ke_grp_list);
1108 /* Get supported PKCS algorithms */
1109 rp->pkcs_alg_list = silc_pkcs_get_supported();
1110 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1112 /* Get supported encryption algorithms */
1113 rp->enc_alg_list = silc_cipher_get_supported();
1114 rp->enc_alg_len = strlen(rp->enc_alg_list);
1116 /* Get supported hash algorithms */
1117 rp->hash_alg_list = silc_hash_get_supported();
1118 rp->hash_alg_len = strlen(rp->hash_alg_list);
1120 /* Get supported HMACs */
1121 rp->hmac_alg_list = silc_hmac_get_supported();
1122 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1125 /* Get supported compression algorithms */
1126 rp->comp_alg_list = "";
1127 rp->comp_alg_len = 0;
1129 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1130 2 + rp->version_len +
1131 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1132 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1133 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1135 *return_payload = rp;
1137 return SILC_SKE_STATUS_OK;
1140 /* Selects the supported security properties from the remote end's Key
1141 Exchange Start Payload. */
1144 silc_ske_select_security_properties(SilcSKE ske,
1146 SilcSKEStartPayload *payload,
1147 SilcSKEStartPayload *remote_payload)
1149 SilcSKEStatus status;
1150 SilcSKEStartPayload *rp;
1154 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1156 rp = remote_payload;
1158 /* Check version string */
1159 if (ske->callbacks->check_version) {
1160 status = ske->callbacks->check_version(ske, rp->version,
1162 ske->callbacks->context);
1163 if (status != SILC_SKE_STATUS_OK) {
1164 ske->status = status;
1169 /* Flags are returned unchanged. */
1170 payload->flags = rp->flags;
1173 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1174 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1175 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1177 /* Put our version to our reply */
1178 payload->version = strdup(version);
1179 payload->version_len = strlen(version);
1181 /* Get supported Key Exchange groups */
1182 cp = rp->ke_grp_list;
1183 if (cp && strchr(cp, ',')) {
1187 len = strcspn(cp, ",");
1188 item = silc_calloc(len + 1, sizeof(char));
1189 memcpy(item, cp, len);
1191 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1193 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1194 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1196 payload->ke_grp_len = len;
1197 payload->ke_grp_list = item;
1202 if (strlen(cp) == 0)
1211 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1212 SILC_LOG_DEBUG(("Could not find supported KE group"));
1214 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1218 if (!rp->ke_grp_len) {
1219 SILC_LOG_DEBUG(("KE group not defined in payload"));
1221 return SILC_SKE_STATUS_BAD_PAYLOAD;
1224 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1225 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1227 payload->ke_grp_len = rp->ke_grp_len;
1228 payload->ke_grp_list = strdup(rp->ke_grp_list);
1231 /* Get supported PKCS algorithms */
1232 cp = rp->pkcs_alg_list;
1233 if (cp && strchr(cp, ',')) {
1237 len = strcspn(cp, ",");
1238 item = silc_calloc(len + 1, sizeof(char));
1239 memcpy(item, cp, len);
1241 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1243 if (silc_pkcs_is_supported(item) == TRUE) {
1244 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1246 payload->pkcs_alg_len = len;
1247 payload->pkcs_alg_list = item;
1252 if (strlen(cp) == 0)
1261 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1262 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1263 silc_free(payload->ke_grp_list);
1265 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1269 if (!rp->pkcs_alg_len) {
1270 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1271 silc_free(payload->ke_grp_list);
1273 return SILC_SKE_STATUS_BAD_PAYLOAD;
1276 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1277 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1279 payload->pkcs_alg_len = rp->pkcs_alg_len;
1280 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1283 /* Get supported encryption algorithms */
1284 cp = rp->enc_alg_list;
1285 if (cp && strchr(cp, ',')) {
1289 len = strcspn(cp, ",");
1290 item = silc_calloc(len + 1, sizeof(char));
1291 memcpy(item, cp, len);
1293 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1295 if (silc_cipher_is_supported(item) == TRUE) {
1296 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1298 payload->enc_alg_len = len;
1299 payload->enc_alg_list = item;
1304 if (strlen(cp) == 0)
1313 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1314 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1315 silc_free(payload->ke_grp_list);
1316 silc_free(payload->pkcs_alg_list);
1318 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1322 if (!rp->enc_alg_len) {
1323 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1324 silc_free(payload->ke_grp_list);
1325 silc_free(payload->pkcs_alg_list);
1327 return SILC_SKE_STATUS_BAD_PAYLOAD;
1330 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1333 payload->enc_alg_len = rp->enc_alg_len;
1334 payload->enc_alg_list = strdup(rp->enc_alg_list);
1337 /* Get supported hash algorithms */
1338 cp = rp->hash_alg_list;
1339 if (cp && strchr(cp, ',')) {
1343 len = strcspn(cp, ",");
1344 item = silc_calloc(len + 1, sizeof(char));
1345 memcpy(item, cp, len);
1347 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1349 if (silc_hash_is_supported(item) == TRUE) {
1350 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1352 payload->hash_alg_len = len;
1353 payload->hash_alg_list = item;
1358 if (strlen(cp) == 0)
1367 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1368 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1369 silc_free(payload->ke_grp_list);
1370 silc_free(payload->pkcs_alg_list);
1371 silc_free(payload->enc_alg_list);
1373 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1377 if (!rp->hash_alg_len) {
1378 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1379 silc_free(payload->ke_grp_list);
1380 silc_free(payload->pkcs_alg_list);
1381 silc_free(payload->enc_alg_list);
1383 return SILC_SKE_STATUS_BAD_PAYLOAD;
1386 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1387 rp->hash_alg_list));
1389 payload->hash_alg_len = rp->hash_alg_len;
1390 payload->hash_alg_list = strdup(rp->hash_alg_list);
1393 /* Get supported HMACs */
1394 cp = rp->hmac_alg_list;
1395 if (cp && strchr(cp, ',')) {
1399 len = strcspn(cp, ",");
1400 item = silc_calloc(len + 1, sizeof(char));
1401 memcpy(item, cp, len);
1403 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1405 if (silc_hmac_is_supported(item) == TRUE) {
1406 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1408 payload->hmac_alg_len = len;
1409 payload->hmac_alg_list = item;
1414 if (strlen(cp) == 0)
1423 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1424 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1425 silc_free(payload->ke_grp_list);
1426 silc_free(payload->pkcs_alg_list);
1427 silc_free(payload->enc_alg_list);
1428 silc_free(payload->hash_alg_list);
1430 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1434 if (!rp->hmac_alg_len) {
1435 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1436 silc_free(payload->ke_grp_list);
1437 silc_free(payload->pkcs_alg_list);
1438 silc_free(payload->enc_alg_list);
1439 silc_free(payload->hash_alg_list);
1441 return SILC_SKE_STATUS_BAD_PAYLOAD;
1444 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1445 rp->hmac_alg_list));
1447 payload->hmac_alg_len = rp->hmac_alg_len;
1448 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1452 /* Get supported compression algorithms */
1453 cp = rp->hash_alg_list;
1454 if (cp && strchr(cp, ',')) {
1458 len = strcspn(cp, ",");
1459 item = silc_calloc(len + 1, sizeof(char));
1460 memcpy(item, cp, len);
1462 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1464 if (silc_hash_is_supported(item) == TRUE) {
1465 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1467 payload->hash_alg_len = len;
1468 payload->hash_alg_list = item;
1473 if (strlen(cp) == 0)
1482 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1483 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1484 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1485 silc_free(payload->ke_grp_list);
1486 silc_free(payload->pkcs_alg_list);
1487 silc_free(payload->enc_alg_list);
1496 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1497 2 + payload->version_len +
1498 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1499 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1500 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1502 return SILC_SKE_STATUS_OK;
1505 /* Creates random number such that 1 < rnd < n and at most length
1506 of len bits. The rnd sent as argument must be initialized. */
1508 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt n,
1512 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1513 unsigned char *string;
1515 SILC_LOG_DEBUG(("Creating random number"));
1517 /* Get the random number as string */
1518 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1520 return SILC_SKE_STATUS_ERROR;
1522 /* Decode the string into a MP integer */
1523 silc_mp_bin2mp(string, (len / 8), rnd);
1524 silc_mp_mod_2exp(rnd, rnd, len);
1527 if (silc_mp_cmp_ui(rnd, 1) < 0)
1528 status = SILC_SKE_STATUS_ERROR;
1530 if (silc_mp_cmp(rnd, &n) >= 0)
1531 status = SILC_SKE_STATUS_ERROR;
1533 memset(string, 'F', (len / 8));
1539 /* Creates a hash value HASH as defined in the SKE protocol. If the
1540 `initiator' is TRUE then this function is used to create the HASH_i
1541 hash value defined in the protocol. If it is FALSE then this is used
1542 to create the HASH value defined by the protocol. */
1544 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1545 unsigned char *return_hash,
1546 uint32 *return_hash_len,
1549 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1551 unsigned char *e, *f, *KEY;
1552 uint32 e_len, f_len, KEY_len;
1555 SILC_LOG_DEBUG(("Start"));
1557 if (initiator == FALSE) {
1558 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1559 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1560 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1562 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1563 ske->ke2_payload->pk_len + e_len +
1565 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1567 /* Format the buffer used to compute the hash value */
1569 silc_buffer_format(buf,
1570 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1571 ske->start_payload_copy->len),
1572 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1573 ske->ke2_payload->pk_len),
1574 SILC_STR_UI_XNSTRING(e, e_len),
1575 SILC_STR_UI_XNSTRING(f, f_len),
1576 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1579 silc_buffer_free(buf);
1580 memset(e, 0, e_len);
1581 memset(f, 0, f_len);
1582 memset(KEY, 0, KEY_len);
1586 return SILC_SKE_STATUS_ERROR;
1589 memset(e, 0, e_len);
1590 memset(f, 0, f_len);
1591 memset(KEY, 0, KEY_len);
1596 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1598 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1599 ske->ke1_payload->pk_len + e_len);
1600 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1602 /* Format the buffer used to compute the hash value */
1604 silc_buffer_format(buf,
1605 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1606 ske->start_payload_copy->len),
1607 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1608 ske->ke1_payload->pk_len),
1609 SILC_STR_UI_XNSTRING(e, e_len),
1612 silc_buffer_free(buf);
1613 memset(e, 0, e_len);
1615 return SILC_SKE_STATUS_ERROR;
1618 memset(e, 0, e_len);
1623 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1624 *return_hash_len = ske->prop->hash->hash->hash_len;
1626 if (initiator == FALSE) {
1627 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1629 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1632 silc_buffer_free(buf);
1637 /* Processes the provided key material `data' as the SILC protocol
1638 specification specifies. */
1641 silc_ske_process_key_material_data(unsigned char *data,
1644 uint32 req_enc_key_len,
1645 uint32 req_hmac_key_len,
1647 SilcSKEKeyMaterial *key)
1650 unsigned char hashd[32];
1651 uint32 hash_len = req_hmac_key_len;
1652 uint32 enc_key_len = req_enc_key_len / 8;
1654 SILC_LOG_DEBUG(("Start"));
1656 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1657 return SILC_SKE_STATUS_ERROR;
1659 buf = silc_buffer_alloc(1 + data_len);
1660 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1661 silc_buffer_format(buf,
1662 SILC_STR_UI_CHAR(0),
1663 SILC_STR_UI_XNSTRING(data, data_len),
1667 memset(hashd, 0, sizeof(hashd));
1669 silc_hash_make(hash, buf->data, buf->len, hashd);
1670 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1671 memcpy(key->send_iv, hashd, req_iv_len);
1672 memset(hashd, 0, sizeof(hashd));
1674 silc_hash_make(hash, buf->data, buf->len, hashd);
1675 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1676 memcpy(key->receive_iv, hashd, req_iv_len);
1677 key->iv_len = req_iv_len;
1679 /* Take the encryption keys. If requested key size is more than
1680 the size of hash length we will distribute more key material
1681 as protocol defines. */
1683 if (enc_key_len > hash_len) {
1685 unsigned char k1[32], k2[32], k3[32];
1686 unsigned char *dtmp;
1689 if (enc_key_len > (3 * hash_len))
1690 return SILC_SKE_STATUS_ERROR;
1692 /* Take first round */
1693 memset(k1, 0, sizeof(k1));
1694 silc_hash_make(hash, buf->data, buf->len, k1);
1696 /* Take second round */
1697 dist = silc_buffer_alloc(data_len + hash_len);
1698 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1699 silc_buffer_format(dist,
1700 SILC_STR_UI_XNSTRING(data, data_len),
1701 SILC_STR_UI_XNSTRING(k1, hash_len),
1703 memset(k2, 0, sizeof(k2));
1704 silc_hash_make(hash, dist->data, dist->len, k2);
1706 /* Take third round */
1707 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1708 silc_buffer_pull_tail(dist, hash_len);
1709 silc_buffer_pull(dist, data_len + hash_len);
1710 silc_buffer_format(dist,
1711 SILC_STR_UI_XNSTRING(k2, hash_len),
1713 silc_buffer_push(dist, data_len + hash_len);
1714 memset(k3, 0, sizeof(k3));
1715 silc_hash_make(hash, dist->data, dist->len, k3);
1717 /* Then, save the keys */
1718 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1719 memcpy(dtmp, k1, hash_len);
1720 memcpy(dtmp + hash_len, k2, hash_len);
1721 memcpy(dtmp + hash_len, k3, hash_len);
1723 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1724 memcpy(key->send_enc_key, dtmp, enc_key_len);
1725 key->enc_key_len = req_enc_key_len;
1727 memset(dtmp, 0, (3 * hash_len));
1728 memset(k1, 0, sizeof(k1));
1729 memset(k2, 0, sizeof(k2));
1730 memset(k3, 0, sizeof(k3));
1732 silc_buffer_free(dist);
1734 /* Take normal hash as key */
1735 memset(hashd, 0, sizeof(hashd));
1736 silc_hash_make(hash, buf->data, buf->len, hashd);
1737 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1738 memcpy(key->send_enc_key, hashd, enc_key_len);
1739 key->enc_key_len = req_enc_key_len;
1743 if (enc_key_len > hash_len) {
1745 unsigned char k1[32], k2[32], k3[32];
1746 unsigned char *dtmp;
1749 if (enc_key_len > (3 * hash_len))
1750 return SILC_SKE_STATUS_ERROR;
1752 /* Take first round */
1753 memset(k1, 0, sizeof(k1));
1754 silc_hash_make(hash, buf->data, buf->len, k1);
1756 /* Take second round */
1757 dist = silc_buffer_alloc(data_len + hash_len);
1758 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1759 silc_buffer_format(dist,
1760 SILC_STR_UI_XNSTRING(data, data_len),
1761 SILC_STR_UI_XNSTRING(k1, hash_len),
1763 memset(k2, 0, sizeof(k2));
1764 silc_hash_make(hash, dist->data, dist->len, k2);
1766 /* Take third round */
1767 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1768 silc_buffer_pull_tail(dist, hash_len);
1769 silc_buffer_pull(dist, data_len + hash_len);
1770 silc_buffer_format(dist,
1771 SILC_STR_UI_XNSTRING(k2, hash_len),
1773 silc_buffer_push(dist, data_len + hash_len);
1774 memset(k3, 0, sizeof(k3));
1775 silc_hash_make(hash, dist->data, dist->len, k3);
1777 /* Then, save the keys */
1778 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1779 memcpy(dtmp, k1, hash_len);
1780 memcpy(dtmp + hash_len, k2, hash_len);
1781 memcpy(dtmp + hash_len, k3, hash_len);
1783 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1784 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1785 key->enc_key_len = req_enc_key_len;
1787 memset(dtmp, 0, (3 * hash_len));
1788 memset(k1, 0, sizeof(k1));
1789 memset(k2, 0, sizeof(k2));
1790 memset(k3, 0, sizeof(k3));
1792 silc_buffer_free(dist);
1794 /* Take normal hash as key */
1795 memset(hashd, 0, sizeof(hashd));
1796 silc_hash_make(hash, buf->data, buf->len, hashd);
1797 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1798 memcpy(key->receive_enc_key, hashd, enc_key_len);
1799 key->enc_key_len = req_enc_key_len;
1803 memset(hashd, 0, sizeof(hashd));
1805 silc_hash_make(hash, buf->data, buf->len, hashd);
1806 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1807 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1808 key->hmac_key_len = req_hmac_key_len;
1810 silc_buffer_free(buf);
1812 return SILC_SKE_STATUS_OK;
1815 /* Processes negotiated key material as protocol specifies. This returns
1816 the actual keys to be used in the SILC. */
1818 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1820 uint32 req_enc_key_len,
1821 uint32 req_hmac_key_len,
1822 SilcSKEKeyMaterial *key)
1824 SilcSKEStatus status;
1826 unsigned char *tmpbuf;
1829 /* Encode KEY to binary data */
1830 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1832 buf = silc_buffer_alloc(klen + ske->hash_len);
1833 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1834 silc_buffer_format(buf,
1835 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1836 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1839 /* Process the key material */
1840 status = silc_ske_process_key_material_data(buf->data, buf->len,
1841 req_iv_len, req_enc_key_len,
1843 ske->prop->hash, key);
1845 memset(tmpbuf, 0, klen);
1847 silc_buffer_free(buf);
1852 /* Free key material structure */
1854 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1860 silc_free(key->send_iv);
1861 if (key->receive_iv)
1862 silc_free(key->receive_iv);
1863 if (key->send_enc_key) {
1864 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1865 silc_free(key->send_enc_key);
1867 if (key->receive_enc_key) {
1868 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1869 silc_free(key->receive_enc_key);
1871 if (key->hmac_key) {
1872 memset(key->hmac_key, 0, key->hmac_key_len);
1873 silc_free(key->hmac_key);