opensc/src/tests/unittests/sm.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;
}