Implement base64 without openssl
This commit is contained in:
+209
-37
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
|
* Copyright (C) 2022 Matt Burt, all xrdp contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,57 +26,229 @@
|
|||||||
|
|
||||||
#include "string_calls.h"
|
#include "string_calls.h"
|
||||||
|
|
||||||
#include <openssl/bio.h>
|
#include "base64.h"
|
||||||
#include <openssl/evp.h>
|
|
||||||
|
|
||||||
size_t
|
/*
|
||||||
base64_decoded_bytes(const char *src)
|
* Values for invalid and padding characters, used in the charmap
|
||||||
|
* for converting base64 to binary
|
||||||
|
*
|
||||||
|
* Thse value are specially chosen to make it easy to detect padding or
|
||||||
|
* invalid characters by or-ing together the values looked up in
|
||||||
|
* a base64 quantum */
|
||||||
|
#define E_INVALID 0x40
|
||||||
|
#define E_PAD 0x80
|
||||||
|
|
||||||
|
/* Determine the character set on this platform */
|
||||||
|
#if ('a' == 0x61 && 'z' == 0x7a ) && \
|
||||||
|
('A' == 0x41 && 'Z' == 0x5a ) && \
|
||||||
|
('0' == 0x30 && '9' == 0x39 )
|
||||||
|
# define PLATFORM_IS_ASCII 1
|
||||||
|
#else
|
||||||
|
# error "Unrecognised character set on this platform"
|
||||||
|
#endif /* character set check */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define a table to map the base64 character values to bit values.
|
||||||
|
*/
|
||||||
|
#ifdef PLATFORM_IS_ASCII
|
||||||
|
#define CHARMAP_BASE 0x28
|
||||||
|
#define E_IV E_INVALID /* For table alignment */
|
||||||
|
const unsigned char charmap[] =
|
||||||
{
|
{
|
||||||
size_t len;
|
/* 0x28 */ E_IV, E_IV, E_IV, 0x3e, E_IV, E_IV, E_IV, 0x3f,
|
||||||
size_t padding;
|
/* 0x30 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||||
|
/* 0x38 */ 0x3c, 0x3d, E_IV, E_IV, E_IV, E_PAD, E_IV, E_IV,
|
||||||
|
/* 0x40 */ E_IV, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||||
|
/* 0x48 */ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||||
|
/* 0x50 */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||||
|
/* 0x58 */ 0x17, 0x18, 0x19, E_IV, E_IV, E_IV, E_IV, E_IV,
|
||||||
|
/* 0x60 */ E_IV, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||||
|
/* 0x68 */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||||
|
/* 0x70 */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||||
|
/* 0x78 */ 0x31, 0x32, 0x33
|
||||||
|
};
|
||||||
|
#undef E_IV
|
||||||
|
#endif /* PLATFORM_IS_ASCII */
|
||||||
|
|
||||||
len = g_strlen(src);
|
|
||||||
padding = 0;
|
|
||||||
|
|
||||||
if (src[len - 1] == '=')
|
/**
|
||||||
|
* Lookup a value in the charmap
|
||||||
|
*
|
||||||
|
* @param x - byte to lookup. Only referenced once so can safely have
|
||||||
|
* side effects.
|
||||||
|
* @param dest - destination to assign result to.
|
||||||
|
*/
|
||||||
|
#define CM_LOOKUP(x,dest) \
|
||||||
|
{ \
|
||||||
|
unsigned int t = (unsigned int)(x) - CHARMAP_BASE;\
|
||||||
|
dest = (t < sizeof(charmap)) ? charmap[t] : E_INVALID; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
int
|
||||||
|
base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len)
|
||||||
|
{
|
||||||
|
*actual_len = 0;
|
||||||
|
size_t src_len;
|
||||||
|
size_t src_i = 0;
|
||||||
|
size_t dst_i = 0;
|
||||||
|
unsigned int a; /* Four characters of base64 quantum */
|
||||||
|
unsigned int b;
|
||||||
|
unsigned int c;
|
||||||
|
unsigned int d;
|
||||||
|
unsigned int v;
|
||||||
|
|
||||||
|
#define OUTPUT_CHAR(x) \
|
||||||
|
{ \
|
||||||
|
if (dst_i < dst_len) \
|
||||||
|
{ \
|
||||||
|
dst[dst_i] = (x);\
|
||||||
|
} \
|
||||||
|
++dst_i; \
|
||||||
|
}
|
||||||
|
|
||||||
|
src_len = g_strlen(src);
|
||||||
|
|
||||||
|
while (src_i < src_len)
|
||||||
{
|
{
|
||||||
padding++;
|
if ((src_len - src_i) >= 4)
|
||||||
|
|
||||||
if (src[len - 2] == '=')
|
|
||||||
{
|
{
|
||||||
padding++;
|
/* Usual case - full quantum */
|
||||||
|
CM_LOOKUP(src[src_i++], a);
|
||||||
|
CM_LOOKUP(src[src_i++], b);
|
||||||
|
CM_LOOKUP(src[src_i++], c);
|
||||||
|
CM_LOOKUP(src[src_i++], d);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Add padding on the end to make up the full quantum */
|
||||||
|
CM_LOOKUP(src[src_i++], a);
|
||||||
|
b = E_PAD;
|
||||||
|
c = E_PAD;
|
||||||
|
d = E_PAD;
|
||||||
|
if ((src_len - src_i) > 0)
|
||||||
|
{
|
||||||
|
CM_LOOKUP(src[src_i++], b);
|
||||||
|
}
|
||||||
|
if ((src_len - src_i) > 0)
|
||||||
|
{
|
||||||
|
CM_LOOKUP(src[src_i++], c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitwise-or the translated quantum values together, so that
|
||||||
|
* any invalid or padding characters can be detected with a
|
||||||
|
* single test */
|
||||||
|
v = a | b | c | d;
|
||||||
|
|
||||||
|
if ((v & E_INVALID) != 0)
|
||||||
|
{
|
||||||
|
return -1; /* At least one invalid character */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & E_PAD) == 0)
|
||||||
|
{
|
||||||
|
/* No padding - a full quantum */
|
||||||
|
v = (a << 18) | (b << 12) | (c << 6) | d;
|
||||||
|
OUTPUT_CHAR(v >> 16);
|
||||||
|
OUTPUT_CHAR((v >> 8) & 0xff);
|
||||||
|
OUTPUT_CHAR(v & 0xff);
|
||||||
|
}
|
||||||
|
else if (((a | b | c) & E_PAD) == 0)
|
||||||
|
{
|
||||||
|
/* No padding in the first 3 chars, so the padding must
|
||||||
|
* be at the end */
|
||||||
|
v = (a << 10) | (b << 4) | (c >> 2);
|
||||||
|
OUTPUT_CHAR(v >> 8);
|
||||||
|
OUTPUT_CHAR(v & 0xff);
|
||||||
|
}
|
||||||
|
else if (((a | b) & E_PAD) == 0 && c == d)
|
||||||
|
{
|
||||||
|
/* No padding in first two chars, so if the last two chars are
|
||||||
|
* equal, they must both be padding */
|
||||||
|
v = (a << 2) | (b >> 4);
|
||||||
|
OUTPUT_CHAR(v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Illegal padding */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return len * 3 / 4 - padding;
|
*actual_len = dst_i;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#undef OUTPUT_CHAR
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
char *
|
size_t
|
||||||
base64_decode(char *dst, const char *src, size_t len)
|
base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len)
|
||||||
{
|
{
|
||||||
BIO *b64;
|
char *p = dst;
|
||||||
BIO *bio;
|
size_t src_i = 0;
|
||||||
char *b64str;
|
size_t max_src_len;
|
||||||
size_t estimated_decoded_bytes;
|
unsigned int v;
|
||||||
size_t decoded_bytes;
|
static const char *b64chr =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"0123456789+/=";
|
||||||
|
|
||||||
b64str = g_strdup(src);
|
/* Each three octets of the source results in four bytes at the output,
|
||||||
estimated_decoded_bytes = base64_decoded_bytes(b64str);
|
* plus we need a terminator. So we can work out the maximum number of
|
||||||
dst[estimated_decoded_bytes] = '\0';
|
* source octets we can process */
|
||||||
|
if (dst_len == 0)
|
||||||
b64 = BIO_new(BIO_f_base64());
|
|
||||||
bio = BIO_new_mem_buf(b64str, len);
|
|
||||||
bio = BIO_push(b64, bio);
|
|
||||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
|
||||||
decoded_bytes = BIO_read(bio, dst, len);
|
|
||||||
BIO_free_all(bio);
|
|
||||||
|
|
||||||
/* if input is corrupt, return empty string */
|
|
||||||
if (estimated_decoded_bytes != decoded_bytes)
|
|
||||||
{
|
{
|
||||||
g_strncpy(dst, "", sizeof(""));
|
max_src_len = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
max_src_len = (dst_len - 1) / 4 * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
if (src_len > max_src_len)
|
||||||
|
{
|
||||||
|
src_len = max_src_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (src_i < src_len)
|
||||||
|
{
|
||||||
|
switch (src_len - src_i)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
v = (unsigned int)(unsigned char)src[src_i++] << 4;
|
||||||
|
*p++ = b64chr[v >> 6];
|
||||||
|
*p++ = b64chr[v & 0x3f];
|
||||||
|
*p++ = b64chr[64];
|
||||||
|
*p++ = b64chr[64];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
v = (unsigned int)(unsigned char)src[src_i++] << 10;
|
||||||
|
v |= (unsigned int)(unsigned char)src[src_i++] << 2;
|
||||||
|
*p++ = b64chr[v >> 12];
|
||||||
|
*p++ = b64chr[(v >> 6) & 0x3f];
|
||||||
|
*p++ = b64chr[v & 0x3f];
|
||||||
|
*p++ = b64chr[64];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
v = (unsigned int)(unsigned char)src[src_i++] << 16;
|
||||||
|
v |= (unsigned int)(unsigned char)src[src_i++] << 8;
|
||||||
|
v |= (unsigned int)(unsigned char)src[src_i++];
|
||||||
|
*p++ = b64chr[v >> 18];
|
||||||
|
*p++ = b64chr[(v >> 12) & 0x3f];
|
||||||
|
*p++ = b64chr[(v >> 6) & 0x3f];
|
||||||
|
*p++ = b64chr[v & 0x3f];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
return src_len;
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-8
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (C) 2017 Koichiro Iwao, all xrdp contributors
|
* Copyright (C) 2021 Koichiro Iwao, all xrdp contributors
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,16 +17,66 @@
|
|||||||
/**
|
/**
|
||||||
* @file common/base64.h
|
* @file common/base64.h
|
||||||
* @brief Base64 encoder / decoder
|
* @brief Base64 encoder / decoder
|
||||||
|
*
|
||||||
|
* Base-64 is described in RFC4648. The following notes apply to this
|
||||||
|
* implementation:-
|
||||||
|
* - The only supported characters are [A-Za-z0-9+/=]. At present,
|
||||||
|
* embedded linefeeds and URL encodings are not supported.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(SSL_CALLS_H)
|
#if !defined(BASE64_CALLS_H)
|
||||||
#define SSL_CALLS_H
|
#define BASE64_CALLS_H
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
|
||||||
size_t
|
/*
|
||||||
base64_decoded_bytes(const char *src);
|
* Decodes a base64 string
|
||||||
char *
|
*
|
||||||
base64_decode(char *dst, const char *src, size_t len);
|
* @param src Pointer to null-terminated source
|
||||||
|
* @param dst Pointer to output buffer
|
||||||
|
* @param dst_len Length of above. No more than this is written to the
|
||||||
|
* output buffer
|
||||||
|
* @param actual_len Pointer to value to receive actual length of decoded data
|
||||||
|
* @return 0 for success, 1 for an invalid input string
|
||||||
|
*
|
||||||
|
* The following notes apply to this implementation:-
|
||||||
|
* - Embedded padding is supported, provided it only occurs at the end
|
||||||
|
* of a quantum as described in RFC4648(4). This allows concatenated
|
||||||
|
* encodings to be fed into the decoder.
|
||||||
|
* - Padding of the last quantum is assumed if not provided.
|
||||||
|
* - Excess padding of the last quantum is ignored.
|
||||||
|
*
|
||||||
|
* Only dst_len bytes at most are written to the output. The length
|
||||||
|
* returned in actual_len however represents how much buffer is needed for
|
||||||
|
* a correct result. This may be more than dst_len, and enables the caller
|
||||||
|
* to detect a potential buffer overflow
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
base64_decode(const char *src, char *dst, size_t dst_len, size_t *actual_len);
|
||||||
|
|
||||||
#endif
|
/*
|
||||||
|
* Encodes a buffer as base64
|
||||||
|
*
|
||||||
|
* @param src Pointer to source
|
||||||
|
* @param src_len Length of above.
|
||||||
|
* @param dst Pointer to output buffer for null-terminated string
|
||||||
|
* @param dst_len Length of above. No more than this is written to the
|
||||||
|
* output buffer
|
||||||
|
* @return Number of source characters processed
|
||||||
|
*
|
||||||
|
* The following notes apply to this implementation:-
|
||||||
|
* - Padding of the last quantum is always written if the number of
|
||||||
|
* source bytes is not divisible by 3.
|
||||||
|
*
|
||||||
|
* The number of source characters processed is always returned. If
|
||||||
|
* the destination buffer is too small for all the output plus a
|
||||||
|
* terminator, the returned value from this procedure will be less than
|
||||||
|
* src_len. In this case no padding characters will have been written,
|
||||||
|
* and the remaining characters can be converted with more calls to
|
||||||
|
* this procedure.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
base64_encode(const char *src, size_t src_len, char *dst, size_t dst_len);
|
||||||
|
|
||||||
|
#endif /* BASE64_CALLS_H */
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ AM_CPPFLAGS = \
|
|||||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||||
$(top_srcdir)/tap-driver.sh
|
$(top_srcdir)/tap-driver.sh
|
||||||
|
|
||||||
|
PACKAGE_STRING = "libcommon"
|
||||||
|
|
||||||
TESTS = test_common
|
TESTS = test_common
|
||||||
check_PROGRAMS = test_common
|
check_PROGRAMS = test_common
|
||||||
|
|
||||||
@@ -14,7 +16,8 @@ test_common_SOURCES = \
|
|||||||
test_common_main.c \
|
test_common_main.c \
|
||||||
test_string_calls.c \
|
test_string_calls.c \
|
||||||
test_os_calls.c \
|
test_os_calls.c \
|
||||||
test_ssl_calls.c
|
test_ssl_calls.c \
|
||||||
|
test_base64.c
|
||||||
|
|
||||||
test_common_CFLAGS = \
|
test_common_CFLAGS = \
|
||||||
@CHECK_CFLAGS@ \
|
@CHECK_CFLAGS@ \
|
||||||
|
|||||||
@@ -0,0 +1,400 @@
|
|||||||
|
|
||||||
|
#if defined(HAVE_CONFIG_H)
|
||||||
|
#include "config_ac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "os_calls.h"
|
||||||
|
#include "string_calls.h"
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
|
#include "test_common.h"
|
||||||
|
/*
|
||||||
|
* These are the example test strings in RFC4648(10)
|
||||||
|
*/
|
||||||
|
static const char *rfc4648_ex1_text = "";
|
||||||
|
static const char *rfc4648_ex1_b64 = "";
|
||||||
|
static const char *rfc4648_ex2_text = "f";
|
||||||
|
static const char *rfc4648_ex2_b64 = "Zg==";
|
||||||
|
static const char *rfc4648_ex3_text = "fo";
|
||||||
|
static const char *rfc4648_ex3_b64 = "Zm8=";
|
||||||
|
static const char *rfc4648_ex4_text = "foo";
|
||||||
|
static const char *rfc4648_ex4_b64 = "Zm9v";
|
||||||
|
static const char *rfc4648_ex5_text = "foob";
|
||||||
|
static const char *rfc4648_ex5_b64 = "Zm9vYg==";
|
||||||
|
static const char *rfc4648_ex6_text = "fooba";
|
||||||
|
static const char *rfc4648_ex6_b64 = "Zm9vYmE=";
|
||||||
|
static const char *rfc4648_ex7_text = "foobar";
|
||||||
|
static const char *rfc4648_ex7_b64 = "Zm9vYmFy";
|
||||||
|
|
||||||
|
/* Every single valid base64 character, except padding */
|
||||||
|
static const char *all_b64 =
|
||||||
|
"ABCDEFGHIJKL"
|
||||||
|
"MNOPQRSTUVWX"
|
||||||
|
"YZabcdefghij"
|
||||||
|
"klmnopqrstuv"
|
||||||
|
"wxyz01234567"
|
||||||
|
"89+/";
|
||||||
|
|
||||||
|
/* What we should get as binary if we decode this */
|
||||||
|
static const char all_b64_decoded[] =
|
||||||
|
{
|
||||||
|
'\x00', '\x10', '\x83', '\x10', '\x51', '\x87', '\x20', '\x92', '\x8b',
|
||||||
|
'\x30', '\xd3', '\x8f', '\x41', '\x14', '\x93', '\x51', '\x55', '\x97',
|
||||||
|
'\x61', '\x96', '\x9b', '\x71', '\xd7', '\x9f', '\x82', '\x18', '\xa3',
|
||||||
|
'\x92', '\x59', '\xa7', '\xa2', '\x9a', '\xab', '\xb2', '\xdb', '\xaf',
|
||||||
|
'\xc3', '\x1c', '\xb3', '\xd3', '\x5d', '\xb7', '\xe3', '\x9e', '\xbb',
|
||||||
|
'\xf3', '\xdf', '\xbf'
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_rfc4648_to_b64(const char *plaintext, size_t len, const char *b64)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
size_t result;
|
||||||
|
|
||||||
|
result = base64_encode(plaintext, len, buff, sizeof(buff));
|
||||||
|
ck_assert_int_eq(result, len);
|
||||||
|
ck_assert_str_eq(buff, b64);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-only encoder wrapper */
|
||||||
|
static void
|
||||||
|
test_rfc4648_to_b64_text(const char *plaintext, const char *b64)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64(plaintext, g_strlen(plaintext), b64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-only decoder wrapper for valid base64 */
|
||||||
|
static void
|
||||||
|
test_rfc4648_from_b64_text(const char *b64, const char *text)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
size_t actual_len;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = base64_decode(b64, buff, sizeof(buff), &actual_len);
|
||||||
|
ck_assert_int_eq(result, 0);
|
||||||
|
ck_assert_int_lt(actual_len, sizeof(buff));
|
||||||
|
buff[actual_len] = '\0';
|
||||||
|
ck_assert_str_eq(buff, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex1_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex1_text, rfc4648_ex1_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex1_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex1_b64, rfc4648_ex1_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex2_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex2_text, rfc4648_ex2_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex2_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex2_b64, rfc4648_ex2_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex3_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex3_text, rfc4648_ex3_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex3_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex3_b64, rfc4648_ex3_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex4_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex4_text, rfc4648_ex4_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex4_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex4_b64, rfc4648_ex4_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex5_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex5_text, rfc4648_ex5_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex5_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex5_b64, rfc4648_ex5_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex6_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex6_text, rfc4648_ex6_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex6_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex6_b64, rfc4648_ex6_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex7_to)
|
||||||
|
{
|
||||||
|
test_rfc4648_to_b64_text(rfc4648_ex7_text, rfc4648_ex7_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_rfc4648_ex7_from)
|
||||||
|
{
|
||||||
|
test_rfc4648_from_b64_text(rfc4648_ex7_b64, rfc4648_ex7_text);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_all_valid_from)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
size_t actual_len;
|
||||||
|
int result;
|
||||||
|
char *str_result;
|
||||||
|
char *str_expected;
|
||||||
|
|
||||||
|
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
|
||||||
|
ck_assert_int_eq(result, 0);
|
||||||
|
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
|
||||||
|
str_result = bin_to_hex(buff, actual_len);
|
||||||
|
str_expected = bin_to_hex(all_b64_decoded, sizeof(all_b64_decoded));
|
||||||
|
ck_assert_str_eq(str_result, str_expected);
|
||||||
|
free(str_result);
|
||||||
|
free(str_expected);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_all_valid_to)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
size_t result;
|
||||||
|
|
||||||
|
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
|
||||||
|
buff, sizeof(buff));
|
||||||
|
ck_assert_int_eq(result, sizeof(all_b64_decoded));
|
||||||
|
ck_assert_str_eq(buff, all_b64);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_all_invalid)
|
||||||
|
{
|
||||||
|
char buff[256];
|
||||||
|
size_t actual_len;
|
||||||
|
char valid[256] = {0};
|
||||||
|
char encoded[5] = { "T0sh" }; /* Decodes to 'OK!' */
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* Make a note of all the valid b64 characters */
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned char c;
|
||||||
|
while ((c = all_b64[i]) != '\0')
|
||||||
|
{
|
||||||
|
valid[c] = 1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the decoder's working on a simple string...*/
|
||||||
|
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
|
||||||
|
ck_assert_int_eq(result, 0);
|
||||||
|
ck_assert_int_eq(actual_len, 3);
|
||||||
|
buff[actual_len] = '\0';
|
||||||
|
ck_assert_str_eq(buff, "OK!");
|
||||||
|
|
||||||
|
/* Now replace the 1st character with all invalid characters in turn,
|
||||||
|
* and check they're rejected */
|
||||||
|
for (i = 0 ; i < 256; ++i)
|
||||||
|
{
|
||||||
|
if (i != '\0' && !valid[i]) /* Don't try the string terminator char! */
|
||||||
|
{
|
||||||
|
encoded[0] = i;
|
||||||
|
result = base64_decode(encoded, buff, sizeof(buff), &actual_len);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
ck_abort_msg("Character 0x%02x was not rejected", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_small_buffer_encode)
|
||||||
|
{
|
||||||
|
char buff[10 * 4 + 1]; /* Enough space for 10 quanta */
|
||||||
|
|
||||||
|
size_t result;
|
||||||
|
|
||||||
|
result = base64_encode(all_b64_decoded, sizeof(all_b64_decoded),
|
||||||
|
buff, sizeof(buff));
|
||||||
|
/* Should have read 10 lots of 24 bits from the input */
|
||||||
|
ck_assert_int_eq(result, 10 * 3);
|
||||||
|
ck_assert_str_eq(buff, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn");
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_small_buffer_decode)
|
||||||
|
{
|
||||||
|
char buff[10]; /* Enough space for 10 chars */
|
||||||
|
|
||||||
|
size_t actual_len;
|
||||||
|
int result;
|
||||||
|
char *str_result;
|
||||||
|
char *str_expected;
|
||||||
|
|
||||||
|
result = base64_decode(all_b64, buff, sizeof(buff), &actual_len);
|
||||||
|
ck_assert_int_eq(result, 0);
|
||||||
|
ck_assert_int_eq(actual_len, sizeof(all_b64_decoded));
|
||||||
|
str_result = bin_to_hex(buff, sizeof(buff));
|
||||||
|
str_expected = bin_to_hex(all_b64_decoded, sizeof(buff));
|
||||||
|
ck_assert_str_eq(str_result, str_expected);
|
||||||
|
free(str_result);
|
||||||
|
free(str_expected);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_add_pad_one)
|
||||||
|
{
|
||||||
|
/* Check that a missing trailing '=' is added when decoding */
|
||||||
|
test_rfc4648_from_b64_text("Zm8", "fo"); /* RFC4648 example 3 */
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_add_pad_two)
|
||||||
|
{
|
||||||
|
/* Check that two missing trailing '=' chars are added when decoding */
|
||||||
|
test_rfc4648_from_b64_text("Zg", "f"); /* RFC4648 example 2 */
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_bad_pad)
|
||||||
|
{
|
||||||
|
char buff[16];
|
||||||
|
size_t actual_len;
|
||||||
|
|
||||||
|
/* Check all bad quanta with padding chars */
|
||||||
|
static const char *bad_pad[] =
|
||||||
|
{
|
||||||
|
"=AAA",
|
||||||
|
"A=AA",
|
||||||
|
"AA=A",
|
||||||
|
"==AA",
|
||||||
|
"=A=A",
|
||||||
|
"=AA=",
|
||||||
|
"A==A",
|
||||||
|
"A=A=",
|
||||||
|
"===A",
|
||||||
|
"A===",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char **p;
|
||||||
|
|
||||||
|
for (p = bad_pad ; *p != NULL ; ++p)
|
||||||
|
{
|
||||||
|
int result = base64_decode(*p, buff, sizeof(buff), &actual_len);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
ck_abort_msg("Padding '%s' was not rejected", *p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
START_TEST(test_b64_concat_pad)
|
||||||
|
{
|
||||||
|
const char *src =
|
||||||
|
"VGVzdA==" /* Test */
|
||||||
|
"IA==" /* <space> */
|
||||||
|
"Y29uY2F0ZW5hdGVk" /* concatenated */
|
||||||
|
"IA==" /* <space> */
|
||||||
|
"cGFkZGluZw=="; /*padding */
|
||||||
|
const char *expected = "Test concatenated padding";
|
||||||
|
char buff[64];
|
||||||
|
size_t actual_len;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = base64_decode(src, buff, sizeof(buff), &actual_len);
|
||||||
|
ck_assert_int_eq(result, 0);
|
||||||
|
ck_assert_int_eq(actual_len, g_strlen(expected));
|
||||||
|
buff[actual_len] = '\0';
|
||||||
|
ck_assert_str_eq(buff, expected);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
Suite *
|
||||||
|
make_suite_test_base64(void)
|
||||||
|
{
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc_b64;
|
||||||
|
|
||||||
|
s = suite_create("base64");
|
||||||
|
|
||||||
|
tc_b64 = tcase_create("base64");
|
||||||
|
suite_add_tcase(s, tc_b64);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex1_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex2_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex3_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex4_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex5_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex6_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_rfc4648_ex7_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_all_valid_from);
|
||||||
|
tcase_add_test(tc_b64, test_b64_all_valid_to);
|
||||||
|
tcase_add_test(tc_b64, test_b64_all_invalid);
|
||||||
|
tcase_add_test(tc_b64, test_b64_small_buffer_encode);
|
||||||
|
tcase_add_test(tc_b64, test_b64_small_buffer_decode);
|
||||||
|
tcase_add_test(tc_b64, test_b64_add_pad_one);
|
||||||
|
tcase_add_test(tc_b64, test_b64_add_pad_two);
|
||||||
|
tcase_add_test(tc_b64, test_b64_bad_pad);
|
||||||
|
tcase_add_test(tc_b64, test_b64_concat_pad);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
@@ -4,8 +4,12 @@
|
|||||||
|
|
||||||
#include <check.h>
|
#include <check.h>
|
||||||
|
|
||||||
|
char *
|
||||||
|
bin_to_hex(const char *input, int length);
|
||||||
|
|
||||||
Suite *make_suite_test_string(void);
|
Suite *make_suite_test_string(void);
|
||||||
Suite *make_suite_test_os_calls(void);
|
Suite *make_suite_test_os_calls(void);
|
||||||
Suite *make_suite_test_ssl_calls(void);
|
Suite *make_suite_test_ssl_calls(void);
|
||||||
|
Suite *make_suite_test_base64(void);
|
||||||
|
|
||||||
#endif /* TEST_COMMON_H */
|
#endif /* TEST_COMMON_H */
|
||||||
|
|||||||
@@ -10,6 +10,36 @@
|
|||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a binary buffer to a hexadecimal representation
|
||||||
|
*
|
||||||
|
* Result must be free'd after use
|
||||||
|
*/
|
||||||
|
char *
|
||||||
|
bin_to_hex(const char *input, int length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *result = (char *)malloc(length * 2 + 1);
|
||||||
|
if (result != NULL)
|
||||||
|
{
|
||||||
|
char *p = result;
|
||||||
|
const char *hexdigit = "0123456789abcdef";
|
||||||
|
for (i = 0 ; i < length ; ++i)
|
||||||
|
{
|
||||||
|
int c = input[i];
|
||||||
|
if (c < 0)
|
||||||
|
{
|
||||||
|
c += 256;
|
||||||
|
}
|
||||||
|
*p++ = hexdigit[ c / 16];
|
||||||
|
*p++ = hexdigit[ c % 16];
|
||||||
|
}
|
||||||
|
*p = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int main (void)
|
int main (void)
|
||||||
{
|
{
|
||||||
int number_failed;
|
int number_failed;
|
||||||
@@ -18,6 +48,7 @@ int main (void)
|
|||||||
sr = srunner_create (make_suite_test_string());
|
sr = srunner_create (make_suite_test_string());
|
||||||
srunner_add_suite(sr, make_suite_test_os_calls());
|
srunner_add_suite(sr, make_suite_test_os_calls());
|
||||||
srunner_add_suite(sr, make_suite_test_ssl_calls());
|
srunner_add_suite(sr, make_suite_test_ssl_calls());
|
||||||
|
srunner_add_suite(sr, make_suite_test_base64());
|
||||||
// srunner_add_suite(sr, make_list_suite());
|
// srunner_add_suite(sr, make_list_suite());
|
||||||
|
|
||||||
srunner_set_tap(sr, "-");
|
srunner_set_tap(sr, "-");
|
||||||
|
|||||||
@@ -9,32 +9,6 @@
|
|||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
static
|
|
||||||
char *bin_to_hex(const char *input, int length)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *result = (char *)g_malloc(length * 2 + 1, 0);
|
|
||||||
if (result != NULL)
|
|
||||||
{
|
|
||||||
char *p = result;
|
|
||||||
const char *hexdigit = "0123456789abcdef";
|
|
||||||
for (i = 0 ; i < length ; ++i)
|
|
||||||
{
|
|
||||||
int c = input[i];
|
|
||||||
if (c < 0)
|
|
||||||
{
|
|
||||||
c += 256;
|
|
||||||
}
|
|
||||||
*p++ = hexdigit[ c / 16];
|
|
||||||
*p++ = hexdigit[ c % 16];
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
START_TEST(test_rc4_enc_ok)
|
START_TEST(test_rc4_enc_ok)
|
||||||
{
|
{
|
||||||
const char *key = "16_byte_key-----";
|
const char *key = "16_byte_key-----";
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
|||||||
struct xrdp_cfg_globals *globals;
|
struct xrdp_cfg_globals *globals;
|
||||||
char resultIP[256];
|
char resultIP[256];
|
||||||
char *plain; /* base64 decoded string */
|
char *plain; /* base64 decoded string */
|
||||||
|
size_t plain_length; /* length of decoded base64 string */
|
||||||
size_t base64_length; /* length of base64 string */
|
size_t base64_length; /* length of base64 string */
|
||||||
|
|
||||||
globals = &self->xrdp_config->cfg_globals;
|
globals = &self->xrdp_config->cfg_globals;
|
||||||
@@ -379,8 +380,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
|||||||
{
|
{
|
||||||
base64_length = g_strlen(value + BASE64PREFIX_LEN);
|
base64_length = g_strlen(value + BASE64PREFIX_LEN);
|
||||||
plain = (char *)g_malloc(base64_length, 0);
|
plain = (char *)g_malloc(base64_length, 0);
|
||||||
base64_decode(plain, value + BASE64PREFIX_LEN, base64_length);
|
base64_decode(value + BASE64PREFIX_LEN,
|
||||||
g_strncpy(value, plain, g_strlen(plain));
|
plain, base64_length, &plain_length);
|
||||||
|
g_strncpy(value, plain, plain_length);
|
||||||
g_free(plain);
|
g_free(plain);
|
||||||
}
|
}
|
||||||
else if (g_strncmp(ASK, value, ASK_LEN) == 0)
|
else if (g_strncmp(ASK, value, ASK_LEN) == 0)
|
||||||
@@ -421,7 +423,9 @@ xrdp_wm_show_edits(struct xrdp_wm *self, struct xrdp_bitmap *combo)
|
|||||||
{
|
{
|
||||||
base64_length = g_strlen(value + ASK_LEN + BASE64PREFIX_LEN);
|
base64_length = g_strlen(value + ASK_LEN + BASE64PREFIX_LEN);
|
||||||
plain = (char *)g_malloc(base64_length, 0);
|
plain = (char *)g_malloc(base64_length, 0);
|
||||||
base64_decode(plain, value + ASK_LEN + BASE64PREFIX_LEN, base64_length);
|
base64_decode(value + ASK_LEN + BASE64PREFIX_LEN,
|
||||||
|
plain, base64_length, &plain_length);
|
||||||
|
plain[plain_length] = '\0';
|
||||||
g_strncpy(b->caption1, plain, 255);
|
g_strncpy(b->caption1, plain, 255);
|
||||||
g_free(plain);
|
g_free(plain);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user