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 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
620 /* Compute the shared secret key */
621 KEY = silc_calloc(1, sizeof(*KEY));
623 silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
624 &ske->prop->group->group);
627 SILC_LOG_DEBUG(("Getting public key"));
629 /* Get the public key */
630 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
632 status = SILC_SKE_STATUS_ERROR;
635 ske->ke2_payload->pk_data = pk;
636 ske->ke2_payload->pk_len = pk_len;
637 ske->ke2_payload->pk_type = pk_type;
639 SILC_LOG_DEBUG(("Computing HASH value"));
641 /* Compute the hash value */
642 memset(hash, 0, sizeof(hash));
643 status = silc_ske_make_hash(ske, hash, &hash_len);
644 if (status != SILC_SKE_STATUS_OK)
647 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
648 memcpy(ske->hash, hash, hash_len);
649 ske->hash_len = hash_len;
651 SILC_LOG_DEBUG(("Signing HASH value"));
653 /* Sign the hash value */
654 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
655 private_key->prv_len);
656 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
659 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
660 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
661 memset(sign, 0, sizeof(sign));
662 ske->ke2_payload->sign_len = sign_len;
664 /* Encode the Key Exchange 2 Payload */
665 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
667 if (status != SILC_SKE_STATUS_OK)
670 /* Send the packet. */
672 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
674 silc_buffer_free(payload_buf);
679 silc_mp_clear(ske->KEY);
682 silc_ske_payload_two_free(ske->ke2_payload);
684 if (status == SILC_SKE_STATUS_OK)
685 return SILC_SKE_STATUS_ERROR;
687 ske->status = status;
691 /* The Key Exchange protocol is ended by calling this function. This
692 must not be called until the keys are processed like the protocol
693 defines. This function is for both initiator and responder. */
695 SilcSKEStatus silc_ske_end(SilcSKE ske,
696 SilcSKESendPacketCb send_packet,
701 SILC_LOG_DEBUG(("Start"));
703 packet = silc_buffer_alloc(4);
704 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
705 silc_buffer_format(packet,
706 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
710 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
712 silc_buffer_free(packet);
714 return SILC_SKE_STATUS_OK;
717 /* Aborts the Key Exchange protocol. This is called if error occurs
718 while performing the protocol. The status argument is the error
719 status and it is sent to the remote end. */
721 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
722 SilcSKESendPacketCb send_packet,
727 SILC_LOG_DEBUG(("Start"));
729 packet = silc_buffer_alloc(4);
730 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
731 silc_buffer_format(packet,
732 SILC_STR_UI_SHORT(status),
736 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
738 silc_buffer_free(packet);
740 return SILC_SKE_STATUS_OK;
743 /* Assembles security properties to Key Exchange Start Payload to be
744 sent to the remote end. This checks system wide (SILC system, that is)
745 settings and chooses from those. However, if other properties
746 should be used this function is easy to replace by another function,
747 as, this function is called by the caller of the protocol and not
748 by the protocol itself. */
751 silc_ske_assemble_security_properties(SilcSKE ske,
754 SilcSKEStartPayload **return_payload)
756 SilcSKEStartPayload *rp;
759 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
761 rp = silc_calloc(1, sizeof(*rp));
766 /* Set random cookie */
767 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
768 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
769 rp->cookie[i] = silc_rng_get_byte(ske->rng);
770 rp->cookie_len = SILC_SKE_COOKIE_LEN;
773 rp->version = strdup(version);
774 rp->version_len = strlen(version);
776 /* Get supported Key Exhange groups */
777 rp->ke_grp_list = silc_ske_get_supported_groups();
778 rp->ke_grp_len = strlen(rp->ke_grp_list);
780 /* Get supported PKCS algorithms */
781 rp->pkcs_alg_list = silc_pkcs_get_supported();
782 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
784 /* Get supported encryption algorithms */
785 rp->enc_alg_list = silc_cipher_get_supported();
786 rp->enc_alg_len = strlen(rp->enc_alg_list);
788 /* Get supported hash algorithms */
789 rp->hash_alg_list = silc_hash_get_supported();
790 rp->hash_alg_len = strlen(rp->hash_alg_list);
793 /* Get supported compression algorithms */
794 rp->comp_alg_list = "";
795 rp->comp_alg_len = 0;
797 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
798 2 + rp->version_len +
799 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
800 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
801 2 + rp->comp_alg_len;
803 *return_payload = rp;
805 return SILC_SKE_STATUS_OK;
808 /* Selects the supported security properties from the remote end's Key
809 Exchange Start Payload. */
812 silc_ske_select_security_properties(SilcSKE ske,
814 SilcSKEStartPayload *payload,
815 SilcSKEStartPayload *remote_payload)
817 SilcSKEStatus status;
818 SilcSKEStartPayload *rp;
822 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
826 /* Check version string */
827 status = silc_ske_check_version(ske, rp->version, rp->version_len);
828 if (status != SILC_SKE_STATUS_OK) {
829 ske->status = status;
833 /* Flags are returned unchanged. */
834 payload->flags = rp->flags;
837 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
838 payload->cookie_len = SILC_SKE_COOKIE_LEN;
839 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
841 /* Put our version to our reply */
842 payload->version = strdup(version);
843 payload->version_len = strlen(version);
845 /* Get supported Key Exchange groups */
846 cp = rp->ke_grp_list;
847 if (cp && strchr(cp, ',')) {
851 len = strcspn(cp, ",");
852 item = silc_calloc(len + 1, sizeof(char));
853 memcpy(item, cp, len);
855 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
857 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
858 SILC_LOG_DEBUG(("Found KE group `%s'", item));
860 payload->ke_grp_len = len;
861 payload->ke_grp_list = item;
875 if (!payload->ke_grp_len && !payload->ke_grp_list) {
876 SILC_LOG_DEBUG(("Could not find supported KE group"));
878 return SILC_SKE_STATUS_UNKNOWN_GROUP;
882 if (!rp->ke_grp_len) {
883 SILC_LOG_DEBUG(("KE group not defined in payload"));
885 return SILC_SKE_STATUS_BAD_PAYLOAD;
888 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
889 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
891 payload->ke_grp_len = rp->ke_grp_len;
892 payload->ke_grp_list = strdup(rp->ke_grp_list);
895 /* Get supported PKCS algorithms */
896 cp = rp->pkcs_alg_list;
897 if (cp && strchr(cp, ',')) {
901 len = strcspn(cp, ",");
902 item = silc_calloc(len + 1, sizeof(char));
903 memcpy(item, cp, len);
905 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
907 if (silc_pkcs_is_supported(item) == TRUE) {
908 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
910 payload->pkcs_alg_len = len;
911 payload->pkcs_alg_list = item;
925 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
926 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
927 silc_free(payload->ke_grp_list);
929 return SILC_SKE_STATUS_UNKNOWN_PKCS;
933 if (!rp->pkcs_alg_len) {
934 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
935 silc_free(payload->ke_grp_list);
937 return SILC_SKE_STATUS_BAD_PAYLOAD;
940 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
941 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
943 payload->pkcs_alg_len = rp->pkcs_alg_len;
944 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
947 /* Get supported encryption algorithms */
948 cp = rp->enc_alg_list;
949 if (cp && strchr(cp, ',')) {
953 len = strcspn(cp, ",");
954 item = silc_calloc(len + 1, sizeof(char));
955 memcpy(item, cp, len);
957 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
959 if (silc_cipher_is_supported(item) == TRUE) {
960 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
962 payload->enc_alg_len = len;
963 payload->enc_alg_list = item;
977 if (!payload->enc_alg_len && !payload->enc_alg_list) {
978 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
979 silc_free(payload->ke_grp_list);
980 silc_free(payload->pkcs_alg_list);
982 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
986 if (!rp->enc_alg_len) {
987 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
988 silc_free(payload->ke_grp_list);
989 silc_free(payload->pkcs_alg_list);
991 return SILC_SKE_STATUS_BAD_PAYLOAD;
994 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
997 payload->enc_alg_len = rp->enc_alg_len;
998 payload->enc_alg_list = strdup(rp->enc_alg_list);
1001 /* Get supported hash algorithms */
1002 cp = rp->hash_alg_list;
1003 if (cp && strchr(cp, ',')) {
1007 len = strcspn(cp, ",");
1008 item = silc_calloc(len + 1, sizeof(char));
1009 memcpy(item, cp, len);
1011 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1013 if (silc_hash_is_supported(item) == TRUE) {
1014 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1016 payload->hash_alg_len = len;
1017 payload->hash_alg_list = item;
1022 if (strlen(cp) == 0)
1031 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1032 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1033 silc_free(payload->ke_grp_list);
1034 silc_free(payload->pkcs_alg_list);
1035 silc_free(payload->enc_alg_list);
1037 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1041 if (!rp->hash_alg_len) {
1042 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1043 silc_free(payload->ke_grp_list);
1044 silc_free(payload->pkcs_alg_list);
1045 silc_free(payload->enc_alg_list);
1047 return SILC_SKE_STATUS_BAD_PAYLOAD;
1050 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1051 rp->hash_alg_list));
1053 payload->hash_alg_len = rp->hash_alg_len;
1054 payload->hash_alg_list = strdup(rp->hash_alg_list);
1058 /* Get supported compression algorithms */
1059 cp = rp->hash_alg_list;
1060 if (cp && strchr(cp, ',')) {
1064 len = strcspn(cp, ",");
1065 item = silc_calloc(len + 1, sizeof(char));
1066 memcpy(item, cp, len);
1068 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1070 if (silc_hash_is_supported(item) == TRUE) {
1071 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1073 payload->hash_alg_len = len;
1074 payload->hash_alg_list = item;
1079 if (strlen(cp) == 0)
1088 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1089 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1090 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1091 silc_free(payload->ke_grp_list);
1092 silc_free(payload->pkcs_alg_list);
1093 silc_free(payload->enc_alg_list);
1102 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1103 2 + payload->version_len +
1104 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1105 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1106 2 + payload->comp_alg_len;
1108 return SILC_SKE_STATUS_OK;
1111 /* Creates random number such that 1 < rnd < n and at most length
1112 of len bits. The rnd sent as argument must be initialized. */
1114 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1118 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1119 unsigned char *string;
1121 SILC_LOG_DEBUG(("Creating random number"));
1123 /* Get the random number as string */
1124 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1126 return SILC_SKE_STATUS_ERROR;
1128 /* Decode the string into a MP integer */
1129 silc_mp_bin2mp(string, (len / 8), rnd);
1130 silc_mp_mod_2exp(rnd, rnd, len);
1133 if (silc_mp_cmp_ui(rnd, 1) < 0)
1134 status = SILC_SKE_STATUS_ERROR;
1136 if (silc_mp_cmp(rnd, &n) >= 0)
1137 status = SILC_SKE_STATUS_ERROR;
1139 memset(string, 'F', (len / 8));
1145 /* Creates a hash value HASH as defined in the SKE protocol. */
1147 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1148 unsigned char *return_hash,
1149 unsigned int *return_hash_len)
1151 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1153 unsigned char *e, *f, *KEY;
1154 unsigned int e_len, f_len, KEY_len;
1157 SILC_LOG_DEBUG(("Start"));
1159 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1160 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1161 KEY = silc_mp_mp2bin(ske->KEY, &KEY_len);
1163 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1164 ske->pk_len + e_len + f_len + KEY_len);
1165 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1167 /* Format the buffer used to compute the hash value */
1168 ret = silc_buffer_format(buf,
1169 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1170 ske->start_payload_copy->len),
1171 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1172 SILC_STR_UI_XNSTRING(e, e_len),
1173 SILC_STR_UI_XNSTRING(f, f_len),
1174 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1177 silc_buffer_free(buf);
1178 memset(e, 0, e_len);
1179 memset(f, 0, f_len);
1180 memset(KEY, 0, KEY_len);
1184 return SILC_SKE_STATUS_ERROR;
1188 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1189 *return_hash_len = ske->prop->hash->hash->hash_len;
1191 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1193 silc_buffer_free(buf);
1194 memset(e, 0, e_len);
1195 memset(f, 0, f_len);
1196 memset(KEY, 0, KEY_len);
1204 /* Processes negotiated key material as protocol specifies. This returns
1205 the actual keys to be used in the SILC. */
1207 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1208 unsigned int req_iv_len,
1209 unsigned int req_enc_key_len,
1210 unsigned int req_hmac_key_len,
1211 SilcSKEKeyMaterial *key)
1215 unsigned char *tmpbuf;
1216 unsigned char hash[32];
1217 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1218 unsigned int enc_key_len = req_enc_key_len / 8;
1221 SILC_LOG_DEBUG(("Start"));
1223 /* Encode KEY to binary data */
1224 tmpbuf = silc_mp_mp2bin(ske->KEY, &klen);
1226 buf = silc_buffer_alloc(1 + klen + hash_len);
1227 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1228 ret = silc_buffer_format(buf,
1229 SILC_STR_UI_CHAR(0),
1230 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1231 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1234 memset(tmpbuf, 0, klen);
1236 silc_buffer_free(buf);
1237 return SILC_SKE_STATUS_ERROR;
1241 memset(hash, 0, sizeof(hash));
1243 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1244 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1245 memcpy(key->send_iv, hash, req_iv_len);
1246 memset(hash, 0, sizeof(hash));
1248 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1250 memcpy(key->receive_iv, hash, req_iv_len);
1251 key->iv_len = req_iv_len;
1253 /* Take the encryption keys. If requested key size is more than
1254 the size of hash length we will distribute more key material
1255 as protocol defines. */
1257 if (enc_key_len > hash_len) {
1259 unsigned char k1[32], k2[32], k3[32];
1260 unsigned char *dtmp;
1263 if (enc_key_len > (3 * hash_len))
1264 return SILC_SKE_STATUS_ERROR;
1266 memset(k1, 0, sizeof(k1));
1267 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1270 dist = silc_buffer_alloc(hash_len * 3);
1272 silc_buffer_pull_tail(dist, klen + hash_len);
1273 silc_buffer_format(dist,
1274 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1275 SILC_STR_UI_XNSTRING(k1, hash_len),
1278 memset(k2, 0, sizeof(k2));
1279 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1281 silc_buffer_pull(dist, klen + hash_len);
1282 silc_buffer_format(dist,
1283 SILC_STR_UI_XNSTRING(k2, hash_len),
1285 silc_buffer_push(dist, klen + hash_len);
1287 memset(k3, 0, sizeof(k3));
1288 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1290 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1291 memcpy(dtmp, k1, hash_len);
1292 memcpy(dtmp + hash_len, k2, hash_len);
1293 memcpy(dtmp + hash_len, k3, hash_len);
1295 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1296 memcpy(key->send_enc_key, dtmp, enc_key_len);
1297 key->enc_key_len = req_enc_key_len;
1299 memset(dtmp, 0, (3 * hash_len));
1300 memset(k1, 0, sizeof(k1));
1301 memset(k2, 0, sizeof(k2));
1302 memset(k3, 0, sizeof(k3));
1304 silc_buffer_free(dist);
1306 /* Take normal hash as key */
1307 memset(hash, 0, sizeof(hash));
1308 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1309 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1310 memcpy(key->send_enc_key, hash, enc_key_len);
1311 key->enc_key_len = req_enc_key_len;
1315 if (enc_key_len > hash_len) {
1317 unsigned char k1[32], k2[32], k3[32];
1318 unsigned char *dtmp;
1321 if (enc_key_len > (3 * hash_len))
1322 return SILC_SKE_STATUS_ERROR;
1324 memset(k1, 0, sizeof(k1));
1325 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1328 dist = silc_buffer_alloc(hash_len * 3);
1330 silc_buffer_pull_tail(dist, klen + hash_len);
1331 silc_buffer_format(dist,
1332 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1333 SILC_STR_UI_XNSTRING(k1, hash_len),
1336 memset(k2, 0, sizeof(k2));
1337 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1339 silc_buffer_pull(dist, klen + hash_len);
1340 silc_buffer_format(dist,
1341 SILC_STR_UI_XNSTRING(k2, hash_len),
1343 silc_buffer_push(dist, klen + hash_len);
1345 memset(k3, 0, sizeof(k3));
1346 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1348 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1349 memcpy(dtmp, k1, hash_len);
1350 memcpy(dtmp + hash_len, k2, hash_len);
1351 memcpy(dtmp + hash_len, k3, hash_len);
1353 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1354 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1355 key->enc_key_len = req_enc_key_len;
1357 memset(dtmp, 0, (3 * hash_len));
1358 memset(k1, 0, sizeof(k1));
1359 memset(k2, 0, sizeof(k2));
1360 memset(k3, 0, sizeof(k3));
1362 silc_buffer_free(dist);
1364 /* Take normal hash as key */
1365 memset(hash, 0, sizeof(hash));
1366 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1367 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1368 memcpy(key->receive_enc_key, hash, enc_key_len);
1369 key->enc_key_len = req_enc_key_len;
1373 memset(hash, 0, sizeof(hash));
1375 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1376 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1377 memcpy(key->hmac_key, hash, req_hmac_key_len);
1378 key->hmac_key_len = req_hmac_key_len;
1380 memset(tmpbuf, 0, klen);
1383 return SILC_SKE_STATUS_OK;