5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 - 2001 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);
53 silc_ske_payload_ke_free(ske->ke1_payload);
58 silc_free(ske->prop->group);
60 silc_pkcs_free(ske->prop->pkcs);
61 if (ske->prop->cipher)
62 silc_cipher_free(ske->prop->cipher);
64 silc_hash_free(ske->prop->hash);
66 silc_hmac_free(ske->prop->hmac);
69 if (ske->start_payload_copy)
70 silc_buffer_free(ske->start_payload_copy);
74 silc_mp_clear(ske->x);
78 silc_mp_clear(ske->KEY);
87 /* Starts the SILC Key Exchange protocol for initiator. The connection
88 to the remote end must be established before calling this function
89 and the connecting socket must be sent as argument. This function
90 creates the Key Exchange Start Paload which includes all our
91 configured security properties. This payload is then sent to the
92 remote end for further processing. This payload must be sent as
93 argument to the function, however, it must not be encoded
94 already, it is done by this function.
96 The packet sending is done by calling a callback function. Caller
97 must provide a routine to send the packet. */
99 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
100 SilcSocketConnection sock,
101 SilcSKEStartPayload *start_payload,
102 SilcSKESendPacketCb send_packet,
105 SilcSKEStatus status = SILC_SKE_STATUS_OK;
106 SilcBuffer payload_buf;
108 SILC_LOG_DEBUG(("Start"));
113 /* Encode the payload */
114 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
115 if (status != SILC_SKE_STATUS_OK)
118 /* Take a copy of the payload buffer for future use. It is used to
119 compute the HASH value. */
120 ske->start_payload_copy = silc_buffer_copy(payload_buf);
122 /* Send the packet. */
124 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
126 silc_buffer_free(payload_buf);
131 /* Function called after ske_initiator_start fuction. This receives
132 the remote ends Key Exchange Start payload which includes the
133 security properties selected by the responder from our payload
134 sent in the silc_ske_initiator_start function. */
136 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
137 SilcBuffer start_payload,
141 SilcSKEStatus status = SILC_SKE_STATUS_OK;
142 SilcSKEStartPayload *payload;
143 SilcSKESecurityProperties prop;
144 SilcSKEDiffieHellmanGroup group;
146 SILC_LOG_DEBUG(("Start"));
148 /* Decode the payload */
149 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
150 if (status != SILC_SKE_STATUS_OK) {
151 ske->status = status;
155 /* Take the selected security properties into use while doing
156 the key exchange. This is used only while doing the key
157 exchange. The same data is returned to upper levels by calling
158 the callback function. */
159 ske->prop = prop = silc_calloc(1, sizeof(*prop));
160 prop->flags = payload->flags;
161 status = silc_ske_get_group_by_name(payload->ke_grp_list, &group);
162 if (status != SILC_SKE_STATUS_OK)
167 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
168 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
172 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
173 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
177 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
178 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
182 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
183 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
187 ske->start_payload = payload;
189 /* Return the received payload by calling the callback function. */
191 (*callback)(ske, context);
197 silc_ske_payload_start_free(payload);
202 silc_pkcs_free(prop->pkcs);
204 silc_cipher_free(prop->cipher);
206 silc_hash_free(prop->hash);
208 silc_hmac_free(prop->hmac);
212 if (status == SILC_SKE_STATUS_OK)
213 return SILC_SKE_STATUS_ERROR;
215 ske->status = status;
219 /* This function creates random number x, such that 1 < x < q and
220 computes e = g ^ x mod p and sends the result to the remote end in
221 Key Exchange Payload. */
223 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
224 SilcPublicKey public_key,
225 SilcPrivateKey private_key,
226 SilcSKESendPacketCb send_packet,
229 SilcSKEStatus status = SILC_SKE_STATUS_OK;
230 SilcBuffer payload_buf;
232 SilcSKEKEPayload *payload;
235 SILC_LOG_DEBUG(("Start"));
237 /* Create the random number x, 1 < x < q. */
238 x = silc_calloc(1, sizeof(*x));
241 silc_ske_create_rnd(ske, ske->prop->group->group_order,
242 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
244 if (status != SILC_SKE_STATUS_OK) {
247 ske->status = status;
251 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
253 /* Do the Diffie Hellman computation, e = g ^ x mod p */
255 silc_mp_powm(&e, &ske->prop->group->generator, x,
256 &ske->prop->group->group);
258 /* Encode the result to Key Exchange Payload. */
260 payload = silc_calloc(1, sizeof(*payload));
261 ske->ke1_payload = payload;
266 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
267 if (!payload->pk_data) {
272 ske->status = SILC_SKE_STATUS_OK;
275 payload->pk_len = pk_len;
276 payload->pk_type = SILC_SKE_PK_TYPE_SILC;
278 /* Compute signature data if we are doing mutual authentication */
279 if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
280 unsigned char hash[32], sign[1024];
281 uint32 hash_len, sign_len;
283 SILC_LOG_DEBUG(("We are doing mutual authentication"));
284 SILC_LOG_DEBUG(("Computing HASH value"));
286 /* Compute the hash value */
287 memset(hash, 0, sizeof(hash));
288 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
290 SILC_LOG_DEBUG(("Signing HASH_i value"));
292 /* Sign the hash value */
293 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
294 private_key->prv_len);
295 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
296 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
297 memcpy(payload->sign_data, sign, sign_len);
298 memset(sign, 0, sizeof(sign));
299 payload->sign_len = sign_len;
302 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
303 if (status != SILC_SKE_STATUS_OK) {
307 silc_free(payload->pk_data);
309 ske->status = status;
315 /* Send the packet. */
317 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_1, context);
319 silc_buffer_free(payload_buf);
324 /* Receives Key Exchange Payload from responder consisting responders
325 public key, f, and signature. This function verifies the public key,
326 computes the secret shared key and verifies the signature. */
328 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
329 SilcBuffer ke_payload,
330 SilcSKEVerifyCb verify_key,
331 void *verify_context,
335 SilcSKEStatus status = SILC_SKE_STATUS_OK;
336 SilcSKEKEPayload *payload;
337 SilcPublicKey public_key = NULL;
339 unsigned char hash[32];
342 SILC_LOG_DEBUG(("Start"));
344 /* Decode the payload */
345 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
346 if (status != SILC_SKE_STATUS_OK) {
347 ske->status = status;
350 ske->ke2_payload = payload;
352 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
354 /* Compute the shared secret key */
355 KEY = silc_calloc(1, sizeof(*KEY));
357 silc_mp_powm(KEY, &payload->x, ske->x, &ske->prop->group->group);
360 SILC_LOG_DEBUG(("Verifying public key"));
362 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
364 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
369 status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
370 payload->pk_type, verify_context);
371 if (status != SILC_SKE_STATUS_OK)
375 SILC_LOG_DEBUG(("Public key is authentic"));
377 /* Compute the hash value */
378 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
379 if (status != SILC_SKE_STATUS_OK)
382 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
383 memcpy(ske->hash, hash, hash_len);
384 ske->hash_len = hash_len;
386 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
388 /* Verify signature */
389 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
391 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
392 payload->sign_len, hash, hash_len) == FALSE) {
394 SILC_LOG_DEBUG(("Signature don't match"));
396 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
400 SILC_LOG_DEBUG(("Signature is Ok"));
402 silc_pkcs_public_key_free(public_key);
403 memset(hash, 'F', hash_len);
405 /* Call the callback. */
407 (*callback)(ske, context);
412 memset(hash, 'F', sizeof(hash));
413 silc_ske_payload_ke_free(payload);
414 ske->ke2_payload = NULL;
416 silc_mp_clear(ske->KEY);
421 silc_pkcs_public_key_free(public_key);
424 memset(ske->hash, 'F', hash_len);
425 silc_free(ske->hash);
429 if (status == SILC_SKE_STATUS_OK)
430 return SILC_SKE_STATUS_ERROR;
432 ske->status = status;
436 /* Starts Key Exchange protocol for responder. Responder receives
437 Key Exchange Start Payload from initiator consisting of all the
438 security properties the initiator supports. This function decodes
439 the payload and parses the payload further and selects the right
440 security properties. */
442 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
443 SilcSocketConnection sock,
445 SilcBuffer start_payload,
450 SilcSKEStatus status = SILC_SKE_STATUS_OK;
451 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
453 SILC_LOG_DEBUG(("Start"));
458 /* Decode the payload */
459 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
460 if (status != SILC_SKE_STATUS_OK) {
461 ske->status = status;
465 /* Take a copy of the payload buffer for future use. It is used to
466 compute the HASH value. */
467 ske->start_payload_copy = silc_buffer_copy(start_payload);
469 /* Force the mutual authentication flag if we want to do it. */
471 SILC_LOG_DEBUG(("Force mutual authentication"));
472 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
475 /* Parse and select the security properties from the payload */
476 payload = silc_calloc(1, sizeof(*payload));
477 status = silc_ske_select_security_properties(ske, version,
478 payload, remote_payload);
479 if (status != SILC_SKE_STATUS_OK)
482 ske->start_payload = payload;
484 /* Call the callback function. */
486 (*callback)(ske, context);
492 silc_ske_payload_start_free(remote_payload);
496 if (status == SILC_SKE_STATUS_OK)
497 return SILC_SKE_STATUS_ERROR;
499 ske->status = status;
503 /* The selected security properties from the initiator payload is now
504 encoded into Key Exchange Start Payload and sent to the initiator. */
506 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
507 SilcSKEStartPayload *start_payload,
508 SilcSKESendPacketCb send_packet,
511 SilcSKEStatus status = SILC_SKE_STATUS_OK;
512 SilcBuffer payload_buf;
513 SilcSKESecurityProperties prop;
514 SilcSKEDiffieHellmanGroup group = NULL;
516 SILC_LOG_DEBUG(("Start"));
518 /* Allocate security properties from the payload. These are allocated
519 only for this negotiation and will be free'd after KE is over. */
520 ske->prop = prop = silc_calloc(1, sizeof(*prop));
521 prop->flags = start_payload->flags;
522 status = silc_ske_get_group_by_name(start_payload->ke_grp_list, &group);
523 if (status != SILC_SKE_STATUS_OK)
528 if (silc_pkcs_alloc(start_payload->pkcs_alg_list,
529 &prop->pkcs) == FALSE) {
530 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
534 if (silc_cipher_alloc(start_payload->enc_alg_list,
535 &prop->cipher) == FALSE) {
536 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
540 if (silc_hash_alloc(start_payload->hash_alg_list,
541 &prop->hash) == FALSE) {
542 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
546 if (silc_hmac_alloc(start_payload->hmac_alg_list, NULL,
547 &prop->hmac) == FALSE) {
548 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
552 /* Encode the payload */
553 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
554 if (status != SILC_SKE_STATUS_OK)
557 /* Send the packet. */
559 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, context);
561 silc_buffer_free(payload_buf);
570 silc_pkcs_free(prop->pkcs);
572 silc_cipher_free(prop->cipher);
574 silc_hash_free(prop->hash);
576 silc_hmac_free(prop->hmac);
580 if (status == SILC_SKE_STATUS_OK)
581 return SILC_SKE_STATUS_ERROR;
583 ske->status = status;
587 /* This function receives the Key Exchange Payload from the initiator.
588 After processing the payload this then selects random number x,
589 such that 1 < x < q and computes f = g ^ x mod p. This then puts
590 the result f to a Key Exchange Payload which is later processed
591 in ske_responder_finish function. The callback function should
592 not touch the payload (it should merely call the ske_responder_finish
595 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
596 SilcBuffer ke_payload,
597 SilcSKEVerifyCb verify_key,
598 void *verify_context,
602 SilcSKEStatus status = SILC_SKE_STATUS_OK;
603 SilcSKEKEPayload *recv_payload, *send_payload;
606 SILC_LOG_DEBUG(("Start"));
608 /* Decode Key Exchange Payload */
609 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
610 if (status != SILC_SKE_STATUS_OK) {
611 ske->status = status;
615 ske->ke1_payload = recv_payload;
617 /* Verify the received public key and verify the signature if we are
618 doing mutual authentication. */
619 if (ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
620 SilcPublicKey public_key = NULL;
621 unsigned char hash[32];
624 SILC_LOG_DEBUG(("We are doing mutual authentication"));
625 SILC_LOG_DEBUG(("Verifying public key"));
627 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
628 recv_payload->pk_len,
630 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
635 status = (*verify_key)(ske, recv_payload->pk_data, recv_payload->pk_len,
636 recv_payload->pk_type, verify_context);
637 if (status != SILC_SKE_STATUS_OK)
641 SILC_LOG_DEBUG(("Public key is authentic"));
643 /* Compute the hash value */
644 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
645 if (status != SILC_SKE_STATUS_OK)
648 SILC_LOG_DEBUG(("Verifying signature"));
650 /* Verify signature */
651 silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
653 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
654 recv_payload->sign_len, hash, hash_len) == FALSE) {
656 SILC_LOG_DEBUG(("Signature don't match"));
658 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
662 SILC_LOG_DEBUG(("Signature is Ok"));
664 silc_pkcs_public_key_free(public_key);
665 memset(hash, 'F', hash_len);
668 /* Create the random number x, 1 < x < q. */
669 x = silc_calloc(1, sizeof(*x));
672 silc_ske_create_rnd(ske, ske->prop->group->group_order,
673 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
675 if (status != SILC_SKE_STATUS_OK) {
681 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
683 /* Do the Diffie Hellman computation, f = g ^ x mod p */
685 silc_mp_powm(&f, &ske->prop->group->generator, x,
686 &ske->prop->group->group);
688 /* Save the results for later processing */
689 send_payload = silc_calloc(1, sizeof(*send_payload));
692 ske->ke2_payload = send_payload;
694 /* Call the callback. */
696 (*callback)(ske, context);
701 /* This function computes the secret shared key KEY = e ^ x mod p, and,
702 a hash value to be signed and sent to the other end. This then
703 encodes Key Exchange Payload and sends it to the other end. */
705 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
706 SilcPublicKey public_key,
707 SilcPrivateKey private_key,
708 SilcSKEPKType pk_type,
709 SilcSKESendPacketCb send_packet,
712 SilcSKEStatus status = SILC_SKE_STATUS_OK;
713 SilcBuffer payload_buf;
715 unsigned char hash[32], sign[1024], *pk;
716 uint32 hash_len, sign_len, pk_len;
718 SILC_LOG_DEBUG(("Start"));
720 if (!public_key || !private_key) {
721 status = SILC_SKE_STATUS_ERROR;
725 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
727 /* Compute the shared secret key */
728 KEY = silc_calloc(1, sizeof(*KEY));
730 silc_mp_powm(KEY, &ske->ke1_payload->x, ske->x,
731 &ske->prop->group->group);
734 SILC_LOG_DEBUG(("Getting public key"));
736 /* Get the public key */
737 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
739 status = SILC_SKE_STATUS_ERROR;
742 ske->ke2_payload->pk_data = pk;
743 ske->ke2_payload->pk_len = pk_len;
744 ske->ke2_payload->pk_type = pk_type;
746 SILC_LOG_DEBUG(("Computing HASH value"));
748 /* Compute the hash value */
749 memset(hash, 0, sizeof(hash));
750 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
751 if (status != SILC_SKE_STATUS_OK)
754 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
755 memcpy(ske->hash, hash, hash_len);
756 ske->hash_len = hash_len;
758 SILC_LOG_DEBUG(("Signing HASH value"));
760 /* Sign the hash value */
761 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
762 private_key->prv_len);
763 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
764 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
765 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
766 memset(sign, 0, sizeof(sign));
767 ske->ke2_payload->sign_len = sign_len;
769 /* Encode the Key Exchange Payload */
770 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
772 if (status != SILC_SKE_STATUS_OK)
775 /* Send the packet. */
777 (*send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE_2, context);
779 silc_buffer_free(payload_buf);
784 silc_mp_clear(ske->KEY);
787 silc_ske_payload_ke_free(ske->ke2_payload);
789 if (status == SILC_SKE_STATUS_OK)
790 return SILC_SKE_STATUS_ERROR;
792 ske->status = status;
796 /* The Key Exchange protocol is ended by calling this function. This
797 must not be called until the keys are processed like the protocol
798 defines. This function is for both initiator and responder. */
800 SilcSKEStatus silc_ske_end(SilcSKE ske,
801 SilcSKESendPacketCb send_packet,
806 SILC_LOG_DEBUG(("Start"));
808 packet = silc_buffer_alloc(4);
809 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
810 silc_buffer_format(packet,
811 SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
815 (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
817 silc_buffer_free(packet);
819 return SILC_SKE_STATUS_OK;
822 /* Aborts the Key Exchange protocol. This is called if error occurs
823 while performing the protocol. The status argument is the error
824 status and it is sent to the remote end. */
826 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
827 SilcSKESendPacketCb send_packet,
832 SILC_LOG_DEBUG(("Start"));
834 packet = silc_buffer_alloc(4);
835 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
836 silc_buffer_format(packet,
837 SILC_STR_UI_SHORT(status),
841 (*send_packet)(ske, packet, SILC_PACKET_FAILURE, context);
843 silc_buffer_free(packet);
845 return SILC_SKE_STATUS_OK;
848 /* Assembles security properties to Key Exchange Start Payload to be
849 sent to the remote end. This checks system wide (SILC system, that is)
850 settings and chooses from those. However, if other properties
851 should be used this function is easy to replace by another function,
852 as, this function is called by the caller of the protocol and not
853 by the protocol itself. */
856 silc_ske_assemble_security_properties(SilcSKE ske,
859 SilcSKEStartPayload **return_payload)
861 SilcSKEStartPayload *rp;
864 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
866 rp = silc_calloc(1, sizeof(*rp));
871 /* Set random cookie */
872 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
873 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
874 rp->cookie[i] = silc_rng_get_byte(ske->rng);
875 rp->cookie_len = SILC_SKE_COOKIE_LEN;
878 rp->version = strdup(version);
879 rp->version_len = strlen(version);
881 /* Get supported Key Exhange groups */
882 rp->ke_grp_list = silc_ske_get_supported_groups();
883 rp->ke_grp_len = strlen(rp->ke_grp_list);
885 /* Get supported PKCS algorithms */
886 rp->pkcs_alg_list = silc_pkcs_get_supported();
887 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
889 /* Get supported encryption algorithms */
890 rp->enc_alg_list = silc_cipher_get_supported();
891 rp->enc_alg_len = strlen(rp->enc_alg_list);
893 /* Get supported hash algorithms */
894 rp->hash_alg_list = silc_hash_get_supported();
895 rp->hash_alg_len = strlen(rp->hash_alg_list);
897 /* Get supported HMACs */
898 rp->hmac_alg_list = silc_hmac_get_supported();
899 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
902 /* Get supported compression algorithms */
903 rp->comp_alg_list = "";
904 rp->comp_alg_len = 0;
906 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
907 2 + rp->version_len +
908 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
909 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
910 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
912 *return_payload = rp;
914 return SILC_SKE_STATUS_OK;
917 /* Selects the supported security properties from the remote end's Key
918 Exchange Start Payload. */
921 silc_ske_select_security_properties(SilcSKE ske,
923 SilcSKEStartPayload *payload,
924 SilcSKEStartPayload *remote_payload)
926 SilcSKEStatus status;
927 SilcSKEStartPayload *rp;
931 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
935 /* Check version string */
936 status = silc_ske_check_version(ske, rp->version, rp->version_len);
937 if (status != SILC_SKE_STATUS_OK) {
938 ske->status = status;
942 /* Flags are returned unchanged. */
943 payload->flags = rp->flags;
946 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
947 payload->cookie_len = SILC_SKE_COOKIE_LEN;
948 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
950 /* Put our version to our reply */
951 payload->version = strdup(version);
952 payload->version_len = strlen(version);
954 /* Get supported Key Exchange groups */
955 cp = rp->ke_grp_list;
956 if (cp && strchr(cp, ',')) {
960 len = strcspn(cp, ",");
961 item = silc_calloc(len + 1, sizeof(char));
962 memcpy(item, cp, len);
964 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
966 if (silc_ske_get_group_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
967 SILC_LOG_DEBUG(("Found KE group `%s'", item));
969 payload->ke_grp_len = len;
970 payload->ke_grp_list = item;
984 if (!payload->ke_grp_len && !payload->ke_grp_list) {
985 SILC_LOG_DEBUG(("Could not find supported KE group"));
987 return SILC_SKE_STATUS_UNKNOWN_GROUP;
991 if (!rp->ke_grp_len) {
992 SILC_LOG_DEBUG(("KE group not defined in payload"));
994 return SILC_SKE_STATUS_BAD_PAYLOAD;
997 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
998 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1000 payload->ke_grp_len = rp->ke_grp_len;
1001 payload->ke_grp_list = strdup(rp->ke_grp_list);
1004 /* Get supported PKCS algorithms */
1005 cp = rp->pkcs_alg_list;
1006 if (cp && strchr(cp, ',')) {
1010 len = strcspn(cp, ",");
1011 item = silc_calloc(len + 1, sizeof(char));
1012 memcpy(item, cp, len);
1014 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1016 if (silc_pkcs_is_supported(item) == TRUE) {
1017 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1019 payload->pkcs_alg_len = len;
1020 payload->pkcs_alg_list = item;
1025 if (strlen(cp) == 0)
1034 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1035 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1036 silc_free(payload->ke_grp_list);
1038 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1042 if (!rp->pkcs_alg_len) {
1043 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1044 silc_free(payload->ke_grp_list);
1046 return SILC_SKE_STATUS_BAD_PAYLOAD;
1049 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1050 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1052 payload->pkcs_alg_len = rp->pkcs_alg_len;
1053 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1056 /* Get supported encryption algorithms */
1057 cp = rp->enc_alg_list;
1058 if (cp && strchr(cp, ',')) {
1062 len = strcspn(cp, ",");
1063 item = silc_calloc(len + 1, sizeof(char));
1064 memcpy(item, cp, len);
1066 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1068 if (silc_cipher_is_supported(item) == TRUE) {
1069 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1071 payload->enc_alg_len = len;
1072 payload->enc_alg_list = item;
1077 if (strlen(cp) == 0)
1086 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1087 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1088 silc_free(payload->ke_grp_list);
1089 silc_free(payload->pkcs_alg_list);
1091 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1095 if (!rp->enc_alg_len) {
1096 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1097 silc_free(payload->ke_grp_list);
1098 silc_free(payload->pkcs_alg_list);
1100 return SILC_SKE_STATUS_BAD_PAYLOAD;
1103 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1106 payload->enc_alg_len = rp->enc_alg_len;
1107 payload->enc_alg_list = strdup(rp->enc_alg_list);
1110 /* Get supported hash algorithms */
1111 cp = rp->hash_alg_list;
1112 if (cp && strchr(cp, ',')) {
1116 len = strcspn(cp, ",");
1117 item = silc_calloc(len + 1, sizeof(char));
1118 memcpy(item, cp, len);
1120 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1122 if (silc_hash_is_supported(item) == TRUE) {
1123 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1125 payload->hash_alg_len = len;
1126 payload->hash_alg_list = item;
1131 if (strlen(cp) == 0)
1140 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1141 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1142 silc_free(payload->ke_grp_list);
1143 silc_free(payload->pkcs_alg_list);
1144 silc_free(payload->enc_alg_list);
1146 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1150 if (!rp->hash_alg_len) {
1151 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1152 silc_free(payload->ke_grp_list);
1153 silc_free(payload->pkcs_alg_list);
1154 silc_free(payload->enc_alg_list);
1156 return SILC_SKE_STATUS_BAD_PAYLOAD;
1159 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1160 rp->hash_alg_list));
1162 payload->hash_alg_len = rp->hash_alg_len;
1163 payload->hash_alg_list = strdup(rp->hash_alg_list);
1166 /* Get supported HMACs */
1167 cp = rp->hmac_alg_list;
1168 if (cp && strchr(cp, ',')) {
1172 len = strcspn(cp, ",");
1173 item = silc_calloc(len + 1, sizeof(char));
1174 memcpy(item, cp, len);
1176 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1178 if (silc_hmac_is_supported(item) == TRUE) {
1179 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1181 payload->hmac_alg_len = len;
1182 payload->hmac_alg_list = item;
1187 if (strlen(cp) == 0)
1196 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1197 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1198 silc_free(payload->ke_grp_list);
1199 silc_free(payload->pkcs_alg_list);
1200 silc_free(payload->enc_alg_list);
1201 silc_free(payload->hash_alg_list);
1203 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1207 if (!rp->hmac_alg_len) {
1208 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1209 silc_free(payload->ke_grp_list);
1210 silc_free(payload->pkcs_alg_list);
1211 silc_free(payload->enc_alg_list);
1212 silc_free(payload->hash_alg_list);
1214 return SILC_SKE_STATUS_BAD_PAYLOAD;
1217 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1218 rp->hmac_alg_list));
1220 payload->hmac_alg_len = rp->hmac_alg_len;
1221 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1225 /* Get supported compression algorithms */
1226 cp = rp->hash_alg_list;
1227 if (cp && strchr(cp, ',')) {
1231 len = strcspn(cp, ",");
1232 item = silc_calloc(len + 1, sizeof(char));
1233 memcpy(item, cp, len);
1235 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1237 if (silc_hash_is_supported(item) == TRUE) {
1238 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1240 payload->hash_alg_len = len;
1241 payload->hash_alg_list = item;
1246 if (strlen(cp) == 0)
1255 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1256 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1257 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1258 silc_free(payload->ke_grp_list);
1259 silc_free(payload->pkcs_alg_list);
1260 silc_free(payload->enc_alg_list);
1269 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1270 2 + payload->version_len +
1271 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1272 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1273 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1275 return SILC_SKE_STATUS_OK;
1278 /* Creates random number such that 1 < rnd < n and at most length
1279 of len bits. The rnd sent as argument must be initialized. */
1281 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
1285 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1286 unsigned char *string;
1288 SILC_LOG_DEBUG(("Creating random number"));
1290 /* Get the random number as string */
1291 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1293 return SILC_SKE_STATUS_ERROR;
1295 /* Decode the string into a MP integer */
1296 silc_mp_bin2mp(string, (len / 8), rnd);
1297 silc_mp_mod_2exp(rnd, rnd, len);
1300 if (silc_mp_cmp_ui(rnd, 1) < 0)
1301 status = SILC_SKE_STATUS_ERROR;
1303 if (silc_mp_cmp(rnd, &n) >= 0)
1304 status = SILC_SKE_STATUS_ERROR;
1306 memset(string, 'F', (len / 8));
1312 /* Creates a hash value HASH as defined in the SKE protocol. If the
1313 `initiator' is TRUE then this function is used to create the HASH_i
1314 hash value defined in the protocol. If it is FALSE then this is used
1315 to create the HASH value defined by the protocol. */
1317 SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1318 unsigned char *return_hash,
1319 uint32 *return_hash_len,
1322 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1324 unsigned char *e, *f, *KEY;
1325 uint32 e_len, f_len, KEY_len;
1328 SILC_LOG_DEBUG(("Start"));
1330 if (initiator == FALSE) {
1331 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1332 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1333 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1335 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1336 ske->pk_len + e_len + f_len + KEY_len);
1337 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1339 /* Format the buffer used to compute the hash value */
1341 silc_buffer_format(buf,
1342 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1343 ske->start_payload_copy->len),
1344 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1345 SILC_STR_UI_XNSTRING(e, e_len),
1346 SILC_STR_UI_XNSTRING(f, f_len),
1347 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1350 silc_buffer_free(buf);
1351 memset(e, 0, e_len);
1352 memset(f, 0, f_len);
1353 memset(KEY, 0, KEY_len);
1357 return SILC_SKE_STATUS_ERROR;
1360 memset(e, 0, e_len);
1361 memset(f, 0, f_len);
1362 memset(KEY, 0, KEY_len);
1367 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1369 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1370 ske->pk_len + e_len);
1371 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1373 /* Format the buffer used to compute the hash value */
1375 silc_buffer_format(buf,
1376 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1377 ske->start_payload_copy->len),
1378 SILC_STR_UI_XNSTRING(ske->pk, ske->pk_len),
1379 SILC_STR_UI_XNSTRING(e, e_len),
1382 silc_buffer_free(buf);
1383 memset(e, 0, e_len);
1385 return SILC_SKE_STATUS_ERROR;
1388 memset(e, 0, e_len);
1393 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1394 *return_hash_len = ske->prop->hash->hash->hash_len;
1396 if (initiator == FALSE) {
1397 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1399 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1402 silc_buffer_free(buf);
1407 /* Processes the provided key material `data' as the SILC protocol
1408 specification specifies. */
1411 silc_ske_process_key_material_data(unsigned char *data,
1414 uint32 req_enc_key_len,
1415 uint32 req_hmac_key_len,
1417 SilcSKEKeyMaterial *key)
1420 unsigned char hashd[32];
1421 uint32 hash_len = req_hmac_key_len;
1422 uint32 enc_key_len = req_enc_key_len / 8;
1424 SILC_LOG_DEBUG(("Start"));
1426 buf = silc_buffer_alloc(1 + data_len);
1427 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1428 silc_buffer_format(buf,
1429 SILC_STR_UI_CHAR(0),
1430 SILC_STR_UI_XNSTRING(data, data_len),
1434 memset(hashd, 0, sizeof(hashd));
1436 silc_hash_make(hash, buf->data, buf->len, hashd);
1437 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1438 memcpy(key->send_iv, hashd, req_iv_len);
1439 memset(hashd, 0, sizeof(hashd));
1441 silc_hash_make(hash, buf->data, buf->len, hashd);
1442 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1443 memcpy(key->receive_iv, hashd, req_iv_len);
1444 key->iv_len = req_iv_len;
1446 /* Take the encryption keys. If requested key size is more than
1447 the size of hash length we will distribute more key material
1448 as protocol defines. */
1450 if (enc_key_len > hash_len) {
1452 unsigned char k1[32], k2[32], k3[32];
1453 unsigned char *dtmp;
1456 if (enc_key_len > (3 * hash_len))
1457 return SILC_SKE_STATUS_ERROR;
1459 /* Take first round */
1460 memset(k1, 0, sizeof(k1));
1461 silc_hash_make(hash, buf->data, buf->len, k1);
1463 /* Take second round */
1464 dist = silc_buffer_alloc(data_len + hash_len);
1465 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1466 silc_buffer_format(dist,
1467 SILC_STR_UI_XNSTRING(data, data_len),
1468 SILC_STR_UI_XNSTRING(k1, hash_len),
1470 memset(k2, 0, sizeof(k2));
1471 silc_hash_make(hash, dist->data, dist->len, k2);
1473 /* Take third round */
1474 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1475 silc_buffer_pull_tail(dist, hash_len);
1476 silc_buffer_pull(dist, data_len + hash_len);
1477 silc_buffer_format(dist,
1478 SILC_STR_UI_XNSTRING(k2, hash_len),
1480 silc_buffer_push(dist, data_len + hash_len);
1481 memset(k3, 0, sizeof(k3));
1482 silc_hash_make(hash, dist->data, dist->len, k3);
1484 /* Then, save the keys */
1485 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1486 memcpy(dtmp, k1, hash_len);
1487 memcpy(dtmp + hash_len, k2, hash_len);
1488 memcpy(dtmp + hash_len, k3, hash_len);
1490 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1491 memcpy(key->send_enc_key, dtmp, enc_key_len);
1492 key->enc_key_len = req_enc_key_len;
1494 memset(dtmp, 0, (3 * hash_len));
1495 memset(k1, 0, sizeof(k1));
1496 memset(k2, 0, sizeof(k2));
1497 memset(k3, 0, sizeof(k3));
1499 silc_buffer_free(dist);
1501 /* Take normal hash as key */
1502 memset(hashd, 0, sizeof(hashd));
1503 silc_hash_make(hash, buf->data, buf->len, hashd);
1504 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1505 memcpy(key->send_enc_key, hashd, enc_key_len);
1506 key->enc_key_len = req_enc_key_len;
1510 if (enc_key_len > hash_len) {
1512 unsigned char k1[32], k2[32], k3[32];
1513 unsigned char *dtmp;
1516 if (enc_key_len > (3 * hash_len))
1517 return SILC_SKE_STATUS_ERROR;
1519 /* Take first round */
1520 memset(k1, 0, sizeof(k1));
1521 silc_hash_make(hash, buf->data, buf->len, k1);
1523 /* Take second round */
1524 dist = silc_buffer_alloc(data_len + hash_len);
1525 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1526 silc_buffer_format(dist,
1527 SILC_STR_UI_XNSTRING(data, data_len),
1528 SILC_STR_UI_XNSTRING(k1, hash_len),
1530 memset(k2, 0, sizeof(k2));
1531 silc_hash_make(hash, dist->data, dist->len, k2);
1533 /* Take third round */
1534 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1535 silc_buffer_pull_tail(dist, hash_len);
1536 silc_buffer_pull(dist, data_len + hash_len);
1537 silc_buffer_format(dist,
1538 SILC_STR_UI_XNSTRING(k2, hash_len),
1540 silc_buffer_push(dist, data_len + hash_len);
1541 memset(k3, 0, sizeof(k3));
1542 silc_hash_make(hash, dist->data, dist->len, k3);
1544 /* Then, save the keys */
1545 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1546 memcpy(dtmp, k1, hash_len);
1547 memcpy(dtmp + hash_len, k2, hash_len);
1548 memcpy(dtmp + hash_len, k3, hash_len);
1550 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1551 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1552 key->enc_key_len = req_enc_key_len;
1554 memset(dtmp, 0, (3 * hash_len));
1555 memset(k1, 0, sizeof(k1));
1556 memset(k2, 0, sizeof(k2));
1557 memset(k3, 0, sizeof(k3));
1559 silc_buffer_free(dist);
1561 /* Take normal hash as key */
1562 memset(hashd, 0, sizeof(hashd));
1563 silc_hash_make(hash, buf->data, buf->len, hashd);
1564 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1565 memcpy(key->receive_enc_key, hashd, enc_key_len);
1566 key->enc_key_len = req_enc_key_len;
1570 memset(hashd, 0, sizeof(hashd));
1572 silc_hash_make(hash, buf->data, buf->len, hashd);
1573 key->hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1574 memcpy(key->hmac_key, hashd, req_hmac_key_len);
1575 key->hmac_key_len = req_hmac_key_len;
1577 silc_buffer_free(buf);
1579 return SILC_SKE_STATUS_OK;
1582 /* Processes negotiated key material as protocol specifies. This returns
1583 the actual keys to be used in the SILC. */
1585 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1587 uint32 req_enc_key_len,
1588 uint32 req_hmac_key_len,
1589 SilcSKEKeyMaterial *key)
1591 SilcSKEStatus status;
1593 unsigned char *tmpbuf;
1596 /* Encode KEY to binary data */
1597 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1599 buf = silc_buffer_alloc(klen + ske->hash_len);
1600 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1601 silc_buffer_format(buf,
1602 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1603 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1606 /* Process the key material */
1607 status = silc_ske_process_key_material_data(buf->data, buf->len,
1608 req_iv_len, req_enc_key_len,
1610 ske->prop->hash, key);
1612 memset(tmpbuf, 0, klen);
1614 silc_buffer_free(buf);
1619 /* Free key material structure */
1621 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1627 silc_free(key->send_iv);
1628 if (key->receive_iv)
1629 silc_free(key->receive_iv);
1630 if (key->send_enc_key) {
1631 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1632 silc_free(key->send_enc_key);
1634 if (key->receive_enc_key) {
1635 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1636 silc_free(key->receive_enc_key);
1638 if (key->hmac_key) {
1639 memset(key->hmac_key, 0, key->hmac_key_len);
1640 silc_free(key->hmac_key);