377 lines
12 KiB
C
377 lines
12 KiB
C
/*
|
|
* sm.c: Unit tests for Secure Messaging
|
|
*
|
|
* Copyright (C) 2021 Red Hat, Inc.
|
|
*
|
|
* Author: Jakub Jelen <jjelen@redhat.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "torture.h"
|
|
#include "libopensc/log.c"
|
|
#include "sm/sm-common.h"
|
|
|
|
/* Setup context */
|
|
static int setup_sc_context(void **state)
|
|
{
|
|
sc_context_t *ctx = NULL;
|
|
int rv;
|
|
|
|
rv = sc_establish_context(&ctx, "sm");
|
|
assert_non_null(ctx);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
|
|
*state = ctx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Cleanup context */
|
|
static int teardown_sc_context(void **state)
|
|
{
|
|
sc_context_t *ctx = *state;
|
|
int rv;
|
|
|
|
rv = sc_release_context(ctx);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void torture_sm_incr_ssc(void **state)
|
|
{
|
|
unsigned char in[] = {0x00, 0x00};
|
|
|
|
(void)state;
|
|
|
|
/* just make sure it does not crash */
|
|
sm_incr_ssc(NULL, 0);
|
|
|
|
/* zero-length input should not underflow the buffer */
|
|
sm_incr_ssc(in, 0);
|
|
|
|
/* shortest possible input */
|
|
in[0] = 0x42;
|
|
sm_incr_ssc(in, 1);
|
|
assert_int_equal(in[0], 0x43);
|
|
|
|
/* overflow to the second byte */
|
|
in[0] = 0x00;
|
|
in[1] = 0xff;
|
|
sm_incr_ssc(in, 2);
|
|
assert_int_equal(in[0], 0x01);
|
|
assert_int_equal(in[1], 0x00);
|
|
|
|
/* overflow */
|
|
in[0] = 0xff;
|
|
in[1] = 0xff;
|
|
sm_incr_ssc(in, 2);
|
|
assert_int_equal(in[0], 0x00);
|
|
assert_int_equal(in[1], 0x00);
|
|
}
|
|
|
|
static void torture_sm_crypt_des_cbc3(void **state)
|
|
{
|
|
sc_context_t *ctx = *state;
|
|
/* Test vector from
|
|
* https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-20.pdf
|
|
* 5.2.1.1 The Variable Plaintext Known Answer Test -TCBC Mode
|
|
*/
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char plain[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char ciphertext[] = {0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00};
|
|
unsigned char *out = NULL; /* allocates */
|
|
size_t out_len = 0;
|
|
int rv;
|
|
|
|
rv = sm_encrypt_des_cbc3(ctx, key, plain, sizeof(plain), &out, &out_len, 1);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_int_equal(out_len, sizeof(ciphertext));
|
|
assert_memory_equal(out, ciphertext, sizeof(ciphertext));
|
|
free(out);
|
|
out = NULL;
|
|
out_len = 0;
|
|
|
|
rv = sm_decrypt_des_cbc3(ctx, key, ciphertext, sizeof(ciphertext), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_memory_equal(out, plain, sizeof(plain));
|
|
free(out);
|
|
}
|
|
|
|
static void torture_sm_crypt_des_cbc3_multiblock(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
sc_context_t *ctx = *state;
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00};
|
|
unsigned char ciphertext[] = {
|
|
0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00,
|
|
0xAF, 0xA0, 0x77, 0x1d, 0x35, 0xE1, 0xCC, 0x26};
|
|
unsigned char *out = NULL; /* allocates */
|
|
size_t out_len = 0;
|
|
int rv;
|
|
|
|
rv = sm_encrypt_des_cbc3(ctx, key, plain, sizeof(plain), &out, &out_len, 1);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_int_equal(out_len, sizeof(ciphertext));
|
|
assert_memory_equal(out, ciphertext, sizeof(ciphertext));
|
|
free(out);
|
|
out = NULL;
|
|
out_len = 0;
|
|
|
|
rv = sm_decrypt_des_cbc3(ctx, key, ciphertext, sizeof(ciphertext), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_memory_equal(out, plain, sizeof(plain));
|
|
free(out);
|
|
}
|
|
|
|
static void torture_sm_crypt_des_cbc3_force_pad(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
sc_context_t *ctx = *state;
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char plain[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char ciphertext[] = {
|
|
0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00,
|
|
0xC6, 0xD3, 0xE1, 0x4F, 0xFB, 0xDE, 0xDF, 0xF9};
|
|
unsigned char *out = NULL; /* allocates */
|
|
size_t out_len = 0;
|
|
int rv;
|
|
|
|
rv = sm_encrypt_des_cbc3(ctx, key, plain, sizeof(plain), &out, &out_len, 0);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_int_equal(out_len, sizeof(ciphertext));
|
|
assert_memory_equal(out, ciphertext, sizeof(ciphertext));
|
|
free(out);
|
|
out = NULL;
|
|
out_len = 0;
|
|
|
|
rv = sm_decrypt_des_cbc3(ctx, key, ciphertext, sizeof(ciphertext), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_memory_equal(out, plain, sizeof(plain));
|
|
free(out);
|
|
}
|
|
|
|
static void torture_sm_encrypt_des_ecb3(void **state)
|
|
{
|
|
/* Test vector from
|
|
* https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-20.pdf
|
|
* 5.2.1.1 The Variable Plaintext Known Answer Test -TCBC Mode
|
|
*/
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char plain[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char ciphertext[] = {0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00};
|
|
unsigned char *out = NULL; /* allocates */
|
|
int out_len = 0;
|
|
int rv;
|
|
|
|
(void)state;
|
|
|
|
rv = sm_encrypt_des_ecb3(key, plain, sizeof(plain), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_int_equal(out_len, sizeof(ciphertext));
|
|
assert_memory_equal(out, ciphertext, sizeof(ciphertext));
|
|
free(out);
|
|
out = NULL;
|
|
out_len = 0;
|
|
|
|
rv = sm_encrypt_des_ecb3(key, ciphertext, sizeof(ciphertext), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_memory_equal(out, plain, sizeof(plain));
|
|
free(out);
|
|
}
|
|
|
|
static void torture_sm_encrypt_des_ecb3_multiblock(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char ciphertext[] = {
|
|
0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00,
|
|
0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F};
|
|
unsigned char *out = NULL; /* allocates */
|
|
int out_len = 0;
|
|
int rv;
|
|
|
|
(void)state;
|
|
|
|
rv = sm_encrypt_des_ecb3(key, plain, sizeof(plain), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_int_equal(out_len, sizeof(ciphertext));
|
|
assert_memory_equal(out, ciphertext, sizeof(ciphertext));
|
|
free(out);
|
|
out = NULL;
|
|
out_len = 0;
|
|
|
|
rv = sm_encrypt_des_ecb3(key, ciphertext, sizeof(ciphertext), &out, &out_len);
|
|
assert_int_equal(rv, SC_SUCCESS);
|
|
assert_memory_equal(out, plain, sizeof(plain));
|
|
free(out);
|
|
}
|
|
|
|
static void torture_DES_cbc_cksum_3des(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char iv[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char checksum_ref[] = {
|
|
0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00};
|
|
unsigned long sum_ref = 0xdd31d900UL;
|
|
unsigned char checksum[8];
|
|
unsigned long sum;
|
|
|
|
(void)state;
|
|
|
|
sum = DES_cbc_cksum_3des(plain, &checksum, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
assert_memory_equal(checksum, checksum_ref, sizeof(checksum_ref));
|
|
|
|
/* The checksum argument is not required */
|
|
sum = DES_cbc_cksum_3des(plain, NULL, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
}
|
|
|
|
static void torture_DES_cbc_cksum_3des_multiblock(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char iv[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
/* I think this function assumes/requires full blocks */
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char checksum_ref[] = {
|
|
0xC6, 0x3F, 0x6E, 0x72, 0xC7, 0xCF, 0x4E, 0x07};
|
|
unsigned long sum_ref = 0xc7cf4e07UL;
|
|
unsigned char checksum[8];
|
|
unsigned long sum;
|
|
|
|
(void)state;
|
|
|
|
sum = DES_cbc_cksum_3des(plain, &checksum, sizeof(plain), key, &iv);
|
|
assert_memory_equal(checksum, checksum_ref, sizeof(checksum_ref));
|
|
assert_int_equal(sum, sum_ref);
|
|
|
|
/* The checksum argument is not required */
|
|
sum = DES_cbc_cksum_3des(plain, NULL, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
}
|
|
|
|
static void torture_DES_cbc_cksum_3des_emv96(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char iv[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char checksum_ref[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0xDD, 0x31, 0xD9, 0x00};
|
|
unsigned long sum_ref = 0xdd31d900UL;
|
|
unsigned char checksum[8];
|
|
unsigned long sum;
|
|
|
|
(void)state;
|
|
|
|
sum = DES_cbc_cksum_3des_emv96(plain, &checksum, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
assert_memory_equal(checksum, checksum_ref, sizeof(checksum_ref));
|
|
|
|
/* The checksum argument is not required */
|
|
sum = DES_cbc_cksum_3des_emv96(plain, NULL, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
}
|
|
|
|
static void torture_DES_cbc_cksum_3des_emv96_multiblock(void **state)
|
|
{
|
|
/* not a test vector -- generated by openssl 1.1.1 */
|
|
unsigned char key[] = {
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY1 */
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* KEY2 */};
|
|
unsigned char iv[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
/* I think this function assumes/requires full blocks */
|
|
unsigned char plain[] = {
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
unsigned char checksum_ref[] = {
|
|
0x95, 0xf8, 0xA5, 0xe5, 0xC7, 0xCF, 0x4E, 0x07};
|
|
unsigned long sum_ref = 0xc7cf4e07UL;
|
|
unsigned char checksum[8] = {0};
|
|
unsigned long sum;
|
|
|
|
(void)state;
|
|
|
|
sum = DES_cbc_cksum_3des_emv96(plain, &checksum, sizeof(plain), key, &iv);
|
|
assert_memory_equal(checksum, checksum_ref, sizeof(checksum_ref));
|
|
assert_int_equal(sum, sum_ref);
|
|
|
|
/* The checksum argument is not required */
|
|
sum = DES_cbc_cksum_3des_emv96(plain, NULL, sizeof(plain), key, &iv);
|
|
assert_int_equal(sum, sum_ref);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int rc;
|
|
struct CMUnitTest tests[] = {
|
|
/* sm_incr_ssc */
|
|
cmocka_unit_test(torture_sm_incr_ssc),
|
|
/* sm_encrypt_des_cbc3 and sm_decrypt_des_cbc3 */
|
|
cmocka_unit_test_setup_teardown(torture_sm_crypt_des_cbc3,
|
|
setup_sc_context, teardown_sc_context),
|
|
cmocka_unit_test_setup_teardown(torture_sm_crypt_des_cbc3_multiblock,
|
|
setup_sc_context, teardown_sc_context),
|
|
cmocka_unit_test_setup_teardown(torture_sm_crypt_des_cbc3_force_pad,
|
|
setup_sc_context, teardown_sc_context),
|
|
/* sm_encrypt_des_ecb3 */
|
|
cmocka_unit_test(torture_sm_encrypt_des_ecb3),
|
|
cmocka_unit_test(torture_sm_encrypt_des_ecb3_multiblock),
|
|
/* DES_cbc_cksum_3des */
|
|
cmocka_unit_test(torture_DES_cbc_cksum_3des),
|
|
cmocka_unit_test(torture_DES_cbc_cksum_3des_multiblock),
|
|
/* DES_cbc_cksum_3des_emv96 */
|
|
cmocka_unit_test(torture_DES_cbc_cksum_3des_emv96),
|
|
cmocka_unit_test(torture_DES_cbc_cksum_3des_emv96_multiblock),
|
|
};
|
|
|
|
rc = cmocka_run_group_tests(tests, NULL, NULL);
|
|
return rc;
|
|
}
|