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.2 2000/07/05 06:05:15 priikone
24 * Global cosmetic change.
26 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
27 * Imported from internal CVS/Added Log headers.
32 #include "silcincludes.h"
33 #include "payload_internal.h"
34 #include "groups_internal.h"
36 /* Allocates new SKE object. */
38 SilcSKE silc_ske_alloc()
42 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
44 ske = silc_calloc(1, sizeof(*ske));
49 /* Free's SKE object. */
51 void silc_ske_free(SilcSKE ske)
53 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
56 /* Free start payload */
57 if (ske->start_payload)
58 silc_ske_payload_start_free(ske->start_payload);
60 /* Free KE1 payload */
62 silc_ske_payload_one_free(ske->ke1_payload);
64 /* Free KE2 payload */
66 silc_ske_payload_two_free(ske->ke2_payload);
71 silc_free(ske->prop->group);
73 silc_pkcs_free(ske->prop->pkcs);
74 if (ske->prop->cipher)
75 silc_cipher_free(ske->prop->cipher);
77 silc_hash_free(ske->prop->hash);
80 if (ske->start_payload_copy)
81 silc_buffer_free(ske->start_payload_copy);
84 silc_mp_clear(&ske->x);
85 silc_mp_clear(&ske->KEY);
92 /* Starts the SILC Key Exchange protocol for initiator. The connection
93 to the remote end must be established before calling this function
94 and the connecting socket must be sent as argument. This function
95 creates the Key Exchange Start Paload which includes all our
96 configured security properties. This payload is then sent to the
97 remote end for further processing. This payload must be sent as
98 argument to the function, however, it must not be encoded
99 already, it is done by this function.
101 The packet sending is done by calling a callback function. Caller
102 must provide a routine to send the packet. */
104 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
105 SilcSocketConnection sock,
106 SilcSKEStartPayload *start_payload,
107 SilcSKESendPacketCb send_packet,
110 SilcSKEStatus status = SILC_SKE_STATUS_OK;
111 SilcBuffer payload_buf;
113 SILC_LOG_DEBUG(("Start"));
118 /* Encode the payload */
119 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
120 if (status != SILC_SKE_STATUS_OK)
123 /* Take a copy of the payload buffer for future use. It is used to
124 compute the HASH value. */
125 ske->start_payload_copy = silc_buffer_copy(payload_buf);
127 /* Send the packet. */
129 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
131 silc_buffer_free(payload_buf);
136 /* Function called after ske_initiator_start fuction. This receives
137 the remote ends Key Exchange Start payload which includes the
138 security properties selected by the responder from our payload
139 sent in the silc_ske_initiator_start function. */
141 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
142 SilcBuffer start_payload,
146 SilcSKEStatus status = SILC_SKE_STATUS_OK;
147 SilcSKEStartPayload *payload;
148 SilcSKESecurityProperties prop;
149 SilcSKEDiffieHellmanGroup group;
151 SILC_LOG_DEBUG(("Start"));
153 /* Decode the payload */
154 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
155 if (status != SILC_SKE_STATUS_OK)
158 /* Take the selected security properties into use while doing
159 the key exchange. This is used only while doing the key
160 exchange. The same data is returned to upper levels by calling
161 the callback function. */
162 ske->prop = prop = silc_calloc(1, sizeof(*prop));
163 prop->flags = payload->flags;
164 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
165 if (status != SILC_SKE_STATUS_OK)
170 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
171 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
175 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
176 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
180 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
181 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
185 ske->start_payload = payload;
187 /* Return the received payload by calling the callback function. */
189 (*callback)(ske, context);
195 silc_ske_payload_start_free(payload);
200 silc_pkcs_free(prop->pkcs);
202 silc_cipher_free(prop->cipher);
204 silc_hash_free(prop->hash);
208 if (status == SILC_SKE_STATUS_OK)
209 return SILC_SKE_STATUS_ERROR;
214 /* This function creates random number x, such that 1 < x < q and
215 computes e = g ^ x mod p and sends the result to the remote end in
216 Key Exchange 1 Payload. */
218 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
219 SilcSKESendPacketCb send_packet,
222 SilcSKEStatus status = SILC_SKE_STATUS_OK;
223 SilcBuffer payload_buf;
225 SilcSKEOnePayload *payload;
227 SILC_LOG_DEBUG(("Start"));
229 /* Create the random number x, 1 < x < q. */
232 silc_ske_create_rnd(ske, ske->prop->group->group_order,
233 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
235 if (status != SILC_SKE_STATUS_OK) {
240 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
242 /* Do the Diffie Hellman computation, e = g ^ x mod p */
244 silc_mp_powm(&e, &ske->prop->group->generator, &x,
245 &ske->prop->group->group);
247 /* Encode the result to Key Exchange 1 Payload. */
248 payload = silc_calloc(1, sizeof(*payload));
250 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
251 if (status != SILC_SKE_STATUS_OK) {
258 ske->ke1_payload = payload;
261 /* Send the packet. */
263 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
265 silc_buffer_free(payload_buf);
270 /* Receives Key Exchange 2 Payload from responder consisting responders
271 public key, f, and signature. This function verifies the public key,
272 computes the secret shared key and verifies the signature. */
274 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
275 SilcBuffer ke2_payload,
279 SilcSKEStatus status = SILC_SKE_STATUS_OK;
280 SilcSKETwoPayload *payload;
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 /* Verify the public key */ /* XXX */
303 status = silc_ske_verify_public_key(ske, payload->pk_data,
305 if (status != SILC_SKE_STATUS_OK)
308 SILC_LOG_DEBUG(("Public key is authentic"));
310 /* Compute the hash value */
311 status = silc_ske_make_hash(ske, hash, &hash_len);
312 if (status != SILC_SKE_STATUS_OK)
315 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
316 memcpy(ske->hash, hash, hash_len);
317 ske->hash_len = hash_len;
319 SILC_LOG_DEBUG(("Verifying signature"));
321 /* Verify signature */
322 silc_pkcs_set_public_key(ske->prop->pkcs, payload->pk_data, payload->pk_len);
323 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
324 payload->sign_data, payload->sign_len,
325 hash, hash_len) == FALSE) {
327 SILC_LOG_DEBUG(("Signature don't match"));
329 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
333 SILC_LOG_DEBUG(("Signature is Ok"));
335 memset(hash, 'F', hash_len);
337 /* Call the callback. */
339 (*callback)(ske, context);
344 memset(hash, 'F', hash_len);
345 silc_ske_payload_two_free(payload);
347 silc_mp_clear(&ske->KEY);
350 memset(ske->hash, 'F', hash_len);
351 silc_free(ske->hash);
355 if (status == SILC_SKE_STATUS_OK)
356 return SILC_SKE_STATUS_ERROR;
361 /* Starts Key Exchange protocol for responder. Responder receives
362 Key Exchange Start Payload from initiator consisting of all the
363 security properties the initiator supports. This function decodes
364 the payload and parses the payload further and selects the right
365 security properties. */
367 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
368 SilcSocketConnection sock,
369 SilcBuffer start_payload,
373 SilcSKEStatus status = SILC_SKE_STATUS_OK;
374 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
376 SILC_LOG_DEBUG(("Start"));
381 /* Decode the payload */
382 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
383 if (status != SILC_SKE_STATUS_OK)
386 /* Take a copy of the payload buffer for future use. It is used to
387 compute the HASH value. */
388 ske->start_payload_copy = silc_buffer_copy(start_payload);
390 /* Parse and select the security properties from the payload */
391 payload = silc_calloc(1, sizeof(*payload));
392 status = silc_ske_select_security_properties(ske, payload, remote_payload);
393 if (status != SILC_SKE_STATUS_OK)
396 ske->start_payload = payload;
398 /* Call the callback function. */
400 (*callback)(ske, context);
406 silc_ske_payload_start_free(remote_payload);
410 if (status == SILC_SKE_STATUS_OK)
411 return SILC_SKE_STATUS_ERROR;
416 /* The selected security properties from the initiator payload is now
417 encoded into Key Exchange Start Payload and sent to the initiator. */
419 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
420 SilcSKEStartPayload *start_payload,
421 SilcSKESendPacketCb send_packet,
424 SilcSKEStatus status = SILC_SKE_STATUS_OK;
425 SilcBuffer payload_buf;
426 SilcSKESecurityProperties prop;
427 SilcSKEDiffieHellmanGroup group;
429 SILC_LOG_DEBUG(("Start"));
431 /* Allocate security properties from the payload. These are allocated
432 only for this negotiation and will be free'd after KE is over. */
433 ske->prop = prop = silc_calloc(1, sizeof(*prop));
434 prop->flags = start_payload->flags;
435 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
436 if (status != SILC_SKE_STATUS_OK)
441 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
442 &prop->pkcs) == FALSE) {
443 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
447 if (silc_cipher_alloc(start_payload->enc_alg_list,
448 &prop->cipher) == FALSE) {
449 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
453 if (silc_hash_alloc(start_payload->hash_alg_list,
454 &prop->hash) == FALSE) {
455 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
459 /* Encode the payload */
460 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
461 if (status != SILC_SKE_STATUS_OK)
464 /* Send the packet. */
466 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
468 silc_buffer_free(payload_buf);
476 silc_pkcs_free(prop->pkcs);
478 silc_cipher_free(prop->cipher);
480 silc_hash_free(prop->hash);
484 if (status == SILC_SKE_STATUS_OK)
485 return SILC_SKE_STATUS_ERROR;
490 /* This function receives the Key Exchange 1 Payload from the initiator.
491 After processing the payload this then selects random number x,
492 such that 1 < x < q and computes f = g ^ x mod p. This then puts
493 the result f to a Key Exchange 2 Payload which is later processed
494 in ske_responder_finish function. The callback function should
495 not touch the payload (it should merely call the ske_responder_finish
498 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
499 SilcBuffer ke1_payload,
503 SilcSKEStatus status = SILC_SKE_STATUS_OK;
504 SilcSKEOnePayload *one_payload;
505 SilcSKETwoPayload *two_payload;
508 SILC_LOG_DEBUG(("Start"));
510 /* Decode Key Exchange 1 Payload */
511 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
512 if (status != SILC_SKE_STATUS_OK)
515 /* Create the random number x, 1 < x < q. */
518 silc_ske_create_rnd(ske, ske->prop->group->group_order,
519 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
521 if (status != SILC_SKE_STATUS_OK) {
526 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
528 /* Do the Diffie Hellman computation, f = g ^ x mod p */
530 silc_mp_powm(&f, &ske->prop->group->generator, &x,
531 &ske->prop->group->group);
533 /* Save the results for later processing */
534 two_payload = silc_calloc(1, sizeof(*two_payload));
537 ske->ke1_payload = one_payload;
538 ske->ke2_payload = two_payload;
540 /* Call the callback. */
542 (*callback)(ske, context);
547 /* This function computes the secret shared key KEY = e ^ x mod p, and,
548 a hash value to be signed and sent to the other end. This then
549 encodes Key Exchange 2 Payload and sends it to the other end. */
551 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
555 unsigned int prv_len,
556 SilcSKEPKType pk_type,
557 SilcSKESendPacketCb send_packet,
560 SilcSKEStatus status = SILC_SKE_STATUS_OK;
561 SilcBuffer payload_buf;
563 unsigned char hash[32], sign[256];
564 unsigned int hash_len, sign_len;
566 SILC_LOG_DEBUG(("Start"));
568 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
570 /* Compute the shared secret key */
572 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
573 &ske->prop->group->group);
576 SILC_LOG_DEBUG(("Getting public key"));
578 /* Get the public key */
579 ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
580 memcpy(ske->ke2_payload->pk_data, pk, pk_len);
581 ske->ke2_payload->pk_len = pk_len;
582 ske->ke2_payload->pk_type = pk_type;
584 SILC_LOG_DEBUG(("Computing HASH value"));
586 /* Compute the hash value */
587 memset(hash, 0, sizeof(hash));
588 status = silc_ske_make_hash(ske, hash, &hash_len);
589 if (status != SILC_SKE_STATUS_OK)
592 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
593 memcpy(ske->hash, hash, hash_len);
594 ske->hash_len = hash_len;
596 SILC_LOG_DEBUG(("Signing HASH value"));
598 /* Sign the hash value */
599 silc_pkcs_set_private_key(ske->prop->pkcs, prv, prv_len);
600 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
603 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
604 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
605 memset(sign, 0, sizeof(sign));
606 ske->ke2_payload->sign_len = sign_len;
608 /* Encode the Key Exchange 2 Payload */
609 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
611 if (status != SILC_SKE_STATUS_OK)
614 /* Send the packet. */
616 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
618 silc_buffer_free(payload_buf);
623 silc_mp_clear(&ske->KEY);
624 silc_ske_payload_two_free(ske->ke2_payload);
626 if (status == SILC_SKE_STATUS_OK)
627 return SILC_SKE_STATUS_ERROR;
632 /* The Key Exchange protocol is ended by calling this function. This
633 must not be called until the keys are processed like the protocol
634 defines. This function is for both initiator and responder. */
636 SilcSKEStatus silc_ske_end(SilcSKE ske,
637 SilcSKESendPacketCb send_packet,
640 SilcSKEStatus status = SILC_SKE_STATUS_OK;
643 SILC_LOG_DEBUG(("Start"));
645 packet = silc_buffer_alloc(1);
649 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
654 /* Aborts the Key Exchange protocol. This is called if error occurs
655 while performing the protocol. The status argument is the error
656 status and it is sent to the remote end. */
658 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
659 SilcSKESendPacketCb send_packet,
664 SILC_LOG_DEBUG(("Start"));
666 packet = silc_buffer_alloc(4);
667 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
668 silc_buffer_format(packet,
669 SILC_STR_UI_SHORT(status),
673 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
675 silc_buffer_free(packet);
677 return SILC_SKE_STATUS_OK;
680 /* Assembles security properties to Key Exchange Start Payload to be
681 sent to the remote end. This checks system wide (SILC system, that is)
682 settings and chooses from those. However, if other properties
683 should be used this function is easy to replace by another function,
684 as, this function is called by the caller of the protocol and not
685 by the protocol itself. */
688 silc_ske_assemble_security_properties(SilcSKE ske,
689 SilcSKEStartPayload **return_payload)
691 SilcSKEStartPayload *rp;
693 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
695 rp = silc_calloc(1, sizeof(*rp));
703 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
704 rp->cookie_len = SILC_SKE_COOKIE_LEN;
705 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
707 /* Get supported Key Exhange groups */
708 rp->ke_grp_list = silc_ske_get_supported_groups();
709 rp->ke_grp_len = strlen(rp->ke_grp_list);
711 /* Get supported PKCS algorithms */
712 rp->pkcs_alg_list = silc_pkcs_get_supported();
713 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
715 /* Get supported encryption algorithms */
716 rp->enc_alg_list = silc_cipher_get_supported();
717 rp->enc_alg_len = strlen(rp->enc_alg_list);
719 /* Get supported hash algorithms */
720 rp->hash_alg_list = silc_hash_get_supported();
721 rp->hash_alg_len = strlen(rp->hash_alg_list);
724 /* Get supported compression algorithms */
725 rp->comp_alg_list = "";
726 rp->comp_alg_len = 0;
728 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
729 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
730 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
731 2 + rp->comp_alg_len;
733 *return_payload = rp;
735 return SILC_SKE_STATUS_OK;
738 /* Selects the supported security properties from the remote end's Key
739 Exchange Start Payload. */
742 silc_ske_select_security_properties(SilcSKE ske,
743 SilcSKEStartPayload *payload,
744 SilcSKEStartPayload *remote_payload)
746 SilcSKEStartPayload *rp;
750 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
754 /* Flags are returned unchanged. */
755 payload->flags = rp->flags;
757 /* XXX Cookie check?? */
758 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
759 payload->cookie_len = SILC_SKE_COOKIE_LEN;
760 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
762 /* Get supported Key Exchange groups */
763 cp = rp->ke_grp_list;
764 if (cp && strchr(cp, ',')) {
768 len = strcspn(cp, ",");
769 item = silc_calloc(len + 1, sizeof(char));
770 memcpy(item, cp, len);
772 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
774 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
775 SILC_LOG_DEBUG(("Found KE group `%s'", item));
777 payload->ke_grp_len = len;
778 payload->ke_grp_list = item;
792 if (!payload->ke_grp_len && !payload->ke_grp_list) {
793 SILC_LOG_DEBUG(("Could not find supported KE group"));
795 return SILC_SKE_STATUS_UNKNOWN_GROUP;
799 if (!rp->ke_grp_len) {
800 SILC_LOG_DEBUG(("KE group not defined in payload"));
802 return SILC_SKE_STATUS_BAD_PAYLOAD;
805 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
806 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
808 payload->ke_grp_len = rp->ke_grp_len;
809 payload->ke_grp_list = strdup(rp->ke_grp_list);
812 /* Get supported PKCS algorithms */
813 cp = rp->pkcs_alg_list;
814 if (cp && strchr(cp, ',')) {
818 len = strcspn(cp, ",");
819 item = silc_calloc(len + 1, sizeof(char));
820 memcpy(item, cp, len);
822 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
824 if (silc_pkcs_is_supported(item) == TRUE) {
825 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
827 payload->pkcs_alg_len = len;
828 payload->pkcs_alg_list = item;
842 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
843 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
844 silc_free(payload->ke_grp_list);
846 return SILC_SKE_STATUS_UNKNOWN_PKCS;
850 if (!rp->pkcs_alg_len) {
851 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
852 silc_free(payload->ke_grp_list);
854 return SILC_SKE_STATUS_BAD_PAYLOAD;
857 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
858 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
860 payload->pkcs_alg_len = rp->pkcs_alg_len;
861 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
864 /* Get supported encryption algorithms */
865 cp = rp->enc_alg_list;
866 if (cp && strchr(cp, ',')) {
870 len = strcspn(cp, ",");
871 item = silc_calloc(len + 1, sizeof(char));
872 memcpy(item, cp, len);
874 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
876 if (silc_cipher_is_supported(item) == TRUE) {
877 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
879 payload->enc_alg_len = len;
880 payload->enc_alg_list = item;
894 if (!payload->enc_alg_len && !payload->enc_alg_list) {
895 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
896 silc_free(payload->ke_grp_list);
897 silc_free(payload->pkcs_alg_list);
899 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
903 if (!rp->enc_alg_len) {
904 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
905 silc_free(payload->ke_grp_list);
906 silc_free(payload->pkcs_alg_list);
908 return SILC_SKE_STATUS_BAD_PAYLOAD;
911 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
914 payload->enc_alg_len = rp->enc_alg_len;
915 payload->enc_alg_list = strdup(rp->enc_alg_list);
918 /* Get supported hash algorithms */
919 cp = rp->hash_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 hash alg `%s'", item));
930 if (silc_hash_is_supported(item) == TRUE) {
931 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
933 payload->hash_alg_len = len;
934 payload->hash_alg_list = item;
948 if (!payload->hash_alg_len && !payload->hash_alg_list) {
949 SILC_LOG_DEBUG(("Could not find supported hash alg"));
950 silc_free(payload->ke_grp_list);
951 silc_free(payload->pkcs_alg_list);
952 silc_free(payload->enc_alg_list);
954 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
958 if (!rp->hash_alg_len) {
959 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
960 silc_free(payload->ke_grp_list);
961 silc_free(payload->pkcs_alg_list);
962 silc_free(payload->enc_alg_list);
964 return SILC_SKE_STATUS_BAD_PAYLOAD;
967 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
970 payload->hash_alg_len = rp->hash_alg_len;
971 payload->hash_alg_list = strdup(rp->hash_alg_list);
975 /* Get supported compression algorithms */
976 cp = rp->hash_alg_list;
977 if (cp && strchr(cp, ',')) {
981 len = strcspn(cp, ",");
982 item = silc_calloc(len + 1, sizeof(char));
983 memcpy(item, cp, len);
985 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
987 if (silc_hash_is_supported(item) == TRUE) {
988 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
990 payload->hash_alg_len = len;
991 payload->hash_alg_list = item;
1005 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1006 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1007 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1008 silc_free(payload->ke_grp_list);
1009 silc_free(payload->pkcs_alg_list);
1010 silc_free(payload->enc_alg_list);
1019 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1020 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1021 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1022 2 + payload->comp_alg_len;
1024 return SILC_SKE_STATUS_OK;
1027 /* Creates random number such that 1 < rnd < n and at most length
1028 of len bits. The rnd sent as argument must be initialized. */
1030 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1034 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1035 unsigned char *string;
1037 SILC_LOG_DEBUG(("Creating random number"));
1039 /* Get the random number as string */
1040 string = silc_rng_get_rn_string(ske->rng, (len / 8));
1042 /* Decode the string into a MP integer */
1043 silc_mp_set_str(rnd, string, 16);
1044 silc_mp_mod_2exp(rnd, rnd, len);
1047 if (silc_mp_cmp_ui(rnd, 1) < 0)
1048 status = SILC_SKE_STATUS_ERROR;
1050 if (silc_mp_cmp(rnd, &n) >= 0)
1051 status = SILC_SKE_STATUS_ERROR;
1053 memset(string, 'F', (len / 8));
1061 SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske,
1062 unsigned char *pubkey,
1063 unsigned int pubkey_len)
1065 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1070 /* Creates a hash value HASH as defined in the SKE protocol. */
1072 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1073 unsigned char *return_hash,
1074 unsigned int *return_hash_len)
1076 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1078 unsigned char *e, *f, *KEY;
1079 unsigned int e_len, f_len, KEY_len;
1081 SILC_LOG_DEBUG(("Start"));
1083 e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
1084 e = silc_calloc(e_len + 1, sizeof(unsigned char));
1085 silc_mp_get_str(e, 16, &ske->ke1_payload->e);
1087 f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
1088 f = silc_calloc(f_len + 1, sizeof(unsigned char));
1089 silc_mp_get_str(f, 16, &ske->ke2_payload->f);
1091 KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
1092 KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
1093 silc_mp_get_str(KEY, 16, &ske->KEY);
1095 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1096 ske->pk_len + e_len + f_len + KEY_len);
1097 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1099 /* Format the buffer used to compute the hash value */
1100 silc_buffer_format(buf,
1101 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1102 ske->start_payload_copy->len),
1103 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1104 SILC_STR_UI_XNSTRING(e, e_len),
1105 SILC_STR_UI_XNSTRING(f, f_len),
1106 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1110 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1114 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1115 *return_hash_len = ske->prop->hash->hash->hash_len;
1117 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1119 silc_buffer_free(buf);
1120 memset(e, 0, e_len);
1121 memset(f, 0, f_len);
1122 memset(KEY, 0, KEY_len);
1130 /* Processes negotiated key material as protocol specifies. This returns
1131 the actual keys to be used in the SILC. */
1133 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1134 unsigned int req_iv_len,
1135 unsigned int req_enc_key_len,
1136 unsigned int req_hmac_key_len,
1137 SilcSKEKeyMaterial *key)
1142 unsigned char *tmpbuf;
1143 unsigned char hash[32];
1144 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1145 unsigned int enc_key_len = req_enc_key_len / 8;
1147 SILC_LOG_DEBUG(("Start"));
1149 silc_mp_init_set(&tmp, &ske->KEY);
1151 klen = silc_mp_size(&tmp);
1153 /* Format the KEY material into binary data */
1154 tmpbuf = silc_calloc(klen, sizeof(unsigned char));
1155 for (i = klen; i > 0; i--) {
1156 tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
1157 silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
1160 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;