This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
unsigned char *return_hash,
SilcUInt32 *return_hash_len,
int initiator);
unsigned char *return_hash,
SilcUInt32 *return_hash_len,
int initiator);
The `send_packet' callback is a function that sends the packet to
network. The SKE library will call it at any time packet needs to
The `send_packet' callback is a function that sends the packet to
network. The SKE library will call it at any time packet needs to
The `payload_receive' callback is called when the remote host's Key
Exchange Start Payload has been processed. The payload is saved
The `payload_receive' callback is called when the remote host's Key
Exchange Start Payload has been processed. The payload is saved
That is why the application must call the completion callback when the
verification process has been completed. The library then calls the user
callback (`proto_continue'), if it is provided to indicate that the SKE
That is why the application must call the completion callback when the
verification process has been completed. The library then calls the user
callback (`proto_continue'), if it is provided to indicate that the SKE
The `proto_continue' callback is called to indicate that it is
safe to continue the execution of the SKE protocol after executing
an asynchronous operation, such as calling the `verify_key' callback
The `proto_continue' callback is called to indicate that it is
safe to continue the execution of the SKE protocol after executing
an asynchronous operation, such as calling the `verify_key' callback
The `check_version' callback is called to verify the remote host's
version. The application may check its own version against the remote
host's version and determine whether supporting the remote host
The `check_version' callback is called to verify the remote host's
version. The application may check its own version against the remote
host's version and determine whether supporting the remote host
- (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
+ (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
compute the HASH value. */
ske->start_payload_copy = payload_buf;
ske->start_payload = start_payload;
compute the HASH value. */
ske->start_payload_copy = payload_buf;
ske->start_payload = start_payload;
security properties selected by the responder from our payload
sent in the silc_ske_initiator_start function. */
security properties selected by the responder from our payload
sent in the silc_ske_initiator_start function. */
silc_ske_payload_start_free(ske->start_payload);
/* Take the selected security properties into use while doing
silc_ske_payload_start_free(ske->start_payload);
/* Take the selected security properties into use while doing
exchange. The same data is returned to upper levels by calling
the callback function. */
ske->prop = prop = silc_calloc(1, sizeof(*prop));
exchange. The same data is returned to upper levels by calling
the callback function. */
ske->prop = prop = silc_calloc(1, sizeof(*prop));
-/* This function creates random number x, such that 1 < x < q and
- computes e = g ^ x mod p and sends the result to the remote end in
+/* This function creates random number x, such that 1 < x < q and
+ computes e = g ^ x mod p and sends the result to the remote end in
silc_ske_create_rnd(ske, &ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
x);
silc_ske_create_rnd(ske, &ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
x);
/* Do the Diffie Hellman computation, e = g ^ x mod p */
silc_mp_init(&payload->x);
/* Do the Diffie Hellman computation, e = g ^ x mod p */
silc_mp_init(&payload->x);
- silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
+ silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x,
silc_ske_make_hash(ske, hash, &hash_len, TRUE);
SILC_LOG_DEBUG(("Signing HASH_i value"));
silc_ske_make_hash(ske, hash, &hash_len, TRUE);
SILC_LOG_DEBUG(("Signing HASH_i value"));
private_key->prv_len);
if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
!silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
private_key->prv_len);
if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
!silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
- (*ske->callbacks->send_packet)(ske, payload_buf,
- SILC_PACKET_KEY_EXCHANGE_1,
+ (*ske->callbacks->send_packet)(ske, payload_buf,
+ SILC_PACKET_KEY_EXCHANGE_1,
&public_key)) {
status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
SILC_LOG_ERROR(("Unsupported/malformed public key received"));
&public_key)) {
status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
SILC_LOG_ERROR(("Unsupported/malformed public key received"));
payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
/* Receives Key Exchange Payload from responder consisting responders
public key, f, and signature. This function verifies the public key,
/* Receives Key Exchange Payload from responder consisting responders
public key, f, and signature. This function verifies the public key,
The `proto_continue' will be called to indicate that the caller may
continue with the SKE protocol. The caller must not continue
The `proto_continue' will be called to indicate that the caller may
continue with the SKE protocol. The caller must not continue
This calls the `verify_key' callback to verify the received public
key or certificate. If the `verify_key' is provided then the remote
This calls the `verify_key' callback to verify the received public
key or certificate. If the `verify_key' is provided then the 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. */
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. */
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);
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;
/* We will continue to the final state after the public key has
been verified by the caller. */
return SILC_SKE_STATUS_PENDING;
/* Starts Key Exchange protocol for responder. Responder receives
Key Exchange Start Payload from initiator consisting of all the
security properties the initiator supports. This function decodes
/* Starts Key Exchange protocol for responder. Responder receives
Key Exchange Start Payload from initiator consisting of all the
security properties the initiator supports. This function decodes
encoded into Key Exchange Start Payload and sent to the initiator. */
SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
encoded into Key Exchange Start Payload and sent to the initiator. */
SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
- (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
+ (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE,
ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
SilcPublicKey public_key = NULL;
unsigned char hash[32];
SilcUInt32 hash_len;
/* Decode the public key */
ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
SilcPublicKey public_key = NULL;
unsigned char hash[32];
SilcUInt32 hash_len;
/* Decode the public key */
&public_key)) {
ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
SILC_LOG_ERROR(("Unsupported/malformed public key received"));
&public_key)) {
ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
SILC_LOG_ERROR(("Unsupported/malformed public key received"));
recv_payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
recv_payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
silc_pkcs_public_key_free(public_key);
memset(hash, 'F', hash_len);
}
/* Create the random number x, 1 < x < q. */
x = silc_calloc(1, sizeof(*x));
silc_mp_init(x);
/* Create the random number x, 1 < x < q. */
x = silc_calloc(1, sizeof(*x));
silc_mp_init(x);
silc_ske_create_rnd(ske, &ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
x);
silc_ske_create_rnd(ske, &ske->prop->group->group_order,
silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
x);
/* Do the Diffie Hellman computation, f = g ^ x mod p */
silc_mp_init(&send_payload->x);
/* Do the Diffie Hellman computation, f = g ^ x mod p */
silc_mp_init(&send_payload->x);
- silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
+ silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x,
/* Call the callback. The caller may now continue with the SKE protocol. */
ske->status = SILC_SKE_STATUS_OK;
if (ske->callbacks->proto_continue)
/* Call the callback. The caller may now continue with the SKE protocol. */
ske->status = SILC_SKE_STATUS_OK;
if (ske->callbacks->proto_continue)
function first generated a random number x, such that 1 < x < q
and computes f = g ^ x mod p. This then puts the result f to a Key
function first generated a random number x, such that 1 < x < q
and computes f = g ^ x mod p. This then puts the result f to a Key
The `proto_continue' will be called to indicate that the caller may
continue with the SKE protocol. The caller must not continue
The `proto_continue' will be called to indicate that the caller may
continue with the SKE protocol. The caller must not continue
ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
SILC_LOG_DEBUG(("We are doing mutual authentication"));
ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
SILC_LOG_DEBUG(("We are doing mutual authentication"));
if (!recv_payload->pk_data && ske->callbacks->verify_key) {
SILC_LOG_ERROR(("Remote end did not send its public key (or "
"certificate), even though we require it"));
if (!recv_payload->pk_data && ske->callbacks->verify_key) {
SILC_LOG_ERROR(("Remote end did not send its public key (or "
"certificate), even though we require it"));
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
silc_mp_init(KEY);
/* Compute the shared secret key */
KEY = silc_calloc(1, sizeof(*KEY));
silc_mp_init(KEY);
- silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
+ silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x,
&ske->prop->group->group);
ske->KEY = KEY;
if (public_key && private_key) {
SILC_LOG_DEBUG(("Getting public key"));
&ske->prop->group->group);
ske->KEY = KEY;
if (public_key && private_key) {
SILC_LOG_DEBUG(("Getting public key"));
/* Compute the hash value */
memset(hash, 0, sizeof(hash));
status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
/* Compute the hash value */
memset(hash, 0, sizeof(hash));
status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
ske->hash = silc_memdup(hash, hash_len);
ske->hash_len = hash_len;
ske->hash = silc_memdup(hash, hash_len);
ske->hash_len = hash_len;
private_key->prv_len);
if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
!silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
private_key->prv_len);
if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
!silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
SILC_PACKET_KEY_EXCHANGE_2,
ske->callbacks->context);
SILC_PACKET_KEY_EXCHANGE_2,
ske->callbacks->context);
silc_buffer_set(&packet, data, 4);
if (ske->callbacks->send_packet)
silc_buffer_set(&packet, data, 4);
if (ske->callbacks->send_packet)
- (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_SUCCESS,
+ (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_SUCCESS,
silc_buffer_set(&packet, data, 4);
if (ske->callbacks->send_packet)
silc_buffer_set(&packet, data, 4);
if (ske->callbacks->send_packet)
- (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_FAILURE,
+ (*ske->callbacks->send_packet)(ske, &packet, SILC_PACKET_FAILURE,
as, this function is called by the caller of the protocol and not
by the protocol itself. */
as, this function is called by the caller of the protocol and not
by the protocol itself. */
silc_ske_assemble_security_properties(SilcSKE ske,
SilcSKESecurityPropertyFlag flags,
const char *version,
silc_ske_assemble_security_properties(SilcSKE ske,
SilcSKESecurityPropertyFlag flags,
const char *version,
silc_ske_select_security_properties(SilcSKE ske,
const char *version,
SilcSKEStartPayload *payload,
silc_ske_select_security_properties(SilcSKE ske,
const char *version,
SilcSKEStartPayload *payload,
- payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
- 2 + payload->version_len +
- 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
- 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
+ payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN +
+ 2 + payload->version_len +
+ 2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len +
+ 2 + payload->enc_alg_len + 2 + payload->hash_alg_len +
/* Creates random number such that 1 < rnd < n and at most length
of len bits. The rnd sent as argument must be initialized. */
/* Creates random number such that 1 < rnd < n and at most length
of len bits. The rnd sent as argument must be initialized. */
hash value defined in the protocol. If it is FALSE then this is used
to create the HASH value defined by the protocol. */
hash value defined in the protocol. If it is FALSE then this is used
to create the HASH value defined by the protocol. */
unsigned char *return_hash,
SilcUInt32 *return_hash_len,
int initiator)
unsigned char *return_hash,
SilcUInt32 *return_hash_len,
int initiator)
e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
- buf = silc_buffer_alloc_size(ske->start_payload_copy->len +
- ske->ke2_payload->pk_len +
- ske->ke1_payload->pk_len +
+ buf = silc_buffer_alloc_size(ske->start_payload_copy->len +
+ ske->ke2_payload->pk_len +
+ ske->ke1_payload->pk_len +
e_len + f_len + KEY_len);
if (!buf)
return SILC_SKE_STATUS_OUT_OF_MEMORY;
/* Initiator is not required to send its public key */
if (!ske->ke1_payload->pk_data) {
e_len + f_len + KEY_len);
if (!buf)
return SILC_SKE_STATUS_OUT_OF_MEMORY;
/* Initiator is not required to send its public key */
if (!ske->ke1_payload->pk_data) {
ske->ke2_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_UI_XNSTRING(f, f_len),
SILC_STR_UI_XNSTRING(KEY, KEY_len),
SILC_STR_END);
} else {
ske->ke2_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_UI_XNSTRING(f, f_len),
SILC_STR_UI_XNSTRING(KEY, KEY_len),
SILC_STR_END);
} else {
ske->ke1_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_UI_XNSTRING(f, f_len),
ske->ke1_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_UI_XNSTRING(f, f_len),
silc_buffer_format(buf,
SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
ske->start_payload_copy->len),
silc_buffer_format(buf,
SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
ske->start_payload_copy->len),
ske->ke1_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_END);
ske->ke1_payload->pk_len),
SILC_STR_UI_XNSTRING(e, e_len),
SILC_STR_END);
/* Take first round */
memset(k1, 0, sizeof(k1));
silc_hash_make(hash, buf->data, buf->len, k1);
/* Take first round */
memset(k1, 0, sizeof(k1));
silc_hash_make(hash, buf->data, buf->len, k1);
/* Take first round */
memset(k1, 0, sizeof(k1));
silc_hash_make(hash, buf->data, buf->len, k1);
/* Take first round */
memset(k1, 0, sizeof(k1));
silc_hash_make(hash, buf->data, buf->len, k1);
SILC_STR_END);
memset(k2, 0, sizeof(k2));
silc_hash_make(hash, dist->data, dist->len, k2);
SILC_STR_END);
memset(k2, 0, sizeof(k2));
silc_hash_make(hash, dist->data, dist->len, k2);
/* Take third round */
dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
silc_buffer_pull_tail(dist, hash_len);
/* Take third round */
dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
silc_buffer_pull_tail(dist, hash_len);
/* Processes negotiated key material as protocol specifies. This returns
the actual keys to be used in the SILC. */
/* Processes negotiated key material as protocol specifies. This returns
the actual keys to be used in the SILC. */
SilcUInt32 req_iv_len,
SilcUInt32 req_enc_key_len,
SilcUInt32 req_hmac_key_len,
SilcUInt32 req_iv_len,
SilcUInt32 req_enc_key_len,
SilcUInt32 req_hmac_key_len,
/* Process the key material */
status = silc_ske_process_key_material_data(buf->data, buf->len,
req_iv_len, req_enc_key_len,
/* Process the key material */
status = silc_ske_process_key_material_data(buf->data, buf->len,
req_iv_len, req_enc_key_len,
SilcUInt32 *protocol_version,
char **protocol_version_string,
SilcUInt32 *protocol_version,
char **protocol_version_string,
char **software_version_string,
char **vendor_version)
{
return silc_parse_version_string(ske->remote_version,
char **software_version_string,
char **vendor_version)
{
return silc_parse_version_string(ske->remote_version,