5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 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"
23 #include "payload_internal.h"
24 #include "groups_internal.h"
26 /* Allocates new SKE object. */
28 SilcSKE silc_ske_alloc()
32 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
34 ske = silc_calloc(1, sizeof(*ske));
35 ske->status = SILC_SKE_STATUS_OK;
40 /* Free's SKE object. */
42 void silc_ske_free(SilcSKE ske)
44 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
47 /* Free start payload */
48 if (ske->start_payload)
49 silc_ske_payload_start_free(ske->start_payload);
51 /* Free KE1 payload */
53 silc_ske_payload_one_free(ske->ke1_payload);
55 /* Free KE2 payload */
57 silc_ske_payload_two_free(ske->ke2_payload);
62 silc_free(ske->prop->group);
64 silc_pkcs_free(ske->prop->pkcs);
65 if (ske->prop->cipher)
66 silc_cipher_free(ske->prop->cipher);
68 silc_hash_free(ske->prop->hash);
71 if (ske->start_payload_copy)
72 silc_buffer_free(ske->start_payload_copy);
76 silc_mp_clear(ske->x);
80 silc_mp_clear(ske->KEY);
89 /* Starts the SILC Key Exchange protocol for initiator. The connection
90 to the remote end must be established before calling this function
91 and the connecting socket must be sent as argument. This function
92 creates the Key Exchange Start Paload which includes all our
93 configured security properties. This payload is then sent to the
94 remote end for further processing. This payload must be sent as
95 argument to the function, however, it must not be encoded
96 already, it is done by this function.
98 The packet sending is done by calling a callback function. Caller
99 must provide a routine to send the packet. */
101 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
102 SilcSocketConnection sock,
103 SilcSKEStartPayload *start_payload,
104 SilcSKESendPacketCb send_packet,
107 SilcSKEStatus status = SILC_SKE_STATUS_OK;
108 SilcBuffer payload_buf;
110 SILC_LOG_DEBUG(("Start"));
115 /* Encode the payload */
116 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
117 if (status != SILC_SKE_STATUS_OK)
120 /* Take a copy of the payload buffer for future use. It is used to
121 compute the HASH value. */
122 ske->start_payload_copy = silc_buffer_copy(payload_buf);
124 /* Send the packet. */
126 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
128 silc_buffer_free(payload_buf);
133 /* Function called after ske_initiator_start fuction. This receives
134 the remote ends Key Exchange Start payload which includes the
135 security properties selected by the responder from our payload
136 sent in the silc_ske_initiator_start function. */
138 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
139 SilcBuffer start_payload,
143 SilcSKEStatus status = SILC_SKE_STATUS_OK;
144 SilcSKEStartPayload *payload;
145 SilcSKESecurityProperties prop;
146 SilcSKEDiffieHellmanGroup group;
148 SILC_LOG_DEBUG(("Start"));
150 /* Decode the payload */
151 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
152 if (status != SILC_SKE_STATUS_OK) {
153 ske->status = status;
157 /* Take the selected security properties into use while doing
158 the key exchange. This is used only while doing the key
159 exchange. The same data is returned to upper levels by calling
160 the callback function. */
161 ske->prop = prop = silc_calloc(1, sizeof(*prop));
162 prop->flags = payload->flags;
163 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
164 if (status != SILC_SKE_STATUS_OK)
169 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
170 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
174 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
175 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
179 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
180 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
184 ske->start_payload = payload;
186 /* Return the received payload by calling the callback function. */
188 (*callback)(ske, context);
194 silc_ske_payload_start_free(payload);
199 silc_pkcs_free(prop->pkcs);
201 silc_cipher_free(prop->cipher);
203 silc_hash_free(prop->hash);
207 if (status == SILC_SKE_STATUS_OK)
208 return SILC_SKE_STATUS_ERROR;
210 ske->status = status;
214 /* This function creates random number x, such that 1 < x < q and
215 computes e = g ^ x mod p and sends the result to the remote end in
216 Key Exchange 1 Payload. */
218 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
219 SilcPublicKey public_key,
220 SilcSKESendPacketCb send_packet,
223 SilcSKEStatus status = SILC_SKE_STATUS_OK;
224 SilcBuffer payload_buf;
226 SilcSKEOnePayload *payload;
229 SILC_LOG_DEBUG(("Start"));
231 /* Create the random number x, 1 < x < q. */
232 x = silc_calloc(1, sizeof(*x));
235 silc_ske_create_rnd(ske, ske->prop->group->group_order,
236 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
238 if (status != SILC_SKE_STATUS_OK) {
241 ske->status = status;
245 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
247 /* Do the Diffie Hellman computation, e = g ^ x mod p */
249 silc_mp_powm(&e, &ske->prop->group->generator, x,
250 &ske->prop->group->group);
252 /* Encode the result to Key Exchange 1 Payload. */
253 payload = silc_calloc(1, sizeof(*payload));
255 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
256 if (!payload->pk_data) {
261 ske->status = SILC_SKE_STATUS_OK;
264 payload->pk_len = pk_len;
265 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
266 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
267 if (status != SILC_SKE_STATUS_OK) {
271 silc_free(payload->pk_data);
273 ske->status = status;
277 ske->ke1_payload = payload;
280 /* Send the packet. */
282 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
284 silc_buffer_free(payload_buf);
289 /* Receives Key Exchange 2 Payload from responder consisting responders
290 public key, f, and signature. This function verifies the public key,
291 computes the secret shared key and verifies the signature. */
293 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
294 SilcBuffer ke2_payload,
295 SilcSKEVerifyCb verify_key,
296 void *verify_context,
300 SilcSKEStatus status = SILC_SKE_STATUS_OK;
301 SilcSKETwoPayload *payload;
302 SilcPublicKey public_key = NULL;
304 unsigned char hash[32];
305 unsigned int hash_len;
307 SILC_LOG_DEBUG(("Start"));
309 /* Decode the payload */
310 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
311 if (status != SILC_SKE_STATUS_OK) {
312 ske->status = status;
315 ske->ke2_payload = payload;
317 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
319 /* Compute the shared secret key */
320 KEY = silc_calloc(1, sizeof(*KEY));
322 silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
325 SILC_LOG_DEBUG(("Verifying public key"));
327 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
329 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
334 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
335 payload->pk_type, verify_context);
336 if (status != SILC_SKE_STATUS_OK)
340 SILC_LOG_DEBUG(("Public key is authentic"));
342 /* Compute the hash value */
343 status = silc_ske_make_hash(ske, hash, &hash_len);
344 if (status != SILC_SKE_STATUS_OK)
347 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
348 memcpy(ske->hash, hash, hash_len);
349 ske->hash_len = hash_len;
351 SILC_LOG_DEBUG(("Verifying signature"));
353 /* Verify signature */
354 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
356 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
357 payload->sign_len, hash, hash_len) == FALSE) {
359 SILC_LOG_DEBUG(("Signature don't match"));
361 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
365 SILC_LOG_DEBUG(("Signature is Ok"));
367 silc_pkcs_public_key_free(public_key);
368 memset(hash, 'F', hash_len);
370 /* Call the callback. */
372 (*callback)(ske, context);
377 memset(hash, 'F', sizeof(hash));
378 silc_ske_payload_two_free(payload);
379 ske->ke2_payload = NULL;
381 silc_mp_clear(ske->KEY);
386 silc_pkcs_public_key_free(public_key);
389 memset(ske->hash, 'F', hash_len);
390 silc_free(ske->hash);
394 if (status == SILC_SKE_STATUS_OK)
395 return SILC_SKE_STATUS_ERROR;
397 ske->status = status;
401 /* Starts Key Exchange protocol for responder. Responder receives
402 Key Exchange Start Payload from initiator consisting of all the
403 security properties the initiator supports. This function decodes
404 the payload and parses the payload further and selects the right
405 security properties. */
407 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
408 SilcSocketConnection sock,
410 SilcBuffer start_payload,
414 SilcSKEStatus status = SILC_SKE_STATUS_OK;
415 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
417 SILC_LOG_DEBUG(("Start"));
422 /* Decode the payload */
423 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
424 if (status != SILC_SKE_STATUS_OK) {
425 ske->status = status;
429 /* Take a copy of the payload buffer for future use. It is used to
430 compute the HASH value. */
431 ske->start_payload_copy = silc_buffer_copy(start_payload);
433 /* Parse and select the security properties from the payload */
434 payload = silc_calloc(1, sizeof(*payload));
435 status = silc_ske_select_security_properties(ske, version,
436 payload, remote_payload);
437 if (status != SILC_SKE_STATUS_OK)
440 ske->start_payload = payload;
442 /* Call the callback function. */
444 (*callback)(ske, context);
450 silc_ske_payload_start_free(remote_payload);
454 if (status == SILC_SKE_STATUS_OK)
455 return SILC_SKE_STATUS_ERROR;
457 ske->status = status;
461 /* The selected security properties from the initiator payload is now
462 encoded into Key Exchange Start Payload and sent to the initiator. */
464 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
465 SilcSKEStartPayload *start_payload,
466 SilcSKESendPacketCb send_packet,
469 SilcSKEStatus status = SILC_SKE_STATUS_OK;
470 SilcBuffer payload_buf;
471 SilcSKESecurityProperties prop;
472 SilcSKEDiffieHellmanGroup group = NULL;
474 SILC_LOG_DEBUG(("Start"));
476 /* Allocate security properties from the payload. These are allocated
477 only for this negotiation and will be free'd after KE is over. */
478 ske->prop = prop = silc_calloc(1, sizeof(*prop));
479 prop->flags = start_payload->flags;
480 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
481 if (status != SILC_SKE_STATUS_OK)
486 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
487 &prop->pkcs) == FALSE) {
488 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
492 if (silc_cipher_alloc(start_payload->enc_alg_list,
493 &prop->cipher) == FALSE) {
494 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
498 if (silc_hash_alloc(start_payload->hash_alg_list,
499 &prop->hash) == FALSE) {
500 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
504 /* Encode the payload */
505 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
506 if (status != SILC_SKE_STATUS_OK)
509 /* Send the packet. */
511 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
513 silc_buffer_free(payload_buf);
522 silc_pkcs_free(prop->pkcs);
524 silc_cipher_free(prop->cipher);
526 silc_hash_free(prop->hash);
530 if (status == SILC_SKE_STATUS_OK)
531 return SILC_SKE_STATUS_ERROR;
533 ske->status = status;
537 /* This function receives the Key Exchange 1 Payload from the initiator.
538 After processing the payload this then selects random number x,
539 such that 1 < x < q and computes f = g ^ x mod p. This then puts
540 the result f to a Key Exchange 2 Payload which is later processed
541 in ske_responder_finish function. The callback function should
542 not touch the payload (it should merely call the ske_responder_finish
545 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
546 SilcBuffer ke1_payload,
550 SilcSKEStatus status = SILC_SKE_STATUS_OK;
551 SilcSKEOnePayload *one_payload;
552 SilcSKETwoPayload *two_payload;
555 SILC_LOG_DEBUG(("Start"));
557 /* Decode Key Exchange 1 Payload */
558 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
559 if (status != SILC_SKE_STATUS_OK) {
560 ske->status = status;
564 /* Create the random number x, 1 < x < q. */
565 x = silc_calloc(1, sizeof(*x));
568 silc_ske_create_rnd(ske, ske->prop->group->group_order,
569 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
571 if (status != SILC_SKE_STATUS_OK) {
577 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
579 /* Do the Diffie Hellman computation, f = g ^ x mod p */
581 silc_mp_powm(&f, &ske->prop->group->generator, x,
582 &ske->prop->group->group);
584 /* Save the results for later processing */
585 two_payload = silc_calloc(1, sizeof(*two_payload));
588 ske->ke1_payload = one_payload;
589 ske->ke2_payload = two_payload;
591 /* Call the callback. */
593 (*callback)(ske, context);
598 /* This function computes the secret shared key KEY = e ^ x mod p, and,
599 a hash value to be signed and sent to the other end. This then
600 encodes Key Exchange 2 Payload and sends it to the other end. */
602 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
603 SilcPublicKey public_key,
604 SilcPrivateKey private_key,
605 SilcSKEPKType pk_type,
606 SilcSKESendPacketCb send_packet,
609 SilcSKEStatus status = SILC_SKE_STATUS_OK;
610 SilcBuffer payload_buf;
612 unsigned char hash[32], sign[256], *pk;
613 unsigned int hash_len, sign_len, pk_len;
615 SILC_LOG_DEBUG(("Start"));
617 if (!public_key || !private_key) {
618 status = SILC_SKE_STATUS_ERROR;
622 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
624 /* Compute the shared secret key */
625 KEY = silc_calloc(1, sizeof(*KEY));
627 silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
628 &ske->prop->group->group);
631 SILC_LOG_DEBUG(("Getting public key"));
633 /* Get the public key */
634 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
636 status = SILC_SKE_STATUS_ERROR;
639 ske->ke2_payload->pk_data = pk;
640 ske->ke2_payload->pk_len = pk_len;
641 ske->ke2_payload->pk_type = pk_type;
643 SILC_LOG_DEBUG(("Computing HASH value"));
645 /* Compute the hash value */
646 memset(hash, 0, sizeof(hash));
647 status = silc_ske_make_hash(ske, hash, &hash_len);
648 if (status != SILC_SKE_STATUS_OK)
651 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
652 memcpy(ske->hash, hash, hash_len);
653 ske->hash_len = hash_len;
655 SILC_LOG_DEBUG(("Signing HASH value"));
657 /* Sign the hash value */
658 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
659 private_key->prv_len);
660 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
661 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
662 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
663 memset(sign, 0, sizeof(sign));
664 ske->ke2_payload->sign_len = sign_len;
666 /* Encode the Key Exchange 2 Payload */
667 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
669 if (status != SILC_SKE_STATUS_OK)
672 /* Send the packet. */
674 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
676 silc_buffer_free(payload_buf);
681 silc_mp_clear(ske->KEY);
684 silc_ske_payload_two_free(ske->ke2_payload);
686 if (status == SILC_SKE_STATUS_OK)
687 return SILC_SKE_STATUS_ERROR;
689 ske->status = status;
693 /* The Key Exchange protocol is ended by calling this function. This
694 must not be called until the keys are processed like the protocol
695 defines. This function is for both initiator and responder. */
697 SilcSKEStatus silc_ske_end(SilcSKE ske,
698 SilcSKESendPacketCb send_packet,
703 SILC_LOG_DEBUG(("Start"));
705 packet = silc_buffer_alloc(4);
706 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
707 silc_buffer_format(packet,
708 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
712 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
714 silc_buffer_free(packet);
716 return SILC_SKE_STATUS_OK;
719 /* Aborts the Key Exchange protocol. This is called if error occurs
720 while performing the protocol. The status argument is the error
721 status and it is sent to the remote end. */
723 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
724 SilcSKESendPacketCb send_packet,
729 SILC_LOG_DEBUG(("Start"));
731 packet = silc_buffer_alloc(4);
732 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
733 silc_buffer_format(packet,
734 SILC_STR_UI_SHORT(status),
738 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
740 silc_buffer_free(packet);
742 return SILC_SKE_STATUS_OK;
745 /* Assembles security properties to Key Exchange Start Payload to be
746 sent to the remote end. This checks system wide (SILC system, that is)
747 settings and chooses from those. However, if other properties
748 should be used this function is easy to replace by another function,
749 as, this function is called by the caller of the protocol and not
750 by the protocol itself. */
753 silc_ske_assemble_security_properties(SilcSKE ske,
756 SilcSKEStartPayload **return_payload)
758 SilcSKEStartPayload *rp;
761 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
763 rp = silc_calloc(1, sizeof(*rp));
768 /* Set random cookie */
769 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
770 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
771 rp->cookie[i] = silc_rng_get_byte(ske->rng);
772 rp->cookie_len = SILC_SKE_COOKIE_LEN;
775 rp->version = strdup(version);
776 rp->version_len = strlen(version);
778 /* Get supported Key Exhange groups */
779 rp->ke_grp_list = silc_ske_get_supported_groups();
780 rp->ke_grp_len = strlen(rp->ke_grp_list);
782 /* Get supported PKCS algorithms */
783 rp->pkcs_alg_list = silc_pkcs_get_supported();
784 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
786 /* Get supported encryption algorithms */
787 rp->enc_alg_list = silc_cipher_get_supported();
788 rp->enc_alg_len = strlen(rp->enc_alg_list);
790 /* Get supported hash algorithms */
791 rp->hash_alg_list = silc_hash_get_supported();
792 rp->hash_alg_len = strlen(rp->hash_alg_list);
795 /* Get supported compression algorithms */
796 rp->comp_alg_list = "";
797 rp->comp_alg_len = 0;
799 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
800 2 + rp->version_len +
801 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
802 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
803 2 + rp->comp_alg_len;
805 *return_payload = rp;
807 return SILC_SKE_STATUS_OK;
810 /* Selects the supported security properties from the remote end's Key
811 Exchange Start Payload. */
814 silc_ske_select_security_properties(SilcSKE ske,
816 SilcSKEStartPayload *payload,
817 SilcSKEStartPayload *remote_payload)
819 SilcSKEStatus status;
820 SilcSKEStartPayload *rp;
824 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
828 /* Check version string */
829 status = silc_ske_check_version(ske, rp->version, rp->version_len);
830 if (status != SILC_SKE_STATUS_OK) {
831 ske->status = status;
835 /* Flags are returned unchanged. */
836 payload->flags = rp->flags;
839 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
840 payload->cookie_len = SILC_SKE_COOKIE_LEN;
841 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
843 /* Put our version to our reply */
844 payload->version = strdup(version);
845 payload->version_len = strlen(version);
847 /* Get supported Key Exchange groups */
848 cp = rp->ke_grp_list;
849 if (cp && strchr(cp, ',')) {
853 len = strcspn(cp, ",");
854 item = silc_calloc(len + 1, sizeof(char));
855 memcpy(item, cp, len);
857 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
859 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
860 SILC_LOG_DEBUG(("Found KE group `%s'", item));
862 payload->ke_grp_len = len;
863 payload->ke_grp_list = item;
877 if (!payload->ke_grp_len && !payload->ke_grp_list) {
878 SILC_LOG_DEBUG(("Could not find supported KE group"));
880 return SILC_SKE_STATUS_UNKNOWN_GROUP;
884 if (!rp->ke_grp_len) {
885 SILC_LOG_DEBUG(("KE group not defined in payload"));
887 return SILC_SKE_STATUS_BAD_PAYLOAD;
890 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
891 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
893 payload->ke_grp_len = rp->ke_grp_len;
894 payload->ke_grp_list = strdup(rp->ke_grp_list);
897 /* Get supported PKCS algorithms */
898 cp = rp->pkcs_alg_list;
899 if (cp && strchr(cp, ',')) {
903 len = strcspn(cp, ",");
904 item = silc_calloc(len + 1, sizeof(char));
905 memcpy(item, cp, len);
907 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
909 if (silc_pkcs_is_supported(item) == TRUE) {
910 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
912 payload->pkcs_alg_len = len;
913 payload->pkcs_alg_list = item;
927 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
928 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
929 silc_free(payload->ke_grp_list);
931 return SILC_SKE_STATUS_UNKNOWN_PKCS;
935 if (!rp->pkcs_alg_len) {
936 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
937 silc_free(payload->ke_grp_list);
939 return SILC_SKE_STATUS_BAD_PAYLOAD;
942 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
943 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
945 payload->pkcs_alg_len = rp->pkcs_alg_len;
946 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
949 /* Get supported encryption algorithms */
950 cp = rp->enc_alg_list;
951 if (cp && strchr(cp, ',')) {
955 len = strcspn(cp, ",");
956 item = silc_calloc(len + 1, sizeof(char));
957 memcpy(item, cp, len);
959 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
961 if (silc_cipher_is_supported(item) == TRUE) {
962 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
964 payload->enc_alg_len = len;
965 payload->enc_alg_list = item;
979 if (!payload->enc_alg_len && !payload->enc_alg_list) {
980 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
981 silc_free(payload->ke_grp_list);
982 silc_free(payload->pkcs_alg_list);
984 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
988 if (!rp->enc_alg_len) {
989 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
990 silc_free(payload->ke_grp_list);
991 silc_free(payload->pkcs_alg_list);
993 return SILC_SKE_STATUS_BAD_PAYLOAD;
996 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
999 payload->enc_alg_len = rp->enc_alg_len;
1000 payload->enc_alg_list = strdup(rp->enc_alg_list);
1003 /* Get supported hash algorithms */
1004 cp = rp->hash_alg_list;
1005 if (cp && strchr(cp, ',')) {
1009 len = strcspn(cp, ",");
1010 item = silc_calloc(len + 1, sizeof(char));
1011 memcpy(item, cp, len);
1013 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1015 if (silc_hash_is_supported(item) == TRUE) {
1016 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1018 payload->hash_alg_len = len;
1019 payload->hash_alg_list = item;
1024 if (strlen(cp) == 0)
1033 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1034 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1035 silc_free(payload->ke_grp_list);
1036 silc_free(payload->pkcs_alg_list);
1037 silc_free(payload->enc_alg_list);
1039 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1043 if (!rp->hash_alg_len) {
1044 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1045 silc_free(payload->ke_grp_list);
1046 silc_free(payload->pkcs_alg_list);
1047 silc_free(payload->enc_alg_list);
1049 return SILC_SKE_STATUS_BAD_PAYLOAD;
1052 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1053 rp->hash_alg_list));
1055 payload->hash_alg_len = rp->hash_alg_len;
1056 payload->hash_alg_list = strdup(rp->hash_alg_list);
1060 /* Get supported compression algorithms */
1061 cp = rp->hash_alg_list;
1062 if (cp && strchr(cp, ',')) {
1066 len = strcspn(cp, ",");
1067 item = silc_calloc(len + 1, sizeof(char));
1068 memcpy(item, cp, len);
1070 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1072 if (silc_hash_is_supported(item) == TRUE) {
1073 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1075 payload->hash_alg_len = len;
1076 payload->hash_alg_list = item;
1081 if (strlen(cp) == 0)
1090 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1091 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1092 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1093 silc_free(payload->ke_grp_list);
1094 silc_free(payload->pkcs_alg_list);
1095 silc_free(payload->enc_alg_list);
1104 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1105 2 + payload->version_len +
1106 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1107 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1108 2 + payload->comp_alg_len;
1110 return SILC_SKE_STATUS_OK;
1113 /* Creates random number such that 1 < rnd < n and at most length
1114 of len bits. The rnd sent as argument must be initialized. */
1116 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1120 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1121 unsigned char *string;
1123 SILC_LOG_DEBUG(("Creating random number"));
1125 /* Get the random number as string */
1126 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1128 return SILC_SKE_STATUS_ERROR;
1130 /* Decode the string into a MP integer */
1131 silc_mp_bin2mp(string, (len / 8), rnd);
1132 silc_mp_mod_2exp(rnd, rnd, len);
1135 if (silc_mp_cmp_ui(rnd, 1) < 0)
1136 status = SILC_SKE_STATUS_ERROR;
1138 if (silc_mp_cmp(rnd, &n) >= 0)
1139 status = SILC_SKE_STATUS_ERROR;
1141 memset(string, 'F', (len / 8));
1147 /* Creates a hash value HASH as defined in the SKE protocol. */
1149 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1150 unsigned char *return_hash,
1151 unsigned int *return_hash_len)
1153 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1155 unsigned char *e, *f, *KEY;
1156 unsigned int e_len, f_len, KEY_len;
1159 SILC_LOG_DEBUG(("Start"));
1161 e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
1162 f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
1163 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1165 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1166 ske->pk_len + e_len + f_len + KEY_len);
1167 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1169 /* Format the buffer used to compute the hash value */
1170 ret = silc_buffer_format(buf,
1171 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1172 ske->start_payload_copy->len),
1173 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1174 SILC_STR_UI_XNSTRING(e, e_len),
1175 SILC_STR_UI_XNSTRING(f, f_len),
1176 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1179 silc_buffer_free(buf);
1180 memset(e, 0, e_len);
1181 memset(f, 0, f_len);
1182 memset(KEY, 0, KEY_len);
1186 return SILC_SKE_STATUS_ERROR;
1190 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1191 *return_hash_len = ske->prop->hash->hash->hash_len;
1193 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1195 silc_buffer_free(buf);
1196 memset(e, 0, e_len);
1197 memset(f, 0, f_len);
1198 memset(KEY, 0, KEY_len);
1206 /* Processes negotiated key material as protocol specifies. This returns
1207 the actual keys to be used in the SILC. */
1209 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1210 unsigned int req_iv_len,
1211 unsigned int req_enc_key_len,
1212 unsigned int req_hmac_key_len,
1213 SilcSKEKeyMaterial *key)
1217 unsigned char *tmpbuf;
1218 unsigned char hash[32];
1219 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1220 unsigned int enc_key_len = req_enc_key_len / 8;
1223 SILC_LOG_DEBUG(("Start"));
1225 /* Encode KEY to binary data */
1226 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1228 buf = silc_buffer_alloc(1 + klen + hash_len);
1229 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1230 ret = silc_buffer_format(buf,
1231 SILC_STR_UI_CHAR(0),
1232 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1233 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1236 memset(tmpbuf, 0, klen);
1238 silc_buffer_free(buf);
1239 return SILC_SKE_STATUS_ERROR;
1243 memset(hash, 0, sizeof(hash));
1245 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1246 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1247 memcpy(key->send_iv, hash, req_iv_len);
1248 memset(hash, 0, sizeof(hash));
1250 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1251 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1252 memcpy(key->receive_iv, hash, req_iv_len);
1253 key->iv_len = req_iv_len;
1255 /* Take the encryption keys. If requested key size is more than
1256 the size of hash length we will distribute more key material
1257 as protocol defines. */
1259 if (enc_key_len > hash_len) {
1261 unsigned char k1[32], k2[32], k3[32];
1262 unsigned char *dtmp;
1265 if (enc_key_len > (3 * hash_len))
1266 return SILC_SKE_STATUS_ERROR;
1268 memset(k1, 0, sizeof(k1));
1269 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1272 dist = silc_buffer_alloc(hash_len * 3);
1274 silc_buffer_pull_tail(dist, klen + hash_len);
1275 silc_buffer_format(dist,
1276 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1277 SILC_STR_UI_XNSTRING(k1, hash_len),
1280 memset(k2, 0, sizeof(k2));
1281 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1283 silc_buffer_pull(dist, klen + hash_len);
1284 silc_buffer_format(dist,
1285 SILC_STR_UI_XNSTRING(k2, hash_len),
1287 silc_buffer_push(dist, klen + hash_len);
1289 memset(k3, 0, sizeof(k3));
1290 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1292 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1293 memcpy(dtmp, k1, hash_len);
1294 memcpy(dtmp + hash_len, k2, hash_len);
1295 memcpy(dtmp + hash_len, k3, hash_len);
1297 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1298 memcpy(key->send_enc_key, dtmp, enc_key_len);
1299 key->enc_key_len = req_enc_key_len;
1301 memset(dtmp, 0, (3 * hash_len));
1302 memset(k1, 0, sizeof(k1));
1303 memset(k2, 0, sizeof(k2));
1304 memset(k3, 0, sizeof(k3));
1306 silc_buffer_free(dist);
1308 /* Take normal hash as key */
1309 memset(hash, 0, sizeof(hash));
1310 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1311 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1312 memcpy(key->send_enc_key, hash, enc_key_len);
1313 key->enc_key_len = req_enc_key_len;
1317 if (enc_key_len > hash_len) {
1319 unsigned char k1[32], k2[32], k3[32];
1320 unsigned char *dtmp;
1323 if (enc_key_len > (3 * hash_len))
1324 return SILC_SKE_STATUS_ERROR;
1326 memset(k1, 0, sizeof(k1));
1327 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1330 dist = silc_buffer_alloc(hash_len * 3);
1332 silc_buffer_pull_tail(dist, klen + hash_len);
1333 silc_buffer_format(dist,
1334 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1335 SILC_STR_UI_XNSTRING(k1, hash_len),
1338 memset(k2, 0, sizeof(k2));
1339 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1341 silc_buffer_pull(dist, klen + hash_len);
1342 silc_buffer_format(dist,
1343 SILC_STR_UI_XNSTRING(k2, hash_len),
1345 silc_buffer_push(dist, klen + hash_len);
1347 memset(k3, 0, sizeof(k3));
1348 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1350 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1351 memcpy(dtmp, k1, hash_len);
1352 memcpy(dtmp + hash_len, k2, hash_len);
1353 memcpy(dtmp + hash_len, k3, hash_len);
1355 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1356 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1357 key->enc_key_len = req_enc_key_len;
1359 memset(dtmp, 0, (3 * hash_len));
1360 memset(k1, 0, sizeof(k1));
1361 memset(k2, 0, sizeof(k2));
1362 memset(k3, 0, sizeof(k3));
1364 silc_buffer_free(dist);
1366 /* Take normal hash as key */
1367 memset(hash, 0, sizeof(hash));
1368 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1369 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1370 memcpy(key->receive_enc_key, hash, enc_key_len);
1371 key->enc_key_len = req_enc_key_len;
1375 memset(hash, 0, sizeof(hash));
1377 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1378 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1379 memcpy(key->hmac_key, hash, req_hmac_key_len);
1380 key->hmac_key_len = req_hmac_key_len;
1382 memset(tmpbuf, 0, klen);
1385 return SILC_SKE_STATUS_OK;