Files
m241Neelima/components/ip_net2-6.9/ipssh/src/ipssh_keyex_rsa.c
T
2026-07-30 11:19:44 +05:30

660 lines
20 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_keyex_rsa.c,v $ $Revision: 1.4.12.3 $
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_keyex_rsa.c,v $
* $Author: jli7 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Roger Boden <roger.boden@windriver.com>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include "ipssh_config.h"
#ifdef IPSSH_USE_KEYEX_RSA
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include <ipcom_type.h>
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_syslog.h>
#include <ipcom_err.h>
#include <ipcrypto.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "ipssh.h"
#include "ipssh_h.h"
#include "ipssh_buffer.h"
#include "ipssh_transport.h"
#include "ipssh_keyex_dh.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_GLOBAL Ip_err ipssh_send_msg_kexrsa_pubkey(Ipssh_conn* ssh_conn);
IP_GLOBAL Ip_err ipssh_send_msg_kexrsa_done(Ipssh_conn* ssh_conn);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC int
ipssh_kexrsa_get_hash_size(Ipssh_conn* ssh_conn)
{
switch(ssh_conn->conn_prop_pending.kex_alg[0])
{
case IPSSH_KEYEX_RSA1024_SHA1_ID:
return SHA_DIGEST_LENGTH;
case IPSSH_KEYEX_RSA2048_SHA256_ID:
return SHA256_DIGEST_LENGTH;
default:
IP_PANIC();
return 0;
}
}
/*
*===========================================================================
* ipssh_send_msg_kexrsa_secret
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_send_msg_kexrsa_secret(Ipssh_conn* ssh_conn, RSA* transient_key)
{
Ip_err rc = IPCOM_ERR_FAILED;
int encr_k_len;
int len;
Ip_u8* encr_k = IP_NULL;
Ip_u8* oaep_padded_shared_secret = IP_NULL;
Ip_u8* mpint_shared_secret = IP_NULL;
Ipcom_buffer* pkt = IP_NULL;
/* Generate random integer, K in rfc 4432, also known as shared secret */
ssh_conn->secr_len = RSA_size(transient_key) - 2*ipssh_kexrsa_get_hash_size(ssh_conn) - 7;
ssh_conn->shared_secret = ipcom_malloc(RSA_size(transient_key));
if (!ssh_conn->shared_secret)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: out of memory");
return IPCOM_ERR_NO_MEMORY;
}
if (!RAND_bytes(ssh_conn->shared_secret, ssh_conn->secr_len))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: failed to get random bytes");
goto cleanup;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_MPINT,
ssh_conn->shared_secret,
ssh_conn->secr_len,
7))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: failed to add K to hash list");
goto cleanup;
}
encr_k_len = RSA_size(transient_key);
encr_k = ipcom_malloc(encr_k_len);
oaep_padded_shared_secret = ipcom_malloc(encr_k_len);
mpint_shared_secret = ipcom_malloc(ssh_conn->secr_len+4);
if (!encr_k || !oaep_padded_shared_secret || !mpint_shared_secret)
goto cleanup;
IP_SET_HTONL(mpint_shared_secret, ssh_conn->secr_len);
ipcom_memcpy(mpint_shared_secret+4, ssh_conn->shared_secret, ssh_conn->secr_len);
ipcrypto_rsa_oaep_encode(ssh_conn->hash_func(), mpint_shared_secret, ssh_conn->secr_len+4, oaep_padded_shared_secret, encr_k_len);
len = RSA_public_encrypt(encr_k_len, oaep_padded_shared_secret, encr_k, transient_key, RSA_NO_PADDING);
if (len < 0)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: failed to encrypt K");
goto cleanup;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_STR,
encr_k,
len,
6))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: failed to add encrypted K to hash list");
goto cleanup;
}
pkt = ipssh_buffer_new_v2_pkt(encr_k_len+64, IPSSH_MSG_KEX_RSA_SECRET);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_secret :: failed to allocate pkt");
goto cleanup;
}
(void)ipssh_buffer_put_sshbuf(pkt, encr_k, encr_k_len);
rc = ipssh_send_pkt(ssh_conn, pkt, IP_FALSE);
cleanup:
if (encr_k)
ipcom_free(encr_k);
if (oaep_padded_shared_secret)
ipcom_free(oaep_padded_shared_secret);
if (mpint_shared_secret)
ipcom_free(mpint_shared_secret);
if(pkt)
ipcom_buffer_free(pkt);
return rc;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
IP_GLOBAL Ip_err
ipssh_msg_kexrsa_done(Ipssh_conn* ssh_conn)
{
char* sig_type = IP_NULL;
Ip_u8* signature = IP_NULL;
Ip_u32 sign_len;
Ip_err rc = IPCOM_ERR_FAILED;
if(ipssh_calc_hash((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
ssh_conn->hash_func,
8,
&(ssh_conn->hash),
&(ssh_conn->hash_len)))
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_done :: ipssh_calc_hash() failed");
goto cleanup;
}
if(ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6)) /* Skip headers */
goto cleanup;
/* Process signature */
if(ipcom_buffer_consume(ssh_conn->recv_plain_buf, 4)) /* Skip blob len field */
goto cleanup;
sig_type=ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf);
signature=ipssh_buffer_get_sshbuf(ssh_conn->recv_plain_buf, &sign_len);
if(!sig_type || !signature)
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_done :: failed to unpack signature");
goto cleanup;
}
/* Verify signature */
if(ipssh_verify_signature(ssh_conn->data.clt.srv_pub_key, ssh_conn->hash, ssh_conn->hash_len, sig_type, signature, sign_len) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_done :: ipssh_verify_signature() failed");
goto cleanup;
}
if(ssh_conn->sess_id_len == 0)
{
ssh_conn->sess_id = ipcom_malloc(ssh_conn->hash_len);
if(!ssh_conn->sess_id)
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_done :: out of memory");
goto cleanup;
}
ssh_conn->sess_id_len = ssh_conn->hash_len;
ipcom_memcpy(ssh_conn->sess_id, ssh_conn->hash, ssh_conn->sess_id_len);
}
rc = IPCOM_SUCCESS;
cleanup:
if (sig_type)
ipcom_free(sig_type);
if (signature)
ipcom_free(signature);
return rc;
}
/*
*===========================================================================
* ipssh_msg_kexrsa_pubkey
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_kexrsa_pubkey(Ipssh_conn* ssh_conn)
{
Ip_err rc = IPCOM_ERR_FAILED;
EVP_PKEY* transient_key = IP_NULL;
Ip_u8* srv_key_ptr;
Ip_u8* transient_key_ptr;
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
srv_key_ptr = ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf);
ssh_conn->data.clt.srv_pub_key = ipssh_buffer_get_pub_key(ssh_conn->recv_plain_buf);
if (!ssh_conn->data.clt.srv_pub_key)
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_pubkey :: failed to unpack srv key");
return IPCOM_ERR_FAILED;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_RAW,
srv_key_ptr,
ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf) - srv_key_ptr,
4))
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_pubkey :: failed to add host key to hash list");
goto cleanup;
}
transient_key_ptr = ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf);
transient_key = ipssh_buffer_get_pub_key(ssh_conn->recv_plain_buf);
if (!transient_key)
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_pubkey :: failed to unpack transient key");
goto cleanup;
}
if (transient_key->type != NID_rsaEncryption)
{
IPCOM_LOG1(ERR, "ipssh_msg_kexrsa_pubkey :: transient key not an RSA key: key type=%d",
transient_key->type);
goto cleanup;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_RAW,
transient_key_ptr,
ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf) - transient_key_ptr,
5))
{
IPCOM_LOG0(ERR, "ipssh_msg_kexrsa_pubkey :: failed to add transient key to hash list");
goto cleanup;
}
rc = ipssh_send_msg_kexrsa_secret(ssh_conn, transient_key->pkey.rsa);
cleanup:
if (transient_key)
EVP_PKEY_free(transient_key);
return rc;
}
/*
*===========================================================================
* ipssh_send_msg_kexrsa_pubkey
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_kexrsa_pubkey(Ipssh_conn* ssh_conn)
{
Ipcom_buffer* pkt;
Ip_err rc = IPCOM_ERR_FAILED;
Ip_size_t srv_key_pos;
Ip_size_t transient_key_pos;
pkt = ipssh_buffer_new_v2_pkt(1024, IPSSH_MSG_KEX_RSA_PUBKEY);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: out of memory");
return IPCOM_ERR_FAILED;
}
srv_key_pos = ipcom_buffer_end_pos(pkt);
switch(ssh_conn->conn_prop_pending.srv_host_key_alg[0])
{
case IPSSH_DSA_ID:
if (ipssh_buffer_put_dsa_key(pkt, ssh_conn->srv_dsa_key))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: failed to add srv dsa key to pkt");
goto cleanup;
}
break;
case IPSSH_RSA_ID:
if (ipssh_buffer_put_rsa_key(pkt, ssh_conn->srv_rsa_key))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: failed to add srv rsa key to pkt");
goto cleanup;
}
break;
default:
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: unknown srv host key");
IP_PANIC();
goto cleanup;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_RAW,
(Ip_u8*)ipcom_buffer_ptr2pos(pkt, srv_key_pos),
ipcom_buffer_end_pos(pkt) - srv_key_pos,
4))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: failed to add host key to hash list");
goto cleanup;
}
transient_key_pos = ipcom_buffer_end_pos(pkt);
if (ipssh_buffer_put_rsa_key(pkt, ssh_conn->srv_rsa_keyex_key))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: out of memory");
goto cleanup;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_RAW,
(Ip_u8*)ipcom_buffer_ptr2pos(pkt, transient_key_pos),
ipcom_buffer_end_pos(pkt) - transient_key_pos,
5))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_pubkey :: failed to add transient key to hash list");
goto cleanup;
}
rc = ipssh_send_pkt(ssh_conn, pkt, IP_FALSE);
ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_KEX_RSA;
cleanup:
ipcom_buffer_free(pkt);
return rc;
}
/*
*===========================================================================
* ipssh_send_msg_kexrsa_done
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_kexrsa_done(Ipssh_conn* ssh_conn)
{
Ip_err rc = IPCOM_ERR_FAILED;
Ipcom_buffer* pkt = IP_NULL;
if(ipssh_calc_hash((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
ssh_conn->hash_func,
8,
&(ssh_conn->hash),
&(ssh_conn->hash_len)))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: ipssh_calc_hash() failed");
goto failed;
}
if(ssh_conn->sess_id_len == 0)
{
ssh_conn->sess_id = ipcom_malloc(ssh_conn->hash_len);
if(!ssh_conn->sess_id)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: out of memory");
goto failed;
}
ssh_conn->sess_id_len = ssh_conn->hash_len;
ipcom_memcpy(ssh_conn->sess_id, ssh_conn->hash, ssh_conn->sess_id_len);
}
pkt = ipssh_buffer_new_v2_pkt(2048, IPSSH_MSG_KEX_RSA_DONE);
if (!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: failed to allocate pkt");
goto failed;
}
if (ipssh_sign_hash(ssh_conn, pkt) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: ipssh_sign_hash() failed");
goto failed;
}
if (ipssh_send_pkt(ssh_conn, pkt, IP_FALSE) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: failed to send SSH_MSG_NEW_KEY");
goto failed;
}
if(ipssh_compute_keys(ssh_conn))
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: ipssh_compute_keys() failed");
goto failed;
}
if (ipssh_send_new_key_msg(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_kexrsa_done :: failed to send SSH_MSG_NEW_KEY");
goto failed;
}
rc = IPCOM_SUCCESS;
failed:
if (pkt)
ipcom_buffer_free(pkt);
return rc;
}
/*
*===========================================================================
*
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_msg_kex_rsa_secret(Ipssh_conn* ssh_conn)
{
Ip_u8* encr_shared_secret; /* K in rfc 4432 */
int len;
Ip_u8* shared_secret = IP_NULL;
Ip_u8* oaep_padded_shared_secret = IP_NULL;
Ip_err rc = IPCOM_ERR_FAILED;
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6);
encr_shared_secret = ipssh_buffer_get_sshbuf(ssh_conn->recv_plain_buf, (Ip_u32*)&len);
if (!encr_shared_secret)
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: failed to unpack secret");
return IPCOM_ERR_FAILED;
}
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_STR,
encr_shared_secret,
len,
6))
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: failed to add encrypted K to hash list");
goto cleanup;
}
shared_secret = ipcom_malloc(RSA_size(ssh_conn->srv_rsa_keyex_key)+64);
oaep_padded_shared_secret = ipcom_malloc(RSA_size(ssh_conn->srv_rsa_keyex_key)+64);
if (!shared_secret || !oaep_padded_shared_secret)
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: out of memory");
goto cleanup;
}
len = RSA_private_decrypt(len, encr_shared_secret, oaep_padded_shared_secret, ssh_conn->srv_rsa_keyex_key, RSA_NO_PADDING);
if (len < 0)
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: RSA_private_decrypt failed");
goto cleanup;
}
if (ipcrypto_rsa_oaep_decode(ssh_conn->hash_func(), oaep_padded_shared_secret, len, shared_secret, (int*)&len) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: failed to oaep decode shared secret");
goto cleanup;
}
if (len < 4)
{
IPCOM_LOG1(ERR, "ipssh_msg_kex_rsa_secret :: invalid K lenght: %d", len);
goto cleanup;
}
ipcom_memmove(shared_secret, &shared_secret[4], len -4); /* Remove the length field */
len -= 4;
if (ipssh_msg2list((Ipssh_msg_list*)&(ssh_conn->handshake_msgs),
IPSSH_MPINT,
shared_secret,
len,
7))
{
IPCOM_LOG0(ERR, "ipssh_msg_kex_rsa_secret :: failed to add shared secret K to hash list");
goto cleanup;
}
ssh_conn->shared_secret = shared_secret;
shared_secret = IP_NULL;
ssh_conn->secr_len = len;
rc = ipssh_send_msg_kexrsa_done(ssh_conn);
ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_NEW_KEY;
cleanup:
ipcom_free(encr_shared_secret);
if (shared_secret)
ipcom_free(shared_secret);
if (oaep_padded_shared_secret)
ipcom_free(oaep_padded_shared_secret);
return rc;
}
/*
*===========================================================================
* ipssh_do_keyex_rsa_clt
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_do_keyex_rsa_clt(Ipssh_conn* ssh_conn)
{
if (ipssh_read_v2_pkt2(ssh_conn, IPSSH_MSG_KEX_RSA_PUBKEY) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to read SSH_MSG_KEY_RSA_PUBKEY");
return IPCOM_ERR_FAILED;
}
if (ipssh_msg_kexrsa_pubkey(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to process SSH_MSG_KEY_RSA_PUBKEY");
return IPCOM_ERR_FAILED;
}
if (ipssh_read_v2_pkt2(ssh_conn, IPSSH_MSG_KEX_RSA_DONE) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to read SSH_MSG_KEY_RSA_DONE");
return IPCOM_ERR_FAILED;
}
if (ipssh_msg_kexrsa_done(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to process SSH_MSG_KEY_RSA_DONE");
return IPCOM_ERR_FAILED;
}
if(ipssh_compute_keys(ssh_conn))
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: ipssh_compute_keys() failed");
return IPCOM_ERR_FAILED;
}
if (ipssh_send_new_key_msg(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to send SSH_MSG_NEW_KEY");
return IPCOM_ERR_FAILED;
}
if(ipssh_read_v2_pkt2(ssh_conn, IPSSH_MSG_NEWKEYS) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to read SSH_MSG_NEW_KEY");
return IPCOM_ERR_FAILED;
}
if(ipssh_msg_new_key(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_do_keyex_rsa_clt :: failed to process SSH_MSG_NEW_KEY");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#else
int ipssh_keyex_rsa_empty_file;
#endif /* IPSSH_USE_RSA_KEYEX */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/