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);
70 silc_hmac_free(ske->prop->hmac);
73 if (ske->start_payload_copy)
74 silc_buffer_free(ske->start_payload_copy);
78 silc_mp_clear(ske->x);
82 silc_mp_clear(ske->KEY);
91 /* Starts the SILC Key Exchange protocol for initiator. The connection
92 to the remote end must be established before calling this function
93 and the connecting socket must be sent as argument. This function
94 creates the Key Exchange Start Paload which includes all our
95 configured security properties. This payload is then sent to the
96 remote end for further processing. This payload must be sent as
97 argument to the function, however, it must not be encoded
98 already, it is done by this function.
100 The packet sending is done by calling a callback function. Caller
101 must provide a routine to send the packet. */
103 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
104 SilcSocketConnection sock,
105 SilcSKEStartPayload *start_payload,
106 SilcSKESendPacketCb send_packet,
109 SilcSKEStatus status = SILC_SKE_STATUS_OK;
110 SilcBuffer payload_buf;
112 SILC_LOG_DEBUG(("Start"));
117 /* Encode the payload */
118 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
119 if (status != SILC_SKE_STATUS_OK)
122 /* Take a copy of the payload buffer for future use. It is used to
123 compute the HASH value. */
124 ske->start_payload_copy = silc_buffer_copy(payload_buf);
126 /* Send the packet. */
128 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
130 silc_buffer_free(payload_buf);
135 /* Function called after ske_initiator_start fuction. This receives
136 the remote ends Key Exchange Start payload which includes the
137 security properties selected by the responder from our payload
138 sent in the silc_ske_initiator_start function. */
140 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
141 SilcBuffer start_payload,
145 SilcSKEStatus status = SILC_SKE_STATUS_OK;
146 SilcSKEStartPayload *payload;
147 SilcSKESecurityProperties prop;
148 SilcSKEDiffieHellmanGroup group;
150 SILC_LOG_DEBUG(("Start"));
152 /* Decode the payload */
153 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
154 if (status != SILC_SKE_STATUS_OK) {
155 ske->status = status;
159 /* Take the selected security properties into use while doing
160 the key exchange. This is used only while doing the key
161 exchange. The same data is returned to upper levels by calling
162 the callback function. */
163 ske->prop = prop = silc_calloc(1, sizeof(*prop));
164 prop->flags = payload->flags;
165 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
166 if (status != SILC_SKE_STATUS_OK)
171 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
172 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
176 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
177 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
181 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
182 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
186 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
187 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
191 ske->start_payload = payload;
193 /* Return the received payload by calling the callback function. */
195 (*callback)(ske, context);
201 silc_ske_payload_start_free(payload);
206 silc_pkcs_free(prop->pkcs);
208 silc_cipher_free(prop->cipher);
210 silc_hash_free(prop->hash);
212 silc_hmac_free(prop->hmac);
216 if (status == SILC_SKE_STATUS_OK)
217 return SILC_SKE_STATUS_ERROR;
219 ske->status = status;
223 /* This function creates random number x, such that 1 < x < q and
224 computes e = g ^ x mod p and sends the result to the remote end in
225 Key Exchange 1 Payload. */
227 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
228 SilcPublicKey public_key,
229 SilcSKESendPacketCb send_packet,
232 SilcSKEStatus status = SILC_SKE_STATUS_OK;
233 SilcBuffer payload_buf;
235 SilcSKEOnePayload *payload;
238 SILC_LOG_DEBUG(("Start"));
240 /* Create the random number x, 1 < x < q. */
241 x = silc_calloc(1, sizeof(*x));
244 silc_ske_create_rnd(ske, ske->prop->group->group_order,
245 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
247 if (status != SILC_SKE_STATUS_OK) {
250 ske->status = status;
254 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
256 /* Do the Diffie Hellman computation, e = g ^ x mod p */
258 silc_mp_powm(&e, &ske->prop->group->generator, x,
259 &ske->prop->group->group);
261 /* Encode the result to Key Exchange 1 Payload. */
262 payload = silc_calloc(1, sizeof(*payload));
264 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
265 if (!payload->pk_data) {
270 ske->status = SILC_SKE_STATUS_OK;
273 payload->pk_len = pk_len;
274 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
275 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
276 if (status != SILC_SKE_STATUS_OK) {
280 silc_free(payload->pk_data);
282 ske->status = status;
286 ske->ke1_payload = payload;
289 /* Send the packet. */
291 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
293 silc_buffer_free(payload_buf);
298 /* Receives Key Exchange 2 Payload from responder consisting responders
299 public key, f, and signature. This function verifies the public key,
300 computes the secret shared key and verifies the signature. */
302 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
303 SilcBuffer ke2_payload,
304 SilcSKEVerifyCb verify_key,
305 void *verify_context,
309 SilcSKEStatus status = SILC_SKE_STATUS_OK;
310 SilcSKETwoPayload *payload;
311 SilcPublicKey public_key = NULL;
313 unsigned char hash[32];
314 unsigned int hash_len;
316 SILC_LOG_DEBUG(("Start"));
318 /* Decode the payload */
319 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
320 if (status != SILC_SKE_STATUS_OK) {
321 ske->status = status;
324 ske->ke2_payload = payload;
326 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
328 /* Compute the shared secret key */
329 KEY = silc_calloc(1, sizeof(*KEY));
331 silc_mp_powm(KEY, &payload->f, ske->x, &ske->prop->group->group);
334 SILC_LOG_DEBUG(("Verifying public key"));
336 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
338 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
343 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
344 payload->pk_type, verify_context);
345 if (status != SILC_SKE_STATUS_OK)
349 SILC_LOG_DEBUG(("Public key is authentic"));
351 /* Compute the hash value */
352 status = silc_ske_make_hash(ske, hash, &hash_len);
353 if (status != SILC_SKE_STATUS_OK)
356 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
357 memcpy(ske->hash, hash, hash_len);
358 ske->hash_len = hash_len;
360 SILC_LOG_DEBUG(("Verifying signature"));
362 /* Verify signature */
363 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
365 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
366 payload->sign_len, hash, hash_len) == FALSE) {
368 SILC_LOG_DEBUG(("Signature don't match"));
370 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
374 SILC_LOG_DEBUG(("Signature is Ok"));
376 silc_pkcs_public_key_free(public_key);
377 memset(hash, 'F', hash_len);
379 /* Call the callback. */
381 (*callback)(ske, context);
386 memset(hash, 'F', sizeof(hash));
387 silc_ske_payload_two_free(payload);
388 ske->ke2_payload = NULL;
390 silc_mp_clear(ske->KEY);
395 silc_pkcs_public_key_free(public_key);
398 memset(ske->hash, 'F', hash_len);
399 silc_free(ske->hash);
403 if (status == SILC_SKE_STATUS_OK)
404 return SILC_SKE_STATUS_ERROR;
406 ske->status = status;
410 /* Starts Key Exchange protocol for responder. Responder receives
411 Key Exchange Start Payload from initiator consisting of all the
412 security properties the initiator supports. This function decodes
413 the payload and parses the payload further and selects the right
414 security properties. */
416 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
417 SilcSocketConnection sock,
419 SilcBuffer start_payload,
423 SilcSKEStatus status = SILC_SKE_STATUS_OK;
424 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
426 SILC_LOG_DEBUG(("Start"));
431 /* Decode the payload */
432 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
433 if (status != SILC_SKE_STATUS_OK) {
434 ske->status = status;
438 /* Take a copy of the payload buffer for future use. It is used to
439 compute the HASH value. */
440 ske->start_payload_copy = silc_buffer_copy(start_payload);
442 /* Parse and select the security properties from the payload */
443 payload = silc_calloc(1, sizeof(*payload));
444 status = silc_ske_select_security_properties(ske, version,
445 payload, remote_payload);
446 if (status != SILC_SKE_STATUS_OK)
449 ske->start_payload = payload;
451 /* Call the callback function. */
453 (*callback)(ske, context);
459 silc_ske_payload_start_free(remote_payload);
463 if (status == SILC_SKE_STATUS_OK)
464 return SILC_SKE_STATUS_ERROR;
466 ske->status = status;
470 /* The selected security properties from the initiator payload is now
471 encoded into Key Exchange Start Payload and sent to the initiator. */
473 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
474 SilcSKEStartPayload *start_payload,
475 SilcSKESendPacketCb send_packet,
478 SilcSKEStatus status = SILC_SKE_STATUS_OK;
479 SilcBuffer payload_buf;
480 SilcSKESecurityProperties prop;
481 SilcSKEDiffieHellmanGroup group = NULL;
483 SILC_LOG_DEBUG(("Start"));
485 /* Allocate security properties from the payload. These are allocated
486 only for this negotiation and will be free'd after KE is over. */
487 ske->prop = prop = silc_calloc(1, sizeof(*prop));
488 prop->flags = start_payload->flags;
489 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
490 if (status != SILC_SKE_STATUS_OK)
495 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
496 &prop->pkcs) == FALSE) {
497 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
501 if (silc_cipher_alloc(start_payload->enc_alg_list,
502 &prop->cipher) == FALSE) {
503 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
507 if (silc_hash_alloc(start_payload->hash_alg_list,
508 &prop->hash) == FALSE) {
509 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
513 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
514 &prop->hmac) == FALSE) {
515 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
519 /* Encode the payload */
520 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
521 if (status != SILC_SKE_STATUS_OK)
524 /* Send the packet. */
526 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
528 silc_buffer_free(payload_buf);
537 silc_pkcs_free(prop->pkcs);
539 silc_cipher_free(prop->cipher);
541 silc_hash_free(prop->hash);
543 silc_hmac_free(prop->hmac);
547 if (status == SILC_SKE_STATUS_OK)
548 return SILC_SKE_STATUS_ERROR;
550 ske->status = status;
554 /* This function receives the Key Exchange 1 Payload from the initiator.
555 After processing the payload this then selects random number x,
556 such that 1 < x < q and computes f = g ^ x mod p. This then puts
557 the result f to a Key Exchange 2 Payload which is later processed
558 in ske_responder_finish function. The callback function should
559 not touch the payload (it should merely call the ske_responder_finish
562 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
563 SilcBuffer ke1_payload,
567 SilcSKEStatus status = SILC_SKE_STATUS_OK;
568 SilcSKEOnePayload *one_payload;
569 SilcSKETwoPayload *two_payload;
572 SILC_LOG_DEBUG(("Start"));
574 /* Decode Key Exchange 1 Payload */
575 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
576 if (status != SILC_SKE_STATUS_OK) {
577 ske->status = status;
581 /* Create the random number x, 1 < x < q. */
582 x = silc_calloc(1, sizeof(*x));
585 silc_ske_create_rnd(ske, ske->prop->group->group_order,
586 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
588 if (status != SILC_SKE_STATUS_OK) {
594 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
596 /* Do the Diffie Hellman computation, f = g ^ x mod p */
598 silc_mp_powm(&f, &ske->prop->group->generator, x,
599 &ske->prop->group->group);
601 /* Save the results for later processing */
602 two_payload = silc_calloc(1, sizeof(*two_payload));
605 ske->ke1_payload = one_payload;
606 ske->ke2_payload = two_payload;
608 /* Call the callback. */
610 (*callback)(ske, context);
615 /* This function computes the secret shared key KEY = e ^ x mod p, and,
616 a hash value to be signed and sent to the other end. This then
617 encodes Key Exchange 2 Payload and sends it to the other end. */
619 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
620 SilcPublicKey public_key,
621 SilcPrivateKey private_key,
622 SilcSKEPKType pk_type,
623 SilcSKESendPacketCb send_packet,
626 SilcSKEStatus status = SILC_SKE_STATUS_OK;
627 SilcBuffer payload_buf;
629 unsigned char hash[32], sign[1024], *pk;
630 unsigned int hash_len, sign_len, pk_len;
632 SILC_LOG_DEBUG(("Start"));
634 if (!public_key || !private_key) {
635 status = SILC_SKE_STATUS_ERROR;
639 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
641 /* Compute the shared secret key */
642 KEY = silc_calloc(1, sizeof(*KEY));
644 silc_mp_powm(KEY, &ske->ke1_payload->e, ske->x,
645 &ske->prop->group->group);
648 SILC_LOG_DEBUG(("Getting public key"));
650 /* Get the public key */
651 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
653 status = SILC_SKE_STATUS_ERROR;
656 ske->ke2_payload->pk_data = pk;
657 ske->ke2_payload->pk_len = pk_len;
658 ske->ke2_payload->pk_type = pk_type;
660 SILC_LOG_DEBUG(("Computing HASH value"));
662 /* Compute the hash value */
663 memset(hash, 0, sizeof(hash));
664 status = silc_ske_make_hash(ske, hash, &hash_len);
665 if (status != SILC_SKE_STATUS_OK)
668 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
669 memcpy(ske->hash, hash, hash_len);
670 ske->hash_len = hash_len;
672 SILC_LOG_DEBUG(("Signing HASH value"));
674 /* Sign the hash value */
675 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
676 private_key->prv_len);
677 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
678 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
679 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
680 memset(sign, 0, sizeof(sign));
681 ske->ke2_payload->sign_len = sign_len;
683 /* Encode the Key Exchange 2 Payload */
684 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
686 if (status != SILC_SKE_STATUS_OK)
689 /* Send the packet. */
691 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
693 silc_buffer_free(payload_buf);
698 silc_mp_clear(ske->KEY);
701 silc_ske_payload_two_free(ske->ke2_payload);
703 if (status == SILC_SKE_STATUS_OK)
704 return SILC_SKE_STATUS_ERROR;
706 ske->status = status;
710 /* The Key Exchange protocol is ended by calling this function. This
711 must not be called until the keys are processed like the protocol
712 defines. This function is for both initiator and responder. */
714 SilcSKEStatus silc_ske_end(SilcSKE ske,
715 SilcSKESendPacketCb send_packet,
720 SILC_LOG_DEBUG(("Start"));
722 packet = silc_buffer_alloc(4);
723 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
724 silc_buffer_format(packet,
725 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
729 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
731 silc_buffer_free(packet);
733 return SILC_SKE_STATUS_OK;
736 /* Aborts the Key Exchange protocol. This is called if error occurs
737 while performing the protocol. The status argument is the error
738 status and it is sent to the remote end. */
740 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
741 SilcSKESendPacketCb send_packet,
746 SILC_LOG_DEBUG(("Start"));
748 packet = silc_buffer_alloc(4);
749 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
750 silc_buffer_format(packet,
751 SILC_STR_UI_SHORT(status),
755 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
757 silc_buffer_free(packet);
759 return SILC_SKE_STATUS_OK;
762 /* Assembles security properties to Key Exchange Start Payload to be
763 sent to the remote end. This checks system wide (SILC system, that is)
764 settings and chooses from those. However, if other properties
765 should be used this function is easy to replace by another function,
766 as, this function is called by the caller of the protocol and not
767 by the protocol itself. */
770 silc_ske_assemble_security_properties(SilcSKE ske,
773 SilcSKEStartPayload **return_payload)
775 SilcSKEStartPayload *rp;
778 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
780 rp = silc_calloc(1, sizeof(*rp));
785 /* Set random cookie */
786 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
787 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
788 rp->cookie[i] = silc_rng_get_byte(ske->rng);
789 rp->cookie_len = SILC_SKE_COOKIE_LEN;
792 rp->version = strdup(version);
793 rp->version_len = strlen(version);
795 /* Get supported Key Exhange groups */
796 rp->ke_grp_list = silc_ske_get_supported_groups();
797 rp->ke_grp_len = strlen(rp->ke_grp_list);
799 /* Get supported PKCS algorithms */
800 rp->pkcs_alg_list = silc_pkcs_get_supported();
801 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
803 /* Get supported encryption algorithms */
804 rp->enc_alg_list = silc_cipher_get_supported();
805 rp->enc_alg_len = strlen(rp->enc_alg_list);
807 /* Get supported hash algorithms */
808 rp->hash_alg_list = silc_hash_get_supported();
809 rp->hash_alg_len = strlen(rp->hash_alg_list);
811 /* Get supported HMACs */
812 rp->hmac_alg_list = silc_hmac_get_supported();
813 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
816 /* Get supported compression algorithms */
817 rp->comp_alg_list = "";
818 rp->comp_alg_len = 0;
820 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
821 2 + rp->version_len +
822 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
823 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
824 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
826 *return_payload = rp;
828 return SILC_SKE_STATUS_OK;
831 /* Selects the supported security properties from the remote end's Key
832 Exchange Start Payload. */
835 silc_ske_select_security_properties(SilcSKE ske,
837 SilcSKEStartPayload *payload,
838 SilcSKEStartPayload *remote_payload)
840 SilcSKEStatus status;
841 SilcSKEStartPayload *rp;
845 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
849 /* Check version string */
850 status = silc_ske_check_version(ske, rp->version, rp->version_len);
851 if (status != SILC_SKE_STATUS_OK) {
852 ske->status = status;
856 /* Flags are returned unchanged. */
857 payload->flags = rp->flags;
860 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
861 payload->cookie_len = SILC_SKE_COOKIE_LEN;
862 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
864 /* Put our version to our reply */
865 payload->version = strdup(version);
866 payload->version_len = strlen(version);
868 /* Get supported Key Exchange groups */
869 cp = rp->ke_grp_list;
870 if (cp && strchr(cp, ',')) {
874 len = strcspn(cp, ",");
875 item = silc_calloc(len + 1, sizeof(char));
876 memcpy(item, cp, len);
878 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
880 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
881 SILC_LOG_DEBUG(("Found KE group `%s'", item));
883 payload->ke_grp_len = len;
884 payload->ke_grp_list = item;
898 if (!payload->ke_grp_len && !payload->ke_grp_list) {
899 SILC_LOG_DEBUG(("Could not find supported KE group"));
901 return SILC_SKE_STATUS_UNKNOWN_GROUP;
905 if (!rp->ke_grp_len) {
906 SILC_LOG_DEBUG(("KE group not defined in payload"));
908 return SILC_SKE_STATUS_BAD_PAYLOAD;
911 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
912 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
914 payload->ke_grp_len = rp->ke_grp_len;
915 payload->ke_grp_list = strdup(rp->ke_grp_list);
918 /* Get supported PKCS algorithms */
919 cp = rp->pkcs_alg_list;
920 if (cp && strchr(cp, ',')) {
924 len = strcspn(cp, ",");
925 item = silc_calloc(len + 1, sizeof(char));
926 memcpy(item, cp, len);
928 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
930 if (silc_pkcs_is_supported(item) == TRUE) {
931 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
933 payload->pkcs_alg_len = len;
934 payload->pkcs_alg_list = item;
948 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
949 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
950 silc_free(payload->ke_grp_list);
952 return SILC_SKE_STATUS_UNKNOWN_PKCS;
956 if (!rp->pkcs_alg_len) {
957 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
958 silc_free(payload->ke_grp_list);
960 return SILC_SKE_STATUS_BAD_PAYLOAD;
963 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
964 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
966 payload->pkcs_alg_len = rp->pkcs_alg_len;
967 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
970 /* Get supported encryption algorithms */
971 cp = rp->enc_alg_list;
972 if (cp && strchr(cp, ',')) {
976 len = strcspn(cp, ",");
977 item = silc_calloc(len + 1, sizeof(char));
978 memcpy(item, cp, len);
980 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
982 if (silc_cipher_is_supported(item) == TRUE) {
983 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
985 payload->enc_alg_len = len;
986 payload->enc_alg_list = item;
1000 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1001 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1002 silc_free(payload->ke_grp_list);
1003 silc_free(payload->pkcs_alg_list);
1005 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1009 if (!rp->enc_alg_len) {
1010 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1011 silc_free(payload->ke_grp_list);
1012 silc_free(payload->pkcs_alg_list);
1014 return SILC_SKE_STATUS_BAD_PAYLOAD;
1017 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1020 payload->enc_alg_len = rp->enc_alg_len;
1021 payload->enc_alg_list = strdup(rp->enc_alg_list);
1024 /* Get supported hash algorithms */
1025 cp = rp->hash_alg_list;
1026 if (cp && strchr(cp, ',')) {
1030 len = strcspn(cp, ",");
1031 item = silc_calloc(len + 1, sizeof(char));
1032 memcpy(item, cp, len);
1034 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1036 if (silc_hash_is_supported(item) == TRUE) {
1037 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1039 payload->hash_alg_len = len;
1040 payload->hash_alg_list = item;
1045 if (strlen(cp) == 0)
1054 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1055 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1056 silc_free(payload->ke_grp_list);
1057 silc_free(payload->pkcs_alg_list);
1058 silc_free(payload->enc_alg_list);
1060 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1064 if (!rp->hash_alg_len) {
1065 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1066 silc_free(payload->ke_grp_list);
1067 silc_free(payload->pkcs_alg_list);
1068 silc_free(payload->enc_alg_list);
1070 return SILC_SKE_STATUS_BAD_PAYLOAD;
1073 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1074 rp->hash_alg_list));
1076 payload->hash_alg_len = rp->hash_alg_len;
1077 payload->hash_alg_list = strdup(rp->hash_alg_list);
1080 /* Get supported HMACs */
1081 cp = rp->hmac_alg_list;
1082 if (cp && strchr(cp, ',')) {
1086 len = strcspn(cp, ",");
1087 item = silc_calloc(len + 1, sizeof(char));
1088 memcpy(item, cp, len);
1090 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1092 if (silc_hmac_is_supported(item) == TRUE) {
1093 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1095 payload->hmac_alg_len = len;
1096 payload->hmac_alg_list = item;
1101 if (strlen(cp) == 0)
1110 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1111 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1112 silc_free(payload->ke_grp_list);
1113 silc_free(payload->pkcs_alg_list);
1114 silc_free(payload->enc_alg_list);
1115 silc_free(payload->hash_alg_list);
1117 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1121 if (!rp->hmac_alg_len) {
1122 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1123 silc_free(payload->ke_grp_list);
1124 silc_free(payload->pkcs_alg_list);
1125 silc_free(payload->enc_alg_list);
1126 silc_free(payload->hash_alg_list);
1128 return SILC_SKE_STATUS_BAD_PAYLOAD;
1131 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1132 rp->hmac_alg_list));
1134 payload->hmac_alg_len = rp->hmac_alg_len;
1135 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1139 /* Get supported compression algorithms */
1140 cp = rp->hash_alg_list;
1141 if (cp && strchr(cp, ',')) {
1145 len = strcspn(cp, ",");
1146 item = silc_calloc(len + 1, sizeof(char));
1147 memcpy(item, cp, len);
1149 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1151 if (silc_hash_is_supported(item) == TRUE) {
1152 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1154 payload->hash_alg_len = len;
1155 payload->hash_alg_list = item;
1160 if (strlen(cp) == 0)
1169 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1170 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1171 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1172 silc_free(payload->ke_grp_list);
1173 silc_free(payload->pkcs_alg_list);
1174 silc_free(payload->enc_alg_list);
1183 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1184 2 + payload->version_len +
1185 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1186 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1187 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1189 return SILC_SKE_STATUS_OK;
1192 /* Creates random number such that 1 < rnd < n and at most length
1193 of len bits. The rnd sent as argument must be initialized. */
1195 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1199 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1200 unsigned char *string;
1202 SILC_LOG_DEBUG(("Creating random number"));
1204 /* Get the random number as string */
1205 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1207 return SILC_SKE_STATUS_ERROR;
1209 /* Decode the string into a MP integer */
1210 silc_mp_bin2mp(string, (len / 8), rnd);
1211 silc_mp_mod_2exp(rnd, rnd, len);
1214 if (silc_mp_cmp_ui(rnd, 1) < 0)
1215 status = SILC_SKE_STATUS_ERROR;
1217 if (silc_mp_cmp(rnd, &n) >= 0)
1218 status = SILC_SKE_STATUS_ERROR;
1220 memset(string, 'F', (len / 8));
1226 /* Creates a hash value HASH as defined in the SKE protocol. */
1228 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1229 unsigned char *return_hash,
1230 unsigned int *return_hash_len)
1232 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1234 unsigned char *e, *f, *KEY;
1235 unsigned int e_len, f_len, KEY_len;
1238 SILC_LOG_DEBUG(("Start"));
1240 e = silc_mp_mp2bin(&ske->ke1_payload->e, 0, &e_len);
1241 f = silc_mp_mp2bin(&ske->ke2_payload->f, 0, &f_len);
1242 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1244 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1245 ske->pk_len + e_len + f_len + KEY_len);
1246 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1248 /* Format the buffer used to compute the hash value */
1249 ret = silc_buffer_format(buf,
1250 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1251 ske->start_payload_copy->len),
1252 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1253 SILC_STR_UI_XNSTRING(e, e_len),
1254 SILC_STR_UI_XNSTRING(f, f_len),
1255 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1258 silc_buffer_free(buf);
1259 memset(e, 0, e_len);
1260 memset(f, 0, f_len);
1261 memset(KEY, 0, KEY_len);
1265 return SILC_SKE_STATUS_ERROR;
1269 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1270 *return_hash_len = ske->prop->hash->hash->hash_len;
1272 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1274 silc_buffer_free(buf);
1275 memset(e, 0, e_len);
1276 memset(f, 0, f_len);
1277 memset(KEY, 0, KEY_len);
1285 /* Processes the provided key material `data' as the SILC protocol
1286 specification specifies. */
1289 silc_ske_process_key_material_data(unsigned char *data,
1290 unsigned int data_len,
1291 unsigned int req_iv_len,
1292 unsigned int req_enc_key_len,
1293 unsigned int req_hmac_key_len,
1295 SilcSKEKeyMaterial *key)
1298 unsigned char hashd[32];
1299 unsigned int hash_len = req_hmac_key_len;
1300 unsigned int enc_key_len = req_enc_key_len / 8;
1302 SILC_LOG_DEBUG(("Start"));
1304 buf = silc_buffer_alloc(1 + data_len);
1305 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1306 silc_buffer_format(buf,
1307 SILC_STR_UI_CHAR(0),
1308 SILC_STR_UI_XNSTRING(data, data_len),
1312 memset(hashd, 0, sizeof(hashd));
1314 silc_hash_make(hash, buf->data, buf->len, hashd);
1315 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1316 memcpy(key->send_iv, hashd, req_iv_len);
1317 memset(hashd, 0, sizeof(hashd));
1319 silc_hash_make(hash, buf->data, buf->len, hashd);
1320 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1321 memcpy(key->receive_iv, hashd, req_iv_len);
1322 key->iv_len = req_iv_len;
1324 /* Take the encryption keys. If requested key size is more than
1325 the size of hash length we will distribute more key material
1326 as protocol defines. */
1328 if (enc_key_len > hash_len) {
1330 unsigned char k1[32], k2[32], k3[32];
1331 unsigned char *dtmp;
1334 if (enc_key_len > (3 * hash_len))
1335 return SILC_SKE_STATUS_ERROR;
1337 /* Take first round */
1338 memset(k1, 0, sizeof(k1));
1339 silc_hash_make(hash, buf->data, buf->len, k1);
1341 /* Take second round */
1342 dist = silc_buffer_alloc(data_len + hash_len);
1343 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1344 silc_buffer_format(dist,
1345 SILC_STR_UI_XNSTRING(data, data_len),
1346 SILC_STR_UI_XNSTRING(k1, hash_len),
1348 memset(k2, 0, sizeof(k2));
1349 silc_hash_make(hash, dist->data, dist->len, k2);
1351 /* Take third round */
1352 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1353 silc_buffer_pull_tail(dist, hash_len);
1354 silc_buffer_pull(dist, data_len + hash_len);
1355 silc_buffer_format(dist,
1356 SILC_STR_UI_XNSTRING(k2, hash_len),
1358 silc_buffer_push(dist, data_len + hash_len);
1359 memset(k3, 0, sizeof(k3));
1360 silc_hash_make(hash, dist->data, dist->len, k3);
1362 /* Then, save the keys */
1363 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1364 memcpy(dtmp, k1, hash_len);
1365 memcpy(dtmp + hash_len, k2, hash_len);
1366 memcpy(dtmp + hash_len, k3, hash_len);
1368 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1369 memcpy(key->send_enc_key, dtmp, enc_key_len);
1370 key->enc_key_len = req_enc_key_len;
1372 memset(dtmp, 0, (3 * hash_len));
1373 memset(k1, 0, sizeof(k1));
1374 memset(k2, 0, sizeof(k2));
1375 memset(k3, 0, sizeof(k3));
1377 silc_buffer_free(dist);
1379 /* Take normal hash as key */
1380 memset(hashd, 0, sizeof(hashd));
1381 silc_hash_make(hash, buf->data, buf->len, hashd);
1382 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1383 memcpy(key->send_enc_key, hashd, enc_key_len);
1384 key->enc_key_len = req_enc_key_len;
1388 if (enc_key_len > hash_len) {
1390 unsigned char k1[32], k2[32], k3[32];
1391 unsigned char *dtmp;
1394 if (enc_key_len > (3 * hash_len))
1395 return SILC_SKE_STATUS_ERROR;
1397 /* Take first round */
1398 memset(k1, 0, sizeof(k1));
1399 silc_hash_make(hash, buf->data, buf->len, k1);
1401 /* Take second round */
1402 dist = silc_buffer_alloc(data_len + hash_len);
1403 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1404 silc_buffer_format(dist,
1405 SILC_STR_UI_XNSTRING(data, data_len),
1406 SILC_STR_UI_XNSTRING(k1, hash_len),
1408 memset(k2, 0, sizeof(k2));
1409 silc_hash_make(hash, dist->data, dist->len, k2);
1411 /* Take third round */
1412 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1413 silc_buffer_pull_tail(dist, hash_len);
1414 silc_buffer_pull(dist, data_len + hash_len);
1415 silc_buffer_format(dist,
1416 SILC_STR_UI_XNSTRING(k2, hash_len),
1418 silc_buffer_push(dist, data_len + hash_len);
1419 memset(k3, 0, sizeof(k3));
1420 silc_hash_make(hash, dist->data, dist->len, k3);
1422 /* Then, save the keys */
1423 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1424 memcpy(dtmp, k1, hash_len);
1425 memcpy(dtmp + hash_len, k2, hash_len);
1426 memcpy(dtmp + hash_len, k3, hash_len);
1428 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1429 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1430 key->enc_key_len = req_enc_key_len;
1432 memset(dtmp, 0, (3 * hash_len));
1433 memset(k1, 0, sizeof(k1));
1434 memset(k2, 0, sizeof(k2));
1435 memset(k3, 0, sizeof(k3));
1437 silc_buffer_free(dist);
1439 /* Take normal hash as key */
1440 memset(hashd, 0, sizeof(hashd));
1441 silc_hash_make(hash, buf->data, buf->len, hashd);
1442 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1443 memcpy(key->receive_enc_key, hashd, enc_key_len);
1444 key->enc_key_len = req_enc_key_len;
1448 memset(hashd, 0, sizeof(hashd));
1450 silc_hash_make(hash, buf->data, buf->len, hashd);
1451 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1452 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1453 key->hmac_key_len = req_hmac_key_len;
1455 silc_buffer_free(buf);
1457 return SILC_SKE_STATUS_OK;
1460 /* Processes negotiated key material as protocol specifies. This returns
1461 the actual keys to be used in the SILC. */
1463 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1464 unsigned int req_iv_len,
1465 unsigned int req_enc_key_len,
1466 unsigned int req_hmac_key_len,
1467 SilcSKEKeyMaterial *key)
1469 SilcSKEStatus status;
1471 unsigned char *tmpbuf;
1474 /* Encode KEY to binary data */
1475 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1477 buf = silc_buffer_alloc(klen + ske->hash_len);
1478 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1479 silc_buffer_format(buf,
1480 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1481 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1484 /* Process the key material */
1485 status = silc_ske_process_key_material_data(buf->data, buf->len,
1486 req_iv_len, req_enc_key_len,
1488 ske->prop->hash, key);
1490 memset(tmpbuf, 0, klen);
1492 silc_buffer_free(buf);
1497 /* Free key material structure */
1499 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1505 silc_free(key->send_iv);
1506 if (key->receive_iv)
1507 silc_free(key->receive_iv);
1508 if (key->send_enc_key) {
1509 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1510 silc_free(key->send_enc_key);
1512 if (key->receive_enc_key) {
1513 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1514 silc_free(key->receive_enc_key);
1516 if (key->hmac_key) {
1517 memset(key->hmac_key, 0, key->hmac_key_len);
1518 silc_free(key->hmac_key);