laforge has uploaded this change for review. (
https://gerrit.osmocom.org/c/pysim/+/35461?usp=email )
Change subject: HACK/WIP: some work on ES9+ / SM-DP crypto
......................................................................
HACK/WIP: some work on ES9+ / SM-DP crypto
Change-Id: I6232847432dc6920cd2bd08c84d7099c29ca1c11
---
A DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der
A DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der
A DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der
A DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der
A DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem
A DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem
A DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem
A DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem
A DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem
A DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem
A DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem
A DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem
A DPauth/data_sig.der
A DPtls/CERT_S_SM_DP2_TLS.csr.cnf
A DPtls/CERT_S_SM_DP2_TLS.der
A DPtls/CERT_S_SM_DP2_TLS.ext.cnf
A DPtls/CERT_S_SM_DP4_TLS.csr.cnf
A DPtls/CERT_S_SM_DP4_TLS.der
A DPtls/CERT_S_SM_DP4_TLS.ext.cnf
A DPtls/CERT_S_SM_DP8_TLS.csr.cnf
A DPtls/CERT_S_SM_DP8_TLS.der
A DPtls/CERT_S_SM_DP8_TLS.ext.cnf
A DPtls/CERT_S_SM_DP_TLS.csr.cnf
A DPtls/CERT_S_SM_DP_TLS.ext.cnf
A DPtls/CERT_S_SM_DP_TLS_BRP.der
A DPtls/CERT_S_SM_DP_TLS_NIST.der
A DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der
A DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der
A DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der
A DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der
A DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der
A DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der
A DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der
A DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der
A DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der
A DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der
A DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der
A DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der
A DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der
A DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der
A DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der
A DPtls/PK_S_SM_DP2_TLS_NIST.pem
A DPtls/PK_S_SM_DP4_TLS.pem
A DPtls/PK_S_SM_DP8_TLS.pem
A DPtls/PK_S_SM_DP_TLS_BRP.pem
A DPtls/PK_S_SM_DP_TLS_NIST.pem
A DPtls/SK_S_SM_DP2_TLS_NIST.pem
A DPtls/SK_S_SM_DP4_TLS.pem
A DPtls/SK_S_SM_DP8_TLS.pem
A DPtls/SK_S_SM_DP_TLS_BRP.pem
A DPtls/SK_S_SM_DP_TLS_NIST.pem
A es9p_sig.py
A pySim/smdp_crypto.py
A server.pem
A sm-dp-http.py
55 files changed, 804 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/61/35461/1
diff --git a/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der
b/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der
new file mode 100644
index 0000000..a3caae5
--- /dev/null
+++ b/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der
Binary files differ
diff --git a/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der
b/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der
new file mode 100644
index 0000000..81715bb
--- /dev/null
+++ b/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der
Binary files differ
diff --git a/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der
b/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der
new file mode 100644
index 0000000..45c043c
--- /dev/null
+++ b/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der
Binary files differ
diff --git a/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der
b/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der
new file mode 100644
index 0000000..914b8a1
--- /dev/null
+++ b/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der
Binary files differ
diff --git a/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem b/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem
new file mode 100644
index 0000000..e37c621
--- /dev/null
+++ b/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABC7uB8ltAFvlGV95rR2tzR03jKMJ
+XkT3LupBDwjHVhIskGPJZbf8hSnAyk6bT2WWnCg8ZWNkV4dxGPbRFy1qI2U=
+-----END PUBLIC KEY-----
diff --git a/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem
b/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem
new file mode 100644
index 0000000..63fc92d
--- /dev/null
+++ b/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKy6bRdNRwJr0DpFDg6GQOEfyYH3m
+DverJcQOA/jbtlCOFFdQjCvgAXNH7Pob+fd159B+gF5S4ZiLe1hacRGuMw==
+-----END PUBLIC KEY-----
diff --git a/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem b/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem
new file mode 100644
index 0000000..cbd8ccc
--- /dev/null
+++ b/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABCVdfa8A74Qddvp6Y9Y+s/5sn3BJ
+LTgZI/j4vXsk88WtFo6+OwndgPKef/0kpNG+dH+DI+RykoOW3engFRzquhg=
+-----END PUBLIC KEY-----
diff --git a/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem b/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem
new file mode 100644
index 0000000..8424bb4
--- /dev/null
+++ b/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETf7U9GlHkb8Wlc6gMHo1tBgBlpU4
+e7dbfSRHtrUgnwRFrk5eUhzROIjXX+B8hYAiKuINuqwdd812MEmTQhvXOQ==
+-----END PUBLIC KEY-----
diff --git a/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem b/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem
new file mode 100644
index 0000000..dc20882
--- /dev/null
+++ b/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgkrJAMDAggBAQc=
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHgCAQEEIAwXNVwBHQ/o19rdY/GXhc9sUcvNRmroi+j4G8EFiEb2oAsGCSskAwMC
+CAEBB6FEA0IABC7uB8ltAFvlGV95rR2tzR03jKMJXkT3LupBDwjHVhIskGPJZbf8
+hSnAyk6bT2WWnCg8ZWNkV4dxGPbRFy1qI2U=
+-----END EC PRIVATE KEY-----
diff --git a/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem
b/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem
new file mode 100644
index 0000000..0b19301
--- /dev/null
+++ b/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIJwyoJXUiELZ/6QE9xJRKqLFQloaJjhqtqFF1YEeA5FBoAoGCCqGSM49
+AwEHoUQDQgAEKy6bRdNRwJr0DpFDg6GQOEfyYH3mDverJcQOA/jbtlCOFFdQjCvg
+AXNH7Pob+fd159B+gF5S4ZiLe1hacRGuMw==
+-----END EC PRIVATE KEY-----
diff --git a/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem b/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem
new file mode 100644
index 0000000..6e9d064
--- /dev/null
+++ b/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgkrJAMDAggBAQc=
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHgCAQEEIJP7M9BYTzSbB/i10q+T18PjVLNJo7kTUC5qvAcOTUkpoAsGCSskAwMC
+CAEBB6FEA0IABCVdfa8A74Qddvp6Y9Y+s/5sn3BJLTgZI/j4vXsk88WtFo6+Ownd
+gPKef/0kpNG+dH+DI+RykoOW3engFRzquhg=
+-----END EC PRIVATE KEY-----
diff --git a/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem b/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem
new file mode 100644
index 0000000..35df74b
--- /dev/null
+++ b/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAp8wcJE5gxSzVt4B6uMNgwmUkYBUH3KvF3VmLWmFtXVoAoGCCqGSM49
+AwEHoUQDQgAETf7U9GlHkb8Wlc6gMHo1tBgBlpU4e7dbfSRHtrUgnwRFrk5eUhzR
+OIjXX+B8hYAiKuINuqwdd812MEmTQhvXOQ==
+-----END EC PRIVATE KEY-----
diff --git a/DPauth/data_sig.der b/DPauth/data_sig.der
new file mode 100644
index 0000000..7f44ce2
--- /dev/null
+++ b/DPauth/data_sig.der
@@ -0,0 +1 @@
+0D AL¶þV¿eRÌÍìAHÊt£×ôͺnìE<Nåû R¤~&Àk\þ~ ÉRlÜÛ°¥7ì¶NmWø
\ No newline at end of file
diff --git a/DPtls/CERT_S_SM_DP2_TLS.csr.cnf b/DPtls/CERT_S_SM_DP2_TLS.csr.cnf
new file mode 100644
index 0000000..8ed5b2b
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP2_TLS.csr.cnf
@@ -0,0 +1,10 @@
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+O = ACME
+
+# shall be aligned with SGP.23 value #TEST_DP_ADDRESS2
+CN =
testsmdpplus2.example.com
+
diff --git a/DPtls/CERT_S_SM_DP2_TLS.der b/DPtls/CERT_S_SM_DP2_TLS.der
new file mode 100644
index 0000000..be20b34
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP2_TLS.der
Binary files differ
diff --git a/DPtls/CERT_S_SM_DP2_TLS.ext.cnf b/DPtls/CERT_S_SM_DP2_TLS.ext.cnf
new file mode 100644
index 0000000..d224daf
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP2_TLS.ext.cnf
@@ -0,0 +1,14 @@
+######################################################################################################################################################################
+# Extensions for a DPTLS
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, serverAuth, clientAuth
+certificatePolicies = 2.23.146.1.2.1.3
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+
+# RID shall be aligend with SGP.23 value SM-DP+OID2
+# DNS name shall be aligned with SGP.23 value #TEST_DP_ADDRESS2
+subjectAltName =
DNS:testsmdpplus2.example.com, RID:2.999.12
+
+crlDistributionPoints=URI:http://ci.test.example.com/CRL-A.crl,
URI:http://ci.test.example.com/CRL-B.crl
+
diff --git a/DPtls/CERT_S_SM_DP4_TLS.csr.cnf b/DPtls/CERT_S_SM_DP4_TLS.csr.cnf
new file mode 100644
index 0000000..abaa1da
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP4_TLS.csr.cnf
@@ -0,0 +1,10 @@
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+O = ACME
+
+# shall be aligned with SGP.23 value #TEST_DP_ADDRESS4
+CN =
testsmdpplus4.example.com
+
diff --git a/DPtls/CERT_S_SM_DP4_TLS.der b/DPtls/CERT_S_SM_DP4_TLS.der
new file mode 100644
index 0000000..07b4c85
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP4_TLS.der
Binary files differ
diff --git a/DPtls/CERT_S_SM_DP4_TLS.ext.cnf b/DPtls/CERT_S_SM_DP4_TLS.ext.cnf
new file mode 100644
index 0000000..31f6463
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP4_TLS.ext.cnf
@@ -0,0 +1,14 @@
+######################################################################################################################################################################
+# Extensions for a DPTLS
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, serverAuth, clientAuth
+certificatePolicies = 2.23.146.1.2.1.3
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+
+# RID shall be aligend with SGP.23 value SM-DP+OID4
+# DNS name shall be aligned with SGP.23 value #TEST_DP_ADDRESS4
+subjectAltName =
DNS:testsmdpplus4.example.com, RID:2.999.14
+
+crlDistributionPoints=URI:http://ci.test.example.com/CRL-A.crl,
URI:http://ci.test.example.com/CRL-B.crl
+
diff --git a/DPtls/CERT_S_SM_DP8_TLS.csr.cnf b/DPtls/CERT_S_SM_DP8_TLS.csr.cnf
new file mode 100644
index 0000000..39ebdfb
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP8_TLS.csr.cnf
@@ -0,0 +1,10 @@
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+O = ACME
+
+# shall be aligned with SGP.23 value #TEST_DP_ADDRESS8
+CN =
testsmdpplus8.example.com
+
diff --git a/DPtls/CERT_S_SM_DP8_TLS.der b/DPtls/CERT_S_SM_DP8_TLS.der
new file mode 100644
index 0000000..3b45b14
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP8_TLS.der
Binary files differ
diff --git a/DPtls/CERT_S_SM_DP8_TLS.ext.cnf b/DPtls/CERT_S_SM_DP8_TLS.ext.cnf
new file mode 100644
index 0000000..cc88f83
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP8_TLS.ext.cnf
@@ -0,0 +1,14 @@
+######################################################################################################################################################################
+# Extensions for a DPTLS
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, serverAuth, clientAuth
+certificatePolicies = 2.23.146.1.2.1.3
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+
+# RID shall be aligend with SGP.23 value SM-DP+OID8
+# DNS name shall be aligned with SGP.23 value #TEST_DP_ADDRESS8
+subjectAltName =
DNS:testsmdpplus8.example.com, RID:2.999.18
+
+crlDistributionPoints=URI:http://ci.test.example.com/CRL-A.crl,
URI:http://ci.test.example.com/CRL-B.crl
+
diff --git a/DPtls/CERT_S_SM_DP_TLS.csr.cnf b/DPtls/CERT_S_SM_DP_TLS.csr.cnf
new file mode 100644
index 0000000..d9b785c
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP_TLS.csr.cnf
@@ -0,0 +1,10 @@
+[ req ]
+prompt = no
+distinguished_name = req_distinguished_name
+
+[ req_distinguished_name ]
+O = ACME
+
+# shall be aligned with SGP.23 value #TEST_DP_ADDRESS1
+CN =
testsmdpplus1.example.com
+
diff --git a/DPtls/CERT_S_SM_DP_TLS.ext.cnf b/DPtls/CERT_S_SM_DP_TLS.ext.cnf
new file mode 100644
index 0000000..f80caf6
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP_TLS.ext.cnf
@@ -0,0 +1,14 @@
+######################################################################################################################################################################
+# Extensions for a DPTLS
+keyUsage = critical, digitalSignature
+extendedKeyUsage = critical, serverAuth, clientAuth
+certificatePolicies = 2.23.146.1.2.1.3
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer
+
+# RID shall be aligend with SGP.23 value SM-DP+OID
+# DNS name shall be aligned with SGP.23 value #TEST_DP_ADDRESS1
+subjectAltName =
DNS:testsmdpplus1.example.com, RID:2.999.10
+
+crlDistributionPoints=URI:http://ci.test.example.com/CRL-A.crl,
URI:http://ci.test.example.com/CRL-B.crl
+
diff --git a/DPtls/CERT_S_SM_DP_TLS_BRP.der b/DPtls/CERT_S_SM_DP_TLS_BRP.der
new file mode 100644
index 0000000..dc730f0
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP_TLS_BRP.der
Binary files differ
diff --git a/DPtls/CERT_S_SM_DP_TLS_NIST.der b/DPtls/CERT_S_SM_DP_TLS_NIST.der
new file mode 100644
index 0000000..0cb9ba7
--- /dev/null
+++ b/DPtls/CERT_S_SM_DP_TLS_NIST.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der
new file mode 100644
index 0000000..4f91532
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der
new file mode 100644
index 0000000..70820fa
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der
new file mode 100644
index 0000000..33cc6fb
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der
b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der
new file mode 100644
index 0000000..5d0ae30
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der
b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der
new file mode 100644
index 0000000..38927b1
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der
new file mode 100644
index 0000000..32909ce
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der
new file mode 100644
index 0000000..ea11075
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der
new file mode 100644
index 0000000..93a0cc0
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der
b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der
new file mode 100644
index 0000000..3d00317
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der
b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der
new file mode 100644
index 0000000..179c37b
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der
new file mode 100644
index 0000000..da5516c
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der
new file mode 100644
index 0000000..b1c222c
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der
b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der
new file mode 100644
index 0000000..638e4a1
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der
b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der
new file mode 100644
index 0000000..6746cbb
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der
Binary files differ
diff --git a/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der
b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der
new file mode 100644
index 0000000..6977bd3
--- /dev/null
+++ b/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der
Binary files differ
diff --git a/DPtls/PK_S_SM_DP2_TLS_NIST.pem b/DPtls/PK_S_SM_DP2_TLS_NIST.pem
new file mode 100644
index 0000000..702bcf7
--- /dev/null
+++ b/DPtls/PK_S_SM_DP2_TLS_NIST.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGtkADHVON2E+dQ+3v3NC/tULwHJS
+7YRla0XW9wh4lQip/+CWFyOvEe/I3aaaafK1GIuzEhOCCrLdHvWALo/Utg==
+-----END PUBLIC KEY-----
diff --git a/DPtls/PK_S_SM_DP4_TLS.pem b/DPtls/PK_S_SM_DP4_TLS.pem
new file mode 100644
index 0000000..9c165c7
--- /dev/null
+++ b/DPtls/PK_S_SM_DP4_TLS.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOtvoTSOoGvY7otiZg2y7aKdiVrMN
+cCYwPcNrwV32ETbE++cCAbTFpm49rGsrO5V6mbtOdBAD6L90LwgTAqp9pg==
+-----END PUBLIC KEY-----
diff --git a/DPtls/PK_S_SM_DP8_TLS.pem b/DPtls/PK_S_SM_DP8_TLS.pem
new file mode 100644
index 0000000..0ff4586
--- /dev/null
+++ b/DPtls/PK_S_SM_DP8_TLS.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzkExGPpkmW7Yspv8rIUzg+ZdPyKh
+meeWa/QGmmlYOSvlOdAA6lGlSIsQh9brR8ABhG0eaH7EkOgagJZJQgxSaw==
+-----END PUBLIC KEY-----
diff --git a/DPtls/PK_S_SM_DP_TLS_BRP.pem b/DPtls/PK_S_SM_DP_TLS_BRP.pem
new file mode 100644
index 0000000..8fd826f
--- /dev/null
+++ b/DPtls/PK_S_SM_DP_TLS_BRP.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABEwizNgsjQIh+dhUO3LhB7zJ/ZBU
+1mx1wOt0p73nMOdhjvZbJwteguQ6eW+N7guvivvrilNiU3oC/WXHnkEZa7U=
+-----END PUBLIC KEY-----
diff --git a/DPtls/PK_S_SM_DP_TLS_NIST.pem b/DPtls/PK_S_SM_DP_TLS_NIST.pem
new file mode 100644
index 0000000..15ea8ea
--- /dev/null
+++ b/DPtls/PK_S_SM_DP_TLS_NIST.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKCQwdc6O/R+uZ2g5QH2ybkzLQ3CU
+YhybOWEz8bJLtQG4/k6yTT4NOS8lP28blGJws8opLjTbb3qHs6X2rJRfCA==
+-----END PUBLIC KEY-----
diff --git a/DPtls/SK_S_SM_DP2_TLS_NIST.pem b/DPtls/SK_S_SM_DP2_TLS_NIST.pem
new file mode 100644
index 0000000..b25606d
--- /dev/null
+++ b/DPtls/SK_S_SM_DP2_TLS_NIST.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIE5lYcZAiPZpkHrb45SxGoQkLgM6gqiEAjFjbckbTuP1oAoGCCqGSM49
+AwEHoUQDQgAEGtkADHVON2E+dQ+3v3NC/tULwHJS7YRla0XW9wh4lQip/+CWFyOv
+Ee/I3aaaafK1GIuzEhOCCrLdHvWALo/Utg==
+-----END EC PRIVATE KEY-----
diff --git a/DPtls/SK_S_SM_DP4_TLS.pem b/DPtls/SK_S_SM_DP4_TLS.pem
new file mode 100644
index 0000000..32bdfde
--- /dev/null
+++ b/DPtls/SK_S_SM_DP4_TLS.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPJlnS9Sj0sRN0DVig0q8+srSOEiwrYKavb8lq2Gvm+koAoGCCqGSM49
+AwEHoUQDQgAEOtvoTSOoGvY7otiZg2y7aKdiVrMNcCYwPcNrwV32ETbE++cCAbTF
+pm49rGsrO5V6mbtOdBAD6L90LwgTAqp9pg==
+-----END EC PRIVATE KEY-----
diff --git a/DPtls/SK_S_SM_DP8_TLS.pem b/DPtls/SK_S_SM_DP8_TLS.pem
new file mode 100644
index 0000000..51ca168
--- /dev/null
+++ b/DPtls/SK_S_SM_DP8_TLS.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIP9uSlCbrds4EIgxwjzMLUQwevKB6SWWf4zfHZVUoCiNoAoGCCqGSM49
+AwEHoUQDQgAEzkExGPpkmW7Yspv8rIUzg+ZdPyKhmeeWa/QGmmlYOSvlOdAA6lGl
+SIsQh9brR8ABhG0eaH7EkOgagJZJQgxSaw==
+-----END EC PRIVATE KEY-----
diff --git a/DPtls/SK_S_SM_DP_TLS_BRP.pem b/DPtls/SK_S_SM_DP_TLS_BRP.pem
new file mode 100644
index 0000000..6ad37b0
--- /dev/null
+++ b/DPtls/SK_S_SM_DP_TLS_BRP.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgkrJAMDAggBAQc=
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHgCAQEEID9nFSgCs/TH+uZ5WFX2glQeReNe//TooFVloPGRKnguoAsGCSskAwMC
+CAEBB6FEA0IABEwizNgsjQIh+dhUO3LhB7zJ/ZBU1mx1wOt0p73nMOdhjvZbJwte
+guQ6eW+N7guvivvrilNiU3oC/WXHnkEZa7U=
+-----END EC PRIVATE KEY-----
diff --git a/DPtls/SK_S_SM_DP_TLS_NIST.pem b/DPtls/SK_S_SM_DP_TLS_NIST.pem
new file mode 100644
index 0000000..c1329f9
--- /dev/null
+++ b/DPtls/SK_S_SM_DP_TLS_NIST.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIKA+fORVBHS+pLeoc5nOWoyfZhtoD5QBOf/4Tp3sak2MoAoGCCqGSM49
+AwEHoUQDQgAEKCQwdc6O/R+uZ2g5QH2ybkzLQ3CUYhybOWEz8bJLtQG4/k6yTT4N
+OS8lP28blGJws8opLjTbb3qHs6X2rJRfCA==
+-----END EC PRIVATE KEY-----
diff --git a/es9p_sig.py b/es9p_sig.py
new file mode 100755
index 0000000..fc08a9f
--- /dev/null
+++ b/es9p_sig.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+
+from pySim.utils import b2h, h2b
+from pprint import pprint as pp
+
+from cryptography.hazmat.primitives.serialization import load_pem_private_key
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.x509 import load_pem_x509_certificate, load_der_x509_certificate
+from base64 import b64decode
+
+with open('server.pem', 'rb') as f:
+ pem_bytes = f.read()
+
+#cert = load_pem_x509_certificate(pem_bytes)
+#print(cert)
+#key = load_pem_private_key(pem_bytes, None)
+#print(key)
+
+# from an actual exchange between Comprion test eUICC + lpac against rsp.esim.me:8083
+#
{"type":"progress","payload":{"code":0,"message":"es9p_initiate_authentication","data":null}}
+# HTTP Req
https://rsp.esim.me:8083/gsma/rsp2/es9plus/initiateAuthentication:
{"smdpAddress":"rsp.esim.me:8083","euiccChallenge":"cRHkgblvUbp7uM+hwM8p7Q==","euiccInfo1":"vyBhggMCAgCpLAQUwLxwujaSnUO0Z/9XVwUw5Xq4/NgEFPVBcr35ipXWXL64ijihwR2ACoXDqiwEFMC8cLo2kp1DtGf/V1cFMOV6uPzYBBT1QXK9+YqV1ly+uIo4ocEdgAqFww=="}
+euicc_challenge = b64decode('cRHkgblvUbp7uM+hwM8p7Q==')
+euicc_info1 =
b64decode("vyBhggMCAgCpLAQUwLxwujaSnUO0Z/9XVwUw5Xq4/NgEFPVBcr35ipXWXL64ijihwR2ACoXDqiwEFMC8cLo2kp1DtGf/V1cFMOV6uPzYBBT1QXK9+YqV1ly+uIo4ocEdgAqFww==")
+# HTTP Resp:
{"header":{"functionExecutionStatus":{"status":"Executed-Success"}},"serverSigned1":"MEiAEF7KJ2yimkyhlcxrsBiHaCKBEHER5IG5b1G6e7jPocDPKe2DEHJzcC5lc2ltLm1lOjgwODOEEAvjnivyXEiliHwazCzm9x4=","euiccCiPKIdToBeUsed":"BBT1QXK9+YqV1ly+uIo4ocEdgAqFww==","serverSignature1":"XzdAtrqULn5f\/AwhetyKdDLdORLx9Hzo\/bfV4scgA8J4exhkasTC\/xZZmZ331OQsdJuq7Fpqh3+gI7uI0SE2BKVBvA==","serverCertificate":"MIICYDCCAgWgAwIBAgICAQAwCgYIKoZIzj0EAwIwSTELMAkGA1UEBhMCSVQxEDAOBgNVBAoMB1JTUFRFU1QxETAPBgNVBAsMCFRFU1RDRVJUMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kwHhcNMTgwMzI4MDAwMDAwWhcNMjEwMzI3MDAwMDAwWjBMMScwJQYDVQQDDB5OWFAgVGVzdCBTTS1EUCsgQXV0aGVudGljYXRpb24xFDASBgNVBAoMC05YUCBBdXN0cmlhMQswCQYDVQQGEwJBVDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPQ+vACwEgNEUzAYXNszI19AOQOAuPgAesSbf7CEzdRQ8AtH6n1ZivF9sYBsaNm6qodzZHjlPgE3WzcMQN5pCw+jgdkwgdYwHQYDVR0OBBYEFJbWoxNJ9dzzl4TKofi3hBWqFQwjMB8GA1UdIwQYMBaAFPVBcr35ipXWXL64ijihwR2ACoXDMA4GA1UdDwEB\/wQEAwIHgDAXBgNVHSABAf8EDTALMAkGB2eBEgECAQQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUEuY3JsMCegJaAjhiFodHRwOi8vY2kudGVzdC5nc21hLmNvbS9DUkwtQi5jcmwwDgYDVR0RBAcwBYgDiDcKMAoGCCqGSM49BAMCA0kAMEYCIQDIkDnIR8wmryRs5A98C3sqQ8Dq5pjD5bkZs78VhSbLUAIhAOP5S+QXJDyt9gLkhoR1v1i\/gyojU0v\/XibSOO6JNn50","transactionId":"5ECA276CA29A4CA195CC6BB018876822"}
+server_signed1 =
b64decode("MEiAEF7KJ2yimkyhlcxrsBiHaCKBEHER5IG5b1G6e7jPocDPKe2DEHJzcC5lc2ltLm1lOjgwODOEEAvjnivyXEiliHwazCzm9x4=")
+euicc_ci_pikd_to_be_used = b64decode('BBT1QXK9+YqV1ly+uIo4ocEdgAqFww==')
+server_signature =
b64decode("XzdAtrqULn5f\/AwhetyKdDLdORLx9Hzo\/bfV4scgA8J4exhkasTC\/xZZmZ331OQsdJuq7Fpqh3+gI7uI0SE2BKVBvA==")
+server_certificate =
b64decode("MIICYDCCAgWgAwIBAgICAQAwCgYIKoZIzj0EAwIwSTELMAkGA1UEBhMCSVQxEDAOBgNVBAoMB1JTUFRFU1QxETAPBgNVBAsMCFRFU1RDRVJUMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kwHhcNMTgwMzI4MDAwMDAwWhcNMjEwMzI3MDAwMDAwWjBMMScwJQYDVQQDDB5OWFAgVGVzdCBTTS1EUCsgQXV0aGVudGljYXRpb24xFDASBgNVBAoMC05YUCBBdXN0cmlhMQswCQYDVQQGEwJBVDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPQ+vACwEgNEUzAYXNszI19AOQOAuPgAesSbf7CEzdRQ8AtH6n1ZivF9sYBsaNm6qodzZHjlPgE3WzcMQN5pCw+jgdkwgdYwHQYDVR0OBBYEFJbWoxNJ9dzzl4TKofi3hBWqFQwjMB8GA1UdIwQYMBaAFPVBcr35ipXWXL64ijihwR2ACoXDMA4GA1UdDwEB\/wQEAwIHgDAXBgNVHSABAf8EDTALMAkGB2eBEgECAQQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUEuY3JsMCegJaAjhiFodHRwOi8vY2kudGVzdC5nc21hLmNvbS9DUkwtQi5jcmwwDgYDVR0RBAcwBYgDiDcKMAoGCCqGSM49BAMCA0kAMEYCIQDIkDnIR8wmryRs5A98C3sqQ8Dq5pjD5bkZs78VhSbLUAIhAOP5S+QXJDyt9gLkhoR1v1i\/gyojU0v\/XibSOO6JNn50")
+with open('server_cert.der','wb') as f:
+ f.write(server_certificate)
+with open('data_sig.bin','wb') as f:
+ f.write(server_signature)
+with open('data.bin','wb') as f:
+ f.write(server_signed1)
+
+#
{"type":"progress","payload":{"code":0,"message":"es10b_authenticate_server","data":null}}
+server_cert = load_der_x509_certificate(server_certificate)
+print("Server certificate")
+pp(server_cert)
+pp(server_cert.issuer)
+pp(server_cert.subject)
+pp(server_cert.signature_algorithm_oid)
+pp(server_cert.extensions)
+pp(b2h(euicc_ci_pikd_to_be_used))
+pkey = server_cert.public_key()
+print("server_signed1: %s" % b2h(server_signed1))
+print("server_signature: %s" % b2h(server_signature))
+# convert ECDSA signature from "BSI TS 03111 wrapped in TLV" into more commonly
used DER format
+r = server_signature[3:3+32]
+s = server_signature[3+32:3+32+32]
+print("r: %s" % b2h(r))
+print("s: %s" % b2h(s))
+server_signature_der = encode_dss_signature(int.from_bytes(r), int.from_bytes(s))
+print("server_signature_der: %s" % b2h(server_signature_der))
+with open('data_sig.der','wb') as f:
+ f.write(server_signature_der)
+pkey.verify(server_signature_der, server_signed1, ec.ECDSA(hashes.SHA256()))
+
+#sys.exit(0)
+
+print()
+#
{"type":"progress","payload":{"code":0,"message":"es9p_authenticate_client","data":null}}
+# HTTP Req
https://rsp.esim.me:8083/gsma/rsp2/es9plus/authenticateClient:
{"transactionId":"5ECA276CA29A4CA195CC6BB018876822","authenticateServerResponse":"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"}
+authenticate_server_resp =
b64decode("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")
+# HTTP Resp:
{"smdpSigned2":"MBWAEF7KJ2yimkyhlcxrsBiHaCIBAf8=","smdpSignature2":"XzdAlSZBMgwHOMrxZkmFrZKf5HPDc2+4cbDbik31VW2YIPb4kp+uLN8OVGuJeQZS+XkvDfTNJnYkphv9rC+K34kueQ==","profileMetadata":"vyU2WgqYlFGIKCAQEACCkQZUZVZpLTKSDVRlbGNvIFZpbGxhZ2WVAQK2DjAMgAIHgIEGQUJDREVG","smdpCertificate":"MIICYTCCAgagAwIBAgICAQEwCgYIKoZIzj0EAwIwSTELMAkGA1UEBhMCSVQxEDAOBgNVBAoMB1JTUFRFU1QxETAPBgNVBAsMCFRFU1RDRVJUMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kwHhcNMTgwMzI4MDAwMDAwWhcNMTMwMzI3MDAwMDAwWjBNMSgwJgYDVQQDDB9OWFAgVGVzdCBTTS1EUCsgUHJvZmlsZSBCaW5kaW5nMRQwEgYDVQQKDAtOWFAgQXVzdHJpYTELMAkGA1UEBhMCQVQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR6J+\/982zA4p\/2wYxdP9qbhbMf9w1M6CEc\/0Gw6dXNn3gMG+wy7vqAsf0mx5KkKlQdEf2kTvelNvN85p1ZiPdWo4HZMIHWMB0GA1UdDgQWBBR3DJnk7lhra7KKQyoQROJXe40QezAfBgNVHSMEGDAWgBT1QXK9+YqV1ly+uIo4ocEdgAqFwzAOBgNVHQ8BAf8EBAMCB4AwFwYDVR0gAQH\/BA0wCzAJBgdngRIBAgEFMFsGA1UdHwRUMFIwJ6AloCOGIWh0dHA6Ly9jaS50ZXN0LmdzbWEuY29tL0NSTC1BLmNybDAnoCWgI4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUIuY3JsMA4GA1UdEQQHMAWIA4g3CjAKBggqhkjOPQQDAgNJADBGAiEAmrnxGnTKBZVIbLM+1vDjhg9PNVZhVVl7r2KJWNFw2H0CIQDNtrIB8LKhsUgFXuFxhCXYEnGH7h0aW\/9Je04k5nd\/tw==","header":{"functionExecutionStatus":{"status":"Executed-Success"}},"transactionId":"5ECA276CA29A4CA195CC6BB018876822"}
+smdp_signed2 = b64decode("MBWAEF7KJ2yimkyhlcxrsBiHaCIBAf8=")
+smdp_signature2 =
b64decode("XzdAlSZBMgwHOMrxZkmFrZKf5HPDc2+4cbDbik31VW2YIPb4kp+uLN8OVGuJeQZS+XkvDfTNJnYkphv9rC+K34kueQ==")
+profile_metadata =
b64decode("vyU2WgqYlFGIKCAQEACCkQZUZVZpLTKSDVRlbGNvIFZpbGxhZ2WVAQK2DjAMgAIHgIEGQUJDREVG")
+smdp_certificate =
b64decode("MIICYTCCAgagAwIBAgICAQEwCgYIKoZIzj0EAwIwSTELMAkGA1UEBhMCSVQxEDAOBgNVBAoMB1JTUFRFU1QxETAPBgNVBAsMCFRFU1RDRVJUMRUwEwYDVQQDDAxHU01BIFRlc3QgQ0kwHhcNMTgwMzI4MDAwMDAwWhcNMTMwMzI3MDAwMDAwWjBNMSgwJgYDVQQDDB9OWFAgVGVzdCBTTS1EUCsgUHJvZmlsZSBCaW5kaW5nMRQwEgYDVQQKDAtOWFAgQXVzdHJpYTELMAkGA1UEBhMCQVQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR6J+\/982zA4p\/2wYxdP9qbhbMf9w1M6CEc\/0Gw6dXNn3gMG+wy7vqAsf0mx5KkKlQdEf2kTvelNvN85p1ZiPdWo4HZMIHWMB0GA1UdDgQWBBR3DJnk7lhra7KKQyoQROJXe40QezAfBgNVHSMEGDAWgBT1QXK9+YqV1ly+uIo4ocEdgAqFwzAOBgNVHQ8BAf8EBAMCB4AwFwYDVR0gAQH\/BA0wCzAJBgdngRIBAgEFMFsGA1UdHwRUMFIwJ6AloCOGIWh0dHA6Ly9jaS50ZXN0LmdzbWEuY29tL0NSTC1BLmNybDAnoCWgI4YhaHR0cDovL2NpLnRlc3QuZ3NtYS5jb20vQ1JMLUIuY3JsMA4GA1UdEQQHMAWIA4g3CjAKBggqhkjOPQQDAgNJADBGAiEAmrnxGnTKBZVIbLM+1vDjhg9PNVZhVVl7r2KJWNFw2H0CIQDNtrIB8LKhsUgFXuFxhCXYEnGH7h0aW\/9Je04k5nd\/tw==")
+#
{"type":"progress","payload":{"code":0,"message":"es10b_prepare_download","data":null}}
+
+smdp_cert = load_der_x509_certificate(smdp_certificate)
+print("SMDP certificate")
+pp(smdp_cert)
+pp(smdp_cert.issuer)
+pp(smdp_cert.subject)
+pp(smdp_cert.signature_algorithm_oid)
+pp(server_cert.extensions)
+pkey = smdp_cert.public_key()
+r = smdp_signature2[3:3+32]
+s = smdp_signature2[3+32:3+32+32]
+smdp_signature2_der = encode_dss_signature(int.from_bytes(r), int.from_bytes(s))
+pkey.verify(smdp_signature2_der, smdp_signed2, ec.ECDSA(hashes.SHA256()))
+
+
+
+
+
+#
{"type":"progress","payload":{"code":0,"message":"es9p_get_bound_profile_package","data":null}}
+# HTTP Req
https://rsp.esim.me:8083/gsma/rsp2/es9plus/getBoundProfilePackage:
{"transactionId":"5ECA276CA29A4CA195CC6BB018876822","prepareDownloadResponse":"vyEXoRWAEF7KJ2yimkyhlcxrsBiHaCICAX8="}
+# HTTP Resp:
{"header":{"functionExecutionStatus":{"status":"Failed","statusCodeData":{"subjectIdentifier":"2ELC-O\/VI-LLAG-EXX2","subjectCode":"8.1.1","reasonCode":"3.8","message":"Confirmation
Code mismatch"}}}}
+#
{"type":"lpa","payload":{"code":-1,"message":"es9p_get_bound_profile_package","data":"{\"subjectIdentifier\":\"2ELC-O/VI-LLAG-EXX2\",\"subjectCode\":\"8.1.1\",\"reasonCode\":\"3.8\",\"message\":\"Confirmation
Code mismatch\"}"}}
+
+
+
+print("PKId To be used: %s" % b2h(euicc_ci_pikd_to_be_used))
diff --git a/pySim/smdp_crypto.py b/pySim/smdp_crypto.py
new file mode 100644
index 0000000..a99e3b7
--- /dev/null
+++ b/pySim/smdp_crypto.py
@@ -0,0 +1,242 @@
+
+# That block of data is split into segments of a maximum size of 1020 bytes (including
the tag, length field and MAC).
+MAX_SEGMENT_SIZE = 1020
+
+import abc
+from typing import List
+
+# for BPS key derivation
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF
+
+from Cryptodome.Cipher import AES
+from Cryptodome.Hash import CMAC
+
+from pySim.utils import bertlv_encode_len, bertlv_parse_one, b2h
+
+class BspAlgo(abc.ABC):
+ blocksize = None
+ enum_name = None
+
+ def _get_padding(self, in_len: int, multiple: int, padding: int = 0):
+ """Return padding bytes towards multiple of N."""
+ if in_len % multiple == 0:
+ return b''
+ pad_cnt = multiple - (in_len % multiple)
+ return b'\x00' * pad_cnt
+
+ def _pad_to_multiple(self, indat: bytes, multiple: int, padding: int = 0):
+ return indat + self._get_padding(len(indat), self.blocksize, padding)
+
+ def __init__(self):
+ pass
+
+ def __str__(self):
+ return self.__class__.__name__
+
+class BspAlgoCrypt(BspAlgo, abc.ABC):
+
+ def __init__(self, s_enc: bytes):
+ self.iv = bytes([0] * (self.blocksize-1)) + b'\x01'
+ self.s_enc = s_enc
+ self.block_nr = 0
+ pass
+
+ def encrypt(self, data:bytes) -> bytes:
+ """Encrypt given input bytes using the key material given in
constructor."""
+ padded_data = self._pad_to_multiple(data, self.blocksize)
+ return self._encrypt(padded_data)
+
+ def decrypt(self, data:bytes) -> bytes:
+ """Decrypt given input bytes using the key material given in
constructor."""
+ return self._decrypt(data)
+
+ @abc.abstractmethod
+ def _encrypt(self, data:bytes) -> bytes:
+ """Actual implementation, to be implemented by derived
class."""
+ pass
+
+ #(a)abc.abstractmethod
+ def _decrypt(self, data:bytes) -> bytes:
+ """Actual implementation, to be implemented by derived
class."""
+ pass
+
+class BspAlgoCryptAES128(BspAlgoCrypt):
+ name = 'AES-CBC-128'
+ blocksize = 16
+
+ def _get_padding(self, in_len: int, multiple: int, padding: int = 0):
+ # SGP.22 section 2.6.4.4
+ # Append a byte with value '80' to the right of the data block;
+ pad = b'\x80'
+ # Append 0 to 15 bytes with value '00' so that the length of the padded
data block
+ # is a multiple of 16 bytes.
+ if (in_len + 1) % multiple == 0:
+ return pad
+ pad_cnt = multiple - ((in_len + 1) % multiple)
+ pad = pad + b'\x00' * pad_cnt
+ return pad
+
+ def _get_icv(self):
+ # The binary value of this number SHALL be left padded with zeroes to form a full
block.
+ data = self.block_nr.to_bytes(self.blocksize, "big")
+ iv = bytes([0] * (self.blocksize-1)) + b'\x01'
+ # This block SHALL be encrypted with S-ENC to produce the ICV for command
encryption.
+ cipher = AES.new(self.s_enc, AES.MODE_CBC, iv)
+ icv = cipher.encrypt(data)
+ self.block_nr = self.block_nr + 1
+ return icv
+
+ def _encrypt(self, data: bytes) -> bytes:
+ cipher = AES.new(self.s_enc, AES.MODE_CBC, self._get_icv())
+ return cipher.encrypt(data)
+
+ def _decrypt(self, data: bytes) -> bytes:
+ cipher = AES.new(self.s_enc, AES.MODE_CBC, self._get_icv())
+ return cipher.decrypt(data)
+
+
+class BspAlgoMac(BspAlgo, abc.ABC):
+
+ def __init__(self, s_mac: bytes, initial_mac_chaining_value: bytes):
+ self.s_mac = s_mac
+ self.mac_chain = initial_mac_chaining_value
+
+ def auth(self, tag: int, data: bytes) -> bytes:
+ assert tag <= 255
+ # The input data used for C-MAC computation comprises the MAC Chaining value, the
tag, the final length and the result of step 2
+ lcc = len(data) + self.l_mac
+ tag_and_length = bytes([tag]) + bertlv_encode_len(lcc)
+ temp_data = self.mac_chain + tag_and_length + data
+ c_mac = self._auth(temp_data)
+ # The output data is computed by concatenating the following data: the tag, the
final length, the result of step 2 and the C-MAC value.
+ return tag_and_length + data + c_mac
+
+ def verify(self, ciphertext: bytes) -> bool:
+ print("ciphertext=%s" % b2h(ciphertext))
+ mac_stripped = ciphertext[0:-self.l_mac]
+ mac_received = ciphertext[-self.l_mac:]
+ print("mac_stripped=%s" % b2h(mac_stripped))
+ print("mac_received=%s" % b2h(mac_received))
+ temp_data = self.mac_chain + mac_stripped
+ mac_computed = self._auth(temp_data)
+ print("mac_computed=%s" % b2h(mac_computed))
+ if mac_received != mac_computed:
+ raise ValueError("MAC value not matching")
+ return mac_stripped
+
+ @abc.abstractmethod
+ def _auth(self, temp_data: bytes) -> bytes:
+ """To be implemented by algorithm specific derived
class."""
+ pass
+
+class BspAlgoMacAES128(BspAlgoMac):
+ name = 'AES-CMAC-128'
+ l_mac = 8
+
+ def _auth(self, temp_data: bytes) -> bytes:
+ # The full MAC value is computed using the MACing algorithm as defined in table
4c.
+ cmac = CMAC.new(self.s_mac, ciphermod=AES)
+ cmac.update(temp_data)
+ full_c_mac = cmac.digest()
+ # Subsequent MAC chaining values are the full result of step 4 of the previous
data block
+ self.mac_chain = full_c_mac
+ # If the algorithm is AES-CBC-128 or SM4-CBC, the C-MAC value is the 8 most
significant bytes of the result of step 4
+ return full_c_mac[0:8]
+
+
+
+def bsp_key_derivation(shared_secret: bytes, key_type: int, key_length: int, host_id_lv:
bytes, eid_lv, l : int = 16):
+ """BSP protocol key derivation as per SGP.22 v3.0 Section
2.6.4.2"""
+ assert key_type <= 255
+ assert key_length <= 255
+ shared_info = bytes([key_type, key_length]) + host_id_lv + eid_lv
+
+ # X9.63 Key Derivation Function with SHA256
+ xkdf = X963KDF(algorithm=hashes.SHA256(), length=l*3, sharedinfo=shared_info)
+ out = xkdf.derive(shared_secret)
+
+ initial_mac_chaining_value = out[0:l]
+ s_enc = out[l:2*l]
+ s_mac = out[l*2:3*l]
+ return s_enc, s_mac, initial_mac_chaining_value
+
+
+
+class BspInstance:
+ """An instance of the BSP crypto. Initialized once with the key
material via constructor,
+ then the user can call any number of encrypt_and_mac cycles to protect plaintext and
+ generate the respective ciphertext."""
+ def __init__(self, s_enc: bytes, s_mac: bytes, initial_mcv: bytes):
+ self.c_algo = BspAlgoCryptAES128(s_enc)
+ self.m_algo = BspAlgoMacAES128(s_mac, initial_mcv)
+
+ TAG_LEN = 1
+ length_len = len(bertlv_encode_len(MAX_SEGMENT_SIZE))
+ self.max_payload_size = MAX_SEGMENT_SIZE - 1 - length_len - TAG_LEN -
self.m_algo.l_mac
+
+ @classmethod
+ def from_kdf(cls, shared_secret: bytes, key_type: int, key_length: int, host_id_lv:
bytes, eid_lv: bytes):
+ """Convenience constructor for constructing an instance with keys
from KDF."""
+ s_enc, s_mac, initial_mcv = bsp_key_derivation(shared_secret, key_type,
key_length, host_id_lv, eid_lv)
+ return cls(s_enc, s_mac, initial_mcv)
+
+ def encrypt_and_mac_one(self, tag: int, plaintext:bytes) -> bytes:
+ assert tag <= 255
+ assert len(plaintext) < self.max_payload_size
+ """Encrypt + MAC a single plaintext TLV. Returns the protected
ciphertex."""
+ ciphered = self.c_algo.encrypt(plaintext)
+ maced = self.m_algo.auth(tag, ciphered)
+ return maced
+
+ def encrypt_and_mac(self, tag: int, plaintext:bytes) -> List[bytes]:
+ remainder = plaintext
+ result = []
+ while len(remainder):
+ remaining_len = len(remainder)
+ if remaining_len < self.max_payload_size:
+ segment_len = remaining_len
+ segment = remainder
+ remainder = b''
+ else:
+ segment_len = self.max_payload_size
+ segment = remainder[0:segment_len]
+ remainder = remainder[segment_len:]
+ result.append(self.encrypt_and_mac_one(tag, segment))
+ return result
+
+ def mac_only_one(self, tag: int, plaintext: bytes) -> bytes:
+ """MAC a single plaintext TLV. Returns the protected
ciphertex."""
+ assert tag <= 255
+ assert len(plaintext) < self.max_payload_size
+ maced = self.m_algo.auth(tag, plaintext)
+ return maced
+
+ def mac_only(self, tag: int, plaintext:bytes) -> List[bytes]:
+ remainder = plaintext
+ result = []
+ while len(remainder):
+ remaining_len = len(remainder)
+ if remaining_len < self.max_payload_size:
+ segment_len = remaining_len
+ segment = remainder
+ remainder = b''
+ else:
+ segment_len = self.max_payload_size
+ segment = remainder[0:segment_len]
+ remainder = remainder[segment_len:]
+ result.append(self.mac_only_one(tag, segment))
+ return result
+
+ def demac_and_decrypt_one(self, ciphertext: bytes) -> bytes:
+ payload = self.m_algo.verify(ciphertext)
+ tdict, l, val, remain = bertlv_parse_one(payload)
+ print("tag=%s, l=%u, val=%s, remain=%s" % (tdict, l, b2h(val),
b2h(remain)))
+ plaintext = self.c_algo.decrypt(val)
+ return plaintext
+
+ def demac_and_decrypt(self, ciphertext_list: List[bytes]):
+ plaintext_list = []
+ for ciphertext in ciphertext_list:
+ plaintext_list.append(self.demac_and_decrypt_one(ciphertext))
+ return plaintext_list
diff --git a/server.pem b/server.pem
new file mode 100644
index 0000000..5a63365
--- /dev/null
+++ b/server.pem
@@ -0,0 +1,28 @@
+-----BEGIN PUBLIC KEY-----
+MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABEwizNgsjQIh+dhUO3LhB7zJ/ZBU
+1mx1wOt0p73nMOdhjvZbJwteguQ6eW+N7guvivvrilNiU3oC/WXHnkEZa7U=
+-----END PUBLIC KEY-----
+-----BEGIN EC PARAMETERS-----
+BgkrJAMDAggBAQc=
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHgCAQEEID9nFSgCs/TH+uZ5WFX2glQeReNe//TooFVloPGRKnguoAsGCSskAwMC
+CAEBB6FEA0IABEwizNgsjQIh+dhUO3LhB7zJ/ZBU1mx1wOt0p73nMOdhjvZbJwte
+guQ6eW+N7guvivvrilNiU3oC/WXHnkEZa7U=
+-----END EC PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICgjCCAimgAwIBAgIBCTAKBggqhkjOPQQDAjBEMRAwDgYDVQQDDAdUZXN0IENJ
+MREwDwYDVQQLDAhURVNUQ0VSVDEQMA4GA1UECgwHUlNQVEVTVDELMAkGA1UEBhMC
+SVQwHhcNMjMwNjA5MTkwNDU3WhcNMjQwNzExMTkwNDU3WjAzMQ0wCwYDVQQKDARB
+Q01FMSIwIAYDVQQDDBl0ZXN0c21kcHBsdXMxLmV4YW1wbGUuY29tMFowFAYHKoZI
+zj0CAQYJKyQDAwIIAQEHA0IABEwizNgsjQIh+dhUO3LhB7zJ/ZBU1mx1wOt0p73n
+MOdhjvZbJwteguQ6eW+N7guvivvrilNiU3oC/WXHnkEZa7WjggEaMIIBFjAOBgNV
+HQ8BAf8EBAMCB4AwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBQG
+A1UdIAQNMAswCQYHZ4ESAQIBAzAdBgNVHQ4EFgQUPTMJg/OfzFvS5K1ophmnR0iu
+i50wHwYDVR0jBBgwFoAUwLxwujaSnUO0Z/9XVwUw5Xq4/NgwKQYDVR0RBCIwIIIZ
+dGVzdHNtZHBwbHVzMS5leGFtcGxlLmNvbYgDiDcKMGEGA1UdHwRaMFgwKqAooCaG
+JGh0dHA6Ly9jaS50ZXN0LmV4YW1wbGUuY29tL0NSTC1BLmNybDAqoCigJoYkaHR0
+cDovL2NpLnRlc3QuZXhhbXBsZS5jb20vQ1JMLUIuY3JsMAoGCCqGSM49BAMCA0cA
+MEQCIApcIEyTa5qMAEzGohhaowudyFI+gtlVJCdRkigpaJUbAiARhnBzfX903/Uw
+2s35o2v0PlFVG3p940QMCCoc4yz3hA==
+-----END CERTIFICATE-----
diff --git a/sm-dp-http.py b/sm-dp-http.py
new file mode 100755
index 0000000..2195529
--- /dev/null
+++ b/sm-dp-http.py
@@ -0,0 +1,222 @@
+#!/usr/bin/env python3
+
+# SM-DP+ HTTP service for GSMA consumer eSIM RSP
+#
+# (C) 2023 by Harald Welte <laforge(a)osmocom.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 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/>.
+
+import json
+import sys
+import argparse
+import uuid
+import os
+from pprint import pprint as pp
+
+import base64
+from base64 import b64decode
+from klein import Klein
+import asn1tools
+
+from pySim.utils import h2b, b2h
+
+ASN1_DIR="/home/laforge/Downloads/sim_usim_isim/esim/asn1/"
+ASN1_FILES=['rsp.asn','PKIX1Implicit88.asn',
'PKIX1Explicit88.asn']
+
+# TODO: evaluate User-Agent + X-Admin-Protocol header
+# TODO: reject any non-JSON Content-type
+
+def b64encode2str(req: bytes) -> str:
+ return base64.b64encode(req).decode('ascii')
+
+def set_headers(request):
+ request.setHeader('Content-Type', 'application/json;charset=UTF-8')
+ request.setHeader('X-Admin-Protocol', 'gsma/rsp/v2.1.0')
+
+def build_resp_header(js: dict, status: str = 'Executed-Success',
status_code_data = None):
+ # SGP.22 v3.0 6.5.1.4
+ js['header'] = {
+ 'functionExecutionStatus': {
+ 'status': status,
+ }
+ }
+ if status_code_data:
+ js['header']['functionExecutionStatus']['statusCodeData']
= status_code_data
+
+from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature,
encode_dss_signature
+from cryptography.hazmat.primitives.serialization import load_pem_private_key, Encoding
+from cryptography.hazmat.primitives.asymmetric import ec
+from cryptography.hazmat.primitives import hashes
+from cryptography import x509
+
+def ecdsa_dss_to_tr03111(sig: bytes) -> bytes:
+ """convert from DER format to BSI TR-03111; first get long integers;
then convert those to bytes."""
+ r, s = decode_dss_signature(sig)
+ return r.to_bytes(32, 'big') + s.to_bytes(32, 'big')
+
+def ecdsa_tr03111_to_dss(sig: bytes) -> bytes:
+ """convert an ECDSA signature from BSI TR-03111 format to DER: first
get long integers; then encode those."""
+ r = int.from_bytes(sig[0:32], 'big')
+ s = int.from_bytes(sig[32:32*2], 'big')
+ return encode_dss_signature(r, s)
+
+class ApiError:
+ def __init__(self, status:str, ):
+ self.status = status
+
+ def __str__(self):
+ js = {}
+ build_resp_header(js, status, status_code_data)
+ return json.dumps(js)
+
+class SmDppHttpServer:
+ app = Klein()
+ asn1 = asn1tools.compile_files([ASN1_DIR + x for x in ASN1_FILES])
+ with open('DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der', 'rb') as f:
+ server_cert = x509.load_der_x509_certificate(f.read())
+ with open('DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem', 'rb') as f:
+ server_private_key = load_pem_private_key(f.read(), None)
+
+ def _ecdsa_sign(self, plaintext: bytes) -> bytes:
+ """Sign some input-data using an ECDSA signature compliant with
SGP.22,
+ which internally refers to Global Platform 2.2 Annex E, which in turn points
+ to BSI TS-03111 which states "concatengated raw R + S values".
"""
+ sig = self.server_private_key.sign(plaintext, ec.ECDSA(hashes.SHA256()))
+ # convert from DER format to BSI TR-03111; first get long integers; then convert
those to bytes
+ return ecdsa_dss_to_tr03111(sig)
+
+
+ @app.route('/gsma/rsp2/es9plus/initiateAuthentication',
methods=['POST'])
+ def initiateAutentication(self, request):
+ output = {}
+ set_headers(request)
+ content = json.loads(request.content.read())
+ print("Rx JSON: %s" % content)
+ # TODO: Verify that the received address matches its own SM-DP+ address, where
the comparison SHALL be
+ # case-insensitive. Otherwise, the SM-DP+ SHALL return a status code "SM-DP+
Address - Refused".
+ #if content['smdpAddress'] != FIXME: ...
+
+ euiccChallenge = b64decode(content['euiccChallenge'])
+ if len(euiccChallenge) != 16:
+ raise ValueError
+
+ euiccInfo1_bin = b64decode(content['euiccInfo1'])
+ euiccInfo1 = self.asn1.decode('EUICCInfo1', euiccInfo1_bin)
+ print("euiccInfo1: %s" % euiccInfo1)
+ #euiccInfo1['svn']
+
+ # TODO: If euiccCiPKIdListForSigningV3 is present ...
+ # verify it supports one of the keys indicated by euiccCiPKIdListForSigning
+ #euiccInfo1['euiccCiPKIdListForSigning']
+
+ # TODO: Determine the set of CERT.DPauth.SIG that satisfy the following
criteria:
+ # * Part of a certificate chain ending at one of the eSIM CA RootCA Certificate,
whose Public Keys is
+ # supported by the eUICC (indicated by euiccCiPKIdListForVerification).
+ # * Using a certificate chain that the eUICC and the LPA both support:
+ #euiccInfo1['euiccCiPKIdListForVerification']
+
+ # Generate a TransactionID which is used to identify the ongoing RSP session. The
TransactionID
+ # SHALL be unique within the scope and lifetime of each SM-DP+.
+ transactionId = uuid.uuid4().hex
+
+ # Generate a serverChallenge for eUICC authentication attached to the ongoing RSP
session.
+ serverChallenge = os.urandom(16)
+
+ # Generate a serverSigned1 data object as expected by the eUICC and described in
section 5.7.13 "ES10b.AuthenticateServer". If and only if both eUICC and LPA
indicate crlStaplingV3Support, the SM-DP+ SHALL indicate crlStaplingV3Used in
sessionContext.
+ serverSigned1 = {
+ 'transactionId': h2b(transactionId),
+ 'euiccChallenge': euiccChallenge,
+ 'serverAddress': 'testsmdpplus1.example.com',
+ 'serverChallenge': serverChallenge,
+ }
+ print("Tx serverSigned1: %s" % serverSigned1)
+ serverSigned1_bin = self.asn1.encode('ServerSigned1', serverSigned1)
+ output['serverSigned1'] = b64encode2str(serverSigned1_bin)
+
+ # Generate a signature (serverSignature1) as described in section 5.7.13
"ES10b.AuthenticateServer" using the SK related to the selected
CERT.DPauth.SIG.
+ # serverSignature1 SHALL be created using the private key associated to the RSP
Server Certificate for authentication, and verified by the eUICC using the contained
public key as described in section 2.6.9. serverSignature1 SHALL apply on serverSigned1
data object.
+ output['serverSignature1'] = b64encode2str(b'\x5f\x37\x40' +
self._ecdsa_sign(serverSigned1_bin))
+
+ output['transactionId'] = transactionId
+ server_cert_aki =
self.server_cert.extensions.get_extension_for_class(x509.AuthorityKeyIdentifier)
+ output['euiccCiPKIdToBeUsed'] =
b64encode2str(server_cert_aki.value.key_identifier)
+ output['serverCertificate'] =
b64encode2str(self.server_cert.public_bytes(Encoding.DER))
+ #output['otherCertsInChain'] = b64encode2str()
+ build_resp_header(output)
+ print("Tx JSON: %s" % output)
+
+ # FIXME: store all that state somewhere
+
+ return json.dumps(output)
+
+ @app.route('/gsma/rsp2/es9plus/authenticateClient',
methods=['POST'])
+ def authenticateClient(self, request):
+ set_headers(request)
+ content = json.loads(request.content.read())
+ print("Rx JSON: %s" % content)
+ transactionId = content['transactionId']
+ authenticateServerResp_bin =
b64decode(content['authenticateServerResponse'])
+ authenticateServerResp = self.asn1.decode('AuthenticateServerResponse',
authenticateServerResp_bin)
+ #print("Rx authenticateServerResp: %s" % authenticateServerResp)
+ print(authenticateServerResp)
+ if 'authenticateResponseError' in authenticateServerResp:
+ #r_err = authenticateServerResp['authenticateResponseError']
+ #r_err['transactionId']
+ #r_err['authenticateErrorCode']
+ raise ValueError
+
+ r_ok = authenticateServerResp['authenticateResponseOk']
+ #r_ok['euiccSigned1']
+ #r_ok['euiccSignature1']
+ #r_ok['euiccCertificate']
+ #r_ok['eumCertificate']
+
+ output = {}
+ output['transactionId'] = transactionId
+ build_resp_header(output)
+
+ return json.dumps(output)
+
+ @app.route('/gsma/rsp2/es9plus/getBoundProfilePackage',
methods=['POST'])
+ def getBoundProfilePackage(self, request):
+ set_headers(request)
+ content = json.loads(request.content.read())
+ transactionId = content['transactionId']
+ #content['prepareDownloadResponse']
+
+ output = {}
+ output['transactionId'] = transactionId
+ output['boundProfilePackage'] = bpp
+ build_resp_header(output)
+
+ return json.dumps(output)
+
+ #(a)app.route('/gsma/rsp2/es9plus/handleNotification'ion',
methods=['POST'])
+ #(a)app.route('/gsma/rsp3/es9plus/handleDeviceChangeRequestuest,
methods=['POST']')
+ #(a)app.route('/gsma/rsp2/es9plus/cancelSession'ion', methods=['POST'])
+
+def main(argv):
+ parser = argparse.ArgumentParser()
+ #parser.add_argument("-H", "--host", help="Host/IP to bind
HTTP to", default="localhost")
+ #parser.add_argument("-p", "--port", help="TCP port to bind
HTTP to", default=8000)
+ #parser.add_argument("-v", "--verbose", help="increase
output verbosity", action='count', default=0)
+
+ args = parser.parse_args()
+
+ hs = SmDppHttpServer()
+
#hs.app.run(endpoint_description="ssl:port=8000:dhParameters=dh_param_2048.pem")
+ hs.app.run("localhost", 80)
+
+if __name__ == "__main__":
+ main(sys.argv)
--
To view, visit
https://gerrit.osmocom.org/c/pysim/+/35461?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I6232847432dc6920cd2bd08c84d7099c29ca1c11
Gerrit-Change-Number: 35461
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newchange