kaoh / globalplatform

C library + command-line for Open- / GlobalPlatform smart cards
https://kaoh.github.io/globalplatform/
Other
72 stars 30 forks source link

Self check failures on several architectures: #84

Closed jas4711 closed 11 months ago

jas4711 commented 1 year ago

Hi. The globalplatform package just entered Debian, and it is attempted to be built on several architectures, see:

https://buildd.debian.org/status/package.php?p=globalplatform

But the scp01Test and scp02Test self-checks fails with output like this on several architectures:

(sid_armhf-dchroot)jas@abel:~/globalplatform-2.3.1+dfsg/globalplatform/src$ ./scp01Test 
[==========] Running 4 test(s).
[ RUN      ] mutual_auth_visa2
[       OK ] mutual_auth_visa2
[ RUN      ] install
[  ERROR   ] --- difference at offset 53 0xd4 0x00
1 bytes of 0xbedd39a8 and 0x18bcac8 differ
/home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:54: error: Check of parameter capdu, function send_APDU failed
/home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:74: note: Expected parameter declared here
[   LINE   ] --- /home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:54: error: Failure!
[  FAILED  ] install
[ RUN      ] get_status
[       OK ] get_status
[ RUN      ] get_status_mac_enc
[       OK ] get_status_mac_enc
[==========] 4 test(s) run.
[  PASSED  ] 3 test(s).
[  FAILED  ] 1 test(s), listed below:
[  FAILED  ] install

 1 FAILED TEST(S)
(sid_armhf-dchroot)jas@abel:~/globalplatform-2.3.1+dfsg/globalplatform/src$ ./scp02Test 
[==========] Running 2 test(s).
[ RUN      ] get_status_mac_only
[       OK ] get_status_mac_only
[ RUN      ] install_mac_enc
[  ERROR   ] --- difference at offset 53 0xd4 0x00
1 bytes of 0xbeb61a68 and 0x7cfac8 differ
/home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:54: error: Check of parameter capdu, function send_APDU failed
/home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:74: note: Expected parameter declared here
[   LINE   ] --- /home/jas/globalplatform-2.3.1+dfsg/globalplatform/src/testUtil.c:54: error: Failure!
[  FAILED  ] install_mac_enc
[==========] 2 test(s) run.
[  PASSED  ] 1 test(s).
[  FAILED  ] 1 test(s), listed below:
[  FAILED  ] install_mac_enc

 1 FAILED TEST(S)
(sid_armhf-dchroot)jas@abel:~/globalplatform-2.3.1+dfsg/globalplatform/src$ 

I'm able to reproduce the problem under valgrind on amd64 too. (To get valgrind to work, I had to disable -fsanitize=address from DEBUG build.)

