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);
92 silc_mp_uninit(ske->x);
96 silc_mp_uninit(ske->KEY);
100 silc_free(ske->hash);
105 /* Sets the callback functions for the SKE session.
107 The `send_packet' callback is a function that sends the packet to
108 network. The SKE library will call it at any time packet needs to
109 be sent to the remote host.
111 The `payload_receive' callback is called when the remote host's Key
112 Exchange Start Payload has been processed. The payload is saved
113 to ske->start_payload if the application would need it. The application
114 must also provide the payload to the next state of the SKE.
116 The `verify_key' callback is called to verify the received public key
117 or certificate. The verification process is most likely asynchronous.
118 That is why the application must call the completion callback when the
119 verification process has been completed. The library then calls the user
120 callback (`proto_continue'), if it is provided to indicate that the SKE
121 protocol may continue.
123 The `proto_continue' callback is called to indicate that it is
124 safe to continue the execution of the SKE protocol after executing
125 an asynchronous operation, such as calling the `verify_key' callback
126 function, which is asynchronous. The application should check the
127 ske->status in this function to check whether it is Ok to continue
128 the execution of the protocol.
130 The `check_version' callback is called to verify the remote host's
131 version. The application may check its own version against the remote
132 host's version and determine whether supporting the remote host
135 The `context' is passed as argument to all of the above callback
138 void silc_ske_set_callbacks(SilcSKE ske,
139 SilcSKESendPacketCb send_packet,
140 SilcSKECb payload_receive,
141 SilcSKEVerifyCb verify_key,
142 SilcSKECb proto_continue,
143 SilcSKECheckVersion check_version,
147 silc_free(ske->callbacks);
148 ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
149 ske->callbacks->send_packet = send_packet;
150 ske->callbacks->payload_receive = payload_receive;
151 ske->callbacks->verify_key = verify_key;
152 ske->callbacks->proto_continue = proto_continue;
153 ske->callbacks->check_version = check_version;
154 ske->callbacks->context = context;
157 /* Starts the SILC Key Exchange protocol for initiator. The connection
158 to the remote end must be established before calling this function
159 and the connecting socket must be sent as argument. This function
160 creates the Key Exchange Start Payload which includes all our
161 configured security properties. This payload is then sent to the
162 remote end for further processing. This payload must be sent as
163 argument to the function, however, it must not be encoded
164 already, it is done by this function.
166 The packet sending is done by calling a callback function. Caller
167 must provide a routine to send the packet. */
169 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
170 SilcSocketConnection sock,
171 SilcSKEStartPayload *start_payload)
173 SilcSKEStatus status = SILC_SKE_STATUS_OK;
174 SilcBuffer payload_buf;
176 SILC_LOG_DEBUG(("Start"));
181 /* Encode the payload */
182 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
183 if (status != SILC_SKE_STATUS_OK)
186 /* Take a copy of the payload buffer for future use. It is used to
187 compute the HASH value. */
188 ske->start_payload_copy = silc_buffer_copy(payload_buf);
190 /* Send the packet. */
191 if (ske->callbacks->send_packet)
192 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
193 ske->callbacks->context);
195 silc_buffer_free(payload_buf);
200 /* Function called after ske_initiator_start fuction. This receives
201 the remote ends Key Exchange Start payload which includes the
202 security properties selected by the responder from our payload
203 sent in the silc_ske_initiator_start function. */
205 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
206 SilcBuffer start_payload)
208 SilcSKEStatus status = SILC_SKE_STATUS_OK;
209 SilcSKEStartPayload *payload;
210 SilcSKESecurityProperties prop;
211 SilcSKEDiffieHellmanGroup group;
213 SILC_LOG_DEBUG(("Start"));
215 /* Decode the payload */
216 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
217 if (status != SILC_SKE_STATUS_OK) {
218 ske->status = status;
222 /* Take the selected security properties into use while doing
223 the key exchange. This is used only while doing the key
224 exchange. The same data is returned to upper levels by calling
225 the callback function. */
226 ske->prop = prop = silc_calloc(1, sizeof(*prop));
227 prop->flags = payload->flags;
228 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
229 if (status != SILC_SKE_STATUS_OK)
234 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
235 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
239 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
240 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
244 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
245 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
249 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
250 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
254 ske->start_payload = payload;
256 /* Return the received payload by calling the callback function. */
257 if (ske->callbacks->payload_receive)
258 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
264 silc_ske_payload_start_free(payload);
269 silc_pkcs_free(prop->pkcs);
271 silc_cipher_free(prop->cipher);
273 silc_hash_free(prop->hash);
275 silc_hmac_free(prop->hmac);
279 if (status == SILC_SKE_STATUS_OK)
280 return SILC_SKE_STATUS_ERROR;
282 ske->status = status;
286 /* This function creates random number x, such that 1 < x < q and
287 computes e = g ^ x mod p and sends the result to the remote end in
288 Key Exchange Payload. */
290 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
291 SilcPublicKey public_key,
292 SilcPrivateKey private_key)
294 SilcSKEStatus status = SILC_SKE_STATUS_OK;
295 SilcBuffer payload_buf;
297 SilcSKEKEPayload *payload;
300 SILC_LOG_DEBUG(("Start"));
302 /* Create the random number x, 1 < x < q. */
303 x = silc_calloc(1, sizeof(*x));
306 silc_ske_create_rnd(ske, ske->prop->group->group_order,
307 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
309 if (status != SILC_SKE_STATUS_OK) {
312 ske->status = status;
316 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
318 /* Do the Diffie Hellman computation, e = g ^ x mod p */
320 silc_mp_pow_mod(&e, &ske->prop->group->generator, x,
321 &ske->prop->group->group);
323 /* Encode the result to Key Exchange Payload. */
325 payload = silc_calloc(1, sizeof(*payload));
326 ske->ke1_payload = payload;
332 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
333 if (!payload->pk_data) {
338 ske->status = SILC_SKE_STATUS_OK;
341 payload->pk_len = pk_len;
343 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
345 /* Compute signature data if we are doing mutual authentication */
346 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
347 unsigned char hash[32], sign[1024];
348 uint32 hash_len, sign_len;
350 SILC_LOG_DEBUG(("We are doing mutual authentication"));
351 SILC_LOG_DEBUG(("Computing HASH_i value"));
353 /* Compute the hash value */
354 memset(hash, 0, sizeof(hash));
355 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
357 SILC_LOG_DEBUG(("Signing HASH_i value"));
359 /* Sign the hash value */
360 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
361 private_key->prv_len);
362 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
363 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
364 memcpy(payload->sign_data, sign, sign_len);
365 memset(sign, 0, sizeof(sign));
366 payload->sign_len = sign_len;
369 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
370 if (status != SILC_SKE_STATUS_OK) {
374 silc_free(payload->pk_data);
376 ske->status = status;
382 /* Send the packet. */
383 if (ske->callbacks->send_packet)
384 (*ske->callbacks->send_packet)(ske, payload_buf,
385 SILC_PACKET_KEY_EXCHANGE_1,
386 ske->callbacks->context);
388 silc_buffer_free(payload_buf);
393 /* An initiator finish final callback that is called to indicate that
394 the SKE protocol may continue. */
396 static void silc_ske_initiator_finish_final(SilcSKE ske,
397 SilcSKEStatus status,
400 SilcSKEKEPayload *payload;
401 unsigned char hash[32];
403 SilcPublicKey public_key = NULL;
405 /* If the SKE was freed during the async call then free it really now,
406 otherwise just decrement the reference counter. */
407 if (ske->status == SILC_SKE_STATUS_FREED) {
414 payload = ske->ke2_payload;
416 /* If the caller returns PENDING status SKE library will assume that
417 the caller will re-call this callback when it is not anymore in
419 if (status == SILC_SKE_STATUS_PENDING)
422 /* If the status is an error then the public key that was verified
423 by the caller is not authentic. */
424 if (status != SILC_SKE_STATUS_OK) {
425 ske->status = status;
426 if (ske->callbacks->proto_continue)
427 ske->callbacks->proto_continue(ske, ske->callbacks->context);
431 if (payload->pk_data) {
432 /* Decode the public key */
433 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
435 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
436 if (ske->callbacks->proto_continue)
437 ske->callbacks->proto_continue(ske, ske->callbacks->context);
441 SILC_LOG_DEBUG(("Public key is authentic"));
443 /* Compute the hash value */
444 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
445 if (status != SILC_SKE_STATUS_OK)
448 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
449 memcpy(ske->hash, hash, hash_len);
450 ske->hash_len = hash_len;
452 SILC_LOG_DEBUG(("Verifying signature (HASH)"));
454 /* Verify signature */
455 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
456 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
457 payload->sign_len, hash, hash_len) == FALSE) {
459 SILC_LOG_DEBUG(("Signature don't match"));
461 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
465 SILC_LOG_DEBUG(("Signature is Ok"));
467 silc_pkcs_public_key_free(public_key);
468 memset(hash, 'F', hash_len);
471 ske->status = SILC_SKE_STATUS_OK;
473 /* Call the callback. The caller may now continue the SKE protocol. */
474 if (ske->callbacks->proto_continue)
475 ske->callbacks->proto_continue(ske, ske->callbacks->context);
480 memset(hash, 'F', sizeof(hash));
481 silc_ske_payload_ke_free(payload);
482 ske->ke2_payload = NULL;
484 silc_mp_uninit(ske->KEY);
489 silc_pkcs_public_key_free(public_key);
492 memset(ske->hash, 'F', hash_len);
493 silc_free(ske->hash);
497 if (status == SILC_SKE_STATUS_OK)
498 ske->status = SILC_SKE_STATUS_ERROR;
500 ske->status = status;
502 /* Call the callback. */
503 if (ske->callbacks->proto_continue)
504 ske->callbacks->proto_continue(ske, ske->callbacks->context);
507 /* Receives Key Exchange Payload from responder consisting responders
508 public key, f, and signature. This function verifies the public key,
509 computes the secret shared key and verifies the signature.
511 The `callback' will be called to indicate that the caller may
512 continue with the SKE protocol. The caller must not continue
513 before the SKE libary has called that callback. If this function
514 returns an error the callback will not be called. It is called
515 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
516 However, note that when the library calls the callback the ske->status
519 This calls the `verify_key' callback to verify the received public
520 key or certificate. If the `verify_key' is provided then the remote
521 must send public key and it is considered to be an error if remote
522 does not send its public key. If caller is performing a re-key with
523 SKE then the `verify_key' is usually not provided when it is not also
524 required for the remote to send its public key. */
526 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
527 SilcBuffer ke_payload)
529 SilcSKEStatus status = SILC_SKE_STATUS_OK;
530 SilcSKEKEPayload *payload;
533 SILC_LOG_DEBUG(("Start"));
535 /* Decode the payload */
536 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
537 if (status != SILC_SKE_STATUS_OK) {
538 ske->status = status;
541 ske->ke2_payload = payload;
543 if (!payload->pk_data && ske->callbacks->verify_key) {
544 SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
545 "even though we require it"));
546 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
550 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
552 /* Compute the shared secret key */
553 KEY = silc_calloc(1, sizeof(*KEY));
555 silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
558 if (payload->pk_data && ske->callbacks->verify_key) {
559 SILC_LOG_DEBUG(("Verifying public key"));
562 (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
563 payload->pk_type, ske->callbacks->context,
564 silc_ske_initiator_finish_final, NULL);
566 /* We will continue to the final state after the public key has
567 been verified by the caller. */
568 return SILC_SKE_STATUS_PENDING;
571 /* Continue to final state */
572 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
574 return SILC_SKE_STATUS_OK;
577 silc_ske_payload_ke_free(payload);
578 ske->ke2_payload = NULL;
580 silc_mp_uninit(ske->KEY);
584 if (status == SILC_SKE_STATUS_OK)
585 return SILC_SKE_STATUS_ERROR;
587 ske->status = status;
591 /* Starts Key Exchange protocol for responder. Responder receives
592 Key Exchange Start Payload from initiator consisting of all the
593 security properties the initiator supports. This function decodes
594 the payload and parses the payload further and selects the right
595 security properties. */
597 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
598 SilcSocketConnection sock,
600 SilcBuffer start_payload,
603 SilcSKEStatus status = SILC_SKE_STATUS_OK;
604 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
606 SILC_LOG_DEBUG(("Start"));
611 /* Decode the payload */
612 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
613 if (status != SILC_SKE_STATUS_OK) {
614 ske->status = status;
618 /* Take a copy of the payload buffer for future use. It is used to
619 compute the HASH value. */
620 ske->start_payload_copy = silc_buffer_copy(start_payload);
622 /* Force the mutual authentication flag if we want to do it. */
624 SILC_LOG_DEBUG(("Force mutual authentication"));
625 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
628 /* Parse and select the security properties from the payload */
629 payload = silc_calloc(1, sizeof(*payload));
630 status = silc_ske_select_security_properties(ske, version,
631 payload, remote_payload);
632 if (status != SILC_SKE_STATUS_OK)
635 ske->start_payload = payload;
637 /* Call the callback function. */
638 if (ske->callbacks->payload_receive)
639 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
645 silc_ske_payload_start_free(remote_payload);
649 if (status == SILC_SKE_STATUS_OK)
650 return SILC_SKE_STATUS_ERROR;
652 ske->status = status;
656 /* The selected security properties from the initiator payload is now
657 encoded into Key Exchange Start Payload and sent to the initiator. */
659 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
660 SilcSKEStartPayload *start_payload)
662 SilcSKEStatus status = SILC_SKE_STATUS_OK;
663 SilcBuffer payload_buf;
664 SilcSKESecurityProperties prop;
665 SilcSKEDiffieHellmanGroup group = NULL;
667 SILC_LOG_DEBUG(("Start"));
669 /* Allocate security properties from the payload. These are allocated
670 only for this negotiation and will be free'd after KE is over. */
671 ske->prop = prop = silc_calloc(1, sizeof(*prop));
672 prop->flags = start_payload->flags;
673 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
674 if (status != SILC_SKE_STATUS_OK)
679 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
680 &prop->pkcs) == FALSE) {
681 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
685 if (silc_cipher_alloc(start_payload->enc_alg_list,
686 &prop->cipher) == FALSE) {
687 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
691 if (silc_hash_alloc(start_payload->hash_alg_list,
692 &prop->hash) == FALSE) {
693 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
697 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
698 &prop->hmac) == FALSE) {
699 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
703 /* Encode the payload */
704 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
705 if (status != SILC_SKE_STATUS_OK)
708 /* Send the packet. */
709 if (ske->callbacks->send_packet)
710 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
711 ske->callbacks->context);
713 silc_buffer_free(payload_buf);
722 silc_pkcs_free(prop->pkcs);
724 silc_cipher_free(prop->cipher);
726 silc_hash_free(prop->hash);
728 silc_hmac_free(prop->hmac);
732 if (status == SILC_SKE_STATUS_OK)
733 return SILC_SKE_STATUS_ERROR;
735 ske->status = status;
739 /* An responder phase 2 final callback that is called to indicate that
740 the SKE protocol may continue. */
742 static void silc_ske_responder_phase2_final(SilcSKE ske,
743 SilcSKEStatus status,
746 SilcSKEKEPayload *recv_payload, *send_payload;
749 /* If the SKE was freed during the async call then free it really now,
750 otherwise just decrement the reference counter. */
751 if (ske->status == SILC_SKE_STATUS_FREED) {
758 recv_payload = ske->ke1_payload;
760 /* If the caller returns PENDING status SKE library will assume that
761 the caller will re-call this callback when it is not anymore in
763 if (status == SILC_SKE_STATUS_PENDING)
766 /* If the status is an error then the public key that was verified
767 by the caller is not authentic. */
768 if (status != SILC_SKE_STATUS_OK) {
769 ske->status = status;
770 if (ske->callbacks->proto_continue)
771 ske->callbacks->proto_continue(ske, ske->callbacks->context);
775 /* The public key verification was performed only if the Mutual
776 Authentication flag is set. */
777 if (ske->start_payload &&
778 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
779 SilcPublicKey public_key = NULL;
780 unsigned char hash[32];
783 /* Decode the public key */
784 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
785 recv_payload->pk_len,
787 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
788 if (ske->callbacks->proto_continue)
789 ske->callbacks->proto_continue(ske, ske->callbacks->context);
793 SILC_LOG_DEBUG(("Public key is authentic"));
795 /* Compute the hash value */
796 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
797 if (status != SILC_SKE_STATUS_OK) {
798 ske->status = status;
799 if (ske->callbacks->proto_continue)
800 ske->callbacks->proto_continue(ske, ske->callbacks->context);
804 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
806 /* Verify signature */
807 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
808 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
809 recv_payload->sign_len, hash, hash_len) == FALSE) {
811 SILC_LOG_DEBUG(("Signature don't match"));
813 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
814 if (ske->callbacks->proto_continue)
815 ske->callbacks->proto_continue(ske, ske->callbacks->context);
819 SILC_LOG_DEBUG(("Signature is Ok"));
821 silc_pkcs_public_key_free(public_key);
822 memset(hash, 'F', hash_len);
825 /* Create the random number x, 1 < x < q. */
826 x = silc_calloc(1, sizeof(*x));
829 silc_ske_create_rnd(ske, ske->prop->group->group_order,
830 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
832 if (status != SILC_SKE_STATUS_OK) {
835 ske->status = status;
836 if (ske->callbacks->proto_continue)
837 ske->callbacks->proto_continue(ske, ske->callbacks->context);
841 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
843 /* Do the Diffie Hellman computation, f = g ^ x mod p */
845 silc_mp_pow_mod(&f, &ske->prop->group->generator, x,
846 &ske->prop->group->group);
848 /* Save the results for later processing */
849 send_payload = silc_calloc(1, sizeof(*send_payload));
852 ske->ke2_payload = send_payload;
854 /* Call the callback. The caller may now continue with the SKE protocol. */
855 ske->status = SILC_SKE_STATUS_OK;
856 if (ske->callbacks->proto_continue)
857 ske->callbacks->proto_continue(ske, ske->callbacks->context);
860 /* This function receives the Key Exchange Payload from the initiator.
861 This also performs the mutual authentication if required. Then, this
862 function first generated a random number x, such that 1 < x < q
863 and computes f = g ^ x mod p. This then puts the result f to a Key
866 The `callback' will be called to indicate that the caller may
867 continue with the SKE protocol. The caller must not continue
868 before the SKE libary has called that callback. If this function
869 returns an error the callback will not be called. It is called
870 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
871 However, note that when the library calls the callback the ske->status
874 This calls the `verify_key' callback to verify the received public
875 key or certificate if the Mutual Authentication flag is set. If the
876 `verify_key' is provided then the remote must send public key and it
877 is considered to be an error if remote does not send its public key. */
879 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
880 SilcBuffer ke_payload)
882 SilcSKEStatus status = SILC_SKE_STATUS_OK;
883 SilcSKEKEPayload *recv_payload;
885 SILC_LOG_DEBUG(("Start"));
887 /* Decode Key Exchange Payload */
888 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
889 if (status != SILC_SKE_STATUS_OK) {
890 ske->status = status;
894 ske->ke1_payload = recv_payload;
896 /* Verify the received public key and verify the signature if we are
897 doing mutual authentication. */
898 if (ske->start_payload &&
899 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
901 SILC_LOG_DEBUG(("We are doing mutual authentication"));
903 if (!recv_payload->pk_data && ske->callbacks->verify_key) {
904 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
905 "certificate), even though we require it"));
906 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
910 if (recv_payload->pk_data && ske->callbacks->verify_key) {
911 SILC_LOG_DEBUG(("Verifying public key"));
914 (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
915 recv_payload->pk_len,
916 recv_payload->pk_type,
917 ske->callbacks->context,
918 silc_ske_responder_phase2_final, NULL);
920 /* We will continue to the final state after the public key has
921 been verified by the caller. */
922 return SILC_SKE_STATUS_PENDING;
926 /* Continue to final state */
927 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
929 return SILC_SKE_STATUS_OK;
932 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
933 value to be signed and sent to the other end. This then encodes Key
934 Exchange Payload and sends it to the other end. */
936 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
937 SilcPublicKey public_key,
938 SilcPrivateKey private_key,
939 SilcSKEPKType pk_type)
941 SilcSKEStatus status = SILC_SKE_STATUS_OK;
942 SilcBuffer payload_buf;
944 unsigned char hash[32], sign[1024], *pk;
945 uint32 hash_len, sign_len, pk_len;
947 SILC_LOG_DEBUG(("Start"));
949 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
951 /* Compute the shared secret key */
952 KEY = silc_calloc(1, sizeof(*KEY));
954 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
955 &ske->prop->group->group);
958 if (public_key && private_key) {
959 SILC_LOG_DEBUG(("Getting public key"));
961 /* Get the public key */
962 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
964 status = SILC_SKE_STATUS_ERROR;
967 ske->ke2_payload->pk_data = pk;
968 ske->ke2_payload->pk_len = pk_len;
970 SILC_LOG_DEBUG(("Computing HASH value"));
972 /* Compute the hash value */
973 memset(hash, 0, sizeof(hash));
974 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
975 if (status != SILC_SKE_STATUS_OK)
978 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
979 memcpy(ske->hash, hash, hash_len);
980 ske->hash_len = hash_len;
982 SILC_LOG_DEBUG(("Signing HASH value"));
984 /* Sign the hash value */
985 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
986 private_key->prv_len);
987 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
988 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
989 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
990 memset(sign, 0, sizeof(sign));
991 ske->ke2_payload->sign_len = sign_len;
993 ske->ke2_payload->pk_type = pk_type;
995 /* Encode the Key Exchange Payload */
996 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
998 if (status != SILC_SKE_STATUS_OK)
1001 /* Send the packet. */
1002 if (ske->callbacks->send_packet)
1003 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2,
1004 ske->callbacks->context);
1006 silc_buffer_free(payload_buf);
1011 silc_mp_uninit(ske->KEY);
1012 silc_free(ske->KEY);
1014 silc_ske_payload_ke_free(ske->ke2_payload);
1016 if (status == SILC_SKE_STATUS_OK)
1017 return SILC_SKE_STATUS_ERROR;
1019 ske->status = status;
1023 /* The Key Exchange protocol is ended by calling this function. This
1024 must not be called until the keys are processed like the protocol
1025 defines. This function is for both initiator and responder. */
1027 SilcSKEStatus silc_ske_end(SilcSKE ske)
1031 SILC_LOG_DEBUG(("Start"));
1033 packet = silc_buffer_alloc(4);
1034 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1035 silc_buffer_format(packet,
1036 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1039 if (ske->callbacks->send_packet)
1040 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1041 ske->callbacks->context);
1043 silc_buffer_free(packet);
1045 return SILC_SKE_STATUS_OK;
1048 /* Aborts the Key Exchange protocol. This is called if error occurs
1049 while performing the protocol. The status argument is the error
1050 status and it is sent to the remote end. */
1052 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1056 SILC_LOG_DEBUG(("Start"));
1058 packet = silc_buffer_alloc(4);
1059 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1060 silc_buffer_format(packet,
1061 SILC_STR_UI_INT((uint32)status),
1064 if (ske->callbacks->send_packet)
1065 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1066 ske->callbacks->context);
1068 silc_buffer_free(packet);
1070 return SILC_SKE_STATUS_OK;
1073 /* Assembles security properties to Key Exchange Start Payload to be
1074 sent to the remote end. This checks system wide (SILC system, that is)
1075 settings and chooses from those. However, if other properties
1076 should be used this function is easy to replace by another function,
1077 as, this function is called by the caller of the protocol and not
1078 by the protocol itself. */
1081 silc_ske_assemble_security_properties(SilcSKE ske,
1082 unsigned char flags,
1084 SilcSKEStartPayload **return_payload)
1086 SilcSKEStartPayload *rp;
1089 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1091 rp = silc_calloc(1, sizeof(*rp));
1096 /* Set random cookie */
1097 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1098 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1099 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1100 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1103 rp->version = strdup(version);
1104 rp->version_len = strlen(version);
1106 /* Get supported Key Exhange groups */
1107 rp->ke_grp_list = silc_ske_get_supported_groups();
1108 rp->ke_grp_len = strlen(rp->ke_grp_list);
1110 /* Get supported PKCS algorithms */
1111 rp->pkcs_alg_list = silc_pkcs_get_supported();
1112 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1114 /* Get supported encryption algorithms */
1115 rp->enc_alg_list = silc_cipher_get_supported();
1116 rp->enc_alg_len = strlen(rp->enc_alg_list);
1118 /* Get supported hash algorithms */
1119 rp->hash_alg_list = silc_hash_get_supported();
1120 rp->hash_alg_len = strlen(rp->hash_alg_list);
1122 /* Get supported HMACs */
1123 rp->hmac_alg_list = silc_hmac_get_supported();
1124 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1127 /* Get supported compression algorithms */
1128 rp->comp_alg_list = "";
1129 rp->comp_alg_len = 0;
1131 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1132 2 + rp->version_len +
1133 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1134 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1135 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1137 *return_payload = rp;
1139 return SILC_SKE_STATUS_OK;
1142 /* Selects the supported security properties from the remote end's Key
1143 Exchange Start Payload. */
1146 silc_ske_select_security_properties(SilcSKE ske,
1148 SilcSKEStartPayload *payload,
1149 SilcSKEStartPayload *remote_payload)
1151 SilcSKEStatus status;
1152 SilcSKEStartPayload *rp;
1156 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1158 rp = remote_payload;
1160 /* Check version string */
1161 if (ske->callbacks->check_version) {
1162 status = ske->callbacks->check_version(ske, rp->version,
1164 ske->callbacks->context);
1165 if (status != SILC_SKE_STATUS_OK) {
1166 ske->status = status;
1171 /* Flags are returned unchanged. */
1172 payload->flags = rp->flags;
1175 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1176 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1177 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1179 /* Put our version to our reply */
1180 payload->version = strdup(version);
1181 payload->version_len = strlen(version);
1183 /* Get supported Key Exchange groups */
1184 cp = rp->ke_grp_list;
1185 if (cp && strchr(cp, ',')) {
1189 len = strcspn(cp, ",");
1190 item = silc_calloc(len + 1, sizeof(char));
1191 memcpy(item, cp, len);
1193 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1195 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1196 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1198 payload->ke_grp_len = len;
1199 payload->ke_grp_list = item;
1204 if (strlen(cp) == 0)
1213 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1214 SILC_LOG_DEBUG(("Could not find supported KE group"));
1216 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1220 if (!rp->ke_grp_len) {
1221 SILC_LOG_DEBUG(("KE group not defined in payload"));
1223 return SILC_SKE_STATUS_BAD_PAYLOAD;
1226 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1227 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1229 payload->ke_grp_len = rp->ke_grp_len;
1230 payload->ke_grp_list = strdup(rp->ke_grp_list);
1233 /* Get supported PKCS algorithms */
1234 cp = rp->pkcs_alg_list;
1235 if (cp && strchr(cp, ',')) {
1239 len = strcspn(cp, ",");
1240 item = silc_calloc(len + 1, sizeof(char));
1241 memcpy(item, cp, len);
1243 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1245 if (silc_pkcs_is_supported(item) == TRUE) {
1246 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1248 payload->pkcs_alg_len = len;
1249 payload->pkcs_alg_list = item;
1254 if (strlen(cp) == 0)
1263 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1264 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1265 silc_free(payload->ke_grp_list);
1267 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1271 if (!rp->pkcs_alg_len) {
1272 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1273 silc_free(payload->ke_grp_list);
1275 return SILC_SKE_STATUS_BAD_PAYLOAD;
1278 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1279 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1281 payload->pkcs_alg_len = rp->pkcs_alg_len;
1282 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1285 /* Get supported encryption algorithms */
1286 cp = rp->enc_alg_list;
1287 if (cp && strchr(cp, ',')) {
1291 len = strcspn(cp, ",");
1292 item = silc_calloc(len + 1, sizeof(char));
1293 memcpy(item, cp, len);
1295 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1297 if (silc_cipher_is_supported(item) == TRUE) {
1298 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1300 payload->enc_alg_len = len;
1301 payload->enc_alg_list = item;
1306 if (strlen(cp) == 0)
1315 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1316 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1317 silc_free(payload->ke_grp_list);
1318 silc_free(payload->pkcs_alg_list);
1320 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1324 if (!rp->enc_alg_len) {
1325 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1326 silc_free(payload->ke_grp_list);
1327 silc_free(payload->pkcs_alg_list);
1329 return SILC_SKE_STATUS_BAD_PAYLOAD;
1332 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1335 payload->enc_alg_len = rp->enc_alg_len;
1336 payload->enc_alg_list = strdup(rp->enc_alg_list);
1339 /* Get supported hash algorithms */
1340 cp = rp->hash_alg_list;
1341 if (cp && strchr(cp, ',')) {
1345 len = strcspn(cp, ",");
1346 item = silc_calloc(len + 1, sizeof(char));
1347 memcpy(item, cp, len);
1349 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1351 if (silc_hash_is_supported(item) == TRUE) {
1352 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1354 payload->hash_alg_len = len;
1355 payload->hash_alg_list = item;
1360 if (strlen(cp) == 0)
1369 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1370 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1371 silc_free(payload->ke_grp_list);
1372 silc_free(payload->pkcs_alg_list);
1373 silc_free(payload->enc_alg_list);
1375 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1379 if (!rp->hash_alg_len) {
1380 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1381 silc_free(payload->ke_grp_list);
1382 silc_free(payload->pkcs_alg_list);
1383 silc_free(payload->enc_alg_list);
1385 return SILC_SKE_STATUS_BAD_PAYLOAD;
1388 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1389 rp->hash_alg_list));
1391 payload->hash_alg_len = rp->hash_alg_len;
1392 payload->hash_alg_list = strdup(rp->hash_alg_list);
1395 /* Get supported HMACs */
1396 cp = rp->hmac_alg_list;
1397 if (cp && strchr(cp, ',')) {
1401 len = strcspn(cp, ",");
1402 item = silc_calloc(len + 1, sizeof(char));
1403 memcpy(item, cp, len);
1405 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1407 if (silc_hmac_is_supported(item) == TRUE) {
1408 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1410 payload->hmac_alg_len = len;
1411 payload->hmac_alg_list = item;
1416 if (strlen(cp) == 0)
1425 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1426 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1427 silc_free(payload->ke_grp_list);
1428 silc_free(payload->pkcs_alg_list);
1429 silc_free(payload->enc_alg_list);
1430 silc_free(payload->hash_alg_list);
1432 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1436 if (!rp->hmac_alg_len) {
1437 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1438 silc_free(payload->ke_grp_list);
1439 silc_free(payload->pkcs_alg_list);
1440 silc_free(payload->enc_alg_list);
1441 silc_free(payload->hash_alg_list);
1443 return SILC_SKE_STATUS_BAD_PAYLOAD;
1446 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1447 rp->hmac_alg_list));
1449 payload->hmac_alg_len = rp->hmac_alg_len;
1450 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1454 /* Get supported compression algorithms */
1455 cp = rp->hash_alg_list;
1456 if (cp && strchr(cp, ',')) {
1460 len = strcspn(cp, ",");
1461 item = silc_calloc(len + 1, sizeof(char));
1462 memcpy(item, cp, len);
1464 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1466 if (silc_hash_is_supported(item) == TRUE) {
1467 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1469 payload->hash_alg_len = len;
1470 payload->hash_alg_list = item;
1475 if (strlen(cp) == 0)
1484 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1485 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1486 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1487 silc_free(payload->ke_grp_list);
1488 silc_free(payload->pkcs_alg_list);
1489 silc_free(payload->enc_alg_list);
1498 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1499 2 + payload->version_len +
1500 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1501 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1502 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1504 return SILC_SKE_STATUS_OK;
1507 /* Creates random number such that 1 < rnd < n and at most length
1508 of len bits. The rnd sent as argument must be initialized. */
1510 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt n,
1514 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1515 unsigned char *string;
1517 SILC_LOG_DEBUG(("Creating random number"));
1519 /* Get the random number as string */
1520 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1522 return SILC_SKE_STATUS_ERROR;
1524 /* Decode the string into a MP integer */
1525 silc_mp_bin2mp(string, (len / 8), rnd);
1526 silc_mp_mod_2exp(rnd, rnd, len);
1529 if (silc_mp_cmp_ui(rnd, 1) < 0)
1530 status = SILC_SKE_STATUS_ERROR;
1532 if (silc_mp_cmp(rnd, &n) >= 0)
1533 status = SILC_SKE_STATUS_ERROR;
1535 memset(string, 'F', (len / 8));
1541 /* Creates a hash value HASH as defined in the SKE protocol. If the
1542 `initiator' is TRUE then this function is used to create the HASH_i
1543 hash value defined in the protocol. If it is FALSE then this is used
1544 to create the HASH value defined by the protocol. */
1546 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1547 unsigned char *return_hash,
1548 uint32 *return_hash_len,
1551 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1553 unsigned char *e, *f, *KEY;
1554 uint32 e_len, f_len, KEY_len;
1557 SILC_LOG_DEBUG(("Start"));
1559 if (initiator == FALSE) {
1560 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1561 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1562 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1564 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1565 ske->pk_len + e_len + f_len + KEY_len);
1566 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1568 /* Format the buffer used to compute the hash value */
1570 silc_buffer_format(buf,
1571 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1572 ske->start_payload_copy->len),
1573 SILC_STR_UI_XNSTRING(ske->pk, ske->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->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->pk, ske->pk_len),
1608 SILC_STR_UI_XNSTRING(e, e_len),
1611 silc_buffer_free(buf);
1612 memset(e, 0, e_len);
1614 return SILC_SKE_STATUS_ERROR;
1617 memset(e, 0, e_len);
1622 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1623 *return_hash_len = ske->prop->hash->hash->hash_len;
1625 if (initiator == FALSE) {
1626 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1628 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1631 silc_buffer_free(buf);
1636 /* Processes the provided key material `data' as the SILC protocol
1637 specification specifies. */
1640 silc_ske_process_key_material_data(unsigned char *data,
1643 uint32 req_enc_key_len,
1644 uint32 req_hmac_key_len,
1646 SilcSKEKeyMaterial *key)
1649 unsigned char hashd[32];
1650 uint32 hash_len = req_hmac_key_len;
1651 uint32 enc_key_len = req_enc_key_len / 8;
1653 SILC_LOG_DEBUG(("Start"));
1655 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1656 return SILC_SKE_STATUS_ERROR;
1658 buf = silc_buffer_alloc(1 + data_len);
1659 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1660 silc_buffer_format(buf,
1661 SILC_STR_UI_CHAR(0),
1662 SILC_STR_UI_XNSTRING(data, data_len),
1666 memset(hashd, 0, sizeof(hashd));
1668 silc_hash_make(hash, buf->data, buf->len, hashd);
1669 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1670 memcpy(key->send_iv, hashd, req_iv_len);
1671 memset(hashd, 0, sizeof(hashd));
1673 silc_hash_make(hash, buf->data, buf->len, hashd);
1674 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1675 memcpy(key->receive_iv, hashd, req_iv_len);
1676 key->iv_len = req_iv_len;
1678 /* Take the encryption keys. If requested key size is more than
1679 the size of hash length we will distribute more key material
1680 as protocol defines. */
1682 if (enc_key_len > hash_len) {
1684 unsigned char k1[32], k2[32], k3[32];
1685 unsigned char *dtmp;
1688 if (enc_key_len > (3 * hash_len))
1689 return SILC_SKE_STATUS_ERROR;
1691 /* Take first round */
1692 memset(k1, 0, sizeof(k1));
1693 silc_hash_make(hash, buf->data, buf->len, k1);
1695 /* Take second round */
1696 dist = silc_buffer_alloc(data_len + hash_len);
1697 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1698 silc_buffer_format(dist,
1699 SILC_STR_UI_XNSTRING(data, data_len),
1700 SILC_STR_UI_XNSTRING(k1, hash_len),
1702 memset(k2, 0, sizeof(k2));
1703 silc_hash_make(hash, dist->data, dist->len, k2);
1705 /* Take third round */
1706 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1707 silc_buffer_pull_tail(dist, hash_len);
1708 silc_buffer_pull(dist, data_len + hash_len);
1709 silc_buffer_format(dist,
1710 SILC_STR_UI_XNSTRING(k2, hash_len),
1712 silc_buffer_push(dist, data_len + hash_len);
1713 memset(k3, 0, sizeof(k3));
1714 silc_hash_make(hash, dist->data, dist->len, k3);
1716 /* Then, save the keys */
1717 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1718 memcpy(dtmp, k1, hash_len);
1719 memcpy(dtmp + hash_len, k2, hash_len);
1720 memcpy(dtmp + hash_len, k3, hash_len);
1722 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1723 memcpy(key->send_enc_key, dtmp, enc_key_len);
1724 key->enc_key_len = req_enc_key_len;
1726 memset(dtmp, 0, (3 * hash_len));
1727 memset(k1, 0, sizeof(k1));
1728 memset(k2, 0, sizeof(k2));
1729 memset(k3, 0, sizeof(k3));
1731 silc_buffer_free(dist);
1733 /* Take normal hash as key */
1734 memset(hashd, 0, sizeof(hashd));
1735 silc_hash_make(hash, buf->data, buf->len, hashd);
1736 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1737 memcpy(key->send_enc_key, hashd, enc_key_len);
1738 key->enc_key_len = req_enc_key_len;
1742 if (enc_key_len > hash_len) {
1744 unsigned char k1[32], k2[32], k3[32];
1745 unsigned char *dtmp;
1748 if (enc_key_len > (3 * hash_len))
1749 return SILC_SKE_STATUS_ERROR;
1751 /* Take first round */
1752 memset(k1, 0, sizeof(k1));
1753 silc_hash_make(hash, buf->data, buf->len, k1);
1755 /* Take second round */
1756 dist = silc_buffer_alloc(data_len + hash_len);
1757 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1758 silc_buffer_format(dist,
1759 SILC_STR_UI_XNSTRING(data, data_len),
1760 SILC_STR_UI_XNSTRING(k1, hash_len),
1762 memset(k2, 0, sizeof(k2));
1763 silc_hash_make(hash, dist->data, dist->len, k2);
1765 /* Take third round */
1766 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1767 silc_buffer_pull_tail(dist, hash_len);
1768 silc_buffer_pull(dist, data_len + hash_len);
1769 silc_buffer_format(dist,
1770 SILC_STR_UI_XNSTRING(k2, hash_len),
1772 silc_buffer_push(dist, data_len + hash_len);
1773 memset(k3, 0, sizeof(k3));
1774 silc_hash_make(hash, dist->data, dist->len, k3);
1776 /* Then, save the keys */
1777 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1778 memcpy(dtmp, k1, hash_len);
1779 memcpy(dtmp + hash_len, k2, hash_len);
1780 memcpy(dtmp + hash_len, k3, hash_len);
1782 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1783 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1784 key->enc_key_len = req_enc_key_len;
1786 memset(dtmp, 0, (3 * hash_len));
1787 memset(k1, 0, sizeof(k1));
1788 memset(k2, 0, sizeof(k2));
1789 memset(k3, 0, sizeof(k3));
1791 silc_buffer_free(dist);
1793 /* Take normal hash as key */
1794 memset(hashd, 0, sizeof(hashd));
1795 silc_hash_make(hash, buf->data, buf->len, hashd);
1796 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1797 memcpy(key->receive_enc_key, hashd, enc_key_len);
1798 key->enc_key_len = req_enc_key_len;
1802 memset(hashd, 0, sizeof(hashd));
1804 silc_hash_make(hash, buf->data, buf->len, hashd);
1805 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1806 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1807 key->hmac_key_len = req_hmac_key_len;
1809 silc_buffer_free(buf);
1811 return SILC_SKE_STATUS_OK;
1814 /* Processes negotiated key material as protocol specifies. This returns
1815 the actual keys to be used in the SILC. */
1817 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1819 uint32 req_enc_key_len,
1820 uint32 req_hmac_key_len,
1821 SilcSKEKeyMaterial *key)
1823 SilcSKEStatus status;
1825 unsigned char *tmpbuf;
1828 /* Encode KEY to binary data */
1829 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1831 buf = silc_buffer_alloc(klen + ske->hash_len);
1832 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1833 silc_buffer_format(buf,
1834 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1835 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1838 /* Process the key material */
1839 status = silc_ske_process_key_material_data(buf->data, buf->len,
1840 req_iv_len, req_enc_key_len,
1842 ske->prop->hash, key);
1844 memset(tmpbuf, 0, klen);
1846 silc_buffer_free(buf);
1851 /* Free key material structure */
1853 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1859 silc_free(key->send_iv);
1860 if (key->receive_iv)
1861 silc_free(key->receive_iv);
1862 if (key->send_enc_key) {
1863 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1864 silc_free(key->send_enc_key);
1866 if (key->receive_enc_key) {
1867 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1868 silc_free(key->receive_enc_key);
1870 if (key->hmac_key) {
1871 memset(key->hmac_key, 0, key->hmac_key_len);
1872 silc_free(key->hmac_key);