+ if (status == SILC_SKE_STATUS_OK)
+ ske->status = SILC_SKE_STATUS_ERROR;
+
+ ske->status = status;
+
+ /* Call the callback. */
+ if (ske->callbacks->proto_continue)
+ ske->callbacks->proto_continue(ske, ske->callbacks->context);
+}
+
+/* Receives Key Exchange Payload from responder consisting responders
+ public key, f, and signature. This function verifies the public key,
+ computes the secret shared key and verifies the signature.
+
+ The `proto_continue' will be called to indicate that the caller may
+ continue with the SKE protocol. The caller must not continue
+ before the SKE libary has called that callback. If this function
+ returns an error the callback will not be called. It is called
+ if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
+ However, note that when the library calls the callback the ske->status
+ may be error.
+
+ This calls the `verify_key' callback to verify the received public
+ key or certificate. If the `verify_key' is provided then the remote
+ must send public key and it is considered to be an error if remote
+ does not send its public key. If caller is performing a re-key with
+ SKE then the `verify_key' is usually not provided when it is not also
+ required for the remote to send its public key. */
+
+SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
+ SilcBuffer ke_payload)
+{
+ SilcSKEStatus status = SILC_SKE_STATUS_OK;
+ SilcSKEKEPayload *payload;
+ SilcMPInt *KEY;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Decode the payload */
+ status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
+ if (status != SILC_SKE_STATUS_OK) {
+ ske->status = status;
+ return status;
+ }
+ ske->ke2_payload = payload;
+
+ if (!payload->pk_data && ske->callbacks->verify_key) {
+ SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
+ "even though we require it"));
+ ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
+ goto err;
+ }
+
+ SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
+
+ /* Compute the shared secret key */
+ KEY = silc_calloc(1, sizeof(*KEY));
+ silc_mp_init(KEY);
+ silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
+ ske->KEY = KEY;
+
+ if (payload->pk_data && ske->callbacks->verify_key) {
+ SILC_LOG_DEBUG(("Verifying public key"));
+
+ ske->users++;
+ (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
+ payload->pk_type, ske->callbacks->context,
+ silc_ske_initiator_finish_final, NULL);
+
+ /* We will continue to the final state after the public key has
+ been verified by the caller. */
+ return SILC_SKE_STATUS_PENDING;
+ }
+
+ /* Continue to final state */
+ ske->users++;
+ silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
+
+ return SILC_SKE_STATUS_OK;
+
+ err:
+ silc_ske_payload_ke_free(payload);
+ ske->ke2_payload = NULL;
+
+ silc_mp_uninit(ske->KEY);
+ silc_free(ske->KEY);
+ ske->KEY = NULL;
+