/* * sm.c: Unit tests for Secure Messaging * * Copyright (C) 2021 Red Hat, Inc. * * Author: Jakub Jelen * * 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 . */ #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; }