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.4 2000/07/07 06:46:43 priikone
24 * Removed ske_verify_public_key function as it is not needed
25 * anymore. Added support to the public key verification as callback
26 * function. Other minor changes and bug fixes.
28 * Revision 1.3 2000/07/06 07:12:39 priikone
29 * Support for SILC style public keys added.
31 * Revision 1.2 2000/07/05 06:05:15 priikone
32 * Global cosmetic change.
34 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
35 * Imported from internal CVS/Added Log headers.
40 #include "silcincludes.h"
41 #include "payload_internal.h"
42 #include "groups_internal.h"
44 /* Allocates new SKE object. */
46 SilcSKE silc_ske_alloc()
50 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
52 ske = silc_calloc(1, sizeof(*ske));
57 /* Free's SKE object. */
59 void silc_ske_free(SilcSKE ske)
61 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
64 /* Free start payload */
65 if (ske->start_payload)
66 silc_ske_payload_start_free(ske->start_payload);
68 /* Free KE1 payload */
70 silc_ske_payload_one_free(ske->ke1_payload);
72 /* Free KE2 payload */
74 silc_ske_payload_two_free(ske->ke2_payload);
79 silc_free(ske->prop->group);
81 silc_pkcs_free(ske->prop->pkcs);
82 if (ske->prop->cipher)
83 silc_cipher_free(ske->prop->cipher);
85 silc_hash_free(ske->prop->hash);
88 if (ske->start_payload_copy)
89 silc_buffer_free(ske->start_payload_copy);
93 silc_mp_clear(&ske->x);
94 silc_mp_clear(&ske->KEY);
102 /* Starts the SILC Key Exchange protocol for initiator. The connection
103 to the remote end must be established before calling this function
104 and the connecting socket must be sent as argument. This function
105 creates the Key Exchange Start Paload which includes all our
106 configured security properties. This payload is then sent to the
107 remote end for further processing. This payload must be sent as
108 argument to the function, however, it must not be encoded
109 already, it is done by this function.
111 The packet sending is done by calling a callback function. Caller
112 must provide a routine to send the packet. */
114 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
115 SilcSocketConnection sock,
116 SilcSKEStartPayload *start_payload,
117 SilcSKESendPacketCb send_packet,
120 SilcSKEStatus status = SILC_SKE_STATUS_OK;
121 SilcBuffer payload_buf;
123 SILC_LOG_DEBUG(("Start"));
128 /* Encode the payload */
129 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
130 if (status != SILC_SKE_STATUS_OK)
133 /* Take a copy of the payload buffer for future use. It is used to
134 compute the HASH value. */
135 ske->start_payload_copy = silc_buffer_copy(payload_buf);
137 /* Send the packet. */
139 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
141 silc_buffer_free(payload_buf);
146 /* Function called after ske_initiator_start fuction. This receives
147 the remote ends Key Exchange Start payload which includes the
148 security properties selected by the responder from our payload
149 sent in the silc_ske_initiator_start function. */
151 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
152 SilcBuffer start_payload,
156 SilcSKEStatus status = SILC_SKE_STATUS_OK;
157 SilcSKEStartPayload *payload;
158 SilcSKESecurityProperties prop;
159 SilcSKEDiffieHellmanGroup group;
161 SILC_LOG_DEBUG(("Start"));
163 /* Decode the payload */
164 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
165 if (status != SILC_SKE_STATUS_OK)
168 /* Take the selected security properties into use while doing
169 the key exchange. This is used only while doing the key
170 exchange. The same data is returned to upper levels by calling
171 the callback function. */
172 ske->prop = prop = silc_calloc(1, sizeof(*prop));
173 prop->flags = payload->flags;
174 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
175 if (status != SILC_SKE_STATUS_OK)
180 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
181 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
185 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
186 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
190 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
191 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
195 ske->start_payload = payload;
197 /* Return the received payload by calling the callback function. */
199 (*callback)(ske, context);
205 silc_ske_payload_start_free(payload);
210 silc_pkcs_free(prop->pkcs);
212 silc_cipher_free(prop->cipher);
214 silc_hash_free(prop->hash);
218 if (status == SILC_SKE_STATUS_OK)
219 return SILC_SKE_STATUS_ERROR;
224 /* This function creates random number x, such that 1 < x < q and
225 computes e = g ^ x mod p and sends the result to the remote end in
226 Key Exchange 1 Payload. */
228 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
229 SilcSKESendPacketCb send_packet,
232 SilcSKEStatus status = SILC_SKE_STATUS_OK;
233 SilcBuffer payload_buf;
235 SilcSKEOnePayload *payload;
237 SILC_LOG_DEBUG(("Start"));
239 /* Create the random number x, 1 < x < q. */
242 silc_ske_create_rnd(ske, ske->prop->group->group_order,
243 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
245 if (status != SILC_SKE_STATUS_OK) {
250 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
252 /* Do the Diffie Hellman computation, e = g ^ x mod p */
254 silc_mp_powm(&e, &ske->prop->group->generator, &x,
255 &ske->prop->group->group);
257 /* Encode the result to Key Exchange 1 Payload. */
258 payload = silc_calloc(1, sizeof(*payload));
260 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
261 if (status != SILC_SKE_STATUS_OK) {
268 ske->ke1_payload = payload;
271 /* Send the packet. */
273 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
275 silc_buffer_free(payload_buf);
280 /* Receives Key Exchange 2 Payload from responder consisting responders
281 public key, f, and signature. This function verifies the public key,
282 computes the secret shared key and verifies the signature. */
284 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
285 SilcBuffer ke2_payload,
286 SilcSKEVerifyCb verify_key,
287 void *verify_context,
291 SilcSKEStatus status = SILC_SKE_STATUS_OK;
292 SilcSKETwoPayload *payload;
293 SilcPublicKey public_key = NULL;
295 unsigned char hash[32];
296 unsigned int hash_len;
298 SILC_LOG_DEBUG(("Start"));
300 /* Decode the payload */
301 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
302 if (status != SILC_SKE_STATUS_OK)
304 ske->ke2_payload = payload;
306 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
308 /* Compute the shared secret key */
310 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
313 SILC_LOG_DEBUG(("Verifying public key"));
315 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
317 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
322 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
323 payload->pk_type, verify_context);
324 if (status != SILC_SKE_STATUS_OK)
328 SILC_LOG_DEBUG(("Public key is authentic"));
330 /* Compute the hash value */
331 status = silc_ske_make_hash(ske, hash, &hash_len);
332 if (status != SILC_SKE_STATUS_OK)
335 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
336 memcpy(ske->hash, hash, hash_len);
337 ske->hash_len = hash_len;
339 SILC_LOG_DEBUG(("Verifying signature"));
341 /* Verify signature */
342 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
344 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
345 payload->sign_data, payload->sign_len,
346 hash, hash_len) == FALSE) {
348 SILC_LOG_DEBUG(("Signature don't match"));
350 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
354 SILC_LOG_DEBUG(("Signature is Ok"));
356 silc_pkcs_public_key_free(public_key);
357 memset(hash, 'F', hash_len);
359 /* Call the callback. */
361 (*callback)(ske, context);
366 memset(hash, 'F', sizeof(hash));
367 silc_ske_payload_two_free(payload);
368 ske->ke2_payload = NULL;
370 silc_mp_clear(&ske->KEY);
373 silc_pkcs_public_key_free(public_key);
376 memset(ske->hash, 'F', hash_len);
377 silc_free(ske->hash);
381 if (status == SILC_SKE_STATUS_OK)
382 return SILC_SKE_STATUS_ERROR;
387 /* Starts Key Exchange protocol for responder. Responder receives
388 Key Exchange Start Payload from initiator consisting of all the
389 security properties the initiator supports. This function decodes
390 the payload and parses the payload further and selects the right
391 security properties. */
393 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
394 SilcSocketConnection sock,
395 SilcBuffer start_payload,
399 SilcSKEStatus status = SILC_SKE_STATUS_OK;
400 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
402 SILC_LOG_DEBUG(("Start"));
407 /* Decode the payload */
408 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
409 if (status != SILC_SKE_STATUS_OK)
412 /* Take a copy of the payload buffer for future use. It is used to
413 compute the HASH value. */
414 ske->start_payload_copy = silc_buffer_copy(start_payload);
416 /* Parse and select the security properties from the payload */
417 payload = silc_calloc(1, sizeof(*payload));
418 status = silc_ske_select_security_properties(ske, payload, remote_payload);
419 if (status != SILC_SKE_STATUS_OK)
422 ske->start_payload = payload;
424 /* Call the callback function. */
426 (*callback)(ske, context);
432 silc_ske_payload_start_free(remote_payload);
436 if (status == SILC_SKE_STATUS_OK)
437 return SILC_SKE_STATUS_ERROR;
442 /* The selected security properties from the initiator payload is now
443 encoded into Key Exchange Start Payload and sent to the initiator. */
445 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
446 SilcSKEStartPayload *start_payload,
447 SilcSKESendPacketCb send_packet,
450 SilcSKEStatus status = SILC_SKE_STATUS_OK;
451 SilcBuffer payload_buf;
452 SilcSKESecurityProperties prop;
453 SilcSKEDiffieHellmanGroup group;
455 SILC_LOG_DEBUG(("Start"));
457 /* Allocate security properties from the payload. These are allocated
458 only for this negotiation and will be free'd after KE is over. */
459 ske->prop = prop = silc_calloc(1, sizeof(*prop));
460 prop->flags = start_payload->flags;
461 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
462 if (status != SILC_SKE_STATUS_OK)
467 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
468 &prop->pkcs) == FALSE) {
469 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
473 if (silc_cipher_alloc(start_payload->enc_alg_list,
474 &prop->cipher) == FALSE) {
475 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
479 if (silc_hash_alloc(start_payload->hash_alg_list,
480 &prop->hash) == FALSE) {
481 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
485 /* Encode the payload */
486 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
487 if (status != SILC_SKE_STATUS_OK)
490 /* Send the packet. */
492 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
494 silc_buffer_free(payload_buf);
502 silc_pkcs_free(prop->pkcs);
504 silc_cipher_free(prop->cipher);
506 silc_hash_free(prop->hash);
510 if (status == SILC_SKE_STATUS_OK)
511 return SILC_SKE_STATUS_ERROR;
516 /* This function receives the Key Exchange 1 Payload from the initiator.
517 After processing the payload this then selects random number x,
518 such that 1 < x < q and computes f = g ^ x mod p. This then puts
519 the result f to a Key Exchange 2 Payload which is later processed
520 in ske_responder_finish function. The callback function should
521 not touch the payload (it should merely call the ske_responder_finish
524 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
525 SilcBuffer ke1_payload,
529 SilcSKEStatus status = SILC_SKE_STATUS_OK;
530 SilcSKEOnePayload *one_payload;
531 SilcSKETwoPayload *two_payload;
534 SILC_LOG_DEBUG(("Start"));
536 /* Decode Key Exchange 1 Payload */
537 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
538 if (status != SILC_SKE_STATUS_OK)
541 /* Create the random number x, 1 < x < q. */
544 silc_ske_create_rnd(ske, ske->prop->group->group_order,
545 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
547 if (status != SILC_SKE_STATUS_OK) {
552 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
554 /* Do the Diffie Hellman computation, f = g ^ x mod p */
556 silc_mp_powm(&f, &ske->prop->group->generator, &x,
557 &ske->prop->group->group);
559 /* Save the results for later processing */
560 two_payload = silc_calloc(1, sizeof(*two_payload));
563 ske->ke1_payload = one_payload;
564 ske->ke2_payload = two_payload;
566 /* Call the callback. */
568 (*callback)(ske, context);
573 /* This function computes the secret shared key KEY = e ^ x mod p, and,
574 a hash value to be signed and sent to the other end. This then
575 encodes Key Exchange 2 Payload and sends it to the other end. */
577 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
578 SilcPublicKey public_key,
579 SilcPrivateKey private_key,
580 SilcSKEPKType pk_type,
581 SilcSKESendPacketCb send_packet,
584 SilcSKEStatus status = SILC_SKE_STATUS_OK;
585 SilcBuffer payload_buf;
587 unsigned char hash[32], sign[256], *pk;
588 unsigned int hash_len, sign_len, pk_len;
590 SILC_LOG_DEBUG(("Start"));
592 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
594 /* Compute the shared secret key */
596 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
597 &ske->prop->group->group);
600 SILC_LOG_DEBUG(("Getting public key"));
602 /* Get the public key */
603 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
604 ske->ke2_payload->pk_data = pk;
605 ske->ke2_payload->pk_len = pk_len;
606 ske->ke2_payload->pk_type = pk_type;
608 SILC_LOG_DEBUG(("Computing HASH value"));
610 /* Compute the hash value */
611 memset(hash, 0, sizeof(hash));
612 status = silc_ske_make_hash(ske, hash, &hash_len);
613 if (status != SILC_SKE_STATUS_OK)
616 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
617 memcpy(ske->hash, hash, hash_len);
618 ske->hash_len = hash_len;
620 SILC_LOG_DEBUG(("Signing HASH value"));
622 /* Sign the hash value */
623 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
624 private_key->prv_len);
625 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
628 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
629 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
630 memset(sign, 0, sizeof(sign));
631 ske->ke2_payload->sign_len = sign_len;
633 /* Encode the Key Exchange 2 Payload */
634 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
636 if (status != SILC_SKE_STATUS_OK)
639 /* Send the packet. */
641 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
643 silc_buffer_free(payload_buf);
648 silc_mp_clear(&ske->KEY);
649 silc_ske_payload_two_free(ske->ke2_payload);
651 if (status == SILC_SKE_STATUS_OK)
652 return SILC_SKE_STATUS_ERROR;
657 /* The Key Exchange protocol is ended by calling this function. This
658 must not be called until the keys are processed like the protocol
659 defines. This function is for both initiator and responder. */
661 SilcSKEStatus silc_ske_end(SilcSKE ske,
662 SilcSKESendPacketCb send_packet,
665 SilcSKEStatus status = SILC_SKE_STATUS_OK;
668 SILC_LOG_DEBUG(("Start"));
670 packet = silc_buffer_alloc(1);
674 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
679 /* Aborts the Key Exchange protocol. This is called if error occurs
680 while performing the protocol. The status argument is the error
681 status and it is sent to the remote end. */
683 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
684 SilcSKESendPacketCb send_packet,
689 SILC_LOG_DEBUG(("Start"));
691 packet = silc_buffer_alloc(4);
692 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
693 silc_buffer_format(packet,
694 SILC_STR_UI_SHORT(status),
698 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
700 silc_buffer_free(packet);
702 return SILC_SKE_STATUS_OK;
705 /* Assembles security properties to Key Exchange Start Payload to be
706 sent to the remote end. This checks system wide (SILC system, that is)
707 settings and chooses from those. However, if other properties
708 should be used this function is easy to replace by another function,
709 as, this function is called by the caller of the protocol and not
710 by the protocol itself. */
713 silc_ske_assemble_security_properties(SilcSKE ske,
714 SilcSKEStartPayload **return_payload)
716 SilcSKEStartPayload *rp;
718 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
720 rp = silc_calloc(1, sizeof(*rp));
728 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
729 rp->cookie_len = SILC_SKE_COOKIE_LEN;
730 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
732 /* Get supported Key Exhange groups */
733 rp->ke_grp_list = silc_ske_get_supported_groups();
734 rp->ke_grp_len = strlen(rp->ke_grp_list);
736 /* Get supported PKCS algorithms */
737 rp->pkcs_alg_list = silc_pkcs_get_supported();
738 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
740 /* Get supported encryption algorithms */
741 rp->enc_alg_list = silc_cipher_get_supported();
742 rp->enc_alg_len = strlen(rp->enc_alg_list);
744 /* Get supported hash algorithms */
745 rp->hash_alg_list = silc_hash_get_supported();
746 rp->hash_alg_len = strlen(rp->hash_alg_list);
749 /* Get supported compression algorithms */
750 rp->comp_alg_list = "";
751 rp->comp_alg_len = 0;
753 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
754 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
755 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
756 2 + rp->comp_alg_len;
758 *return_payload = rp;
760 return SILC_SKE_STATUS_OK;
763 /* Selects the supported security properties from the remote end's Key
764 Exchange Start Payload. */
767 silc_ske_select_security_properties(SilcSKE ske,
768 SilcSKEStartPayload *payload,
769 SilcSKEStartPayload *remote_payload)
771 SilcSKEStartPayload *rp;
775 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
779 /* Flags are returned unchanged. */
780 payload->flags = rp->flags;
782 /* XXX Cookie check?? */
783 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
784 payload->cookie_len = SILC_SKE_COOKIE_LEN;
785 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
787 /* Get supported Key Exchange groups */
788 cp = rp->ke_grp_list;
789 if (cp && strchr(cp, ',')) {
793 len = strcspn(cp, ",");
794 item = silc_calloc(len + 1, sizeof(char));
795 memcpy(item, cp, len);
797 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
799 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
800 SILC_LOG_DEBUG(("Found KE group `%s'", item));
802 payload->ke_grp_len = len;
803 payload->ke_grp_list = item;
817 if (!payload->ke_grp_len && !payload->ke_grp_list) {
818 SILC_LOG_DEBUG(("Could not find supported KE group"));
820 return SILC_SKE_STATUS_UNKNOWN_GROUP;
824 if (!rp->ke_grp_len) {
825 SILC_LOG_DEBUG(("KE group not defined in payload"));
827 return SILC_SKE_STATUS_BAD_PAYLOAD;
830 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
831 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
833 payload->ke_grp_len = rp->ke_grp_len;
834 payload->ke_grp_list = strdup(rp->ke_grp_list);
837 /* Get supported PKCS algorithms */
838 cp = rp->pkcs_alg_list;
839 if (cp && strchr(cp, ',')) {
843 len = strcspn(cp, ",");
844 item = silc_calloc(len + 1, sizeof(char));
845 memcpy(item, cp, len);
847 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
849 if (silc_pkcs_is_supported(item) == TRUE) {
850 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
852 payload->pkcs_alg_len = len;
853 payload->pkcs_alg_list = item;
867 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
868 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
869 silc_free(payload->ke_grp_list);
871 return SILC_SKE_STATUS_UNKNOWN_PKCS;
875 if (!rp->pkcs_alg_len) {
876 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
877 silc_free(payload->ke_grp_list);
879 return SILC_SKE_STATUS_BAD_PAYLOAD;
882 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
883 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
885 payload->pkcs_alg_len = rp->pkcs_alg_len;
886 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
889 /* Get supported encryption algorithms */
890 cp = rp->enc_alg_list;
891 if (cp && strchr(cp, ',')) {
895 len = strcspn(cp, ",");
896 item = silc_calloc(len + 1, sizeof(char));
897 memcpy(item, cp, len);
899 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
901 if (silc_cipher_is_supported(item) == TRUE) {
902 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
904 payload->enc_alg_len = len;
905 payload->enc_alg_list = item;
919 if (!payload->enc_alg_len && !payload->enc_alg_list) {
920 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
921 silc_free(payload->ke_grp_list);
922 silc_free(payload->pkcs_alg_list);
924 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
928 if (!rp->enc_alg_len) {
929 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
930 silc_free(payload->ke_grp_list);
931 silc_free(payload->pkcs_alg_list);
933 return SILC_SKE_STATUS_BAD_PAYLOAD;
936 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
939 payload->enc_alg_len = rp->enc_alg_len;
940 payload->enc_alg_list = strdup(rp->enc_alg_list);
943 /* Get supported hash algorithms */
944 cp = rp->hash_alg_list;
945 if (cp && strchr(cp, ',')) {
949 len = strcspn(cp, ",");
950 item = silc_calloc(len + 1, sizeof(char));
951 memcpy(item, cp, len);
953 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
955 if (silc_hash_is_supported(item) == TRUE) {
956 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
958 payload->hash_alg_len = len;
959 payload->hash_alg_list = item;
973 if (!payload->hash_alg_len && !payload->hash_alg_list) {
974 SILC_LOG_DEBUG(("Could not find supported hash alg"));
975 silc_free(payload->ke_grp_list);
976 silc_free(payload->pkcs_alg_list);
977 silc_free(payload->enc_alg_list);
979 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
983 if (!rp->hash_alg_len) {
984 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
985 silc_free(payload->ke_grp_list);
986 silc_free(payload->pkcs_alg_list);
987 silc_free(payload->enc_alg_list);
989 return SILC_SKE_STATUS_BAD_PAYLOAD;
992 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
995 payload->hash_alg_len = rp->hash_alg_len;
996 payload->hash_alg_list = strdup(rp->hash_alg_list);
1000 /* Get supported compression algorithms */
1001 cp = rp->hash_alg_list;
1002 if (cp && strchr(cp, ',')) {
1006 len = strcspn(cp, ",");
1007 item = silc_calloc(len + 1, sizeof(char));
1008 memcpy(item, cp, len);
1010 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1012 if (silc_hash_is_supported(item) == TRUE) {
1013 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1015 payload->hash_alg_len = len;
1016 payload->hash_alg_list = item;
1021 if (strlen(cp) == 0)
1030 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1031 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1032 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1033 silc_free(payload->ke_grp_list);
1034 silc_free(payload->pkcs_alg_list);
1035 silc_free(payload->enc_alg_list);
1044 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1045 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1046 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1047 2 + payload->comp_alg_len;
1049 return SILC_SKE_STATUS_OK;
1052 /* Creates random number such that 1 < rnd < n and at most length
1053 of len bits. The rnd sent as argument must be initialized. */
1055 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1059 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1060 unsigned char *string;
1062 SILC_LOG_DEBUG(("Creating random number"));
1064 /* Get the random number as string */
1065 string = silc_rng_get_rn_string(ske->rng, (len / 8));
1067 /* Decode the string into a MP integer */
1068 silc_mp_set_str(rnd, string, 16);
1069 silc_mp_mod_2exp(rnd, rnd, len);
1072 if (silc_mp_cmp_ui(rnd, 1) < 0)
1073 status = SILC_SKE_STATUS_ERROR;
1075 if (silc_mp_cmp(rnd, &n) >= 0)
1076 status = SILC_SKE_STATUS_ERROR;
1078 memset(string, 'F', (len / 8));
1084 /* Creates a hash value HASH as defined in the SKE protocol. */
1086 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1087 unsigned char *return_hash,
1088 unsigned int *return_hash_len)
1090 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1092 unsigned char *e, *f, *KEY;
1093 unsigned int e_len, f_len, KEY_len;
1095 SILC_LOG_DEBUG(("Start"));
1097 e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
1098 e = silc_calloc(e_len + 1, sizeof(unsigned char));
1099 silc_mp_get_str(e, 16, &ske->ke1_payload->e);
1101 f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
1102 f = silc_calloc(f_len + 1, sizeof(unsigned char));
1103 silc_mp_get_str(f, 16, &ske->ke2_payload->f);
1105 KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
1106 KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
1107 silc_mp_get_str(KEY, 16, &ske->KEY);
1109 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1110 ske->pk_len + e_len + f_len + KEY_len);
1111 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1113 /* Format the buffer used to compute the hash value */
1114 silc_buffer_format(buf,
1115 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1116 ske->start_payload_copy->len),
1117 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1118 SILC_STR_UI_XNSTRING(e, e_len),
1119 SILC_STR_UI_XNSTRING(f, f_len),
1120 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1124 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1128 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1129 *return_hash_len = ske->prop->hash->hash->hash_len;
1131 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1133 silc_buffer_free(buf);
1134 memset(e, 0, e_len);
1135 memset(f, 0, f_len);
1136 memset(KEY, 0, KEY_len);
1144 /* Processes negotiated key material as protocol specifies. This returns
1145 the actual keys to be used in the SILC. */
1147 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1148 unsigned int req_iv_len,
1149 unsigned int req_enc_key_len,
1150 unsigned int req_hmac_key_len,
1151 SilcSKEKeyMaterial *key)
1156 unsigned char *tmpbuf;
1157 unsigned char hash[32];
1158 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1159 unsigned int enc_key_len = req_enc_key_len / 8;
1161 SILC_LOG_DEBUG(("Start"));
1163 silc_mp_init_set(&tmp, &ske->KEY);
1165 klen = silc_mp_size(&tmp);
1167 /* Format the KEY material into binary data */
1168 tmpbuf = silc_calloc(klen, sizeof(unsigned char));
1169 for (i = klen; i > 0; i--) {
1170 tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
1171 silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
1174 buf = silc_buffer_alloc(1 + klen + hash_len);
1176 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1177 silc_buffer_format(buf,
1178 SILC_STR_UI_CHAR(0),
1179 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1180 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1184 memset(hash, 0, sizeof(hash));
1186 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1187 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1188 memcpy(key->send_iv, hash, req_iv_len);
1189 memset(hash, 0, sizeof(hash));
1191 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1192 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1193 memcpy(key->receive_iv, hash, req_iv_len);
1194 key->iv_len = req_iv_len;
1196 /* Take the encryption keys. If requested key size is more than
1197 the size of hash length we will distribute more key material
1198 as protocol defines. */
1200 if (enc_key_len > hash_len) {
1202 unsigned char k1[32], k2[32], k3[32];
1203 unsigned char *dtmp;
1206 if (enc_key_len > (3 * hash_len))
1207 return SILC_SKE_STATUS_ERROR;
1209 memset(k1, 0, sizeof(k1));
1210 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1213 dist = silc_buffer_alloc(hash_len * 3);
1215 silc_buffer_pull_tail(dist, klen + hash_len);
1216 silc_buffer_format(dist,
1217 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1218 SILC_STR_UI_XNSTRING(k1, hash_len),
1221 memset(k2, 0, sizeof(k2));
1222 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1224 silc_buffer_pull(dist, klen + hash_len);
1225 silc_buffer_format(dist,
1226 SILC_STR_UI_XNSTRING(k2, hash_len),
1228 silc_buffer_push(dist, klen + hash_len);
1230 memset(k3, 0, sizeof(k3));
1231 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1233 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1234 memcpy(dtmp, k1, hash_len);
1235 memcpy(dtmp + hash_len, k2, hash_len);
1236 memcpy(dtmp + hash_len, k3, hash_len);
1238 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1239 memcpy(key->send_enc_key, dtmp, enc_key_len);
1240 key->enc_key_len = req_enc_key_len;
1242 memset(dtmp, 0, (3 * hash_len));
1243 memset(k1, 0, sizeof(k1));
1244 memset(k2, 0, sizeof(k2));
1245 memset(k3, 0, sizeof(k3));
1247 silc_buffer_free(dist);
1249 /* Take normal hash as key */
1250 memset(hash, 0, sizeof(hash));
1251 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1252 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1253 memcpy(key->send_enc_key, hash, enc_key_len);
1254 key->enc_key_len = req_enc_key_len;
1258 if (enc_key_len > hash_len) {
1260 unsigned char k1[32], k2[32], k3[32];
1261 unsigned char *dtmp;
1264 if (enc_key_len > (3 * hash_len))
1265 return SILC_SKE_STATUS_ERROR;
1267 memset(k1, 0, sizeof(k1));
1268 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1271 dist = silc_buffer_alloc(hash_len * 3);
1273 silc_buffer_pull_tail(dist, klen + hash_len);
1274 silc_buffer_format(dist,
1275 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1276 SILC_STR_UI_XNSTRING(k1, hash_len),
1279 memset(k2, 0, sizeof(k2));
1280 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1282 silc_buffer_pull(dist, klen + hash_len);
1283 silc_buffer_format(dist,
1284 SILC_STR_UI_XNSTRING(k2, hash_len),
1286 silc_buffer_push(dist, klen + hash_len);
1288 memset(k3, 0, sizeof(k3));
1289 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1291 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1292 memcpy(dtmp, k1, hash_len);
1293 memcpy(dtmp + hash_len, k2, hash_len);
1294 memcpy(dtmp + hash_len, k3, hash_len);
1296 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1297 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1298 key->enc_key_len = req_enc_key_len;
1300 memset(dtmp, 0, (3 * hash_len));
1301 memset(k1, 0, sizeof(k1));
1302 memset(k2, 0, sizeof(k2));
1303 memset(k3, 0, sizeof(k3));
1305 silc_buffer_free(dist);
1307 /* Take normal hash as key */
1308 memset(hash, 0, sizeof(hash));
1309 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1310 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1311 memcpy(key->receive_enc_key, hash, enc_key_len);
1312 key->enc_key_len = req_enc_key_len;
1316 memset(hash, 0, sizeof(hash));
1318 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1319 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1320 memcpy(key->hmac_key, hash, req_hmac_key_len);
1321 key->hmac_key_len = req_hmac_key_len;
1323 memset(tmpbuf, 0, klen);
1326 return SILC_SKE_STATUS_OK;