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 SilcSKEStartPayload *rp;
782 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
786 /* Flags are returned unchanged. */
787 payload->flags = rp->flags;
790 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
791 payload->cookie_len = SILC_SKE_COOKIE_LEN;
792 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
794 /* Check version string */
795 silc_ske_check_version(ske, rp->version, rp->version_len);
797 /* Put our version to our reply */
798 payload->version = strdup(version);
799 payload->version_len = strlen(version);
801 /* Get supported Key Exchange groups */
802 cp = rp->ke_grp_list;
803 if (cp && strchr(cp, ',')) {
807 len = strcspn(cp, ",");
808 item = silc_calloc(len + 1, sizeof(char));
809 memcpy(item, cp, len);
811 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
813 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
814 SILC_LOG_DEBUG(("Found KE group `%s'", item));
816 payload->ke_grp_len = len;
817 payload->ke_grp_list = item;
831 if (!payload->ke_grp_len && !payload->ke_grp_list) {
832 SILC_LOG_DEBUG(("Could not find supported KE group"));
834 return SILC_SKE_STATUS_UNKNOWN_GROUP;
838 if (!rp->ke_grp_len) {
839 SILC_LOG_DEBUG(("KE group not defined in payload"));
841 return SILC_SKE_STATUS_BAD_PAYLOAD;
844 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
845 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
847 payload->ke_grp_len = rp->ke_grp_len;
848 payload->ke_grp_list = strdup(rp->ke_grp_list);
851 /* Get supported PKCS algorithms */
852 cp = rp->pkcs_alg_list;
853 if (cp && strchr(cp, ',')) {
857 len = strcspn(cp, ",");
858 item = silc_calloc(len + 1, sizeof(char));
859 memcpy(item, cp, len);
861 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
863 if (silc_pkcs_is_supported(item) == TRUE) {
864 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
866 payload->pkcs_alg_len = len;
867 payload->pkcs_alg_list = item;
881 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
882 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
883 silc_free(payload->ke_grp_list);
885 return SILC_SKE_STATUS_UNKNOWN_PKCS;
889 if (!rp->pkcs_alg_len) {
890 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
891 silc_free(payload->ke_grp_list);
893 return SILC_SKE_STATUS_BAD_PAYLOAD;
896 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
897 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
899 payload->pkcs_alg_len = rp->pkcs_alg_len;
900 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
903 /* Get supported encryption algorithms */
904 cp = rp->enc_alg_list;
905 if (cp && strchr(cp, ',')) {
909 len = strcspn(cp, ",");
910 item = silc_calloc(len + 1, sizeof(char));
911 memcpy(item, cp, len);
913 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
915 if (silc_cipher_is_supported(item) == TRUE) {
916 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
918 payload->enc_alg_len = len;
919 payload->enc_alg_list = item;
933 if (!payload->enc_alg_len && !payload->enc_alg_list) {
934 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
935 silc_free(payload->ke_grp_list);
936 silc_free(payload->pkcs_alg_list);
938 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
942 if (!rp->enc_alg_len) {
943 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
944 silc_free(payload->ke_grp_list);
945 silc_free(payload->pkcs_alg_list);
947 return SILC_SKE_STATUS_BAD_PAYLOAD;
950 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
953 payload->enc_alg_len = rp->enc_alg_len;
954 payload->enc_alg_list = strdup(rp->enc_alg_list);
957 /* Get supported hash algorithms */
958 cp = rp->hash_alg_list;
959 if (cp && strchr(cp, ',')) {
963 len = strcspn(cp, ",");
964 item = silc_calloc(len + 1, sizeof(char));
965 memcpy(item, cp, len);
967 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
969 if (silc_hash_is_supported(item) == TRUE) {
970 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
972 payload->hash_alg_len = len;
973 payload->hash_alg_list = item;
987 if (!payload->hash_alg_len && !payload->hash_alg_list) {
988 SILC_LOG_DEBUG(("Could not find supported hash alg"));
989 silc_free(payload->ke_grp_list);
990 silc_free(payload->pkcs_alg_list);
991 silc_free(payload->enc_alg_list);
993 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
997 if (!rp->hash_alg_len) {
998 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
999 silc_free(payload->ke_grp_list);
1000 silc_free(payload->pkcs_alg_list);
1001 silc_free(payload->enc_alg_list);
1003 return SILC_SKE_STATUS_BAD_PAYLOAD;
1006 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1007 rp->hash_alg_list));
1009 payload->hash_alg_len = rp->hash_alg_len;
1010 payload->hash_alg_list = strdup(rp->hash_alg_list);
1014 /* Get supported compression algorithms */
1015 cp = rp->hash_alg_list;
1016 if (cp && strchr(cp, ',')) {
1020 len = strcspn(cp, ",");
1021 item = silc_calloc(len + 1, sizeof(char));
1022 memcpy(item, cp, len);
1024 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1026 if (silc_hash_is_supported(item) == TRUE) {
1027 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1029 payload->hash_alg_len = len;
1030 payload->hash_alg_list = item;
1035 if (strlen(cp) == 0)
1044 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1045 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1046 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1047 silc_free(payload->ke_grp_list);
1048 silc_free(payload->pkcs_alg_list);
1049 silc_free(payload->enc_alg_list);
1058 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1059 2 + payload->version_len +
1060 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1061 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1062 2 + payload->comp_alg_len;
1064 return SILC_SKE_STATUS_OK;
1067 /* Creates random number such that 1 < rnd < n and at most length
1068 of len bits. The rnd sent as argument must be initialized. */
1070 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1074 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1075 unsigned char *string;
1077 SILC_LOG_DEBUG(("Creating random number"));
1079 /* Get the random number as string */
1080 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1082 /* Decode the string into a MP integer */
1083 silc_mp_bin2mp(string, (len / 8), rnd);
1084 silc_mp_mod_2exp(rnd, rnd, len);
1087 if (silc_mp_cmp_ui(rnd, 1) < 0)
1088 status = SILC_SKE_STATUS_ERROR;
1090 if (silc_mp_cmp(rnd, &n) >= 0)
1091 status = SILC_SKE_STATUS_ERROR;
1093 memset(string, 'F', (len / 8));
1099 /* Creates a hash value HASH as defined in the SKE protocol. */
1101 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1102 unsigned char *return_hash,
1103 unsigned int *return_hash_len)
1105 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1107 unsigned char *e, *f, *KEY;
1108 unsigned int e_len, f_len, KEY_len;
1110 SILC_LOG_DEBUG(("Start"));
1112 e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
1113 f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
1114 KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
1116 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1117 ske->pk_len + e_len + f_len + KEY_len);
1118 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1120 /* Format the buffer used to compute the hash value */
1121 silc_buffer_format(buf,
1122 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1123 ske->start_payload_copy->len),
1124 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1125 SILC_STR_UI_XNSTRING(e, e_len),
1126 SILC_STR_UI_XNSTRING(f, f_len),
1127 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1131 SILC_LOG_HEXDUMP(("Hash buffer"), buf->data, buf->len);
1135 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1136 *return_hash_len = ske->prop->hash->hash->hash_len;
1138 SILC_LOG_HEXDUMP(("Hash"), return_hash, *return_hash_len);
1140 silc_buffer_free(buf);
1141 memset(e, 0, e_len);
1142 memset(f, 0, f_len);
1143 memset(KEY, 0, KEY_len);
1151 /* Processes negotiated key material as protocol specifies. This returns
1152 the actual keys to be used in the SILC. */
1154 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1155 unsigned int req_iv_len,
1156 unsigned int req_enc_key_len,
1157 unsigned int req_hmac_key_len,
1158 SilcSKEKeyMaterial *key)
1162 unsigned char *tmpbuf;
1163 unsigned char hash[32];
1164 unsigned int hash_len = ske->prop->hash->hash->hash_len;
1165 unsigned int enc_key_len = req_enc_key_len / 8;
1167 SILC_LOG_DEBUG(("Start"));
1169 /* Encode KEY to binary data */
1170 tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
1172 buf = silc_buffer_alloc(1 + klen + hash_len);
1173 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1174 silc_buffer_format(buf,
1175 SILC_STR_UI_CHAR(0),
1176 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1177 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1181 memset(hash, 0, sizeof(hash));
1183 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1184 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1185 memcpy(key->send_iv, hash, req_iv_len);
1186 memset(hash, 0, sizeof(hash));
1188 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1189 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1190 memcpy(key->receive_iv, hash, req_iv_len);
1191 key->iv_len = req_iv_len;
1193 /* Take the encryption keys. If requested key size is more than
1194 the size of hash length we will distribute more key material
1195 as protocol defines. */
1197 if (enc_key_len > hash_len) {
1199 unsigned char k1[32], k2[32], k3[32];
1200 unsigned char *dtmp;
1203 if (enc_key_len > (3 * hash_len))
1204 return SILC_SKE_STATUS_ERROR;
1206 memset(k1, 0, sizeof(k1));
1207 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1210 dist = silc_buffer_alloc(hash_len * 3);
1212 silc_buffer_pull_tail(dist, klen + hash_len);
1213 silc_buffer_format(dist,
1214 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1215 SILC_STR_UI_XNSTRING(k1, hash_len),
1218 memset(k2, 0, sizeof(k2));
1219 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1221 silc_buffer_pull(dist, klen + hash_len);
1222 silc_buffer_format(dist,
1223 SILC_STR_UI_XNSTRING(k2, hash_len),
1225 silc_buffer_push(dist, klen + hash_len);
1227 memset(k3, 0, sizeof(k3));
1228 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1230 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1231 memcpy(dtmp, k1, hash_len);
1232 memcpy(dtmp + hash_len, k2, hash_len);
1233 memcpy(dtmp + hash_len, k3, hash_len);
1235 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1236 memcpy(key->send_enc_key, dtmp, enc_key_len);
1237 key->enc_key_len = req_enc_key_len;
1239 memset(dtmp, 0, (3 * hash_len));
1240 memset(k1, 0, sizeof(k1));
1241 memset(k2, 0, sizeof(k2));
1242 memset(k3, 0, sizeof(k3));
1244 silc_buffer_free(dist);
1246 /* Take normal hash as key */
1247 memset(hash, 0, sizeof(hash));
1248 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1249 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1250 memcpy(key->send_enc_key, hash, enc_key_len);
1251 key->enc_key_len = req_enc_key_len;
1255 if (enc_key_len > hash_len) {
1257 unsigned char k1[32], k2[32], k3[32];
1258 unsigned char *dtmp;
1261 if (enc_key_len > (3 * hash_len))
1262 return SILC_SKE_STATUS_ERROR;
1264 memset(k1, 0, sizeof(k1));
1265 silc_hash_make(ske->prop->hash, buf->data, buf->len, k1);
1268 dist = silc_buffer_alloc(hash_len * 3);
1270 silc_buffer_pull_tail(dist, klen + hash_len);
1271 silc_buffer_format(dist,
1272 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1273 SILC_STR_UI_XNSTRING(k1, hash_len),
1276 memset(k2, 0, sizeof(k2));
1277 silc_hash_make(ske->prop->hash, dist->data, dist->len, k2);
1279 silc_buffer_pull(dist, klen + hash_len);
1280 silc_buffer_format(dist,
1281 SILC_STR_UI_XNSTRING(k2, hash_len),
1283 silc_buffer_push(dist, klen + hash_len);
1285 memset(k3, 0, sizeof(k3));
1286 silc_hash_make(ske->prop->hash, dist->data, dist->len, k3);
1288 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1289 memcpy(dtmp, k1, hash_len);
1290 memcpy(dtmp + hash_len, k2, hash_len);
1291 memcpy(dtmp + hash_len, k3, hash_len);
1293 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1294 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1295 key->enc_key_len = req_enc_key_len;
1297 memset(dtmp, 0, (3 * hash_len));
1298 memset(k1, 0, sizeof(k1));
1299 memset(k2, 0, sizeof(k2));
1300 memset(k3, 0, sizeof(k3));
1302 silc_buffer_free(dist);
1304 /* Take normal hash as key */
1305 memset(hash, 0, sizeof(hash));
1306 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1307 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1308 memcpy(key->receive_enc_key, hash, enc_key_len);
1309 key->enc_key_len = req_enc_key_len;
1313 memset(hash, 0, sizeof(hash));
1315 silc_hash_make(ske->prop->hash, buf->data, buf->len, hash);
1316 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1317 memcpy(key->hmac_key, hash, req_hmac_key_len);
1318 key->hmac_key_len = req_hmac_key_len;
1320 memset(tmpbuf, 0, klen);
1323 return SILC_SKE_STATUS_OK;