laforge has uploaded this change for review.

View Change

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ÌÍìAˆHÊt£×ôͺ„nìE<Nåû R¤~&Àk\þ~­ ÉRlÜÛ°Ÿ‰¥7ì¶NŒŽmWø
\ 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
+
+ #@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@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)
+
+ #@app.route('/gsma/rsp2/es9plus/handleNotification', methods=['POST'])
+ #@app.route('/gsma/rsp3/es9plus/handleDeviceChangeRequest, methods=['POST']')
+ #@app.route('/gsma/rsp2/es9plus/cancelSession', 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 change 35461. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I6232847432dc6920cd2bd08c84d7099c29ca1c11
Gerrit-Change-Number: 35461
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge@osmocom.org>
Gerrit-MessageType: newchange