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 (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
357 payload->sign_data, payload->sign_len,
358 hash, hash_len) == FALSE) {
360 SILC_LOG_DEBUG(("Signature don't match"));
362 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
366 SILC_LOG_DEBUG(("Signature is Ok"));
368 silc_pkcs_public_key_free(public_key);
369 memset(hash, 'F', hash_len);
371 /* Call the callback. */
373 (*callback)(ske, context);
378 memset(hash, 'F', sizeof(hash));
379 silc_ske_payload_two_free(payload);
380 ske->ke2_payload = NULL;
382 silc_mp_clear(ske->KEY);
387 silc_pkcs_public_key_free(public_key);
390 memset(ske->hash, 'F', hash_len);
391 silc_free(ske->hash);
395 if (status == SILC_SKE_STATUS_OK)
396 return SILC_SKE_STATUS_ERROR;
398 ske->status = status;
402 /* Starts Key Exchange protocol for responder. Responder receives
403 Key Exchange Start Payload from initiator consisting of all the
404 security properties the initiator supports. This function decodes
405 the payload and parses the payload further and selects the right
406 security properties. */
408 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
409 SilcSocketConnection sock,
411 SilcBuffer start_payload,
415 SilcSKEStatus status = SILC_SKE_STATUS_OK;
416 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
418 SILC_LOG_DEBUG(("Start"));
423 /* Decode the payload */
424 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
425 if (status != SILC_SKE_STATUS_OK) {
426 ske->status = status;
430 /* Take a copy of the payload buffer for future use. It is used to
431 compute the HASH value. */
432 ske->start_payload_copy = silc_buffer_copy(start_payload);
434 /* Parse and select the security properties from the payload */
435 payload = silc_calloc(1, sizeof(*payload));
436 status = silc_ske_select_security_properties(ske, version,
437 payload, remote_payload);
438 if (status != SILC_SKE_STATUS_OK)
441 ske->start_payload = payload;
443 /* Call the callback function. */
445 (*callback)(ske, context);
451 silc_ske_payload_start_free(remote_payload);
455 if (status == SILC_SKE_STATUS_OK)
456 return SILC_SKE_STATUS_ERROR;
458 ske->status = status;
462 /* The selected security properties from the initiator payload is now
463 encoded into Key Exchange Start Payload and sent to the initiator. */
465 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
466 SilcSKEStartPayload *start_payload,
467 SilcSKESendPacketCb send_packet,
470 SilcSKEStatus status = SILC_SKE_STATUS_OK;
471 SilcBuffer payload_buf;
472 SilcSKESecurityProperties prop;
473 SilcSKEDiffieHellmanGroup group = NULL;
475 SILC_LOG_DEBUG(("Start"));
477 /* Allocate security properties from the payload. These are allocated
478 only for this negotiation and will be free'd after KE is over. */
479 ske->prop = prop = silc_calloc(1, sizeof(*prop));
480 prop->flags = start_payload->flags;
481 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
482 if (status != SILC_SKE_STATUS_OK)
487 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
488 &prop->pkcs) == FALSE) {
489 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
493 if (silc_cipher_alloc(start_payload->enc_alg_list,
494 &prop->cipher) == FALSE) {
495 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
499 if (silc_hash_alloc(start_payload->hash_alg_list,
500 &prop->hash) == FALSE) {
501 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
505 /* Encode the payload */
506 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
507 if (status != SILC_SKE_STATUS_OK)
510 /* Send the packet. */
512 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
514 silc_buffer_free(payload_buf);
523 silc_pkcs_free(prop->pkcs);
525 silc_cipher_free(prop->cipher);
527 silc_hash_free(prop->hash);
531 if (status == SILC_SKE_STATUS_OK)
532 return SILC_SKE_STATUS_ERROR;
534 ske->status = status;
538 /* This function receives the Key Exchange 1 Payload from the initiator.
539 After processing the payload this then selects random number x,
540 such that 1 < x < q and computes f = g ^ x mod p. This then puts
541 the result f to a Key Exchange 2 Payload which is later processed
542 in ske_responder_finish function. The callback function should
543 not touch the payload (it should merely call the ske_responder_finish
546 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
547 SilcBuffer ke1_payload,
551 SilcSKEStatus status = SILC_SKE_STATUS_OK;
552 SilcSKEOnePayload *one_payload;
553 SilcSKETwoPayload *two_payload;
556 SILC_LOG_DEBUG(("Start"));
558 /* Decode Key Exchange 1 Payload */
559 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
560 if (status != SILC_SKE_STATUS_OK) {
561 ske->status = status;
565 /* Create the random number x, 1 < x < q. */
566 x = silc_calloc(1, sizeof(*x));
569 silc_ske_create_rnd(ske, ske->prop->group->group_order,
570 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
572 if (status != SILC_SKE_STATUS_OK) {
578 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
580 /* Do the Diffie Hellman computation, f = g ^ x mod p */
582 silc_mp_powm(&f, &ske->prop->group->generator, x,
583 &ske->prop->group->group);
585 /* Save the results for later processing */
586 two_payload = silc_calloc(1, sizeof(*two_payload));
589 ske->ke1_payload = one_payload;
590 ske->ke2_payload = two_payload;
592 /* Call the callback. */
594 (*callback)(ske, context);
599 /* This function computes the secret shared key KEY = e ^ x mod p, and,
600 a hash value to be signed and sent to the other end. This then
601 encodes Key Exchange 2 Payload and sends it to the other end. */
603 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
604 SilcPublicKey public_key,
605 SilcPrivateKey private_key,
606 SilcSKEPKType pk_type,
607 SilcSKESendPacketCb send_packet,
610 SilcSKEStatus status = SILC_SKE_STATUS_OK;
611 SilcBuffer payload_buf;
613 unsigned char hash[32], sign[256], *pk;
614 unsigned int hash_len, sign_len, pk_len;
616 SILC_LOG_DEBUG(("Start"));
618 if (!public_key || !private_key) {
619 status = SILC_SKE_STATUS_ERROR;
623 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
625 /* Compute the shared secret key */
626 KEY = silc_calloc(1, sizeof(*KEY));
628 silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
629 &ske->prop->group->group);
632 SILC_LOG_DEBUG(("Getting public key"));
634 /* Get the public key */
635 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
637 status = SILC_SKE_STATUS_ERROR;
640 ske->ke2_payload->pk_data = pk;
641 ske->ke2_payload->pk_len = pk_len;
642 ske->ke2_payload->pk_type = pk_type;
644 SILC_LOG_DEBUG(("Computing HASH value"));
646 /* Compute the hash value */
647 memset(hash, 0, sizeof(hash));
648 status = silc_ske_make_hash(ske, hash, &hash_len);
649 if (status != SILC_SKE_STATUS_OK)
652 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
653 memcpy(ske->hash, hash, hash_len);
654 ske->hash_len = hash_len;
656 SILC_LOG_DEBUG(("Signing HASH value"));
658 /* Sign the hash value */
659 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
660 private_key->prv_len);
661 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
664 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
665 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
666 memset(sign, 0, sizeof(sign));
667 ske->ke2_payload->sign_len = sign_len;
669 /* Encode the Key Exchange 2 Payload */
670 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
672 if (status != SILC_SKE_STATUS_OK)
675 /* Send the packet. */
677 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
679 silc_buffer_free(payload_buf);
684 silc_mp_clear(ske->KEY);
687 silc_ske_payload_two_free(ske->ke2_payload);
689 if (status == SILC_SKE_STATUS_OK)
690 return SILC_SKE_STATUS_ERROR;
692 ske->status = status;
696 /* The Key Exchange protocol is ended by calling this function. This
697 must not be called until the keys are processed like the protocol
698 defines. This function is for both initiator and responder. */
700 SilcSKEStatus silc_ske_end(SilcSKE ske,
701 SilcSKESendPacketCb send_packet,
706 SILC_LOG_DEBUG(("Start"));
708 packet = silc_buffer_alloc(4);
709 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
710 silc_buffer_format(packet,
711 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
715 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
717 silc_buffer_free(packet);
719 return SILC_SKE_STATUS_OK;
722 /* Aborts the Key Exchange protocol. This is called if error occurs
723 while performing the protocol. The status argument is the error
724 status and it is sent to the remote end. */
726 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
727 SilcSKESendPacketCb send_packet,
732 SILC_LOG_DEBUG(("Start"));
734 packet = silc_buffer_alloc(4);
735 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
736 silc_buffer_format(packet,
737 SILC_STR_UI_SHORT(status),
741 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
743 silc_buffer_free(packet);
745 return SILC_SKE_STATUS_OK;
748 /* Assembles security properties to Key Exchange Start Payload to be
749 sent to the remote end. This checks system wide (SILC system, that is)
750 settings and chooses from those. However, if other properties
751 should be used this function is easy to replace by another function,
752 as, this function is called by the caller of the protocol and not
753 by the protocol itself. */
756 silc_ske_assemble_security_properties(SilcSKE ske,
759 SilcSKEStartPayload **return_payload)
761 SilcSKEStartPayload *rp;
764 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
766 rp = silc_calloc(1, sizeof(*rp));
771 /* Set random cookie */
772 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
773 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
774 rp->cookie[i] = silc_rng_get_byte(ske->rng);
775 rp->cookie_len = SILC_SKE_COOKIE_LEN;
778 rp->version = strdup(version);
779 rp->version_len = strlen(version);
781 /* Get supported Key Exhange groups */
782 rp->ke_grp_list = silc_ske_get_supported_groups();
783 rp->ke_grp_len = strlen(rp->ke_grp_list);
785 /* Get supported PKCS algorithms */
786 rp->pkcs_alg_list = silc_pkcs_get_supported();
787 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
789 /* Get supported encryption algorithms */
790 rp->enc_alg_list = silc_cipher_get_supported();
791 rp->enc_alg_len = strlen(rp->enc_alg_list);
793 /* Get supported hash algorithms */
794 rp->hash_alg_list = silc_hash_get_supported();
795 rp->hash_alg_len = strlen(rp->hash_alg_list);
798 /* Get supported compression algorithms */
799 rp->comp_alg_list = "";
800 rp->comp_alg_len = 0;
802 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
803 2 + rp->version_len +
804 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
805 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
806 2 + rp->comp_alg_len;
808 *return_payload = rp;
810 return SILC_SKE_STATUS_OK;
813 /* Selects the supported security properties from the remote end's Key
814 Exchange Start Payload. */
817 silc_ske_select_security_properties(SilcSKE ske,
819 SilcSKEStartPayload *payload,
820 SilcSKEStartPayload *remote_payload)
822 SilcSKEStatus status;
823 SilcSKEStartPayload *rp;
827 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
831 /* Check version string */
832 status = silc_ske_check_version(ske, rp->version, rp->version_len);
833 if (status != SILC_SKE_STATUS_OK) {
834 ske->status = status;
838 /* Flags are returned unchanged. */
839 payload->flags = rp->flags;
842 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
843 payload->cookie_len = SILC_SKE_COOKIE_LEN;
844 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
846 /* Put our version to our reply */
847 payload->version = strdup(version);
848 payload->version_len = strlen(version);
850 /* Get supported Key Exchange groups */
851 cp = rp->ke_grp_list;
852 if (cp && strchr(cp, ',')) {
856 len = strcspn(cp, ",");
857 item = silc_calloc(len + 1, sizeof(char));
858 memcpy(item, cp, len);
860 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
862 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
863 SILC_LOG_DEBUG(("Found KE group `%s'", item));
865 payload->ke_grp_len = len;
866 payload->ke_grp_list = item;
880 if (!payload->ke_grp_len && !payload->ke_grp_list) {
881 SILC_LOG_DEBUG(("Could not find supported KE group"));
883 return SILC_SKE_STATUS_UNKNOWN_GROUP;
887 if (!rp->ke_grp_len) {
888 SILC_LOG_DEBUG(("KE group not defined in payload"));
890 return SILC_SKE_STATUS_BAD_PAYLOAD;
893 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
894 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
896 payload->ke_grp_len = rp->ke_grp_len;
897 payload->ke_grp_list = strdup(rp->ke_grp_list);
900 /* Get supported PKCS algorithms */
901 cp = rp->pkcs_alg_list;
902 if (cp && strchr(cp, ',')) {
906 len = strcspn(cp, ",");
907 item = silc_calloc(len + 1, sizeof(char));
908 memcpy(item, cp, len);
910 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
912 if (silc_pkcs_is_supported(item) == TRUE) {
913 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
915 payload->pkcs_alg_len = len;
916 payload->pkcs_alg_list = item;
930 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
931 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
932 silc_free(payload->ke_grp_list);
934 return SILC_SKE_STATUS_UNKNOWN_PKCS;
938 if (!rp->pkcs_alg_len) {
939 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
940 silc_free(payload->ke_grp_list);
942 return SILC_SKE_STATUS_BAD_PAYLOAD;
945 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
946 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
948 payload->pkcs_alg_len = rp->pkcs_alg_len;
949 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
952 /* Get supported encryption algorithms */
953 cp = rp->enc_alg_list;
954 if (cp && strchr(cp, ',')) {
958 len = strcspn(cp, ",");
959 item = silc_calloc(len + 1, sizeof(char));
960 memcpy(item, cp, len);
962 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
964 if (silc_cipher_is_supported(item) == TRUE) {
965 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
967 payload->enc_alg_len = len;
968 payload->enc_alg_list = item;
982 if (!payload->enc_alg_len && !payload->enc_alg_list) {
983 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
984 silc_free(payload->ke_grp_list);
985 silc_free(payload->pkcs_alg_list);
987 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
991 if (!rp->enc_alg_len) {
992 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
993 silc_free(payload->ke_grp_list);
994 silc_free(payload->pkcs_alg_list);
996 return SILC_SKE_STATUS_BAD_PAYLOAD;
999 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1002 payload->enc_alg_len = rp->enc_alg_len;
1003 payload->enc_alg_list = strdup(rp->enc_alg_list);
1006 /* Get supported hash algorithms */
1007 cp = rp->hash_alg_list;
1008 if (cp && strchr(cp, ',')) {
1012 len = strcspn(cp, ",");
1013 item = silc_calloc(len + 1, sizeof(char));
1014 memcpy(item, cp, len);
1016 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1018 if (silc_hash_is_supported(item) == TRUE) {
1019 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1021 payload->hash_alg_len = len;
1022 payload->hash_alg_list = item;
1027 if (strlen(cp) == 0)
1036 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1037 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1038 silc_free(payload->ke_grp_list);
1039 silc_free(payload->pkcs_alg_list);
1040 silc_free(payload->enc_alg_list);
1042 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1046 if (!rp->hash_alg_len) {
1047 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1048 silc_free(payload->ke_grp_list);
1049 silc_free(payload->pkcs_alg_list);
1050 silc_free(payload->enc_alg_list);
1052 return SILC_SKE_STATUS_BAD_PAYLOAD;
1055 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1056 rp->hash_alg_list));
1058 payload->hash_alg_len = rp->hash_alg_len;
1059 payload->hash_alg_list = strdup(rp->hash_alg_list);
1063 /* Get supported compression algorithms */
1064 cp = rp->hash_alg_list;
1065 if (cp && strchr(cp, ',')) {
1069 len = strcspn(cp, ",");
1070 item = silc_calloc(len + 1, sizeof(char));
1071 memcpy(item, cp, len);
1073 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1075 if (silc_hash_is_supported(item) == TRUE) {
1076 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1078 payload->hash_alg_len = len;
1079 payload->hash_alg_list = item;
1084 if (strlen(cp) == 0)
1093 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1094 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1095 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1096 silc_free(payload->ke_grp_list);
1097 silc_free(payload->pkcs_alg_list);
1098 silc_free(payload->enc_alg_list);
1107 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1108 2 + payload->version_len +
1109 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1110 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1111 2 + payload->comp_alg_len;
1113 return SILC_SKE_STATUS_OK;
1116 /* Creates random number such that 1 < rnd < n and at most length
1117 of len bits. The rnd sent as argument must be initialized. */
1119 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1123 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1124 unsigned char *string;
1126 SILC_LOG_DEBUG(("Creating random number"));
1128 /* Get the random number as string */
1129 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1131 return SILC_SKE_STATUS_ERROR;
1133 /* Decode the string into a MP integer */
1134 silc_mp_bin2mp(string, (len / 8), rnd);
1135 silc_mp_mod_2exp(rnd, rnd, len);
1138 if (silc_mp_cmp_ui(rnd, 1) < 0)
1139 status = SILC_SKE_STATUS_ERROR;
1141 if (silc_mp_cmp(rnd, &n) >= 0)
1142 status = SILC_SKE_STATUS_ERROR;
1144 memset(string, 'F', (len / 8));
1150 /* Creates a hash value HASH as defined in the SKE protocol. */
1152 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1153 unsigned char *return_hash,
1154 unsigned int *return_hash_len)
1156 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1158 unsigned char *e, *f, *KEY;
1159 unsigned int e_len, f_len, KEY_len;
1162 SILC_LOG_DEBUG(("Start"));
1164 e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
1165 f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
1166 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1168 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1169 ske->pk_len + e_len + f_len + KEY_len);
1170 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1172 /* Format the buffer used to compute the hash value */
1173 ret = silc_buffer_format(buf,
1174 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1175 ske->start_payload_copy->len),
1176 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1177 SILC_STR_UI_XNSTRING(e, e_len),
1178 SILC_STR_UI_XNSTRING(f, f_len),
1179 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1182 silc_buffer_free(buf);
1183 memset(e, 0, e_len);
1184 memset(f, 0, f_len);
1185 memset(KEY, 0, KEY_len);
1189 return SILC_SKE_STATUS_ERROR;
1193 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1194 *return_hash_len = ske->prop->hash->hash->hash_len;
1196 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1198 silc_buffer_free(buf);
1199 memset(e, 0, e_len);
1200 memset(f, 0, f_len);
1201 memset(KEY, 0, KEY_len);
1209 /* Processes negotiated key material as protocol specifies. This returns
1210 the actual keys to be used in the SILC. */
1212 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1213 unsigned int req_iv_len,
1214 unsigned int req_enc_key_len,
1215 unsigned int req_hmac_key_len,
1216 SilcSKEKeyMaterial *key)
1220 unsigned char *tmpbuf;
1221 unsigned char hash[32];
1222 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1223 unsigned int enc_key_len = req_enc_key_len / 8;
1226 SILC_LOG_DEBUG(("Start"));
1228 /* Encode KEY to binary data */
1229 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1231 buf = silc_buffer_alloc(1 + klen + hash_len);
1232 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1233 ret = silc_buffer_format(buf,
1234 SILC_STR_UI_CHAR(0),
1235 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1236 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1239 memset(tmpbuf, 0, klen);
1241 silc_buffer_free(buf);
1242 return SILC_SKE_STATUS_ERROR;
1246 memset(hash, 0, sizeof(hash));
1248 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1250 memcpy(key->send_iv, hash, req_iv_len);
1251 memset(hash, 0, sizeof(hash));
1253 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1254 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1255 memcpy(key->receive_iv, hash, req_iv_len);
1256 key->iv_len = req_iv_len;
1258 /* Take the encryption keys. If requested key size is more than
1259 the size of hash length we will distribute more key material
1260 as protocol defines. */
1262 if (enc_key_len > hash_len) {
1264 unsigned char k1[32], k2[32], k3[32];
1265 unsigned char *dtmp;
1268 if (enc_key_len > (3 * hash_len))
1269 return SILC_SKE_STATUS_ERROR;
1271 memset(k1, 0, sizeof(k1));
1272 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1275 dist = silc_buffer_alloc(hash_len * 3);
1277 silc_buffer_pull_tail(dist, klen + hash_len);
1278 silc_buffer_format(dist,
1279 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1280 SILC_STR_UI_XNSTRING(k1, hash_len),
1283 memset(k2, 0, sizeof(k2));
1284 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1286 silc_buffer_pull(dist, klen + hash_len);
1287 silc_buffer_format(dist,
1288 SILC_STR_UI_XNSTRING(k2, hash_len),
1290 silc_buffer_push(dist, klen + hash_len);
1292 memset(k3, 0, sizeof(k3));
1293 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1295 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1296 memcpy(dtmp, k1, hash_len);
1297 memcpy(dtmp + hash_len, k2, hash_len);
1298 memcpy(dtmp + hash_len, k3, hash_len);
1300 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1301 memcpy(key->send_enc_key, dtmp, enc_key_len);
1302 key->enc_key_len = req_enc_key_len;
1304 memset(dtmp, 0, (3 * hash_len));
1305 memset(k1, 0, sizeof(k1));
1306 memset(k2, 0, sizeof(k2));
1307 memset(k3, 0, sizeof(k3));
1309 silc_buffer_free(dist);
1311 /* Take normal hash as key */
1312 memset(hash, 0, sizeof(hash));
1313 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1314 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1315 memcpy(key->send_enc_key, hash, enc_key_len);
1316 key->enc_key_len = req_enc_key_len;
1320 if (enc_key_len > hash_len) {
1322 unsigned char k1[32], k2[32], k3[32];
1323 unsigned char *dtmp;
1326 if (enc_key_len > (3 * hash_len))
1327 return SILC_SKE_STATUS_ERROR;
1329 memset(k1, 0, sizeof(k1));
1330 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1333 dist = silc_buffer_alloc(hash_len * 3);
1335 silc_buffer_pull_tail(dist, klen + hash_len);
1336 silc_buffer_format(dist,
1337 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1338 SILC_STR_UI_XNSTRING(k1, hash_len),
1341 memset(k2, 0, sizeof(k2));
1342 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1344 silc_buffer_pull(dist, klen + hash_len);
1345 silc_buffer_format(dist,
1346 SILC_STR_UI_XNSTRING(k2, hash_len),
1348 silc_buffer_push(dist, klen + hash_len);
1350 memset(k3, 0, sizeof(k3));
1351 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1353 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1354 memcpy(dtmp, k1, hash_len);
1355 memcpy(dtmp + hash_len, k2, hash_len);
1356 memcpy(dtmp + hash_len, k3, hash_len);
1358 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1359 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1360 key->enc_key_len = req_enc_key_len;
1362 memset(dtmp, 0, (3 * hash_len));
1363 memset(k1, 0, sizeof(k1));
1364 memset(k2, 0, sizeof(k2));
1365 memset(k3, 0, sizeof(k3));
1367 silc_buffer_free(dist);
1369 /* Take normal hash as key */
1370 memset(hash, 0, sizeof(hash));
1371 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1372 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1373 memcpy(key->receive_enc_key, hash, enc_key_len);
1374 key->enc_key_len = req_enc_key_len;
1378 memset(hash, 0, sizeof(hash));
1380 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1381 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1382 memcpy(key->hmac_key, hash, req_hmac_key_len);
1383 key->hmac_key_len = req_hmac_key_len;
1385 memset(tmpbuf, 0, klen);
1388 return SILC_SKE_STATUS_OK;