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.
22 #include "silcincludes.h"
23 #include "payload_internal.h"
24 #include "groups_internal.h"
26 /* Allocates new SKE object. */
28 SilcSKE silc_ske_alloc()
32 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
34 ske = silc_calloc(1, sizeof(*ske));
35 ske->status = SILC_SKE_STATUS_OK;
40 /* Free's SKE object. */
42 void silc_ske_free(SilcSKE ske)
44 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
47 /* Free start payload */
48 if (ske->start_payload)
49 silc_ske_payload_start_free(ske->start_payload);
51 /* Free KE1 payload */
53 silc_ske_payload_one_free(ske->ke1_payload);
55 /* Free KE2 payload */
57 silc_ske_payload_two_free(ske->ke2_payload);
62 silc_free(ske->prop->group);
64 silc_pkcs_free(ske->prop->pkcs);
65 if (ske->prop->cipher)
66 silc_cipher_free(ske->prop->cipher);
68 silc_hash_free(ske->prop->hash);
71 if (ske->start_payload_copy)
72 silc_buffer_free(ske->start_payload_copy);
76 silc_mp_clear(&ske->x);
77 silc_mp_clear(&ske->KEY);
85 /* Starts the SILC Key Exchange protocol for initiator. The connection
86 to the remote end must be established before calling this function
87 and the connecting socket must be sent as argument. This function
88 creates the Key Exchange Start Paload which includes all our
89 configured security properties. This payload is then sent to the
90 remote end for further processing. This payload must be sent as
91 argument to the function, however, it must not be encoded
92 already, it is done by this function.
94 The packet sending is done by calling a callback function. Caller
95 must provide a routine to send the packet. */
97 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
98 SilcSocketConnection sock,
99 SilcSKEStartPayload *start_payload,
100 SilcSKESendPacketCb send_packet,
103 SilcSKEStatus status = SILC_SKE_STATUS_OK;
104 SilcBuffer payload_buf;
106 SILC_LOG_DEBUG(("Start"));
111 /* Encode the payload */
112 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
113 if (status != SILC_SKE_STATUS_OK)
116 /* Take a copy of the payload buffer for future use. It is used to
117 compute the HASH value. */
118 ske->start_payload_copy = silc_buffer_copy(payload_buf);
120 /* Send the packet. */
122 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
124 silc_buffer_free(payload_buf);
129 /* Function called after ske_initiator_start fuction. This receives
130 the remote ends Key Exchange Start payload which includes the
131 security properties selected by the responder from our payload
132 sent in the silc_ske_initiator_start function. */
134 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
135 SilcBuffer start_payload,
139 SilcSKEStatus status = SILC_SKE_STATUS_OK;
140 SilcSKEStartPayload *payload;
141 SilcSKESecurityProperties prop;
142 SilcSKEDiffieHellmanGroup group;
144 SILC_LOG_DEBUG(("Start"));
146 /* Decode the payload */
147 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
148 if (status != SILC_SKE_STATUS_OK)
151 /* Take the selected security properties into use while doing
152 the key exchange. This is used only while doing the key
153 exchange. The same data is returned to upper levels by calling
154 the callback function. */
155 ske->prop = prop = silc_calloc(1, sizeof(*prop));
156 prop->flags = payload->flags;
157 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
158 if (status != SILC_SKE_STATUS_OK)
163 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
164 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
168 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
169 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
173 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
174 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
178 ske->start_payload = payload;
180 /* Return the received payload by calling the callback function. */
182 (*callback)(ske, context);
188 silc_ske_payload_start_free(payload);
193 silc_pkcs_free(prop->pkcs);
195 silc_cipher_free(prop->cipher);
197 silc_hash_free(prop->hash);
201 if (status == SILC_SKE_STATUS_OK)
202 return SILC_SKE_STATUS_ERROR;
204 ske->status = status;
208 /* This function creates random number x, such that 1 < x < q and
209 computes e = g ^ x mod p and sends the result to the remote end in
210 Key Exchange 1 Payload. */
212 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
213 SilcPublicKey public_key,
214 SilcSKESendPacketCb send_packet,
217 SilcSKEStatus status = SILC_SKE_STATUS_OK;
218 SilcBuffer payload_buf;
220 SilcSKEOnePayload *payload;
223 SILC_LOG_DEBUG(("Start"));
225 /* Create the random number x, 1 < x < q. */
228 silc_ske_create_rnd(ske, ske->prop->group->group_order,
229 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
231 if (status != SILC_SKE_STATUS_OK) {
236 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
238 /* Do the Diffie Hellman computation, e = g ^ x mod p */
240 silc_mp_powm(&e, &ske->prop->group->generator, &x,
241 &ske->prop->group->group);
243 /* Encode the result to Key Exchange 1 Payload. */
244 payload = silc_calloc(1, sizeof(*payload));
246 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
247 payload->pk_len = pk_len;
248 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
249 status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
250 if (status != SILC_SKE_STATUS_OK) {
257 ske->ke1_payload = payload;
260 /* Send the packet. */
262 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
264 silc_buffer_free(payload_buf);
269 /* Receives Key Exchange 2 Payload from responder consisting responders
270 public key, f, and signature. This function verifies the public key,
271 computes the secret shared key and verifies the signature. */
273 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
274 SilcBuffer ke2_payload,
275 SilcSKEVerifyCb verify_key,
276 void *verify_context,
280 SilcSKEStatus status = SILC_SKE_STATUS_OK;
281 SilcSKETwoPayload *payload;
282 SilcPublicKey public_key = NULL;
284 unsigned char hash[32];
285 unsigned int hash_len;
287 SILC_LOG_DEBUG(("Start"));
289 /* Decode the payload */
290 status = silc_ske_payload_two_decode(ske, ke2_payload, &payload);
291 if (status != SILC_SKE_STATUS_OK)
293 ske->ke2_payload = payload;
295 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
297 /* Compute the shared secret key */
299 silc_mp_powm(&KEY, &payload->f, &ske->x, &ske->prop->group->group);
302 SILC_LOG_DEBUG(("Verifying public key"));
304 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
306 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
311 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
312 payload->pk_type, verify_context);
313 if (status != SILC_SKE_STATUS_OK)
317 SILC_LOG_DEBUG(("Public key is authentic"));
319 /* Compute the hash value */
320 status = silc_ske_make_hash(ske, hash, &hash_len);
321 if (status != SILC_SKE_STATUS_OK)
324 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
325 memcpy(ske->hash, hash, hash_len);
326 ske->hash_len = hash_len;
328 SILC_LOG_DEBUG(("Verifying signature"));
330 /* Verify signature */
331 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
333 if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
334 payload->sign_data, payload->sign_len,
335 hash, hash_len) == FALSE) {
337 SILC_LOG_DEBUG(("Signature don't match"));
339 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
343 SILC_LOG_DEBUG(("Signature is Ok"));
345 silc_pkcs_public_key_free(public_key);
346 memset(hash, 'F', hash_len);
348 /* Call the callback. */
350 (*callback)(ske, context);
355 memset(hash, 'F', sizeof(hash));
356 silc_ske_payload_two_free(payload);
357 ske->ke2_payload = NULL;
359 silc_mp_clear(&ske->KEY);
362 silc_pkcs_public_key_free(public_key);
365 memset(ske->hash, 'F', hash_len);
366 silc_free(ske->hash);
370 if (status == SILC_SKE_STATUS_OK)
371 return SILC_SKE_STATUS_ERROR;
373 ske->status = status;
377 /* Starts Key Exchange protocol for responder. Responder receives
378 Key Exchange Start Payload from initiator consisting of all the
379 security properties the initiator supports. This function decodes
380 the payload and parses the payload further and selects the right
381 security properties. */
383 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
384 SilcSocketConnection sock,
386 SilcBuffer start_payload,
390 SilcSKEStatus status = SILC_SKE_STATUS_OK;
391 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
393 SILC_LOG_DEBUG(("Start"));
398 /* Decode the payload */
399 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
400 if (status != SILC_SKE_STATUS_OK)
403 /* Take a copy of the payload buffer for future use. It is used to
404 compute the HASH value. */
405 ske->start_payload_copy = silc_buffer_copy(start_payload);
407 /* Parse and select the security properties from the payload */
408 payload = silc_calloc(1, sizeof(*payload));
409 status = silc_ske_select_security_properties(ske, version,
410 payload, remote_payload);
411 if (status != SILC_SKE_STATUS_OK)
414 ske->start_payload = payload;
416 /* Call the callback function. */
418 (*callback)(ske, context);
424 silc_ske_payload_start_free(remote_payload);
428 if (status == SILC_SKE_STATUS_OK)
429 return SILC_SKE_STATUS_ERROR;
431 ske->status = status;
435 /* The selected security properties from the initiator payload is now
436 encoded into Key Exchange Start Payload and sent to the initiator. */
438 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
439 SilcSKEStartPayload *start_payload,
440 SilcSKESendPacketCb send_packet,
443 SilcSKEStatus status = SILC_SKE_STATUS_OK;
444 SilcBuffer payload_buf;
445 SilcSKESecurityProperties prop;
446 SilcSKEDiffieHellmanGroup group;
448 SILC_LOG_DEBUG(("Start"));
450 /* Allocate security properties from the payload. These are allocated
451 only for this negotiation and will be free'd after KE is over. */
452 ske->prop = prop = silc_calloc(1, sizeof(*prop));
453 prop->flags = start_payload->flags;
454 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
455 if (status != SILC_SKE_STATUS_OK)
460 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
461 &prop->pkcs) == FALSE) {
462 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
466 if (silc_cipher_alloc(start_payload->enc_alg_list,
467 &prop->cipher) == FALSE) {
468 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
472 if (silc_hash_alloc(start_payload->hash_alg_list,
473 &prop->hash) == FALSE) {
474 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
478 /* Encode the payload */
479 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
480 if (status != SILC_SKE_STATUS_OK)
483 /* Send the packet. */
485 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
487 silc_buffer_free(payload_buf);
495 silc_pkcs_free(prop->pkcs);
497 silc_cipher_free(prop->cipher);
499 silc_hash_free(prop->hash);
503 if (status == SILC_SKE_STATUS_OK)
504 return SILC_SKE_STATUS_ERROR;
506 ske->status = status;
510 /* This function receives the Key Exchange 1 Payload from the initiator.
511 After processing the payload this then selects random number x,
512 such that 1 < x < q and computes f = g ^ x mod p. This then puts
513 the result f to a Key Exchange 2 Payload which is later processed
514 in ske_responder_finish function. The callback function should
515 not touch the payload (it should merely call the ske_responder_finish
518 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
519 SilcBuffer ke1_payload,
523 SilcSKEStatus status = SILC_SKE_STATUS_OK;
524 SilcSKEOnePayload *one_payload;
525 SilcSKETwoPayload *two_payload;
528 SILC_LOG_DEBUG(("Start"));
530 /* Decode Key Exchange 1 Payload */
531 status = silc_ske_payload_one_decode(ske, ke1_payload, &one_payload);
532 if (status != SILC_SKE_STATUS_OK)
535 /* Create the random number x, 1 < x < q. */
538 silc_ske_create_rnd(ske, ske->prop->group->group_order,
539 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
541 if (status != SILC_SKE_STATUS_OK) {
546 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
548 /* Do the Diffie Hellman computation, f = g ^ x mod p */
550 silc_mp_powm(&f, &ske->prop->group->generator, &x,
551 &ske->prop->group->group);
553 /* Save the results for later processing */
554 two_payload = silc_calloc(1, sizeof(*two_payload));
557 ske->ke1_payload = one_payload;
558 ske->ke2_payload = two_payload;
560 /* Call the callback. */
562 (*callback)(ske, context);
567 /* This function computes the secret shared key KEY = e ^ x mod p, and,
568 a hash value to be signed and sent to the other end. This then
569 encodes Key Exchange 2 Payload and sends it to the other end. */
571 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
572 SilcPublicKey public_key,
573 SilcPrivateKey private_key,
574 SilcSKEPKType pk_type,
575 SilcSKESendPacketCb send_packet,
578 SilcSKEStatus status = SILC_SKE_STATUS_OK;
579 SilcBuffer payload_buf;
581 unsigned char hash[32], sign[256], *pk;
582 unsigned int hash_len, sign_len, pk_len;
584 SILC_LOG_DEBUG(("Start"));
586 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
588 /* Compute the shared secret key */
590 silc_mp_powm(&KEY, &ske->ke1_payload->e, &ske->x,
591 &ske->prop->group->group);
594 SILC_LOG_DEBUG(("Getting public key"));
596 /* Get the public key */
597 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
598 ske->ke2_payload->pk_data = pk;
599 ske->ke2_payload->pk_len = pk_len;
600 ske->ke2_payload->pk_type = pk_type;
602 SILC_LOG_DEBUG(("Computing HASH value"));
604 /* Compute the hash value */
605 memset(hash, 0, sizeof(hash));
606 status = silc_ske_make_hash(ske, hash, &hash_len);
607 if (status != SILC_SKE_STATUS_OK)
610 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
611 memcpy(ske->hash, hash, hash_len);
612 ske->hash_len = hash_len;
614 SILC_LOG_DEBUG(("Signing HASH value"));
616 /* Sign the hash value */
617 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
618 private_key->prv_len);
619 ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
622 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
623 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
624 memset(sign, 0, sizeof(sign));
625 ske->ke2_payload->sign_len = sign_len;
627 /* Encode the Key Exchange 2 Payload */
628 status = silc_ske_payload_two_encode(ske, ske->ke2_payload,
630 if (status != SILC_SKE_STATUS_OK)
633 /* Send the packet. */
635 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
637 silc_buffer_free(payload_buf);
642 silc_mp_clear(&ske->KEY);
643 silc_ske_payload_two_free(ske->ke2_payload);
645 if (status == SILC_SKE_STATUS_OK)
646 return SILC_SKE_STATUS_ERROR;
648 ske->status = status;
652 /* The Key Exchange protocol is ended by calling this function. This
653 must not be called until the keys are processed like the protocol
654 defines. This function is for both initiator and responder. */
656 SilcSKEStatus silc_ske_end(SilcSKE ske,
657 SilcSKESendPacketCb send_packet,
662 SILC_LOG_DEBUG(("Start"));
664 packet = silc_buffer_alloc(4);
665 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
666 silc_buffer_format(packet,
667 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
671 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
673 silc_buffer_free(packet);
675 return SILC_SKE_STATUS_OK;
678 /* Aborts the Key Exchange protocol. This is called if error occurs
679 while performing the protocol. The status argument is the error
680 status and it is sent to the remote end. */
682 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
683 SilcSKESendPacketCb send_packet,
688 SILC_LOG_DEBUG(("Start"));
690 packet = silc_buffer_alloc(4);
691 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
692 silc_buffer_format(packet,
693 SILC_STR_UI_SHORT(status),
697 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
699 silc_buffer_free(packet);
701 return SILC_SKE_STATUS_OK;
704 /* Assembles security properties to Key Exchange Start Payload to be
705 sent to the remote end. This checks system wide (SILC system, that is)
706 settings and chooses from those. However, if other properties
707 should be used this function is easy to replace by another function,
708 as, this function is called by the caller of the protocol and not
709 by the protocol itself. */
712 silc_ske_assemble_security_properties(SilcSKE ske,
715 SilcSKEStartPayload **return_payload)
717 SilcSKEStartPayload *rp;
720 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
722 rp = silc_calloc(1, sizeof(*rp));
727 /* Set random cookie */
728 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
729 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
730 rp->cookie[i] = silc_rng_get_byte(ske->rng);
731 rp->cookie_len = SILC_SKE_COOKIE_LEN;
734 rp->version = strdup(version);
735 rp->version_len = strlen(version);
737 /* Get supported Key Exhange groups */
738 rp->ke_grp_list = silc_ske_get_supported_groups();
739 rp->ke_grp_len = strlen(rp->ke_grp_list);
741 /* Get supported PKCS algorithms */
742 rp->pkcs_alg_list = silc_pkcs_get_supported();
743 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
745 /* Get supported encryption algorithms */
746 rp->enc_alg_list = silc_cipher_get_supported();
747 rp->enc_alg_len = strlen(rp->enc_alg_list);
749 /* Get supported hash algorithms */
750 rp->hash_alg_list = silc_hash_get_supported();
751 rp->hash_alg_len = strlen(rp->hash_alg_list);
754 /* Get supported compression algorithms */
755 rp->comp_alg_list = "";
756 rp->comp_alg_len = 0;
758 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
759 2 + rp->version_len +
760 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
761 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
762 2 + rp->comp_alg_len;
764 *return_payload = rp;
766 return SILC_SKE_STATUS_OK;
769 /* Selects the supported security properties from the remote end's Key
770 Exchange Start Payload. */
773 silc_ske_select_security_properties(SilcSKE ske,
775 SilcSKEStartPayload *payload,
776 SilcSKEStartPayload *remote_payload)
778 SilcSKEStatus status;
779 SilcSKEStartPayload *rp;
783 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
787 /* Check version string */
788 status = silc_ske_check_version(ske, rp->version, rp->version_len);
789 if (status != SILC_SKE_STATUS_OK)
792 /* Flags are returned unchanged. */
793 payload->flags = rp->flags;
796 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
797 payload->cookie_len = SILC_SKE_COOKIE_LEN;
798 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
800 /* Put our version to our reply */
801 payload->version = strdup(version);
802 payload->version_len = strlen(version);
804 /* Get supported Key Exchange groups */
805 cp = rp->ke_grp_list;
806 if (cp && strchr(cp, ',')) {
810 len = strcspn(cp, ",");
811 item = silc_calloc(len + 1, sizeof(char));
812 memcpy(item, cp, len);
814 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
816 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
817 SILC_LOG_DEBUG(("Found KE group `%s'", item));
819 payload->ke_grp_len = len;
820 payload->ke_grp_list = item;
834 if (!payload->ke_grp_len && !payload->ke_grp_list) {
835 SILC_LOG_DEBUG(("Could not find supported KE group"));
837 return SILC_SKE_STATUS_UNKNOWN_GROUP;
841 if (!rp->ke_grp_len) {
842 SILC_LOG_DEBUG(("KE group not defined in payload"));
844 return SILC_SKE_STATUS_BAD_PAYLOAD;
847 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
848 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
850 payload->ke_grp_len = rp->ke_grp_len;
851 payload->ke_grp_list = strdup(rp->ke_grp_list);
854 /* Get supported PKCS algorithms */
855 cp = rp->pkcs_alg_list;
856 if (cp && strchr(cp, ',')) {
860 len = strcspn(cp, ",");
861 item = silc_calloc(len + 1, sizeof(char));
862 memcpy(item, cp, len);
864 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
866 if (silc_pkcs_is_supported(item) == TRUE) {
867 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
869 payload->pkcs_alg_len = len;
870 payload->pkcs_alg_list = item;
884 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
885 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
886 silc_free(payload->ke_grp_list);
888 return SILC_SKE_STATUS_UNKNOWN_PKCS;
892 if (!rp->pkcs_alg_len) {
893 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
894 silc_free(payload->ke_grp_list);
896 return SILC_SKE_STATUS_BAD_PAYLOAD;
899 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
900 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
902 payload->pkcs_alg_len = rp->pkcs_alg_len;
903 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
906 /* Get supported encryption algorithms */
907 cp = rp->enc_alg_list;
908 if (cp && strchr(cp, ',')) {
912 len = strcspn(cp, ",");
913 item = silc_calloc(len + 1, sizeof(char));
914 memcpy(item, cp, len);
916 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
918 if (silc_cipher_is_supported(item) == TRUE) {
919 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
921 payload->enc_alg_len = len;
922 payload->enc_alg_list = item;
936 if (!payload->enc_alg_len && !payload->enc_alg_list) {
937 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
938 silc_free(payload->ke_grp_list);
939 silc_free(payload->pkcs_alg_list);
941 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
945 if (!rp->enc_alg_len) {
946 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
947 silc_free(payload->ke_grp_list);
948 silc_free(payload->pkcs_alg_list);
950 return SILC_SKE_STATUS_BAD_PAYLOAD;
953 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
956 payload->enc_alg_len = rp->enc_alg_len;
957 payload->enc_alg_list = strdup(rp->enc_alg_list);
960 /* Get supported hash algorithms */
961 cp = rp->hash_alg_list;
962 if (cp && strchr(cp, ',')) {
966 len = strcspn(cp, ",");
967 item = silc_calloc(len + 1, sizeof(char));
968 memcpy(item, cp, len);
970 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
972 if (silc_hash_is_supported(item) == TRUE) {
973 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
975 payload->hash_alg_len = len;
976 payload->hash_alg_list = item;
990 if (!payload->hash_alg_len && !payload->hash_alg_list) {
991 SILC_LOG_DEBUG(("Could not find supported hash alg"));
992 silc_free(payload->ke_grp_list);
993 silc_free(payload->pkcs_alg_list);
994 silc_free(payload->enc_alg_list);
996 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1000 if (!rp->hash_alg_len) {
1001 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1002 silc_free(payload->ke_grp_list);
1003 silc_free(payload->pkcs_alg_list);
1004 silc_free(payload->enc_alg_list);
1006 return SILC_SKE_STATUS_BAD_PAYLOAD;
1009 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1010 rp->hash_alg_list));
1012 payload->hash_alg_len = rp->hash_alg_len;
1013 payload->hash_alg_list = strdup(rp->hash_alg_list);
1017 /* Get supported compression algorithms */
1018 cp = rp->hash_alg_list;
1019 if (cp && strchr(cp, ',')) {
1023 len = strcspn(cp, ",");
1024 item = silc_calloc(len + 1, sizeof(char));
1025 memcpy(item, cp, len);
1027 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1029 if (silc_hash_is_supported(item) == TRUE) {
1030 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1032 payload->hash_alg_len = len;
1033 payload->hash_alg_list = item;
1038 if (strlen(cp) == 0)
1047 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1048 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1049 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1050 silc_free(payload->ke_grp_list);
1051 silc_free(payload->pkcs_alg_list);
1052 silc_free(payload->enc_alg_list);
1061 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1062 2 + payload->version_len +
1063 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1064 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1065 2 + payload->comp_alg_len;
1067 return SILC_SKE_STATUS_OK;
1070 /* Creates random number such that 1 < rnd < n and at most length
1071 of len bits. The rnd sent as argument must be initialized. */
1073 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1077 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1078 unsigned char *string;
1080 SILC_LOG_DEBUG(("Creating random number"));
1082 /* Get the random number as string */
1083 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1085 /* Decode the string into a MP integer */
1086 silc_mp_bin2mp(string, (len / 8), rnd);
1087 silc_mp_mod_2exp(rnd, rnd, len);
1090 if (silc_mp_cmp_ui(rnd, 1) < 0)
1091 status = SILC_SKE_STATUS_ERROR;
1093 if (silc_mp_cmp(rnd, &n) >= 0)
1094 status = SILC_SKE_STATUS_ERROR;
1096 memset(string, 'F', (len / 8));
1102 /* Creates a hash value HASH as defined in the SKE protocol. */
1104 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1105 unsigned char *return_hash,
1106 unsigned int *return_hash_len)
1108 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1110 unsigned char *e, *f, *KEY;
1111 unsigned int e_len, f_len, KEY_len;
1113 SILC_LOG_DEBUG(("Start"));
1115 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1116 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1117 KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1119 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1120 ske->pk_len + e_len + f_len + KEY_len);
1121 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1123 /* Format the buffer used to compute the hash value */
1124 silc_buffer_format(buf,
1125 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1126 ske->start_payload_copy->len),
1127 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1128 SILC_STR_UI_XNSTRING(e, e_len),
1129 SILC_STR_UI_XNSTRING(f, f_len),
1130 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1134 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1138 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1139 *return_hash_len = ske->prop->hash->hash->hash_len;
1141 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1143 silc_buffer_free(buf);
1144 memset(e, 0, e_len);
1145 memset(f, 0, f_len);
1146 memset(KEY, 0, KEY_len);
1154 /* Processes negotiated key material as protocol specifies. This returns
1155 the actual keys to be used in the SILC. */
1157 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1158 unsigned int req_iv_len,
1159 unsigned int req_enc_key_len,
1160 unsigned int req_hmac_key_len,
1161 SilcSKEKeyMaterial *key)
1165 unsigned char *tmpbuf;
1166 unsigned char hash[32];
1167 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1168 unsigned int enc_key_len = req_enc_key_len / 8;
1170 SILC_LOG_DEBUG(("Start"));
1172 /* Encode KEY to binary data */
1173 tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1175 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;