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.3 2000/07/06 07:12:39 priikone
24 * Support for SILC style public keys added.
26 * Revision 1.2 2000/07/05 06:05:15 priikone
27 * Global cosmetic change.
29 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
30 * Imported from internal CVS/Added Log headers.
35 #include "silcincludes.h"
36 #include "payload_internal.h"
37 #include "groups_internal.h"
39 /* Allocates new SKE object. */
41 SilcSKE silc_ske_alloc()
45 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
47 ske = silc_calloc(1, sizeof(*ske));
52 /* Free's SKE object. */
54 void silc_ske_free(SilcSKE ske)
56 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
59 /* Free start payload */
60 if (ske->start_payload)
61 silc_ske_payload_start_free(ske->start_payload);
63 /* Free KE1 payload */
65 silc_ske_payload_one_free(ske->ke1_payload);
67 /* Free KE2 payload */
69 silc_ske_payload_two_free(ske->ke2_payload);
74 silc_free(ske->prop->group);
76 silc_pkcs_free(ske->prop->pkcs);
77 if (ske->prop->cipher)
78 silc_cipher_free(ske->prop->cipher);
80 silc_hash_free(ske->prop->hash);
83 if (ske->start_payload_copy)
84 silc_buffer_free(ske->start_payload_copy);
87 silc_mp_clear(&ske->x);
88 silc_mp_clear(&ske->KEY);
95 /* Starts the SILC Key Exchange protocol for initiator. The connection
96 to the remote end must be established before calling this function
97 and the connecting socket must be sent as argument. This function
98 creates the Key Exchange Start Paload which includes all our
99 configured security properties. This payload is then sent to the
100 remote end for further processing. This payload must be sent as
101 argument to the function, however, it must not be encoded
102 already, it is done by this function.
104 The packet sending is done by calling a callback function. Caller
105 must provide a routine to send the packet. */
107 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
108 SilcSocketConnection sock,
109 SilcSKEStartPayload *start_payload,
110 SilcSKESendPacketCb send_packet,
113 SilcSKEStatus status = SILC_SKE_STATUS_OK;
114 SilcBuffer payload_buf;
116 SILC_LOG_DEBUG(("Start"));
121 /* Encode the payload */
122 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
123 if (status != SILC_SKE_STATUS_OK)
126 /* Take a copy of the payload buffer for future use. It is used to
127 compute the HASH value. */
128 ske->start_payload_copy = silc_buffer_copy(payload_buf);
130 /* Send the packet. */
132 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
134 silc_buffer_free(payload_buf);
139 /* Function called after ske_initiator_start fuction. This receives
140 the remote ends Key Exchange Start payload which includes the
141 security properties selected by the responder from our payload
142 sent in the silc_ske_initiator_start function. */
144 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
145 SilcBuffer start_payload,
149 SilcSKEStatus status = SILC_SKE_STATUS_OK;
150 SilcSKEStartPayload *payload;
151 SilcSKESecurityProperties prop;
152 SilcSKEDiffieHellmanGroup group;
154 SILC_LOG_DEBUG(("Start"));
156 /* Decode the payload */
157 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
158 if (status != SILC_SKE_STATUS_OK)
161 /* Take the selected security properties into use while doing
162 the key exchange. This is used only while doing the key
163 exchange. The same data is returned to upper levels by calling
164 the callback function. */
165 ske->prop = prop = silc_calloc(1, sizeof(*prop));
166 prop->flags = payload->flags;
167 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
168 if (status != SILC_SKE_STATUS_OK)
173 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
174 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
178 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
179 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
183 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
184 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
188 ske->start_payload = payload;
190 /* Return the received payload by calling the callback function. */
192 (*callback)(ske, context);
198 silc_ske_payload_start_free(payload);
203 silc_pkcs_free(prop->pkcs);
205 silc_cipher_free(prop->cipher);
207 silc_hash_free(prop->hash);
211 if (status == SILC_SKE_STATUS_OK)
212 return SILC_SKE_STATUS_ERROR;
217 /* This function creates random number x, such that 1 < x < q and
218 computes e = g ^ x mod p and sends the result to the remote end in
219 Key Exchange 1 Payload. */
221 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
222 SilcSKESendPacketCb send_packet,
225 SilcSKEStatus status = SILC_SKE_STATUS_OK;
226 SilcBuffer payload_buf;
228 SilcSKEOnePayload *payload;
230 SILC_LOG_DEBUG(("Start"));
232 /* Create the random number x, 1 < x < q. */
235 silc_ske_create_rnd(ske, ske->prop->group->group_order,
236 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
238 if (status != SILC_SKE_STATUS_OK) {
243 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
245 /* Do the Diffie Hellman computation, e = g ^ x mod p */
247 silc_mp_powm(&e, &ske->prop->group->generator, &x,
248 &ske->prop->group->group);
250 /* Encode the result to Key Exchange 1 Payload. */
251 payload = silc_calloc(1, sizeof(*payload));
253 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
254 if (status != SILC_SKE_STATUS_OK) {
261 ske->ke1_payload = payload;
264 /* Send the packet. */
266 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
268 silc_buffer_free(payload_buf);
273 /* Receives Key Exchange 2 Payload from responder consisting responders
274 public key, f, and signature. This function verifies the public key,
275 computes the secret shared key and verifies the signature. */
277 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
278 SilcBuffer ke2_payload,
282 SilcSKEStatus status = SILC_SKE_STATUS_OK;
283 SilcSKETwoPayload *payload;
285 unsigned char hash[32];
286 unsigned int hash_len;
288 SILC_LOG_DEBUG(("Start"));
290 /* Decode the payload */
291 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
292 if (status != SILC_SKE_STATUS_OK)
294 ske->ke2_payload = payload;
296 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
298 /* Compute the shared secret key */
300 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
303 SILC_LOG_DEBUG(("Verifying public key"));
305 /* Verify the public key */ /* XXX */
306 status = silc_ske_verify_public_key(ske, payload->pk_data,
308 if (status != SILC_SKE_STATUS_OK)
311 SILC_LOG_DEBUG(("Public key is authentic"));
313 /* Compute the hash value */
314 status = silc_ske_make_hash(ske, hash, &hash_len);
315 if (status != SILC_SKE_STATUS_OK)
318 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
319 memcpy(ske->hash, hash, hash_len);
320 ske->hash_len = hash_len;
322 SILC_LOG_DEBUG(("Verifying signature"));
324 /* Verify signature */
325 silc_pkcs_public_key_data_set(ske->prop->pkcs, payload->pk_data,
327 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
328 payload->sign_data, payload->sign_len,
329 hash, hash_len) == FALSE) {
331 SILC_LOG_DEBUG(("Signature don't match"));
333 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
337 SILC_LOG_DEBUG(("Signature is Ok"));
339 memset(hash, 'F', hash_len);
341 /* Call the callback. */
343 (*callback)(ske, context);
348 memset(hash, 'F', hash_len);
349 silc_ske_payload_two_free(payload);
351 silc_mp_clear(&ske->KEY);
354 memset(ske->hash, 'F', hash_len);
355 silc_free(ske->hash);
359 if (status == SILC_SKE_STATUS_OK)
360 return SILC_SKE_STATUS_ERROR;
365 /* Starts Key Exchange protocol for responder. Responder receives
366 Key Exchange Start Payload from initiator consisting of all the
367 security properties the initiator supports. This function decodes
368 the payload and parses the payload further and selects the right
369 security properties. */
371 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
372 SilcSocketConnection sock,
373 SilcBuffer start_payload,
377 SilcSKEStatus status = SILC_SKE_STATUS_OK;
378 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
380 SILC_LOG_DEBUG(("Start"));
385 /* Decode the payload */
386 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
387 if (status != SILC_SKE_STATUS_OK)
390 /* Take a copy of the payload buffer for future use. It is used to
391 compute the HASH value. */
392 ske->start_payload_copy = silc_buffer_copy(start_payload);
394 /* Parse and select the security properties from the payload */
395 payload = silc_calloc(1, sizeof(*payload));
396 status = silc_ske_select_security_properties(ske, payload, remote_payload);
397 if (status != SILC_SKE_STATUS_OK)
400 ske->start_payload = payload;
402 /* Call the callback function. */
404 (*callback)(ske, context);
410 silc_ske_payload_start_free(remote_payload);
414 if (status == SILC_SKE_STATUS_OK)
415 return SILC_SKE_STATUS_ERROR;
420 /* The selected security properties from the initiator payload is now
421 encoded into Key Exchange Start Payload and sent to the initiator. */
423 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
424 SilcSKEStartPayload *start_payload,
425 SilcSKESendPacketCb send_packet,
428 SilcSKEStatus status = SILC_SKE_STATUS_OK;
429 SilcBuffer payload_buf;
430 SilcSKESecurityProperties prop;
431 SilcSKEDiffieHellmanGroup group;
433 SILC_LOG_DEBUG(("Start"));
435 /* Allocate security properties from the payload. These are allocated
436 only for this negotiation and will be free'd after KE is over. */
437 ske->prop = prop = silc_calloc(1, sizeof(*prop));
438 prop->flags = start_payload->flags;
439 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
440 if (status != SILC_SKE_STATUS_OK)
445 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
446 &prop->pkcs) == FALSE) {
447 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
451 if (silc_cipher_alloc(start_payload->enc_alg_list,
452 &prop->cipher) == FALSE) {
453 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
457 if (silc_hash_alloc(start_payload->hash_alg_list,
458 &prop->hash) == FALSE) {
459 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
463 /* Encode the payload */
464 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
465 if (status != SILC_SKE_STATUS_OK)
468 /* Send the packet. */
470 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
472 silc_buffer_free(payload_buf);
480 silc_pkcs_free(prop->pkcs);
482 silc_cipher_free(prop->cipher);
484 silc_hash_free(prop->hash);
488 if (status == SILC_SKE_STATUS_OK)
489 return SILC_SKE_STATUS_ERROR;
494 /* This function receives the Key Exchange 1 Payload from the initiator.
495 After processing the payload this then selects random number x,
496 such that 1 < x < q and computes f = g ^ x mod p. This then puts
497 the result f to a Key Exchange 2 Payload which is later processed
498 in ske_responder_finish function. The callback function should
499 not touch the payload (it should merely call the ske_responder_finish
502 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
503 SilcBuffer ke1_payload,
507 SilcSKEStatus status = SILC_SKE_STATUS_OK;
508 SilcSKEOnePayload *one_payload;
509 SilcSKETwoPayload *two_payload;
512 SILC_LOG_DEBUG(("Start"));
514 /* Decode Key Exchange 1 Payload */
515 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
516 if (status != SILC_SKE_STATUS_OK)
519 /* Create the random number x, 1 < x < q. */
522 silc_ske_create_rnd(ske, ske->prop->group->group_order,
523 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
525 if (status != SILC_SKE_STATUS_OK) {
530 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
532 /* Do the Diffie Hellman computation, f = g ^ x mod p */
534 silc_mp_powm(&f, &ske->prop->group->generator, &x,
535 &ske->prop->group->group);
537 /* Save the results for later processing */
538 two_payload = silc_calloc(1, sizeof(*two_payload));
541 ske->ke1_payload = one_payload;
542 ske->ke2_payload = two_payload;
544 /* Call the callback. */
546 (*callback)(ske, context);
551 /* This function computes the secret shared key KEY = e ^ x mod p, and,
552 a hash value to be signed and sent to the other end. This then
553 encodes Key Exchange 2 Payload and sends it to the other end. */
555 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
559 unsigned int prv_len,
560 SilcSKEPKType pk_type,
561 SilcSKESendPacketCb send_packet,
564 SilcSKEStatus status = SILC_SKE_STATUS_OK;
565 SilcBuffer payload_buf;
567 unsigned char hash[32], sign[256];
568 unsigned int hash_len, sign_len;
570 SILC_LOG_DEBUG(("Start"));
572 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
574 /* Compute the shared secret key */
576 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
577 &ske->prop->group->group);
580 SILC_LOG_DEBUG(("Getting public key"));
582 /* Get the public key */
583 ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
584 memcpy(ske->ke2_payload->pk_data, pk, pk_len);
585 ske->ke2_payload->pk_len = pk_len;
586 ske->ke2_payload->pk_type = pk_type;
588 SILC_LOG_DEBUG(("Computing HASH value"));
590 /* Compute the hash value */
591 memset(hash, 0, sizeof(hash));
592 status = silc_ske_make_hash(ske, hash, &hash_len);
593 if (status != SILC_SKE_STATUS_OK)
596 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
597 memcpy(ske->hash, hash, hash_len);
598 ske->hash_len = hash_len;
600 SILC_LOG_DEBUG(("Signing HASH value"));
602 /* Sign the hash value */
603 silc_pkcs_private_key_data_set(ske->prop->pkcs, prv, prv_len);
604 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
607 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
608 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
609 memset(sign, 0, sizeof(sign));
610 ske->ke2_payload->sign_len = sign_len;
612 /* Encode the Key Exchange 2 Payload */
613 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
615 if (status != SILC_SKE_STATUS_OK)
618 /* Send the packet. */
620 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
622 silc_buffer_free(payload_buf);
627 silc_mp_clear(&ske->KEY);
628 silc_ske_payload_two_free(ske->ke2_payload);
630 if (status == SILC_SKE_STATUS_OK)
631 return SILC_SKE_STATUS_ERROR;
636 /* The Key Exchange protocol is ended by calling this function. This
637 must not be called until the keys are processed like the protocol
638 defines. This function is for both initiator and responder. */
640 SilcSKEStatus silc_ske_end(SilcSKE ske,
641 SilcSKESendPacketCb send_packet,
644 SilcSKEStatus status = SILC_SKE_STATUS_OK;
647 SILC_LOG_DEBUG(("Start"));
649 packet = silc_buffer_alloc(1);
653 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
658 /* Aborts the Key Exchange protocol. This is called if error occurs
659 while performing the protocol. The status argument is the error
660 status and it is sent to the remote end. */
662 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
663 SilcSKESendPacketCb send_packet,
668 SILC_LOG_DEBUG(("Start"));
670 packet = silc_buffer_alloc(4);
671 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
672 silc_buffer_format(packet,
673 SILC_STR_UI_SHORT(status),
677 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
679 silc_buffer_free(packet);
681 return SILC_SKE_STATUS_OK;
684 /* Assembles security properties to Key Exchange Start Payload to be
685 sent to the remote end. This checks system wide (SILC system, that is)
686 settings and chooses from those. However, if other properties
687 should be used this function is easy to replace by another function,
688 as, this function is called by the caller of the protocol and not
689 by the protocol itself. */
692 silc_ske_assemble_security_properties(SilcSKE ske,
693 SilcSKEStartPayload **return_payload)
695 SilcSKEStartPayload *rp;
697 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
699 rp = silc_calloc(1, sizeof(*rp));
707 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
708 rp->cookie_len = SILC_SKE_COOKIE_LEN;
709 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
711 /* Get supported Key Exhange groups */
712 rp->ke_grp_list = silc_ske_get_supported_groups();
713 rp->ke_grp_len = strlen(rp->ke_grp_list);
715 /* Get supported PKCS algorithms */
716 rp->pkcs_alg_list = silc_pkcs_get_supported();
717 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
719 /* Get supported encryption algorithms */
720 rp->enc_alg_list = silc_cipher_get_supported();
721 rp->enc_alg_len = strlen(rp->enc_alg_list);
723 /* Get supported hash algorithms */
724 rp->hash_alg_list = silc_hash_get_supported();
725 rp->hash_alg_len = strlen(rp->hash_alg_list);
728 /* Get supported compression algorithms */
729 rp->comp_alg_list = "";
730 rp->comp_alg_len = 0;
732 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
733 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
734 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
735 2 + rp->comp_alg_len;
737 *return_payload = rp;
739 return SILC_SKE_STATUS_OK;
742 /* Selects the supported security properties from the remote end's Key
743 Exchange Start Payload. */
746 silc_ske_select_security_properties(SilcSKE ske,
747 SilcSKEStartPayload *payload,
748 SilcSKEStartPayload *remote_payload)
750 SilcSKEStartPayload *rp;
754 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
758 /* Flags are returned unchanged. */
759 payload->flags = rp->flags;
761 /* XXX Cookie check?? */
762 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
763 payload->cookie_len = SILC_SKE_COOKIE_LEN;
764 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
766 /* Get supported Key Exchange groups */
767 cp = rp->ke_grp_list;
768 if (cp && strchr(cp, ',')) {
772 len = strcspn(cp, ",");
773 item = silc_calloc(len + 1, sizeof(char));
774 memcpy(item, cp, len);
776 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
778 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
779 SILC_LOG_DEBUG(("Found KE group `%s'", item));
781 payload->ke_grp_len = len;
782 payload->ke_grp_list = item;
796 if (!payload->ke_grp_len && !payload->ke_grp_list) {
797 SILC_LOG_DEBUG(("Could not find supported KE group"));
799 return SILC_SKE_STATUS_UNKNOWN_GROUP;
803 if (!rp->ke_grp_len) {
804 SILC_LOG_DEBUG(("KE group not defined in payload"));
806 return SILC_SKE_STATUS_BAD_PAYLOAD;
809 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
810 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
812 payload->ke_grp_len = rp->ke_grp_len;
813 payload->ke_grp_list = strdup(rp->ke_grp_list);
816 /* Get supported PKCS algorithms */
817 cp = rp->pkcs_alg_list;
818 if (cp && strchr(cp, ',')) {
822 len = strcspn(cp, ",");
823 item = silc_calloc(len + 1, sizeof(char));
824 memcpy(item, cp, len);
826 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
828 if (silc_pkcs_is_supported(item) == TRUE) {
829 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
831 payload->pkcs_alg_len = len;
832 payload->pkcs_alg_list = item;
846 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
847 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
848 silc_free(payload->ke_grp_list);
850 return SILC_SKE_STATUS_UNKNOWN_PKCS;
854 if (!rp->pkcs_alg_len) {
855 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
856 silc_free(payload->ke_grp_list);
858 return SILC_SKE_STATUS_BAD_PAYLOAD;
861 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
862 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
864 payload->pkcs_alg_len = rp->pkcs_alg_len;
865 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
868 /* Get supported encryption algorithms */
869 cp = rp->enc_alg_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 encryption alg `%s'", item));
880 if (silc_cipher_is_supported(item) == TRUE) {
881 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
883 payload->enc_alg_len = len;
884 payload->enc_alg_list = item;
898 if (!payload->enc_alg_len && !payload->enc_alg_list) {
899 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
900 silc_free(payload->ke_grp_list);
901 silc_free(payload->pkcs_alg_list);
903 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
907 if (!rp->enc_alg_len) {
908 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
909 silc_free(payload->ke_grp_list);
910 silc_free(payload->pkcs_alg_list);
912 return SILC_SKE_STATUS_BAD_PAYLOAD;
915 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
918 payload->enc_alg_len = rp->enc_alg_len;
919 payload->enc_alg_list = strdup(rp->enc_alg_list);
922 /* Get supported hash algorithms */
923 cp = rp->hash_alg_list;
924 if (cp && strchr(cp, ',')) {
928 len = strcspn(cp, ",");
929 item = silc_calloc(len + 1, sizeof(char));
930 memcpy(item, cp, len);
932 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
934 if (silc_hash_is_supported(item) == TRUE) {
935 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
937 payload->hash_alg_len = len;
938 payload->hash_alg_list = item;
952 if (!payload->hash_alg_len && !payload->hash_alg_list) {
953 SILC_LOG_DEBUG(("Could not find supported hash alg"));
954 silc_free(payload->ke_grp_list);
955 silc_free(payload->pkcs_alg_list);
956 silc_free(payload->enc_alg_list);
958 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
962 if (!rp->hash_alg_len) {
963 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
964 silc_free(payload->ke_grp_list);
965 silc_free(payload->pkcs_alg_list);
966 silc_free(payload->enc_alg_list);
968 return SILC_SKE_STATUS_BAD_PAYLOAD;
971 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
974 payload->hash_alg_len = rp->hash_alg_len;
975 payload->hash_alg_list = strdup(rp->hash_alg_list);
979 /* Get supported compression algorithms */
980 cp = rp->hash_alg_list;
981 if (cp && strchr(cp, ',')) {
985 len = strcspn(cp, ",");
986 item = silc_calloc(len + 1, sizeof(char));
987 memcpy(item, cp, len);
989 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
991 if (silc_hash_is_supported(item) == TRUE) {
992 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
994 payload->hash_alg_len = len;
995 payload->hash_alg_list = item;
1000 if (strlen(cp) == 0)
1009 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1010 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1011 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1012 silc_free(payload->ke_grp_list);
1013 silc_free(payload->pkcs_alg_list);
1014 silc_free(payload->enc_alg_list);
1023 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1024 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1025 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1026 2 + payload->comp_alg_len;
1028 return SILC_SKE_STATUS_OK;
1031 /* Creates random number such that 1 < rnd < n and at most length
1032 of len bits. The rnd sent as argument must be initialized. */
1034 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1038 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1039 unsigned char *string;
1041 SILC_LOG_DEBUG(("Creating random number"));
1043 /* Get the random number as string */
1044 string = silc_rng_get_rn_string(ske->rng, (len / 8));
1046 /* Decode the string into a MP integer */
1047 silc_mp_set_str(rnd, string, 16);
1048 silc_mp_mod_2exp(rnd, rnd, len);
1051 if (silc_mp_cmp_ui(rnd, 1) < 0)
1052 status = SILC_SKE_STATUS_ERROR;
1054 if (silc_mp_cmp(rnd, &n) >= 0)
1055 status = SILC_SKE_STATUS_ERROR;
1057 memset(string, 'F', (len / 8));
1065 SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske,
1066 unsigned char *pubkey,
1067 unsigned int pubkey_len)
1069 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1074 /* Creates a hash value HASH as defined in the SKE protocol. */
1076 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1077 unsigned char *return_hash,
1078 unsigned int *return_hash_len)
1080 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1082 unsigned char *e, *f, *KEY;
1083 unsigned int e_len, f_len, KEY_len;
1085 SILC_LOG_DEBUG(("Start"));
1087 e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
1088 e = silc_calloc(e_len + 1, sizeof(unsigned char));
1089 silc_mp_get_str(e, 16, &ske->ke1_payload->e);
1091 f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
1092 f = silc_calloc(f_len + 1, sizeof(unsigned char));
1093 silc_mp_get_str(f, 16, &ske->ke2_payload->f);
1095 KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
1096 KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
1097 silc_mp_get_str(KEY, 16, &ske->KEY);
1099 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1100 ske->pk_len + e_len + f_len + KEY_len);
1101 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1103 /* Format the buffer used to compute the hash value */
1104 silc_buffer_format(buf,
1105 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1106 ske->start_payload_copy->len),
1107 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1108 SILC_STR_UI_XNSTRING(e, e_len),
1109 SILC_STR_UI_XNSTRING(f, f_len),
1110 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1114 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1118 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1119 *return_hash_len = ske->prop->hash->hash->hash_len;
1121 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1123 silc_buffer_free(buf);
1124 memset(e, 0, e_len);
1125 memset(f, 0, f_len);
1126 memset(KEY, 0, KEY_len);
1134 /* Processes negotiated key material as protocol specifies. This returns
1135 the actual keys to be used in the SILC. */
1137 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1138 unsigned int req_iv_len,
1139 unsigned int req_enc_key_len,
1140 unsigned int req_hmac_key_len,
1141 SilcSKEKeyMaterial *key)
1146 unsigned char *tmpbuf;
1147 unsigned char hash[32];
1148 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1149 unsigned int enc_key_len = req_enc_key_len / 8;
1151 SILC_LOG_DEBUG(("Start"));
1153 silc_mp_init_set(&tmp, &ske->KEY);
1155 klen = silc_mp_size(&tmp);
1157 /* Format the KEY material into binary data */
1158 tmpbuf = silc_calloc(klen, sizeof(unsigned char));
1159 for (i = klen; i > 0; i--) {
1160 tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
1161 silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
1164 buf = silc_buffer_alloc(1 + klen + hash_len);
1166 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1167 silc_buffer_format(buf,
1168 SILC_STR_UI_CHAR(0),
1169 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1170 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1174 memset(hash, 0, sizeof(hash));
1176 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1177 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1178 memcpy(key->send_iv, hash, req_iv_len);
1179 memset(hash, 0, sizeof(hash));
1181 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1182 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1183 memcpy(key->receive_iv, hash, req_iv_len);
1184 key->iv_len = req_iv_len;
1186 /* Take the encryption keys. If requested key size is more than
1187 the size of hash length we will distribute more key material
1188 as protocol defines. */
1190 if (enc_key_len > hash_len) {
1192 unsigned char k1[32], k2[32], k3[32];
1193 unsigned char *dtmp;
1196 if (enc_key_len > (3 * hash_len))
1197 return SILC_SKE_STATUS_ERROR;
1199 memset(k1, 0, sizeof(k1));
1200 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1203 dist = silc_buffer_alloc(hash_len * 3);
1205 silc_buffer_pull_tail(dist, klen + hash_len);
1206 silc_buffer_format(dist,
1207 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1208 SILC_STR_UI_XNSTRING(k1, hash_len),
1211 memset(k2, 0, sizeof(k2));
1212 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1214 silc_buffer_pull(dist, klen + hash_len);
1215 silc_buffer_format(dist,
1216 SILC_STR_UI_XNSTRING(k2, hash_len),
1218 silc_buffer_push(dist, klen + hash_len);
1220 memset(k3, 0, sizeof(k3));
1221 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1223 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1224 memcpy(dtmp, k1, hash_len);
1225 memcpy(dtmp + hash_len, k2, hash_len);
1226 memcpy(dtmp + hash_len, k3, hash_len);
1228 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1229 memcpy(key->send_enc_key, dtmp, enc_key_len);
1230 key->enc_key_len = req_enc_key_len;
1232 memset(dtmp, 0, (3 * hash_len));
1233 memset(k1, 0, sizeof(k1));
1234 memset(k2, 0, sizeof(k2));
1235 memset(k3, 0, sizeof(k3));
1237 silc_buffer_free(dist);
1239 /* Take normal hash as key */
1240 memset(hash, 0, sizeof(hash));
1241 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1242 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1243 memcpy(key->send_enc_key, hash, enc_key_len);
1244 key->enc_key_len = req_enc_key_len;
1248 if (enc_key_len > hash_len) {
1250 unsigned char k1[32], k2[32], k3[32];
1251 unsigned char *dtmp;
1254 if (enc_key_len > (3 * hash_len))
1255 return SILC_SKE_STATUS_ERROR;
1257 memset(k1, 0, sizeof(k1));
1258 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1261 dist = silc_buffer_alloc(hash_len * 3);
1263 silc_buffer_pull_tail(dist, klen + hash_len);
1264 silc_buffer_format(dist,
1265 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1266 SILC_STR_UI_XNSTRING(k1, hash_len),
1269 memset(k2, 0, sizeof(k2));
1270 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1272 silc_buffer_pull(dist, klen + hash_len);
1273 silc_buffer_format(dist,
1274 SILC_STR_UI_XNSTRING(k2, hash_len),
1276 silc_buffer_push(dist, klen + hash_len);
1278 memset(k3, 0, sizeof(k3));
1279 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1281 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1282 memcpy(dtmp, k1, hash_len);
1283 memcpy(dtmp + hash_len, k2, hash_len);
1284 memcpy(dtmp + hash_len, k3, hash_len);
1286 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1287 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1288 key->enc_key_len = req_enc_key_len;
1290 memset(dtmp, 0, (3 * hash_len));
1291 memset(k1, 0, sizeof(k1));
1292 memset(k2, 0, sizeof(k2));
1293 memset(k3, 0, sizeof(k3));
1295 silc_buffer_free(dist);
1297 /* Take normal hash as key */
1298 memset(hash, 0, sizeof(hash));
1299 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1300 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1301 memcpy(key->receive_enc_key, hash, enc_key_len);
1302 key->enc_key_len = req_enc_key_len;
1306 memset(hash, 0, sizeof(hash));
1308 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1309 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1310 memcpy(key->hmac_key, hash, req_hmac_key_len);
1311 key->hmac_key_len = req_hmac_key_len;
1313 memset(tmpbuf, 0, klen);
1316 return SILC_SKE_STATUS_OK;