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.5 2000/07/10 05:34:22 priikone
24 * Added mp binary encoding as protocols defines.
26 * Revision 1.4 2000/07/07 06:46:43 priikone
27 * Removed ske_verify_public_key function as it is not needed
28 * anymore. Added support to the public key verification as callback
29 * function. Other minor changes and bug fixes.
31 * Revision 1.3 2000/07/06 07:12:39 priikone
32 * Support for SILC style public keys added.
34 * Revision 1.2 2000/07/05 06:05:15 priikone
35 * Global cosmetic change.
37 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
38 * Imported from internal CVS/Added Log headers.
43 #include "silcincludes.h"
44 #include "payload_internal.h"
45 #include "groups_internal.h"
47 /* Allocates new SKE object. */
49 SilcSKE silc_ske_alloc()
53 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
55 ske = silc_calloc(1, sizeof(*ske));
60 /* Free's SKE object. */
62 void silc_ske_free(SilcSKE ske)
64 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
67 /* Free start payload */
68 if (ske->start_payload)
69 silc_ske_payload_start_free(ske->start_payload);
71 /* Free KE1 payload */
73 silc_ske_payload_one_free(ske->ke1_payload);
75 /* Free KE2 payload */
77 silc_ske_payload_two_free(ske->ke2_payload);
82 silc_free(ske->prop->group);
84 silc_pkcs_free(ske->prop->pkcs);
85 if (ske->prop->cipher)
86 silc_cipher_free(ske->prop->cipher);
88 silc_hash_free(ske->prop->hash);
91 if (ske->start_payload_copy)
92 silc_buffer_free(ske->start_payload_copy);
96 silc_mp_clear(&ske->x);
97 silc_mp_clear(&ske->KEY);
100 silc_free(ske->hash);
105 /* Starts the SILC Key Exchange protocol for initiator. The connection
106 to the remote end must be established before calling this function
107 and the connecting socket must be sent as argument. This function
108 creates the Key Exchange Start Paload which includes all our
109 configured security properties. This payload is then sent to the
110 remote end for further processing. This payload must be sent as
111 argument to the function, however, it must not be encoded
112 already, it is done by this function.
114 The packet sending is done by calling a callback function. Caller
115 must provide a routine to send the packet. */
117 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
118 SilcSocketConnection sock,
119 SilcSKEStartPayload *start_payload,
120 SilcSKESendPacketCb send_packet,
123 SilcSKEStatus status = SILC_SKE_STATUS_OK;
124 SilcBuffer payload_buf;
126 SILC_LOG_DEBUG(("Start"));
131 /* Encode the payload */
132 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
133 if (status != SILC_SKE_STATUS_OK)
136 /* Take a copy of the payload buffer for future use. It is used to
137 compute the HASH value. */
138 ske->start_payload_copy = silc_buffer_copy(payload_buf);
140 /* Send the packet. */
142 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
144 silc_buffer_free(payload_buf);
149 /* Function called after ske_initiator_start fuction. This receives
150 the remote ends Key Exchange Start payload which includes the
151 security properties selected by the responder from our payload
152 sent in the silc_ske_initiator_start function. */
154 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
155 SilcBuffer start_payload,
159 SilcSKEStatus status = SILC_SKE_STATUS_OK;
160 SilcSKEStartPayload *payload;
161 SilcSKESecurityProperties prop;
162 SilcSKEDiffieHellmanGroup group;
164 SILC_LOG_DEBUG(("Start"));
166 /* Decode the payload */
167 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
168 if (status != SILC_SKE_STATUS_OK)
171 /* Take the selected security properties into use while doing
172 the key exchange. This is used only while doing the key
173 exchange. The same data is returned to upper levels by calling
174 the callback function. */
175 ske->prop = prop = silc_calloc(1, sizeof(*prop));
176 prop->flags = payload->flags;
177 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
178 if (status != SILC_SKE_STATUS_OK)
183 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
184 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
188 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
189 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
193 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
194 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
198 ske->start_payload = payload;
200 /* Return the received payload by calling the callback function. */
202 (*callback)(ske, context);
208 silc_ske_payload_start_free(payload);
213 silc_pkcs_free(prop->pkcs);
215 silc_cipher_free(prop->cipher);
217 silc_hash_free(prop->hash);
221 if (status == SILC_SKE_STATUS_OK)
222 return SILC_SKE_STATUS_ERROR;
227 /* This function creates random number x, such that 1 < x < q and
228 computes e = g ^ x mod p and sends the result to the remote end in
229 Key Exchange 1 Payload. */
231 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
232 SilcSKESendPacketCb send_packet,
235 SilcSKEStatus status = SILC_SKE_STATUS_OK;
236 SilcBuffer payload_buf;
238 SilcSKEOnePayload *payload;
240 SILC_LOG_DEBUG(("Start"));
242 /* Create the random number x, 1 < x < q. */
245 silc_ske_create_rnd(ske, ske->prop->group->group_order,
246 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
248 if (status != SILC_SKE_STATUS_OK) {
253 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
255 /* Do the Diffie Hellman computation, e = g ^ x mod p */
257 silc_mp_powm(&e, &ske->prop->group->generator, &x,
258 &ske->prop->group->group);
260 /* Encode the result to Key Exchange 1 Payload. */
261 payload = silc_calloc(1, sizeof(*payload));
263 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
264 if (status != SILC_SKE_STATUS_OK) {
271 ske->ke1_payload = payload;
274 /* Send the packet. */
276 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
278 silc_buffer_free(payload_buf);
283 /* Receives Key Exchange 2 Payload from responder consisting responders
284 public key, f, and signature. This function verifies the public key,
285 computes the secret shared key and verifies the signature. */
287 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
288 SilcBuffer ke2_payload,
289 SilcSKEVerifyCb verify_key,
290 void *verify_context,
294 SilcSKEStatus status = SILC_SKE_STATUS_OK;
295 SilcSKETwoPayload *payload;
296 SilcPublicKey public_key = NULL;
298 unsigned char hash[32];
299 unsigned int hash_len;
301 SILC_LOG_DEBUG(("Start"));
303 /* Decode the payload */
304 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
305 if (status != SILC_SKE_STATUS_OK)
307 ske->ke2_payload = payload;
309 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
311 /* Compute the shared secret key */
313 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
316 SILC_LOG_DEBUG(("Verifying public key"));
318 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
320 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
325 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
326 payload->pk_type, verify_context);
327 if (status != SILC_SKE_STATUS_OK)
331 SILC_LOG_DEBUG(("Public key is authentic"));
333 /* Compute the hash value */
334 status = silc_ske_make_hash(ske, hash, &hash_len);
335 if (status != SILC_SKE_STATUS_OK)
338 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
339 memcpy(ske->hash, hash, hash_len);
340 ske->hash_len = hash_len;
342 SILC_LOG_DEBUG(("Verifying signature"));
344 /* Verify signature */
345 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
347 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
348 payload->sign_data, payload->sign_len,
349 hash, hash_len) == FALSE) {
351 SILC_LOG_DEBUG(("Signature don't match"));
353 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
357 SILC_LOG_DEBUG(("Signature is Ok"));
359 silc_pkcs_public_key_free(public_key);
360 memset(hash, 'F', hash_len);
362 /* Call the callback. */
364 (*callback)(ske, context);
369 memset(hash, 'F', sizeof(hash));
370 silc_ske_payload_two_free(payload);
371 ske->ke2_payload = NULL;
373 silc_mp_clear(&ske->KEY);
376 silc_pkcs_public_key_free(public_key);
379 memset(ske->hash, 'F', hash_len);
380 silc_free(ske->hash);
384 if (status == SILC_SKE_STATUS_OK)
385 return SILC_SKE_STATUS_ERROR;
390 /* Starts Key Exchange protocol for responder. Responder receives
391 Key Exchange Start Payload from initiator consisting of all the
392 security properties the initiator supports. This function decodes
393 the payload and parses the payload further and selects the right
394 security properties. */
396 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
397 SilcSocketConnection sock,
398 SilcBuffer start_payload,
402 SilcSKEStatus status = SILC_SKE_STATUS_OK;
403 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
405 SILC_LOG_DEBUG(("Start"));
410 /* Decode the payload */
411 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
412 if (status != SILC_SKE_STATUS_OK)
415 /* Take a copy of the payload buffer for future use. It is used to
416 compute the HASH value. */
417 ske->start_payload_copy = silc_buffer_copy(start_payload);
419 /* Parse and select the security properties from the payload */
420 payload = silc_calloc(1, sizeof(*payload));
421 status = silc_ske_select_security_properties(ske, payload, remote_payload);
422 if (status != SILC_SKE_STATUS_OK)
425 ske->start_payload = payload;
427 /* Call the callback function. */
429 (*callback)(ske, context);
435 silc_ske_payload_start_free(remote_payload);
439 if (status == SILC_SKE_STATUS_OK)
440 return SILC_SKE_STATUS_ERROR;
445 /* The selected security properties from the initiator payload is now
446 encoded into Key Exchange Start Payload and sent to the initiator. */
448 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
449 SilcSKEStartPayload *start_payload,
450 SilcSKESendPacketCb send_packet,
453 SilcSKEStatus status = SILC_SKE_STATUS_OK;
454 SilcBuffer payload_buf;
455 SilcSKESecurityProperties prop;
456 SilcSKEDiffieHellmanGroup group;
458 SILC_LOG_DEBUG(("Start"));
460 /* Allocate security properties from the payload. These are allocated
461 only for this negotiation and will be free'd after KE is over. */
462 ske->prop = prop = silc_calloc(1, sizeof(*prop));
463 prop->flags = start_payload->flags;
464 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
465 if (status != SILC_SKE_STATUS_OK)
470 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
471 &prop->pkcs) == FALSE) {
472 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
476 if (silc_cipher_alloc(start_payload->enc_alg_list,
477 &prop->cipher) == FALSE) {
478 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
482 if (silc_hash_alloc(start_payload->hash_alg_list,
483 &prop->hash) == FALSE) {
484 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
488 /* Encode the payload */
489 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
490 if (status != SILC_SKE_STATUS_OK)
493 /* Send the packet. */
495 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
497 silc_buffer_free(payload_buf);
505 silc_pkcs_free(prop->pkcs);
507 silc_cipher_free(prop->cipher);
509 silc_hash_free(prop->hash);
513 if (status == SILC_SKE_STATUS_OK)
514 return SILC_SKE_STATUS_ERROR;
519 /* This function receives the Key Exchange 1 Payload from the initiator.
520 After processing the payload this then selects random number x,
521 such that 1 < x < q and computes f = g ^ x mod p. This then puts
522 the result f to a Key Exchange 2 Payload which is later processed
523 in ske_responder_finish function. The callback function should
524 not touch the payload (it should merely call the ske_responder_finish
527 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
528 SilcBuffer ke1_payload,
532 SilcSKEStatus status = SILC_SKE_STATUS_OK;
533 SilcSKEOnePayload *one_payload;
534 SilcSKETwoPayload *two_payload;
537 SILC_LOG_DEBUG(("Start"));
539 /* Decode Key Exchange 1 Payload */
540 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
541 if (status != SILC_SKE_STATUS_OK)
544 /* Create the random number x, 1 < x < q. */
547 silc_ske_create_rnd(ske, ske->prop->group->group_order,
548 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
550 if (status != SILC_SKE_STATUS_OK) {
555 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
557 /* Do the Diffie Hellman computation, f = g ^ x mod p */
559 silc_mp_powm(&f, &ske->prop->group->generator, &x,
560 &ske->prop->group->group);
562 /* Save the results for later processing */
563 two_payload = silc_calloc(1, sizeof(*two_payload));
566 ske->ke1_payload = one_payload;
567 ske->ke2_payload = two_payload;
569 /* Call the callback. */
571 (*callback)(ske, context);
576 /* This function computes the secret shared key KEY = e ^ x mod p, and,
577 a hash value to be signed and sent to the other end. This then
578 encodes Key Exchange 2 Payload and sends it to the other end. */
580 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
581 SilcPublicKey public_key,
582 SilcPrivateKey private_key,
583 SilcSKEPKType pk_type,
584 SilcSKESendPacketCb send_packet,
587 SilcSKEStatus status = SILC_SKE_STATUS_OK;
588 SilcBuffer payload_buf;
590 unsigned char hash[32], sign[256], *pk;
591 unsigned int hash_len, sign_len, pk_len;
593 SILC_LOG_DEBUG(("Start"));
595 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
597 /* Compute the shared secret key */
599 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
600 &ske->prop->group->group);
603 SILC_LOG_DEBUG(("Getting public key"));
605 /* Get the public key */
606 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
607 ske->ke2_payload->pk_data = pk;
608 ske->ke2_payload->pk_len = pk_len;
609 ske->ke2_payload->pk_type = pk_type;
611 SILC_LOG_DEBUG(("Computing HASH value"));
613 /* Compute the hash value */
614 memset(hash, 0, sizeof(hash));
615 status = silc_ske_make_hash(ske, hash, &hash_len);
616 if (status != SILC_SKE_STATUS_OK)
619 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
620 memcpy(ske->hash, hash, hash_len);
621 ske->hash_len = hash_len;
623 SILC_LOG_DEBUG(("Signing HASH value"));
625 /* Sign the hash value */
626 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
627 private_key->prv_len);
628 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
631 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
632 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
633 memset(sign, 0, sizeof(sign));
634 ske->ke2_payload->sign_len = sign_len;
636 /* Encode the Key Exchange 2 Payload */
637 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
639 if (status != SILC_SKE_STATUS_OK)
642 /* Send the packet. */
644 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
646 silc_buffer_free(payload_buf);
651 silc_mp_clear(&ske->KEY);
652 silc_ske_payload_two_free(ske->ke2_payload);
654 if (status == SILC_SKE_STATUS_OK)
655 return SILC_SKE_STATUS_ERROR;
660 /* The Key Exchange protocol is ended by calling this function. This
661 must not be called until the keys are processed like the protocol
662 defines. This function is for both initiator and responder. */
664 SilcSKEStatus silc_ske_end(SilcSKE ske,
665 SilcSKESendPacketCb send_packet,
668 SilcSKEStatus status = SILC_SKE_STATUS_OK;
671 SILC_LOG_DEBUG(("Start"));
673 packet = silc_buffer_alloc(1);
677 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
682 /* Aborts the Key Exchange protocol. This is called if error occurs
683 while performing the protocol. The status argument is the error
684 status and it is sent to the remote end. */
686 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
687 SilcSKESendPacketCb send_packet,
692 SILC_LOG_DEBUG(("Start"));
694 packet = silc_buffer_alloc(4);
695 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
696 silc_buffer_format(packet,
697 SILC_STR_UI_SHORT(status),
701 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
703 silc_buffer_free(packet);
705 return SILC_SKE_STATUS_OK;
708 /* Assembles security properties to Key Exchange Start Payload to be
709 sent to the remote end. This checks system wide (SILC system, that is)
710 settings and chooses from those. However, if other properties
711 should be used this function is easy to replace by another function,
712 as, this function is called by the caller of the protocol and not
713 by the protocol itself. */
716 silc_ske_assemble_security_properties(SilcSKE ske,
717 SilcSKEStartPayload **return_payload)
719 SilcSKEStartPayload *rp;
721 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
723 rp = silc_calloc(1, sizeof(*rp));
731 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
732 rp->cookie_len = SILC_SKE_COOKIE_LEN;
733 memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
735 /* Get supported Key Exhange groups */
736 rp->ke_grp_list = silc_ske_get_supported_groups();
737 rp->ke_grp_len = strlen(rp->ke_grp_list);
739 /* Get supported PKCS algorithms */
740 rp->pkcs_alg_list = silc_pkcs_get_supported();
741 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
743 /* Get supported encryption algorithms */
744 rp->enc_alg_list = silc_cipher_get_supported();
745 rp->enc_alg_len = strlen(rp->enc_alg_list);
747 /* Get supported hash algorithms */
748 rp->hash_alg_list = silc_hash_get_supported();
749 rp->hash_alg_len = strlen(rp->hash_alg_list);
752 /* Get supported compression algorithms */
753 rp->comp_alg_list = "";
754 rp->comp_alg_len = 0;
756 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
757 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
758 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
759 2 + rp->comp_alg_len;
761 *return_payload = rp;
763 return SILC_SKE_STATUS_OK;
766 /* Selects the supported security properties from the remote end's Key
767 Exchange Start Payload. */
770 silc_ske_select_security_properties(SilcSKE ske,
771 SilcSKEStartPayload *payload,
772 SilcSKEStartPayload *remote_payload)
774 SilcSKEStartPayload *rp;
778 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
782 /* Flags are returned unchanged. */
783 payload->flags = rp->flags;
785 /* XXX Cookie check?? */
786 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
787 payload->cookie_len = SILC_SKE_COOKIE_LEN;
788 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
790 /* Get supported Key Exchange groups */
791 cp = rp->ke_grp_list;
792 if (cp && strchr(cp, ',')) {
796 len = strcspn(cp, ",");
797 item = silc_calloc(len + 1, sizeof(char));
798 memcpy(item, cp, len);
800 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
802 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
803 SILC_LOG_DEBUG(("Found KE group `%s'", item));
805 payload->ke_grp_len = len;
806 payload->ke_grp_list = item;
820 if (!payload->ke_grp_len && !payload->ke_grp_list) {
821 SILC_LOG_DEBUG(("Could not find supported KE group"));
823 return SILC_SKE_STATUS_UNKNOWN_GROUP;
827 if (!rp->ke_grp_len) {
828 SILC_LOG_DEBUG(("KE group not defined in payload"));
830 return SILC_SKE_STATUS_BAD_PAYLOAD;
833 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
834 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
836 payload->ke_grp_len = rp->ke_grp_len;
837 payload->ke_grp_list = strdup(rp->ke_grp_list);
840 /* Get supported PKCS algorithms */
841 cp = rp->pkcs_alg_list;
842 if (cp && strchr(cp, ',')) {
846 len = strcspn(cp, ",");
847 item = silc_calloc(len + 1, sizeof(char));
848 memcpy(item, cp, len);
850 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
852 if (silc_pkcs_is_supported(item) == TRUE) {
853 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
855 payload->pkcs_alg_len = len;
856 payload->pkcs_alg_list = item;
870 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
871 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
872 silc_free(payload->ke_grp_list);
874 return SILC_SKE_STATUS_UNKNOWN_PKCS;
878 if (!rp->pkcs_alg_len) {
879 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
880 silc_free(payload->ke_grp_list);
882 return SILC_SKE_STATUS_BAD_PAYLOAD;
885 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
886 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
888 payload->pkcs_alg_len = rp->pkcs_alg_len;
889 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
892 /* Get supported encryption algorithms */
893 cp = rp->enc_alg_list;
894 if (cp && strchr(cp, ',')) {
898 len = strcspn(cp, ",");
899 item = silc_calloc(len + 1, sizeof(char));
900 memcpy(item, cp, len);
902 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
904 if (silc_cipher_is_supported(item) == TRUE) {
905 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
907 payload->enc_alg_len = len;
908 payload->enc_alg_list = item;
922 if (!payload->enc_alg_len && !payload->enc_alg_list) {
923 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
924 silc_free(payload->ke_grp_list);
925 silc_free(payload->pkcs_alg_list);
927 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
931 if (!rp->enc_alg_len) {
932 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
933 silc_free(payload->ke_grp_list);
934 silc_free(payload->pkcs_alg_list);
936 return SILC_SKE_STATUS_BAD_PAYLOAD;
939 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
942 payload->enc_alg_len = rp->enc_alg_len;
943 payload->enc_alg_list = strdup(rp->enc_alg_list);
946 /* Get supported hash algorithms */
947 cp = rp->hash_alg_list;
948 if (cp && strchr(cp, ',')) {
952 len = strcspn(cp, ",");
953 item = silc_calloc(len + 1, sizeof(char));
954 memcpy(item, cp, len);
956 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
958 if (silc_hash_is_supported(item) == TRUE) {
959 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
961 payload->hash_alg_len = len;
962 payload->hash_alg_list = item;
976 if (!payload->hash_alg_len && !payload->hash_alg_list) {
977 SILC_LOG_DEBUG(("Could not find supported hash alg"));
978 silc_free(payload->ke_grp_list);
979 silc_free(payload->pkcs_alg_list);
980 silc_free(payload->enc_alg_list);
982 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
986 if (!rp->hash_alg_len) {
987 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
988 silc_free(payload->ke_grp_list);
989 silc_free(payload->pkcs_alg_list);
990 silc_free(payload->enc_alg_list);
992 return SILC_SKE_STATUS_BAD_PAYLOAD;
995 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
998 payload->hash_alg_len = rp->hash_alg_len;
999 payload->hash_alg_list = strdup(rp->hash_alg_list);
1003 /* Get supported compression algorithms */
1004 cp = rp->hash_alg_list;
1005 if (cp && strchr(cp, ',')) {
1009 len = strcspn(cp, ",");
1010 item = silc_calloc(len + 1, sizeof(char));
1011 memcpy(item, cp, len);
1013 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1015 if (silc_hash_is_supported(item) == TRUE) {
1016 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1018 payload->hash_alg_len = len;
1019 payload->hash_alg_list = item;
1024 if (strlen(cp) == 0)
1033 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1034 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1035 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1036 silc_free(payload->ke_grp_list);
1037 silc_free(payload->pkcs_alg_list);
1038 silc_free(payload->enc_alg_list);
1047 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1048 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1049 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1050 2 + payload->comp_alg_len;
1052 return SILC_SKE_STATUS_OK;
1055 /* Creates random number such that 1 < rnd < n and at most length
1056 of len bits. The rnd sent as argument must be initialized. */
1058 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1062 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1063 unsigned char *string;
1065 SILC_LOG_DEBUG(("Creating random number"));
1067 /* Get the random number as string */
1068 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1070 /* Decode the string into a MP integer */
1071 silc_mp_bin2mp(string, (len / 8), rnd);
1072 silc_mp_mod_2exp(rnd, rnd, len);
1075 if (silc_mp_cmp_ui(rnd, 1) < 0)
1076 status = SILC_SKE_STATUS_ERROR;
1078 if (silc_mp_cmp(rnd, &n) >= 0)
1079 status = SILC_SKE_STATUS_ERROR;
1081 memset(string, 'F', (len / 8));
1087 /* Creates a hash value HASH as defined in the SKE protocol. */
1089 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1090 unsigned char *return_hash,
1091 unsigned int *return_hash_len)
1093 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1095 unsigned char *e, *f, *KEY;
1096 unsigned int e_len, f_len, KEY_len;
1098 SILC_LOG_DEBUG(("Start"));
1100 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1101 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1102 KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1104 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1105 ske->pk_len + e_len + f_len + KEY_len);
1106 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1108 /* Format the buffer used to compute the hash value */
1109 silc_buffer_format(buf,
1110 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1111 ske->start_payload_copy->len),
1112 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1113 SILC_STR_UI_XNSTRING(e, e_len),
1114 SILC_STR_UI_XNSTRING(f, f_len),
1115 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1119 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1123 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1124 *return_hash_len = ske->prop->hash->hash->hash_len;
1126 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1128 silc_buffer_free(buf);
1129 memset(e, 0, e_len);
1130 memset(f, 0, f_len);
1131 memset(KEY, 0, KEY_len);
1139 /* Processes negotiated key material as protocol specifies. This returns
1140 the actual keys to be used in the SILC. */
1142 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1143 unsigned int req_iv_len,
1144 unsigned int req_enc_key_len,
1145 unsigned int req_hmac_key_len,
1146 SilcSKEKeyMaterial *key)
1150 unsigned char *tmpbuf;
1151 unsigned char hash[32];
1152 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1153 unsigned int enc_key_len = req_enc_key_len / 8;
1155 SILC_LOG_DEBUG(("Start"));
1157 /* Encode KEY to binary data */
1158 tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1160 buf = silc_buffer_alloc(1 + klen + hash_len);
1161 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1162 silc_buffer_format(buf,
1163 SILC_STR_UI_CHAR(0),
1164 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1165 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1169 memset(hash, 0, sizeof(hash));
1171 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1172 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1173 memcpy(key->send_iv, hash, req_iv_len);
1174 memset(hash, 0, sizeof(hash));
1176 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1177 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1178 memcpy(key->receive_iv, hash, req_iv_len);
1179 key->iv_len = req_iv_len;
1181 /* Take the encryption keys. If requested key size is more than
1182 the size of hash length we will distribute more key material
1183 as protocol defines. */
1185 if (enc_key_len > hash_len) {
1187 unsigned char k1[32], k2[32], k3[32];
1188 unsigned char *dtmp;
1191 if (enc_key_len > (3 * hash_len))
1192 return SILC_SKE_STATUS_ERROR;
1194 memset(k1, 0, sizeof(k1));
1195 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1198 dist = silc_buffer_alloc(hash_len * 3);
1200 silc_buffer_pull_tail(dist, klen + hash_len);
1201 silc_buffer_format(dist,
1202 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1203 SILC_STR_UI_XNSTRING(k1, hash_len),
1206 memset(k2, 0, sizeof(k2));
1207 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1209 silc_buffer_pull(dist, klen + hash_len);
1210 silc_buffer_format(dist,
1211 SILC_STR_UI_XNSTRING(k2, hash_len),
1213 silc_buffer_push(dist, klen + hash_len);
1215 memset(k3, 0, sizeof(k3));
1216 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1218 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1219 memcpy(dtmp, k1, hash_len);
1220 memcpy(dtmp + hash_len, k2, hash_len);
1221 memcpy(dtmp + hash_len, k3, hash_len);
1223 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1224 memcpy(key->send_enc_key, dtmp, enc_key_len);
1225 key->enc_key_len = req_enc_key_len;
1227 memset(dtmp, 0, (3 * hash_len));
1228 memset(k1, 0, sizeof(k1));
1229 memset(k2, 0, sizeof(k2));
1230 memset(k3, 0, sizeof(k3));
1232 silc_buffer_free(dist);
1234 /* Take normal hash as key */
1235 memset(hash, 0, sizeof(hash));
1236 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1237 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1238 memcpy(key->send_enc_key, hash, enc_key_len);
1239 key->enc_key_len = req_enc_key_len;
1243 if (enc_key_len > hash_len) {
1245 unsigned char k1[32], k2[32], k3[32];
1246 unsigned char *dtmp;
1249 if (enc_key_len > (3 * hash_len))
1250 return SILC_SKE_STATUS_ERROR;
1252 memset(k1, 0, sizeof(k1));
1253 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1256 dist = silc_buffer_alloc(hash_len * 3);
1258 silc_buffer_pull_tail(dist, klen + hash_len);
1259 silc_buffer_format(dist,
1260 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1261 SILC_STR_UI_XNSTRING(k1, hash_len),
1264 memset(k2, 0, sizeof(k2));
1265 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1267 silc_buffer_pull(dist, klen + hash_len);
1268 silc_buffer_format(dist,
1269 SILC_STR_UI_XNSTRING(k2, hash_len),
1271 silc_buffer_push(dist, klen + hash_len);
1273 memset(k3, 0, sizeof(k3));
1274 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1276 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1277 memcpy(dtmp, k1, hash_len);
1278 memcpy(dtmp + hash_len, k2, hash_len);
1279 memcpy(dtmp + hash_len, k3, hash_len);
1281 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1282 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1283 key->enc_key_len = req_enc_key_len;
1285 memset(dtmp, 0, (3 * hash_len));
1286 memset(k1, 0, sizeof(k1));
1287 memset(k2, 0, sizeof(k2));
1288 memset(k3, 0, sizeof(k3));
1290 silc_buffer_free(dist);
1292 /* Take normal hash as key */
1293 memset(hash, 0, sizeof(hash));
1294 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1295 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1296 memcpy(key->receive_enc_key, hash, enc_key_len);
1297 key->enc_key_len = req_enc_key_len;
1301 memset(hash, 0, sizeof(hash));
1303 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1304 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1305 memcpy(key->hmac_key, hash, req_hmac_key_len);
1306 key->hmac_key_len = req_hmac_key_len;
1308 memset(tmpbuf, 0, klen);
1311 return SILC_SKE_STATUS_OK;