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.
23 * Revision 1.6 2000/07/19 07:04:37 priikone
24 * Added version detection support to SKE. Minor bugfixes.
26 * Revision 1.5 2000/07/10 05:34:22 priikone
27 * Added mp binary encoding as protocols defines.
29 * Revision 1.4 2000/07/07 06:46:43 priikone
30 * Removed ske_verify_public_key function as it is not needed
31 * anymore. Added support to the public key verification as callback
32 * function. Other minor changes and bug fixes.
34 * Revision 1.3 2000/07/06 07:12:39 priikone
35 * Support for SILC style public keys added.
37 * Revision 1.2 2000/07/05 06:05:15 priikone
38 * Global cosmetic change.
40 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
41 * Imported from internal CVS/Added Log headers.
46 #include "silcincludes.h"
47 #include "payload_internal.h"
48 #include "groups_internal.h"
50 /* Allocates new SKE object. */
52 SilcSKE silc_ske_alloc()
56 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
58 ske = silc_calloc(1, sizeof(*ske));
63 /* Free's SKE object. */
65 void silc_ske_free(SilcSKE ske)
67 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
70 /* Free start payload */
71 if (ske->start_payload)
72 silc_ske_payload_start_free(ske->start_payload);
74 /* Free KE1 payload */
76 silc_ske_payload_one_free(ske->ke1_payload);
78 /* Free KE2 payload */
80 silc_ske_payload_two_free(ske->ke2_payload);
85 silc_free(ske->prop->group);
87 silc_pkcs_free(ske->prop->pkcs);
88 if (ske->prop->cipher)
89 silc_cipher_free(ske->prop->cipher);
91 silc_hash_free(ske->prop->hash);
94 if (ske->start_payload_copy)
95 silc_buffer_free(ske->start_payload_copy);
99 silc_mp_clear(&ske->x);
100 silc_mp_clear(&ske->KEY);
103 silc_free(ske->hash);
108 /* Starts the SILC Key Exchange protocol for initiator. The connection
109 to the remote end must be established before calling this function
110 and the connecting socket must be sent as argument. This function
111 creates the Key Exchange Start Paload which includes all our
112 configured security properties. This payload is then sent to the
113 remote end for further processing. This payload must be sent as
114 argument to the function, however, it must not be encoded
115 already, it is done by this function.
117 The packet sending is done by calling a callback function. Caller
118 must provide a routine to send the packet. */
120 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
121 SilcSocketConnection sock,
122 SilcSKEStartPayload *start_payload,
123 SilcSKESendPacketCb send_packet,
126 SilcSKEStatus status = SILC_SKE_STATUS_OK;
127 SilcBuffer payload_buf;
129 SILC_LOG_DEBUG(("Start"));
134 /* Encode the payload */
135 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
136 if (status != SILC_SKE_STATUS_OK)
139 /* Take a copy of the payload buffer for future use. It is used to
140 compute the HASH value. */
141 ske->start_payload_copy = silc_buffer_copy(payload_buf);
143 /* Send the packet. */
145 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
147 silc_buffer_free(payload_buf);
152 /* Function called after ske_initiator_start fuction. This receives
153 the remote ends Key Exchange Start payload which includes the
154 security properties selected by the responder from our payload
155 sent in the silc_ske_initiator_start function. */
157 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
158 SilcBuffer start_payload,
162 SilcSKEStatus status = SILC_SKE_STATUS_OK;
163 SilcSKEStartPayload *payload;
164 SilcSKESecurityProperties prop;
165 SilcSKEDiffieHellmanGroup group;
167 SILC_LOG_DEBUG(("Start"));
169 /* Decode the payload */
170 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
171 if (status != SILC_SKE_STATUS_OK)
174 /* Take the selected security properties into use while doing
175 the key exchange. This is used only while doing the key
176 exchange. The same data is returned to upper levels by calling
177 the callback function. */
178 ske->prop = prop = silc_calloc(1, sizeof(*prop));
179 prop->flags = payload->flags;
180 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
181 if (status != SILC_SKE_STATUS_OK)
186 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
187 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
191 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
192 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
196 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
197 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
201 ske->start_payload = payload;
203 /* Return the received payload by calling the callback function. */
205 (*callback)(ske, context);
211 silc_ske_payload_start_free(payload);
216 silc_pkcs_free(prop->pkcs);
218 silc_cipher_free(prop->cipher);
220 silc_hash_free(prop->hash);
224 if (status == SILC_SKE_STATUS_OK)
225 return SILC_SKE_STATUS_ERROR;
230 /* This function creates random number x, such that 1 < x < q and
231 computes e = g ^ x mod p and sends the result to the remote end in
232 Key Exchange 1 Payload. */
234 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
235 SilcPublicKey public_key,
236 SilcSKESendPacketCb send_packet,
239 SilcSKEStatus status = SILC_SKE_STATUS_OK;
240 SilcBuffer payload_buf;
242 SilcSKEOnePayload *payload;
245 SILC_LOG_DEBUG(("Start"));
247 /* Create the random number x, 1 < x < q. */
250 silc_ske_create_rnd(ske, ske->prop->group->group_order,
251 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
253 if (status != SILC_SKE_STATUS_OK) {
258 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
260 /* Do the Diffie Hellman computation, e = g ^ x mod p */
262 silc_mp_powm(&e, &ske->prop->group->generator, &x,
263 &ske->prop->group->group);
265 /* Encode the result to Key Exchange 1 Payload. */
266 payload = silc_calloc(1, sizeof(*payload));
268 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
269 payload->pk_len = pk_len;
270 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
271 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
272 if (status != SILC_SKE_STATUS_OK) {
279 ske->ke1_payload = payload;
282 /* Send the packet. */
284 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
286 silc_buffer_free(payload_buf);
291 /* Receives Key Exchange 2 Payload from responder consisting responders
292 public key, f, and signature. This function verifies the public key,
293 computes the secret shared key and verifies the signature. */
295 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
296 SilcBuffer ke2_payload,
297 SilcSKEVerifyCb verify_key,
298 void *verify_context,
302 SilcSKEStatus status = SILC_SKE_STATUS_OK;
303 SilcSKETwoPayload *payload;
304 SilcPublicKey public_key = NULL;
306 unsigned char hash[32];
307 unsigned int hash_len;
309 SILC_LOG_DEBUG(("Start"));
311 /* Decode the payload */
312 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
313 if (status != SILC_SKE_STATUS_OK)
315 ske->ke2_payload = payload;
317 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
319 /* Compute the shared secret key */
321 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
324 SILC_LOG_DEBUG(("Verifying public key"));
326 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
328 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
333 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
334 payload->pk_type, verify_context);
335 if (status != SILC_SKE_STATUS_OK)
339 SILC_LOG_DEBUG(("Public key is authentic"));
341 /* Compute the hash value */
342 status = silc_ske_make_hash(ske, hash, &hash_len);
343 if (status != SILC_SKE_STATUS_OK)
346 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
347 memcpy(ske->hash, hash, hash_len);
348 ske->hash_len = hash_len;
350 SILC_LOG_DEBUG(("Verifying signature"));
352 /* Verify signature */
353 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
355 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
356 payload->sign_data, payload->sign_len,
357 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);
384 silc_pkcs_public_key_free(public_key);
387 memset(ske->hash, 'F', hash_len);
388 silc_free(ske->hash);
392 if (status == SILC_SKE_STATUS_OK)
393 return SILC_SKE_STATUS_ERROR;
398 /* Starts Key Exchange protocol for responder. Responder receives
399 Key Exchange Start Payload from initiator consisting of all the
400 security properties the initiator supports. This function decodes
401 the payload and parses the payload further and selects the right
402 security properties. */
404 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
405 SilcSocketConnection sock,
407 SilcBuffer start_payload,
411 SilcSKEStatus status = SILC_SKE_STATUS_OK;
412 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
414 SILC_LOG_DEBUG(("Start"));
419 /* Decode the payload */
420 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
421 if (status != SILC_SKE_STATUS_OK)
424 /* Take a copy of the payload buffer for future use. It is used to
425 compute the HASH value. */
426 ske->start_payload_copy = silc_buffer_copy(start_payload);
428 /* Parse and select the security properties from the payload */
429 payload = silc_calloc(1, sizeof(*payload));
430 status = silc_ske_select_security_properties(ske, version,
431 payload, remote_payload);
432 if (status != SILC_SKE_STATUS_OK)
435 ske->start_payload = payload;
437 /* Call the callback function. */
439 (*callback)(ske, context);
445 silc_ske_payload_start_free(remote_payload);
449 if (status == SILC_SKE_STATUS_OK)
450 return SILC_SKE_STATUS_ERROR;
455 /* The selected security properties from the initiator payload is now
456 encoded into Key Exchange Start Payload and sent to the initiator. */
458 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
459 SilcSKEStartPayload *start_payload,
460 SilcSKESendPacketCb send_packet,
463 SilcSKEStatus status = SILC_SKE_STATUS_OK;
464 SilcBuffer payload_buf;
465 SilcSKESecurityProperties prop;
466 SilcSKEDiffieHellmanGroup group;
468 SILC_LOG_DEBUG(("Start"));
470 /* Allocate security properties from the payload. These are allocated
471 only for this negotiation and will be free'd after KE is over. */
472 ske->prop = prop = silc_calloc(1, sizeof(*prop));
473 prop->flags = start_payload->flags;
474 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
475 if (status != SILC_SKE_STATUS_OK)
480 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
481 &prop->pkcs) == FALSE) {
482 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
486 if (silc_cipher_alloc(start_payload->enc_alg_list,
487 &prop->cipher) == FALSE) {
488 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
492 if (silc_hash_alloc(start_payload->hash_alg_list,
493 &prop->hash) == FALSE) {
494 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
498 /* Encode the payload */
499 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
500 if (status != SILC_SKE_STATUS_OK)
503 /* Send the packet. */
505 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
507 silc_buffer_free(payload_buf);
515 silc_pkcs_free(prop->pkcs);
517 silc_cipher_free(prop->cipher);
519 silc_hash_free(prop->hash);
523 if (status == SILC_SKE_STATUS_OK)
524 return SILC_SKE_STATUS_ERROR;
529 /* This function receives the Key Exchange 1 Payload from the initiator.
530 After processing the payload this then selects random number x,
531 such that 1 < x < q and computes f = g ^ x mod p. This then puts
532 the result f to a Key Exchange 2 Payload which is later processed
533 in ske_responder_finish function. The callback function should
534 not touch the payload (it should merely call the ske_responder_finish
537 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
538 SilcBuffer ke1_payload,
542 SilcSKEStatus status = SILC_SKE_STATUS_OK;
543 SilcSKEOnePayload *one_payload;
544 SilcSKETwoPayload *two_payload;
547 SILC_LOG_DEBUG(("Start"));
549 /* Decode Key Exchange 1 Payload */
550 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
551 if (status != SILC_SKE_STATUS_OK)
554 /* Create the random number x, 1 < x < q. */
557 silc_ske_create_rnd(ske, ske->prop->group->group_order,
558 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
560 if (status != SILC_SKE_STATUS_OK) {
565 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
567 /* Do the Diffie Hellman computation, f = g ^ x mod p */
569 silc_mp_powm(&f, &ske->prop->group->generator, &x,
570 &ske->prop->group->group);
572 /* Save the results for later processing */
573 two_payload = silc_calloc(1, sizeof(*two_payload));
576 ske->ke1_payload = one_payload;
577 ske->ke2_payload = two_payload;
579 /* Call the callback. */
581 (*callback)(ske, context);
586 /* This function computes the secret shared key KEY = e ^ x mod p, and,
587 a hash value to be signed and sent to the other end. This then
588 encodes Key Exchange 2 Payload and sends it to the other end. */
590 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
591 SilcPublicKey public_key,
592 SilcPrivateKey private_key,
593 SilcSKEPKType pk_type,
594 SilcSKESendPacketCb send_packet,
597 SilcSKEStatus status = SILC_SKE_STATUS_OK;
598 SilcBuffer payload_buf;
600 unsigned char hash[32], sign[256], *pk;
601 unsigned int hash_len, sign_len, pk_len;
603 SILC_LOG_DEBUG(("Start"));
605 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
607 /* Compute the shared secret key */
609 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
610 &ske->prop->group->group);
613 SILC_LOG_DEBUG(("Getting public key"));
615 /* Get the public key */
616 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
617 ske->ke2_payload->pk_data = pk;
618 ske->ke2_payload->pk_len = pk_len;
619 ske->ke2_payload->pk_type = pk_type;
621 SILC_LOG_DEBUG(("Computing HASH value"));
623 /* Compute the hash value */
624 memset(hash, 0, sizeof(hash));
625 status = silc_ske_make_hash(ske, hash, &hash_len);
626 if (status != SILC_SKE_STATUS_OK)
629 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
630 memcpy(ske->hash, hash, hash_len);
631 ske->hash_len = hash_len;
633 SILC_LOG_DEBUG(("Signing HASH value"));
635 /* Sign the hash value */
636 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
637 private_key->prv_len);
638 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
641 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
642 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
643 memset(sign, 0, sizeof(sign));
644 ske->ke2_payload->sign_len = sign_len;
646 /* Encode the Key Exchange 2 Payload */
647 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
649 if (status != SILC_SKE_STATUS_OK)
652 /* Send the packet. */
654 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
656 silc_buffer_free(payload_buf);
661 silc_mp_clear(&ske->KEY);
662 silc_ske_payload_two_free(ske->ke2_payload);
664 if (status == SILC_SKE_STATUS_OK)
665 return SILC_SKE_STATUS_ERROR;
670 /* The Key Exchange protocol is ended by calling this function. This
671 must not be called until the keys are processed like the protocol
672 defines. This function is for both initiator and responder. */
674 SilcSKEStatus silc_ske_end(SilcSKE ske,
675 SilcSKESendPacketCb send_packet,
678 SilcSKEStatus status = SILC_SKE_STATUS_OK;
681 SILC_LOG_DEBUG(("Start"));
683 packet = silc_buffer_alloc(1);
687 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
692 /* Aborts the Key Exchange protocol. This is called if error occurs
693 while performing the protocol. The status argument is the error
694 status and it is sent to the remote end. */
696 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
697 SilcSKESendPacketCb send_packet,
702 SILC_LOG_DEBUG(("Start"));
704 packet = silc_buffer_alloc(4);
705 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
706 silc_buffer_format(packet,
707 SILC_STR_UI_SHORT(status),
711 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
713 silc_buffer_free(packet);
715 return SILC_SKE_STATUS_OK;
718 /* Assembles security properties to Key Exchange Start Payload to be
719 sent to the remote end. This checks system wide (SILC system, that is)
720 settings and chooses from those. However, if other properties
721 should be used this function is easy to replace by another function,
722 as, this function is called by the caller of the protocol and not
723 by the protocol itself. */
726 silc_ske_assemble_security_properties(SilcSKE ske,
728 SilcSKEStartPayload **return_payload)
730 SilcSKEStartPayload *rp;
732 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
734 rp = silc_calloc(1, sizeof(*rp));
742 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
743 rp->cookie_len = SILC_SKE_COOKIE_LEN;
744 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
747 rp->version = strdup(version);
748 rp->version_len = strlen(version);
750 /* Get supported Key Exhange groups */
751 rp->ke_grp_list = silc_ske_get_supported_groups();
752 rp->ke_grp_len = strlen(rp->ke_grp_list);
754 /* Get supported PKCS algorithms */
755 rp->pkcs_alg_list = silc_pkcs_get_supported();
756 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
758 /* Get supported encryption algorithms */
759 rp->enc_alg_list = silc_cipher_get_supported();
760 rp->enc_alg_len = strlen(rp->enc_alg_list);
762 /* Get supported hash algorithms */
763 rp->hash_alg_list = silc_hash_get_supported();
764 rp->hash_alg_len = strlen(rp->hash_alg_list);
767 /* Get supported compression algorithms */
768 rp->comp_alg_list = "";
769 rp->comp_alg_len = 0;
771 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
772 2 + rp->version_len +
773 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
774 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
775 2 + rp->comp_alg_len;
777 *return_payload = rp;
779 return SILC_SKE_STATUS_OK;
782 /* Selects the supported security properties from the remote end's Key
783 Exchange Start Payload. */
786 silc_ske_select_security_properties(SilcSKE ske,
788 SilcSKEStartPayload *payload,
789 SilcSKEStartPayload *remote_payload)
791 SilcSKEStartPayload *rp;
795 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
799 /* Flags are returned unchanged. */
800 payload->flags = rp->flags;
803 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
804 payload->cookie_len = SILC_SKE_COOKIE_LEN;
805 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
807 /* XXX Do version check */
809 /* Put our version to our reply */
810 payload->version = strdup(version);
811 payload->version_len = strlen(version);
813 /* Get supported Key Exchange groups */
814 cp = rp->ke_grp_list;
815 if (cp && strchr(cp, ',')) {
819 len = strcspn(cp, ",");
820 item = silc_calloc(len + 1, sizeof(char));
821 memcpy(item, cp, len);
823 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
825 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
826 SILC_LOG_DEBUG(("Found KE group `%s'", item));
828 payload->ke_grp_len = len;
829 payload->ke_grp_list = item;
843 if (!payload->ke_grp_len && !payload->ke_grp_list) {
844 SILC_LOG_DEBUG(("Could not find supported KE group"));
846 return SILC_SKE_STATUS_UNKNOWN_GROUP;
850 if (!rp->ke_grp_len) {
851 SILC_LOG_DEBUG(("KE group not defined in payload"));
853 return SILC_SKE_STATUS_BAD_PAYLOAD;
856 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
857 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
859 payload->ke_grp_len = rp->ke_grp_len;
860 payload->ke_grp_list = strdup(rp->ke_grp_list);
863 /* Get supported PKCS algorithms */
864 cp = rp->pkcs_alg_list;
865 if (cp && strchr(cp, ',')) {
869 len = strcspn(cp, ",");
870 item = silc_calloc(len + 1, sizeof(char));
871 memcpy(item, cp, len);
873 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
875 if (silc_pkcs_is_supported(item) == TRUE) {
876 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
878 payload->pkcs_alg_len = len;
879 payload->pkcs_alg_list = item;
893 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
894 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
895 silc_free(payload->ke_grp_list);
897 return SILC_SKE_STATUS_UNKNOWN_PKCS;
901 if (!rp->pkcs_alg_len) {
902 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
903 silc_free(payload->ke_grp_list);
905 return SILC_SKE_STATUS_BAD_PAYLOAD;
908 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
909 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
911 payload->pkcs_alg_len = rp->pkcs_alg_len;
912 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
915 /* Get supported encryption algorithms */
916 cp = rp->enc_alg_list;
917 if (cp && strchr(cp, ',')) {
921 len = strcspn(cp, ",");
922 item = silc_calloc(len + 1, sizeof(char));
923 memcpy(item, cp, len);
925 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
927 if (silc_cipher_is_supported(item) == TRUE) {
928 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
930 payload->enc_alg_len = len;
931 payload->enc_alg_list = item;
945 if (!payload->enc_alg_len && !payload->enc_alg_list) {
946 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
947 silc_free(payload->ke_grp_list);
948 silc_free(payload->pkcs_alg_list);
950 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
954 if (!rp->enc_alg_len) {
955 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
956 silc_free(payload->ke_grp_list);
957 silc_free(payload->pkcs_alg_list);
959 return SILC_SKE_STATUS_BAD_PAYLOAD;
962 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
965 payload->enc_alg_len = rp->enc_alg_len;
966 payload->enc_alg_list = strdup(rp->enc_alg_list);
969 /* Get supported hash algorithms */
970 cp = rp->hash_alg_list;
971 if (cp && strchr(cp, ',')) {
975 len = strcspn(cp, ",");
976 item = silc_calloc(len + 1, sizeof(char));
977 memcpy(item, cp, len);
979 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
981 if (silc_hash_is_supported(item) == TRUE) {
982 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
984 payload->hash_alg_len = len;
985 payload->hash_alg_list = item;
999 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1000 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1001 silc_free(payload->ke_grp_list);
1002 silc_free(payload->pkcs_alg_list);
1003 silc_free(payload->enc_alg_list);
1005 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1009 if (!rp->hash_alg_len) {
1010 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1011 silc_free(payload->ke_grp_list);
1012 silc_free(payload->pkcs_alg_list);
1013 silc_free(payload->enc_alg_list);
1015 return SILC_SKE_STATUS_BAD_PAYLOAD;
1018 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1019 rp->hash_alg_list));
1021 payload->hash_alg_len = rp->hash_alg_len;
1022 payload->hash_alg_list = strdup(rp->hash_alg_list);
1026 /* Get supported compression algorithms */
1027 cp = rp->hash_alg_list;
1028 if (cp && strchr(cp, ',')) {
1032 len = strcspn(cp, ",");
1033 item = silc_calloc(len + 1, sizeof(char));
1034 memcpy(item, cp, len);
1036 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1038 if (silc_hash_is_supported(item) == TRUE) {
1039 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1041 payload->hash_alg_len = len;
1042 payload->hash_alg_list = item;
1047 if (strlen(cp) == 0)
1056 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1057 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1058 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1059 silc_free(payload->ke_grp_list);
1060 silc_free(payload->pkcs_alg_list);
1061 silc_free(payload->enc_alg_list);
1070 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1071 2 + payload->version_len +
1072 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1073 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1074 2 + payload->comp_alg_len;
1076 return SILC_SKE_STATUS_OK;
1079 /* Creates random number such that 1 < rnd < n and at most length
1080 of len bits. The rnd sent as argument must be initialized. */
1082 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1086 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1087 unsigned char *string;
1089 SILC_LOG_DEBUG(("Creating random number"));
1091 /* Get the random number as string */
1092 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1094 /* Decode the string into a MP integer */
1095 silc_mp_bin2mp(string, (len / 8), rnd);
1096 silc_mp_mod_2exp(rnd, rnd, len);
1099 if (silc_mp_cmp_ui(rnd, 1) < 0)
1100 status = SILC_SKE_STATUS_ERROR;
1102 if (silc_mp_cmp(rnd, &n) >= 0)
1103 status = SILC_SKE_STATUS_ERROR;
1105 memset(string, 'F', (len / 8));
1111 /* Creates a hash value HASH as defined in the SKE protocol. */
1113 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1114 unsigned char *return_hash,
1115 unsigned int *return_hash_len)
1117 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1119 unsigned char *e, *f, *KEY;
1120 unsigned int e_len, f_len, KEY_len;
1122 SILC_LOG_DEBUG(("Start"));
1124 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1125 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1126 KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1128 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1129 ske->pk_len + e_len + f_len + KEY_len);
1130 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1132 /* Format the buffer used to compute the hash value */
1133 silc_buffer_format(buf,
1134 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1135 ske->start_payload_copy->len),
1136 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1137 SILC_STR_UI_XNSTRING(e, e_len),
1138 SILC_STR_UI_XNSTRING(f, f_len),
1139 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1143 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1147 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1148 *return_hash_len = ske->prop->hash->hash->hash_len;
1150 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1152 silc_buffer_free(buf);
1153 memset(e, 0, e_len);
1154 memset(f, 0, f_len);
1155 memset(KEY, 0, KEY_len);
1163 /* Processes negotiated key material as protocol specifies. This returns
1164 the actual keys to be used in the SILC. */
1166 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1167 unsigned int req_iv_len,
1168 unsigned int req_enc_key_len,
1169 unsigned int req_hmac_key_len,
1170 SilcSKEKeyMaterial *key)
1174 unsigned char *tmpbuf;
1175 unsigned char hash[32];
1176 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1177 unsigned int enc_key_len = req_enc_key_len / 8;
1179 SILC_LOG_DEBUG(("Start"));
1181 /* Encode KEY to binary data */
1182 tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1184 buf = silc_buffer_alloc(1 + klen + hash_len);
1185 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1186 silc_buffer_format(buf,
1187 SILC_STR_UI_CHAR(0),
1188 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1189 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1193 memset(hash, 0, sizeof(hash));
1195 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1196 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1197 memcpy(key->send_iv, hash, req_iv_len);
1198 memset(hash, 0, sizeof(hash));
1200 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1201 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1202 memcpy(key->receive_iv, hash, req_iv_len);
1203 key->iv_len = req_iv_len;
1205 /* Take the encryption keys. If requested key size is more than
1206 the size of hash length we will distribute more key material
1207 as protocol defines. */
1209 if (enc_key_len > hash_len) {
1211 unsigned char k1[32], k2[32], k3[32];
1212 unsigned char *dtmp;
1215 if (enc_key_len > (3 * hash_len))
1216 return SILC_SKE_STATUS_ERROR;
1218 memset(k1, 0, sizeof(k1));
1219 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1222 dist = silc_buffer_alloc(hash_len * 3);
1224 silc_buffer_pull_tail(dist, klen + hash_len);
1225 silc_buffer_format(dist,
1226 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1227 SILC_STR_UI_XNSTRING(k1, hash_len),
1230 memset(k2, 0, sizeof(k2));
1231 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1233 silc_buffer_pull(dist, klen + hash_len);
1234 silc_buffer_format(dist,
1235 SILC_STR_UI_XNSTRING(k2, hash_len),
1237 silc_buffer_push(dist, klen + hash_len);
1239 memset(k3, 0, sizeof(k3));
1240 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1242 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1243 memcpy(dtmp, k1, hash_len);
1244 memcpy(dtmp + hash_len, k2, hash_len);
1245 memcpy(dtmp + hash_len, k3, hash_len);
1247 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1248 memcpy(key->send_enc_key, dtmp, enc_key_len);
1249 key->enc_key_len = req_enc_key_len;
1251 memset(dtmp, 0, (3 * hash_len));
1252 memset(k1, 0, sizeof(k1));
1253 memset(k2, 0, sizeof(k2));
1254 memset(k3, 0, sizeof(k3));
1256 silc_buffer_free(dist);
1258 /* Take normal hash as key */
1259 memset(hash, 0, sizeof(hash));
1260 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1261 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1262 memcpy(key->send_enc_key, hash, enc_key_len);
1263 key->enc_key_len = req_enc_key_len;
1267 if (enc_key_len > hash_len) {
1269 unsigned char k1[32], k2[32], k3[32];
1270 unsigned char *dtmp;
1273 if (enc_key_len > (3 * hash_len))
1274 return SILC_SKE_STATUS_ERROR;
1276 memset(k1, 0, sizeof(k1));
1277 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1280 dist = silc_buffer_alloc(hash_len * 3);
1282 silc_buffer_pull_tail(dist, klen + hash_len);
1283 silc_buffer_format(dist,
1284 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1285 SILC_STR_UI_XNSTRING(k1, hash_len),
1288 memset(k2, 0, sizeof(k2));
1289 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1291 silc_buffer_pull(dist, klen + hash_len);
1292 silc_buffer_format(dist,
1293 SILC_STR_UI_XNSTRING(k2, hash_len),
1295 silc_buffer_push(dist, klen + hash_len);
1297 memset(k3, 0, sizeof(k3));
1298 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1300 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1301 memcpy(dtmp, k1, hash_len);
1302 memcpy(dtmp + hash_len, k2, hash_len);
1303 memcpy(dtmp + hash_len, k3, hash_len);
1305 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1306 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1307 key->enc_key_len = req_enc_key_len;
1309 memset(dtmp, 0, (3 * hash_len));
1310 memset(k1, 0, sizeof(k1));
1311 memset(k2, 0, sizeof(k2));
1312 memset(k3, 0, sizeof(k3));
1314 silc_buffer_free(dist);
1316 /* Take normal hash as key */
1317 memset(hash, 0, sizeof(hash));
1318 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1319 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1320 memcpy(key->receive_enc_key, hash, enc_key_len);
1321 key->enc_key_len = req_enc_key_len;
1325 memset(hash, 0, sizeof(hash));
1327 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1328 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1329 memcpy(key->hmac_key, hash, req_hmac_key_len);
1330 key->hmac_key_len = req_hmac_key_len;
1332 memset(tmpbuf, 0, klen);
1335 return SILC_SKE_STATUS_OK;