| // SPDX-License-Identifier: BSD-2-Clause |
| /* LibTomCrypt, modular cryptographic library -- Tom St Denis |
| * |
| * LibTomCrypt is a library that provides various cryptographic |
| * algorithms in a highly modular and flexible manner. |
| * |
| * The library is free for all purposes without any express |
| * guarantee it works. |
| */ |
| #include "tomcrypt_private.h" |
| #include <stdarg.h> |
| |
| /** |
| @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, void*) |
| @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: |
| sdata = va_arg(args, char*); |
| size += 4; |
| size += strlen(sdata); |
| break; |
| case LTC_SSHDATA_MPINT: |
| vdata = va_arg(args, void*); |
| /* Calculate size */ |
| size += 4; |
| if (mp_iszero(vdata) != LTC_MP_YES) { |
| size += mp_unsigned_bin_size(vdata); |
| if ((mp_count_bits(vdata) & 7) == 0) size++; /* Zero padding if high bit set */ |
| } |
| break; |
| |
| case LTC_SSHDATA_EOL: /* Should never get here */ |
| default: |
| 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 = strlen(sdata); |
| STORE32H(size, out); |
| out += 4; |
| XMEMCPY(out, sdata, size); |
| out += size; |
| break; |
| case LTC_SSHDATA_MPINT: |
| vdata = va_arg(args, void*); |
| if (mp_iszero(vdata) == LTC_MP_YES) { |
| STORE32H(0, out); |
| out += 4; |
| } else { |
| size = mp_unsigned_bin_size(vdata); |
| if ((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 ((err = mp_to_unsigned_bin(vdata, out)) != CRYPT_OK) { |
| err = CRYPT_ERROR; |
| goto error; |
| } |
| out += size; |
| } |
| break; |
| |
| case LTC_SSHDATA_EOL: /* Should never get here */ |
| default: |
| err = CRYPT_INVALID_ARG; |
| goto error; |
| } |
| } |
| err = CRYPT_OK; |
| |
| error: |
| va_end(args); |
| errornoargs: |
| return err; |
| } |
| |
| #endif |
| |
| /* ref: $Format:%D$ */ |
| /* git commit: $Format:%H$ */ |
| /* commit time: $Format:%ai$ */ |