5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
23 #include "groups_internal.h"
25 /* Static functions */
26 static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
29 static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
30 unsigned char *return_hash,
31 uint32 *return_hash_len,
34 /* Structure to hold all SKE callbacks. */
35 struct SilcSKECallbacksStruct {
36 SilcSKESendPacketCb send_packet;
37 SilcSKECb payload_receive;
38 SilcSKEVerifyCb verify_key;
39 SilcSKECb proto_continue;
40 SilcSKECheckVersion check_version;
44 /* Allocates new SKE object. */
46 SilcSKE silc_ske_alloc(SilcRng rng, void *context)
50 SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
52 ske = silc_calloc(1, sizeof(*ske));
53 ske->status = SILC_SKE_STATUS_OK;
55 ske->user_data = context;
61 /* Free's SKE object. */
63 void silc_ske_free(SilcSKE ske)
67 SILC_LOG_DEBUG(("Key Exchange set to FREED status"));
68 ske->status = SILC_SKE_STATUS_FREED;
72 SILC_LOG_DEBUG(("Freeing Key Exchange object"));
75 /* Free start payload */
76 if (ske->start_payload)
77 silc_ske_payload_start_free(ske->start_payload);
81 silc_ske_payload_ke_free(ske->ke1_payload);
83 silc_ske_payload_ke_free(ske->ke2_payload);
88 silc_ske_group_free(ske->prop->group);
90 silc_pkcs_free(ske->prop->pkcs);
91 if (ske->prop->cipher)
92 silc_cipher_free(ske->prop->cipher);
94 silc_hash_free(ske->prop->hash);
96 silc_hmac_free(ske->prop->hmac);
99 if (ske->start_payload_copy)
100 silc_buffer_free(ske->start_payload_copy);
102 silc_mp_uninit(ske->x);
106 silc_mp_uninit(ske->KEY);
109 silc_free(ske->hash);
110 silc_free(ske->callbacks);
115 /* Sets the callback functions for the SKE session.
117 The `send_packet' callback is a function that sends the packet to
118 network. The SKE library will call it at any time packet needs to
119 be sent to the remote host.
121 The `payload_receive' callback is called when the remote host's Key
122 Exchange Start Payload has been processed. The payload is saved
123 to ske->start_payload if the application would need it. The application
124 must also provide the payload to the next state of the SKE.
126 The `verify_key' callback is called to verify the received public key
127 or certificate. The verification process is most likely asynchronous.
128 That is why the application must call the completion callback when the
129 verification process has been completed. The library then calls the user
130 callback (`proto_continue'), if it is provided to indicate that the SKE
131 protocol may continue.
133 The `proto_continue' callback is called to indicate that it is
134 safe to continue the execution of the SKE protocol after executing
135 an asynchronous operation, such as calling the `verify_key' callback
136 function, which is asynchronous. The application should check the
137 ske->status in this function to check whether it is Ok to continue
138 the execution of the protocol.
140 The `check_version' callback is called to verify the remote host's
141 version. The application may check its own version against the remote
142 host's version and determine whether supporting the remote host
145 The `context' is passed as argument to all of the above callback
148 void silc_ske_set_callbacks(SilcSKE ske,
149 SilcSKESendPacketCb send_packet,
150 SilcSKECb payload_receive,
151 SilcSKEVerifyCb verify_key,
152 SilcSKECb proto_continue,
153 SilcSKECheckVersion check_version,
157 silc_free(ske->callbacks);
158 ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
159 ske->callbacks->send_packet = send_packet;
160 ske->callbacks->payload_receive = payload_receive;
161 ske->callbacks->verify_key = verify_key;
162 ske->callbacks->proto_continue = proto_continue;
163 ske->callbacks->check_version = check_version;
164 ske->callbacks->context = context;
167 /* Starts the SILC Key Exchange protocol for initiator. The connection
168 to the remote end must be established before calling this function
169 and the connecting socket must be sent as argument. This function
170 creates the Key Exchange Start Payload which includes all our
171 configured security properties. This payload is then sent to the
172 remote end for further processing. This payload must be sent as
173 argument to the function, however, it must not be encoded
174 already, it is done by this function. The caller must not free
175 the `start_payload' since the SKE library will save it.
177 The packet sending is done by calling a callback function. Caller
178 must provide a routine to send the packet. */
180 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
181 SilcSocketConnection sock,
182 SilcSKEStartPayload *start_payload)
184 SilcSKEStatus status = SILC_SKE_STATUS_OK;
185 SilcBuffer payload_buf;
187 SILC_LOG_DEBUG(("Start"));
192 /* Encode the payload */
193 status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
194 if (status != SILC_SKE_STATUS_OK)
197 /* Take a copy of the payload buffer for future use. It is used to
198 compute the HASH value. */
199 ske->start_payload_copy = silc_buffer_copy(payload_buf);
200 ske->start_payload = start_payload;
202 /* Send the packet. */
203 if (ske->callbacks->send_packet)
204 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
205 ske->callbacks->context);
207 silc_buffer_free(payload_buf);
212 /* Function called after ske_initiator_start fuction. This receives
213 the remote ends Key Exchange Start payload which includes the
214 security properties selected by the responder from our payload
215 sent in the silc_ske_initiator_start function. */
217 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
218 SilcBuffer start_payload)
220 SilcSKEStatus status = SILC_SKE_STATUS_OK;
221 SilcSKEStartPayload *payload;
222 SilcSKESecurityProperties prop;
223 SilcSKEDiffieHellmanGroup group;
225 SILC_LOG_DEBUG(("Start"));
227 /* Decode the payload */
228 status = silc_ske_payload_start_decode(ske, start_payload, &payload);
229 if (status != SILC_SKE_STATUS_OK) {
230 ske->status = status;
231 silc_ske_payload_start_free(ske->start_payload);
235 /* Check that the cookie is returned unmodified */
236 if (memcmp(ske->start_payload->cookie, payload->cookie,
237 ske->start_payload->cookie_len)) {
238 SILC_LOG_DEBUG(("Responder modified our cookie and it must not do it"));
239 ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
240 silc_ske_payload_start_free(ske->start_payload);
244 /* Check version string */
245 if (ske->callbacks->check_version) {
246 status = ske->callbacks->check_version(ske, payload->version,
247 payload->version_len,
248 ske->callbacks->context);
249 if (status != SILC_SKE_STATUS_OK) {
250 ske->status = status;
251 silc_ske_payload_start_free(ske->start_payload);
256 /* Free our KE Start Payload context, we don't need it anymore. */
257 silc_ske_payload_start_free(ske->start_payload);
259 /* Take the selected security properties into use while doing
260 the key exchange. This is used only while doing the key
261 exchange. The same data is returned to upper levels by calling
262 the callback function. */
263 ske->prop = prop = silc_calloc(1, sizeof(*prop));
264 prop->flags = payload->flags;
265 status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
266 if (status != SILC_SKE_STATUS_OK)
271 if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
272 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
276 if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
277 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
281 if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
282 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
286 if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
287 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
291 /* Save remote's KE Start Payload */
292 ske->start_payload = payload;
294 /* Return the received payload by calling the callback function. */
295 if (ske->callbacks->payload_receive)
296 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
302 silc_ske_payload_start_free(payload);
304 silc_ske_group_free(group);
307 silc_pkcs_free(prop->pkcs);
309 silc_cipher_free(prop->cipher);
311 silc_hash_free(prop->hash);
313 silc_hmac_free(prop->hmac);
317 if (status == SILC_SKE_STATUS_OK)
318 return SILC_SKE_STATUS_ERROR;
320 ske->status = status;
324 /* This function creates random number x, such that 1 < x < q and
325 computes e = g ^ x mod p and sends the result to the remote end in
326 Key Exchange Payload. */
328 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
329 SilcPublicKey public_key,
330 SilcPrivateKey private_key,
331 SilcSKEPKType pk_type)
333 SilcSKEStatus status = SILC_SKE_STATUS_OK;
334 SilcBuffer payload_buf;
336 SilcSKEKEPayload *payload;
339 SILC_LOG_DEBUG(("Start"));
341 /* Create the random number x, 1 < x < q. */
342 x = silc_calloc(1, sizeof(*x));
345 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
346 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
348 if (status != SILC_SKE_STATUS_OK) {
351 ske->status = status;
355 /* Encode the result to Key Exchange Payload. */
357 payload = silc_calloc(1, sizeof(*payload));
358 ske->ke1_payload = payload;
360 SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
362 /* Do the Diffie Hellman computation, e = g ^ x mod p */
363 silc_mp_init(&payload->x);
364 silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
365 &ske->prop->group->group);
369 payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
370 if (!payload->pk_data) {
373 silc_mp_uninit(&payload->x);
375 ske->status = SILC_SKE_STATUS_OK;
378 payload->pk_len = pk_len;
380 payload->pk_type = pk_type;
382 /* Compute signature data if we are doing mutual authentication */
383 if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
384 unsigned char hash[32], sign[1024];
385 uint32 hash_len, sign_len;
387 SILC_LOG_DEBUG(("We are doing mutual authentication"));
388 SILC_LOG_DEBUG(("Computing HASH_i value"));
390 /* Compute the hash value */
391 memset(hash, 0, sizeof(hash));
392 silc_ske_make_hash(ske, hash, &hash_len, TRUE);
394 SILC_LOG_DEBUG(("Signing HASH_i value"));
396 /* Sign the hash value */
397 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
398 private_key->prv_len);
399 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
400 payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
401 memcpy(payload->sign_data, sign, sign_len);
402 memset(sign, 0, sizeof(sign));
403 payload->sign_len = sign_len;
406 status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
407 if (status != SILC_SKE_STATUS_OK) {
410 silc_mp_uninit(&payload->x);
411 silc_free(payload->pk_data);
413 ske->status = status;
419 /* Send the packet. */
420 if (ske->callbacks->send_packet)
421 (*ske->callbacks->send_packet)(ske, payload_buf,
422 SILC_PACKET_KEY_EXCHANGE_1,
423 ske->callbacks->context);
425 silc_buffer_free(payload_buf);
430 /* An initiator finish final callback that is called to indicate that
431 the SKE protocol may continue. */
433 static void silc_ske_initiator_finish_final(SilcSKE ske,
434 SilcSKEStatus status,
437 SilcSKEKEPayload *payload;
438 unsigned char hash[32];
440 SilcPublicKey public_key = NULL;
442 /* If the SKE was freed during the async call then free it really now,
443 otherwise just decrement the reference counter. */
444 if (ske->status == SILC_SKE_STATUS_FREED) {
449 /* If the caller returns PENDING status SKE library will assume that
450 the caller will re-call this callback when it is not anymore in
452 if (status == SILC_SKE_STATUS_PENDING)
456 payload = ske->ke2_payload;
458 /* If the status is an error then the public key that was verified
459 by the caller is not authentic. */
460 if (status != SILC_SKE_STATUS_OK) {
461 ske->status = status;
462 if (ske->callbacks->proto_continue)
463 ske->callbacks->proto_continue(ske, ske->callbacks->context);
467 if (payload->pk_data) {
468 /* Decode the public key */
469 if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len,
471 status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
472 if (ske->callbacks->proto_continue)
473 ske->callbacks->proto_continue(ske, ske->callbacks->context);
477 SILC_LOG_DEBUG(("Public key is authentic"));
479 /* Compute the hash value */
480 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
481 if (status != SILC_SKE_STATUS_OK)
484 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
485 memcpy(ske->hash, hash, hash_len);
486 ske->hash_len = hash_len;
488 SILC_LOG_DEBUG(("Verifying signature (HASH)"));
490 /* Verify signature */
491 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
492 if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
493 payload->sign_len, hash, hash_len) == FALSE) {
495 SILC_LOG_DEBUG(("Signature don't match"));
497 status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
501 SILC_LOG_DEBUG(("Signature is Ok"));
503 silc_pkcs_public_key_free(public_key);
504 memset(hash, 'F', hash_len);
507 ske->status = SILC_SKE_STATUS_OK;
509 /* Call the callback. The caller may now continue the SKE protocol. */
510 if (ske->callbacks->proto_continue)
511 ske->callbacks->proto_continue(ske, ske->callbacks->context);
516 memset(hash, 'F', sizeof(hash));
517 silc_ske_payload_ke_free(payload);
518 ske->ke2_payload = NULL;
520 silc_mp_uninit(ske->KEY);
525 silc_pkcs_public_key_free(public_key);
528 memset(ske->hash, 'F', hash_len);
529 silc_free(ske->hash);
533 if (status == SILC_SKE_STATUS_OK)
534 ske->status = SILC_SKE_STATUS_ERROR;
536 ske->status = status;
538 /* Call the callback. */
539 if (ske->callbacks->proto_continue)
540 ske->callbacks->proto_continue(ske, ske->callbacks->context);
543 /* Receives Key Exchange Payload from responder consisting responders
544 public key, f, and signature. This function verifies the public key,
545 computes the secret shared key and verifies the signature.
547 The `proto_continue' will be called to indicate that the caller may
548 continue with the SKE protocol. The caller must not continue
549 before the SKE libary has called that callback. If this function
550 returns an error the callback will not be called. It is called
551 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
552 However, note that when the library calls the callback the ske->status
555 This calls the `verify_key' callback to verify the received public
556 key or certificate. If the `verify_key' is provided then the remote
557 must send public key and it is considered to be an error if remote
558 does not send its public key. If caller is performing a re-key with
559 SKE then the `verify_key' is usually not provided when it is not also
560 required for the remote to send its public key. */
562 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
563 SilcBuffer ke_payload)
565 SilcSKEStatus status = SILC_SKE_STATUS_OK;
566 SilcSKEKEPayload *payload;
569 SILC_LOG_DEBUG(("Start"));
571 /* Decode the payload */
572 status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
573 if (status != SILC_SKE_STATUS_OK) {
574 ske->status = status;
577 ske->ke2_payload = payload;
579 if (!payload->pk_data && ske->callbacks->verify_key) {
580 SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
581 "even though we require it"));
582 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
586 SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
588 /* Compute the shared secret key */
589 KEY = silc_calloc(1, sizeof(*KEY));
591 silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
594 if (payload->pk_data && ske->callbacks->verify_key) {
595 SILC_LOG_DEBUG(("Verifying public key"));
598 (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
599 payload->pk_type, ske->callbacks->context,
600 silc_ske_initiator_finish_final, NULL);
602 /* We will continue to the final state after the public key has
603 been verified by the caller. */
604 return SILC_SKE_STATUS_PENDING;
607 /* Continue to final state */
609 silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
611 return SILC_SKE_STATUS_OK;
614 silc_ske_payload_ke_free(payload);
615 ske->ke2_payload = NULL;
617 silc_mp_uninit(ske->KEY);
621 if (status == SILC_SKE_STATUS_OK)
622 return SILC_SKE_STATUS_ERROR;
624 ske->status = status;
628 /* Starts Key Exchange protocol for responder. Responder receives
629 Key Exchange Start Payload from initiator consisting of all the
630 security properties the initiator supports. This function decodes
631 the payload and parses the payload further and selects the right
632 security properties. */
634 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
635 SilcSocketConnection sock,
637 SilcBuffer start_payload,
638 SilcSKESecurityPropertyFlag flags)
640 SilcSKEStatus status = SILC_SKE_STATUS_OK;
641 SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
643 SILC_LOG_DEBUG(("Start"));
648 /* Decode the payload */
649 status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
650 if (status != SILC_SKE_STATUS_OK) {
651 ske->status = status;
655 /* Take a copy of the payload buffer for future use. It is used to
656 compute the HASH value. */
657 ske->start_payload_copy = silc_buffer_copy(start_payload);
659 /* Force the mutual authentication flag if we want to do it. */
660 if (flags & SILC_SKE_SP_FLAG_MUTUAL) {
661 SILC_LOG_DEBUG(("Force mutual authentication"));
662 remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
665 /* Force PFS flag if we require it */
666 if (flags & SILC_SKE_SP_FLAG_PFS) {
667 SILC_LOG_DEBUG(("Force PFS"));
668 remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
671 /* Parse and select the security properties from the payload */
672 payload = silc_calloc(1, sizeof(*payload));
673 status = silc_ske_select_security_properties(ske, version,
674 payload, remote_payload);
675 if (status != SILC_SKE_STATUS_OK)
678 ske->start_payload = payload;
680 /* Call the callback function. */
681 if (ske->callbacks->payload_receive)
682 (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
684 silc_ske_payload_start_free(remote_payload);
690 silc_ske_payload_start_free(remote_payload);
694 if (status == SILC_SKE_STATUS_OK)
695 return SILC_SKE_STATUS_ERROR;
697 ske->status = status;
701 /* The selected security properties from the initiator payload is now
702 encoded into Key Exchange Start Payload and sent to the initiator. */
704 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
706 SilcSKEStatus status = SILC_SKE_STATUS_OK;
707 SilcBuffer payload_buf;
708 SilcSKESecurityProperties prop;
709 SilcSKEDiffieHellmanGroup group = NULL;
711 SILC_LOG_DEBUG(("Start"));
713 /* Allocate security properties from the payload. These are allocated
714 only for this negotiation and will be free'd after KE is over. */
715 ske->prop = prop = silc_calloc(1, sizeof(*prop));
716 prop->flags = ske->start_payload->flags;
717 status = silc_ske_group_get_by_name(ske->start_payload->ke_grp_list, &group);
718 if (status != SILC_SKE_STATUS_OK)
723 if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list,
724 &prop->pkcs) == FALSE) {
725 status = SILC_SKE_STATUS_UNKNOWN_PKCS;
729 if (silc_cipher_alloc(ske->start_payload->enc_alg_list,
730 &prop->cipher) == FALSE) {
731 status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
735 if (silc_hash_alloc(ske->start_payload->hash_alg_list,
736 &prop->hash) == FALSE) {
737 status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
741 if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
742 &prop->hmac) == FALSE) {
743 status = SILC_SKE_STATUS_UNKNOWN_HMAC;
747 /* Encode the payload */
748 status = silc_ske_payload_start_encode(ske, ske->start_payload,
750 if (status != SILC_SKE_STATUS_OK)
753 /* Send the packet. */
754 if (ske->callbacks->send_packet)
755 (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
756 ske->callbacks->context);
758 silc_buffer_free(payload_buf);
764 silc_ske_group_free(group);
767 silc_pkcs_free(prop->pkcs);
769 silc_cipher_free(prop->cipher);
771 silc_hash_free(prop->hash);
773 silc_hmac_free(prop->hmac);
777 if (status == SILC_SKE_STATUS_OK)
778 return SILC_SKE_STATUS_ERROR;
780 ske->status = status;
784 /* An responder phase 2 final callback that is called to indicate that
785 the SKE protocol may continue. */
787 static void silc_ske_responder_phase2_final(SilcSKE ske,
788 SilcSKEStatus status,
791 SilcSKEKEPayload *recv_payload, *send_payload;
794 /* If the SKE was freed during the async call then free it really now,
795 otherwise just decrement the reference counter. */
796 if (ske->status == SILC_SKE_STATUS_FREED) {
801 /* If the caller returns PENDING status SKE library will assume that
802 the caller will re-call this callback when it is not anymore in
804 if (status == SILC_SKE_STATUS_PENDING)
808 recv_payload = ske->ke1_payload;
810 /* If the status is an error then the public key that was verified
811 by the caller is not authentic. */
812 if (status != SILC_SKE_STATUS_OK) {
813 ske->status = status;
814 if (ske->callbacks->proto_continue)
815 ske->callbacks->proto_continue(ske, ske->callbacks->context);
819 /* The public key verification was performed only if the Mutual
820 Authentication flag is set. */
821 if (ske->start_payload &&
822 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
823 SilcPublicKey public_key = NULL;
824 unsigned char hash[32];
827 /* Decode the public key */
828 if (!silc_pkcs_public_key_decode(recv_payload->pk_data,
829 recv_payload->pk_len,
831 ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
832 if (ske->callbacks->proto_continue)
833 ske->callbacks->proto_continue(ske, ske->callbacks->context);
837 SILC_LOG_DEBUG(("Public key is authentic"));
839 /* Compute the hash value */
840 status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
841 if (status != SILC_SKE_STATUS_OK) {
842 ske->status = status;
843 if (ske->callbacks->proto_continue)
844 ske->callbacks->proto_continue(ske, ske->callbacks->context);
848 SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
850 /* Verify signature */
851 silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
852 if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data,
853 recv_payload->sign_len, hash, hash_len) == FALSE) {
855 SILC_LOG_DEBUG(("Signature don't match"));
857 ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
858 if (ske->callbacks->proto_continue)
859 ske->callbacks->proto_continue(ske, ske->callbacks->context);
863 SILC_LOG_DEBUG(("Signature is Ok"));
865 silc_pkcs_public_key_free(public_key);
866 memset(hash, 'F', hash_len);
869 /* Create the random number x, 1 < x < q. */
870 x = silc_calloc(1, sizeof(*x));
873 silc_ske_create_rnd(ske, &ske->prop->group->group_order,
874 silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
876 if (status != SILC_SKE_STATUS_OK) {
879 ske->status = status;
880 if (ske->callbacks->proto_continue)
881 ske->callbacks->proto_continue(ske, ske->callbacks->context);
885 /* Save the results for later processing */
886 send_payload = silc_calloc(1, sizeof(*send_payload));
888 ske->ke2_payload = send_payload;
890 SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
892 /* Do the Diffie Hellman computation, f = g ^ x mod p */
893 silc_mp_init(&send_payload->x);
894 silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
895 &ske->prop->group->group);
897 /* Call the callback. The caller may now continue with the SKE protocol. */
898 ske->status = SILC_SKE_STATUS_OK;
899 if (ske->callbacks->proto_continue)
900 ske->callbacks->proto_continue(ske, ske->callbacks->context);
903 /* This function receives the Key Exchange Payload from the initiator.
904 This also performs the mutual authentication if required. Then, this
905 function first generated a random number x, such that 1 < x < q
906 and computes f = g ^ x mod p. This then puts the result f to a Key
909 The `proto_continue' will be called to indicate that the caller may
910 continue with the SKE protocol. The caller must not continue
911 before the SKE libary has called that callback. If this function
912 returns an error the callback will not be called. It is called
913 if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
914 However, note that when the library calls the callback the ske->status
917 This calls the `verify_key' callback to verify the received public
918 key or certificate if the Mutual Authentication flag is set. If the
919 `verify_key' is provided then the remote must send public key and it
920 is considered to be an error if remote does not send its public key. */
922 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
923 SilcBuffer ke_payload)
925 SilcSKEStatus status = SILC_SKE_STATUS_OK;
926 SilcSKEKEPayload *recv_payload;
928 SILC_LOG_DEBUG(("Start"));
930 /* Decode Key Exchange Payload */
931 status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
932 if (status != SILC_SKE_STATUS_OK) {
933 ske->status = status;
937 ske->ke1_payload = recv_payload;
939 /* Verify the received public key and verify the signature if we are
940 doing mutual authentication. */
941 if (ske->start_payload &&
942 ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
944 SILC_LOG_DEBUG(("We are doing mutual authentication"));
946 if (!recv_payload->pk_data && ske->callbacks->verify_key) {
947 SILC_LOG_DEBUG(("Remote end did not send its public key (or "
948 "certificate), even though we require it"));
949 ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
953 if (recv_payload->pk_data && ske->callbacks->verify_key) {
954 SILC_LOG_DEBUG(("Verifying public key"));
957 (*ske->callbacks->verify_key)(ske, recv_payload->pk_data,
958 recv_payload->pk_len,
959 recv_payload->pk_type,
960 ske->callbacks->context,
961 silc_ske_responder_phase2_final, NULL);
963 /* We will continue to the final state after the public key has
964 been verified by the caller. */
965 return SILC_SKE_STATUS_PENDING;
969 /* Continue to final state */
971 silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
973 return SILC_SKE_STATUS_OK;
976 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
977 value to be signed and sent to the other end. This then encodes Key
978 Exchange Payload and sends it to the other end. */
980 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
981 SilcPublicKey public_key,
982 SilcPrivateKey private_key,
983 SilcSKEPKType pk_type)
985 SilcSKEStatus status = SILC_SKE_STATUS_OK;
986 SilcBuffer payload_buf;
988 unsigned char hash[32], sign[1024], *pk;
989 uint32 hash_len, sign_len, pk_len;
991 SILC_LOG_DEBUG(("Start"));
993 SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
995 /* Compute the shared secret key */
996 KEY = silc_calloc(1, sizeof(*KEY));
998 silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
999 &ske->prop->group->group);
1002 if (public_key && private_key) {
1003 SILC_LOG_DEBUG(("Getting public key"));
1005 /* Get the public key */
1006 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1008 status = SILC_SKE_STATUS_ERROR;
1011 ske->ke2_payload->pk_data = pk;
1012 ske->ke2_payload->pk_len = pk_len;
1014 SILC_LOG_DEBUG(("Computing HASH value"));
1016 /* Compute the hash value */
1017 memset(hash, 0, sizeof(hash));
1018 status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
1019 if (status != SILC_SKE_STATUS_OK)
1022 ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
1023 memcpy(ske->hash, hash, hash_len);
1024 ske->hash_len = hash_len;
1026 SILC_LOG_DEBUG(("Signing HASH value"));
1028 /* Sign the hash value */
1029 silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
1030 private_key->prv_len);
1031 silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
1032 ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
1033 memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1034 memset(sign, 0, sizeof(sign));
1035 ske->ke2_payload->sign_len = sign_len;
1037 ske->ke2_payload->pk_type = pk_type;
1039 /* Encode the Key Exchange Payload */
1040 status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1042 if (status != SILC_SKE_STATUS_OK)
1045 /* Send the packet. */
1046 if (ske->callbacks->send_packet)
1047 (*ske->callbacks->send_packet)(ske, payload_buf,
1048 SILC_PACKET_KEY_EXCHANGE_2,
1049 ske->callbacks->context);
1051 silc_buffer_free(payload_buf);
1056 silc_mp_uninit(ske->KEY);
1057 silc_free(ske->KEY);
1059 silc_ske_payload_ke_free(ske->ke2_payload);
1061 if (status == SILC_SKE_STATUS_OK)
1062 return SILC_SKE_STATUS_ERROR;
1064 ske->status = status;
1068 /* The Key Exchange protocol is ended by calling this function. This
1069 must not be called until the keys are processed like the protocol
1070 defines. This function is for both initiator and responder. */
1072 SilcSKEStatus silc_ske_end(SilcSKE ske)
1076 SILC_LOG_DEBUG(("Start"));
1078 packet = silc_buffer_alloc(4);
1079 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1080 silc_buffer_format(packet,
1081 SILC_STR_UI_INT((uint32)SILC_SKE_STATUS_OK),
1084 if (ske->callbacks->send_packet)
1085 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS,
1086 ske->callbacks->context);
1088 silc_buffer_free(packet);
1090 return SILC_SKE_STATUS_OK;
1093 /* Aborts the Key Exchange protocol. This is called if error occurs
1094 while performing the protocol. The status argument is the error
1095 status and it is sent to the remote end. */
1097 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1101 SILC_LOG_DEBUG(("Start"));
1103 packet = silc_buffer_alloc(4);
1104 silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
1105 silc_buffer_format(packet,
1106 SILC_STR_UI_INT((uint32)status),
1109 if (ske->callbacks->send_packet)
1110 (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE,
1111 ske->callbacks->context);
1113 silc_buffer_free(packet);
1115 return SILC_SKE_STATUS_OK;
1118 /* Assembles security properties to Key Exchange Start Payload to be
1119 sent to the remote end. This checks system wide (SILC system, that is)
1120 settings and chooses from those. However, if other properties
1121 should be used this function is easy to replace by another function,
1122 as, this function is called by the caller of the protocol and not
1123 by the protocol itself. */
1126 silc_ske_assemble_security_properties(SilcSKE ske,
1127 SilcSKESecurityPropertyFlag flags,
1128 const char *version,
1129 SilcSKEStartPayload **return_payload)
1131 SilcSKEStartPayload *rp;
1134 SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1136 rp = silc_calloc(1, sizeof(*rp));
1139 rp->flags = (unsigned char)flags;
1141 /* Set random cookie */
1142 rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1143 for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1144 rp->cookie[i] = silc_rng_get_byte(ske->rng);
1145 rp->cookie_len = SILC_SKE_COOKIE_LEN;
1148 rp->version = strdup(version);
1149 rp->version_len = strlen(version);
1151 /* Get supported Key Exhange groups */
1152 rp->ke_grp_list = silc_ske_get_supported_groups();
1153 rp->ke_grp_len = strlen(rp->ke_grp_list);
1155 /* Get supported PKCS algorithms */
1156 rp->pkcs_alg_list = silc_pkcs_get_supported();
1157 rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1159 /* Get supported encryption algorithms */
1160 rp->enc_alg_list = silc_cipher_get_supported();
1161 rp->enc_alg_len = strlen(rp->enc_alg_list);
1163 /* Get supported hash algorithms */
1164 rp->hash_alg_list = silc_hash_get_supported();
1165 rp->hash_alg_len = strlen(rp->hash_alg_list);
1167 /* Get supported HMACs */
1168 rp->hmac_alg_list = silc_hmac_get_supported();
1169 rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1172 /* Get supported compression algorithms */
1173 rp->comp_alg_list = strdup("");
1174 rp->comp_alg_len = 0;
1176 rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1177 2 + rp->version_len +
1178 2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len +
1179 2 + rp->enc_alg_len + 2 + rp->hash_alg_len +
1180 2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1182 *return_payload = rp;
1184 return SILC_SKE_STATUS_OK;
1187 /* Selects the supported security properties from the remote end's Key
1188 Exchange Start Payload. */
1191 silc_ske_select_security_properties(SilcSKE ske,
1192 const char *version,
1193 SilcSKEStartPayload *payload,
1194 SilcSKEStartPayload *remote_payload)
1196 SilcSKEStatus status;
1197 SilcSKEStartPayload *rp;
1201 SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1203 rp = remote_payload;
1205 /* Check version string */
1206 if (ske->callbacks->check_version) {
1207 status = ske->callbacks->check_version(ske, rp->version,
1209 ske->callbacks->context);
1210 if (status != SILC_SKE_STATUS_OK) {
1211 ske->status = status;
1216 /* Flags are returned unchanged. */
1217 payload->flags = rp->flags;
1219 /* Take cookie, we must return it to sender unmodified. */
1220 payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1221 payload->cookie_len = SILC_SKE_COOKIE_LEN;
1222 memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1224 /* Put our version to our reply */
1225 payload->version = strdup(version);
1226 payload->version_len = strlen(version);
1228 /* Get supported Key Exchange groups */
1229 cp = rp->ke_grp_list;
1230 if (cp && strchr(cp, ',')) {
1234 len = strcspn(cp, ",");
1235 item = silc_calloc(len + 1, sizeof(char));
1236 memcpy(item, cp, len);
1238 SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1240 if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1241 SILC_LOG_DEBUG(("Found KE group `%s'", item));
1243 payload->ke_grp_len = len;
1244 payload->ke_grp_list = item;
1249 if (strlen(cp) == 0)
1258 if (!payload->ke_grp_len && !payload->ke_grp_list) {
1259 SILC_LOG_DEBUG(("Could not find supported KE group"));
1261 return SILC_SKE_STATUS_UNKNOWN_GROUP;
1265 if (!rp->ke_grp_len) {
1266 SILC_LOG_DEBUG(("KE group not defined in payload"));
1268 return SILC_SKE_STATUS_BAD_PAYLOAD;
1271 SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1272 SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1274 payload->ke_grp_len = rp->ke_grp_len;
1275 payload->ke_grp_list = strdup(rp->ke_grp_list);
1278 /* Get supported PKCS algorithms */
1279 cp = rp->pkcs_alg_list;
1280 if (cp && strchr(cp, ',')) {
1284 len = strcspn(cp, ",");
1285 item = silc_calloc(len + 1, sizeof(char));
1286 memcpy(item, cp, len);
1288 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1290 if (silc_pkcs_is_supported(item) == TRUE) {
1291 SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1293 payload->pkcs_alg_len = len;
1294 payload->pkcs_alg_list = item;
1299 if (strlen(cp) == 0)
1308 if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1309 SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1310 silc_free(payload->ke_grp_list);
1312 return SILC_SKE_STATUS_UNKNOWN_PKCS;
1316 if (!rp->pkcs_alg_len) {
1317 SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1318 silc_free(payload->ke_grp_list);
1320 return SILC_SKE_STATUS_BAD_PAYLOAD;
1323 SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1324 SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1326 payload->pkcs_alg_len = rp->pkcs_alg_len;
1327 payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1330 /* Get supported encryption algorithms */
1331 cp = rp->enc_alg_list;
1332 if (cp && strchr(cp, ',')) {
1336 len = strcspn(cp, ",");
1337 item = silc_calloc(len + 1, sizeof(char));
1338 memcpy(item, cp, len);
1340 SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1342 if (silc_cipher_is_supported(item) == TRUE) {
1343 SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1345 payload->enc_alg_len = len;
1346 payload->enc_alg_list = item;
1351 if (strlen(cp) == 0)
1360 if (!payload->enc_alg_len && !payload->enc_alg_list) {
1361 SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1362 silc_free(payload->ke_grp_list);
1363 silc_free(payload->pkcs_alg_list);
1365 return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1369 if (!rp->enc_alg_len) {
1370 SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1371 silc_free(payload->ke_grp_list);
1372 silc_free(payload->pkcs_alg_list);
1374 return SILC_SKE_STATUS_BAD_PAYLOAD;
1377 SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1380 payload->enc_alg_len = rp->enc_alg_len;
1381 payload->enc_alg_list = strdup(rp->enc_alg_list);
1384 /* Get supported hash algorithms */
1385 cp = rp->hash_alg_list;
1386 if (cp && strchr(cp, ',')) {
1390 len = strcspn(cp, ",");
1391 item = silc_calloc(len + 1, sizeof(char));
1392 memcpy(item, cp, len);
1394 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1396 if (silc_hash_is_supported(item) == TRUE) {
1397 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1399 payload->hash_alg_len = len;
1400 payload->hash_alg_list = item;
1405 if (strlen(cp) == 0)
1414 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1415 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1416 silc_free(payload->ke_grp_list);
1417 silc_free(payload->pkcs_alg_list);
1418 silc_free(payload->enc_alg_list);
1420 return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1424 if (!rp->hash_alg_len) {
1425 SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1426 silc_free(payload->ke_grp_list);
1427 silc_free(payload->pkcs_alg_list);
1428 silc_free(payload->enc_alg_list);
1430 return SILC_SKE_STATUS_BAD_PAYLOAD;
1433 SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1434 rp->hash_alg_list));
1436 payload->hash_alg_len = rp->hash_alg_len;
1437 payload->hash_alg_list = strdup(rp->hash_alg_list);
1440 /* Get supported HMACs */
1441 cp = rp->hmac_alg_list;
1442 if (cp && strchr(cp, ',')) {
1446 len = strcspn(cp, ",");
1447 item = silc_calloc(len + 1, sizeof(char));
1448 memcpy(item, cp, len);
1450 SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1452 if (silc_hmac_is_supported(item) == TRUE) {
1453 SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1455 payload->hmac_alg_len = len;
1456 payload->hmac_alg_list = item;
1461 if (strlen(cp) == 0)
1470 if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1471 SILC_LOG_DEBUG(("Could not find supported HMAC"));
1472 silc_free(payload->ke_grp_list);
1473 silc_free(payload->pkcs_alg_list);
1474 silc_free(payload->enc_alg_list);
1475 silc_free(payload->hash_alg_list);
1477 return SILC_SKE_STATUS_UNKNOWN_HMAC;
1481 if (!rp->hmac_alg_len) {
1482 SILC_LOG_DEBUG(("HMAC not defined in payload"));
1483 silc_free(payload->ke_grp_list);
1484 silc_free(payload->pkcs_alg_list);
1485 silc_free(payload->enc_alg_list);
1486 silc_free(payload->hash_alg_list);
1488 return SILC_SKE_STATUS_BAD_PAYLOAD;
1491 SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1492 rp->hmac_alg_list));
1494 payload->hmac_alg_len = rp->hmac_alg_len;
1495 payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1499 /* Get supported compression algorithms */
1500 cp = rp->hash_alg_list;
1501 if (cp && strchr(cp, ',')) {
1505 len = strcspn(cp, ",");
1506 item = silc_calloc(len + 1, sizeof(char));
1507 memcpy(item, cp, len);
1509 SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1511 if (silc_hash_is_supported(item) == TRUE) {
1512 SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1514 payload->hash_alg_len = len;
1515 payload->hash_alg_list = item;
1520 if (strlen(cp) == 0)
1529 if (!payload->hash_alg_len && !payload->hash_alg_list) {
1530 SILC_LOG_DEBUG(("Could not find supported hash alg"));
1531 silc_ske_abort(ske, SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION);
1532 silc_free(payload->ke_grp_list);
1533 silc_free(payload->pkcs_alg_list);
1534 silc_free(payload->enc_alg_list);
1543 payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
1544 2 + payload->version_len +
1545 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
1546 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
1547 2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1549 return SILC_SKE_STATUS_OK;
1552 /* Creates random number such that 1 < rnd < n and at most length
1553 of len bits. The rnd sent as argument must be initialized. */
1555 static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n,
1559 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1560 unsigned char *string;
1562 SILC_LOG_DEBUG(("Creating random number"));
1564 /* Get the random number as string */
1565 string = silc_rng_get_rn_data(ske->rng, (len / 8));
1567 return SILC_SKE_STATUS_ERROR;
1569 /* Decode the string into a MP integer */
1570 silc_mp_bin2mp(string, (len / 8), rnd);
1571 silc_mp_mod_2exp(rnd, rnd, len);
1574 if (silc_mp_cmp_ui(rnd, 1) < 0)
1575 status = SILC_SKE_STATUS_ERROR;
1577 if (silc_mp_cmp(rnd, n) >= 0)
1578 status = SILC_SKE_STATUS_ERROR;
1580 memset(string, 'F', (len / 8));
1586 /* Creates a hash value HASH as defined in the SKE protocol. If the
1587 `initiator' is TRUE then this function is used to create the HASH_i
1588 hash value defined in the protocol. If it is FALSE then this is used
1589 to create the HASH value defined by the protocol. */
1591 static SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
1592 unsigned char *return_hash,
1593 uint32 *return_hash_len,
1596 SilcSKEStatus status = SILC_SKE_STATUS_OK;
1598 unsigned char *e, *f, *KEY;
1599 uint32 e_len, f_len, KEY_len;
1602 SILC_LOG_DEBUG(("Start"));
1604 if (initiator == FALSE) {
1605 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1606 f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1607 KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1609 /* Format the buffer used to compute the hash value */
1610 /* XXX Backward support for 0.6.1 */
1611 if (ske->backward_version == 1) {
1612 SILC_LOG_DEBUG(("*********** Using old KE payload"));
1613 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1614 ske->ke2_payload->pk_len + e_len +
1616 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1619 silc_buffer_format(buf,
1620 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1621 ske->start_payload_copy->len),
1622 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1623 ske->ke2_payload->pk_len),
1624 SILC_STR_UI_XNSTRING(e, e_len),
1625 SILC_STR_UI_XNSTRING(f, f_len),
1626 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1629 /* Initiator is not required to send its public key */
1630 SILC_LOG_DEBUG(("*********** Using new KE payload"));
1631 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1632 ske->ke2_payload->pk_len +
1633 ske->ke1_payload->pk_len +
1634 e_len + f_len + KEY_len);
1635 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1637 if (!ske->ke1_payload->pk_data) {
1639 silc_buffer_format(buf,
1640 SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1642 ske->start_payload_copy->
1644 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1645 ske->ke2_payload->pk_len),
1646 SILC_STR_UI_XNSTRING(e, e_len),
1647 SILC_STR_UI_XNSTRING(f, f_len),
1648 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1652 silc_buffer_format(buf,
1653 SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1655 ske->start_payload_copy->
1657 SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data,
1658 ske->ke2_payload->pk_len),
1659 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1660 ske->ke1_payload->pk_len),
1661 SILC_STR_UI_XNSTRING(e, e_len),
1662 SILC_STR_UI_XNSTRING(f, f_len),
1663 SILC_STR_UI_XNSTRING(KEY, KEY_len),
1668 silc_buffer_free(buf);
1669 memset(e, 0, e_len);
1670 memset(f, 0, f_len);
1671 memset(KEY, 0, KEY_len);
1675 return SILC_SKE_STATUS_ERROR;
1678 memset(e, 0, e_len);
1679 memset(f, 0, f_len);
1680 memset(KEY, 0, KEY_len);
1685 e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1687 buf = silc_buffer_alloc(ske->start_payload_copy->len +
1688 ske->ke1_payload->pk_len + e_len);
1689 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1691 /* Format the buffer used to compute the hash value */
1693 silc_buffer_format(buf,
1694 SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1695 ske->start_payload_copy->len),
1696 SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data,
1697 ske->ke1_payload->pk_len),
1698 SILC_STR_UI_XNSTRING(e, e_len),
1701 silc_buffer_free(buf);
1702 memset(e, 0, e_len);
1704 return SILC_SKE_STATUS_ERROR;
1707 memset(e, 0, e_len);
1712 silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1713 *return_hash_len = ske->prop->hash->hash->hash_len;
1715 if (initiator == FALSE) {
1716 SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1718 SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1721 silc_buffer_free(buf);
1726 /* Processes the provided key material `data' as the SILC protocol
1727 specification defines. */
1730 silc_ske_process_key_material_data(unsigned char *data,
1733 uint32 req_enc_key_len,
1734 uint32 req_hmac_key_len,
1736 SilcSKEKeyMaterial *key)
1739 unsigned char hashd[32];
1740 uint32 hash_len = req_hmac_key_len;
1741 uint32 enc_key_len = req_enc_key_len / 8;
1743 SILC_LOG_DEBUG(("Start"));
1745 if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1746 return SILC_SKE_STATUS_ERROR;
1748 buf = silc_buffer_alloc(1 + data_len);
1749 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1750 silc_buffer_format(buf,
1751 SILC_STR_UI_CHAR(0),
1752 SILC_STR_UI_XNSTRING(data, data_len),
1756 memset(hashd, 0, sizeof(hashd));
1758 silc_hash_make(hash, buf->data, buf->len, hashd);
1759 key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1760 memcpy(key->send_iv, hashd, req_iv_len);
1761 memset(hashd, 0, sizeof(hashd));
1763 silc_hash_make(hash, buf->data, buf->len, hashd);
1764 key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1765 memcpy(key->receive_iv, hashd, req_iv_len);
1766 key->iv_len = req_iv_len;
1768 /* Take the encryption keys. If requested key size is more than
1769 the size of hash length we will distribute more key material
1770 as protocol defines. */
1772 if (enc_key_len > hash_len) {
1774 unsigned char k1[32], k2[32], k3[32];
1775 unsigned char *dtmp;
1778 if (enc_key_len > (3 * hash_len))
1779 return SILC_SKE_STATUS_ERROR;
1781 /* Take first round */
1782 memset(k1, 0, sizeof(k1));
1783 silc_hash_make(hash, buf->data, buf->len, k1);
1785 /* Take second round */
1786 dist = silc_buffer_alloc(data_len + hash_len);
1787 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1788 silc_buffer_format(dist,
1789 SILC_STR_UI_XNSTRING(data, data_len),
1790 SILC_STR_UI_XNSTRING(k1, hash_len),
1792 memset(k2, 0, sizeof(k2));
1793 silc_hash_make(hash, dist->data, dist->len, k2);
1795 /* Take third round */
1796 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1797 silc_buffer_pull_tail(dist, hash_len);
1798 silc_buffer_pull(dist, data_len + hash_len);
1799 silc_buffer_format(dist,
1800 SILC_STR_UI_XNSTRING(k2, hash_len),
1802 silc_buffer_push(dist, data_len + hash_len);
1803 memset(k3, 0, sizeof(k3));
1804 silc_hash_make(hash, dist->data, dist->len, k3);
1806 /* Then, save the keys */
1807 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1808 memcpy(dtmp, k1, hash_len);
1809 memcpy(dtmp + hash_len, k2, hash_len);
1810 memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1812 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1813 memcpy(key->send_enc_key, dtmp, enc_key_len);
1814 key->enc_key_len = req_enc_key_len;
1816 memset(dtmp, 0, (3 * hash_len));
1817 memset(k1, 0, sizeof(k1));
1818 memset(k2, 0, sizeof(k2));
1819 memset(k3, 0, sizeof(k3));
1821 silc_buffer_free(dist);
1823 /* Take normal hash as key */
1824 memset(hashd, 0, sizeof(hashd));
1825 silc_hash_make(hash, buf->data, buf->len, hashd);
1826 key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1827 memcpy(key->send_enc_key, hashd, enc_key_len);
1828 key->enc_key_len = req_enc_key_len;
1832 if (enc_key_len > hash_len) {
1834 unsigned char k1[32], k2[32], k3[32];
1835 unsigned char *dtmp;
1838 if (enc_key_len > (3 * hash_len))
1839 return SILC_SKE_STATUS_ERROR;
1841 /* Take first round */
1842 memset(k1, 0, sizeof(k1));
1843 silc_hash_make(hash, buf->data, buf->len, k1);
1845 /* Take second round */
1846 dist = silc_buffer_alloc(data_len + hash_len);
1847 silc_buffer_pull_tail(dist, SILC_BUFFER_END(dist));
1848 silc_buffer_format(dist,
1849 SILC_STR_UI_XNSTRING(data, data_len),
1850 SILC_STR_UI_XNSTRING(k1, hash_len),
1852 memset(k2, 0, sizeof(k2));
1853 silc_hash_make(hash, dist->data, dist->len, k2);
1855 /* Take third round */
1856 dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1857 silc_buffer_pull_tail(dist, hash_len);
1858 silc_buffer_pull(dist, data_len + hash_len);
1859 silc_buffer_format(dist,
1860 SILC_STR_UI_XNSTRING(k2, hash_len),
1862 silc_buffer_push(dist, data_len + hash_len);
1863 memset(k3, 0, sizeof(k3));
1864 silc_hash_make(hash, dist->data, dist->len, k3);
1866 /* Then, save the keys */
1867 dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1868 memcpy(dtmp, k1, hash_len);
1869 memcpy(dtmp + hash_len, k2, hash_len);
1870 memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1872 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1873 memcpy(key->receive_enc_key, dtmp, enc_key_len);
1874 key->enc_key_len = req_enc_key_len;
1876 memset(dtmp, 0, (3 * hash_len));
1877 memset(k1, 0, sizeof(k1));
1878 memset(k2, 0, sizeof(k2));
1879 memset(k3, 0, sizeof(k3));
1881 silc_buffer_free(dist);
1883 /* Take normal hash as key */
1884 memset(hashd, 0, sizeof(hashd));
1885 silc_hash_make(hash, buf->data, buf->len, hashd);
1886 key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1887 memcpy(key->receive_enc_key, hashd, enc_key_len);
1888 key->enc_key_len = req_enc_key_len;
1891 /* Take HMAC keys */
1892 memset(hashd, 0, sizeof(hashd));
1894 silc_hash_make(hash, buf->data, buf->len, hashd);
1895 key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1896 memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
1897 memset(hashd, 0, sizeof(hashd));
1899 silc_hash_make(hash, buf->data, buf->len, hashd);
1900 key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1901 memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
1902 key->hmac_key_len = req_hmac_key_len;
1903 memset(hashd, 0, sizeof(hashd));
1905 silc_buffer_free(buf);
1907 return SILC_SKE_STATUS_OK;
1910 /* Processes negotiated key material as protocol specifies. This returns
1911 the actual keys to be used in the SILC. */
1913 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
1915 uint32 req_enc_key_len,
1916 uint32 req_hmac_key_len,
1917 SilcSKEKeyMaterial *key)
1919 SilcSKEStatus status;
1921 unsigned char *tmpbuf;
1924 /* Encode KEY to binary data */
1925 tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1927 buf = silc_buffer_alloc(klen + ske->hash_len);
1928 silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
1929 silc_buffer_format(buf,
1930 SILC_STR_UI_XNSTRING(tmpbuf, klen),
1931 SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1934 /* Process the key material */
1935 status = silc_ske_process_key_material_data(buf->data, buf->len,
1936 req_iv_len, req_enc_key_len,
1938 ske->prop->hash, key);
1940 memset(tmpbuf, 0, klen);
1942 silc_buffer_free(buf);
1947 /* Free key material structure */
1949 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1955 silc_free(key->send_iv);
1956 if (key->receive_iv)
1957 silc_free(key->receive_iv);
1958 if (key->send_enc_key) {
1959 memset(key->send_enc_key, 0, key->enc_key_len / 8);
1960 silc_free(key->send_enc_key);
1962 if (key->receive_enc_key) {
1963 memset(key->receive_enc_key, 0, key->enc_key_len / 8);
1964 silc_free(key->receive_enc_key);
1966 if (key->send_hmac_key) {
1967 memset(key->send_hmac_key, 0, key->hmac_key_len);
1968 silc_free(key->send_hmac_key);
1970 if (key->receive_hmac_key) {
1971 memset(key->receive_hmac_key, 0, key->hmac_key_len);
1972 silc_free(key->receive_hmac_key);
1977 const char *silc_ske_status_string[] =
1981 "Unkown error occurred",
1982 "Bad payload in packet",
1983 "Unsupported group",
1984 "Unsupported cipher",
1986 "Unsupported hash function",
1988 "Unsupported public key (or certificate)",
1989 "Incorrect signature",
1990 "Bad or unsupported version",
1995 "Remote did not provide public key",
1996 "Key exchange protocol is not active",
1997 "Bad reserved field in packet",
1998 "Bad payload length in packet",
2004 /* Maps status to readable string and returns the string. If string is not
2005 found and empty character string ("") is returned. */
2007 const char *silc_ske_map_status(SilcSKEStatus status)
2011 for (i = 0; silc_ske_status_string[i]; i++)
2013 return silc_ske_status_string[i];