164 lines
4.8 KiB
C
164 lines
4.8 KiB
C
/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
|
|
/* SPDX-License-Identifier: Unlicense */
|
|
#include "tomcrypt_private.h"
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wconversion"
|
|
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
|
|
|
/**
|
|
@file ssh_encode_sequence_multi.c
|
|
SSH data type representation as per RFC4251, Russ Williams
|
|
*/
|
|
|
|
#ifdef LTC_SSH
|
|
|
|
/**
|
|
Encode a SSH sequence using a VA list
|
|
@param out [out] Destination for data
|
|
@param outlen [in/out] Length of buffer and resulting length of output
|
|
@remark <...> is of the form <type, data> (int, <int,ulong32,ulong64>) except for string&name-list <type, data, size> (int, void*, unsigned long)
|
|
@return CRYPT_OK on success
|
|
*/
|
|
int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
|
|
{
|
|
int err;
|
|
va_list args;
|
|
ulong32 size;
|
|
ssh_data_type type;
|
|
void *vdata;
|
|
const char *sdata;
|
|
int idata;
|
|
ulong32 u32data;
|
|
ulong64 u64data;
|
|
|
|
LTC_ARGCHK(out != NULL);
|
|
LTC_ARGCHK(outlen != NULL);
|
|
|
|
/* Check values and calculate output size */
|
|
size = 0;
|
|
va_start(args, outlen);
|
|
while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
|
|
switch (type) {
|
|
case LTC_SSHDATA_BYTE:
|
|
case LTC_SSHDATA_BOOLEAN: /* Both stored as 1 byte */
|
|
LTC_UNUSED_PARAM( va_arg(args, int) );
|
|
size++;
|
|
break;
|
|
case LTC_SSHDATA_UINT32:
|
|
LTC_UNUSED_PARAM( va_arg(args, ulong32) );
|
|
size += 4;
|
|
break;
|
|
case LTC_SSHDATA_UINT64:
|
|
LTC_UNUSED_PARAM( va_arg(args, ulong64) );
|
|
size += 8;
|
|
break;
|
|
case LTC_SSHDATA_STRING:
|
|
case LTC_SSHDATA_NAMELIST:
|
|
LTC_UNUSED_PARAM( va_arg(args, char*) );
|
|
size += va_arg(args, unsigned long);
|
|
size += 4;
|
|
break;
|
|
case LTC_SSHDATA_MPINT:
|
|
vdata = va_arg(args, void*);
|
|
/* Calculate size */
|
|
size += 4;
|
|
if (ltc_mp_iszero(vdata) != LTC_MP_YES) {
|
|
size += ltc_mp_unsigned_bin_size(vdata);
|
|
if ((ltc_mp_count_bits(vdata) & 7) == 0) size++; /* Zero padding if high bit set */
|
|
}
|
|
break;
|
|
|
|
case LTC_SSHDATA_EOL: /* Should never get here */
|
|
err = CRYPT_INVALID_ARG;
|
|
goto error;
|
|
}
|
|
}
|
|
va_end(args);
|
|
|
|
/* Check we have sufficient space */
|
|
if (*outlen < size) {
|
|
*outlen = size;
|
|
err = CRYPT_BUFFER_OVERFLOW;
|
|
goto errornoargs;
|
|
}
|
|
*outlen = size;
|
|
|
|
/* Encode values into buffer */
|
|
va_start(args, outlen);
|
|
while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
|
|
switch (type) {
|
|
case LTC_SSHDATA_BYTE:
|
|
idata = va_arg(args, int);
|
|
|
|
*out++ = (unsigned char)(idata & 255);
|
|
break;
|
|
case LTC_SSHDATA_BOOLEAN:
|
|
idata = va_arg(args, int);
|
|
|
|
/*
|
|
The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
|
|
interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
|
|
*/
|
|
*out++ = (idata)?1:0;
|
|
break;
|
|
case LTC_SSHDATA_UINT32:
|
|
u32data = va_arg(args, ulong32);
|
|
STORE32H(u32data, out);
|
|
out += 4;
|
|
break;
|
|
case LTC_SSHDATA_UINT64:
|
|
u64data = va_arg(args, ulong64);
|
|
STORE64H(u64data, out);
|
|
out += 8;
|
|
break;
|
|
case LTC_SSHDATA_STRING:
|
|
case LTC_SSHDATA_NAMELIST:
|
|
sdata = va_arg(args, char*);
|
|
size = va_arg(args, unsigned long);
|
|
STORE32H(size, out);
|
|
out += 4;
|
|
XMEMCPY(out, sdata, size);
|
|
out += size;
|
|
break;
|
|
case LTC_SSHDATA_MPINT:
|
|
vdata = va_arg(args, void*);
|
|
if (ltc_mp_iszero(vdata) == LTC_MP_YES) {
|
|
STORE32H(0, out);
|
|
out += 4;
|
|
} else {
|
|
size = ltc_mp_unsigned_bin_size(vdata);
|
|
if ((ltc_mp_count_bits(vdata) & 7) == 0) {
|
|
/* Zero padding if high bit set */
|
|
STORE32H(size+1, out);
|
|
out += 4;
|
|
*out++ = 0;
|
|
} else {
|
|
STORE32H(size, out);
|
|
out += 4;
|
|
}
|
|
if (ltc_mp_to_unsigned_bin(vdata, out) != CRYPT_OK) {
|
|
err = CRYPT_ERROR;
|
|
goto error;
|
|
}
|
|
out += size;
|
|
}
|
|
break;
|
|
|
|
case LTC_SSHDATA_EOL: /* Should never get here */
|
|
err = CRYPT_INVALID_ARG;
|
|
goto error;
|
|
}
|
|
}
|
|
err = CRYPT_OK;
|
|
|
|
error:
|
|
va_end(args);
|
|
errornoargs:
|
|
return err;
|
|
}
|
|
|
|
#endif
|
|
|
|
#pragma clang diagnostic pop
|