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.1.1.1 2000/06/27 11:36:56 priikone
24 * Importet from internal CVS/Added Log headers.
29 #include "silcincludes.h"
30 #include "payload_internal.h"
31 #include "groups_internal.h"
33 /* Allocates new SKE object. */
35 SilcSKE silc_ske_alloc()
39 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
41 ske = silc_calloc(1, sizeof(*ske));
43 SILC_LOG_ERROR(("Could not allocate new SKE object"));
50 /* Free's SKE object. */
52 void silc_ske_free(SilcSKE ske)
54 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
57 /* Free start payload */
58 if (ske->start_payload)
59 silc_ske_payload_start_free(ske->start_payload);
61 /* Free KE1 payload */
63 silc_ske_payload_one_free(ske->ke1_payload);
65 /* Free KE2 payload */
67 silc_ske_payload_two_free(ske->ke2_payload);
72 silc_free(ske->prop->group);
74 silc_pkcs_free(ske->prop->pkcs);
75 if (ske->prop->cipher)
76 silc_cipher_free(ske->prop->cipher);
78 silc_hash_free(ske->prop->hash);
81 if (ske->start_payload_copy)
82 silc_buffer_free(ske->start_payload_copy);
85 silc_mp_clear(&ske->x);
86 silc_mp_clear(&ske->KEY);
93 /* Starts the SILC Key Exchange protocol for initiator. The connection
94 to the remote end must be established before calling this function
95 and the connecting socket must be sent as argument. This function
96 creates the Key Exchange Start Paload which includes all our
97 configured security properties. This payload is then sent to the
98 remote end for further processing. This payload must be sent as
99 argument to the function, however, it must not be encoded
100 already, it is done by this function.
102 The packet sending is done by calling a callback function. Caller
103 must provide a routine to send the packet. */
105 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
106 SilcSocketConnection sock,
107 SilcSKEStartPayload *start_payload,
108 SilcSKESendPacketCb send_packet,
111 SilcSKEStatus status = SILC_SKE_STATUS_OK;
112 SilcBuffer payload_buf;
114 SILC_LOG_DEBUG(("Start"));
119 /* Encode the payload */
120 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
121 if (status != SILC_SKE_STATUS_OK)
124 /* Take a copy of the payload buffer for future use. It is used to
125 compute the HASH value. */
126 ske->start_payload_copy = silc_buffer_copy(payload_buf);
128 /* Send the packet. */
130 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
132 silc_buffer_free(payload_buf);
137 /* Function called after ske_initiator_start fuction. This receives
138 the remote ends Key Exchange Start payload which includes the
139 security properties selected by the responder from our payload
140 sent in the silc_ske_initiator_start function. */
142 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
143 SilcBuffer start_payload,
147 SilcSKEStatus status = SILC_SKE_STATUS_OK;
148 SilcSKEStartPayload *payload;
149 SilcSKESecurityProperties prop;
150 SilcSKEDiffieHellmanGroup group;
152 SILC_LOG_DEBUG(("Start"));
154 /* Decode the payload */
155 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
156 if (status != SILC_SKE_STATUS_OK)
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 ske->start_payload = payload;
188 /* Return the received payload by calling the callback function. */
190 (*callback)(ske, context);
196 silc_ske_payload_start_free(payload);
201 silc_pkcs_free(prop->pkcs);
203 silc_cipher_free(prop->cipher);
205 silc_hash_free(prop->hash);
209 if (status == SILC_SKE_STATUS_OK)
210 return SILC_SKE_STATUS_ERROR;
215 /* This function creates random number x, such that 1 < x < q and
216 computes e = g ^ x mod p and sends the result to the remote end in
217 Key Exchange 1 Payload. */
219 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
220 SilcSKESendPacketCb send_packet,
223 SilcSKEStatus status = SILC_SKE_STATUS_OK;
224 SilcBuffer payload_buf;
226 SilcSKEOnePayload *payload;
228 SILC_LOG_DEBUG(("Start"));
230 /* Create the random number x, 1 < x < q. */
233 silc_ske_create_rnd(ske, ske->prop->group->group_order,
234 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
236 if (status != SILC_SKE_STATUS_OK) {
241 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
243 /* Do the Diffie Hellman computation, e = g ^ x mod p */
245 silc_mp_powm(&e, &ske->prop->group->generator, &x,
246 &ske->prop->group->group);
248 /* Encode the result to Key Exchange 1 Payload. */
249 payload = silc_calloc(1, sizeof(*payload));
251 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
252 if (status != SILC_SKE_STATUS_OK) {
259 ske->ke1_payload = payload;
262 /* Send the packet. */
264 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
266 silc_buffer_free(payload_buf);
271 /* Receives Key Exchange 2 Payload from responder consisting responders
272 public key, f, and signature. This function verifies the public key,
273 computes the secret shared key and verifies the signature. */
275 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
276 SilcBuffer ke2_payload,
280 SilcSKEStatus status = SILC_SKE_STATUS_OK;
281 SilcSKETwoPayload *payload;
283 unsigned char hash[32];
284 unsigned int hash_len;
286 SILC_LOG_DEBUG(("Start"));
288 /* Decode the payload */
289 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
290 if (status != SILC_SKE_STATUS_OK)
292 ske->ke2_payload = payload;
294 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
296 /* Compute the shared secret key */
298 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
301 SILC_LOG_DEBUG(("Verifying public key"));
303 /* Verify the public key */ /* XXX */
304 status = silc_ske_verify_public_key(ske, payload->pk_data,
306 if (status != SILC_SKE_STATUS_OK)
309 SILC_LOG_DEBUG(("Public key is authentic"));
311 /* Compute the hash value */
312 status = silc_ske_make_hash(ske, hash, &hash_len);
313 if (status != SILC_SKE_STATUS_OK)
316 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
317 memcpy(ske->hash, hash, hash_len);
318 ske->hash_len = hash_len;
320 SILC_LOG_DEBUG(("Verifying signature"));
322 /* Verify signature */
323 silc_pkcs_set_public_key(ske->prop->pkcs, payload->pk_data, payload->pk_len);
324 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
325 payload->sign_data, payload->sign_len,
326 hash, hash_len) == FALSE) {
328 SILC_LOG_DEBUG(("Signature don't match"));
330 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
334 SILC_LOG_DEBUG(("Signature is Ok"));
336 memset(hash, 'F', hash_len);
338 /* Call the callback. */
340 (*callback)(ske, context);
345 memset(hash, 'F', hash_len);
346 silc_ske_payload_two_free(payload);
348 silc_mp_clear(&ske->KEY);
351 memset(ske->hash, 'F', hash_len);
352 silc_free(ske->hash);
356 if (status == SILC_SKE_STATUS_OK)
357 return SILC_SKE_STATUS_ERROR;
362 /* Starts Key Exchange protocol for responder. Responder receives
363 Key Exchange Start Payload from initiator consisting of all the
364 security properties the initiator supports. This function decodes
365 the payload and parses the payload further and selects the right
366 security properties. */
368 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
369 SilcSocketConnection sock,
370 SilcBuffer start_payload,
374 SilcSKEStatus status = SILC_SKE_STATUS_OK;
375 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
377 SILC_LOG_DEBUG(("Start"));
382 /* Decode the payload */
383 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
384 if (status != SILC_SKE_STATUS_OK)
387 /* Take a copy of the payload buffer for future use. It is used to
388 compute the HASH value. */
389 ske->start_payload_copy = silc_buffer_copy(start_payload);
391 /* Parse and select the security properties from the payload */
392 payload = silc_calloc(1, sizeof(*payload));
393 status = silc_ske_select_security_properties(ske, payload, remote_payload);
394 if (status != SILC_SKE_STATUS_OK)
397 ske->start_payload = payload;
399 /* Call the callback function. */
401 (*callback)(ske, context);
407 silc_ske_payload_start_free(remote_payload);
411 if (status == SILC_SKE_STATUS_OK)
412 return SILC_SKE_STATUS_ERROR;
417 /* The selected security properties from the initiator payload is now
418 encoded into Key Exchange Start Payload and sent to the initiator. */
420 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
421 SilcSKEStartPayload *start_payload,
422 SilcSKESendPacketCb send_packet,
425 SilcSKEStatus status = SILC_SKE_STATUS_OK;
426 SilcBuffer payload_buf;
427 SilcSKESecurityProperties prop;
428 SilcSKEDiffieHellmanGroup group;
430 SILC_LOG_DEBUG(("Start"));
432 /* Allocate security properties from the payload. These are allocated
433 only for this negotiation and will be free'd after KE is over. */
434 ske->prop = prop = silc_calloc(1, sizeof(*prop));
435 prop->flags = start_payload->flags;
436 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
437 if (status != SILC_SKE_STATUS_OK)
442 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
443 &prop->pkcs) == FALSE) {
444 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
448 if (silc_cipher_alloc(start_payload->enc_alg_list,
449 &prop->cipher) == FALSE) {
450 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
454 if (silc_hash_alloc(start_payload->hash_alg_list,
455 &prop->hash) == FALSE) {
456 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
460 /* Encode the payload */
461 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
462 if (status != SILC_SKE_STATUS_OK)
465 /* Send the packet. */
467 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
469 silc_buffer_free(payload_buf);
477 silc_pkcs_free(prop->pkcs);
479 silc_cipher_free(prop->cipher);
481 silc_hash_free(prop->hash);
485 if (status == SILC_SKE_STATUS_OK)
486 return SILC_SKE_STATUS_ERROR;
491 /* This function receives the Key Exchange 1 Payload from the initiator.
492 After processing the payload this then selects random number x,
493 such that 1 < x < q and computes f = g ^ x mod p. This then puts
494 the result f to a Key Exchange 2 Payload which is later processed
495 in ske_responder_finish function. The callback function should
496 not touch the payload (it should merely call the ske_responder_finish
499 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
500 SilcBuffer ke1_payload,
504 SilcSKEStatus status = SILC_SKE_STATUS_OK;
505 SilcSKEOnePayload *one_payload;
506 SilcSKETwoPayload *two_payload;
509 SILC_LOG_DEBUG(("Start"));
511 /* Decode Key Exchange 1 Payload */
512 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
513 if (status != SILC_SKE_STATUS_OK)
516 /* Create the random number x, 1 < x < q. */
519 silc_ske_create_rnd(ske, ske->prop->group->group_order,
520 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
522 if (status != SILC_SKE_STATUS_OK) {
527 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
529 /* Do the Diffie Hellman computation, f = g ^ x mod p */
531 silc_mp_powm(&f, &ske->prop->group->generator, &x,
532 &ske->prop->group->group);
534 /* Save the results for later processing */
535 two_payload = silc_calloc(1, sizeof(*two_payload));
538 ske->ke1_payload = one_payload;
539 ske->ke2_payload = two_payload;
541 /* Call the callback. */
543 (*callback)(ske, context);
548 /* This function computes the secret shared key KEY = e ^ x mod p, and,
549 a hash value to be signed and sent to the other end. This then
550 encodes Key Exchange 2 Payload and sends it to the other end. */
552 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
556 unsigned int prv_len,
557 SilcSKEPKType pk_type,
558 SilcSKESendPacketCb send_packet,
561 SilcSKEStatus status = SILC_SKE_STATUS_OK;
562 SilcBuffer payload_buf;
564 unsigned char hash[32], sign[256];
565 unsigned int hash_len, sign_len;
567 SILC_LOG_DEBUG(("Start"));
569 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
571 /* Compute the shared secret key */
573 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
574 &ske->prop->group->group);
577 SILC_LOG_DEBUG(("Getting public key"));
579 /* Get the public key */
580 ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
581 memcpy(ske->ke2_payload->pk_data, pk, pk_len);
582 ske->ke2_payload->pk_len = pk_len;
583 ske->ke2_payload->pk_type = pk_type;
585 SILC_LOG_DEBUG(("Computing HASH value"));
587 /* Compute the hash value */
588 memset(hash, 0, sizeof(hash));
589 status = silc_ske_make_hash(ske, hash, &hash_len);
590 if (status != SILC_SKE_STATUS_OK)
593 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
594 memcpy(ske->hash, hash, hash_len);
595 ske->hash_len = hash_len;
597 SILC_LOG_DEBUG(("Signing HASH value"));
599 /* Sign the hash value */
600 silc_pkcs_set_private_key(ske->prop->pkcs, prv, prv_len);
601 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
604 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
605 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
606 memset(sign, 0, sizeof(sign));
607 ske->ke2_payload->sign_len = sign_len;
609 /* Encode the Key Exchange 2 Payload */
610 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
612 if (status != SILC_SKE_STATUS_OK)
615 /* Send the packet. */
617 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
619 silc_buffer_free(payload_buf);
624 silc_mp_clear(&ske->KEY);
625 silc_ske_payload_two_free(ske->ke2_payload);
627 if (status == SILC_SKE_STATUS_OK)
628 return SILC_SKE_STATUS_ERROR;
633 /* The Key Exchange protocol is ended by calling this function. This
634 must not be called until the keys are processed like the protocol
635 defines. This function is for both initiator and responder. */
637 SilcSKEStatus silc_ske_end(SilcSKE ske,
638 SilcSKESendPacketCb send_packet,
641 SilcSKEStatus status = SILC_SKE_STATUS_OK;
644 SILC_LOG_DEBUG(("Start"));
646 packet = silc_buffer_alloc(1);
650 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
655 /* Aborts the Key Exchange protocol. This is called if error occurs
656 while performing the protocol. The status argument is the error
657 status and it is sent to the remote end. */
659 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
660 SilcSKESendPacketCb send_packet,
665 SILC_LOG_DEBUG(("Start"));
667 packet = silc_buffer_alloc(4);
668 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
669 silc_buffer_format(packet,
670 SILC_STR_UI_SHORT(status),
674 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
676 silc_buffer_free(packet);
678 return SILC_SKE_STATUS_OK;
681 /* Assembles security properties to Key Exchange Start Payload to be
682 sent to the remote end. This checks system wide (SILC system, that is)
683 settings and chooses from those. However, if other properties
684 should be used this function is easy to replace by another function,
685 as, this function is called by the caller of the protocol and not
686 by the protocol itself. */
689 silc_ske_assemble_security_properties(SilcSKE ske,
690 SilcSKEStartPayload **return_payload)
692 SilcSKEStartPayload *rp;
694 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
696 rp = silc_calloc(1, sizeof(*rp));
704 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
705 rp->cookie_len = SILC_SKE_COOKIE_LEN;
706 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
708 /* Get supported Key Exhange groups */
709 rp->ke_grp_list = silc_ske_get_supported_groups();
710 rp->ke_grp_len = strlen(rp->ke_grp_list);
712 /* Get supported PKCS algorithms */
713 rp->pkcs_alg_list = silc_pkcs_get_supported();
714 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
716 /* Get supported encryption algorithms */
717 rp->enc_alg_list = silc_cipher_get_supported();
718 rp->enc_alg_len = strlen(rp->enc_alg_list);
720 /* Get supported hash algorithms */
721 rp->hash_alg_list = silc_hash_get_supported();
722 rp->hash_alg_len = strlen(rp->hash_alg_list);
725 /* Get supported compression algorithms */
726 rp->comp_alg_list = "";
727 rp->comp_alg_len = 0;
729 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
730 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
731 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
732 2 + rp->comp_alg_len;
734 *return_payload = rp;
736 return SILC_SKE_STATUS_OK;
739 /* Selects the supported security properties from the remote end's Key
740 Exchange Start Payload. */
743 silc_ske_select_security_properties(SilcSKE ske,
744 SilcSKEStartPayload *payload,
745 SilcSKEStartPayload *remote_payload)
747 SilcSKEStartPayload *rp;
751 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
755 /* Flags are returned unchanged. */
756 payload->flags = rp->flags;
758 /* XXX Cookie check?? */
759 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
760 payload->cookie_len = SILC_SKE_COOKIE_LEN;
761 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
763 /* Get supported Key Exchange groups */
764 cp = rp->ke_grp_list;
765 if (cp && strchr(cp, ',')) {
769 len = strcspn(cp, ",");
770 item = silc_calloc(len + 1, sizeof(char));
771 memcpy(item, cp, len);
773 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
775 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
776 SILC_LOG_DEBUG(("Found KE group `%s'", item));
778 payload->ke_grp_len = len;
779 payload->ke_grp_list = item;
793 if (!payload->ke_grp_len && !payload->ke_grp_list) {
794 SILC_LOG_DEBUG(("Could not find supported KE group"));
796 return SILC_SKE_STATUS_UNKNOWN_GROUP;
800 if (!rp->ke_grp_len) {
801 SILC_LOG_DEBUG(("KE group not defined in payload"));
803 return SILC_SKE_STATUS_BAD_PAYLOAD;
806 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
807 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
809 payload->ke_grp_len = rp->ke_grp_len;
810 payload->ke_grp_list = strdup(rp->ke_grp_list);
813 /* Get supported PKCS algorithms */
814 cp = rp->pkcs_alg_list;
815 if (cp && strchr(cp, ',')) {
819 len = strcspn(cp, ",");
820 item = silc_calloc(len + 1, sizeof(char));
821 memcpy(item, cp, len);
823 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
825 if (silc_pkcs_is_supported(item) == TRUE) {
826 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
828 payload->pkcs_alg_len = len;
829 payload->pkcs_alg_list = item;
843 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
844 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
845 silc_free(payload->ke_grp_list);
847 return SILC_SKE_STATUS_UNKNOWN_PKCS;
851 if (!rp->pkcs_alg_len) {
852 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
853 silc_free(payload->ke_grp_list);
855 return SILC_SKE_STATUS_BAD_PAYLOAD;
858 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
859 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
861 payload->pkcs_alg_len = rp->pkcs_alg_len;
862 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
865 /* Get supported encryption algorithms */
866 cp = rp->enc_alg_list;
867 if (cp && strchr(cp, ',')) {
871 len = strcspn(cp, ",");
872 item = silc_calloc(len + 1, sizeof(char));
873 memcpy(item, cp, len);
875 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
877 if (silc_cipher_is_supported(item) == TRUE) {
878 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
880 payload->enc_alg_len = len;
881 payload->enc_alg_list = item;
895 if (!payload->enc_alg_len && !payload->enc_alg_list) {
896 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
897 silc_free(payload->ke_grp_list);
898 silc_free(payload->pkcs_alg_list);
900 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
904 if (!rp->enc_alg_len) {
905 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
906 silc_free(payload->ke_grp_list);
907 silc_free(payload->pkcs_alg_list);
909 return SILC_SKE_STATUS_BAD_PAYLOAD;
912 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
915 payload->enc_alg_len = rp->enc_alg_len;
916 payload->enc_alg_list = strdup(rp->enc_alg_list);
919 /* Get supported hash algorithms */
920 cp = rp->hash_alg_list;
921 if (cp && strchr(cp, ',')) {
925 len = strcspn(cp, ",");
926 item = silc_calloc(len + 1, sizeof(char));
927 memcpy(item, cp, len);
929 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
931 if (silc_hash_is_supported(item) == TRUE) {
932 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
934 payload->hash_alg_len = len;
935 payload->hash_alg_list = item;
949 if (!payload->hash_alg_len && !payload->hash_alg_list) {
950 SILC_LOG_DEBUG(("Could not find supported hash alg"));
951 silc_free(payload->ke_grp_list);
952 silc_free(payload->pkcs_alg_list);
953 silc_free(payload->enc_alg_list);
955 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
959 if (!rp->hash_alg_len) {
960 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
961 silc_free(payload->ke_grp_list);
962 silc_free(payload->pkcs_alg_list);
963 silc_free(payload->enc_alg_list);
965 return SILC_SKE_STATUS_BAD_PAYLOAD;
968 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
971 payload->hash_alg_len = rp->hash_alg_len;
972 payload->hash_alg_list = strdup(rp->hash_alg_list);
976 /* Get supported compression algorithms */
977 cp = rp->hash_alg_list;
978 if (cp && strchr(cp, ',')) {
982 len = strcspn(cp, ",");
983 item = silc_calloc(len + 1, sizeof(char));
984 memcpy(item, cp, len);
986 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
988 if (silc_hash_is_supported(item) == TRUE) {
989 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
991 payload->hash_alg_len = len;
992 payload->hash_alg_list = item;
1006 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1007 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1008 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1009 silc_free(payload->ke_grp_list);
1010 silc_free(payload->pkcs_alg_list);
1011 silc_free(payload->enc_alg_list);
1020 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1021 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1022 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1023 2 + payload->comp_alg_len;
1025 return SILC_SKE_STATUS_OK;
1028 /* Creates random number such that 1 < rnd < n and at most length
1029 of len bits. The rnd sent as argument must be initialized. */
1031 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1035 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1036 unsigned char *string;
1038 SILC_LOG_DEBUG(("Creating random number"));
1040 /* Get the random number as string */
1041 string = silc_rng_get_rn_string(ske->rng, (len / 8));
1043 /* Decode the string into a MP integer */
1044 silc_mp_set_str(rnd, string, 16);
1045 silc_mp_mod_2exp(rnd, rnd, len);
1048 if (silc_mp_cmp_ui(rnd, 1) < 0)
1049 status = SILC_SKE_STATUS_ERROR;
1051 if (silc_mp_cmp(rnd, &n) >= 0)
1052 status = SILC_SKE_STATUS_ERROR;
1054 memset(string, 'F', (len / 8));
1062 SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske,
1063 unsigned char *pubkey,
1064 unsigned int pubkey_len)
1066 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1071 /* Creates a hash value HASH as defined in the SKE protocol. */
1073 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1074 unsigned char *return_hash,
1075 unsigned int *return_hash_len)
1077 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1079 unsigned char *e, *f, *KEY;
1080 unsigned int e_len, f_len, KEY_len;
1082 SILC_LOG_DEBUG(("Start"));
1084 e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
1085 e = silc_calloc(e_len + 1, sizeof(unsigned char));
1086 silc_mp_get_str(e, 16, &ske->ke1_payload->e);
1088 f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
1089 f = silc_calloc(f_len + 1, sizeof(unsigned char));
1090 silc_mp_get_str(f, 16, &ske->ke2_payload->f);
1092 KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
1093 KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
1094 silc_mp_get_str(KEY, 16, &ske->KEY);
1096 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1097 ske->pk_len + e_len + f_len + KEY_len);
1098 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1100 /* Format the buffer used to compute the hash value */
1101 silc_buffer_format(buf,
1102 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1103 ske->start_payload_copy->len),
1104 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1105 SILC_STR_UI_XNSTRING(e, e_len),
1106 SILC_STR_UI_XNSTRING(f, f_len),
1107 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1111 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1115 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1116 *return_hash_len = ske->prop->hash->hash->hash_len;
1118 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1120 silc_buffer_free(buf);
1121 memset(e, 0, e_len);
1122 memset(f, 0, f_len);
1123 memset(KEY, 0, KEY_len);
1131 /* Processes negotiated key material as protocol specifies. This returns
1132 the actual keys to be used in the SILC. */
1134 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1135 unsigned int req_iv_len,
1136 unsigned int req_enc_key_len,
1137 unsigned int req_hmac_key_len,
1138 SilcSKEKeyMaterial *key)
1143 unsigned char *tmpbuf;
1144 unsigned char hash[32];
1145 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1146 unsigned int enc_key_len = req_enc_key_len / 8;
1148 SILC_LOG_DEBUG(("Start"));
1150 silc_mp_init_set(&tmp, &ske->KEY);
1152 klen = silc_mp_size(&tmp);
1154 /* Format the KEY material into binary data */
1155 tmpbuf = silc_calloc(klen, sizeof(unsigned char));
1156 for (i = klen; i > 0; i--) {
1157 tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
1158 silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
1161 buf = silc_buffer_alloc(1 + klen + hash_len);
1163 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1164 silc_buffer_format(buf,
1165 SILC_STR_UI_CHAR(0),
1166 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1167 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1171 memset(hash, 0, sizeof(hash));
1173 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1174 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1175 memcpy(key->send_iv, hash, req_iv_len);
1176 memset(hash, 0, sizeof(hash));
1178 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1179 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1180 memcpy(key->receive_iv, hash, req_iv_len);
1181 key->iv_len = req_iv_len;
1183 /* Take the encryption keys. If requested key size is more than
1184 the size of hash length we will distribute more key material
1185 as protocol defines. */
1187 if (enc_key_len > hash_len) {
1189 unsigned char k1[32], k2[32], k3[32];
1190 unsigned char *dtmp;
1193 if (enc_key_len > (3 * hash_len))
1194 return SILC_SKE_STATUS_ERROR;
1196 memset(k1, 0, sizeof(k1));
1197 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1200 dist = silc_buffer_alloc(hash_len * 3);
1202 silc_buffer_pull_tail(dist, klen + hash_len);
1203 silc_buffer_format(dist,
1204 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1205 SILC_STR_UI_XNSTRING(k1, hash_len),
1208 memset(k2, 0, sizeof(k2));
1209 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1211 silc_buffer_pull(dist, klen + hash_len);
1212 silc_buffer_format(dist,
1213 SILC_STR_UI_XNSTRING(k2, hash_len),
1215 silc_buffer_push(dist, klen + hash_len);
1217 memset(k3, 0, sizeof(k3));
1218 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1220 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1221 memcpy(dtmp, k1, hash_len);
1222 memcpy(dtmp + hash_len, k2, hash_len);
1223 memcpy(dtmp + hash_len, k3, hash_len);
1225 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1226 memcpy(key->send_enc_key, dtmp, enc_key_len);
1227 key->enc_key_len = req_enc_key_len;
1229 memset(dtmp, 0, (3 * hash_len));
1230 memset(k1, 0, sizeof(k1));
1231 memset(k2, 0, sizeof(k2));
1232 memset(k3, 0, sizeof(k3));
1234 silc_buffer_free(dist);
1236 /* Take normal hash as key */
1237 memset(hash, 0, sizeof(hash));
1238 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1239 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1240 memcpy(key->send_enc_key, hash, enc_key_len);
1241 key->enc_key_len = req_enc_key_len;
1245 if (enc_key_len > hash_len) {
1247 unsigned char k1[32], k2[32], k3[32];
1248 unsigned char *dtmp;
1251 if (enc_key_len > (3 * hash_len))
1252 return SILC_SKE_STATUS_ERROR;
1254 memset(k1, 0, sizeof(k1));
1255 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1258 dist = silc_buffer_alloc(hash_len * 3);
1260 silc_buffer_pull_tail(dist, klen + hash_len);
1261 silc_buffer_format(dist,
1262 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1263 SILC_STR_UI_XNSTRING(k1, hash_len),
1266 memset(k2, 0, sizeof(k2));
1267 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1269 silc_buffer_pull(dist, klen + hash_len);
1270 silc_buffer_format(dist,
1271 SILC_STR_UI_XNSTRING(k2, hash_len),
1273 silc_buffer_push(dist, klen + hash_len);
1275 memset(k3, 0, sizeof(k3));
1276 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1278 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1279 memcpy(dtmp, k1, hash_len);
1280 memcpy(dtmp + hash_len, k2, hash_len);
1281 memcpy(dtmp + hash_len, k3, hash_len);
1283 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1284 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1285 key->enc_key_len = req_enc_key_len;
1287 memset(dtmp, 0, (3 * hash_len));
1288 memset(k1, 0, sizeof(k1));
1289 memset(k2, 0, sizeof(k2));
1290 memset(k3, 0, sizeof(k3));
1292 silc_buffer_free(dist);
1294 /* Take normal hash as key */
1295 memset(hash, 0, sizeof(hash));
1296 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1297 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1298 memcpy(key->receive_enc_key, hash, enc_key_len);
1299 key->enc_key_len = req_enc_key_len;
1303 memset(hash, 0, sizeof(hash));
1305 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1306 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1307 memcpy(key->hmac_key, hash, req_hmac_key_len);
1308 key->hmac_key_len = req_hmac_key_len;
1310 memset(tmpbuf, 0, klen);
1313 return SILC_SKE_STATUS_OK;