jas@kaka:~/src/globalplatform/globalplatform/src$ valgrind -q ./scp01Test 
[==========] Running 4 test(s).
[ RUN      ] mutual_auth_visa2
[       OK ] mutual_auth_visa2
[ RUN      ] install
==467245== Conditional jump or move depends on uninitialised value(s)
==467245==    at 0x4CC0B5A: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467245==    by 0x4CC15A1: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467245==    by 0x4CC36F9: _check_expected (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467245==    by 0x10EA97: send_APDU (testUtil.c:54)
==467245==    by 0x10FBA6: OPGP_send_APDU (connection.c:244)
==467245==    by 0x129FD6: install_for_install_and_make_selectable (globalplatform.c:2942)
==467245==    by 0x13677F: OP201_install_for_install_and_make_selectable (globalplatform.c:5928)
==467245==    by 0x10D8B3: install (scp01Test.c:256)
==467245==    by 0x4CC34E0: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467245==    by 0x4CC3EC4: _cmocka_run_group_tests (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467245==    by 0x10E893: main (scp01Test.c:401)
==467245== 
[       OK ] install
[ RUN      ] get_status
[       OK ] get_status
[ RUN      ] get_status_mac_enc
[       OK ] get_status_mac_enc
[==========] 4 test(s) run.
[  PASSED  ] 4 test(s).
jas@kaka:~/src/globalplatform/globalplatform/src$ valgrind -q ./scp02Test 
[==========] Running 2 test(s).
[ RUN      ] get_status_mac_only
==467248== Conditional jump or move depends on uninitialised value(s)
==467248==    at 0x4CC2CA7: _assert_int_equal (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x10C5B3: get_status_mac_only (scp02Test.c:101)
==467248==    by 0x4CC34E0: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x4CC3EC4: _cmocka_run_group_tests (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x10D283: main (scp02Test.c:218)
==467248== 
[       OK ] get_status_mac_only
[ RUN      ] install_mac_enc
==467248== Conditional jump or move depends on uninitialised value(s)
==467248==    at 0x4CC0B5A: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x4CC15A1: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x4CC36F9: _check_expected (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x10D487: send_APDU (testUtil.c:54)
==467248==    by 0x10E596: OPGP_send_APDU (connection.c:244)
==467248==    by 0x1289C6: install_for_install_and_make_selectable (globalplatform.c:2942)
==467248==    by 0x12845F: GP211_install_for_install_and_make_selectable (globalplatform.c:2827)
==467248==    by 0x10D15C: install_mac_enc (scp02Test.c:198)
==467248==    by 0x4CC34E0: ??? (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x4CC3EC4: _cmocka_run_group_tests (in /usr/lib/x86_64-linux-gnu/libcmocka.so.0.7.0)
==467248==    by 0x10D283: main (scp02Test.c:218)
==467248== 
[       OK ] install_mac_enc
[==========] 2 test(s) run.
[  PASSED  ] 2 test(s).
jas@kaka:~/src/globalplatform/globalplatform/src$ 

The C code triggers plenty of type and bound warnings here, and I suspect there is some 'unsigned' vs 'signed' mismatch somewhere causing errors. Before spending too much time debugging, I thought I'd open an issue about it if you can reproduce the problem and debug it more easily than I can.

/Simon

koh-osug commented 1 year ago

I have just run this on Ubuntu x86_64 without valgrind. But I tested the library and gpshell with valgrind. Could cmocka be the issue?

koh-osug commented 12 months ago

I have found 2 incorrect header declaratiosn of the byte array size. Please check again. Also the fixed bate ararys which I'm usign are causing a lot of of warning wlthough I don't understand why it is complaining since the size is OK:

/home/foobar/projects/globalplatform/globalplatform/src/globalplatform.c:4987:26: note: referencing argument 4 of type ‘BYTE ’ {aka ‘unsigned char ’} In file included from /home/foobar/projects/globalplatform/globalplatform/src/globalplatform.c:56: /home/foobar/projects/globalplatform/globalplatform/src/crypto.h:90:19: note: in a call to function ‘create_session_key_SCP02’ 90 | OPGP_ERROR_STATUS create_session_key_SCP02(BYTE key[16], BYTE constant[2], | ^~~~~~~~ /home/foobar/projects/globalplatform/globalplatform/src/globalplatform.c:4993:26: warning: ‘create_session_key_SCP02’ accessing 16 bytes in a region of size 2 [-Wstringop-overflow=] 4993 | status = create_session_key_SCP02(DEK, DEKDerivationConstant, sequenceCounter, secInfo->dataEncryptionSessionKey); | ^~~~~~~~~~~~~~~~~~~~~~~~

jas4711 commented 12 months ago

I think using foo[17] or foo[42] in a C function parameter prototype is equivalent: they are both converted to *foo and the size value is lost. It is possible to sprinkle a 'static' in there, but this is rarely done so I wouldn't recommend it, and it disallows passing NULL, see for example: https://hamberg.no/erlend/posts/2013-02-18-static-array-indices.html

I didn't analyze the first warning, but maybe it goes away if you convert the C function prototype to foo[] or even *foo? The second warning seems like maybe the caller used a too short buffer for the 2-byte constant array?

So I think your patch is essentially a no-op and doesn't change anything. If the buffer size has to be changed, it has to be changed in the caller to the function. I re-ran the valgrind command above, and the output is still the same.

koh-osug commented 11 months ago

I have tried to analyse scp01. I assum the "still reachable leaks" are not a problem and the problem is coming from "Uninitialised value was created by a stack allocation"? Not sure if the Valgrind traces are all correct, but I have not found any explanantion what could be wrong with these lines. Is the amd64 error related to the errors on other platforms?

jas4711 commented 11 months ago

Yes the "Conditional jump or move depends on uninitialised value" normally indicates real source-code level problems.

It is not certain that fixing the amd64 valgrind error will fix the problem on the other platform, but in my experience valgrind is a good tool to find things that merely accidentally work on one platform but actually breaks practically on another platform. So I'd give it a 75% probability that fixing the valgrind problem will fix the platform problems too. And usually debugging and fixing valgrind errors on amd64 is easier than debugging and fixing native problem on other hardware, although maybe this changed in the last few years... the Compile Farm project https://portal.cfarm.net/machines/list/ has many machines available for development if you find it easier to debug it natively.

koh-osug commented 11 months ago

I have fixed the "Uninitialised value was created by a stack allocation" issues. Please give it a try.

jas4711 commented 11 months ago

Thank you! I can confirm valgrind errors are gone now. I'm preparing a new upload to Debian to test on other architectures, although there seems to be some problem with the "pandoc" package in Debian causing build problems.

kaoh commented 11 months ago

Great. Not sure, where I use pandoc, I think it was the man page. If this is mandatory to have in Debian, then a solution must be found, otherwise maybe also the produced output can be included directly without runnig pandoc.

jas4711 commented 11 months ago

It builds with self-checks on many platforms now! So I think your patch fixed it.

https://buildd.debian.org/status/package.php?p=globalplatform

However s390x fails, but it is different:

4/5 Test #4: cryptoTest .......................***Failed    0.00 sec
[==========] Running 3 test(s).
[ RUN      ] test_aes_cmac_128
[       OK ] test_aes_cmac_128
[ RUN      ] test_aes_cmac_192
[       OK ] test_aes_cmac_192
[ RUN      ] test_read_public_rsa_key
[  ERROR   ] --- 0x100010000000000 != 0x10001
[   LINE   ] --- ./globalplatform/src/cryptoTest.c:99: error: Failure!
[  FAILED  ] test_read_public_rsa_key
[==========] 3 test(s) run.
[  PASSED  ] 2 test(s).
[  FAILED  ] 1 test(s), listed below:
[  FAILED  ] test_read_public_rsa_key

Any ideas? See complete log here:

https://buildd.debian.org/status/fetch.php?pkg=globalplatform&arch=s390x&ver=2.3.1%2Bdfsg-4&stamp=1702373785&raw=0

It seems like stdout/stderr ordering seems a bit garbled due to buffering.

koh-osug commented 11 months ago

The prefix is identical:

0x100010000000000 != 0x10001

This looks like 65535, the common RSA exponent. I assume it is an alignment issue or data type issue then.

koh-osug commented 11 months ago

It is this line:

BN_bn2bin(e, ((unsigned char *)rsaExponent));

So, a little endina big endian problem, it seems.

jas4711 commented 11 months ago

The patch in #88 resolves the problem, and now it builds on all platforms in Debian with self-checks, see logs:

https://buildd.debian.org/status/package.php?p=globalplatform https://buildd.debian.org/status/fetch.php?pkg=globalplatform&arch=s390x&ver=2.3.1%2Bdfsg-5&stamp=1702631621&raw=0