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));
39 /* Free's SKE object. */
41 void silc_ske_free(SilcSKE ske)
43 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
46 /* Free start payload */
47 if (ske->start_payload)
48 silc_ske_payload_start_free(ske->start_payload);
50 /* Free KE1 payload */
52 silc_ske_payload_one_free(ske->ke1_payload);
54 /* Free KE2 payload */
56 silc_ske_payload_two_free(ske->ke2_payload);
61 silc_free(ske->prop->group);
63 silc_pkcs_free(ske->prop->pkcs);
64 if (ske->prop->cipher)
65 silc_cipher_free(ske->prop->cipher);
67 silc_hash_free(ske->prop->hash);
70 if (ske->start_payload_copy)
71 silc_buffer_free(ske->start_payload_copy);
75 silc_mp_clear(&ske->x);
76 silc_mp_clear(&ske->KEY);
84 /* Starts the SILC Key Exchange protocol for initiator. The connection
85 to the remote end must be established before calling this function
86 and the connecting socket must be sent as argument. This function
87 creates the Key Exchange Start Paload which includes all our
88 configured security properties. This payload is then sent to the
89 remote end for further processing. This payload must be sent as
90 argument to the function, however, it must not be encoded
91 already, it is done by this function.
93 The packet sending is done by calling a callback function. Caller
94 must provide a routine to send the packet. */
96 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
97 SilcSocketConnection sock,
98 SilcSKEStartPayload *start_payload,
99 SilcSKESendPacketCb send_packet,
102 SilcSKEStatus status = SILC_SKE_STATUS_OK;
103 SilcBuffer payload_buf;
105 SILC_LOG_DEBUG(("Start"));
110 /* Encode the payload */
111 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
112 if (status != SILC_SKE_STATUS_OK)
115 /* Take a copy of the payload buffer for future use. It is used to
116 compute the HASH value. */
117 ske->start_payload_copy = silc_buffer_copy(payload_buf);
119 /* Send the packet. */
121 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
123 silc_buffer_free(payload_buf);
128 /* Function called after ske_initiator_start fuction. This receives
129 the remote ends Key Exchange Start payload which includes the
130 security properties selected by the responder from our payload
131 sent in the silc_ske_initiator_start function. */
133 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
134 SilcBuffer start_payload,
138 SilcSKEStatus status = SILC_SKE_STATUS_OK;
139 SilcSKEStartPayload *payload;
140 SilcSKESecurityProperties prop;
141 SilcSKEDiffieHellmanGroup group;
143 SILC_LOG_DEBUG(("Start"));
145 /* Decode the payload */
146 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
147 if (status != SILC_SKE_STATUS_OK)
150 /* Take the selected security properties into use while doing
151 the key exchange. This is used only while doing the key
152 exchange. The same data is returned to upper levels by calling
153 the callback function. */
154 ske->prop = prop = silc_calloc(1, sizeof(*prop));
155 prop->flags = payload->flags;
156 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
157 if (status != SILC_SKE_STATUS_OK)
162 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
163 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
167 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
168 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
172 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
173 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
177 ske->start_payload = payload;
179 /* Return the received payload by calling the callback function. */
181 (*callback)(ske, context);
187 silc_ske_payload_start_free(payload);
192 silc_pkcs_free(prop->pkcs);
194 silc_cipher_free(prop->cipher);
196 silc_hash_free(prop->hash);
200 if (status == SILC_SKE_STATUS_OK)
201 return SILC_SKE_STATUS_ERROR;
206 /* This function creates random number x, such that 1 < x < q and
207 computes e = g ^ x mod p and sends the result to the remote end in
208 Key Exchange 1 Payload. */
210 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
211 SilcPublicKey public_key,
212 SilcSKESendPacketCb send_packet,
215 SilcSKEStatus status = SILC_SKE_STATUS_OK;
216 SilcBuffer payload_buf;
218 SilcSKEOnePayload *payload;
221 SILC_LOG_DEBUG(("Start"));
223 /* Create the random number x, 1 < x < q. */
226 silc_ske_create_rnd(ske, ske->prop->group->group_order,
227 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
229 if (status != SILC_SKE_STATUS_OK) {
234 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
236 /* Do the Diffie Hellman computation, e = g ^ x mod p */
238 silc_mp_powm(&e, &ske->prop->group->generator, &x,
239 &ske->prop->group->group);
241 /* Encode the result to Key Exchange 1 Payload. */
242 payload = silc_calloc(1, sizeof(*payload));
244 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
245 payload->pk_len = pk_len;
246 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
247 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
248 if (status != SILC_SKE_STATUS_OK) {
255 ske->ke1_payload = payload;
258 /* Send the packet. */
260 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
262 silc_buffer_free(payload_buf);
267 /* Receives Key Exchange 2 Payload from responder consisting responders
268 public key, f, and signature. This function verifies the public key,
269 computes the secret shared key and verifies the signature. */
271 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
272 SilcBuffer ke2_payload,
273 SilcSKEVerifyCb verify_key,
274 void *verify_context,
278 SilcSKEStatus status = SILC_SKE_STATUS_OK;
279 SilcSKETwoPayload *payload;
280 SilcPublicKey public_key = NULL;
282 unsigned char hash[32];
283 unsigned int hash_len;
285 SILC_LOG_DEBUG(("Start"));
287 /* Decode the payload */
288 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
289 if (status != SILC_SKE_STATUS_OK)
291 ske->ke2_payload = payload;
293 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
295 /* Compute the shared secret key */
297 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
300 SILC_LOG_DEBUG(("Verifying public key"));
302 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
304 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
309 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
310 payload->pk_type, verify_context);
311 if (status != SILC_SKE_STATUS_OK)
315 SILC_LOG_DEBUG(("Public key is authentic"));
317 /* Compute the hash value */
318 status = silc_ske_make_hash(ske, hash, &hash_len);
319 if (status != SILC_SKE_STATUS_OK)
322 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
323 memcpy(ske->hash, hash, hash_len);
324 ske->hash_len = hash_len;
326 SILC_LOG_DEBUG(("Verifying signature"));
328 /* Verify signature */
329 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
331 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
332 payload->sign_data, payload->sign_len,
333 hash, hash_len) == FALSE) {
335 SILC_LOG_DEBUG(("Signature don't match"));
337 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
341 SILC_LOG_DEBUG(("Signature is Ok"));
343 silc_pkcs_public_key_free(public_key);
344 memset(hash, 'F', hash_len);
346 /* Call the callback. */
348 (*callback)(ske, context);
353 memset(hash, 'F', sizeof(hash));
354 silc_ske_payload_two_free(payload);
355 ske->ke2_payload = NULL;
357 silc_mp_clear(&ske->KEY);
360 silc_pkcs_public_key_free(public_key);
363 memset(ske->hash, 'F', hash_len);
364 silc_free(ske->hash);
368 if (status == SILC_SKE_STATUS_OK)
369 return SILC_SKE_STATUS_ERROR;
374 /* Starts Key Exchange protocol for responder. Responder receives
375 Key Exchange Start Payload from initiator consisting of all the
376 security properties the initiator supports. This function decodes
377 the payload and parses the payload further and selects the right
378 security properties. */
380 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
381 SilcSocketConnection sock,
383 SilcBuffer start_payload,
387 SilcSKEStatus status = SILC_SKE_STATUS_OK;
388 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
390 SILC_LOG_DEBUG(("Start"));
395 /* Decode the payload */
396 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
397 if (status != SILC_SKE_STATUS_OK)
400 /* Take a copy of the payload buffer for future use. It is used to
401 compute the HASH value. */
402 ske->start_payload_copy = silc_buffer_copy(start_payload);
404 /* Parse and select the security properties from the payload */
405 payload = silc_calloc(1, sizeof(*payload));
406 status = silc_ske_select_security_properties(ske, version,
407 payload, remote_payload);
408 if (status != SILC_SKE_STATUS_OK)
411 ske->start_payload = payload;
413 /* Call the callback function. */
415 (*callback)(ske, context);
421 silc_ske_payload_start_free(remote_payload);
425 if (status == SILC_SKE_STATUS_OK)
426 return SILC_SKE_STATUS_ERROR;
431 /* The selected security properties from the initiator payload is now
432 encoded into Key Exchange Start Payload and sent to the initiator. */
434 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
435 SilcSKEStartPayload *start_payload,
436 SilcSKESendPacketCb send_packet,
439 SilcSKEStatus status = SILC_SKE_STATUS_OK;
440 SilcBuffer payload_buf;
441 SilcSKESecurityProperties prop;
442 SilcSKEDiffieHellmanGroup group;
444 SILC_LOG_DEBUG(("Start"));
446 /* Allocate security properties from the payload. These are allocated
447 only for this negotiation and will be free'd after KE is over. */
448 ske->prop = prop = silc_calloc(1, sizeof(*prop));
449 prop->flags = start_payload->flags;
450 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
451 if (status != SILC_SKE_STATUS_OK)
456 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
457 &prop->pkcs) == FALSE) {
458 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
462 if (silc_cipher_alloc(start_payload->enc_alg_list,
463 &prop->cipher) == FALSE) {
464 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
468 if (silc_hash_alloc(start_payload->hash_alg_list,
469 &prop->hash) == FALSE) {
470 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
474 /* Encode the payload */
475 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
476 if (status != SILC_SKE_STATUS_OK)
479 /* Send the packet. */
481 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
483 silc_buffer_free(payload_buf);
491 silc_pkcs_free(prop->pkcs);
493 silc_cipher_free(prop->cipher);
495 silc_hash_free(prop->hash);
499 if (status == SILC_SKE_STATUS_OK)
500 return SILC_SKE_STATUS_ERROR;
505 /* This function receives the Key Exchange 1 Payload from the initiator.
506 After processing the payload this then selects random number x,
507 such that 1 < x < q and computes f = g ^ x mod p. This then puts
508 the result f to a Key Exchange 2 Payload which is later processed
509 in ske_responder_finish function. The callback function should
510 not touch the payload (it should merely call the ske_responder_finish
513 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
514 SilcBuffer ke1_payload,
518 SilcSKEStatus status = SILC_SKE_STATUS_OK;
519 SilcSKEOnePayload *one_payload;
520 SilcSKETwoPayload *two_payload;
523 SILC_LOG_DEBUG(("Start"));
525 /* Decode Key Exchange 1 Payload */
526 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
527 if (status != SILC_SKE_STATUS_OK)
530 /* Create the random number x, 1 < x < q. */
533 silc_ske_create_rnd(ske, ske->prop->group->group_order,
534 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
536 if (status != SILC_SKE_STATUS_OK) {
541 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
543 /* Do the Diffie Hellman computation, f = g ^ x mod p */
545 silc_mp_powm(&f, &ske->prop->group->generator, &x,
546 &ske->prop->group->group);
548 /* Save the results for later processing */
549 two_payload = silc_calloc(1, sizeof(*two_payload));
552 ske->ke1_payload = one_payload;
553 ske->ke2_payload = two_payload;
555 /* Call the callback. */
557 (*callback)(ske, context);
562 /* This function computes the secret shared key KEY = e ^ x mod p, and,
563 a hash value to be signed and sent to the other end. This then
564 encodes Key Exchange 2 Payload and sends it to the other end. */
566 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
567 SilcPublicKey public_key,
568 SilcPrivateKey private_key,
569 SilcSKEPKType pk_type,
570 SilcSKESendPacketCb send_packet,
573 SilcSKEStatus status = SILC_SKE_STATUS_OK;
574 SilcBuffer payload_buf;
576 unsigned char hash[32], sign[256], *pk;
577 unsigned int hash_len, sign_len, pk_len;
579 SILC_LOG_DEBUG(("Start"));
581 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
583 /* Compute the shared secret key */
585 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
586 &ske->prop->group->group);
589 SILC_LOG_DEBUG(("Getting public key"));
591 /* Get the public key */
592 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
593 ske->ke2_payload->pk_data = pk;
594 ske->ke2_payload->pk_len = pk_len;
595 ske->ke2_payload->pk_type = pk_type;
597 SILC_LOG_DEBUG(("Computing HASH value"));
599 /* Compute the hash value */
600 memset(hash, 0, sizeof(hash));
601 status = silc_ske_make_hash(ske, hash, &hash_len);
602 if (status != SILC_SKE_STATUS_OK)
605 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
606 memcpy(ske->hash, hash, hash_len);
607 ske->hash_len = hash_len;
609 SILC_LOG_DEBUG(("Signing HASH value"));
611 /* Sign the hash value */
612 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
613 private_key->prv_len);
614 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
617 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
618 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
619 memset(sign, 0, sizeof(sign));
620 ske->ke2_payload->sign_len = sign_len;
622 /* Encode the Key Exchange 2 Payload */
623 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
625 if (status != SILC_SKE_STATUS_OK)
628 /* Send the packet. */
630 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
632 silc_buffer_free(payload_buf);
637 silc_mp_clear(&ske->KEY);
638 silc_ske_payload_two_free(ske->ke2_payload);
640 if (status == SILC_SKE_STATUS_OK)
641 return SILC_SKE_STATUS_ERROR;
646 /* The Key Exchange protocol is ended by calling this function. This
647 must not be called until the keys are processed like the protocol
648 defines. This function is for both initiator and responder. */
650 SilcSKEStatus silc_ske_end(SilcSKE ske,
651 SilcSKESendPacketCb send_packet,
654 SilcSKEStatus status = SILC_SKE_STATUS_OK;
657 SILC_LOG_DEBUG(("Start"));
659 packet = silc_buffer_alloc(1);
663 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
668 /* Aborts the Key Exchange protocol. This is called if error occurs
669 while performing the protocol. The status argument is the error
670 status and it is sent to the remote end. */
672 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
673 SilcSKESendPacketCb send_packet,
678 SILC_LOG_DEBUG(("Start"));
680 packet = silc_buffer_alloc(4);
681 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
682 silc_buffer_format(packet,
683 SILC_STR_UI_SHORT(status),
687 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
689 silc_buffer_free(packet);
691 return SILC_SKE_STATUS_OK;
694 /* Assembles security properties to Key Exchange Start Payload to be
695 sent to the remote end. This checks system wide (SILC system, that is)
696 settings and chooses from those. However, if other properties
697 should be used this function is easy to replace by another function,
698 as, this function is called by the caller of the protocol and not
699 by the protocol itself. */
702 silc_ske_assemble_security_properties(SilcSKE ske,
705 SilcSKEStartPayload **return_payload)
707 SilcSKEStartPayload *rp;
710 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
712 rp = silc_calloc(1, sizeof(*rp));
717 /* Set random cookie */
718 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
719 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
720 rp->cookie[i] = silc_rng_get_byte(ske->rng);
721 rp->cookie_len = SILC_SKE_COOKIE_LEN;
724 rp->version = strdup(version);
725 rp->version_len = strlen(version);
727 /* Get supported Key Exhange groups */
728 rp->ke_grp_list = silc_ske_get_supported_groups();
729 rp->ke_grp_len = strlen(rp->ke_grp_list);
731 /* Get supported PKCS algorithms */
732 rp->pkcs_alg_list = silc_pkcs_get_supported();
733 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
735 /* Get supported encryption algorithms */
736 rp->enc_alg_list = silc_cipher_get_supported();
737 rp->enc_alg_len = strlen(rp->enc_alg_list);
739 /* Get supported hash algorithms */
740 rp->hash_alg_list = silc_hash_get_supported();
741 rp->hash_alg_len = strlen(rp->hash_alg_list);
744 /* Get supported compression algorithms */
745 rp->comp_alg_list = "";
746 rp->comp_alg_len = 0;
748 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
749 2 + rp->version_len +
750 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
751 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
752 2 + rp->comp_alg_len;
754 *return_payload = rp;
756 return SILC_SKE_STATUS_OK;
759 /* Selects the supported security properties from the remote end's Key
760 Exchange Start Payload. */
763 silc_ske_select_security_properties(SilcSKE ske,
765 SilcSKEStartPayload *payload,
766 SilcSKEStartPayload *remote_payload)
768 SilcSKEStartPayload *rp;
772 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
776 /* Flags are returned unchanged. */
777 payload->flags = rp->flags;
780 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
781 payload->cookie_len = SILC_SKE_COOKIE_LEN;
782 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
784 /* XXX Do version check */
786 /* Put our version to our reply */
787 payload->version = strdup(version);
788 payload->version_len = strlen(version);
790 /* Get supported Key Exchange groups */
791 cp = rp->ke_grp_list;
792 if (cp && strchr(cp, ',')) {
796 len = strcspn(cp, ",");
797 item = silc_calloc(len + 1, sizeof(char));
798 memcpy(item, cp, len);
800 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
802 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
803 SILC_LOG_DEBUG(("Found KE group `%s'", item));
805 payload->ke_grp_len = len;
806 payload->ke_grp_list = item;
820 if (!payload->ke_grp_len && !payload->ke_grp_list) {
821 SILC_LOG_DEBUG(("Could not find supported KE group"));
823 return SILC_SKE_STATUS_UNKNOWN_GROUP;
827 if (!rp->ke_grp_len) {
828 SILC_LOG_DEBUG(("KE group not defined in payload"));
830 return SILC_SKE_STATUS_BAD_PAYLOAD;
833 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
834 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
836 payload->ke_grp_len = rp->ke_grp_len;
837 payload->ke_grp_list = strdup(rp->ke_grp_list);
840 /* Get supported PKCS algorithms */
841 cp = rp->pkcs_alg_list;
842 if (cp && strchr(cp, ',')) {
846 len = strcspn(cp, ",");
847 item = silc_calloc(len + 1, sizeof(char));
848 memcpy(item, cp, len);
850 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
852 if (silc_pkcs_is_supported(item) == TRUE) {
853 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
855 payload->pkcs_alg_len = len;
856 payload->pkcs_alg_list = item;
870 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
871 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
872 silc_free(payload->ke_grp_list);
874 return SILC_SKE_STATUS_UNKNOWN_PKCS;
878 if (!rp->pkcs_alg_len) {
879 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
880 silc_free(payload->ke_grp_list);
882 return SILC_SKE_STATUS_BAD_PAYLOAD;
885 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
886 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
888 payload->pkcs_alg_len = rp->pkcs_alg_len;
889 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
892 /* Get supported encryption algorithms */
893 cp = rp->enc_alg_list;
894 if (cp && strchr(cp, ',')) {
898 len = strcspn(cp, ",");
899 item = silc_calloc(len + 1, sizeof(char));
900 memcpy(item, cp, len);
902 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
904 if (silc_cipher_is_supported(item) == TRUE) {
905 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
907 payload->enc_alg_len = len;
908 payload->enc_alg_list = item;
922 if (!payload->enc_alg_len && !payload->enc_alg_list) {
923 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
924 silc_free(payload->ke_grp_list);
925 silc_free(payload->pkcs_alg_list);
927 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
931 if (!rp->enc_alg_len) {
932 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
933 silc_free(payload->ke_grp_list);
934 silc_free(payload->pkcs_alg_list);
936 return SILC_SKE_STATUS_BAD_PAYLOAD;
939 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
942 payload->enc_alg_len = rp->enc_alg_len;
943 payload->enc_alg_list = strdup(rp->enc_alg_list);
946 /* Get supported hash algorithms */
947 cp = rp->hash_alg_list;
948 if (cp && strchr(cp, ',')) {
952 len = strcspn(cp, ",");
953 item = silc_calloc(len + 1, sizeof(char));
954 memcpy(item, cp, len);
956 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
958 if (silc_hash_is_supported(item) == TRUE) {
959 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
961 payload->hash_alg_len = len;
962 payload->hash_alg_list = item;
976 if (!payload->hash_alg_len && !payload->hash_alg_list) {
977 SILC_LOG_DEBUG(("Could not find supported hash alg"));
978 silc_free(payload->ke_grp_list);
979 silc_free(payload->pkcs_alg_list);
980 silc_free(payload->enc_alg_list);
982 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
986 if (!rp->hash_alg_len) {
987 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
988 silc_free(payload->ke_grp_list);
989 silc_free(payload->pkcs_alg_list);
990 silc_free(payload->enc_alg_list);
992 return SILC_SKE_STATUS_BAD_PAYLOAD;
995 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
998 payload->hash_alg_len = rp->hash_alg_len;
999 payload->hash_alg_list = strdup(rp->hash_alg_list);
1003 /* Get supported compression algorithms */
1004 cp = rp->hash_alg_list;
1005 if (cp && strchr(cp, ',')) {
1009 len = strcspn(cp, ",");
1010 item = silc_calloc(len + 1, sizeof(char));
1011 memcpy(item, cp, len);
1013 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1015 if (silc_hash_is_supported(item) == TRUE) {
1016 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1018 payload->hash_alg_len = len;
1019 payload->hash_alg_list = item;
1024 if (strlen(cp) == 0)
1033 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1034 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1035 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1036 silc_free(payload->ke_grp_list);
1037 silc_free(payload->pkcs_alg_list);
1038 silc_free(payload->enc_alg_list);
1047 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1048 2 + payload->version_len +
1049 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1050 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1051 2 + payload->comp_alg_len;
1053 return SILC_SKE_STATUS_OK;
1056 /* Creates random number such that 1 < rnd < n and at most length
1057 of len bits. The rnd sent as argument must be initialized. */
1059 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1063 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1064 unsigned char *string;
1066 SILC_LOG_DEBUG(("Creating random number"));
1068 /* Get the random number as string */
1069 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1071 /* Decode the string into a MP integer */
1072 silc_mp_bin2mp(string, (len / 8), rnd);
1073 silc_mp_mod_2exp(rnd, rnd, len);
1076 if (silc_mp_cmp_ui(rnd, 1) < 0)
1077 status = SILC_SKE_STATUS_ERROR;
1079 if (silc_mp_cmp(rnd, &n) >= 0)
1080 status = SILC_SKE_STATUS_ERROR;
1082 memset(string, 'F', (len / 8));
1088 /* Creates a hash value HASH as defined in the SKE protocol. */
1090 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1091 unsigned char *return_hash,
1092 unsigned int *return_hash_len)
1094 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1096 unsigned char *e, *f, *KEY;
1097 unsigned int e_len, f_len, KEY_len;
1099 SILC_LOG_DEBUG(("Start"));
1101 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1102 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1103 KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1105 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1106 ske->pk_len + e_len + f_len + KEY_len);
1107 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1109 /* Format the buffer used to compute the hash value */
1110 silc_buffer_format(buf,
1111 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1112 ske->start_payload_copy->len),
1113 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1114 SILC_STR_UI_XNSTRING(e, e_len),
1115 SILC_STR_UI_XNSTRING(f, f_len),
1116 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1120 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1124 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1125 *return_hash_len = ske->prop->hash->hash->hash_len;
1127 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1129 silc_buffer_free(buf);
1130 memset(e, 0, e_len);
1131 memset(f, 0, f_len);
1132 memset(KEY, 0, KEY_len);
1140 /* Processes negotiated key material as protocol specifies. This returns
1141 the actual keys to be used in the SILC. */
1143 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1144 unsigned int req_iv_len,
1145 unsigned int req_enc_key_len,
1146 unsigned int req_hmac_key_len,
1147 SilcSKEKeyMaterial *key)
1151 unsigned char *tmpbuf;
1152 unsigned char hash[32];
1153 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1154 unsigned int enc_key_len = req_enc_key_len / 8;
1156 SILC_LOG_DEBUG(("Start"));
1158 /* Encode KEY to binary data */
1159 tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1161 buf = silc_buffer_alloc(1 + klen + hash_len);
1162 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1163 silc_buffer_format(buf,
1164 SILC_STR_UI_CHAR(0),
1165 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1166 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1170 memset(hash, 0, sizeof(hash));
1172 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1173 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1174 memcpy(key->send_iv, hash, req_iv_len);
1175 memset(hash, 0, sizeof(hash));
1177 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1178 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1179 memcpy(key->receive_iv, hash, req_iv_len);
1180 key->iv_len = req_iv_len;
1182 /* Take the encryption keys. If requested key size is more than
1183 the size of hash length we will distribute more key material
1184 as protocol defines. */
1186 if (enc_key_len > hash_len) {
1188 unsigned char k1[32], k2[32], k3[32];
1189 unsigned char *dtmp;
1192 if (enc_key_len > (3 * hash_len))
1193 return SILC_SKE_STATUS_ERROR;
1195 memset(k1, 0, sizeof(k1));
1196 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1199 dist = silc_buffer_alloc(hash_len * 3);
1201 silc_buffer_pull_tail(dist, klen + hash_len);
1202 silc_buffer_format(dist,
1203 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1204 SILC_STR_UI_XNSTRING(k1, hash_len),
1207 memset(k2, 0, sizeof(k2));
1208 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1210 silc_buffer_pull(dist, klen + hash_len);
1211 silc_buffer_format(dist,
1212 SILC_STR_UI_XNSTRING(k2, hash_len),
1214 silc_buffer_push(dist, klen + hash_len);
1216 memset(k3, 0, sizeof(k3));
1217 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1219 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1220 memcpy(dtmp, k1, hash_len);
1221 memcpy(dtmp + hash_len, k2, hash_len);
1222 memcpy(dtmp + hash_len, k3, hash_len);
1224 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1225 memcpy(key->send_enc_key, dtmp, enc_key_len);
1226 key->enc_key_len = req_enc_key_len;
1228 memset(dtmp, 0, (3 * hash_len));
1229 memset(k1, 0, sizeof(k1));
1230 memset(k2, 0, sizeof(k2));
1231 memset(k3, 0, sizeof(k3));
1233 silc_buffer_free(dist);
1235 /* Take normal hash as key */
1236 memset(hash, 0, sizeof(hash));
1237 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1238 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1239 memcpy(key->send_enc_key, hash, enc_key_len);
1240 key->enc_key_len = req_enc_key_len;
1244 if (enc_key_len > hash_len) {
1246 unsigned char k1[32], k2[32], k3[32];
1247 unsigned char *dtmp;
1250 if (enc_key_len > (3 * hash_len))
1251 return SILC_SKE_STATUS_ERROR;
1253 memset(k1, 0, sizeof(k1));
1254 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1257 dist = silc_buffer_alloc(hash_len * 3);
1259 silc_buffer_pull_tail(dist, klen + hash_len);
1260 silc_buffer_format(dist,
1261 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1262 SILC_STR_UI_XNSTRING(k1, hash_len),
1265 memset(k2, 0, sizeof(k2));
1266 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1268 silc_buffer_pull(dist, klen + hash_len);
1269 silc_buffer_format(dist,
1270 SILC_STR_UI_XNSTRING(k2, hash_len),
1272 silc_buffer_push(dist, klen + hash_len);
1274 memset(k3, 0, sizeof(k3));
1275 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1277 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1278 memcpy(dtmp, k1, hash_len);
1279 memcpy(dtmp + hash_len, k2, hash_len);
1280 memcpy(dtmp + hash_len, k3, hash_len);
1282 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1283 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1284 key->enc_key_len = req_enc_key_len;
1286 memset(dtmp, 0, (3 * hash_len));
1287 memset(k1, 0, sizeof(k1));
1288 memset(k2, 0, sizeof(k2));
1289 memset(k3, 0, sizeof(k3));
1291 silc_buffer_free(dist);
1293 /* Take normal hash as key */
1294 memset(hash, 0, sizeof(hash));
1295 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1296 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1297 memcpy(key->receive_enc_key, hash, enc_key_len);
1298 key->enc_key_len = req_enc_key_len;
1302 memset(hash, 0, sizeof(hash));
1304 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1305 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1306 memcpy(key->hmac_key, hash, req_hmac_key_len);
1307 key->hmac_key_len = req_hmac_key_len;
1309 memset(tmpbuf, 0, klen);
1312 return SILC_SKE_STATUS_OK;