laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-remsim/+/42300?usp=email )
Change subject: bankd: Avoid osmocom logging mutex deadlock in signal handling
......................................................................
bankd: Avoid osmocom logging mutex deadlock in signal handling
The main thread communicates slotmap add + delete via POSIX signals
to the worker threads. As those signals interrupt the normal
processing of the worker thread, they might get delivered while the
thread is already logging something, causing a deadlock. This has
been observed in the real world in the following stack trace (where it's
actually two nested signals):
Thread 45 (Thread 0x7fa014ff96c0 (LWP 620753) "osmo-remsim-ban"):
#0 futex_wait (private=0, expected=2, futex_word=0x7fa0a992b360 <osmo_log_tgt_mutex>) at ../sysdeps/nptl/futex-internal.h:146
#1 __GI___lll_lock_wait (futex=futex@entry=0x7fa0a992b360 <osmo_log_tgt_mutex>, private=0) at ./nptl/lowlevellock.c:49
#2 0x00007fa0a9730482 in lll_mutex_lock_optimized (mutex=0x7fa0a992b360 <osmo_log_tgt_mutex>) at ./nptl/pthread_mutex_lock.c:48
#3 ___pthread_mutex_lock (mutex=0x7fa0a992b360 <osmo_log_tgt_mutex>) at ./nptl/pthread_mutex_lock.c:93
#4 0x00007fa0a98d878d in log_tgt_mutex_lock_impl () from /usr/local/lib/libosmocore.so.22
#5 0x00007fa0a98db9a1 in log_check_level () from /usr/local/lib/libosmocore.so.22
#6 0x0000559db6278e31 in handle_sig_mapadd (sig=<optimized out>) at bankd_main.c:558
#7 <signal handler called>
#8 0x00007fa0a9701548 in __vfprintf_internal (s=s@entry=0x7fa014fe3a50, format=format@entry=0x7fa0a991905a "%ld ", ap=ap@entry=0x7fa014fe3bd0, mode_flags=mode_flags@entry=0) at ./stdio-common/vfprintf-internal.c:983
#9 0x00007fa0a9722758 in __vsnprintf_internal (string=0x7fa014fe3eb0 "", maxlen=<optimized out>, format=0x7fa0a991905a "%ld ", args=args@entry=0x7fa014fe3bd0, mode_flags=mode_flags@entry=0) at ./libio/vsnprintf.c:114
#10 0x00007fa0a96fcca2 in __GI___snprintf (s=<optimized out>, maxlen=<optimized out>, format=<optimized out>) at ./stdio-common/snprintf.c:31
#11 0x00007fa0a98d91b4 in _output_buf () from /usr/local/lib/libosmocore.so.22
#12 0x00007fa0a98d9def in _output () from /usr/local/lib/libosmocore.so.22
#13 0x00007fa0a98da0ef in osmo_vlogp () from /usr/local/lib/libosmocore.so.22
#14 0x00007fa0a98da2bb in logp2 () from /usr/local/lib/libosmocore.so.22
#15 0x0000559db62790ba in handle_sig_mapdel (sig=35) at bankd_main.c:546
#16 <signal handler called>
#17 0x00007fa0a97a025f in __GI___poll (fds=0x7fa014fe5650, nfds=1, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
#18 0x00007fa0a9892d53 in ?? () from /lib/x86_64-linux-gnu/libpcsclite.so.1
#19 0x00007fa0a988fd9e in SCardTransmit () from /lib/x86_64-linux-gnu/libpcsclite.so.1
#20 0x0000559db627c9ef in pcsc_transceive (worker=0x559dbd5c5750, out=<optimized out>, out_len=<optimized out>, in=<optimized out>, in_len=0x7fa014fe57b8) at bankd_pcsc.c:319
#21 0x0000559db627a479 in worker_handle_tpduModemToCard (pdu=0x7fa050003a50, worker=0x559dbd5c5750) at bankd_main.c:826
#22 worker_handle_rspro (pdu=0x7fa050003a50, worker=0x559dbd5c5750) at bankd_main.c:892
#23 worker_transceive_loop (worker=0x559dbd5c5750) at bankd_main.c:1005
#24 0x0000559db627aff2 in worker_main (arg=<optimized out>) at bankd_main.c:1079
#25 0x00007fa0a972d1f5 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#26 0x00007fa0a97ad8dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
As a hot-fix, let's avoid logging from the handle_sig_map{del,add}()
functions at all, making them safe against a deadlock around this mutex.
We should decide how to proceed in general with potentially some
architectural changes later on; any such changes are not suitable as a
hot fix due to their potential of introducing other regressions.
Change-Id: I5ea32886dfaf624b4dc5ad7924941c7b904c1d36
Related: SYS#7930
---
M src/bankd/bankd_main.c
1 file changed, 12 insertions(+), 10 deletions(-)
Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/src/bankd/bankd_main.c b/src/bankd/bankd_main.c
index 1adc34c..5e33b41 100644
--- a/src/bankd/bankd_main.c
+++ b/src/bankd/bankd_main.c
@@ -521,9 +521,10 @@
static int worker_send_rspro(struct bankd_worker *worker, RsproPDU_t *pdu);
-static void worker_set_state(struct bankd_worker *worker, enum bankd_worker_state new_state)
+static void worker_set_state(struct bankd_worker *worker, enum bankd_worker_state new_state, bool quiet)
{
- LOGW(worker, "Changing state to %s\n", get_value_string(worker_state_names, new_state));
+ if (!quiet)
+ LOGW(worker, "Changing state to %s\n", get_value_string(worker_state_names, new_state));
worker->state = new_state;
worker->timeout = 0;
}
@@ -540,25 +541,26 @@
/* signal handler for receiving SIGMAPDEL from main thread */
static void handle_sig_mapdel(int sig)
{
- LOGW(g_worker, "SIGMAPDEL received: Main thread informs us our map is gone\n");
+ /* DO NOT LOG ANYTHING HERE, IT WILL DEADLOCK WITH THE osmo_log_tgt_mutex */
OSMO_ASSERT(sig == SIGMAPDEL);
if (g_worker->state >= BW_ST_CONN_CLIENT_MAPPED) {
g_worker->slot.bank_id = 0xffff;
g_worker->slot.slot_nr = 0xffff;
- worker_set_state(g_worker, BW_ST_CONN_CLIENT_UNMAPPED);
+ worker_set_state(g_worker, BW_ST_CONN_CLIENT_UNMAPPED, true);
}
}
/* signal handler for receiving SIGMAPADD from main thread */
static void handle_sig_mapadd(int sig)
{
- LOGW(g_worker, "SIGMAPADD received\n");
+ /* DO NOT LOG ANYTHING HERE, IT WILL DEADLOCK WITH THE osmo_log_tgt_mutex */
/* do nothing */
}
static void handle_sig_usr1(int sig)
{
OSMO_ASSERT(sig == SIGUSR1);
+ /* FIXME: WE SHOULD NOT LOG ANYTHING HERE, IT WILL DEADLOCK WITH THE osmo_log_tgt_mutex */
if (pthread_equal(g_bankd->main, pthread_self())) {
struct bankd_worker *worker;
@@ -612,7 +614,7 @@
if (rc < 0)
return rc;
- worker_set_state(worker, BW_ST_CONN_CLIENT_MAPPED_CARD);
+ worker_set_state(worker, BW_ST_CONN_CLIENT_MAPPED_CARD, false);
/* FIXME: notify client about this state change */
return 0;
@@ -763,7 +765,7 @@
}
worker->client.clslot.client_id = pdu->msg.choice.connectClientReq.clientSlot->clientId;
worker->client.clslot.slot_nr = pdu->msg.choice.connectClientReq.clientSlot->slotNr;
- worker_set_state(worker, BW_ST_CONN_CLIENT);
+ worker_set_state(worker, BW_ST_CONN_CLIENT, false);
if (worker_try_slotmap(worker) >= 0)
res = ResultCode_ok;
@@ -1041,7 +1043,7 @@
g_worker = (struct bankd_worker *) arg;
- worker_set_state(g_worker, BW_ST_INIT);
+ worker_set_state(g_worker, BW_ST_INIT, false);
/* not permitted in multithreaded environment */
talloc_disable_null_tracking();
@@ -1065,7 +1067,7 @@
g_worker->client.peer_addr_len = sizeof(g_worker->client.peer_addr);
- worker_set_state(g_worker, BW_ST_ACCEPTING);
+ worker_set_state(g_worker, BW_ST_ACCEPTING, false);
/* first wait for an incoming TCP connection */
rc = accept(g_worker->bankd->accept_fd, (struct sockaddr *) &g_worker->client.peer_addr,
&g_worker->client.peer_addr_len);
@@ -1075,7 +1077,7 @@
g_worker->client.fd = rc;
worker_client_addrstr(buf, sizeof(buf), g_worker);
LOGW(g_worker, "Accepted connection from %s\n", buf);
- worker_set_state(g_worker, BW_ST_CONN_WAIT_ID);
+ worker_set_state(g_worker, BW_ST_CONN_WAIT_ID, false);
/* run the main worker transceive loop body until there was some error */
while (1) {
--
To view, visit https://gerrit.osmocom.org/c/osmo-remsim/+/42300?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-remsim
Gerrit-Branch: master
Gerrit-Change-Id: I5ea32886dfaf624b4dc5ad7924941c7b904c1d36
Gerrit-Change-Number: 42300
Gerrit-PatchSet: 2
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Attention is currently required from: fixeria, lynxis lazus, pespin.
laforge has posted comments on this change by laforge. ( https://gerrit.osmocom.org/c/osmo-remsim/+/42300?usp=email )
Change subject: bankd: Avoid osmocom logging mutex deadlock in signal handling
......................................................................
Patch Set 2: Code-Review+2
(1 comment)
Commit Message:
https://gerrit.osmocom.org/c/osmo-remsim/+/42300/comment/af528f29_1f2fb8e2?… :
PS1, Line 13: the following stack trace
> the stack trace is missing?
mh, I guess git has removed it due to it containing hash marks. IT was definitely in my local editor...
--
To view, visit https://gerrit.osmocom.org/c/osmo-remsim/+/42300?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-remsim
Gerrit-Branch: master
Gerrit-Change-Id: I5ea32886dfaf624b4dc5ad7924941c7b904c1d36
Gerrit-Change-Number: 42300
Gerrit-PatchSet: 2
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Attention: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Comment-Date: Tue, 10 Mar 2026 09:25:00 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: fixeria <vyanitskiy(a)sysmocom.de>
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/42278?usp=email )
Change subject: tests/pySim-smpp2sim_test/card_sanitizer: update card backup with new test keyset
......................................................................
tests/pySim-smpp2sim_test/card_sanitizer: update card backup with new test keyset
In our test setup we run the card_sanitizer.py script regualary to ensure that
we have consistent start conditions when running our tests. In case a testcase
crashes for some reason and leaves messed up files on a test card. The
card_sanitizer.py script will ensure that any problem like that is cleaned up
over night.
For the testcases we are about to add in the patch following this one, we need
to provision a new test keyset to one of our test cards. This has been already
done manually. However since the card_sanitizer still has the old keys in its
backup we will have to update that as well.
Change-Id: I5aa8a413b19b3e43a79d03e904daab50b4b1e767
Related: OS#6868
---
M tests/card_sanitizer/card_backup_3b9f96801f878031e073fe211b674a357530350265f8_8949440000001155314.script
1 file changed, 3 insertions(+), 3 deletions(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/tests/card_sanitizer/card_backup_3b9f96801f878031e073fe211b674a357530350265f8_8949440000001155314.script b/tests/card_sanitizer/card_backup_3b9f96801f878031e073fe211b674a357530350265f8_8949440000001155314.script
index 682d700..4285771 100644
--- a/tests/card_sanitizer/card_backup_3b9f96801f878031e073fe211b674a357530350265f8_8949440000001155314.script
+++ b/tests/card_sanitizer/card_backup_3b9f96801f878031e073fe211b674a357530350265f8_8949440000001155314.script
@@ -2200,9 +2200,9 @@
update_record 7 fe02101da012f436d06824ecdd15050419ff9affffffffffffffffffffffffffffffff
update_record 8 fe02116929a373388ac904aff57ff57f6b3431ffffffffffffffffffffffffffffffff
update_record 9 fe0212a99245a5dc814e2f4c1aa908e9946e03ffffffffffffffffffffffffffffffff
-update_record 10 fe0310521312c05a9aea93d70d44405172a580ffffffffffffffffffffffffffffffff
-update_record 11 fe0311a9e45c72d45abde7db74261ee0c11b1bffffffffffffffffffffffffffffffff
-update_record 12 fe0312867ba36b5873d60ea8b2cdcf3c0ddddaffffffffffffffffffffffffffffffff
+update_record 10 fe03601111111111111111111111111111111111111111111111111111111111111111
+update_record 11 fe03612222222222222222222222222222222222222222222222222222222222222222
+update_record 12 fe03623333333333333333333333333333333333333333333333333333333333333333
#
################################################################################
# MF/DF.SYSTEM/EF.SIM_AUTH_COUNTER #
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42278?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I5aa8a413b19b3e43a79d03e904daab50b4b1e767
Gerrit-Change-Number: 42278
Gerrit-PatchSet: 2
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/42189?usp=email )
Change subject: tests/pySim-smpp2sim_test: add testcases for AES128 and AES256
......................................................................
tests/pySim-smpp2sim_test: add testcases for AES128 and AES256
Extend the existing test script so that it can handle multiple
testcases. Also add support for switching eUICC profiles.
Finally, add a testcases to test OTA-SMS (RFM) with AES128 and
AES256 encryption.
Change-Id: I1f10504f3a29a8c74a17991632d932819fecfa5a
Related: OS#6868
---
D tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
M tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
A tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
A tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
A tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
5 files changed, 161 insertions(+), 46 deletions(-)
Approvals:
daniel: Looks good to me, but someone else must approve
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
deleted file mode 100644
index 1c2a953..0000000
--- a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.cfg
+++ /dev/null
@@ -1,9 +0,0 @@
-# Card parameter:
-ICCID="8949440000001155314"
-KIC='51D4FC44BCBA7C4589DFADA3297720AF'
-KID='0449699C472CE71E2FB7B56245EF7684'
-
-# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
-TAR='B00010'
-APDU='A0A40000027F20A0C0000016'
-EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
\ No newline at end of file
diff --git a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
index 2ca0a9e..0881319 100755
--- a/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
+++ b/tests/pySim-smpp2sim_test/pySim-smpp2sim_test.sh
@@ -20,13 +20,14 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+PYSIM_SHELL=./pySim-shell.py
+PYSIM_SHELL_LOG=./pySim-shell.log
PYSIM_SMPP2SIM=./pySim-smpp2sim.py
PYSIM_SMPP2SIM_LOG=./pySim-smpp2sim.log
PYSIM_SMPP2SIM_PORT=2775
PYSIM_SMPP2SIM_TIMEOUT=10
PYSIM_SMPPOTATOOL=./contrib/smpp-ota-tool.py
PYSIM_SMPPOTATOOL_LOG=./smpp-ota-tool.log
-PYSIM_SHELL=./pySim-shell.py
function dump_logs {
echo ""
@@ -44,12 +45,11 @@
function send_test_request {
echo ""
echo "Sending request to SMPP server:"
- TAR=$1
- C_APDU=$2
- R_APDU_EXPECTED=$3
+ C_APDU=$1
+ R_APDU_EXPECTED=$2
echo "Sending: $C_APDU"
- COMMANDLINE="$PYSIM_SMPPOTATOOL --verbose --port $PYSIM_SMPP2SIM_PORT --kic $KIC --kid $KID --tar $TAR --apdu $C_APDU"
+ COMMANDLINE="$PYSIM_SMPPOTATOOL --verbose --port $PYSIM_SMPP2SIM_PORT --kic $KIC --kid $KID --kic_idx $KEY_INDEX --kid_idx $KEY_INDEX --algo-crypt $ALGO_CRYPT --algo-auth $ALGO_AUTH --tar $TAR --apdu $C_APDU"
echo "Commandline: $COMMANDLINE"
R_APDU=`$COMMANDLINE 2> $PYSIM_SMPPOTATOOL_LOG`
if [ $? -ne 0 ]; then
@@ -57,7 +57,7 @@
dump_logs
exit 1
fi
-
+ echo ""
echo "Got response from SMPP server:"
echo "Sent: $C_APDU"
echo "Received: $R_APDU"
@@ -68,16 +68,14 @@
exit 1
fi
echo "Response matches the expected response -- success!"
- echo ""
}
function start_smpp_server {
PCSC_READER=$1
-
- # Start the SMPP server
echo ""
echo "Starting SMPP server:"
+ # Start the SMPP server
COMMANDLINE="$PYSIM_SMPP2SIM -p $PCSC_READER --smpp-bind-port $PYSIM_SMPP2SIM_PORT --apdu-trace"
echo "Commandline: $COMMANDLINE"
$COMMANDLINE > $PYSIM_SMPP2SIM_LOG 2>&1 &
@@ -102,55 +100,117 @@
echo "SMPP server reachable (port=$PYSIM_SMPP2SIM_PORT)"
}
-function find_card_by_iccid {
- # Find reader number of the card
- ICCID=$1
+function stop_smpp_server {
+ echo ""
+ echo "Stopping SMPP server:"
+ kill $PYSIM_SMPP2SIM_PID
+ echo "SMPP server stopped (PID=$PYSIM_SMPP2SIM_PID)"
+ trap EXIT
+}
+function find_card_by_iccid_or_eid {
+ ICCID=$1
+ EID=$2
echo ""
echo "Searching for card:"
echo "ICCID: \"$ICCID\""
+ if [ -n "$EID" ]; then
+ echo "EID: \"$EID\""
+ fi
+ # Determine number of available PCSC readers
+ PCSC_READER_COUNT=`pcsc_scan -rn | wc -l`
+
+ # In case an EID is set, search for a card with that EID first
+ if [ -n "$EID" ]; then
+ for PCSC_READER in $(seq 0 $(($PCSC_READER_COUNT-1))); do
+ echo "probing card (eID) in reader $PCSC_READER ..."
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "get_eid" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep $EID > /dev/null
+ if [ $? -eq 0 ]; then
+ echo "Found card (eID) in reader $PCSC_READER"
+ return $PCSC_READER
+ fi
+ done
+ fi
+
+ # Search for card with the given ICCID
if [ -z "$ICCID" ]; then
echo "invalid ICCID, zero length ICCID is not allowed! -- abort"
exit 1
fi
-
- PCSC_READER_COUNT=`pcsc_scan -rn | wc -l`
for PCSC_READER in $(seq 0 $(($PCSC_READER_COUNT-1))); do
- echo "probing card in reader $PCSC_READER ..."
- EF_ICCID_DECODED=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e 'select EF.ICCID' -e 'read_binary_decoded --oneline' 2> /dev/null | tail -1`
- echo $EF_ICCID_DECODED | grep $ICCID > /dev/null
+ echo "probing card (ICCID) in reader $PCSC_READER ..."
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select EF.ICCID" -e "read_binary_decoded" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep $ICCID > /dev/null
if [ $? -eq 0 ]; then
- echo "Found card in reader $PCSC_READER"
+ echo "Found card (by ICCID) in reader $PCSC_READER"
return $PCSC_READER
fi
done
- echo "Card with ICCID \"$ICCID\" not found -- abort"
+ echo "Card not found -- abort"
exit 1
}
+function enable_profile {
+ PCSC_READER=$1
+ ICCID=$2
+ EID=$3
+ if [ -z "$EID" ]; then
+ # This is no eUICC, nothing to enable
+ return 0
+ fi
+
+ # Check if the profile is already enabled
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select EF.ICCID" -e "read_binary_decoded" 2> /dev/null | tail -3`
+ ICCID_ENABLED=`echo $RESULT_JSON | jq -r '.iccid'`
+ if [ $ICCID != $ICCID_ENABLED ]; then
+ # Disable the currentle enabled profile
+ echo ""
+ echo "Disabeling currently enabled profile:"
+ echo "ICCID: \"$ICCID\""
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "disable_profile --iccid $ICCID_ENABLED" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep "ok" > /dev/null
+ if [ $? -ne 0 ]; then
+ echo "unable to disable profile with \"$ICCID_ENABLED\""
+ exit 1
+ fi
+ echo "profile disabled"
+
+ # Enable the profile we intend to test with
+ echo ""
+ echo "Enabeling profile:"
+ echo "ICCID: \"$ICCID\""
+ RESULT_JSON=`$PYSIM_SHELL -p $PCSC_READER --noprompt -e "select ADF.ISD-R" -e "enable_profile --iccid $ICCID" 2> /dev/null | tail -3`
+ echo $RESULT_JSON | grep "ok\|profileNotInDisabledState" > /dev/null
+ if [ $? -ne 0 ]; then
+ echo "unable to enable profile with \"$ICCID\""
+ exit 1
+ fi
+ echo "profile enabled"
+ fi
+}
+
export PYTHONPATH=./
echo "pySim-smpp2sim_test - a test program to test pySim-smpp2sim.py"
echo "=============================================================="
-# TODO: At the moment we can only have one card and one testcase. This is
-# sufficient for now. We can extend this later as needed.
+TESTCASE_DIR=`dirname $0`
+for TEST_CONFIG_FILE in $TESTCASE_DIR/testcase_*.cfg ; do
+ echo ""
+ echo "running testcase: $TEST_CONFIG_FILE"
+ . $TEST_CONFIG_FILE
+ find_card_by_iccid_or_eid $ICCID $EID
+ PCSC_READER=$?
+ enable_profile $PCSC_READER $ICCID $EID
+ start_smpp_server $PCSC_READER
+ send_test_request $APDU "$EXPECTED_RESPONSE"
+ stop_smpp_server
+ echo ""
+ echo "testcase ok"
+ echo "--------------------------------------------------------------"
+done
-# Read test parameters from config from file
-TEST_CONFIG_FILE=${0%.*}.cfg
-echo "using config file: $TEST_CONFIG_FILE"
-if ! [ -e "$TEST_CONFIG_FILE" ]; then
- echo "test configuration file does not exist! -- abort"
- exit 1
-fi
-. $TEST_CONFIG_FILE
-
-# Execute testcase
-find_card_by_iccid $ICCID
-start_smpp_server $?
-send_test_request $TAR $APDU "$EXPECTED_RESPONSE"
-
-
-
+echo "done."
diff --git a/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
new file mode 100644
index 0000000..e056490
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_3des_cbc2_rfm.cfg
@@ -0,0 +1,17 @@
+# Preparation:
+# This testcase executes against a sysmoISIM-SJA5 card. For the testcase, the
+# key configuration on the card may be used as it is.
+
+# Card parameter:
+ICCID="8949440000001155314" # <-- change to the ICCID of your card!
+EID=""
+KIC='51D4FC44BCBA7C4589DFADA3297720AF' # <-- change to the KIC1 of your card!
+KID='0449699C472CE71E2FB7B56245EF7684' # <-- change to the KID1 of your card!
+KEY_INDEX=1
+ALGO_CRYPT=triple_des_cbc2
+ALGO_AUTH=triple_des_cbc2
+TAR='B00010'
+
+# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
+APDU='A0A40000027F20A0C0000016'
+EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
diff --git a/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
new file mode 100644
index 0000000..cfd0ef5
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_aes128_cbc_cmac_rfm.cfg
@@ -0,0 +1,19 @@
+# Preparation:
+# This testcase executes against a sysmoEUICC1-C2T, which is equipped with the
+# TS48V1-B-UNIQUE test profile from https://test.rsp.sysmocom.de/ (Activation
+# code: 1$smdpp.test.rsp.sysmocom.de$TS48V1-B-UNIQUE). This testprofile must be
+# present on the eUICC before this testcase can be executed.
+
+# Card parameter:
+ICCID="8949449999999990031"
+EID="89049044900000000000000000102355" # <-- change to the EID of your card!
+KIC='66778899aabbccdd1122334455eeff10'
+KID='112233445566778899aabbccddeeff10'
+KEY_INDEX=2
+ALGO_CRYPT=aes_cbc
+ALGO_AUTH=aes_cmac
+TAR='b00120'
+
+# Testcase: Send OTA-SMS that selects DF.ICCID and returns the select response
+APDU='00a40004022fe200C000001d'
+EXPECTED_RESPONSE='621b8202412183022fe2a503d001408a01058b032f06038002000a8800 9000'
\ No newline at end of file
diff --git a/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg b/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
new file mode 100644
index 0000000..0bffbbe
--- /dev/null
+++ b/tests/pySim-smpp2sim_test/testcase_aes256_cbc_cmac_rfm.cfg
@@ -0,0 +1,28 @@
+# Preparation:
+# This testcase executes against a sysmoISIM-SJA5 card. Since this card model is
+# shipped with a classic DES key configuration, it is necessary to provision
+# AES128 test keys before this testcase may be executed. The the following
+# pySim-shell command sequence may be used:
+#
+# verify_adm 34173960 # <-- change to the ADM key of your card!
+# select /DF.SYSTEM/EF.0348_KEY
+# update_record 10 fe03601111111111111111111111111111111111111111111111111111111111111111
+# update_record 11 fe03612222222222222222222222222222222222222222222222222222222222222222
+# update_record 12 fe03623333333333333333333333333333333333333333333333333333333333333333
+#
+# This overwrites one of the already existing 3DES SCP02 key (KVN 47) and replaces it
+# with an AES256 SCP80 key (KVN 3).
+
+# Card parameter:
+ICCID="8949440000001155314" # <-- change to the ICCID of your card!
+EID=""
+KIC='1111111111111111111111111111111111111111111111111111111111111111'
+KID='2222222222222222222222222222222222222222222222222222222222222222'
+KEY_INDEX=3
+ALGO_CRYPT=aes_cbc
+ALGO_AUTH=aes_cmac
+TAR='B00010'
+
+# Testcase: Send OTA-SMS that selects DF.GSM and returns the select response
+APDU='A0A40000027F20A0C0000016'
+EXPECTED_RESPONSE='0000ffff7f2002000000000009b106350400838a838a 9000'
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42189?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I1f10504f3a29a8c74a17991632d932819fecfa5a
Gerrit-Change-Number: 42189
Gerrit-PatchSet: 6
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu>
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/42237?usp=email )
Change subject: docs/smpp-ota-tool: Add documentation/tutorial
......................................................................
docs/smpp-ota-tool: Add documentation/tutorial
We already have documentation that explains how to run pySim-smpp2sim.
With smpp-ota-tool we now have a counterpart for pySim-smpp2sim, so
let's add documentation for this tool as well.
Related: SYS#7881
Change-Id: If0d18a263f5a6dc035b90f5c5c6a942d46bbba49
---
M docs/index.rst
A docs/smpp-ota-tool.rst
M docs/smpp2sim.rst
3 files changed, 182 insertions(+), 0 deletions(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/docs/index.rst b/docs/index.rst
index 92be830..a6ed7b9 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -48,6 +48,7 @@
sim-rest
suci-keytool
saip-tool
+ smpp-ota-tool
Indices and tables
diff --git a/docs/smpp-ota-tool.rst b/docs/smpp-ota-tool.rst
new file mode 100644
index 0000000..beb494a
--- /dev/null
+++ b/docs/smpp-ota-tool.rst
@@ -0,0 +1,179 @@
+smpp-ota-tool
+=============
+
+The `smpp-ota-tool` allows users to send OTA SMS messages containing APDU scripts (RFM, RAM) via an SMPP server. The
+intended audience are developers who want to test/evaluate the OTA SMS interface of a SIM/UICC/eUICC. `smpp-ota-tool`
+is intended to be used as a companion tool for :ref:`pySim-smpp2sim`, however it should be usable on any other SMPP
+server (such as a production SMSC of a live cellular network) as well.
+
+From the technical perspective `smpp-ota-tool` takes the role of an SMPP ESME. It takes care of the encoding, encryption
+and checksumming (signing) of the RFM/RAM OTA SMS and eventually submits it to the SMPP server. The program then waits
+for a response. The response is automatically parsed and printed on stdout. This makes the program also suitable to be
+called from shell scripts.
+
+.. note:: In the following we will we will refer to `SIM` as one of the following: `SIM`, `USIM`, `ISIM`, `UICC`,
+ `eUICC`, `eSIM`.
+
+Applying OTA keys
+~~~~~~~~~~~~~~~~~
+
+Depending on the `SIM` type you will receive one or more sets of keys which you can use to communicate with the `SIM`
+through a secure channel protocol. When using the OTA SMS method, the SCP80 protocol is used and it therefore crucial
+to use a keyset that is actually suitable for SCP80.
+
+A keyset usually consists of three keys:
+
+#. KIC: the key used for ciphering (encryption/decryption)
+#. KID: the key used to compute a cryptographic checksum (signing)
+#. KIK: the key used to encrypt/decrypt key material (key rotation, adding of new keys)
+
+From the transport security perspective, only KIC and KID are relevant. The KIK (also referenced as "Data Encryption
+Key", DEK) is only used when keys are rotated or new keys are added (see also ETSI TS 102 226, section 8.2.1.5).
+
+When the keyset is programmed into the security domain of the `SIM`, it is tied to a specific cryptographic algorithm
+(3DES, AES128 or AES256) and a so called Key Version Number (KVN). The term "Key Version Number" is misleading, since
+it is actually not a version number. It is a unique identifier of a certain keyset which also identifies for which
+secure channel protocol the keyset may be used. Keysets with a KVN from 1-15 (``0x01``-``0x0F``) are suitable for SCP80.
+This means that it is not only important to know just the KIC/KID/KIK keys. Also the related algorithms and the KVN
+numbers must be known.
+
+.. note:: SCP80 keysets typically start counting from 1 upwards. Typical configurations use a set of 3 keysets with
+ KVN numbers 1-3.
+
+Addressing an Application
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When communicating with a specific application on a `SIM` via SCP80, it is important to address that application with
+the correct parameters. The following two parameters must be known in advance:
+
+#. TAR: The Toolkit Application Reference (TAR) number is a three byte value that uniquely addresses an application
+ on the `SIM`. The exact values may vary (see also ETSI TS 101 220, Table D.1).
+#. MSL: The Minimum Security Level (MSL) is a bit-field that dictates which of the security measures encoded in the
+ SPI are mandatory (see also ETSI TS 102 225, section 5.1.1).
+
+A practical example
+~~~~~~~~~~~~~~~~~~~
+
+.. note:: This tutorial assumes that pySim-smpp2sim is running on the local machine with its default parameters.
+ See also :ref:`pySim-smpp2sim`.
+
+Let's assume that an OTA SMS shall be sent to the SIM RFM application of an sysmoISIM-SJA2. What we want to do is to
+select DF.GSM and to get the select response back.
+
+We have received the following key material from the `SIM` vendor:
+
+::
+
+ KIC1: F09C43EE1A0391665CC9F05AF4E0BD10
+ KID1: 01981F4A20999F62AF99988007BAF6CA
+ KIK1: 8F8AEE5CDCC5D361368BC45673D99195
+ KIC2: 01022916E945B656FDE03F806A105FA2
+ KID2: D326CB69F160333CC5BD1495D448EFD6
+ KIK2: 08037E0590DFE049D4975FFB8652F625
+ KIC3: 2B22824D0D27A3A1CEEC512B312082B4
+ KID3: F1697766925A11F4458295590137B672
+ KIK3: C7EE69B2C5A1C8E160DD36A38EB517B3
+
+Those are three keysets. The enumeration is directly equal to the KVN used. All three keysets are 3DES keys, which
+means triple_des_cbc2 is the correct algorithm to use.
+
+.. note:: The key set configuration can be confirmed by retrieving the key configuration using
+ `get_data key_information` from within an SCP02 session on ADF.ISD.
+
+In this example we intend to address the SIM RFM application on the `SIM`. Which according to the manual has TAR ``B00010``
+and MSL ``0x06``. When we hold ``0x06`` = ``0b00000110`` against the SPI coding chart (see also ETSI TS 102 225,
+section 5.1.1). We can deduct that Ciphering and Cryptographic Checksum are mandatory.
+
+.. note:: The MSL (see also ETSI TS 102 226, section 6.1) is assigned to an application by the `SIM` issuer. It is a
+ custom decision and may vary with different `SIM` types/profiles. In the case of sysmoISIM-SJS1/SJA2/SJA5 the
+ counter requirement has been waived to simplify lab/research type use. In productive environments, `SIM`
+ applications should ideally use an MSL that makes the counter mandatory.
+
+In order to select DF.GSM (``0x7F20``) and to retrieve the select response, two APDUs are needed. The first APDU is the
+select command ``A0A40000027F20`` and the second is the related get-response command ``A0C0000016``. Those APDUs will be
+concatenated and are sent in a single message. The message containing the concatenated APDUs works as a script that
+is received by the SIM RFM application and then executed. This method poses some limitations that have to be taken into
+account when making requests like this (see also ETSI TS 102 226, section 5).
+
+With this information we may now construct a commandline for `smpp-ota-tool.py`. We will pass the KVN as kid_idx and
+kic_idx (see also ETSI TS 102 225, Table 2, fields `KIc` and `KID`). Both index values should refer to the same
+keyset/KVN as keysets should not be mixed. (`smpp-ota-tool` still provides separate parameters anyway to allow testing
+with invalid keyset combinations)
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016
+ 2026-02-26 17:13:56 INFO Connecting to localhost:2775...
+ 2026-02-26 17:13:56 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:13:56 INFO SMS-TPDU sending: 02700000281506191515b00010da1d6cbbd0d11ce4330d844c7408340943e843f67a6d7b0674730881605fd62d...
+ 2026-02-26 17:13:56 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:13:56 INFO SMS-TPDU received: 027100002c12b000107ddf58d1780f771638b3975759f4296cf5c31efc87a16a1b61921426baa16da1b5ba1a9951d59a39
+ 2026-02-26 17:13:56 INFO SMS-TPDU decoded: (Container(rpl=44, rhl=18, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00\x00', pcntr=0, response_status=uEnumIntegerString.new(0, 'por_ok'), cc_rc=b'\x8f\xea\xf5.\xf4\x0e\xc2\x14', secured_data=b'\x02\x90\x00\x00\x00\xff\xff\x7f \x02\x00\x00\x00\x00\x00\t\xb1\x065\x04\x00\x83\x8a\x83\x8a'), Container(number_of_commands=2, last_status_word=u'9000', last_response_data=u'0000ffff7f2002000000000009b106350400838a838a'))
+ 2026-02-26 17:13:56 INFO R-APDU received: 0000ffff7f2002000000000009b106350400838a838a 9000
+ 0000ffff7f2002000000000009b106350400838a838a 9000
+ 2026-02-26 17:13:56 INFO Disconnecting...
+
+The result we see is the select response of DF.GSM and a status word indicating that the last command has been
+processed normally.
+
+As we can see, this mechanism now allows us to perform small administrative tasks remotely. We can read the contents of
+files remotely or make changes to files. Depending on the changes we make, there may be security issues arising from
+replay attacks. With the commandline above, the communication is encrypted and protected by a cryptographic checksum,
+so an adversary can neither read, nor alter the message. However, an adversary could still replay an intercepted
+message and the `SIM` would happily execute the contained APDUs again.
+
+To prevent this, we may include a replay protection counter within the message. In this case, the MSL indicates that a
+replay protection counter is not required. However, to extended the security of our messages, we may chose to use a
+counter anyway. In the following example, we will encode a counter value of 100. We will instruct the `SIM` to make sure
+that the value we send is higher than the counter value that is currently stored in the `SIM`.
+
+To add a replay connection counter we add the commandline arguments `--cntr-req` to set the counter requirement and
+`--cntr` to pass the counter value.
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016 --cntr-req counter_must_be_higher --cntr 100
+ 2026-02-26 17:16:39 INFO Connecting to localhost:2775...
+ 2026-02-26 17:16:39 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:16:39 INFO SMS-TPDU sending: 02700000281516191515b000103a4f599e94f2b5dcfbbda984761b7977df6514c57a580fb4844787c436d2eade...
+ 2026-02-26 17:16:39 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:16:39 INFO SMS-TPDU received: 027100002c12b0001049fb0315f6c6401b553867f412cefaf9355b38271178edb342a3bc9cc7e670cdc1f45eea6ffcbb39
+ 2026-02-26 17:16:39 INFO SMS-TPDU decoded: (Container(rpl=44, rhl=18, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00d', pcntr=0, response_status=uEnumIntegerString.new(0, 'por_ok'), cc_rc=b'\xa9/\xc7\xc9\x00"\xab5', secured_data=b'\x02\x90\x00\x00\x00\xff\xff\x7f \x02\x00\x00\x00\x00\x00\t\xb1\x065\x04\x00\x83\x8a\x83\x8a'), Container(number_of_commands=2, last_status_word=u'9000', last_response_data=u'0000ffff7f2002000000000009b106350400838a838a'))
+ 2026-02-26 17:16:39 INFO R-APDU received: 0000ffff7f2002000000000009b106350400838a838a 9000
+ 0000ffff7f2002000000000009b106350400838a838a 9000
+ 2026-02-26 17:16:39 INFO Disconnecting...
+
+The `SIM` has accepted the message. The message got processed and the `SIM` has set its internal to 100. As an experiment,
+we may try to re-use the counter value:
+
+::
+
+ $ PYTHONPATH=./ ./contrib/smpp-ota-tool.py --kic F09C43EE1A0391665CC9F05AF4E0BD10 --kid 01981F4A20999F62AF99988107BAF6CA --kid_idx 1 --kic_idx 1 --algo-crypt triple_des_cbc2 --algo-auth triple_des_cbc2 --tar B00010 --apdu A0A40000027F20 --apdu A0C0000016 --cntr-req counter_must_be_higher --cntr 100
+ 2026-02-26 17:16:43 INFO Connecting to localhost:2775...
+ 2026-02-26 17:16:43 INFO C-APDU sending: a0a40000027f20a0c0000016...
+ 2026-02-26 17:16:43 INFO SMS-TPDU sending: 02700000281516191515b000103a4f599e94f2b5dcfbbda984761b7977df6514c57a580fb4844787c436d2eade...
+ 2026-02-26 17:16:43 INFO SMS-TPDU sent, waiting for response...
+ 2026-02-26 17:16:43 INFO SMS-TPDU received: 027100000b0ab0001000000000000006
+ 2026-02-26 17:16:43 INFO SMS-TPDU decoded: (Container(rpl=11, rhl=10, tar=b'\xb0\x00\x10', cntr=b'\x00\x00\x00\x00\x00', pcntr=0, response_status=uEnumIntegerString.new(6, 'undefined_security_error'), cc_rc=b'', secured_data=b''), None)
+ Traceback (most recent call last):
+ File "/home/user/work/git_master/pysim/./contrib/smpp-ota-tool.py", line 238, in <module>
+ resp, sw = smpp_handler.transceive_apdu(apdu, opts.src_addr, opts.dest_addr, opts.timeout)
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ File "/home/user/work/git_master/pysim/./contrib/smpp-ota-tool.py", line 162, in transceive_apdu
+ raise ValueError("Response does not contain any last_response_data, no R-APDU received!")
+ ValueError: Response does not contain any last_response_data, no R-APDU received!
+ 2026-02-26 17:16:43 INFO Disconnecting...
+
+As we can see, the `SIM` has rejected the message with an `undefined_security_error`. The replay-protection-counter
+ensures that a message can only be sent once.
+
+.. note:: The replay-protection-counter is implemented as a 5 byte integer value (see also ETSI TS 102 225, Table 3).
+ When the counter has reached its maximum, it will not overflow nor can it be reset.
+
+smpp-ota-tool syntax
+~~~~~~~~~~~~~~~~~~~~
+
+.. argparse::
+ :module: contrib.smpp-ota-tool
+ :func: option_parser
+ :prog: contrib/smpp-ota-tool.py
diff --git a/docs/smpp2sim.rst b/docs/smpp2sim.rst
index cd86900..0ae64e7 100644
--- a/docs/smpp2sim.rst
+++ b/docs/smpp2sim.rst
@@ -55,3 +55,5 @@
SMSPPDownload(DeviceIdentities({'source_dev_id': 'network', 'dest_dev_id': 'uicc'}),Address({'ton_npi': 0, 'call_number': '0123456'}),SMS_TPDU({'tpdu': '400290217ff6227052000000002d02700000281516191212b0000127fa28a5bac69d3c5e9df2c7155dfdde449c826b236215566530787b30e8be5d'}))
INFO root: ENVELOPE: d147820283818604001032548b3b400290217ff6227052000000002d02700000281516191212b0000127fa28a5bac69d3c5e9df2c7155dfdde449c826b236215566530787b30e8be5d
INFO root: SW 9000: 027100002412b000019a551bb7c28183652de0ace6170d0e563c5e949a3ba56747fe4c1dbbef16642c
+
+.. note:: for sending OTA SMS messages :ref:`smpp-ota-tool` may be used.
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/42237?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: If0d18a263f5a6dc035b90f5c5c6a942d46bbba49
Gerrit-Change-Number: 42237
Gerrit-PatchSet: 4
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>