FreeRDP/winpr/libwinpr/crypto/test/TestCryptoCipher.c

233 lines
5.4 KiB
C
Raw Normal View History

#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
Winpr/openssl: Fix digests initialization in multi-thread SSL functions like OpenSSL_add_all_digests should be invoked at very beginning as they are not MT safe. If not we might meet double free exception as following: #0 0x00007f23ddd71c37 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007f23ddd75028 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007f23dddae2a4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #3 0x00007f23dddba55e in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #4 0x00007f23dc6ecfcd in CRYPTO_free () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #5 0x00007f23dc6ef8d1 in OBJ_NAME_add () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #6 0x00007f23dc77dcd8 in EVP_add_digest () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #7 0x00007f23dc782321 in OpenSSL_add_all_digests () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #8 0x00007f23c781da28 in winpr_openssl_get_evp_md (md=4) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:52 #9 0x00007f23c781dccb in winpr_Digest_Init (ctx=0x7f22d064d470, md=<optimized out>) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:344 #10 0x00007f23d486139b in security_salted_mac_signature (rdp=0x7f23859f5a20, data=0x7f238542d4fb "\004\204\022\004", length=4743, encryption=<optimized out>, output=0x7 at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/security.c:378 #11 0x00007f23d488d73f in fastpath_send_update_pdu (fastpath=<optimized out>, updateCode=4 '\004', s=0x7f23859f5f40, skipCompression=true) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/fastpath.c:1076 #12 0x00007f23d4891c4f in update_send_surface_frame_bits (context=0x7f23859f5540, cmd=0x7f22b2ffcc80, first=true, last=true, frameId=6) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/update.c:1041 Related reports: https://rt.openssl.org/Ticket/Display.html?id=2216&user=guest&pass=guest
2016-12-26 17:21:36 +03:00
#include <winpr/ssl.h>
2016-11-21 19:28:54 +03:00
static BOOL test_crypto_cipher_aes_128_cbc()
{
WINPR_CIPHER_CTX* ctx;
BOOL result = FALSE;
BYTE key[] = "0123456789abcdeF";
BYTE iv[] = "1234567887654321";
BYTE ibuf[1024];
BYTE obuf[1024];
size_t ilen;
size_t olen;
size_t xlen;
const char plaintext[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
/* encrypt */
if (!(ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_ENCRYPT, key, iv)))
{
fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __FUNCTION__);
return FALSE;
}
memset(ibuf, 0, sizeof(ibuf));
memset(obuf, 0, sizeof(obuf));
ilen = strnlen(plaintext, sizeof(plaintext)) + 1;
2016-11-21 19:28:54 +03:00
memcpy(ibuf, plaintext, ilen);
ilen = ((ilen + 15) / 16) * 16;
olen = 0;
xlen = 0;
if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
{
fprintf(stderr, "%s: winpr_Cipher_New (encrypt) failed\n", __FUNCTION__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
fprintf(stderr, "%s: winpr_Cipher_Final (encrypt) failed\n", __FUNCTION__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
fprintf(stderr, "%s: error, xlen (%"PRIuz") != ilen (%"PRIuz") (encrypt)\n", __FUNCTION__, xlen, ilen);
2016-11-21 19:28:54 +03:00
goto out;
}
winpr_Cipher_Free(ctx);
/* decrypt */
if (!(ctx = winpr_Cipher_New(WINPR_CIPHER_AES_128_CBC, WINPR_DECRYPT, key, iv)))
{
fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __FUNCTION__);
return FALSE;
}
memset(ibuf, 0, sizeof(ibuf));
memcpy(ibuf, obuf, xlen);
memset(obuf, 0, sizeof(obuf));
ilen = xlen;
olen = 0;
xlen = 0;
if (!winpr_Cipher_Update(ctx, ibuf, ilen, obuf, &olen))
{
fprintf(stderr, "%s: winpr_Cipher_New (decrypt) failed\n", __FUNCTION__);
goto out;
}
xlen += olen;
if (!winpr_Cipher_Final(ctx, obuf + xlen, &olen))
{
fprintf(stderr, "%s: winpr_Cipher_Final (decrypt) failed\n", __FUNCTION__);
goto out;
}
xlen += olen;
if (xlen != ilen)
{
fprintf(stderr, "%s: error, xlen (%"PRIuz") != ilen (%"PRIuz") (decrypt)\n", __FUNCTION__, xlen, ilen);
2016-11-21 19:28:54 +03:00
goto out;
}
if (strcmp((const char*) obuf, plaintext))
{
fprintf(stderr, "%s: error, decrypted data does not match plaintext\n", __FUNCTION__);
goto out;
}
result = TRUE;
out:
winpr_Cipher_Free(ctx);
return result;
}
static const BYTE* TEST_RC4_KEY = (BYTE*) "Key";
static const char* TEST_RC4_PLAINTEXT = "Plaintext";
static const BYTE* TEST_RC4_CIPHERTEXT = (BYTE*) "\xBB\xF3\x16\xE8\xD9\x40\xAF\x0A\xD3";
2016-02-28 13:12:17 +03:00
static BOOL test_crypto_cipher_rc4()
{
size_t len;
2016-02-28 13:12:17 +03:00
BOOL rc = FALSE;
BYTE* text = NULL;
WINPR_RC4_CTX* ctx;
len = strnlen(TEST_RC4_PLAINTEXT, sizeof(TEST_RC4_PLAINTEXT));
2016-11-21 19:28:54 +03:00
if (!(text = (BYTE*) calloc(1, len)))
{
fprintf(stderr, "%s: failed to allocate text buffer (len=%"PRIuz")\n", __FUNCTION__, len);
2016-02-28 13:12:17 +03:00
goto out;
2016-11-21 19:28:54 +03:00
}
if ((ctx = winpr_RC4_New(TEST_RC4_KEY, strnlen((const char*)TEST_RC4_KEY, sizeof(TEST_RC4_KEY)))) == NULL)
2016-11-21 19:28:54 +03:00
{
fprintf(stderr, "%s: winpr_RC4_New failed\n", __FUNCTION__);
2016-02-28 13:12:17 +03:00
goto out;
2016-11-21 19:28:54 +03:00
}
rc = winpr_RC4_Update(ctx, len, (const BYTE*) TEST_RC4_PLAINTEXT, text);
2016-02-28 13:12:17 +03:00
winpr_RC4_Free(ctx);
if (!rc)
2016-11-21 19:28:54 +03:00
{
fprintf(stderr, "%s: winpr_RC4_Update failed\n", __FUNCTION__);
2016-02-28 13:12:17 +03:00
goto out;
2016-11-21 19:28:54 +03:00
}
if (memcmp(text, TEST_RC4_CIPHERTEXT, len) != 0)
{
char* actual;
char* expected;
actual = winpr_BinToHexString(text, len, FALSE);
expected = winpr_BinToHexString(TEST_RC4_CIPHERTEXT, len, FALSE);
2016-11-21 19:28:54 +03:00
fprintf(stderr, "%s: unexpected RC4 ciphertext: Actual: %s Expected: %s\n", __FUNCTION__, actual, expected);
free(actual);
free(expected);
2016-02-28 13:12:17 +03:00
goto out;
}
2016-02-28 13:12:17 +03:00
rc = TRUE;
out:
free(text);
return rc;
}
static const BYTE* TEST_RAND_DATA = (BYTE*)
"\x1F\xC2\xEE\x4C\xA3\x66\x80\xA2\xCE\xFE\x56\xB4\x9E\x08\x30\x96"
"\x33\x6A\xA9\x6D\x36\xFD\x3C\xB7\x83\x04\x4E\x5E\xDC\x22\xCD\xF3"
"\x48\xDF\x3A\x2A\x61\xF1\xA8\xFA\x1F\xC6\xC7\x1B\x81\xB4\xE1\x0E"
"\xCB\xA2\xEF\xA1\x12\x4A\x83\xE5\x1D\x72\x1D\x2D\x26\xA8\x6B\xC0";
static const BYTE* TEST_CIPHER_KEY = (BYTE*)
"\x9D\x7C\xC0\xA1\x94\x3B\x07\x67\x2F\xD3\x83\x10\x51\x83\x38\x0E"
"\x1C\x74\x8C\x4E\x15\x79\xD6\xFF\xE2\xF0\x37\x7F\x8C\xD7\xD2\x13";
static const BYTE* TEST_CIPHER_IV = (BYTE*)
"\xFE\xE3\x9F\xF0\xD1\x5E\x37\x0C\xAB\xAB\x9B\x04\xF3\xDB\x99\x15";
2016-02-28 13:12:17 +03:00
static BOOL test_crypto_cipher_key()
{
int status;
BYTE key[32];
BYTE iv[16];
BYTE salt[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
ZeroMemory(key, sizeof(key));
ZeroMemory(iv, sizeof(iv));
2016-11-21 19:28:54 +03:00
status = winpr_Cipher_BytesToKey(WINPR_CIPHER_AES_256_CBC, WINPR_MD_SHA1,
salt, TEST_RAND_DATA, 64, 4, key, iv);
if (status != 32 || memcmp(key, TEST_CIPHER_KEY, 32) || memcmp(iv, TEST_CIPHER_IV, 16))
{
char* akstr;
char* ekstr;
char* aivstr;
char* eivstr;
akstr = winpr_BinToHexString(key, 32, 0);
ekstr = winpr_BinToHexString(TEST_CIPHER_KEY, 32, 0);
aivstr = winpr_BinToHexString(iv, 16, 0);
eivstr = winpr_BinToHexString(TEST_CIPHER_IV, 16, 0);
fprintf(stderr, "Unexpected EVP_BytesToKey Key: Actual: %s, Expected: %s\n", akstr, ekstr);
fprintf(stderr, "Unexpected EVP_BytesToKey IV : Actual: %s, Expected: %s\n", aivstr, eivstr);
free(akstr);
free(ekstr);
free(aivstr);
free(eivstr);
}
return TRUE;
}
int TestCryptoCipher(int argc, char* argv[])
{
Winpr/openssl: Fix digests initialization in multi-thread SSL functions like OpenSSL_add_all_digests should be invoked at very beginning as they are not MT safe. If not we might meet double free exception as following: #0 0x00007f23ddd71c37 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007f23ddd75028 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007f23dddae2a4 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #3 0x00007f23dddba55e in ?? () from /lib/x86_64-linux-gnu/libc.so.6 #4 0x00007f23dc6ecfcd in CRYPTO_free () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #5 0x00007f23dc6ef8d1 in OBJ_NAME_add () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #6 0x00007f23dc77dcd8 in EVP_add_digest () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #7 0x00007f23dc782321 in OpenSSL_add_all_digests () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 #8 0x00007f23c781da28 in winpr_openssl_get_evp_md (md=4) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:52 #9 0x00007f23c781dccb in winpr_Digest_Init (ctx=0x7f22d064d470, md=<optimized out>) at /home/zihao/workspace/zihao_FreeRDP/winpr/libwinpr/crypto/hash.c:344 #10 0x00007f23d486139b in security_salted_mac_signature (rdp=0x7f23859f5a20, data=0x7f238542d4fb "\004\204\022\004", length=4743, encryption=<optimized out>, output=0x7 at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/security.c:378 #11 0x00007f23d488d73f in fastpath_send_update_pdu (fastpath=<optimized out>, updateCode=4 '\004', s=0x7f23859f5f40, skipCompression=true) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/fastpath.c:1076 #12 0x00007f23d4891c4f in update_send_surface_frame_bits (context=0x7f23859f5540, cmd=0x7f22b2ffcc80, first=true, last=true, frameId=6) at /home/zihao/workspace/zihao_FreeRDP/libfreerdp/core/update.c:1041 Related reports: https://rt.openssl.org/Ticket/Display.html?id=2216&user=guest&pass=guest
2016-12-26 17:21:36 +03:00
winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
2016-11-21 19:28:54 +03:00
if (!test_crypto_cipher_aes_128_cbc())
return -1;
if (!test_crypto_cipher_rc4())
return -1;
if (!test_crypto_cipher_key())
return -1;
return 0;
}