lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
Threads by month
  • ----- 2026 -----
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
gerrit-log@lists.osmocom.org

January 2024

  • 1 participants
  • 1559 discussions
[M] Change in osmo-bsc[master]: vty: disallow combination of early-IA and frequency hopping
by neels 10 Jan '24

10 Jan '24
neels has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/35097?usp=email ) Change subject: vty: disallow combination of early-IA and frequency hopping ...................................................................... Patch Set 4: Code-Review+2 (1 comment) Patchset: PS4: combine votes -- To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/35097?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bsc Gerrit-Branch: master Gerrit-Change-Id: I8d375e5155be7b53034d5c0be5566d2f33af5db0 Gerrit-Change-Number: 35097 Gerrit-PatchSet: 4 Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de> Gerrit-Reviewer: osmith <osmith(a)sysmocom.de> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Comment-Date: Wed, 10 Jan 2024 07:59:43 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[M] Change in osmo-bts[master]: early-IA: use the correct TRX
by neels 10 Jan '24

10 Jan '24
neels has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bts/+/35095?usp=email ) Change subject: early-IA: use the correct TRX ...................................................................... early-IA: use the correct TRX In early-Immediate-Assignment, the BSC sends the IMM ASS message directly after it sent the Channel Activation message, and osmo-bts should cache it until the Channel Activation is complete. So far the code had a bug: it assumed that the lchan was on the same TRX where the IMM ASS is transmitted -- but actually, 'trx' refers to the BCCH channel's TRX, i.e. always c0. Instead, look up the correct TRX by the ARFCN in the IMM ASS message. Now, when frequency hopping is enabled, there will be no ARFCN in the IMM ASS message, hence this fix does not work with frequency hopping. Related osmo-bsc patch disallows this combination. (To also support frequency hopping, osmo-bsc would need to modify the RSL protocol: send the IMM ASS message as a custom IE directly as part of the Channel Activation. Then it is always possible to correllate the IMM ASS with a specific trx and lchan, no matter what information it contains. However, early-IA is a "bad" feature in itself as it "promotes" having high latency on Abis. It seems unnecessary to do extra work to also support this odd use case for frequency hopping.) Related: osmo-bsc I8d375e5155be7b53034d5c0be5566d2f33af5db0 Related: SYS#6655 Change-Id: Id9a930e5c67122812b229dc27ea2bfe246b67611 --- M src/common/rsl.c 1 file changed, 67 insertions(+), 9 deletions(-) Approvals: neels: Looks good to me, approved Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve dexter: Looks good to me, but someone else must approve daniel: Looks good to me, but someone else must approve diff --git a/src/common/rsl.c b/src/common/rsl.c index b5ec17f..bc2a5ea 100644 --- a/src/common/rsl.c +++ b/src/common/rsl.c @@ -371,6 +371,16 @@ return true; } +static struct gsm_bts_trx *trx_lookup_by_arfcn(struct llist_head *trx_list, uint16_t arfcn) +{ + struct gsm_bts_trx *trx; + llist_for_each_entry(trx, trx_list, list) { + if (trx->arfcn == arfcn) + return trx; + } + return NULL; +} + static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, const char *log_name) { @@ -1383,18 +1393,33 @@ * the channel is active. Hence we still wait for the activation, but don't need the Abis roundtrip of Activ ACK * -> Immediate Assignment via the BSC. * If anything is wrong with the sizes or the lchan lookup, behave normally, i.e. do not do the RR IA caching, - * but just send the RR message to the MS as-is. */ + * but just send the RR message to the MS as-is. + * 'trx' here is the TRX of the BCCH channel. To find the correct TRX for the IMM ASS target, we need to look up + * the ARFCN that is contained in the IMM ASS message. When frequency hopping is enabled, there will not be an + * ARFCN, so we cannot support early-IA with frequency hopping enabled. */ if (msg->len >= sizeof(struct gsm48_imm_ass)) { struct gsm48_imm_ass *rr_ia = (void*)msg->data; - struct gsm_lchan *ia_target_lchan = lchan_lookup(trx, rr_ia->chan_desc.chan_nr, "Early IA check: "); - if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) { - /* Target lchan is not yet active. Cache the IA. - * If a previous IA is still lingering, free it. */ - msgb_free(ia_target_lchan->early_rr_ia); - ia_target_lchan->early_rr_ia = msg; + if (rr_ia->chan_desc.h0.h == 0) { + /* hopping is disabled. */ + struct gsm_bts_trx *ia_target_trx; + uint16_t arfcn; + arfcn = (rr_ia->chan_desc.h0.arfcn_high << 8) + rr_ia->chan_desc.h0.arfcn_low; - /* return 1 means: don't msgb_free() the msg */ - return 1; + ia_target_trx = trx_lookup_by_arfcn(&trx->bts->trx_list, arfcn); + if (ia_target_trx) { + /* found the ARFCN's trx */ + struct gsm_lchan *ia_target_lchan; + ia_target_lchan = lchan_lookup(ia_target_trx, rr_ia->chan_desc.chan_nr, "Early IA check: "); + if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) { + /* Target lchan is not yet active. Cache the IA. + * If a previous IA is still lingering, free it. */ + msgb_free(ia_target_lchan->early_rr_ia); + ia_target_lchan->early_rr_ia = msg; + + /* return 1 means: don't msgb_free() the msg */ + return 1; + } + } } } -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/35095?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Id9a930e5c67122812b229dc27ea2bfe246b67611 Gerrit-Change-Number: 35095 Gerrit-PatchSet: 4 Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de> Gerrit-CC: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 0
0 0
[M] Change in osmo-bts[master]: early-IA: use the correct TRX
by neels 10 Jan '24

10 Jan '24
Attention is currently required from: pespin. neels has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bts/+/35095?usp=email ) Change subject: early-IA: use the correct TRX ...................................................................... Patch Set 3: Code-Review+2 (1 comment) Patchset: PS1: > completely untested we got a response from an undisclosed tester that this patch works well on site and is used in production now -- To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/35095?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-bts Gerrit-Branch: master Gerrit-Change-Id: Id9a930e5c67122812b229dc27ea2bfe246b67611 Gerrit-Change-Number: 35095 Gerrit-PatchSet: 3 Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de> Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de> Gerrit-CC: pespin <pespin(a)sysmocom.de> Gerrit-Attention: pespin <pespin(a)sysmocom.de> Gerrit-Comment-Date: Wed, 10 Jan 2024 07:53:52 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: Yes Comment-In-Reply-To: neels <nhofmeyr(a)sysmocom.de> Gerrit-MessageType: comment
1 0
0 0
[S] Change in pysim[master]: euicc: Fix decoding of SubjectKeyIdentifier.
by laforge 09 Jan '24

09 Jan '24
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/35523?usp=email ) Change subject: euicc: Fix decoding of SubjectKeyIdentifier. ...................................................................... euicc: Fix decoding of SubjectKeyIdentifier. There's actually no additional TLV structure inside the Tag 0x04. Change-Id: Ic922355308747a888083c5b26765d272b6b20bd0 --- M pySim/euicc.py 1 file changed, 14 insertions(+), 5 deletions(-) git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/23/35523/1 diff --git a/pySim/euicc.py b/pySim/euicc.py index e405f30..81fbd1e 100644 --- a/pySim/euicc.py +++ b/pySim/euicc.py @@ -94,13 +94,11 @@ # SGP.22 Section 5.7.8: GetEUICCInfo class SVN(BER_TLV_IE, tag=0x82): _construct = VersionType -class SubjectKeyIdentifier(BER_TLV_IE, tag=0x81): +class SubjectKeyIdentifier(BER_TLV_IE, tag=0x04): _construct = HexAdapter(GreedyBytes) -class SubjectKeyIdentifierSeq(BER_TLV_IE, tag=0x04, nested=[SubjectKeyIdentifier]): +class EuiccCiPkiListForVerification(BER_TLV_IE, tag=0xa9, nested=[SubjectKeyIdentifier]): pass -class EuiccCiPkiListForVerification(BER_TLV_IE, tag=0xa9, nested=[SubjectKeyIdentifierSeq]): - pass -class EuiccCiPkiListForSigning(BER_TLV_IE, tag=0xaa, nested=[SubjectKeyIdentifierSeq]): +class EuiccCiPkiListForSigning(BER_TLV_IE, tag=0xaa, nested=[SubjectKeyIdentifier]): pass class EuiccInfo1(BER_TLV_IE, tag=0xbf20, nested=[SVN, EuiccCiPkiListForVerification, EuiccCiPkiListForSigning]): pass -- To view, visit https://gerrit.osmocom.org/c/pysim/+/35523?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: Ic922355308747a888083c5b26765d272b6b20bd0 Gerrit-Change-Number: 35523 Gerrit-PatchSet: 1 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-MessageType: newchange
1 0
0 0
[XL] Change in pysim[master]: Initial proof-of-concept SM-DP+ for GSMA consumer eSIM RSP
by laforge 09 Jan '24

09 Jan '24
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/35461?usp=email ) Change subject: Initial proof-of-concept SM-DP+ for GSMA consumer eSIM RSP ...................................................................... Initial proof-of-concept SM-DP+ for GSMA consumer eSIM RSP This commit introduces * the osmo-smdpp.py program implementing the main procedures and the HTTP/REST based ES9+ * python modules for ES8+ and non-volatile RSP Session State storage * the ASN.1 source files required to parse/encode RSP * 3GPP test certificates from SGP.26 * an unsigned profile package (UPP) of a SAIP v2.3 TS48 test profile As I couldn't get the 'Klein' tls support to work, the SM-DP+ code currently does not support HTTPS/TLS but plan HTTP, so you either have to modify your LPA to use HTTP instead of HTTPS, or put a TLS proxy in front. I have successfully installed an eSIM profile on a test eUICC that contains certificate/key data within the test CI defined in GSMA SGP.26 Change-Id: I6232847432dc6920cd2bd08c84d7099c29ca1c11 --- A .checkpatch.conf M docs/index.rst A docs/osmo-smdpp.rst A osmo-smdpp.py M pySim/esim/__init__.py A pySim/esim/asn1/rsp/PKIX1Explicit88.asn A pySim/esim/asn1/rsp/PKIX1Implicit88.asn A pySim/esim/asn1/rsp/rsp.asn A pySim/esim/es8p.py A pySim/esim/rsp.py M requirements.txt A smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.der A smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.pem A smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.der A smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.pem A smdpp-data/certs/CertificateIssuer/CI-csr.cnf A smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der A smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der A smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der A smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der A smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem A smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem A smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem A smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem A smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem A smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem A smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem A smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem A smdpp-data/certs/DPauth/data_sig.der A smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_BRP.der A smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_NIST.der A smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_BRP.der A smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_NIST.der A smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_BRP.pem A smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_NIST.pem A smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_BRP.pem A smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_NIST.pem A smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_BRP.pem A smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_NIST.pem A smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_BRP.pem A smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_NIST.pem A smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.csr.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.der A smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.ext.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.csr.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.der A smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.ext.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.csr.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.der A smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.ext.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.csr.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.ext.cnf A smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_BRP.der A smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_NIST.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der A smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der A smdpp-data/certs/DPtls/PK_S_SM_DP2_TLS_NIST.pem A smdpp-data/certs/DPtls/PK_S_SM_DP4_TLS.pem A smdpp-data/certs/DPtls/PK_S_SM_DP8_TLS.pem A smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_BRP.pem A smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_NIST.pem A smdpp-data/certs/DPtls/SK_S_SM_DP2_TLS_NIST.pem A smdpp-data/certs/DPtls/SK_S_SM_DP4_TLS.pem A smdpp-data/certs/DPtls/SK_S_SM_DP8_TLS.pem A smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_BRP.pem A smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_NIST.pem A smdpp-data/certs/README A smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.1_NoBERTLV.rename2der A smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.3_NoBERTLV.rename2der A tests/test_esim.py M tests/test_esim_bsp.py 84 files changed, 3,189 insertions(+), 0 deletions(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/.checkpatch.conf b/.checkpatch.conf new file mode 100644 index 0000000..8fdd97e --- /dev/null +++ b/.checkpatch.conf @@ -0,0 +1,2 @@ +--exclude ^pySim/esim/asn1/.*\.asn$ +--exclude ^smdpp-data/.*$ diff --git a/docs/index.rst b/docs/index.rst index a46aee0..bcbc7f0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -42,6 +42,7 @@ trace legacy library + osmo-smdpp Indices and tables diff --git a/docs/osmo-smdpp.rst b/docs/osmo-smdpp.rst new file mode 100644 index 0000000..5687fc6 --- /dev/null +++ b/docs/osmo-smdpp.rst @@ -0,0 +1,93 @@ +osmo-smdpp +========== + +`osmo-smdpp` is a proof-of-concept implementation of a minimal **SM-DP+** as specified for the *GSMA +Consumer eSIM Remote SIM provisioning*. + +At least at this point, it is intended to be used for research and development, and not as a +production SM-DP+. + +Unless you are a GSMA SAS-SM accredited SM-DP+ operator and have related DPtls, DPauth and DPpb +certificates signed by the GSMA CI, you **can not use osmo-smdpp with regular production eUICC**. +This is due to how the GSMA eSIM security architecture works. You can, however, use osmo-smdpp with +so-called *test-eUICC*, which contain certificates/keys signed by GSMA test certificates as laid out +in GSMA SGP.26. + +At this point, osmo-smdpp does not support anything beyond the bare minimum required to download +eSIM profiles to an eUICC. Specifically, there is no ES2+ interface, and there is no built-in +support for profile personalization yet. + +osmo-smdpp currently + +* always provides the exact same profile to every request. The profile always has the same IMSI and + ICCID. +* **is absolutely insecure**, as it + + * does not perform any certificate verification + * does not evaluate/consider any *Matching ID* or *Confirmation Code* + * stores the sessions in an unencrypted _python shelve_ and is hence leaking one-time key materials + used for profile encryption and signing. + + +Running osmo-smdpp +------------------ + +osmo-smdpp does not have built-in TLS support as the used *twisted* framework appears to have +problems when using the example elliptic curve certificates (both NIST and Brainpool) from GSMA. + +So in order to use it, you have to put it behind a TLS reverse proxy, which terminates the ES9+ +HTTPS from the LPA, and then forwards it as plain HTTP to osmo-smdpp. + +nginx as TLS proxy +~~~~~~~~~~~~~~~~~~ + +If you use `nginx` as web server, you can use the following configuration snippet:: + + upstream smdpp { + server localhost:8000; + } + + server { + listen 443 ssl; + server_name testsmdpplus1.example.com; + + ssl_certificate /my/path/to/pysim/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_NIST.pem; + ssl_certificate_key /my/path/to/pysim/smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_NIST.pem; + + location / { + proxy_read_timeout 600s; + + proxy_hide_header X-Powered-By; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-Port $proxy_port; + proxy_set_header Host $host; + + proxy_pass http://smdpp/; + } + } + +You can of course achieve a similar functionality with apache, lighttpd or many other web server +software. + + +osmo-smdpp +~~~~~~~~~~ + +osmo-smdpp currently doesn't have any configuration file or command line options. You just run it, +and it will bind its plain-HTTP ES9+ interface to local TCP port 8000. + +The `smdpp-data/certs`` directory contains the DPtls, DPauth and DPpb as well as CI certificates +used; they are copied from GSMA SGP.26 v2. + +The `smdpp-data/upp` directory contains the UPP (Unprotected Profile Package) used. + + +DNS setup for your LPA +~~~~~~~~~~~~~~~~~~~~~~ + +The LPA must resolve `testsmdpplus1.example.com` to the IP address of your TLS proxy. + +It must also accept the TLS certificates used by your TLS proxy. + diff --git a/osmo-smdpp.py b/osmo-smdpp.py new file mode 100755 index 0000000..6ae5be8 --- /dev/null +++ b/osmo-smdpp.py @@ -0,0 +1,594 @@ +#!/usr/bin/env python3 + +# Early proof-of-concept towards a SM-DP+ HTTP service for GSMA consumer eSIM RSP +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero 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 +import functools +from typing import Optional, Dict, List +from pprint import pprint as pp + +import base64 +from base64 import b64decode +from klein import Klein +from twisted.web.iweb import IRequest +import asn1tools + +from pySim.utils import h2b, b2h, swap_nibbles + +import pySim.esim.rsp as rsp +from pySim.esim.es8p import * + +# HACK: make this configurable +DATA_DIR = './smdpp-data' +HOSTNAME = 'testsmdpplus1.example.com' # must match certificates! + + +def b64encode2str(req: bytes) -> str: + """Encode given input bytes as base64 and return result as string.""" + return base64.b64encode(req).decode('ascii') + +def set_headers(request: IRequest): + """Set the request headers as mandatory by GSMA eSIM RSP.""" + request.setHeader('Content-Type', 'application/json;charset=UTF-8') + request.setHeader('X-Admin-Protocol', 'gsma/rsp/v2.1.0') + +def build_status_code(subject_code: str, reason_code: str, subject_id: Optional[str], message: Optional[str]) -> Dict: + r = {'subjectCode': subject_code, 'reasonCode': reason_code } + if subject_id: + r['subjectIdentifier'] = subject_id + if message: + r['message'] = message + return r + +def build_resp_header(js: dict, status: str = 'Executed-Success', status_code_data = None) -> 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, PublicFormat, PrivateFormat, NoEncryption +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives import hashes +from cryptography.exceptions import InvalidSignature +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.""" + assert len(sig) == 64 + r = int.from_bytes(sig[0:32], 'big') + s = int.from_bytes(sig[32:32*2], 'big') + return encode_dss_signature(r, s) + + +class CertAndPrivkey: + """A pair of certificate and private key, as used for ECDSA signing.""" + def __init__(self, required_policy_oid: Optional[x509.ObjectIdentifier] = None, + cert: Optional[x509.Certificate] = None, priv_key = None): + self.required_policy_oid = required_policy_oid + self.cert = cert + self.priv_key = priv_key + + def cert_from_der_file(self, path: str): + with open(path, 'rb') as f: + cert = x509.load_der_x509_certificate(f.read()) + if self.required_policy_oid: + # verify it is the right type of certificate (id-rspRole-dp-auth, id-rspRole-dp-auth-v2, etc.) + assert cert_policy_has_oid(cert, self.required_policy_oid) + self.cert = cert + + def privkey_from_pem_file(self, path: str, password: Optional[str] = None): + with open(path, 'rb') as f: + self.priv_key = load_pem_private_key(f.read(), password) + + 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.priv_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) + + def get_authority_key_identifier(self) -> x509.AuthorityKeyIdentifier: + """Return the AuthorityKeyIdentifier X.509 extension of the certificate.""" + return list(filter(lambda x: isinstance(x.value, x509.AuthorityKeyIdentifier), self.cert.extensions))[0].value + + def get_subject_alt_name(self) -> x509.SubjectAlternativeName: + """Return the SubjectAlternativeName X.509 extension of the certificate.""" + return list(filter(lambda x: isinstance(x.value, x509.SubjectAlternativeName), self.cert.extensions))[0].value + + def get_cert_as_der(self) -> bytes: + """Return certificate encoded as DER.""" + return self.cert.public_bytes(Encoding.DER) + + def get_curve(self) -> ec.EllipticCurve: + return self.cert.public_key().public_numbers().curve + + + + +class ApiError(Exception): + def __init__(self, subject_code: str, reason_code: str, message: Optional[str] = None, + subject_id: Optional[str] = None): + self.status_code = build_status_code(subject_code, reason_code, subject_id, message) + + def encode(self) -> str: + """Encode the API Error into a responseHeader string.""" + js = {} + build_resp_header(js, 'Failed', self.status_code) + return json.dumps(js) + +def cert_policy_has_oid(cert: x509.Certificate, match_oid: x509.ObjectIdentifier) -> bool: + """Determine if given certificate has a certificatePolicy extension of matching OID.""" + for policy_ext in filter(lambda x: isinstance(x.value, x509.CertificatePolicies), cert.extensions): + if any(policy.policy_identifier == match_oid for policy in policy_ext.value._policies): + return True + return False + +ID_RSP = "2.23.146.1" +ID_RSP_CERT_OBJECTS = '.'.join([ID_RSP, '2']) +ID_RSP_ROLE = '.'.join([ID_RSP_CERT_OBJECTS, '1']) + +class oid: + id_rspRole_ci = x509.ObjectIdentifier(ID_RSP_ROLE + '.0') + id_rspRole_euicc_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.1') + id_rspRole_eum_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.2') + id_rspRole_dp_tls_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.3') + id_rspRole_dp_auth_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.4') + id_rspRole_dp_pb_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.5') + id_rspRole_ds_tls_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.6') + id_rspRole_ds_auth_v2 = x509.ObjectIdentifier(ID_RSP_ROLE + '.7') + +class SmDppHttpServer: + app = Klein() + + @staticmethod + def load_certs_from_path(path: str) -> List[x509.Certificate]: + """Load all DER + PEM files from given directory path and return them as list of x509.Certificate + instances.""" + certs = [] + for dirpath, dirnames, filenames in os.walk(path): + for filename in filenames: + cert = None + if filename.endswith('.der'): + with open(os.path.join(dirpath, filename), 'rb') as f: + cert = x509.load_der_x509_certificate(f.read()) + elif filename.endswith('.pem'): + with open(os.path.join(dirpath, filename), 'rb') as f: + cert = x509.load_pem_x509_certificate(f.read()) + if cert: + # verify it is a CI certificate (keyCertSign + i-rspRole-ci) + if not cert_policy_has_oid(cert, oid.id_rspRole_ci): + raise ValueError("alleged CI certificate %s doesn't have CI policy" % filename) + certs.append(cert) + return certs + + def ci_get_cert_for_pkid(self, ci_pkid: bytes) -> Optional[x509.Certificate]: + """Find CI certificate for given key identifier.""" + for cert in self.ci_certs: + print("cert: %s" % cert) + subject_exts = list(filter(lambda x: isinstance(x.value, x509.SubjectKeyIdentifier), cert.extensions)) + print(subject_exts) + subject_pkid = subject_exts[0].value + print(subject_pkid) + if subject_pkid and subject_pkid.key_identifier == ci_pkid: + return cert + return None + + def __init__(self, server_hostname: str, ci_certs_path: str, use_brainpool: bool = False): + self.server_hostname = server_hostname + self.ci_certs = self.load_certs_from_path(ci_certs_path) + # load DPauth cert + key + self.dp_auth = CertAndPrivkey(oid.id_rspRole_dp_auth_v2) + cert_dir = os.path.join(DATA_DIR, 'certs') + if use_brainpool: + self.dp_auth.cert_from_der_file(os.path.join(cert_dir, 'DPauth', 'CERT_S_SM_DPauth_ECDSA_BRP.der')) + self.dp_auth.privkey_from_pem_file(os.path.join(cert_dir, 'DPauth', 'SK_S_SM_DPauth_ECDSA_BRP.pem')) + else: + self.dp_auth.cert_from_der_file(os.path.join(cert_dir, 'DPauth', 'CERT_S_SM_DPauth_ECDSA_NIST.der')) + self.dp_auth.privkey_from_pem_file(os.path.join(cert_dir, 'DPauth', 'SK_S_SM_DPauth_ECDSA_NIST.pem')) + # load DPpb cert + key + self.dp_pb = CertAndPrivkey(oid.id_rspRole_dp_pb_v2) + if use_brainpool: + self.dp_pb.cert_from_der_file(os.path.join(cert_dir, 'DPpb', 'CERT_S_SM_DPpb_ECDSA_BRP.der')) + self.dp_pb.privkey_from_pem_file(os.path.join(cert_dir, 'DPpb', 'SK_S_SM_DPpb_ECDSA_BRP.pem')) + else: + self.dp_pb.cert_from_der_file(os.path.join(cert_dir, 'DPpb', 'CERT_S_SM_DPpb_ECDSA_NIST.der')) + self.dp_pb.privkey_from_pem_file(os.path.join(cert_dir, 'DPpb', 'SK_S_SM_DPpb_ECDSA_NIST.pem')) + self.rss = rsp.RspSessionStore(os.path.join(DATA_DIR, "sm-dp-sessions")) + + @app.handle_errors(ApiError) + def handle_apierror(self, request: IRequest, failure): + request.setResponseCode(200) + pp(failure) + return failure.value.encode() + + @staticmethod + def _ecdsa_verify(cert: x509.Certificate, signature: bytes, data: bytes) -> bool: + pubkey = cert.public_key() + dss_sig = ecdsa_tr03111_to_dss(signature) + try: + pubkey.verify(dss_sig, data, ec.ECDSA(hashes.SHA256())) + return True + except InvalidSignature: + return False + + @staticmethod + def rsp_api_wrapper(func): + """Wrapper that can be used as decorator in order to perform common REST API endpoint entry/exit + functionality, such as JSON decoding/encoding and debug-printing.""" + @functools.wraps(func) + def _api_wrapper(self, request: IRequest): + # TODO: evaluate User-Agent + X-Admin-Protocol header + # TODO: reject any non-JSON Content-type + + content = json.loads(request.content.read()) + print("Rx JSON: %s" % content) + set_headers(request) + + output = func(self, request, content) or {} + + build_resp_header(output) + print("Tx JSON: %s" % output) + return json.dumps(output) + return _api_wrapper + + @app.route('/gsma/rsp2/es9plus/initiateAuthentication', methods=['POST']) + @rsp_api_wrapper + def initiateAutentication(self, request: IRequest, content: dict) -> dict: + """See ES9+ InitiateAuthentication SGP.22 Section 5.6.1""" + # 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'] != self.server_hostname: + raise ApiError('8.8.1', '3.8', 'Invalid SM-DP+ Address') + + euiccChallenge = b64decode(content['euiccChallenge']) + if len(euiccChallenge) != 16: + raise ValueError + + euiccInfo1_bin = b64decode(content['euiccInfo1']) + euiccInfo1 = rsp.asn1.decode('EUICCInfo1', euiccInfo1_bin) + print("Rx euiccInfo1: %s" % euiccInfo1) + #euiccInfo1['svn'] + + # TODO: If euiccCiPKIdListForSigningV3 is present ... + + pkid_list = euiccInfo1['euiccCiPKIdListForSigning'] + if 'euiccCiPKIdListForSigningV3' in euiccInfo1: + pkid_list = pkid_list + euiccInfo1['euiccCiPKIdListForSigningV3'] + # verify it supports one of the keys indicated by euiccCiPKIdListForSigning + if not any(self.ci_get_cert_for_pkid(x) for x in pkid_list): + raise ApiError('8.8.2', '3.1', 'None of the proposed Public Key Identifiers is supported by the SM-DP+') + + # 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'] + # raise ApiError('8.8.4', '3.7', 'The SM-DP+ has no CERT.DPauth.SIG which chains to one of the eSIM CA Root CA CErtificate with a Public Key supported by the eUICC') + + # 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 + assert not transactionId in self.rss + + # 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': self.server_hostname, + 'serverChallenge': serverChallenge, + } + print("Tx serverSigned1: %s" % serverSigned1) + serverSigned1_bin = rsp.asn1.encode('ServerSigned1', serverSigned1) + print("Tx serverSigned1: %s" % rsp.asn1.decode('ServerSigned1', serverSigned1_bin)) + output = {} + 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.dp_auth.ecdsa_sign(serverSigned1_bin)) + + output['transactionId'] = transactionId + server_cert_aki = self.dp_auth.get_authority_key_identifier() + output['euiccCiPKIdToBeUsed'] = b64encode2str(b'\x04\x14' + server_cert_aki.key_identifier) + output['serverCertificate'] = b64encode2str(self.dp_auth.get_cert_as_der()) # CERT.DPauth.SIG + # FIXME: add those certificate + #output['otherCertsInChain'] = b64encode2str() + + # create SessionState and store it in rss + self.rss[transactionId] = rsp.RspSessionState(transactionId, serverChallenge) + + return output + + @app.route('/gsma/rsp2/es9plus/authenticateClient', methods=['POST']) + @rsp_api_wrapper + def authenticateClient(self, request: IRequest, content: dict) -> dict: + """See ES9+ AuthenticateClient in SGP.22 Section 5.6.3""" + transactionId = content['transactionId'] + + authenticateServerResp_bin = b64decode(content['authenticateServerResponse']) + authenticateServerResp = rsp.asn1.decode('AuthenticateServerResponse', authenticateServerResp_bin) + print("Rx %s: %s" % authenticateServerResp) + if authenticateServerResp[0] == 'authenticateResponseError': + r_err = authenticateServerResp[1] + #r_err['transactionId'] + #r_err['authenticateErrorCode'] + raise ValueError("authenticateResponseError %s" % r_err) + + r_ok = authenticateServerResp[1] + euiccSigned1 = r_ok['euiccSigned1'] + # TODO: use original data, don't re-encode? + euiccSigned1_bin = rsp.asn1.encode('EuiccSigned1', euiccSigned1) + euiccSignature1_bin = r_ok['euiccSignature1'] + euiccCertificate_dec = r_ok['euiccCertificate'] + # TODO: use original data, don't re-encode? + euiccCertificate_bin = rsp.asn1.encode('Certificate', euiccCertificate_dec) + eumCertificate_dec = r_ok['eumCertificate'] + eumCertificate_bin = rsp.asn1.encode('Certificate', eumCertificate_dec) + # TODO v3: otherCertsInChain + + # load certificate + euicc_cert = x509.load_der_x509_certificate(euiccCertificate_bin) + eum_cert = x509.load_der_x509_certificate(eumCertificate_bin) + + # TODO: Verify the validity of the eUICC certificate chain + # raise ApiError('8.1.3', '6.1', 'Verification failed') + # raise ApiError('8.1.3', '6.3', 'Expired') + + # TODO: Verify that the Root Certificate of the eUICC certificate chain corresponds to the + # euiccCiPKIdToBeUsed or euiccCiPKIdToBeUsedV3 + # raise ApiError('8.11.1', '3.9', 'Unknown') + + # Verify euiccSignature1 over euiccSigned1 using pubkey from euiccCertificate. + # Otherwise, the SM-DP+ SHALL return a status code "eUICC - Verification failed" + if not self._ecdsa_verify(euicc_cert, euiccSignature1_bin, euiccSigned1_bin): + raise ApiError('8.1', '6.1', 'Verification failed') + + # Verify that the transactionId is known and relates to an ongoing RSP session. Otherwise, the SM-DP+ + # SHALL return a status code "TransactionId - Unknown" + ss = self.rss.get(transactionId, None) + if ss is None: + raise ApiError('8.10.1', '3.9', 'Unknown') + ss.euicc_cert = euicc_cert + ss.eum_cert = eum_cert # do we need this in the state? + + # TODO: verify eUICC cert is signed by EUM cert + # TODO: verify EUM cert is signed by CI cert + # TODO: verify EID of eUICC cert is within permitted range of EUM cert + + ss.eid = ss.euicc_cert.subject.get_attributes_for_oid(x509.oid.NameOID.SERIAL_NUMBER)[0].value + print("EID (from eUICC cert): %s" % ss.eid) + + # Verify that the serverChallenge attached to the ongoing RSP session matches the + # serverChallenge returned by the eUICC. Otherwise, the SM-DP+ SHALL return a status code "eUICC - + # Verification failed". + if euiccSigned1['serverChallenge'] != ss.serverChallenge: + raise ApiError('8.1', '6.1', 'Verification failed') + + # Put together profileMetadata + _bin + ss.profileMetadata = ProfileMetadata(iccid_bin= h2b(swap_nibbles('89000123456789012358')), spn="OsmocomSPN", profile_name="OsmocomProfile") + profileMetadata_bin = ss.profileMetadata.gen_store_metadata_request() + + # Put together smdpSigned2 + _bin + smdpSigned2 = { + 'transactionId': h2b(ss.transactionId), + 'ccRequiredFlag': False, # whether the Confirmation Code is required + #'bppEuiccOtpk': None, # whether otPK.EUICC.ECKA already used for binding the BPP, tag '5F49' + } + smdpSigned2_bin = rsp.asn1.encode('SmdpSigned2', smdpSigned2) + + ss.smdpSignature2_do = b'\x5f\x37\x40' + self.dp_pb.ecdsa_sign(smdpSigned2_bin + b'\x5f\x37\x40' + euiccSignature1_bin) + + # update non-volatile state with updated ss object + self.rss[transactionId] = ss + return { + 'transactionId': transactionId, + 'profileMetadata': b64encode2str(profileMetadata_bin), + 'smdpSigned2': b64encode2str(smdpSigned2_bin), + 'smdpSignature2': b64encode2str(ss.smdpSignature2_do), + 'smdpCertificate': b64encode2str(self.dp_pb.get_cert_as_der()), # CERT.DPpb.SIG + } + + @app.route('/gsma/rsp2/es9plus/getBoundProfilePackage', methods=['POST']) + @rsp_api_wrapper + def getBoundProfilePackage(self, request: IRequest, content: dict) -> dict: + """See ES9+ GetBoundProfilePackage SGP.22 Section 5.6.2""" + transactionId = content['transactionId'] + + # Verify that the received transactionId is known and relates to an ongoing RSP session + ss = self.rss.get(transactionId, None) + if not ss: + raise ApiError('8.10.1', '3.9', 'The RSP session identified by the TransactionID is unknown') + + prepDownloadResp_bin = b64decode(content['prepareDownloadResponse']) + prepDownloadResp = rsp.asn1.decode('PrepareDownloadResponse', prepDownloadResp_bin) + print("Rx %s: %s" % prepDownloadResp) + + if prepDownloadResp[0] == 'downloadResponseError': + r_err = prepDownloadResp[1] + #r_err['transactionId'] + #r_err['downloadErrorCode'] + raise ValueError("downloadResponseError %s" % r_err) + + r_ok = prepDownloadResp[1] + + # Verify the euiccSignature2 computed over euiccSigned2 and smdpSignature2 using the PK.EUICC.SIG attached to the ongoing RSP session + euiccSigned2 = r_ok['euiccSigned2'] + # TODO: use original data, don't re-encode? + euiccSigned2_bin = rsp.asn1.encode('EUICCSigned2', euiccSigned2) + if not self._ecdsa_verify(ss.euicc_cert, r_ok['euiccSignature2'], euiccSigned2_bin + ss.smdpSignature2_do): + raise ApiError('8.1', '6.1', 'eUICC signature is invalid') + + # not in spec: Verify that signed TransactionID is outer transaction ID + if h2b(transactionId) != euiccSigned2['transactionId']: + raise ApiError('8.10.1', '3.9', 'The signed transactionId != outer transactionId') + + # store otPK.EUICC.ECKA in session state + ss.euicc_otpk = euiccSigned2['euiccOtpk'] + print("euiccOtpk: %s" % (b2h(ss.euicc_otpk))) + + # Generate a one-time ECKA key pair (ot{PK,SK}.DP.ECKA) using the curve indicated by the Key Parameter + # Reference value of CERT.DPpb.ECDDSA + print("curve = %s" % self.dp_pb.get_curve()) + ss.smdp_ot = ec.generate_private_key(self.dp_pb.get_curve()) + # extract the public key in (hopefully) the right format for the ES8+ interface + ss.smdp_otpk = ss.smdp_ot.public_key().public_bytes(Encoding.X962, PublicFormat.UncompressedPoint) + print("smdpOtpk: %s" % b2h(ss.smdp_otpk)) + print("smdpOtsk: %s" % b2h(ss.smdp_ot.private_bytes(Encoding.DER, PrivateFormat.PKCS8, NoEncryption()))) + + ss.host_id = b'mahlzeit' + + # Generate Session Keys using the CRT, opPK.eUICC.ECKA and otSK.DP.ECKA according to annex G + euicc_public_key = ec.EllipticCurvePublicKey.from_encoded_point(ss.smdp_ot.curve, ss.euicc_otpk) + ss.shared_secret = ss.smdp_ot.exchange(ec.ECDH(), euicc_public_key) + print("shared_secret: %s" % b2h(ss.shared_secret)) + + # TODO: Check if this order requires a Confirmation Code verification + + # Perform actual protection + binding of profile package (or return pre-bound one) + with open(os.path.join(DATA_DIR, 'upp', 'TS48 V2 eSIM_GTP_SAIP2.1_NoBERTLV.rename2der'), 'rb') as f: + upp = UnprotectedProfilePackage.from_der(f.read(), metadata=ss.profileMetadata) + # HACK: Use empty PPP as we're still debuggin the configureISDP step, and we want to avoid + # cluttering the log with stuff happening after the failure + #upp = UnprotectedProfilePackage.from_der(b'', metadata=ss.profileMetadata) + if False: + # Use random keys + bpp = BoundProfilePackage.from_upp(upp) + else: + # Use sesssion keys + ppp = ProtectedProfilePackage.from_upp(upp, BspInstance(b'\x00'*16, b'\x11'*16, b'\x22'*16)) + bpp = BoundProfilePackage.from_ppp(ppp) + + # update non-volatile state with updated ss object + self.rss[transactionId] = ss + return { + 'transactionId': transactionId, + 'boundProfilePackage': b64encode2str(bpp.encode(ss, self.dp_pb)), + } + + @app.route('/gsma/rsp2/es9plus/handleNotification', methods=['POST']) + @rsp_api_wrapper + def handleNotification(self, request: IRequest, content: dict) -> dict: + """See ES9+ HandleNotification in SGP.22 Section 5.6.4""" + pendingNotification_bin = b64decode(content['pendingNotification']) + pendingNotification = rsp.asn1.decode('PendingNotification', pendingNotification_bin) + print("Rx %s: %s" % pendingNotification) + if pendingNotification[0] == 'profileInstallationResult': + profileInstallRes = pendingNotification[1] + pird = profileInstallRes['profileInstallationResultData'] + transactionId = b2h(pird['transactionId']) + ss = self.rss.get(transactionId, None) + if ss is None: + print("Unable to find session for transactionId") + return + profileInstallRes['euiccSignPIR'] + # TODO: use original data, don't re-encode? + pird_bin = rsp.asn1.encode('ProfileInstallationResultData', pird) + # verify eUICC signature + if not self._ecdsa_verify(ss.euicc_cert, profileInstallRes['euiccSignPIR'], pird_bin): + print("Unable to verify eUICC signature") + print("Profile Installation Final Result: ", pird['finalResult']) + # remove session state + del self.rss[transactionId] + elif pendingNotification[0] == 'otherSignedNotification': + # TODO + pass + else: + raise ValueError(pendingNotification) + + #(a)app.route('/gsma/rsp3/es9plus/handleDeviceChangeRequest, methods=['POST']') + #@rsp_api_wrapper + #"""See ES9+ ConfirmDeviceChange in SGP.22 Section 5.6.6""" + # TODO: implement this + + @app.route('/gsma/rsp2/es9plus/cancelSession', methods=['POST']) + @rsp_api_wrapper + def cancelSession(self, request: IRequest, content: dict) -> dict: + """See ES9+ CancelSession in SGP.22 Section 5.6.5""" + print("Rx JSON: %s" % content) + transactionId = content['transactionId'] + + # Verify that the received transactionId is known and relates to an ongoing RSP session + ss = self.rss.get(transactionId, None) + if ss is None: + raise ApiError('8.10.1', '3.9', 'The RSP session identified by the transactionId is unknown') + + cancelSessionResponse_bin = b64decode(content['cancelSessionResponse']) + cancelSessionResponse = rsp.asn1.decode('CancelSessionResponse', cancelSessionResponse_bin) + print("Rx %s: %s" % cancelSessionResponse) + + if cancelSessionResponse[0] == 'cancelSessionResponseError': + # FIXME: print some error + return + cancelSessionResponseOk = cancelSessionResponse[1] + # TODO: use original data, don't re-encode? + ecsr = cancelSessionResponseOk['euiccCancelSessionSigned'] + ecsr_bin = rsp.asn1.encode('EuiccCancelSessionSigned', ecsr) + # Verify the eUICC signature (euiccCancelSessionSignature) using the PK.EUICC.SIG attached to the ongoing RSP session + if not self._ecdsa_verify(ss.euicc_cert, cancelSessionResponseOk['euiccCancelSessionSignature'], ecsr_bin): + raise ApiError('8.1', '6.1', 'eUICC signature is invalid') + + # Verify that the received smdpOid corresponds to the one in SM-DP+ CERT.DPauth.SIG + subj_alt_name = self.dp_auth.get_subject_alt_name() + if x509.ObjectIdentifier(ecsr['smdpOid']) != subj_alt_name.oid: + raise ApiError('8.8', '3.10', 'The provided SM-DP+ OID is invalid.') + + if ecsr['transactionId'] != h2b(transactionId): + raise ApiError('8.10.1', '3.9', 'The signed transactionId != outer transactionId') + + # TODO: 1. Notify the Operator using the function "ES2+.HandleNotification" function + # TODO: 2. Terminate the corresponding pending download process. + # TODO: 3. If required, execute the SM-DS Event Deletion procedure described in section 3.6.3. + + # delete actual session data + del self.rss[transactionId] + return { 'transactionId': transactionId } + + +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(HOSTNAME, os.path.join(DATA_DIR, 'certs', 'CertificateIssuer'), use_brainpool=True) + #hs.app.run(endpoint_description="ssl:port=8000:dhParameters=dh_param_2048.pem") + hs.app.run("localhost", 8000) + +if __name__ == "__main__": + main(sys.argv) diff --git a/pySim/esim/__init__.py b/pySim/esim/__init__.py index e69de29..4d6c609 100644 --- a/pySim/esim/__init__.py +++ b/pySim/esim/__init__.py @@ -0,0 +1,16 @@ +import sys +from importlib import resources + +import asn1tools + +def compile_asn1_subdir(subdir_name:str): + """Helper function that compiles ASN.1 syntax from all files within given subdir""" + asn_txt = '' + __ver = sys.version_info + if (__ver.major, __ver.minor) >= (3, 9): + for i in resources.files('pySim.esim').joinpath('asn1').joinpath(subdir_name).iterdir(): + asn_txt += i.read_text() + asn_txt += "\n" + #else: + #print(resources.read_text(__name__, 'asn1/rsp.asn')) + return asn1tools.compile_string(asn_txt, codec='der') diff --git a/pySim/esim/asn1/rsp/PKIX1Explicit88.asn b/pySim/esim/asn1/rsp/PKIX1Explicit88.asn new file mode 100644 index 0000000..9284c65 --- /dev/null +++ b/pySim/esim/asn1/rsp/PKIX1Explicit88.asn @@ -0,0 +1,657 @@ +PKIX1Explicit88 { iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-explicit(18) } + +DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +-- EXPORTS ALL -- + +-- IMPORTS NONE -- + +-- UNIVERSAL Types defined in 1993 and 1998 ASN.1 +-- and required by this specification + +-- pycrate: UniversalString, BMPString and UTF8String already in the builtin types + +--UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING + -- UniversalString is defined in ASN.1:1993 + +--BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING + -- BMPString is the subtype of UniversalString and models + -- the Basic Multilingual Plane of ISO/IEC 10646 + +--UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING + -- The content of this type conforms to RFC 3629. + +-- PKIX specific OIDs + +id-pkix OBJECT IDENTIFIER ::= + { iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) } + +-- PKIX arcs + +id-pe OBJECT IDENTIFIER ::= { id-pkix 1 } + -- arc for private certificate extensions +id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + -- arc for policy qualifier types +id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } + -- arc for extended key purpose OIDS +id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } + -- arc for access descriptors + +-- policyQualifierIds for Internet policy qualifiers + +id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + -- OID for CPS qualifier +id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + -- OID for user notice qualifier + +-- access descriptor definitions + +id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } +id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } +id-ad-timeStamping OBJECT IDENTIFIER ::= { id-ad 3 } +id-ad-caRepository OBJECT IDENTIFIER ::= { id-ad 5 } + +-- attribute data types + +Attribute ::= SEQUENCE { + type AttributeType, + values SET OF AttributeValue } + -- at least one value is required + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= ANY -- DEFINED BY AttributeType + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + +-- suggested naming attributes: Definition of the following +-- information object set may be augmented to meet local +-- requirements. Note that deleting members of the set may +-- prevent interoperability with conforming implementations. +-- presented in pairs: the AttributeType followed by the +-- type definition for the corresponding AttributeValue + +-- Arc for standard naming attributes + +id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 } + +-- Naming attributes of type X520name + +id-at-name AttributeType ::= { id-at 41 } +id-at-surname AttributeType ::= { id-at 4 } +id-at-givenName AttributeType ::= { id-at 42 } +id-at-initials AttributeType ::= { id-at 43 } +id-at-generationQualifier AttributeType ::= { id-at 44 } + +-- Naming attributes of type X520Name: +-- X520name ::= DirectoryString (SIZE (1..ub-name)) +-- +-- Expanded to avoid parameterized type: +X520name ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-name)), + printableString PrintableString (SIZE (1..ub-name)), + universalString UniversalString (SIZE (1..ub-name)), + utf8String UTF8String (SIZE (1..ub-name)), + bmpString BMPString (SIZE (1..ub-name)) } + +-- Naming attributes of type X520CommonName + +id-at-commonName AttributeType ::= { id-at 3 } + +-- Naming attributes of type X520CommonName: +-- X520CommonName ::= DirectoryName (SIZE (1..ub-common-name)) +-- +-- Expanded to avoid parameterized type: +X520CommonName ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-common-name)), + printableString PrintableString (SIZE (1..ub-common-name)), + universalString UniversalString (SIZE (1..ub-common-name)), + utf8String UTF8String (SIZE (1..ub-common-name)), + bmpString BMPString (SIZE (1..ub-common-name)) } + +-- Naming attributes of type X520LocalityName + +id-at-localityName AttributeType ::= { id-at 7 } + +-- Naming attributes of type X520LocalityName: +-- X520LocalityName ::= DirectoryName (SIZE (1..ub-locality-name)) +-- +-- Expanded to avoid parameterized type: +X520LocalityName ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-locality-name)), + printableString PrintableString (SIZE (1..ub-locality-name)), + universalString UniversalString (SIZE (1..ub-locality-name)), + utf8String UTF8String (SIZE (1..ub-locality-name)), + bmpString BMPString (SIZE (1..ub-locality-name)) } + +-- Naming attributes of type X520StateOrProvinceName + +id-at-stateOrProvinceName AttributeType ::= { id-at 8 } + +-- Naming attributes of type X520StateOrProvinceName: +-- X520StateOrProvinceName ::= DirectoryName (SIZE (1..ub-state-name)) +-- +-- Expanded to avoid parameterized type: +X520StateOrProvinceName ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-state-name)), + printableString PrintableString (SIZE (1..ub-state-name)), + universalString UniversalString (SIZE (1..ub-state-name)), + utf8String UTF8String (SIZE (1..ub-state-name)), + bmpString BMPString (SIZE (1..ub-state-name)) } + +-- Naming attributes of type X520OrganizationName + +id-at-organizationName AttributeType ::= { id-at 10 } + +-- Naming attributes of type X520OrganizationName: +-- X520OrganizationName ::= +-- DirectoryName (SIZE (1..ub-organization-name)) +-- +-- Expanded to avoid parameterized type: +X520OrganizationName ::= CHOICE { + teletexString TeletexString + (SIZE (1..ub-organization-name)), + printableString PrintableString + (SIZE (1..ub-organization-name)), + universalString UniversalString + (SIZE (1..ub-organization-name)), + utf8String UTF8String + (SIZE (1..ub-organization-name)), + bmpString BMPString + (SIZE (1..ub-organization-name)) } + +-- Naming attributes of type X520OrganizationalUnitName + +id-at-organizationalUnitName AttributeType ::= { id-at 11 } + +-- Naming attributes of type X520OrganizationalUnitName: +-- X520OrganizationalUnitName ::= +-- DirectoryName (SIZE (1..ub-organizational-unit-name)) +-- +-- Expanded to avoid parameterized type: +X520OrganizationalUnitName ::= CHOICE { + teletexString TeletexString + (SIZE (1..ub-organizational-unit-name)), + printableString PrintableString + (SIZE (1..ub-organizational-unit-name)), + universalString UniversalString + (SIZE (1..ub-organizational-unit-name)), + utf8String UTF8String + (SIZE (1..ub-organizational-unit-name)), + bmpString BMPString + (SIZE (1..ub-organizational-unit-name)) } + +-- Naming attributes of type X520Title + +id-at-title AttributeType ::= { id-at 12 } + +-- Naming attributes of type X520Title: +-- X520Title ::= DirectoryName (SIZE (1..ub-title)) +-- +-- Expanded to avoid parameterized type: +X520Title ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-title)), + printableString PrintableString (SIZE (1..ub-title)), + universalString UniversalString (SIZE (1..ub-title)), + utf8String UTF8String (SIZE (1..ub-title)), + bmpString BMPString (SIZE (1..ub-title)) } + +-- Naming attributes of type X520dnQualifier + +id-at-dnQualifier AttributeType ::= { id-at 46 } + +X520dnQualifier ::= PrintableString + +-- Naming attributes of type X520countryName (digraph from IS 3166) + +id-at-countryName AttributeType ::= { id-at 6 } + +X520countryName ::= PrintableString (SIZE (2)) + +-- Naming attributes of type X520SerialNumber + +id-at-serialNumber AttributeType ::= { id-at 5 } + +X520SerialNumber ::= PrintableString (SIZE (1..ub-serial-number)) + +-- Naming attributes of type X520Pseudonym + +id-at-pseudonym AttributeType ::= { id-at 65 } + +-- Naming attributes of type X520Pseudonym: +-- X520Pseudonym ::= DirectoryName (SIZE (1..ub-pseudonym)) +-- +-- Expanded to avoid parameterized type: +X520Pseudonym ::= CHOICE { + teletexString TeletexString (SIZE (1..ub-pseudonym)), + printableString PrintableString (SIZE (1..ub-pseudonym)), + universalString UniversalString (SIZE (1..ub-pseudonym)), + utf8String UTF8String (SIZE (1..ub-pseudonym)), + bmpString BMPString (SIZE (1..ub-pseudonym)) } + +-- Naming attributes of type DomainComponent (from RFC 4519) + +id-domainComponent AttributeType ::= { 0 9 2342 19200300 100 1 25 } + +DomainComponent ::= IA5String + +-- Legacy attributes + +pkcs-9 OBJECT IDENTIFIER ::= + { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } + +id-emailAddress AttributeType ::= { pkcs-9 1 } + +EmailAddress ::= IA5String (SIZE (1..ub-emailaddress-length)) + +-- naming data types -- + +Name ::= CHOICE { -- only one possibility for now -- + rdnSequence RDNSequence } + +RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + +DistinguishedName ::= RDNSequence + +RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + +-- Directory string type -- + +DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1..MAX)), + bmpString BMPString (SIZE (1..MAX)) } + +-- certificate and CRL specific structures begin here + +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertificate ::= SEQUENCE { + version [0] Version DEFAULT v1, + serialNumber CertificateSerialNumber, + signature AlgorithmIdentifier, + issuer Name, + validity Validity, + subject Name, + subjectPublicKeyInfo SubjectPublicKeyInfo, + issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version MUST be v2 or v3 + subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + -- If present, version MUST be v2 or v3 + extensions [3] Extensions OPTIONAL + -- If present, version MUST be v3 -- } + +Version ::= INTEGER { v1(0), v2(1), v3(2) } + +CertificateSerialNumber ::= INTEGER + +Validity ::= SEQUENCE { + notBefore Time, + notAfter Time } + +Time ::= CHOICE { + utcTime UTCTime, + generalTime GeneralizedTime } + +UniqueIdentifier ::= BIT STRING + +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING } + +Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING + -- contains the DER encoding of an ASN.1 value + -- corresponding to the extension type identified + -- by extnID + } + +-- CRL structures + +CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING } + +TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, MUST be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, version MUST be v2 + } OPTIONAL, + crlExtensions [0] Extensions OPTIONAL } + -- if present, version MUST be v2 + +-- Version, Time, CertificateSerialNumber, and Extensions were +-- defined earlier for use in the certificate structure + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + -- contains a value of the type + -- registered for use with the + -- algorithm object identifier value + +-- X.400 address syntax starts here + +ORAddress ::= SEQUENCE { + built-in-standard-attributes BuiltInStandardAttributes, + built-in-domain-defined-attributes + BuiltInDomainDefinedAttributes OPTIONAL, + -- see also teletex-domain-defined-attributes + extension-attributes ExtensionAttributes OPTIONAL } + +-- Built-in Standard Attributes + +BuiltInStandardAttributes ::= SEQUENCE { + country-name CountryName OPTIONAL, + administration-domain-name AdministrationDomainName OPTIONAL, + network-address [0] IMPLICIT NetworkAddress OPTIONAL, + -- see also extended-network-address + terminal-identifier [1] IMPLICIT TerminalIdentifier OPTIONAL, + private-domain-name [2] PrivateDomainName OPTIONAL, + organization-name [3] IMPLICIT OrganizationName OPTIONAL, + -- see also teletex-organization-name + numeric-user-identifier [4] IMPLICIT NumericUserIdentifier + OPTIONAL, + personal-name [5] IMPLICIT PersonalName OPTIONAL, + -- see also teletex-personal-name + organizational-unit-names [6] IMPLICIT OrganizationalUnitNames + OPTIONAL } + -- see also teletex-organizational-unit-names + +CountryName ::= [APPLICATION 1] CHOICE { + x121-dcc-code NumericString + (SIZE (ub-country-name-numeric-length)), + iso-3166-alpha2-code PrintableString + (SIZE (ub-country-name-alpha-length)) } + +AdministrationDomainName ::= [APPLICATION 2] CHOICE { + numeric NumericString (SIZE (0..ub-domain-name-length)), + printable PrintableString (SIZE (0..ub-domain-name-length)) } + +NetworkAddress ::= X121Address -- see also extended-network-address + +X121Address ::= NumericString (SIZE (1..ub-x121-address-length)) + +TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length)) + +PrivateDomainName ::= CHOICE { + numeric NumericString (SIZE (1..ub-domain-name-length)), + printable PrintableString (SIZE (1..ub-domain-name-length)) } + +OrganizationName ::= PrintableString + (SIZE (1..ub-organization-name-length)) + -- see also teletex-organization-name + +NumericUserIdentifier ::= NumericString + (SIZE (1..ub-numeric-user-id-length)) + +PersonalName ::= SET { + surname [0] IMPLICIT PrintableString + (SIZE (1..ub-surname-length)), + given-name [1] IMPLICIT PrintableString + (SIZE (1..ub-given-name-length)) OPTIONAL, + initials [2] IMPLICIT PrintableString + (SIZE (1..ub-initials-length)) OPTIONAL, + generation-qualifier [3] IMPLICIT PrintableString + (SIZE (1..ub-generation-qualifier-length)) + OPTIONAL } + -- see also teletex-personal-name + +OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units) + OF OrganizationalUnitName + -- see also teletex-organizational-unit-names + +OrganizationalUnitName ::= PrintableString (SIZE + (1..ub-organizational-unit-name-length)) + +-- Built-in Domain-defined Attributes + +BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE + (1..ub-domain-defined-attributes) OF + BuiltInDomainDefinedAttribute + +BuiltInDomainDefinedAttribute ::= SEQUENCE { + type PrintableString (SIZE + (1..ub-domain-defined-attribute-type-length)), + value PrintableString (SIZE + (1..ub-domain-defined-attribute-value-length)) } + +-- Extension Attributes + +ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF + ExtensionAttribute + +ExtensionAttribute ::= SEQUENCE { + extension-attribute-type [0] IMPLICIT INTEGER + (0..ub-extension-attributes), + extension-attribute-value [1] + ANY DEFINED BY extension-attribute-type } + +-- Extension types and attribute values + +common-name INTEGER ::= 1 + +CommonName ::= PrintableString (SIZE (1..ub-common-name-length)) + +teletex-common-name INTEGER ::= 2 + +TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length)) + +teletex-organization-name INTEGER ::= 3 + +TeletexOrganizationName ::= + TeletexString (SIZE (1..ub-organization-name-length)) + +teletex-personal-name INTEGER ::= 4 + +TeletexPersonalName ::= SET { + surname [0] IMPLICIT TeletexString + (SIZE (1..ub-surname-length)), + given-name [1] IMPLICIT TeletexString + (SIZE (1..ub-given-name-length)) OPTIONAL, + initials [2] IMPLICIT TeletexString + (SIZE (1..ub-initials-length)) OPTIONAL, + generation-qualifier [3] IMPLICIT TeletexString + (SIZE (1..ub-generation-qualifier-length)) + OPTIONAL } + +teletex-organizational-unit-names INTEGER ::= 5 + +TeletexOrganizationalUnitNames ::= SEQUENCE SIZE + (1..ub-organizational-units) OF TeletexOrganizationalUnitName + +TeletexOrganizationalUnitName ::= TeletexString + (SIZE (1..ub-organizational-unit-name-length)) + +pds-name INTEGER ::= 7 + +PDSName ::= PrintableString (SIZE (1..ub-pds-name-length)) + +physical-delivery-country-name INTEGER ::= 8 + +PhysicalDeliveryCountryName ::= CHOICE { + x121-dcc-code NumericString (SIZE (ub-country-name-numeric-length)), + iso-3166-alpha2-code PrintableString + (SIZE (ub-country-name-alpha-length)) } + +postal-code INTEGER ::= 9 + +PostalCode ::= CHOICE { + numeric-code NumericString (SIZE (1..ub-postal-code-length)), + printable-code PrintableString (SIZE (1..ub-postal-code-length)) } + +physical-delivery-office-name INTEGER ::= 10 + +PhysicalDeliveryOfficeName ::= PDSParameter + +physical-delivery-office-number INTEGER ::= 11 + +PhysicalDeliveryOfficeNumber ::= PDSParameter + +extension-OR-address-components INTEGER ::= 12 + +ExtensionORAddressComponents ::= PDSParameter + +physical-delivery-personal-name INTEGER ::= 13 + +PhysicalDeliveryPersonalName ::= PDSParameter + +physical-delivery-organization-name INTEGER ::= 14 + +PhysicalDeliveryOrganizationName ::= PDSParameter + +extension-physical-delivery-address-components INTEGER ::= 15 + +ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter + +unformatted-postal-address INTEGER ::= 16 + +UnformattedPostalAddress ::= SET { + printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines) + OF PrintableString (SIZE (1..ub-pds-parameter-length)) OPTIONAL, + teletex-string TeletexString + (SIZE (1..ub-unformatted-address-length)) OPTIONAL } + +street-address INTEGER ::= 17 + +StreetAddress ::= PDSParameter + +post-office-box-address INTEGER ::= 18 + +PostOfficeBoxAddress ::= PDSParameter + +poste-restante-address INTEGER ::= 19 + +PosteRestanteAddress ::= PDSParameter + +unique-postal-name INTEGER ::= 20 + +UniquePostalName ::= PDSParameter + +local-postal-attributes INTEGER ::= 21 + +LocalPostalAttributes ::= PDSParameter + +PDSParameter ::= SET { + printable-string PrintableString + (SIZE(1..ub-pds-parameter-length)) OPTIONAL, + teletex-string TeletexString + (SIZE(1..ub-pds-parameter-length)) OPTIONAL } + +extended-network-address INTEGER ::= 22 + +ExtendedNetworkAddress ::= CHOICE { + e163-4-address SEQUENCE { + number [0] IMPLICIT NumericString + (SIZE (1..ub-e163-4-number-length)), + sub-address [1] IMPLICIT NumericString + (SIZE (1..ub-e163-4-sub-address-length)) + OPTIONAL }, + psap-address [0] IMPLICIT PresentationAddress } + +PresentationAddress ::= SEQUENCE { + pSelector [0] EXPLICIT OCTET STRING OPTIONAL, + sSelector [1] EXPLICIT OCTET STRING OPTIONAL, + tSelector [2] EXPLICIT OCTET STRING OPTIONAL, + nAddresses [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING } + +terminal-type INTEGER ::= 23 + +TerminalType ::= INTEGER { + telex (3), + teletex (4), + g3-facsimile (5), + g4-facsimile (6), + ia5-terminal (7), + videotex (8) } (0..ub-integer-options) + +-- Extension Domain-defined Attributes + +teletex-domain-defined-attributes INTEGER ::= 6 + +TeletexDomainDefinedAttributes ::= SEQUENCE SIZE + (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute + +TeletexDomainDefinedAttribute ::= SEQUENCE { + type TeletexString + (SIZE (1..ub-domain-defined-attribute-type-length)), + value TeletexString + (SIZE (1..ub-domain-defined-attribute-value-length)) } + +-- specifications of Upper Bounds MUST be regarded as mandatory +-- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter +-- Upper Bounds + +-- Upper Bounds +ub-name INTEGER ::= 32768 +ub-common-name INTEGER ::= 64 +ub-locality-name INTEGER ::= 128 +ub-state-name INTEGER ::= 128 +ub-organization-name INTEGER ::= 64 +ub-organizational-unit-name INTEGER ::= 64 +ub-title INTEGER ::= 64 +ub-serial-number INTEGER ::= 64 +ub-match INTEGER ::= 128 +ub-emailaddress-length INTEGER ::= 255 +ub-common-name-length INTEGER ::= 64 +ub-country-name-alpha-length INTEGER ::= 2 +ub-country-name-numeric-length INTEGER ::= 3 +ub-domain-defined-attributes INTEGER ::= 4 +ub-domain-defined-attribute-type-length INTEGER ::= 8 +ub-domain-defined-attribute-value-length INTEGER ::= 128 +ub-domain-name-length INTEGER ::= 16 +ub-extension-attributes INTEGER ::= 256 +ub-e163-4-number-length INTEGER ::= 15 +ub-e163-4-sub-address-length INTEGER ::= 40 +ub-generation-qualifier-length INTEGER ::= 3 +ub-given-name-length INTEGER ::= 16 +ub-initials-length INTEGER ::= 5 +ub-integer-options INTEGER ::= 256 +ub-numeric-user-id-length INTEGER ::= 32 +ub-organization-name-length INTEGER ::= 64 +ub-organizational-unit-name-length INTEGER ::= 32 +ub-organizational-units INTEGER ::= 4 +ub-pds-name-length INTEGER ::= 16 +ub-pds-parameter-length INTEGER ::= 30 +ub-pds-physical-address-lines INTEGER ::= 6 +ub-postal-code-length INTEGER ::= 16 +ub-pseudonym INTEGER ::= 128 +ub-surname-length INTEGER ::= 40 +ub-terminal-id-length INTEGER ::= 24 +ub-unformatted-address-length INTEGER ::= 180 +ub-x121-address-length INTEGER ::= 16 + +-- Note - upper bounds on string types, such as TeletexString, are +-- measured in characters. Excepting PrintableString or IA5String, a +-- significantly greater number of octets will be required to hold +-- such a value. As a minimum, 16 octets, or twice the specified +-- upper bound, whichever is the larger, should be allowed for +-- TeletexString. For UTF8String or UniversalString at least four +-- times the upper bound should be allowed. + +END + diff --git a/pySim/esim/asn1/rsp/PKIX1Implicit88.asn b/pySim/esim/asn1/rsp/PKIX1Implicit88.asn new file mode 100644 index 0000000..aafd785 --- /dev/null +++ b/pySim/esim/asn1/rsp/PKIX1Implicit88.asn @@ -0,0 +1,343 @@ +PKIX1Implicit88 { iso(1) identified-organization(3) dod(6) internet(1) + security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-implicit(19) } + +DEFINITIONS IMPLICIT TAGS ::= + +BEGIN + +-- EXPORTS ALL -- + +IMPORTS + id-pe, id-kp, id-qt-unotice, id-qt-cps, + ORAddress, Name, RelativeDistinguishedName, + CertificateSerialNumber, Attribute, DirectoryString + FROM PKIX1Explicit88 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) mechanisms(5) pkix(7) + id-mod(0) id-pkix1-explicit(18) }; + +-- ISO arc for standard certificate and CRL extensions + +id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} + +-- authority key identifier OID and syntax + +id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } + +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] KeyIdentifier OPTIONAL, + authorityCertIssuer [1] GeneralNames OPTIONAL, + authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + -- authorityCertIssuer and authorityCertSerialNumber MUST both + -- be present or both be absent + +KeyIdentifier ::= OCTET STRING + +-- subject key identifier OID and syntax + +id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } + +SubjectKeyIdentifier ::= KeyIdentifier + +-- key usage extension OID and syntax + +id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } + +KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), -- recent editions of X.509 have + -- renamed this bit to contentCommitment + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) } + +-- private key usage period extension OID and syntax + +id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-ce 16 } + +PrivateKeyUsagePeriod ::= SEQUENCE { + notBefore [0] GeneralizedTime OPTIONAL, + notAfter [1] GeneralizedTime OPTIONAL } + -- either notBefore or notAfter MUST be present + +-- certificate policies extension OID and syntax + +id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } + +anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } + +CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + +PolicyInformation ::= SEQUENCE { + policyIdentifier CertPolicyId, + policyQualifiers SEQUENCE SIZE (1..MAX) OF + PolicyQualifierInfo OPTIONAL } + +CertPolicyId ::= OBJECT IDENTIFIER + +PolicyQualifierInfo ::= SEQUENCE { + policyQualifierId PolicyQualifierId, + qualifier ANY DEFINED BY policyQualifierId } + +-- Implementations that recognize additional policy qualifiers MUST +-- augment the following definition for PolicyQualifierId + +PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) + +-- CPS pointer qualifier + +CPSuri ::= IA5String + +-- user notice qualifier + +UserNotice ::= SEQUENCE { + noticeRef NoticeReference OPTIONAL, + explicitText DisplayText OPTIONAL } + +NoticeReference ::= SEQUENCE { + organization DisplayText, + noticeNumbers SEQUENCE OF INTEGER } + +DisplayText ::= CHOICE { + ia5String IA5String (SIZE (1..200)), + visibleString VisibleString (SIZE (1..200)), + bmpString BMPString (SIZE (1..200)), + utf8String UTF8String (SIZE (1..200)) } + +-- policy mapping extension OID and syntax + +id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } + +PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + issuerDomainPolicy CertPolicyId, + subjectDomainPolicy CertPolicyId } + +-- subject alternative name extension OID and syntax + +id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } + +SubjectAltName ::= GeneralNames + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] AnotherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + +-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as +-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax + +AnotherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id } + +EDIPartyName ::= SEQUENCE { + nameAssigner [0] DirectoryString OPTIONAL, + partyName [1] DirectoryString } + +-- issuer alternative name extension OID and syntax + +id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } + +IssuerAltName ::= GeneralNames + +id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } + +SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + +-- basic constraints extension OID and syntax + +id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } + +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } + +-- name constraints extension OID and syntax + +id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } + +NameConstraints ::= SEQUENCE { + permittedSubtrees [0] GeneralSubtrees OPTIONAL, + excludedSubtrees [1] GeneralSubtrees OPTIONAL } + +GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + +GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] BaseDistance DEFAULT 0, + maximum [1] BaseDistance OPTIONAL } + +BaseDistance ::= INTEGER (0..MAX) + +-- policy constraints extension OID and syntax + +id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } + +PolicyConstraints ::= SEQUENCE { + requireExplicitPolicy [0] SkipCerts OPTIONAL, + inhibitPolicyMapping [1] SkipCerts OPTIONAL } + +SkipCerts ::= INTEGER (0..MAX) + +-- CRL distribution points extension OID and syntax + +id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31} + +CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + +DistributionPoint ::= SEQUENCE { + distributionPoint [0] DistributionPointName OPTIONAL, + reasons [1] ReasonFlags OPTIONAL, + cRLIssuer [2] GeneralNames OPTIONAL } + +DistributionPointName ::= CHOICE { + fullName [0] GeneralNames, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + +ReasonFlags ::= BIT STRING { + unused (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) } + +-- extended key usage extension OID and syntax + +id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37} + +ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + +KeyPurposeId ::= OBJECT IDENTIFIER + +-- permit unspecified key uses + +anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } + +-- extended key purpose OIDs + +id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } +id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } +id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } +id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } +id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } +id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } + +-- inhibit any policy OID and syntax + +id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } + +InhibitAnyPolicy ::= SkipCerts + +-- freshest (delta)CRL extension OID and syntax + +id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } + +FreshestCRL ::= CRLDistributionPoints + +-- authority info access + +id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } + +AuthorityInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +AccessDescription ::= SEQUENCE { + accessMethod OBJECT IDENTIFIER, + accessLocation GeneralName } + +-- subject info access + +id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 } + +SubjectInfoAccessSyntax ::= + SEQUENCE SIZE (1..MAX) OF AccessDescription + +-- CRL number extension OID and syntax + +id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } + +CRLNumber ::= INTEGER (0..MAX) + +-- issuing distribution point extension OID and syntax + +id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 } + +IssuingDistributionPoint ::= SEQUENCE { + distributionPoint [0] DistributionPointName OPTIONAL, + onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + onlySomeReasons [3] ReasonFlags OPTIONAL, + indirectCRL [4] BOOLEAN DEFAULT FALSE, + onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + -- at most one of onlyContainsUserCerts, onlyContainsCACerts, + -- and onlyContainsAttributeCerts may be set to TRUE. + +id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 } + +BaseCRLNumber ::= CRLNumber + +-- reason code extension OID and syntax + +id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 } + +CRLReason ::= ENUMERATED { + unspecified (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + removeFromCRL (8), + privilegeWithdrawn (9), + aACompromise (10) } + +-- certificate issuer CRL entry extension OID and syntax + +id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 } + +CertificateIssuer ::= GeneralNames + +-- hold instruction extension OID and syntax + +id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 } + +HoldInstructionCode ::= OBJECT IDENTIFIER + +-- ANSI x9 arc holdinstruction arc + +holdInstruction OBJECT IDENTIFIER ::= + {joint-iso-itu-t(2) member-body(2) us(840) x9cm(10040) 2} + +-- ANSI X9 holdinstructions + +id-holdinstruction-none OBJECT IDENTIFIER ::= + {holdInstruction 1} -- deprecated + +id-holdinstruction-callissuer OBJECT IDENTIFIER ::= {holdInstruction 2} + +id-holdinstruction-reject OBJECT IDENTIFIER ::= {holdInstruction 3} + +-- invalidity date CRL entry extension OID and syntax + +id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 } + +InvalidityDate ::= GeneralizedTime + +END + diff --git a/pySim/esim/asn1/rsp/rsp.asn b/pySim/esim/asn1/rsp/rsp.asn new file mode 100644 index 0000000..e87b74e --- /dev/null +++ b/pySim/esim/asn1/rsp/rsp.asn @@ -0,0 +1,785 @@ +RSPDefinitions {joint-iso-itu-t(2) international-organizations(23) gsma(146) rsp(1) spec-version(1) version-two(2)} +DEFINITIONS +AUTOMATIC TAGS +EXTENSIBILITY IMPLIED ::= +BEGIN + +IMPORTS Certificate, CertificateList, Time FROM PKIX1Explicit88 {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-explicit(18)} +SubjectKeyIdentifier FROM PKIX1Implicit88 {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-implicit(19)}; + +id-rsp OBJECT IDENTIFIER ::= {joint-iso-itu-t(2) international-organizations(23) gsma(146) rsp(1)} + +-- Basic types, for size constraints +Octet8 ::= OCTET STRING (SIZE(8)) +Octet16 ::= OCTET STRING (SIZE(16)) +OctetTo16 ::= OCTET STRING (SIZE(1..16)) +Octet32 ::= OCTET STRING (SIZE(32)) +Octet1 ::= OCTET STRING(SIZE(1)) +Octet2 ::= OCTET STRING (SIZE(2)) +VersionType ::= OCTET STRING(SIZE(3)) -- major/minor/revision version are coded as binary value on byte 1/2/3, e.g. '02 00 0C' for v2.0.12. +Iccid ::= [APPLICATION 26] OCTET STRING (SIZE(10)) -- ICCID as coded in EFiccid, corresponding tag is '5A' +RemoteOpId ::= [2] INTEGER {installBoundProfilePackage(1)} +TransactionId ::= OCTET STRING (SIZE(1..16)) + +-- Definition of EUICCInfo1 -------------------------- +GetEuiccInfo1Request ::= [32] SEQUENCE { -- Tag 'BF20' +} + +EUICCInfo1 ::= [32] SEQUENCE { -- Tag 'BF20' + svn [2] VersionType, -- GSMA SGP.22 version supported (SVN) + euiccCiPKIdListForVerification [9] SEQUENCE OF SubjectKeyIdentifier, -- List of CI Public Key Identifiers supported on the eUICC for signature verification + euiccCiPKIdListForSigning [10] SEQUENCE OF SubjectKeyIdentifier -- List of CI Public Key Identifier supported on the eUICC for signature creation +} + +-- Definition of EUICCInfo2 -------------------------- +GetEuiccInfo2Request ::= [34] SEQUENCE { -- Tag 'BF22' +} + +EUICCInfo2 ::= [34] SEQUENCE { -- Tag 'BF22' + profileVersion [1] VersionType, -- SIMAlliance Profile package version supported + svn [2] VersionType, -- GSMA SGP.22 version supported (SVN) + euiccFirmwareVer [3] VersionType, -- eUICC Firmware version + extCardResource [4] OCTET STRING, -- Extended Card Resource Information according to ETSI TS 102 226 + uiccCapability [5] UICCCapability, + javacardVersion [6] VersionType OPTIONAL, + globalplatformVersion [7] VersionType OPTIONAL, + rspCapability [8] RspCapability, + euiccCiPKIdListForVerification [9] SEQUENCE OF SubjectKeyIdentifier, -- List of CI Public Key Identifiers supported on the eUICC for signature verification + euiccCiPKIdListForSigning [10] SEQUENCE OF SubjectKeyIdentifier, -- List of CI Public Key Identifier supported on the eUICC for signature creation + euiccCategory [11] INTEGER { + other(0), + basicEuicc(1), + mediumEuicc(2), + contactlessEuicc(3) + } OPTIONAL, + forbiddenProfilePolicyRules [25] PprIds OPTIONAL, -- Tag '99' + ppVersion VersionType, -- Protection Profile version + sasAcreditationNumber UTF8String (SIZE(0..64)), + certificationDataObject [12] CertificationDataObject OPTIONAL +} + +-- Definition of RspCapability +RspCapability ::= BIT STRING { + additionalProfile(0), -- at least one more Profile can be installed + crlSupport(1), -- CRL + rpmSupport(2), -- Remote Profile Management + testProfileSupport (3) -- support for test profile +} + +-- Definition of CertificationDataObject +CertificationDataObject ::= SEQUENCE { + platformLabel UTF8String, -- Platform_Label as defined in GlobalPlatform DLOA specification [57] + discoveryBaseURL UTF8String -- Discovery Base URL of the SE default DLOA Registrar as defined in GlobalPlatform DLOA specification [57] +} + +CertificateInfo ::= BIT STRING { + + reserved(0), -- eUICC has a CERT.EUICC.ECDSA in GlobalPlatform format. The use of this bit is deprecated. + certSigningX509(1), -- eUICC has a CERT.EUICC.ECDSA in X.509 format + rfu2(2), + rfu3(3), + reserved2(4), -- Handling of Certificate in GlobalPlatform format. The use of this bit is deprecated. + certVerificationX509(5)-- Handling of Certificate in X.509 format +} + +-- Definition of UICCCapability +UICCCapability ::= BIT STRING { +/* Sequence is derived from ServicesList[] defined in SIMalliance PEDefinitions*/ + contactlessSupport(0), -- Contactless (SWP, HCI and associated APIs) + usimSupport(1), -- USIM as defined by 3GPP + isimSupport(2), -- ISIM as defined by 3GPP + csimSupport(3), -- CSIM as defined by 3GPP2 + + akaMilenage(4), -- Milenage as AKA algorithm + akaCave(5), -- CAVE as authentication algorithm + akaTuak128(6), -- TUAK as AKA algorithm with 128 bit key length + akaTuak256(7), -- TUAK as AKA algorithm with 256 bit key length + rfu1(8), -- reserved for further algorithms + rfu2(9), -- reserved for further algorithms + + gbaAuthenUsim(10), -- GBA authentication in the context of USIM + gbaAuthenISim(11), -- GBA authentication in the context of ISIM + mbmsAuthenUsim(12), -- MBMS authentication in the context of USIM + eapClient(13), -- EAP client + + javacard(14), -- Javacard support + multos(15), -- Multos support + + multipleUsimSupport(16), -- Multiple USIM applications are supported within the same Profile + multipleIsimSupport(17), -- Multiple ISIM applications are supported within the same Profile + multipleCsimSupport(18) -- Multiple CSIM applications are supported within the same Profile +} + +-- Definition of DeviceInfo +DeviceInfo ::= SEQUENCE { + tac Octet8, + deviceCapabilities DeviceCapabilities, + imei Octet8 OPTIONAL +} + +DeviceCapabilities ::= SEQUENCE { -- Highest fully supported release for each definition + -- The device SHALL set all the capabilities it supports + gsmSupportedRelease VersionType OPTIONAL, + utranSupportedRelease VersionType OPTIONAL, + cdma2000onexSupportedRelease VersionType OPTIONAL, + cdma2000hrpdSupportedRelease VersionType OPTIONAL, + cdma2000ehrpdSupportedRelease VersionType OPTIONAL, + eutranSupportedRelease VersionType OPTIONAL, + contactlessSupportedRelease VersionType OPTIONAL, + rspCrlSupportedVersion VersionType OPTIONAL, + rspRpmSupportedVersion VersionType OPTIONAL +} + +ProfileInfoListRequest ::= [45] SEQUENCE { -- Tag 'BF2D' + searchCriteria [0] CHOICE { + isdpAid [APPLICATION 15] OctetTo16, -- AID of the ISD-P, tag '4F' + iccid Iccid, -- ICCID, tag '5A' + profileClass [21] ProfileClass -- Tag '95' + } OPTIONAL, + tagList [APPLICATION 28] OCTET STRING OPTIONAL -- tag '5C' +} + +-- Definition of ProfileInfoList +ProfileInfoListResponse ::= [45] CHOICE { -- Tag 'BF2D' + profileInfoListOk SEQUENCE OF ProfileInfo, + profileInfoListError ProfileInfoListError +} + +ProfileInfo ::= [PRIVATE 3] SEQUENCE { -- Tag 'E3' + iccid Iccid OPTIONAL, + isdpAid [APPLICATION 15] OctetTo16 OPTIONAL, -- AID of the ISD-P containing the Profile, tag '4F' + profileState [112] ProfileState OPTIONAL, -- Tag '9F70' + profileNickname [16] UTF8String (SIZE(0..64)) OPTIONAL, -- Tag '90' + serviceProviderName [17] UTF8String (SIZE(0..32)) OPTIONAL, -- Tag '91' + profileName [18] UTF8String (SIZE(0..64)) OPTIONAL, -- Tag '92' + iconType [19] IconType OPTIONAL, -- Tag '93' + icon [20] OCTET STRING (SIZE(0..1024)) OPTIONAL, -- Tag '94', see condition in ES10c:GetProfilesInfo + profileClass [21] ProfileClass DEFAULT operational, -- Tag '95' + notificationConfigurationInfo [22] SEQUENCE OF NotificationConfigurationInformation OPTIONAL, -- Tag 'B6' + profileOwner [23] OperatorID OPTIONAL, -- Tag 'B7' + dpProprietaryData [24] DpProprietaryData OPTIONAL, -- Tag 'B8' + profilePolicyRules [25] PprIds OPTIONAL -- Tag '99' +} + +PprIds ::= BIT STRING {-- Definition of Profile Policy Rules identifiers + pprUpdateControl(0), -- defines how to update PPRs via ES6 + ppr1(1), -- Indicator for PPR1 'Disabling of this Profile is not allowed' + ppr2(2), -- Indicator for PPR2 'Deletion of this Profile is not allowed' + ppr3(3) -- Indicator for PPR3 'Deletion of this Profile is required upon its successful disabling' +} + +OperatorID ::= SEQUENCE { + mccMnc OCTET STRING (SIZE(3)), -- MCC and MNC coded as defined in 3GPP TS 24.008 [32] + gid1 OCTET STRING OPTIONAL, -- referring to content of EF GID1 (file identifier '6F3E') as defined in 3GPP TS 31.102 [54] + gid2 OCTET STRING OPTIONAL -- referring to content of EF GID2 (file identifier '6F3F') as defined in 3GPP TS 31.102 [54] +} + +ProfileInfoListError ::= INTEGER {incorrectInputValues(1), undefinedError(127)} + +-- Definition of StoreMetadata request + +StoreMetadataRequest ::= [37] SEQUENCE { -- Tag 'BF25' + iccid Iccid, + serviceProviderName [17] UTF8String (SIZE(0..32)), -- Tag '91' + profileName [18] UTF8String (SIZE(0..64)), -- Tag '92' (corresponds to 'Short Description' defined in SGP.21 [2]) + iconType [19] IconType OPTIONAL, -- Tag '93' (JPG or PNG) + icon [20] OCTET STRING (SIZE(0..1024)) OPTIONAL, -- Tag '94'(Data of the icon. Size 64 x 64 pixel. This field SHALL only be present if iconType is present) + profileClass [21] ProfileClass OPTIONAL, -- Tag '95' (default if absent: 'operational') + notificationConfigurationInfo [22] SEQUENCE OF NotificationConfigurationInformation OPTIONAL, + profileOwner [23] OperatorID OPTIONAL, -- Tag 'B7' + profilePolicyRules [25] PprIds OPTIONAL -- Tag '99' +} + +NotificationEvent ::= BIT STRING { + notificationInstall (0), + notificationEnable(1), + notificationDisable(2), + notificationDelete(3) +} + +NotificationConfigurationInformation ::= SEQUENCE { + profileManagementOperation NotificationEvent, + notificationAddress UTF8String -- FQDN to forward the notification +} + +IconType ::= INTEGER {jpg(0), png(1)} +ProfileState ::= INTEGER {disabled(0), enabled(1)} +ProfileClass ::= INTEGER {test(0), provisioning(1), operational(2)} + +-- Definition of UpdateMetadata request +UpdateMetadataRequest ::= [42] SEQUENCE { -- Tag 'BF2A' + serviceProviderName [17] UTF8String (SIZE(0..32)) OPTIONAL, -- Tag '91' + profileName [18] UTF8String (SIZE(0..64)) OPTIONAL, -- Tag '92' + iconType [19] IconType OPTIONAL, -- Tag '93' + icon [20] OCTET STRING (SIZE(0..1024)) OPTIONAL, -- Tag '94' + profilePolicyRules [25] PprIds OPTIONAL -- Tag '99' +} + +-- Definition of data objects for command PrepareDownload ------------------------- +PrepareDownloadRequest ::= [33] SEQUENCE { -- Tag 'BF21' + smdpSigned2 SmdpSigned2, -- Signed information + smdpSignature2 [APPLICATION 55] OCTET STRING, -- DP_Sign1, tag '5F37' + hashCc Octet32 OPTIONAL, -- Hash of confirmation code + smdpCertificate Certificate -- CERT.DPpb.ECDSA +} + +SmdpSigned2 ::= SEQUENCE { + transactionId [0] TransactionId, -- The TransactionID generated by the SM DP+ + ccRequiredFlag BOOLEAN, --Indicates if the Confirmation Code is required + bppEuiccOtpk [APPLICATION 73] OCTET STRING OPTIONAL -- otPK.EUICC.ECKA already used for binding the BPP, tag '5F49' +} + +PrepareDownloadResponse ::= [33] CHOICE { -- Tag 'BF21' + downloadResponseOk PrepareDownloadResponseOk, + downloadResponseError PrepareDownloadResponseError +} + +PrepareDownloadResponseOk ::= SEQUENCE { + euiccSigned2 EUICCSigned2, -- Signed information + euiccSignature2 [APPLICATION 55] OCTET STRING -- tag '5F37' +} + +EUICCSigned2 ::= SEQUENCE { + transactionId [0] TransactionId, + euiccOtpk [APPLICATION 73] OCTET STRING, -- otPK.EUICC.ECKA, tag '5F49' + hashCc Octet32 OPTIONAL -- Hash of confirmation code +} + +PrepareDownloadResponseError ::= SEQUENCE { + transactionId [0] TransactionId, + downloadErrorCode DownloadErrorCode +} + +DownloadErrorCode ::= INTEGER {invalidCertificate(1), invalidSignature(2), unsupportedCurve(3), noSessionContext(4), invalidTransactionId(5), undefinedError(127)} + +-- Definition of data objects for command AuthenticateServer-------------------- +AuthenticateServerRequest ::= [56] SEQUENCE { -- Tag 'BF38' + serverSigned1 ServerSigned1, -- Signed information + serverSignature1 [APPLICATION 55] OCTET STRING, -- tag ?5F37? + euiccCiPKIdToBeUsed SubjectKeyIdentifier, -- CI Public Key Identifier to be used + serverCertificate Certificate, -- RSP Server Certificate CERT.XXauth.ECDSA + ctxParams1 CtxParams1 +} + +ServerSigned1 ::= SEQUENCE { + transactionId [0] TransactionId, -- The Transaction ID generated by the RSP Server + euiccChallenge [1] Octet16, -- The eUICC Challenge + serverAddress [3] UTF8String, -- The RSP Server address + serverChallenge [4] Octet16 -- The RSP Server Challenge +} + +CtxParams1 ::= CHOICE { + ctxParamsForCommonAuthentication CtxParamsForCommonAuthentication -- New contextual data objects may be defined for extensibility +} + +CtxParamsForCommonAuthentication ::= SEQUENCE { + matchingId UTF8String OPTIONAL,-- The MatchingId could be the Activation code token or EventID or empty + deviceInfo DeviceInfo -- The Device information +} + +AuthenticateServerResponse ::= [56] CHOICE { -- Tag 'BF38' + authenticateResponseOk AuthenticateResponseOk, + authenticateResponseError AuthenticateResponseError +} + +AuthenticateResponseOk ::= SEQUENCE { + euiccSigned1 EuiccSigned1, -- Signed information + euiccSignature1 [APPLICATION 55] OCTET STRING, --EUICC_Sign1, tag 5F37 + euiccCertificate Certificate, -- eUICC Certificate (CERT.EUICC.ECDSA) signed by the EUM + eumCertificate Certificate -- EUM Certificate (CERT.EUM.ECDSA) signed by the requested CI +} + +EuiccSigned1 ::= SEQUENCE { + transactionId [0] TransactionId, + serverAddress [3] UTF8String, + serverChallenge [4] Octet16, -- The RSP Server Challenge + euiccInfo2 [34] EUICCInfo2, + ctxParams1 CtxParams1 +} + +AuthenticateResponseError ::= SEQUENCE { + transactionId [0] TransactionId, + authenticateErrorCode AuthenticateErrorCode +} + +AuthenticateErrorCode ::= INTEGER {invalidCertificate(1), invalidSignature(2), unsupportedCurve(3), noSessionContext(4), invalidOid(5), euiccChallengeMismatch(6), ciPKUnknown(7), undefinedError(127)} + +-- Definition of Cancel Session------------------------------ +CancelSessionRequest ::= [65] SEQUENCE { -- Tag 'BF41' + transactionId TransactionId, -- The TransactionID generated by the RSP Server + reason CancelSessionReason +} + +CancelSessionReason ::= INTEGER {endUserRejection(0), postponed(1), timeout(2), pprNotAllowed(3)} + +CancelSessionResponse ::= [65] CHOICE { -- Tag 'BF41' + cancelSessionResponseOk CancelSessionResponseOk, + cancelSessionResponseError INTEGER {invalidTransactionId(5), undefinedError(127)} +} + +CancelSessionResponseOk ::= SEQUENCE { + euiccCancelSessionSigned EuiccCancelSessionSigned, -- Signed information + euiccCancelSessionSignature [APPLICATION 55] OCTET STRING -- tag '5F37 +} + +EuiccCancelSessionSigned ::= SEQUENCE { + transactionId TransactionId, + smdpOid OBJECT IDENTIFIER, -- SM-DP+ OID as contained in CERT.DPauth.ECDSA + reason CancelSessionReason +} + +-- Definition of Bound Profile Package -------------------------- +BoundProfilePackage ::= [54] SEQUENCE { -- Tag 'BF36' + initialiseSecureChannelRequest [35] InitialiseSecureChannelRequest, -- Tag 'BF23' + firstSequenceOf87 [0] SEQUENCE OF [7] OCTET STRING, -- sequence of '87' TLVs + sequenceOf88 [1] SEQUENCE OF [8] OCTET STRING, -- sequence of '88' TLVs + secondSequenceOf87 [2] SEQUENCE OF [7] OCTET STRING OPTIONAL, -- sequence of '87' TLVs + sequenceOf86 [3] SEQUENCE OF [6] OCTET STRING -- sequence of '86' TLVs +} + +-- Definition of Get eUICC Challenge -------------------------- +GetEuiccChallengeRequest ::= [46] SEQUENCE { -- Tag 'BF2E' +} + +GetEuiccChallengeResponse ::= [46] SEQUENCE { -- Tag 'BF2E' + euiccChallenge Octet16 -- random eUICC challenge +} + +-- Definition of Profile Installation Resulceipt +ProfileInstallationResult ::= [55] SEQUENCE { -- Tag 'BF37' + profileInstallationResultData [39] ProfileInstallationResultData, + euiccSignPIR EuiccSignPIR +} + +ProfileInstallationResultData ::= [39] SEQUENCE { -- Tag 'BF27' + transactionId[0] TransactionId, -- The TransactionID generated by the SM-DP+ + notificationMetadata[47] NotificationMetadata, + smdpOid OBJECT IDENTIFIER OPTIONAL, -- SM-DP+ OID (same value as in CERT.DPpb.ECDSA) + finalResult [2] CHOICE { + successResult SuccessResult, + errorResult ErrorResult + } +} + +EuiccSignPIR ::= [APPLICATION 55] OCTET STRING -- Tag '5F37', eUICC?s signature + +SuccessResult ::= SEQUENCE { + aid [APPLICATION 15] OCTET STRING (SIZE (5..16)), -- AID of ISD-P + simaResponse OCTET STRING -- contains (multiple) 'EUICCResponse' as defined in [5] +} + +ErrorResult ::= SEQUENCE { + bppCommandId BppCommandId, + errorReason ErrorReason, + simaResponse OCTET STRING OPTIONAL -- contains (multiple) 'EUICCResponse' as defined in [5] +} + +BppCommandId ::= INTEGER {initialiseSecureChannel(0), configureISDP(1), storeMetadata(2), storeMetadata2(3), replaceSessionKeys(4), loadProfileElements(5)} + +ErrorReason ::= INTEGER { + incorrectInputValues(1), + invalidSignature(2), + invalidTransactionId(3), + unsupportedCrtValues(4), + unsupportedRemoteOperationType(5), + unsupportedProfileClass(6), + scp03tStructureError(7), + scp03tSecurityError(8), + installFailedDueToIccidAlreadyExistsOnEuicc(9), installFailedDueToInsufficientMemoryForProfile(10), + installFailedDueToInterruption(11), + installFailedDueToPEProcessingError (12), + installFailedDueToIccidMismatch(13), + testProfileInstallFailedDueToInvalidNaaKey(14), + pprNotAllowed(15), + installFailedDueToUnknownError(127) +} + +ListNotificationRequest ::= [40] SEQUENCE { -- Tag 'BF28' + profileManagementOperation [1] NotificationEvent OPTIONAL +} + +ListNotificationResponse ::= [40] CHOICE { -- Tag 'BF28' + notificationMetadataList SEQUENCE OF NotificationMetadata, + listNotificationsResultError INTEGER {undefinedError(127)} +} + +NotificationMetadata ::= [47] SEQUENCE { -- Tag 'BF2F' + seqNumber [0] INTEGER, + profileManagementOperation [1] NotificationEvent, --Only one bit set to 1 + notificationAddress UTF8String, -- FQDN to forward the notification + iccid Iccid OPTIONAL +} + +-- Definition of Profile Nickname Information +SetNicknameRequest ::= [41] SEQUENCE { -- Tag 'BF29' + iccid Iccid, + profileNickname [16] UTF8String (SIZE(0..64)) +} + +SetNicknameResponse ::= [41] SEQUENCE { -- Tag 'BF29' + setNicknameResult INTEGER {ok(0), iccidNotFound (1), undefinedError(127)} +} + +id-rsp-cert-objects OBJECT IDENTIFIER ::= { id-rsp cert-objects(2)} + +id-rspExt OBJECT IDENTIFIER ::= {id-rsp-cert-objects 0} + +id-rspRole OBJECT IDENTIFIER ::= {id-rsp-cert-objects 1} + +-- Definition of OIDs for role identification +id-rspRole-ci OBJECT IDENTIFIER ::= {id-rspRole 0} +id-rspRole-euicc OBJECT IDENTIFIER ::= {id-rspRole 1} +id-rspRole-eum OBJECT IDENTIFIER ::= {id-rspRole 2} +id-rspRole-dp-tls OBJECT IDENTIFIER ::= {id-rspRole 3} +id-rspRole-dp-auth OBJECT IDENTIFIER ::= {id-rspRole 4} +id-rspRole-dp-pb OBJECT IDENTIFIER ::= {id-rspRole 5} +id-rspRole-ds-tls OBJECT IDENTIFIER ::= {id-rspRole 6} +id-rspRole-ds-auth OBJECT IDENTIFIER ::= {id-rspRole 7} + +--Definition of data objects for InitialiseSecureChannel Request +InitialiseSecureChannelRequest ::= [35] SEQUENCE { -- Tag 'BF23' + remoteOpId RemoteOpId, -- Remote Operation Type Identifier (value SHALL be set to installBoundProfilePackage) + transactionId [0] TransactionId, -- The TransactionID generated by the SM-DP+ + controlRefTemplate[6] IMPLICIT ControlRefTemplate, -- Control Reference Template (Key Agreement). Current specification considers a subset of CRT specified in GlobalPlatform Card Specification [8], section 6.4.2.3 for the Mutual Authentication Data Field + smdpOtpk [APPLICATION 73] OCTET STRING, ---otPK.DP.ECKA as specified in GlobalPlatform Card Specification [8] section 6.4.2.3 for ePK.OCE.ECKA, tag '5F49' + smdpSign [APPLICATION 55] OCTET STRING -- SM-DP's signature, tag '5F37' +} + +ControlRefTemplate ::= SEQUENCE { +keyType[0] Octet1, -- Key type according to GlobalPlatform Card Specification [8] Table 11-16, AES= '88', Tag '80' +keyLen[1] Octet1, --Key length in number of bytes. For current specification key length SHALL by 0x10 bytes, Tag '81' +hostId[4] OctetTo16 -- Host ID value , Tag '84' +} + +--Definition of data objects for ConfigureISDPRequest +ConfigureISDPRequest ::= [36] SEQUENCE { -- Tag 'BF24' + dpProprietaryData [24] DpProprietaryData OPTIONAL -- Tag 'B8' +} + +DpProprietaryData ::= SEQUENCE { -- maximum size including tag and length field: 128 bytes + dpOid OBJECT IDENTIFIER -- OID in the tree of the SM-DP+ that created the Profile + -- additional data objects defined by the SM-DP+ MAY follow +} + +-- Definition of request message for command ReplaceSessionKeys +ReplaceSessionKeysRequest ::= [38] SEQUENCE { -- tag 'BF26' +/*The new initial MAC chaining value*/ + initialMacChainingValue OCTET STRING, +/*New session key value for encryption/decryption (PPK-ENC)*/ + ppkEnc OCTET STRING, +/*New session key value of the session key C-MAC computation/verification (PPK-MAC)*/ + ppkCmac OCTET STRING +} + +-- Definition of data objects for RetrieveNotificationsList +RetrieveNotificationsListRequest ::= [43] SEQUENCE { -- Tag 'BF2B' + searchCriteria CHOICE { + seqNumber [0] INTEGER, + profileManagementOperation [1] NotificationEvent + } OPTIONAL +} + +RetrieveNotificationsListResponse ::= [43] CHOICE { -- Tag 'BF2B' + notificationList SEQUENCE OF PendingNotification, + notificationsListResultError INTEGER {noResultAvailable(1), undefinedError(127)} +} + +PendingNotification ::= CHOICE { + profileInstallationResult [55] ProfileInstallationResult, -- tag 'BF37' + otherSignedNotification OtherSignedNotification +} + +OtherSignedNotification ::= SEQUENCE { + tbsOtherNotification NotificationMetadata, + euiccNotificationSignature [APPLICATION 55] OCTET STRING, -- eUICC signature of tbsOtherNotification, Tag '5F37' + euiccCertificate Certificate, -- eUICC Certificate (CERT.EUICC.ECDSA) signed by the EUM + eumCertificate Certificate -- EUM Certificate (CERT.EUM.ECDSA) signed by the requested CI +} + +-- Definition of notificationSent +NotificationSentRequest ::= [48] SEQUENCE { -- Tag 'BF30' + seqNumber [0] INTEGER +} + +NotificationSentResponse ::= [48] SEQUENCE { -- Tag 'BF30' + deleteNotificationStatus INTEGER {ok(0), nothingToDelete(1), undefinedError(127)} +} + +-- Definition of Enable Profile -------------------------- +EnableProfileRequest ::= [49] SEQUENCE { -- Tag 'BF31' + profileIdentifier CHOICE { + isdpAid [APPLICATION 15] OctetTo16, -- AID, tag '4F' + iccid Iccid -- ICCID, tag '5A' + }, + refreshFlag BOOLEAN -- indicating whether REFRESH is required +} + +EnableProfileResponse ::= [49] SEQUENCE { -- Tag 'BF31' + enableResult INTEGER {ok(0), iccidOrAidNotFound (1), profileNotInDisabledState(2), disallowedByPolicy(3), wrongProfileReenabling(4), undefinedError(127)} +} + +-- Definition of Disable Profile -------------------------- +DisableProfileRequest ::= [50] SEQUENCE { -- Tag 'BF32' + profileIdentifier CHOICE { + isdpAid [APPLICATION 15] OctetTo16, -- AID, tag '4F' + iccid Iccid -- ICCID, tag '5A' + }, + refreshFlag BOOLEAN -- indicating whether REFRESH is required +} + +DisableProfileResponse ::= [50] SEQUENCE { -- Tag 'BF32' + disableResult INTEGER {ok(0), iccidOrAidNotFound (1), profileNotInEnabledState(2), disallowedByPolicy(3), undefinedError(127)} +} + +-- Definition of Delete Profile -------------------------- +DeleteProfileRequest ::= [51] CHOICE { -- Tag 'BF33' + isdpAid [APPLICATION 15] OctetTo16, -- AID, tag '4F' + iccid Iccid -- ICCID, tag '5A' +} + +DeleteProfileResponse ::= [51] SEQUENCE { -- Tag 'BF33' + deleteResult INTEGER {ok(0), iccidOrAidNotFound (1), profileNotInDisabledState(2), disallowedByPolicy(3), undefinedError(127)} +} + +-- Definition of Memory Reset -------------------------- +EuiccMemoryResetRequest ::= [52] SEQUENCE { -- Tag 'BF34' + resetOptions [2] BIT STRING { + deleteOperationalProfiles(0), + deleteFieldLoadedTestProfiles(1), + resetDefaultSmdpAddress(2)} +} + +EuiccMemoryResetResponse ::= [52] SEQUENCE { -- Tag 'BF34' + resetResult INTEGER {ok(0), nothingToDelete(1), undefinedError(127)} +} + +-- Definition of Get EID -------------------------- +GetEuiccDataRequest ::= [62] SEQUENCE { -- Tag 'BF3E' + tagList [APPLICATION 28] Octet1 -- tag '5C', the value SHALL be set to '5A' +} + +GetEuiccDataResponse ::= [62] SEQUENCE { -- Tag 'BF3E' + eidValue [APPLICATION 26] Octet16 -- tag '5A' +} + +-- Definition of Get Rat + +GetRatRequest ::= [67] SEQUENCE { -- Tag ' BF43' + -- No input data +} + + +GetRatResponse ::= [67] SEQUENCE { -- Tag 'BF43' + rat RulesAuthorisationTable +} + +RulesAuthorisationTable ::= SEQUENCE OF ProfilePolicyAuthorisationRule +ProfilePolicyAuthorisationRule ::= SEQUENCE { + pprIds PprIds, + allowedOperators SEQUENCE OF OperatorID, + pprFlags BIT STRING {consentRequired(0)} +} + +-- Definition of data structure command for loading a CRL +LoadCRLRequest ::= [53] SEQUENCE { -- Tag 'BF35' + -- A CRL-A + crl CertificateList +} + +-- Definition of data structure response for loading a CRL +LoadCRLResponse ::= [53] CHOICE { -- Tag 'BF35' +loadCRLResponseOk LoadCRLResponseOk, +loadCRLResponseError LoadCRLResponseError +} + +LoadCRLResponseOk ::= SEQUENCE { + missingParts SEQUENCE OF SEQUENCE { + number INTEGER (0..MAX) + } OPTIONAL +} +LoadCRLResponseError ::= INTEGER {invalidSignature(1), invalidCRLFormat(2), notEnoughMemorySpace(3), verificationKeyNotFound(4), undefinedError(127)} + +-- Definition of the extension for Certificate Expiration Date +id-rsp-expDate OBJECT IDENTIFIER ::= {id-rspExt 1} +ExpirationDate ::= Time + +-- Definition of the extension id for total partial-CRL number +id-rsp-totalPartialCrlNumber OBJECT IDENTIFIER ::= {id-rspExt 2} +TotalPartialCrlNumber ::= INTEGER + + +-- Definition of the extension id for the partial-CRL number +id-rsp-partialCrlNumber OBJECT IDENTIFIER ::= {id-rspExt 3} +PartialCrlNumber ::= INTEGER + +-- Definition for ES9+ ASN.1 Binding -------------------------- +RemoteProfileProvisioningRequest ::= [2] CHOICE { -- Tag 'A2' + initiateAuthenticationRequest [57] InitiateAuthenticationRequest, -- Tag 'BF39' + authenticateClientRequest [59] AuthenticateClientRequest, -- Tag 'BF3B' + getBoundProfilePackageRequest [58] GetBoundProfilePackageRequest, -- Tag 'BF3A' + cancelSessionRequestEs9 [65] CancelSessionRequestEs9, -- Tag 'BF41' + handleNotification [61] HandleNotification -- tag 'BF3D' +} + +RemoteProfileProvisioningResponse ::= [2] CHOICE { -- Tag 'A2' + initiateAuthenticationResponse [57] InitiateAuthenticationResponse, -- Tag 'BF39' + authenticateClientResponseEs9 [59] AuthenticateClientResponseEs9, -- Tag 'BF3B' + getBoundProfilePackageResponse [58] GetBoundProfilePackageResponse, -- Tag 'BF3A' + cancelSessionResponseEs9 [65] CancelSessionResponseEs9, -- Tag 'BF41' + authenticateClientResponseEs11 [64] AuthenticateClientResponseEs11 -- Tag 'BF40' +} + +InitiateAuthenticationRequest ::= [57] SEQUENCE { -- Tag 'BF39' + euiccChallenge [1] Octet16, -- random eUICC challenge + smdpAddress [3] UTF8String, + euiccInfo1 EUICCInfo1 +} + +InitiateAuthenticationResponse ::= [57] CHOICE { -- Tag 'BF39' + initiateAuthenticationOk InitiateAuthenticationOkEs9, + initiateAuthenticationError INTEGER { + invalidDpAddress(1), + euiccVersionNotSupportedByDp(2), + ciPKNotSupported(3) + } +} + +InitiateAuthenticationOkEs9 ::= SEQUENCE { + transactionId [0] TransactionId, -- The TransactionID generated by the SM-DP+ + serverSigned1 ServerSigned1, -- Signed information + serverSignature1 [APPLICATION 55] OCTET STRING, -- Server_Sign1, tag '5F37' + euiccCiPKIdToBeUsed SubjectKeyIdentifier, -- The curve CI Public Key to be used as required by ES10b.AuthenticateServer + serverCertificate Certificate +} + +AuthenticateClientRequest ::= [59] SEQUENCE { -- Tag 'BF3B' + transactionId [0] TransactionId, + authenticateServerResponse [56] AuthenticateServerResponse -- This is the response from ES10b.AuthenticateServer +} + +AuthenticateClientResponseEs9 ::= [59] CHOICE { -- Tag 'BF3B' + authenticateClientOk AuthenticateClientOk, + authenticateClientError INTEGER { + eumCertificateInvalid(1), + eumCertificateExpired(2), + euiccCertificateInvalid(3), + euiccCertificateExpired(4), + euiccSignatureInvalid(5), + matchingIdRefused(6), + eidMismatch(7), + noEligibleProfile(8), + ciPKUnknown(9), + invalidTransactionId(10), + undefinedError(127) + } +} + +AuthenticateClientOk ::= SEQUENCE { + transactionId [0] TransactionId, + profileMetaData [37] StoreMetadataRequest, + prepareDownloadRequest [33] PrepareDownloadRequest +} + +GetBoundProfilePackageRequest ::= [58] SEQUENCE { -- Tag 'BF3A' + transactionId [0] TransactionId, + prepareDownloadResponse [33] PrepareDownloadResponse +} + +GetBoundProfilePackageResponse ::= [58] CHOICE { -- Tag 'BF3A' + getBoundProfilePackageOk GetBoundProfilePackageOk, + getBoundProfilePackageError INTEGER { + euiccSignatureInvalid(1), + confirmationCodeMissing(2), + confirmationCodeRefused(3), + confirmationCodeRetriesExceeded(4), + invalidTransactionId(95), + undefinedError(127) + } +} + +GetBoundProfilePackageOk ::= SEQUENCE { + transactionId [0] TransactionId, + boundProfilePackage [54] BoundProfilePackage +} + +HandleNotification ::= [61] SEQUENCE { -- Tag 'BF3D' + pendingNotification PendingNotification +} + +CancelSessionRequestEs9 ::= [65] SEQUENCE { -- Tag 'BF41' + transactionId TransactionId, + cancelSessionResponse CancelSessionResponse -- data structure defined for ES10b.CancelSession function +} + +CancelSessionResponseEs9 ::= [65] CHOICE { -- Tag 'BF41' + cancelSessionOk CancelSessionOk, + cancelSessionError INTEGER { + invalidTransactionId(1), + euiccSignatureInvalid(2), + undefinedError(127) + } +} + +CancelSessionOk ::= SEQUENCE { -- This function has no output data +} + +EuiccConfiguredAddressesRequest ::= [60] SEQUENCE { -- Tag 'BF3C' +} + +EuiccConfiguredAddressesResponse ::= [60] SEQUENCE { -- Tag 'BF3C' + defaultDpAddress UTF8String OPTIONAL, -- Default SM-DP+ address as an FQDN + rootDsAddress UTF8String -- Root SM-DS address as an FQDN +} + +ISDRProprietaryApplicationTemplate ::= [PRIVATE 0] SEQUENCE { -- Tag 'E0' + svn [2] VersionType, -- GSMA SGP.22 version supported (SVN) + lpaeSupport BIT STRING { + lpaeUsingCat(0), -- LPA in the eUICC using Card Application Toolkit + lpaeUsingScws(1) -- LPA in the eUICC using Smartcard Web Server + } OPTIONAL +} + +LpaeActivationRequest ::= [66] SEQUENCE { -- Tag 'BF42' + lpaeOption BIT STRING { + activateCatBasedLpae(0), -- LPAe with LUIe based on CAT + activateScwsBasedLpae(1) -- LPAe with LUIe based on SCWS + } +} + +LpaeActivationResponse ::= [66] SEQUENCE { -- Tag 'BF42' + lpaeActivationResult INTEGER {ok(0), notSupported(1)} +} + +SetDefaultDpAddressRequest ::= [63] SEQUENCE { -- Tag 'BF3F' + defaultDpAddress UTF8String -- Default SM-DP+ address as an FQDN +} + +SetDefaultDpAddressResponse ::= [63] SEQUENCE { -- Tag 'BF3F' + setDefaultDpAddressResult INTEGER { ok (0), undefinedError (127)} +} + +AuthenticateClientResponseEs11 ::= [64] CHOICE { -- Tag 'BF40' + authenticateClientOk AuthenticateClientOkEs11, + authenticateClientError INTEGER { + eumCertificateInvalid(1), + eumCertificateExpired(2), + euiccCertificateInvalid(3), + euiccCertificateExpired(4), + euiccSignatureInvalid(5), + eventIdUnknown(6), + invalidTransactionId(7), + undefinedError(127) + } +} + +AuthenticateClientOkEs11 ::= SEQUENCE { + transactionId TransactionId, + eventEntries SEQUENCE OF EventEntries +} + +EventEntries ::= SEQUENCE { + eventId UTF8String, + rspServerAddress UTF8String +} + +END \ No newline at end of file diff --git a/pySim/esim/es8p.py b/pySim/esim/es8p.py new file mode 100644 index 0000000..81b0fc9 --- /dev/null +++ b/pySim/esim/es8p.py @@ -0,0 +1,185 @@ +# Implementation of GSMA eSIM RSP (Remote SIM Provisioning) ES8+ +# as per SGP22 v3.0 Section 5.5 +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from typing import Dict, List, Optional +from pySim.utils import b2h, h2b, bertlv_encode_tag, bertlv_encode_len + +import pySim.esim.rsp as rsp +from pySim.esim.bsp import BspInstance + +# Given that GSMA RSP uses ASN.1 in a very weird way, we actually cannot encode the full data type before +# signing, but we have to build parts of it separately first, then sign that, so we can put the signature +# into the same sequence as the signed data. We use the existing pySim TLV code for this. + +def wrap_as_der_tlv(tag: int, val: bytes) -> bytes: + """Wrap the 'value' into a DER-encoded TLV.""" + return bertlv_encode_tag(tag) + bertlv_encode_len(len(val)) + val + +def gen_init_sec_chan_signed_part(iscsp: Dict) -> bytes: + """Generate the concatenated remoteOpId, transactionId, controlRefTemplate and smdpOtpk data objects + without the outer SEQUENCE tag / length or the remainder of initialiseSecureChannel, as is required + for signing purpose.""" + out = b'' + out += wrap_as_der_tlv(0x82, bytes([iscsp['remoteOpId']])) + out += wrap_as_der_tlv(0x80, iscsp['transactionId']) + + crt = iscsp['controlRefTemplate'] + out_crt = wrap_as_der_tlv(0x80, crt['keyType']) + out_crt += wrap_as_der_tlv(0x81, crt['keyLen']) + out_crt += wrap_as_der_tlv(0x84, crt['hostId']) + out += wrap_as_der_tlv(0xA6, out_crt) + + out += wrap_as_der_tlv(0x5F49, iscsp['smdpOtpk']) + return out + + +# SGP.22 Section 5.5.1 +def gen_initialiseSecureChannel(transactionId: str, host_id: bytes, smdp_otpk: bytes, euicc_otpk: bytes, dp_pb): + """Generate decoded representation of (signed) initialiseSecureChannel (SGP.22 5.5.2)""" + init_scr = { 'remoteOpId': 1, # installBoundProfilePackage + 'transactionId': h2b(transactionId), + # GlobalPlatform Card Specification Amendment F [13] section 6.5.2.3 for the Mutual Authentication Data Field + 'controlRefTemplate': { 'keyType': bytes([0x88]), 'keyLen': bytes([16]), 'hostId': host_id }, + 'smdpOtpk': smdp_otpk, # otPK.DP.KA + } + to_sign = gen_init_sec_chan_signed_part(init_scr) + wrap_as_der_tlv(0x5f49, euicc_otpk) + init_scr['smdpSign'] = dp_pb.ecdsa_sign(to_sign) + return init_scr + +def gen_replace_session_keys(ppk_enc: bytes, ppk_cmac: bytes, initial_mcv: bytes) -> bytes: + """Generate encoded (but unsigned) ReplaceSessionKeysReqest DO (SGP.22 5.5.4)""" + rsk = { 'ppkEnc': ppk_enc, 'ppkCmac': ppk_cmac, 'initialMacChainingValue': initial_mcv } + return rsp.asn1.encode('ReplaceSessionKeysRequest', rsk) + + +class ProfileMetadata: + """Representation of Profile metadata. Right now only the mandatory bits are + supported, but in general this should follow the StoreMetadataRequest of SGP.22 5.5.3""" + def __init__(self, iccid_bin: bytes, spn: str, profile_name: str): + self.iccid_bin = iccid_bin + self.spn = spn + self.profile_name = profile_name + + def gen_store_metadata_request(self) -> bytes: + """Generate encoded (but unsigned) StoreMetadataReqest DO (SGP.22 5.5.3)""" + smr = { + 'iccid': self.iccid_bin, + 'serviceProviderName': self.spn, + 'profileName': self.profile_name, + } + return rsp.asn1.encode('StoreMetadataRequest', smr) + + +class ProfilePackage: + def __init__(self, metadata: Optional[ProfileMetadata] = None): + self.metadata = metadata + +class UnprotectedProfilePackage(ProfilePackage): + """Representing an unprotected profile package (UPP) as defined in SGP.22 Section 2.5.2""" + + @classmethod + def from_der(cls, der: bytes, metadata: Optional[ProfileMetadata] = None) -> 'UnprotectedProfilePackage': + """Load an UPP from its DER representation.""" + inst = cls(metadata=metadata) + cls.der = der + # TODO: we later certainly want to parse it so we can perform modification (IMSI, key material, ...) + # just like in the traditional SIM/USIM dynamic data phase at the end of personalization + return inst + + def to_der(self): + """Return the DER representation of the UPP.""" + # TODO: once we work on decoded structures, we may want to re-encode here + return self.der + +class ProtectedProfilePackage(ProfilePackage): + """Representing a protected profile package (PPP) as defined in SGP.22 Section 2.5.3""" + + @classmethod + def from_upp(cls, upp: UnprotectedProfilePackage, bsp: BspInstance) -> 'ProtectedProfilePackage': + """Generate the PPP as a sequence of encrypted and MACed Command TLVs representing the UPP""" + inst = cls(metadata=upp.metadata) + inst.upp = upp + # store ppk-enc, ppc-mac + inst.ppk_enc = bsp.c_algo.s_enc + inst.ppk_mac = bsp.m_algo.s_mac + inst.initial_mcv = bsp.m_algo.mac_chain + inst.encoded = bsp.encrypt_and_mac(0x86, upp.to_der()) + return inst + + #def __val__(self): + #return self.encoded + +class BoundProfilePackage(ProfilePackage): + """Representing a bound profile package (BPP) as defined in SGP.22 Section 2.5.4""" + + @classmethod + def from_ppp(cls, ppp: ProtectedProfilePackage): + inst = cls() + inst.upp = None + inst.ppp = ppp + return inst + + @classmethod + def from_upp(cls, upp: UnprotectedProfilePackage): + inst = cls() + inst.upp = upp + inst.ppp = None + return inst + + def encode(self, ss: 'RspSessionState', dp_pb: 'CertAndPrivkey') -> bytes: + """Generate a bound profile package (SGP.22 2.5.4).""" + + def encode_seq(tag: int, sequence: List[bytes]) -> bytes: + """Encode a "sequenceOfXX" as specified in SGP.22 specifying the raw SEQUENCE OF tag, + and assuming the caller provides the fully-encoded (with TAG + LEN) member TLVs.""" + payload = b''.join(sequence) + return bertlv_encode_tag(tag) + bertlv_encode_len(len(payload)) + payload + + bsp = BspInstance.from_kdf(ss.shared_secret, 0x88, 16, ss.host_id, h2b(ss.eid)) + + iscr = gen_initialiseSecureChannel(ss.transactionId, ss.host_id, ss.smdp_otpk, ss.euicc_otpk, dp_pb) + # generate unprotected input data + conf_idsp_bin = rsp.asn1.encode('ConfigureISDPRequest', {}) + if self.upp: + smr_bin = self.upp.metadata.gen_store_metadata_request() + else: + smr_bin = self.ppp.metadata.gen_store_metadata_request() + + # we don't use rsp.asn1.encode('boundProfilePackage') here, as the BSP already provides + # fully encoded + MACed TLVs including their tag + length values. We cannot put those as + # 'value' input into an ASN.1 encoder, as that would double the TAG + LENGTH :( + + # 'initialiseSecureChannelRequest' + bpp_seq = rsp.asn1.encode('InitialiseSecureChannelRequest', iscr) + # firstSequenceOf87 + bpp_seq += encode_seq(0xa0, bsp.encrypt_and_mac(0x87, conf_idsp_bin)) + # sequenceOF88 + bpp_seq += encode_seq(0xa1, bsp.mac_only(0x88, smr_bin)) + + if self.ppp: # we have to use session keys + rsk_bin = gen_replace_session_keys(self.ppp.ppk_enc, self.ppp.ppk_mac, self.ppp.initial_mcv) + # secondSequenceOf87 + bpp_seq += encode_seq(0xa2, bsp.encrypt_and_mac(0x87, rsk_bin)) + else: + self.ppp = ProtectedProfilePackage.from_upp(self.upp, bsp) + + # 'sequenceOf86' + bpp_seq += encode_seq(0xa3, self.ppp.encoded) + + # manual DER encode: wrap in outer SEQUENCE + return bertlv_encode_tag(0xbf36) + bertlv_encode_len(len(bpp_seq)) + bpp_seq diff --git a/pySim/esim/rsp.py b/pySim/esim/rsp.py new file mode 100644 index 0000000..b5289be --- /dev/null +++ b/pySim/esim/rsp.py @@ -0,0 +1,100 @@ +# Implementation of GSMA eSIM RSP (Remote SIM Provisioning) +# as per SGP22 v3.0 +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +from typing import Optional +import shelve +import copyreg + +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.serialization import Encoding +from cryptography import x509 +from collections.abc import MutableMapping + +from pySim.esim import compile_asn1_subdir + +asn1 = compile_asn1_subdir('rsp') + +class RspSessionState: + """Encapsulates the state of a RSP session. It is created during the initiateAuthentication + and subsequently used by further API calls using the same transactionId. The session state + is removed either after cancelSession or after notification. + TODO: add some kind of time based expiration / garbage collection.""" + def __init__(self, transactionId: str, serverChallenge: bytes): + self.transactionId = transactionId + self.serverChallenge = serverChallenge + # used at a later point between API calsl + self.euicc_cert: Optional[x509.Certificate] = None + self.eum_cert: Optional[x509.Certificate] = None + self.eid: Optional[bytes] = None + self.profileMetadata: Optional['ProfileMetadata'] = None + self.smdpSignature2_do = None + # really only needed while processing getBoundProfilePackage request? + self.euicc_otpk: Optional[bytes] = None + self.smdp_ot: Optional[ec.EllipticCurvePrivateKey] = None + self.smdp_otpk: Optional[bytes] = None + self.host_id: Optional[bytes] = None + self.shared_secret: Optional[bytes] = None + + + def __getstate__(self): + """helper function called when pickling the object to persistent storage. We must pickel all + members that are not pickle-able.""" + state = self.__dict__.copy() + # serialize eUICC certificate as DER + if state.get('euicc_cert', None): + state['_euicc_cert'] = self.euicc_cert.public_bytes(Encoding.DER) + del state['euicc_cert'] + # serialize EUM certificate as DER + if state.get('eum_cert', None): + state['_eum_cert'] = self.eum_cert.public_bytes(Encoding.DER) + del state['eum_cert'] + # serialize one-time SMDP private key to integer + curve + if state.get('smdp_ot', None): + state['_smdp_otsk'] = self.smdp_ot.private_numbers().private_value + state['_smdp_ot_curve'] = self.smdp_ot.curve + del state['smdp_ot'] + return state + + def __setstate__(self, state): + """helper function called when unpickling the object from persistent storage. We must recreate all + members from the state generated in __getstate__ above.""" + # restore eUICC certificate from DER + if '_euicc_cert' in state: + self.euicc_cert = x509.load_der_x509_certificate(state['_euicc_cert']) + del state['_euicc_cert'] + else: + self.euicc_cert = None + # restore EUM certificate from DER + if '_eum_cert' in state: + self.eum_cert = x509.load_der_x509_certificate(state['_eum_cert']) + del state['_eum_cert'] + # restore one-time SMDP private key from integer + curve + if state.get('_smdp_otsk', None): + self.smdp_ot = ec.derive_private_key(state['_smdp_otsk'], state['_smdp_ot_curve']) + # FIXME: how to add the public key from smdp_otpk to an instance of EllipticCurvePrivateKey? + del state['_smdp_otsk'] + del state['_smdp_ot_curve'] + # automatically recover all the remainig state + self.__dict__.update(state) + + +class RspSessionStore(shelve.DbfilenameShelf): + """A derived class as wrapper around the database-backed non-volatile storage 'shelve', in case we might + need to extend it in the future. We use it to store RspSessionState objects indexed by transactionId.""" + pass diff --git a/requirements.txt b/requirements.txt index f17e293..5b735f0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,6 @@ colorlog pycryptodomex cryptography +asn1tools packaging git+https://github.com/hologram-io/smpp.pdu diff --git a/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.der b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.der new file mode 100644 index 0000000..98942c1 --- /dev/null +++ b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.der Binary files differ diff --git a/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.pem b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.pem new file mode 100644 index 0000000..4c72371 --- /dev/null +++ b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_BRP.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICUTCCAfigAwIBAgIJALh086v6bETTMAoGCCqGSM49BAMCMEQxEDAOBgNVBAMM +B1Rlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAwDgYDVQQKDAdSU1BURVNUMQsw +CQYDVQQGEwJJVDAgFw0yMDA0MDEwODI3NTFaGA8yMDU1MDQwMTA4Mjc1MVowRDEQ +MA4GA1UEAwwHVGVzdCBDSTERMA8GA1UECwwIVEVTVENFUlQxEDAOBgNVBAoMB1JT +UFRFU1QxCzAJBgNVBAYTAklUMFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABCeH +tNVu2CSp5r4E4Yh/a5i6/rjHY/UoN/cBE+k2Tt2+E5vAx95+Fo8eXNDBhTT8UGTm +T2htxTMnyn8dzqhaKZSjgc8wgcwwHQYDVR0OBBYEFMC8cLo2kp1DtGf/V1cFMOV6 +uPzYMA8GA1UdEwEB/wQFMAMBAf8wFwYDVR0gAQH/BA0wCzAJBgdngRIBAgEAMA4G +A1UdDwEB/wQEAwIBBjAOBgNVHREEBzAFiAOINwEwYQYDVR0fBFowWDAqoCigJoYk +aHR0cDovL2NpLnRlc3QuZXhhbXBsZS5jb20vQ1JMLUEuY3JsMCqgKKAmhiRodHRw +Oi8vY2kudGVzdC5leGFtcGxlLmNvbS9DUkwtQi5jcmwwCgYIKoZIzj0EAwIDRwAw +RAIgPYrf0CKl0FBMUaHx5xS1duTDbQ4wBZN3qKBeNniuux0CIHBek2vLfoANAdtt +f5u5Ce6DVC2oIfpn5UnS24F3oMqM +-----END CERTIFICATE----- diff --git a/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.der b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.der new file mode 100644 index 0000000..22bc277 --- /dev/null +++ b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.der Binary files differ diff --git a/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.pem b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.pem new file mode 100644 index 0000000..9f6f4cd --- /dev/null +++ b/smdpp-data/certs/CertificateIssuer/CERT_CI_ECDSA_NIST.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICUDCCAfegAwIBAgIJALh086v6bETTMAoGCCqGSM49BAMCMEQxEDAOBgNVBAMM +B1Rlc3QgQ0kxETAPBgNVBAsMCFRFU1RDRVJUMRAwDgYDVQQKDAdSU1BURVNUMQsw +CQYDVQQGEwJJVDAgFw0yMDA0MDEwODI3NTFaGA8yMDU1MDQwMTA4Mjc1MVowRDEQ +MA4GA1UEAwwHVGVzdCBDSTERMA8GA1UECwwIVEVTVENFUlQxEDAOBgNVBAoMB1JT +UFRFU1QxCzAJBgNVBAYTAklUMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElAZX +pnPcKI+J1S6opHcEmSeR+cNLADbmM+LQy6lFTWXbMusXmBeZ0vJDiO4rlcEJRUbJ +eQHOrrqWUJGaLiDSKaOBzzCBzDAdBgNVHQ4EFgQU9UFyvfmKldZcvriKOKHBHYAK +hcMwDwYDVR0TAQH/BAUwAwEB/zAXBgNVHSABAf8EDTALMAkGB2eBEgECAQAwDgYD +VR0PAQH/BAQDAgEGMA4GA1UdEQQHMAWIA4g3ATBhBgNVHR8EWjBYMCqgKKAmhiRo +dHRwOi8vY2kudGVzdC5leGFtcGxlLmNvbS9DUkwtQS5jcmwwKqAooCaGJGh0dHA6 +Ly9jaS50ZXN0LmV4YW1wbGUuY29tL0NSTC1CLmNybDAKBggqhkjOPQQDAgNHADBE +AiBSdWqvwgIKbOy/Ll88IIklEP8pdR0pi9OwFdlgWk/mfQIgV5goNuTSBd3S5sPB +tFWTf2tuSTtgL9G2bDV0iak192s= +-----END CERTIFICATE----- diff --git a/smdpp-data/certs/CertificateIssuer/CI-csr.cnf b/smdpp-data/certs/CertificateIssuer/CI-csr.cnf new file mode 100644 index 0000000..89fdf6d --- /dev/null +++ b/smdpp-data/certs/CertificateIssuer/CI-csr.cnf @@ -0,0 +1,25 @@ +#openssl x509 extfile params +extensions = extend +# This prevent the user to be prompted for values +prompt = no + +distinguished_name = dn-param +[dn-param] # DN fields +CN = Test CI +OU = TESTCERT +O = RSPTEST +C = IT + +# Extensions for the Test CI +[extend] # openssl extensions +subjectKeyIdentifier = hash + +basicConstraints = critical, CA:true + +certificatePolicies=critical,2.23.146.1.2.1.0 + +keyUsage =critical, keyCertSign, cRLSign + +subjectAltName = RID:2.999.1 + +crlDistributionPoints=URI:http://ci.test.example.com/CRL-A.crl, URI:http://ci.test.example.com/CRL-B.crl \ No newline at end of file diff --git a/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der b/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der new file mode 100644 index 0000000..a3caae5 --- /dev/null +++ b/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der b/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der new file mode 100644 index 0000000..81715bb --- /dev/null +++ b/smdpp-data/certs/DPauth/CERT_S_SM_DP2auth_ECDSA_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der b/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der new file mode 100644 index 0000000..45c043c --- /dev/null +++ b/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der b/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der new file mode 100644 index 0000000..914b8a1 --- /dev/null +++ b/smdpp-data/certs/DPauth/CERT_S_SM_DPauth_ECDSA_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem b/smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem new file mode 100644 index 0000000..e37c621 --- /dev/null +++ b/smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_BRP.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABC7uB8ltAFvlGV95rR2tzR03jKMJ +XkT3LupBDwjHVhIskGPJZbf8hSnAyk6bT2WWnCg8ZWNkV4dxGPbRFy1qI2U= +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem b/smdpp-data/certs/DPauth/PK_S_SM_DP2auth_ECDSA_NIST.pem new file mode 100644 index 0000000..63fc92d --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem b/smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_BRP.pem new file mode 100644 index 0000000..cbd8ccc --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem b/smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem new file mode 100644 index 0000000..8424bb4 --- /dev/null +++ b/smdpp-data/certs/DPauth/PK_S_SM_DPauth_ECDSA_NIST.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETf7U9GlHkb8Wlc6gMHo1tBgBlpU4 +e7dbfSRHtrUgnwRFrk5eUhzROIjXX+B8hYAiKuINuqwdd812MEmTQhvXOQ== +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem b/smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_BRP.pem new file mode 100644 index 0000000..dc20882 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem b/smdpp-data/certs/DPauth/SK_S_SM_DP2auth_ECDSA_NIST.pem new file mode 100644 index 0000000..0b19301 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem b/smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_BRP.pem new file mode 100644 index 0000000..6e9d064 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem b/smdpp-data/certs/DPauth/SK_S_SM_DPauth_ECDSA_NIST.pem new file mode 100644 index 0000000..35df74b --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPauth/data_sig.der b/smdpp-data/certs/DPauth/data_sig.der new file mode 100644 index 0000000..7f44ce2 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_BRP.der b/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_BRP.der new file mode 100644 index 0000000..a382a5b --- /dev/null +++ b/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_NIST.der b/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_NIST.der new file mode 100644 index 0000000..11a1339 --- /dev/null +++ b/smdpp-data/certs/DPpb/CERT_S_SM_DP2pb_ECDSA_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_BRP.der b/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_BRP.der new file mode 100644 index 0000000..089230b --- /dev/null +++ b/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_NIST.der b/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_NIST.der new file mode 100644 index 0000000..3b585e8 --- /dev/null +++ b/smdpp-data/certs/DPpb/CERT_S_SM_DPpb_ECDSA_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_BRP.pem b/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_BRP.pem new file mode 100644 index 0000000..c6007b6 --- /dev/null +++ b/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_BRP.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABHNhhV5ZAmSyUscaYGKgIeJ7Rvdg +uBOCBqf3RCDvi8Vai5iNFlj51w06LYSAqt9k5ixNcSfeWgorkXqUP0R0qt0= +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_NIST.pem b/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_NIST.pem new file mode 100644 index 0000000..b8c30e2 --- /dev/null +++ b/smdpp-data/certs/DPpb/PK_S_SM_DP2pb_ECDSA_NIST.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPi11oQYiEhbCruj61YT3eWM8+URo +G17HWpZlP19AHEdq451UbAMtMtAHCnuG5dzrqt3zHKXCdmwZa9ebwhoBgA== +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_BRP.pem b/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_BRP.pem new file mode 100644 index 0000000..95c77bf --- /dev/null +++ b/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_BRP.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFowFAYHKoZIzj0CAQYJKyQDAwIIAQEHA0IABIkyU+zJTFHfT+5uDbCVHPxlYnSB +tUGOVXBp9If6oVRmpcuOEMwrOAmc8qkp9/gtrAZRJrcdBkCWHbf5GknpVhI= +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_NIST.pem b/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_NIST.pem new file mode 100644 index 0000000..fabd554 --- /dev/null +++ b/smdpp-data/certs/DPpb/PK_S_SM_DPpb_ECDSA_NIST.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEEwq49At75yXkmGnxnEAdrlwch0J +VaJkSuBfrkvCMU5dwJ9r8BGAJhZTQuISMYd142XztXMlNzBmuZBuC9E4jQ== +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_BRP.pem b/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_BRP.pem new file mode 100644 index 0000000..1e1b437 --- /dev/null +++ b/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_BRP.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgkrJAMDAggBAQc= +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHgCAQEEIJyuLhpWB6nVeDgu7pMuJR9SME+G7rHxcIzb08B74s09oAsGCSskAwMC +CAEBB6FEA0IABHNhhV5ZAmSyUscaYGKgIeJ7RvdguBOCBqf3RCDvi8Vai5iNFlj5 +1w06LYSAqt9k5ixNcSfeWgorkXqUP0R0qt0= +-----END EC PRIVATE KEY----- diff --git a/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_NIST.pem b/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_NIST.pem new file mode 100644 index 0000000..63045bd --- /dev/null +++ b/smdpp-data/certs/DPpb/SK_S_SM_DP2pb_ECDSA_NIST.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIGaTEUljnbqsHcPTBsWL0t/SL3O/Y6yGMZgykLV/kJNFoAoGCCqGSM49 +AwEHoUQDQgAEPi11oQYiEhbCruj61YT3eWM8+URoG17HWpZlP19AHEdq451UbAMt +MtAHCnuG5dzrqt3zHKXCdmwZa9ebwhoBgA== +-----END EC PRIVATE KEY----- diff --git a/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_BRP.pem b/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_BRP.pem new file mode 100644 index 0000000..9da501d --- /dev/null +++ b/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_BRP.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BgkrJAMDAggBAQc= +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHgCAQEEIHX/Mi9BZhba4aSE73HUh0+w3zKV/TXCy6SJ+7K7nHv2oAsGCSskAwMC +CAEBB6FEA0IABIkyU+zJTFHfT+5uDbCVHPxlYnSBtUGOVXBp9If6oVRmpcuOEMwr +OAmc8qkp9/gtrAZRJrcdBkCWHbf5GknpVhI= +-----END EC PRIVATE KEY----- diff --git a/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_NIST.pem b/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_NIST.pem new file mode 100644 index 0000000..9595c07 --- /dev/null +++ b/smdpp-data/certs/DPpb/SK_S_SM_DPpb_ECDSA_NIST.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINzWlLd4lX6Omt292UQz6e+Pc9EeSRxI1CWjipSRvTvtoAoGCCqGSM49 +AwEHoUQDQgAEEEwq49At75yXkmGnxnEAdrlwch0JVaJkSuBfrkvCMU5dwJ9r8BGA +JhZTQuISMYd142XztXMlNzBmuZBuC9E4jQ== +-----END EC PRIVATE KEY----- diff --git a/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.csr.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.csr.cnf new file mode 100644 index 0000000..8ed5b2b --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.der b/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.der new file mode 100644 index 0000000..be20b34 --- /dev/null +++ b/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.ext.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP2_TLS.ext.cnf new file mode 100644 index 0000000..d224daf --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.csr.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.csr.cnf new file mode 100644 index 0000000..abaa1da --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.der b/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.der new file mode 100644 index 0000000..07b4c85 --- /dev/null +++ b/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.ext.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP4_TLS.ext.cnf new file mode 100644 index 0000000..31f6463 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.csr.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.csr.cnf new file mode 100644 index 0000000..39ebdfb --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.der b/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.der new file mode 100644 index 0000000..3b45b14 --- /dev/null +++ b/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.ext.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP8_TLS.ext.cnf new file mode 100644 index 0000000..cc88f83 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.csr.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.csr.cnf new file mode 100644 index 0000000..d9b785c --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.ext.cnf b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS.ext.cnf new file mode 100644 index 0000000..f80caf6 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_BRP.der b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_BRP.der new file mode 100644 index 0000000..dc730f0 --- /dev/null +++ b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_NIST.der b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_NIST.der new file mode 100644 index 0000000..0cb9ba7 --- /dev/null +++ b/smdpp-data/certs/DPtls/CERT_S_SM_DP_TLS_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der new file mode 100644 index 0000000..4f91532 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP2_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der new file mode 100644 index 0000000..70820fa --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP4_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der new file mode 100644 index 0000000..33cc6fb --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP8_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der new file mode 100644 index 0000000..5d0ae30 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der new file mode 100644 index 0000000..38927b1 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2021/CERT_S_SM_DP_TLS_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der new file mode 100644 index 0000000..32909ce --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP2_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der new file mode 100644 index 0000000..ea11075 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP4_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der new file mode 100644 index 0000000..93a0cc0 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP8_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der new file mode 100644 index 0000000..3d00317 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der new file mode 100644 index 0000000..179c37b --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2022/CERT_S_SM_DP_TLS_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der new file mode 100644 index 0000000..da5516c --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP2_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der new file mode 100644 index 0000000..b1c222c --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP4_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der new file mode 100644 index 0000000..638e4a1 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP8_TLS.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der new file mode 100644 index 0000000..6746cbb --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_BRP.der Binary files differ diff --git a/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der new file mode 100644 index 0000000..6977bd3 --- /dev/null +++ b/smdpp-data/certs/DPtls/Old_TLS_Validity/Expired 2023/CERT_S_SM_DP_TLS_NIST.der Binary files differ diff --git a/smdpp-data/certs/DPtls/PK_S_SM_DP2_TLS_NIST.pem b/smdpp-data/certs/DPtls/PK_S_SM_DP2_TLS_NIST.pem new file mode 100644 index 0000000..702bcf7 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/PK_S_SM_DP4_TLS.pem b/smdpp-data/certs/DPtls/PK_S_SM_DP4_TLS.pem new file mode 100644 index 0000000..9c165c7 --- /dev/null +++ b/smdpp-data/certs/DPtls/PK_S_SM_DP4_TLS.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOtvoTSOoGvY7otiZg2y7aKdiVrMN +cCYwPcNrwV32ETbE++cCAbTFpm49rGsrO5V6mbtOdBAD6L90LwgTAqp9pg== +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPtls/PK_S_SM_DP8_TLS.pem b/smdpp-data/certs/DPtls/PK_S_SM_DP8_TLS.pem new file mode 100644 index 0000000..0ff4586 --- /dev/null +++ b/smdpp-data/certs/DPtls/PK_S_SM_DP8_TLS.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzkExGPpkmW7Yspv8rIUzg+ZdPyKh +meeWa/QGmmlYOSvlOdAA6lGlSIsQh9brR8ABhG0eaH7EkOgagJZJQgxSaw== +-----END PUBLIC KEY----- diff --git a/smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_BRP.pem b/smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_BRP.pem new file mode 100644 index 0000000..8fd826f --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_NIST.pem b/smdpp-data/certs/DPtls/PK_S_SM_DP_TLS_NIST.pem new file mode 100644 index 0000000..15ea8ea --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/SK_S_SM_DP2_TLS_NIST.pem b/smdpp-data/certs/DPtls/SK_S_SM_DP2_TLS_NIST.pem new file mode 100644 index 0000000..b25606d --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/SK_S_SM_DP4_TLS.pem b/smdpp-data/certs/DPtls/SK_S_SM_DP4_TLS.pem new file mode 100644 index 0000000..32bdfde --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/SK_S_SM_DP8_TLS.pem b/smdpp-data/certs/DPtls/SK_S_SM_DP8_TLS.pem new file mode 100644 index 0000000..51ca168 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_BRP.pem b/smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_BRP.pem new file mode 100644 index 0000000..6ad37b0 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_NIST.pem b/smdpp-data/certs/DPtls/SK_S_SM_DP_TLS_NIST.pem new file mode 100644 index 0000000..c1329f9 --- /dev/null +++ b/smdpp-data/certs/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/smdpp-data/certs/README b/smdpp-data/certs/README new file mode 100644 index 0000000..a3cd547 --- /dev/null +++ b/smdpp-data/certs/README @@ -0,0 +1 @@ +files taken from SGP.26 v3 diff --git a/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.1_NoBERTLV.rename2der b/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.1_NoBERTLV.rename2der new file mode 100644 index 0000000..7800677 --- /dev/null +++ b/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.1_NoBERTLV.rename2der Binary files differ diff --git a/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.3_NoBERTLV.rename2der b/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.3_NoBERTLV.rename2der new file mode 100644 index 0000000..0a0bdff --- /dev/null +++ b/smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.3_NoBERTLV.rename2der Binary files differ diff --git a/tests/test_esim.py b/tests/test_esim.py new file mode 100755 index 0000000..d4b494e --- /dev/null +++ b/tests/test_esim.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +# (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 unittest +import logging +import base64 + +from pySim.utils import b2h, h2b +from pySim.esim.bsp import * +import pySim.esim.rsp as rsp + +from cryptography.hazmat.primitives.asymmetric import ec + +class TestECKA(unittest.TestCase): + def test_mode51(self): + curve = ec.SECP256R1() + euicc_otpk_der = h2b('0400f7b8d71403f21d84b00cd9e561178d737d3f4d065e62fee279271298dd4f074794ab791b9939d4461296efe388aa26731064263af988b7d2c4d77da44801b5') + smdp_otpk_der = h2b('04a27e2bdbd94dcf67d4c9ae5cb149d9d0f093be7a16dc41ec9db0318e4db72d09234a7d7631979a5d150eec40afe17ce41673df9d2f2e4246d60051c74eba7964') + smdp_otsk_bytes = h2b('fb68a38ccedb69e15cbe03c256228998ac398587e5dc7117f948145c839d61a4') + expected_shared_secret = h2b('c9a993dd4879a8f7161f2085410edd4f9652f1df37be097ba96ba2ca6be528fe') + + euicc_otpk = ec.EllipticCurvePublicKey.from_encoded_point(curve, bytes(euicc_otpk_der)) + smdp_otpk = ec.EllipticCurvePublicKey.from_encoded_point(curve, bytes(smdp_otpk_der)) + smdp_otsk = ec.derive_private_key(int.from_bytes(smdp_otsk_bytes, 'big'), curve) + + shared_secret = smdp_otsk.exchange(ec.ECDH(), euicc_otpk) + + self.assertEqual(shared_secret, expected_shared_secret) + + +class TestBSPdecode(unittest.TestCase): + bpp_b64 = "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" + + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_esim_bsp.py b/tests/test_esim_bsp.py index 650b1fd..d7b37b0 100755 --- a/tests/test_esim_bsp.py +++ b/tests/test_esim_bsp.py @@ -21,6 +21,7 @@ from pySim.utils import b2h, h2b from pySim.esim.bsp import * +import pySim.esim.rsp as rsp class BSP_Test(unittest.TestCase): shared_secret = h2b('8902dca391bbb22570fe60c176076246f568b1941265dff1d729e63039658089') @@ -68,5 +69,30 @@ self.assertEqual(output, h2b('868203f8648e034ae0dc4ce022ee1e60b130dda95e13b21b0da3de7677677f47900c1beb3637b8aa35f3a9e096c0285ffe3e931983df900b36b7e6bc4b9af14b0ee3d49637eb2d4cff314b5d00789a751dfd9554651fb2b7c66ad4e22a794d5b88cb71ccf4c05d53abeba8bd3b0c8209346f014cbdee62be4878e3fea09a96007135a6c584aa843c48972842bdbece1c439723021b3f0d535d557995beedbd2b56f416148df90cb1a4d2fa26288801d56a2cbb0a404f2fd9a73042d7a3486bfb7256c1d274aae5b7ec24e8eba28b7dce69edc44189b24186b98397b4a74831f8ab46e8e46a2ed3077d4924f5d3f6e4c1de5ddffd194e7f0f97d94ea2801d1364835c9871bae6539e3e1355c5970711d845864f04d9c1dccac0d4068dcf4664e9976509fe43fec6beb3ddc96839aba6d89bb1593c5b6ebbc32fff39c4a5bb3e5c9df6a1abc05818dbd5149733381e69521066e1bbd648eb19b00602767e90beaeb3b3b92679940a603c0500e37892d7b4fa44355c3deec8af207f89d04f83cd88603e9cb9c96f74643816e87af85a8a9d0283cdf535d1fbaefb930fd4a0dba2ae30ee9d2d9e2a31827a012a6380af42ac87f3bfd7079ddd8fa27d2299fb4d5879e9a17a5062e13cab4f7bed22ed54932fa53d630bca8592f957a7ed148e9d4f28075c2565a550694b876091a1181ba512e70fde4f28ae6968a18d721396c0fee9cd7744dee90bf85f5adddb3417b3ede9ea3cfd5eae2d820b17600ce3b95f6df38a5bc39302c5155c3f241ddfc7cee527af7f6a67868a577c39e76e26c4ed5d6aca031a97c280da27ae8de20e57a1dbab40a31e96e054f9a6f50578fd00156e37b70eead71af3258075c1ba84282aea462553504a868443b301ed99dcd5f414b720ef67cf5c4d16f1f7b9df741c2343246dcb717f3fa62b633539bdcc0082d161499caad8d097be78133dafd19777559f77c6d7a8f61323ff660613aa47cee26a4f7515204eee3c7eaa00eb55529b0ddae3436ec679fc591fe2063de94db00b5d0f041beeb80a91f108f7cf4b3b1344b0fbb437630ee437b4c7744c54009a59a9099681f3a3fa386f294c0eb4562581202a369772833efdc6e840695352de3864671e7fb0fd081ec162a2a62ea5b8a9da837f3920b4196fbe2ec912ade440537ae4a07dfc115c9c030539f278e0801bda4f15298ba50e329b18992af8b899686ec97175509d4a217d2eba8feef5f5732fc7be86370f7723896b784bd45517af86a7521e952b6be924d91a5190e3c2c65ce8924df43ddb25c529dde324a722a156df459f4b38bb062975fad9fadd27f6425e422b1abd9a7259f0bd712a486e1aa25ca848cf65c5fb888bf61ae136b68cf55cb643c198537cd83df0dbb842c5f4982ca3088cc2d8e867c3049a84b515ec39b0b774a8482099327006acff')) +class TestBSPdecode(unittest.TestCase): + """This test verifies whether some fully encoded/encrypted/MACed bound profile package can be properly + decrypted and verified using our BSP code base.""" + bpp_b64 = "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" + + def test_decrypt_and_mac_verify(self): + bpp_bin = base64.b64decode(self.bpp_b64) + iscr = rsp.asn1.decode('BoundProfilePackage', bpp_bin) + + # BSP segment for ConfigureISDP using S-ENC/S-MAC + bsp = BspInstance(h2b('f11b921c302efb1df6bf218bf2de0dd8'), h2b('8cd4d3a761eeac108641d5f4531a137e'), h2b('ee3140eafd692b68eff40119b363bc6c')) + plain_cfg_isdp = bsp.demac_and_decrypt(iscr['firstSequenceOf87']) + self.assertEqual(plain_cfg_isdp, h2b('bf2400')) + + # BSP segment for StoreMetadata using /S-MAC + plain_smd = bsp.demac_only(iscr['sequenceOf88']) + self.assertEqual(plain_smd, h2b('bf25285a0a89000123456789012341910a4f736d6f636f6d53504e920e4f736d6f636f6d50726f66696c65')) + + # BSP payload using PPK-ENC/PPK-MAC + bsp_ppk = BspInstance(h2b('00000000000000000000000000000000'), h2b('11111111111111111111111111111111'), h2b('22222222222222222222222222222222')) + plain_upp = bsp_ppk.demac_and_decrypt(iscr['sequenceOf86']) + original_upp = b'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wLSCCiugBYAAgQEJgQZngQ8BAgWiEaEPggJBIYMCbwWLA28GBaUAoxmhF4ICQSGDAm83iwNvBgmIAKUGwAFAwgEApB+hHYIERiEAA4MCbzmLA28GC4ABD4gB4KUGwAGAwgEApRqhFIICQSGDAm8+iwNvBgSAAQKIAKUAgwL//6YaoRSCAkEhgwJvP4sDbwYEgAECiAClAIMC//+nGKEWggRCIQAcgwJvQIsDbwYEgAE4iAClAKgaoRGCAkEhgwJvQYsDbwYBiAClAIMF////AACpFqEUggJBIYMCb0WLA28GAoABCIgApQCqFKESggJBIYMCb0iLA28GBIABCKUAqxihFoIEQiEAHIMCb0mLA28GCoABjIgApQCsHKEaggRCIQANgwJvS4sDbwYBgAFBiAClBMECAP+tHKEaggRCIQANgwJvTIsDbwYDgAFBiAClBMECAP+uFqEUggJBIYMCb1CLA28GBoABEIgApQCvgcGhEoICQSGDAm9giwNvBgaAAaqlAIOBqv///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAAsIIBEaESggJBIYMCb2GLA28GA4AB+qUAg4H6////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AALGCARGhEoICQSGDAm9iiwNvBgOAAfqlAIOB+v///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AAD///8AAP///wAA////AACyFqEUggJBIYMCbyyLA28GAogApQPAAUCzGaEXggJBIYMCbzKLA28GA4ABPIgApQPAAUC0HaEbggRCIQAegwJvR4sDbwYCgAIBLIgApQTBAgD/tRuhGYIEQiEAFYMCb02LA28GAYABP4gApQPAAUC2HKEaggRCIQANgwJvTosDbwYCgAFBiAClBMECAP+3E6ERggRCIQAPgwJvT4sDbwYCpQC5GqEYggJBIYMCb1eLA28GAYAByIgApQTBAgD/uhuhGYIEQiEAVYMCb1iLA28GA4ABqogApQPAAUC7RKFCggRGIQAqgwJvgIsDbwYCgAHSpS7AAYDBKf//////////////////////////////////////////////AAAAAAD/vEOhQYIERiEAKYMCb4GLA28GAoABzaUtwAGAwSj//////////////////////////////////////////////wAAAAD/vR6hHIIERiEAA4MCb4KLA28GC4ABHogApQbAAYDCAQC+HqEcggRGIQADgwJvg4sDbwYLgAEeiAClBsABgMIBAL8fgeShF4ICQSGDAm+xiwNvBgSAAciIAKUDwAFAg4HIIf///yHz//8hQ///IUP4/yFDGf8hUyD5IVPx/yFT8v8hU/P/IVP0/yFT9f8hU/b/IVP3/yFT+P8hU/n/AgDw/wIA8f8CAPL/AgDz/wIA9P8CAPX/AgD2/wIA9/8CAPj/AgD5/wIQ8P9mZvD/Zmbx/2Zm8v9mZoP/Zmb0/2Zm9f9mZvb/Zmb3/2Zm+P9mZvn/Znbw/wgh8P8IIfH/CCHy/wgh8/8IIfT/CCH1/wgh9v8IIff/CCH4/wgh+f8IMfD/mZn5/xEREfm/IB+hFIICQSGDAm+yiwNvBgOIAKUDwAFAgwcVAAAA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' + self.assertEqual(plain_upp, base64.b64decode(original_upp)) + + if __name__ == "__main__": unittest.main() -- 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: 12 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-MessageType: merged
1 0
0 0
[XL] Change in pysim[master]: pySim.saip.*: Support for parsing / operating on eSIM profiles
by laforge 09 Jan '24

09 Jan '24
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/35491?usp=email ) Change subject: pySim.saip.*: Support for parsing / operating on eSIM profiles ...................................................................... pySim.saip.*: Support for parsing / operating on eSIM profiles This commit introduces the capability to parse and encode SimAlliance/TCA "Interoperable Profiles" and apply personalization operations on them. Change-Id: I71c252a214a634e1bd6f73472107efe2688ee6d2 --- A pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn A pySim/esim/saip/__init__.py A pySim/esim/saip/personalization.py A pySim/esim/saip/validation.py A tests/test_esim_saip.py 5 files changed, 1,681 insertions(+), 0 deletions(-) Approvals: laforge: Looks good to me, approved Jenkins Builder: Verified diff --git a/pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn b/pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn new file mode 100644 index 0000000..a9cccc9 --- /dev/null +++ b/pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn @@ -0,0 +1,1126 @@ +PEDefinitions {joint-iso-itu-t(2) international-organizations(23) tca(143) euicc-profile(1) spec-version(1) version-three(3)} +DEFINITIONS +AUTOMATIC TAGS +EXTENSIBILITY IMPLIED ::= +BEGIN +EXPORTS UICCCapability; -- Definition to be used in remote provisioning specifications for eligibility check + +-- Basic integer types, for size constraints +maxUInt8 INTEGER ::= 255 +UInt8 ::= INTEGER (0..maxUInt8) +maxUInt15 INTEGER ::= 32767 +UInt15 ::= INTEGER (0..maxUInt15) +maxUInt16 INTEGER ::= 65535 +UInt16 ::= INTEGER (0..maxUInt16) +maxUInt31 INTEGER ::= 2147483647 +UInt31 ::= INTEGER (0..maxUInt31) + +ApplicationIdentifier ::= OCTET STRING (SIZE(5..16)) + +PEHeader ::= SEQUENCE { +mandated NULL OPTIONAL, +-- if set, indicate that the support of this PE is mandatory +identification UInt15 -- Identification number of this PE +} + +ProfileElement ::= CHOICE { + header ProfileHeader, + +/* PEs */ + genericFileManagement PE-GenericFileManagement, + pinCodes PE-PINCodes, + pukCodes PE-PUKCodes, + akaParameter PE-AKAParameter, + cdmaParameter PE-CDMAParameter, + securityDomain PE-SecurityDomain, + rfm PE-RFM, + application PE-Application, + nonStandard PE-NonStandard, + end PE-End, + rfu1 PE-Dummy, -- this avoids renumbering of tag values + rfu2 PE-Dummy, -- in case other non-file-system PEs are + rfu3 PE-Dummy, -- added here in future versions + rfu4 PE-Dummy, + rfu5 PE-Dummy, + +/* PEs related to file system creation using templates defined in this specification */ + mf PE-MF, + cd PE-CD, + telecom PE-TELECOM, + usim PE-USIM, + opt-usim PE-OPT-USIM, + isim PE-ISIM, + opt-isim PE-OPT-ISIM, + phonebook PE-PHONEBOOK, + gsm-access PE-GSM-ACCESS, + csim PE-CSIM, + opt-csim PE-OPT-CSIM, + eap PE-EAP, + df-5gs PE-DF-5GS, + df-saip PE-DF-SAIP, + df-snpn PE-DF-SNPN, + df-5gprose PE-DF-5GPROSE, + iot PE-IoT, + opt-iot PE-OPT-IoT, +... +} + +PE-Dummy ::= SEQUENCE { +} + +ProfileHeader ::= SEQUENCE { +major-version UInt8, -- set to 3 for this version of the specification +minor-version UInt8, -- set to 3 for this version of the specification +profileType UTF8String (SIZE (1..100)) OPTIONAL, -- Profile type +iccid OCTET STRING (SIZE (10)), -- ICCID of the Profile +pol OCTET STRING OPTIONAL, +eUICC-Mandatory-services ServicesList, +eUICC-Mandatory-GFSTEList SEQUENCE OF OBJECT IDENTIFIER, +connectivityParameters OCTET STRING OPTIONAL, +eUICC-Mandatory-AIDs SEQUENCE OF SEQUENCE { + aid ApplicationIdentifier, + version OCTET STRING (SIZE(2)) +} OPTIONAL, +iotOptions IotOptions OPTIONAL -- details for IoT Minimal Profile, mandatory for IoT Minimal Profiles +} + +IotOptions ::= SEQUENCE { +pix OCTET STRING (SIZE (7..11)) -- PIX value to be used for IoT Minimal Profiles +} + +ServicesList ::= SEQUENCE { +/* Contactless */ +contactless NULL OPTIONAL, + +/* NAAs */ +usim NULL OPTIONAL, +isim NULL OPTIONAL, +csim NULL OPTIONAL, + +/* NAA algorithms */ +milenage NULL OPTIONAL, +tuak128 NULL OPTIONAL, +cave NULL OPTIONAL, + +/* USIM/ISIM services */ +gba-usim NULL OPTIONAL, +gba-isim NULL OPTIONAL, +mbms NULL OPTIONAL, + +/* EAP service */ +eap NULL OPTIONAL, + +/* Application Runtime environment */ + javacard NULL OPTIONAL, + multos NULL OPTIONAL, + +/* NAAs */ +multiple-usim NULL OPTIONAL, +multiple-isim NULL OPTIONAL, +multiple-csim NULL OPTIONAL, + +/* Additional algorithms */ +tuak256 NULL OPTIONAL, +usim-test-algorithm NULL OPTIONAL, + +/* File type */ +ber-tlv NULL OPTIONAL, + +/* Linked files */ +dfLink NULL OPTIONAL, + +/* Support of CAT_TP */ +cat-tp NULL OPTIONAL, + +/* Support of 5G */ +get-identity NULL OPTIONAL, +profile-a-x25519 NULL OPTIONAL, +profile-b-p256 NULL OPTIONAL, +suciCalculatorApi NULL OPTIONAL, + +/* Support of DNS Resolution */ +dns-resolution NULL OPTIONAL, + +/* Support of GP Amd F SCP11 */ +scp11ac NULL OPTIONAL, +scp11c-authorization-mechanism NULL OPTIONAL, + +/* Support of S16 mode as defined in GP Amd D and Amd F */ +s16mode NULL OPTIONAL, + +/* Support of enhanced AKA algorithm defined in 3GPP */ +eaka NULL OPTIONAL +} + +-- Definition of UICCCapability +UICCCapability ::= BIT STRING { + contactlessSupport(0), -- Contactless (SWP, HCI and associated APIs) + usimSupport(1), -- USIM as defined by 3GPP + isimSupport(2), -- ISIM as defined by 3GPP + csimSupport(3), -- CSIM as defined by 3GPP2 + + akaMilenage(4), -- Milenage as AKA algorithm + akaCave(5), -- CAVE as authentication algorithm + akaTuak128(6), -- TUAK as AKA algorithm with 128 bit key length + akaTuak256(7), -- TUAK as AKA algorithm with 256 bit key length + usimTestAlgorithm(8), -- USIM test algorithm + rfu2(9), -- reserved for further algorithms + + gbaAuthenUsim(10), -- GBA authentication in the context of USIM + gbaAuthenISim(11), -- GBA authentication in the context of ISIM + mbmsAuthenUsim(12), -- MBMS authentication in the context of USIM + eapClient(13), -- EAP client + + javacard(14), -- Java Card(TM) support + multos(15), -- Multos support + + multipleUsimSupport(16), -- Multiple USIM applications are supported within the same Profile + multipleIsimSupport(17), -- Multiple ISIM applications are supported within the same Profile + multipleCsimSupport(18), -- Multiple CSIM applications are supported within the same Profile + + berTlvFileSupport(19), -- BER TLV files + dfLinkSupport(20), -- Linked Directory Files + catTp(21), -- Support of CAT TP + getIdentity(22), -- Support of the GET IDENTITY command as defined in ETSI TS 102 221 + profile-a-x25519(23), -- Support of ECIES Profile A as defined in 3GPP TS 33.501 [87] + profile-b-p256(24), -- Support of ECIES Profile B as defined in 3GPP TS 33.501 [87] + suciCalculatorApi(25), -- Support of the associated API for SUCI derivation as defined in 3GPP 31.130 [31.130] + dns-resolution(26), -- Support of DNS Resolution as defined by GP Amd B + scp11ac(27), -- Support of GP Amd F SCP11 variants a and c + scp11c-authorization-mechanism(28), -- Support of SCP11c authorization mechanism (Tag 'BF20') + s16mode(29), -- Support of S16 mode as defined in GP Amd D and Amd F + eaka(30), -- Support of enhanced AKA algorithm as defined in 3GPP TS [33.102] + iotminimal(31) -- Support of IoT Minimal Profile as described in section 7.5 +} + +ProprietaryInfo ::= SEQUENCE { + specialFileInformation [PRIVATE 0] OCTET STRING (SIZE (1)) DEFAULT '00'H, + + /* fillPattern, repeatPattern + only one of the parameters may be present. Coding and rules defined within ETSI TS 102 222 [102 222] apply + */ + + fillPattern [PRIVATE 1] OCTET STRING (SIZE(1..200)) OPTIONAL, + repeatPattern [PRIVATE 2] OCTET STRING (SIZE(1..200)) OPTIONAL, + /* Specific parameters for BER-TLV files */ + /* Shall be encoded on the minimum number of octets possible + (i.e. no leading bytes set to '00' are allowed)*/ + maximumFileSize [6] OCTET STRING OPTIONAL, + fileDetails [4] OCTET STRING (SIZE(1)) DEFAULT '01'H +} + +Fcp ::= SEQUENCE { + /* The fileDescriptor shall be encoded as defined in + ETSI TS 102 222 [102 222] + */ + fileDescriptor [2] OCTET STRING (SIZE(2..4)) OPTIONAL, + + /* fileID + For ADFs, the fileID is a temporary value (named temporary file ID + in this document) used only during the profile creation. It has to + be unique within a profile and is used for referencing files within + this ADF using the file path. + */ + fileID [3] OCTET STRING (SIZE(2)) OPTIONAL, + + /* dfName + Only applies for ADFs + */ + dfName [4] ApplicationIdentifier OPTIONAL, + + /* lcsi + Coding according to ETSI TS 102 222 [102 222] + */ + lcsi [10] OCTET STRING (SIZE (1)) DEFAULT '05'H, + + /* securityAttributesReferenced + Either containing EF ARR ID[2] + record number[1] or + record number[1] only and EF ARR ID implicitly known from the + context: File ID 2F06 is automatically applied for ADFs, + the MF and all files directly located under the MF + '6F06' for any other files + */ + securityAttributesReferenced [11] OCTET STRING (SIZE (1..3)) OPTIONAL, + + /* efFileSize + Mandatory for EF file types + Not allowed for DF files and EF link files + Shall be encoded on the minimum number of octets possible + (i.e. no leading bytes set to '00' are allowed) + */ + efFileSize [0] OCTET STRING OPTIONAL, + + /* pinStatusTemplateDO + Not allowed for EF files + Mandatory for DF/ADF files + */ + pinStatusTemplateDO [PRIVATE 6] OCTET STRING OPTIONAL, + + /* shortEFID + Not allowed for DF files + Optional for EF file types / equivalent to ETSI TS 102 222 + shortEFID not provided: in case of a template file, SFI + is set according to Annex A. For files created + by using GenericFileManagement, SFI is calculated from FID + shortEFID provided with no value: no SFI is supported + for this EF + shortEFID available with a length of 1 byte: + The Short File Identifier is coded from bits b8 to b4. + Bits b3,b2,b1 = 000. + */ + shortEFID [8] OCTET STRING (SIZE (0..1)) OPTIONAL, + + /* proprietaryEFInfo + Optional for EF file types + Not allowed for DF files + */ + proprietaryEFInfo [5] ProprietaryInfo OPTIONAL, + + /* linkPath + Specifies the path to the file to which shall be linked, + also valid for DFs. Files within ADFs are addressed + by the temporary file ID of the respective ADF. For the coding + see filePath. In case of a template link file, an empty linkPath indicates that the link file shall be turned into an independent file. + */ + linkPath [PRIVATE 7] OCTET STRING (SIZE (0..8)) OPTIONAL +} + +File ::= SEQUENCE OF CHOICE { + doNotCreate NULL, /* Indicates that this file shall not be created by the eUICC even if present in a PE referencing a "Created by Default" template. +This flag has no effect for the creation of files in the MF and shall not be used for all the files listed in a "Not Created by Default" template*/ + fileDescriptor Fcp, + fillFileOffset UInt16, + fillFileContent OCTET STRING +} + +PE-MF ::= SEQUENCE { +mf-header PEHeader, +templateID OBJECT IDENTIFIER, +mf File, +ef-pl File OPTIONAL, +ef-iccid File, +ef-dir File, +ef-arr File, +ef-umpc File OPTIONAL +} + +PE-CD ::= SEQUENCE { +cd-header PEHeader, +templateID OBJECT IDENTIFIER, +df-cd File, +ef-launchpad File OPTIONAL, +ef-icon File OPTIONAL +} + +PE-TELECOM ::= SEQUENCE { +telecom-header PEHeader, +templateID OBJECT IDENTIFIER, +df-telecom File, +ef-arr File OPTIONAL, +ef-rma File OPTIONAL, +ef-sume File OPTIONAL, +ef-ice-dn File OPTIONAL, +ef-ice-ff File OPTIONAL, +ef-psismsc File OPTIONAL, +df-graphics File OPTIONAL, + ef-img File OPTIONAL, + ef-iidf File OPTIONAL, + ef-ice-graphics File OPTIONAL, + ef-launch-scws File OPTIONAL, + ef-icon File OPTIONAL, +df-phonebook File OPTIONAL, + ef-pbr File OPTIONAL, + ef-ext1 File OPTIONAL, + ef-aas File OPTIONAL, + ef-gas File OPTIONAL, + ef-psc File OPTIONAL, + ef-cc File OPTIONAL, + ef-puid File OPTIONAL, + ef-iap File OPTIONAL, + ef-adn File OPTIONAL, + ef-pbc File OPTIONAL, + ef-anr File OPTIONAL, + ef-puri File OPTIONAL, + ef-email File OPTIONAL, + ef-sne File OPTIONAL, + ef-uid File OPTIONAL, + ef-grp File OPTIONAL, + ef-ccp1 File OPTIONAL, +df-multimedia File OPTIONAL, + ef-mml File OPTIONAL, + ef-mmdf File OPTIONAL, +df-mmss File OPTIONAL, + ef-mlpl File OPTIONAL, + ef-mspl File OPTIONAL, + ef-mmssmode File OPTIONAL, +df-mcs File OPTIONAL, + ef-mst File OPTIONAL, + ef-mcs-config File OPTIONAL, +df-v2x File OPTIONAL, + ef-vst File OPTIONAL, + ef-v2x-config File OPTIONAL, + ef-v2xp-pc5 File OPTIONAL, + ef-v2xp-Uu File OPTIONAL +} + +PE-USIM ::= SEQUENCE { +usim-header PEHeader, +templateID OBJECT IDENTIFIER, +adf-usim File, +ef-imsi File, +ef-arr File, +ef-keys File OPTIONAL, +ef-keysPS File OPTIONAL, +ef-hpplmn File OPTIONAL, +ef-ust File, /* The content of UST file shall be modified by the eUICC during profile installation according to the functionality supported by the eUICC platform i.e. in the case where a service is not supported (and not indicated as required) the related bit(s) will be set to zero */ +ef-fdn File OPTIONAL, +ef-sms File OPTIONAL, +ef-smsp File OPTIONAL, +ef-smss File OPTIONAL, +ef-spn File, +ef-est File, +ef-start-hfn File OPTIONAL, +ef-threshold File OPTIONAL, +ef-psloci File OPTIONAL, +ef-acc File, +ef-fplmn File OPTIONAL, +ef-loci File OPTIONAL, +ef-ad File OPTIONAL, +ef-ecc File, +ef-netpar File OPTIONAL, +ef-epsloci File OPTIONAL, +ef-epsnsc File OPTIONAL +} + +PE-OPT-USIM ::= SEQUENCE { +optusim-header PEHeader, +templateID OBJECT IDENTIFIER, +ef-li File OPTIONAL, +ef-acmax File OPTIONAL, +ef-acm File OPTIONAL, +ef-gid1 File OPTIONAL, +ef-gid2 File OPTIONAL, +ef-msisdn File OPTIONAL, +ef-puct File OPTIONAL, +ef-cbmi File OPTIONAL, +ef-cbmid File OPTIONAL, +ef-sdn File OPTIONAL, +ef-ext2 File OPTIONAL, +ef-ext3 File OPTIONAL, +ef-cbmir File OPTIONAL, +ef-plmnwact File OPTIONAL, +ef-oplmnwact File OPTIONAL, +ef-hplmnwact File OPTIONAL, +ef-dck File OPTIONAL, +ef-cnl File OPTIONAL, +ef-smsr File OPTIONAL, +ef-bdn File OPTIONAL, +ef-ext5 File OPTIONAL, +ef-ccp2 File OPTIONAL, +ef-ext4 File OPTIONAL, +ef-acl File OPTIONAL, +ef-cmi File OPTIONAL, +ef-ici File OPTIONAL, +ef-oci File OPTIONAL, +ef-ict File OPTIONAL, +ef-oct File OPTIONAL, +ef-vgcs File OPTIONAL, +ef-vgcss File OPTIONAL, +ef-vbs File OPTIONAL, +ef-vbss File OPTIONAL, +ef-emlpp File OPTIONAL, +ef-aaem File OPTIONAL, +ef-hiddenkey File OPTIONAL, +ef-pnn File OPTIONAL, +ef-opl File OPTIONAL, +ef-mbdn File OPTIONAL, +ef-ext6 File OPTIONAL, +ef-mbi File OPTIONAL, +ef-mwis File OPTIONAL, +ef-cfis File OPTIONAL, +ef-ext7 File OPTIONAL, +ef-spdi File OPTIONAL, +ef-mmsn File OPTIONAL, +ef-ext8 File OPTIONAL, +ef-mmsicp File OPTIONAL, +ef-mmsup File OPTIONAL, +ef-mmsucp File OPTIONAL, +ef-nia File OPTIONAL, +ef-vgcsca File OPTIONAL, +ef-vbsca File OPTIONAL, +ef-gbabp File OPTIONAL, +ef-msk File OPTIONAL, +ef-muk File OPTIONAL, +ef-ehplmn File OPTIONAL, +ef-gbanl File OPTIONAL, +ef-ehplmnpi File OPTIONAL, +ef-lrplmnsi File OPTIONAL, +ef-nafkca File OPTIONAL, +ef-spni File OPTIONAL, +ef-pnni File OPTIONAL, +ef-ncp-ip File OPTIONAL, +ef-ufc File OPTIONAL, +ef-nasconfig File OPTIONAL, +ef-uicciari File OPTIONAL, +ef-pws File OPTIONAL, +ef-fdnuri File OPTIONAL, +ef-bdnuri File OPTIONAL, +ef-sdnuri File OPTIONAL, +ef-ial File OPTIONAL, -- This file was known as ef-iwl in Version 3.2 and earlier of this specification +ef-ips File OPTIONAL, +ef-ipd File OPTIONAL, +ef-epdgid File OPTIONAL, +ef-epdgselection File OPTIONAL, +ef-epdgidem File OPTIONAL, +ef-epdgselectionem File OPTIONAL, +ef-frompreferred File OPTIONAL, +ef-imsconfigdata File OPTIONAL, +ef-3gpppsdataoff File OPTIONAL, +ef-3gpppsdataoffservicelist File OPTIONAL, +ef-xcapconfigdata File OPTIONAL, +ef-earfcnlist File OPTIONAL, +ef-mudmidconfigdata File OPTIONAL, +ef-eaka File OPTIONAL +} + +PE-PHONEBOOK ::= SEQUENCE { +phonebook-header PEHeader, +templateID OBJECT IDENTIFIER, +df-phonebook File, +ef-pbr File OPTIONAL, +ef-ext1 File OPTIONAL, +ef-aas File OPTIONAL, +ef-gas File OPTIONAL, +ef-psc File OPTIONAL, +ef-cc File OPTIONAL, +ef-puid File OPTIONAL, +ef-iap File OPTIONAL, +ef-adn File OPTIONAL, +ef-pbc File OPTIONAL, +ef-anr File OPTIONAL, +ef-puri File OPTIONAL, +ef-email File OPTIONAL, +ef-sne File OPTIONAL, +ef-uid File OPTIONAL, +ef-grp File OPTIONAL, +ef-ccp1 File OPTIONAL +} + +PE-GSM-ACCESS ::= SEQUENCE { +gsm-access-header PEHeader, +templateID OBJECT IDENTIFIER, +df-gsm-access File, +ef-kc File OPTIONAL, +ef-kcgprs File OPTIONAL, +ef-cpbcch File OPTIONAL, +ef-invscan File OPTIONAL +} + +PE-DF-5GS ::= SEQUENCE { +df-5gs-header PEHeader, +templateID OBJECT IDENTIFIER, +df-df-5gs File, +ef-5gs3gpploci File OPTIONAL, +ef-5gsn3gpploci File OPTIONAL, +ef-5gs3gppnsc File OPTIONAL, +ef-5gsn3gppnsc File OPTIONAL, +ef-5gauthkeys File OPTIONAL, +ef-uac-aic File OPTIONAL, +ef-suci-calc-info File OPTIONAL, +ef-opl5g File OPTIONAL, +ef-supinai File OPTIONAL, +ef-routing-indicator File OPTIONAL, +ef-ursp File OPTIONAL, +ef-tn3gppsnn File OPTIONAL, +ef-cag File OPTIONAL, +ef-sor-cmci File OPTIONAL, +ef-dri File OPTIONAL, +ef-5gsedrx File OPTIONAL, +ef-5gnswo-conf File OPTIONAL, +ef-mchpplmn File OPTIONAL, +ef-kausf-derivation File OPTIONAL +} + +PE-DF-SAIP ::= SEQUENCE { +df-saip-header PEHeader, +templateID OBJECT IDENTIFIER, +df-df-saip File, +ef-suci-calc-info-usim File OPTIONAL +} + +PE-DF-SNPN ::= SEQUENCE { +df-snpn-header PEHeader, +templateID OBJECT IDENTIFIER, +df-df-snpn File, +ef-pws-snpn File OPTIONAL +} + +PE-DF-5GPROSE ::= SEQUENCE { +df-5g-prose-header PEHeader, +templateID OBJECT IDENTIFIER, +df-df-5g-prose File, +ef-5g-prose-st File OPTIONAL, +ef-5g-prose-dd File OPTIONAL, +ef-5g-prose-dc File OPTIONAL, +ef-5g-prose-u2nru File OPTIONAL, +ef-5g-prose-ru File OPTIONAL, +ef-5g-prose-uir File OPTIONAL +} + +PE-ISIM ::= SEQUENCE { +isim-header PEHeader, +templateID OBJECT IDENTIFIER, +adf-isim File, +ef-impi File, +ef-impu File, +ef-domain File, +ef-ist File, /* The content of IST file shall be modified by the eUICC during profile installation according to the functionality supported by the eUICC platform i.e. in the case where a service is not supported (and not indicated as required) the related bit(s) will be set to zero */ +ef-ad File OPTIONAL, +ef-arr File +} + +PE-OPT-ISIM ::= SEQUENCE { +optisim-header PEHeader, +templateID OBJECT IDENTIFIER, +ef-pcscf File OPTIONAL, +ef-sms File OPTIONAL, +ef-smsp File OPTIONAL, +ef-smss File OPTIONAL, +ef-smsr File OPTIONAL, +ef-gbabp File OPTIONAL, +ef-gbanl File OPTIONAL, +ef-nafkca File OPTIONAL, +ef-uicciari File OPTIONAL, +ef-frompreferred File OPTIONAL, +ef-imsconfigdata File OPTIONAL, +ef-xcapconfigdata File OPTIONAL, +ef-webrtcuri File OPTIONAL, +ef-mudmidconfigdata File OPTIONAL +} + +PE-CSIM ::= SEQUENCE { +csim-header PEHeader, +templateID OBJECT IDENTIFIER, +adf-csim File, +ef-arr File, +ef-call-count File, +ef-imsi-m File, +ef-imsi-t File, +ef-tmsi File, +ef-ah File, +ef-aop File, +ef-aloc File, +ef-cdmahome File, +ef-znregi File, +ef-snregi File, +ef-distregi File, +ef-accolc File, +ef-term File, +ef-acp File, +ef-prl File, +ef-ruimid File, +ef-csim-st File, +ef-spc File, +ef-otapaspc File, +ef-namlock File, +ef-ota File, +ef-sp File, +ef-esn-meid-me File, +ef-li File, +ef-usgind File, +ef-ad File, +ef-max-prl File, +ef-spcs File, +ef-mecrp File, +ef-home-tag File, +ef-group-tag File, +ef-specific-tag File, +ef-call-prompt File +} + +PE-OPT-CSIM ::= SEQUENCE { +optcsim-header PEHeader, +templateID OBJECT IDENTIFIER, +ef-ssci File OPTIONAL, +ef-fdn File OPTIONAL, +ef-sms File OPTIONAL, +ef-smsp File OPTIONAL, +ef-smss File OPTIONAL, +ef-ssfc File OPTIONAL, +ef-spn File OPTIONAL, +ef-mdn File OPTIONAL, +ef-ecc File OPTIONAL, +ef-me3gpdopc File OPTIONAL, +ef-3gpdopm File OPTIONAL, +ef-sipcap File OPTIONAL, +ef-mipcap File OPTIONAL, +ef-sipupp File OPTIONAL, +ef-mipupp File OPTIONAL, +ef-sipsp File OPTIONAL, +ef-mipsp File OPTIONAL, +ef-sippapss File OPTIONAL, +ef-puzl File OPTIONAL, +ef-maxpuzl File OPTIONAL, +ef-hrpdcap File OPTIONAL, +ef-hrpdupp File OPTIONAL, +ef-csspr File OPTIONAL, +ef-atc File OPTIONAL, +ef-eprl File OPTIONAL, +ef-bcsmscfg File OPTIONAL, +ef-bcsmspref File OPTIONAL, +ef-bcsmstable File OPTIONAL, +ef-bcsmsp File OPTIONAL, +ef-bakpara File OPTIONAL, +ef-upbakpara File OPTIONAL, +ef-mmsn File OPTIONAL, +ef-ext8 File OPTIONAL, +ef-mmsicp File OPTIONAL, +ef-mmsup File OPTIONAL, +ef-mmsucp File OPTIONAL, +ef-auth-capability File OPTIONAL, +ef-3gcik File OPTIONAL, +ef-dck File OPTIONAL, +ef-gid1 File OPTIONAL, +ef-gid2 File OPTIONAL, +ef-cdmacnl File OPTIONAL, +ef-sf-euimid File OPTIONAL, +ef-est File OPTIONAL, +ef-hidden-key File OPTIONAL, +ef-lcsver File OPTIONAL, +ef-lcscp File OPTIONAL, +ef-sdn File OPTIONAL, +ef-ext2 File OPTIONAL, +ef-ext3 File OPTIONAL, +ef-ici File OPTIONAL, +ef-oci File OPTIONAL, +ef-ext5 File OPTIONAL, +ef-ccp2 File OPTIONAL, +ef-applabels File OPTIONAL, +ef-model File OPTIONAL, +ef-rc File OPTIONAL, +ef-smscap File OPTIONAL, +ef-mipflags File OPTIONAL, +ef-3gpduppext File OPTIONAL, +ef-ipv6cap File OPTIONAL, +ef-tcpconfig File OPTIONAL, +ef-dgc File OPTIONAL, +ef-wapbrowsercp File OPTIONAL, +ef-wapbrowserbm File OPTIONAL, +ef-mmsconfig File OPTIONAL, +ef-jdl File OPTIONAL +} + +PE-EAP ::= SEQUENCE { +eap-header PEHeader, +templateID OBJECT IDENTIFIER, +df-eap File, +ef-eapkeys File OPTIONAL, +ef-eapstatus File, +ef-puid File OPTIONAL, +ef-ps File OPTIONAL, +ef-curid File OPTIONAL, +ef-reid File OPTIONAL, +ef-realm File OPTIONAL +} + +PE-IoT ::= SEQUENCE { +iot-header PEHeader, +templateID OBJECT IDENTIFIER, +mf File OPTIONAL, +ef-pl File OPTIONAL, +ef-iccid File OPTIONAL, +ef-dir File OPTIONAL, +ef-arr File OPTIONAL, +ef-umpc File OPTIONAL, +adf-usim File OPTIONAL, +ef-imsi File, +ef-arr-usim File OPTIONAL, +ef-keys File OPTIONAL, +ef-keysPS File OPTIONAL, +ef-hpplmn File OPTIONAL, +ef-ust File OPTIONAL, +ef-start-hfn File OPTIONAL, +ef-threshold File OPTIONAL, +ef-psloci File OPTIONAL, +ef-acc File, +ef-fplmn File OPTIONAL, +ef-loci File OPTIONAL, +ef-ad File OPTIONAL, +ef-ecc File OPTIONAL, +ef-netpar File OPTIONAL +} + +PE-OPT-IoT ::= SEQUENCE { +optiot-header PEHeader, +templateID OBJECT IDENTIFIER, +ef-fdn File OPTIONAL, +ef-sms File OPTIONAL, +ef-smsp File OPTIONAL, +ef-smss File OPTIONAL, +ef-spn File OPTIONAL, +ef-est File OPTIONAL, +ef-oplmnwact File OPTIONAL, +ef-hplmnwact File OPTIONAL, +ef-ehplmn File OPTIONAL, +ef-epsloci File OPTIONAL, +ef-epsnsc File OPTIONAL, +df-df-5gs File OPTIONAL, +ef-5gs3gpploci File OPTIONAL, +ef-5gsn3gpploci File OPTIONAL, +ef-5gs3gppnsc File OPTIONAL, +ef-5gsn3gppnsc File OPTIONAL, +ef-5gauthkeys File OPTIONAL, +ef-uac-aic File OPTIONAL, +ef-suci-calc-info File OPTIONAL, +ef-opl5g File OPTIONAL, +ef-supi-nai File OPTIONAL, +ef-routing-indicator File OPTIONAL, +ef-ursp File OPTIONAL, +ef-tn3gppsnn File OPTIONAL, +df-df-saip File OPTIONAL, +ef-suci-calc-info-usim File OPTIONAL +} + +/* Create GenericFileManagement +*/ +PE-GenericFileManagement ::= SEQUENCE { + gfm-header PEHeader, + fileManagementCMD SEQUENCE (SIZE (1..MAX)) OF FileManagement +} + +FileManagement ::= SEQUENCE (SIZE (1..MAX)) OF CHOICE { +filePath [0] OCTET STRING (SIZE (0..8)), -- Use Temporary File ID for ADF +createFCP [APPLICATION 2] Fcp, +fillFileOffset UInt16, +fillFileContent [1] OCTET STRING +} + +MappingParameter ::= SEQUENCE { +mappingOptions OCTET STRING (SIZE(1)), + mappingSource ApplicationIdentifier +} + +AlgoParameter ::= SEQUENCE { +algorithmID INTEGER { + milenage(1), + tuak(2), + usim-test-algorithm(3) +}, +algorithmOptions OCTET STRING (SIZE(1)), +key OCTET STRING, +opc OCTET STRING, /* OPc for Milenage; TOPc for TUAK; ignored in case of usim-test-algorithm */ + +/* rotationConstants only apply for Milenage; ignored in case of TUAK and usim-test-algorithm */ + rotationConstants OCTET STRING (SIZE (5)) DEFAULT '4000204060'H, + +/* xoringConstants only apply for Milenage; ignored in case of TUAK and usim-test-algorithm */ +xoringConstants OCTET STRING (SIZE (80)) DEFAULT '0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000020000000000000000000000000000000400000000000000000000000000000008 'H, +authCounterMax OCTET STRING (SIZE(3)) OPTIONAL, /* ignored in case of usim-test-algorithm */ + +/* Number of iterations of Keccak-f[1600] (noted: ) permutation as recommended by 3GPP TS 35.231 [TUAK] in section 7.2. +This parameter only applies for TUAK; ignored otherwise.*/ +numberOfKeccak UInt8 DEFAULT 1 +} + +PE-AKAParameter ::= SEQUENCE { + aka-header PEHeader, +algoConfiguration CHOICE { + mappingParameter MappingParameter, + algoParameter AlgoParameter +}, + +sqnOptions OCTET STRING (SIZE(1)) DEFAULT '02'H, /* ignored in case of usim-test-algorithm */ +-- maximum value for sqnDelta and sqnAgeLimit is '07FFFFFFFFFF'H +sqnDelta OCTET STRING (SIZE(6)) DEFAULT '000010000000'H, /* ignored in case of usim-test-algorithm */ +sqnAgeLimit OCTET STRING (SIZE(6)) DEFAULT '000010000000'H, /* ignored in case of usim-test-algorithm */ + +-- Sequence numbers do not include the index (IND) +-- maximum for any values within sqnInit is '07FFFFFFFFFF'H +sqnInit SEQUENCE (SIZE (32)) OF OCTET STRING (SIZE (6)) DEFAULT '000000000000'H +} + +PE-CDMAParameter ::= SEQUENCE { + cdma-header PEHeader, + +/* A-Key for CAVE Authentication */ +authenticationKey OCTET STRING (SIZE(8)), + +/* +Optional value for ssd +Bytes 1..8: value if shared secret data A +Bytes 9..16: value if shared secret data B +*/ +ssd OCTET STRING (SIZE (16)) OPTIONAL, + +/* + Shared Secrets for HRPD access authentication + Includes the shared secret data. This field is coded as defined in section 4.5.7.10 HRPD Access Authentication CHAP SS Parameters of [S0016]. +*/ +hrpdAccessAuthenticationData OCTET STRING (SIZE (2..32)) OPTIONAL, + +/* + Parameters for simple IP authentication are coded as defined in section 4.5.7.7 SimpleIP CHAP SS Parameters of [S0016]. +*/ +simpleIPAuthenticationData OCTET STRING (SIZE (3..483)) OPTIONAL, + +/* + Parameters for mobile IP authentication are coded as defined in section 4.5.7.8 MobileIP SS Parameters of [S0016]. +*/ +mobileIPAuthenticationData OCTET STRING (SIZE (5..957)) OPTIONAL +} + +PINKeyReferenceValue ::= INTEGER { +pinAppl1(1), -- PIN global of App 1 +pinAppl2(2), -- PIN global of App 2 +pinAppl3(3), -- PIN global of App 3 +pinAppl4(4), -- PIN global of App 4 +pinAppl5(5), -- PIN global of App 5 +pinAppl6(6), -- PIN global of App 6 +pinAppl7(7), -- PIN global of App 7 +pinAppl8(8), -- PIN global of App 8 +adm1(10), -- Administrative Key 1 +adm2(11), -- Administrative Key 2 +adm3(12), -- Administrative Key 3 +adm4(13), -- Administrative Key 4 +adm5(14), -- Administrative Key 5 +secondPINAppl1(129), -- PIN local of App 1 +secondPINAppl2(130), -- PIN local of App 2 +secondPINAppl3(131), -- PIN local of App 3 +secondPINAppl4(132), -- PIN local of App 4 +secondPINAppl5(133), -- PIN local of App 5 +secondPINAppl6(134), -- PIN local of App 6 +secondPINAppl7(135), -- PIN local of App 7 +secondPINAppl8(136), -- PIN local of App 8 +adm6(138), -- Administrative Key 6 +adm7(139), -- Administrative Key 7 +adm8(140), -- Administrative Key 8 +adm9(141), -- Administrative Key 9 +adm10(142) -- Administrative Key 10 +} + +PINConfiguration ::= SEQUENCE { +/* +For every value defined in PINKeyReferenceValue only one entry may be included per PE-PINCodes. +Within the PE-PINCodes sent in the context of the MF only global PIN key references shall be used. For PINs in any ADF/DF only local PINs shall be defined: secondPINAppl1 secondPINAppl8. It is allowed to define the same PINKeyReferenceValue in multiple directories (e.g. secondPINAppl1 may be defined in the ISIM NAA and within the USIM NAA). Provided they are not linked they shall be handled as two independent PIN values which also may reference different PUK references. +*/ + keyReference PINKeyReferenceValue, + pinValue OCTET STRING (SIZE (8)), +/* +In case no unblockingPINReference is set, no PUK applies for the corresponding PIN. +In case a PUKKeyReferenceValue is defined the related PUKKeyReferenceValue shall exist within the PE-PUKCodes list. +Any value defined in PUKKeyReferenceValue may be applied for any PINKeyReferenceValue. +*/ + unblockingPINReference PUKKeyReferenceValue OPTIONAL, + pinAttributes UInt8 DEFAULT 7, + maxNumOfAttemps-retryNumLeft UInt8 DEFAULT 51 +/* maxNumOfAttemps-retryNumLeft is encoded as follows: max Number of Attempts is encoded in the high nibble of this value (Bits b8 to b5) and the Number of retry left is encoded in the low nibble of this value (Bits b4 to b1)*/ +} + +PE-PINCodes ::= SEQUENCE { + pin-Header PEHeader, +pinCodes CHOICE { + pinconfig SEQUENCE (SIZE (1..26))OF PINConfiguration, + filePath OCTET STRING (SIZE (0..8)) /* temporary File ID for ADF, coding according to section 8.3.5 */ +} +/* PIN can be either defined in the current context or shared + with another DF/ADF + Up to 26 PIN could be defined according to TS 102 221 [102 221] +*/ +} + +PUKKeyReferenceValue ::= INTEGER { +pukAppl1(1), -- PUK Reference 1 +pukAppl2(2), -- PUK Reference 2 +pukAppl3(3), -- PUK Reference 3 +pukAppl4(4), -- PUK Reference 4 +pukAppl5(5), -- PUK Reference 5 +pukAppl6(6), -- PUK Reference 6 +pukAppl7(7), -- PUK Reference 7 +pukAppl8(8), -- PUK Reference 8 +secondPUKAppl1(129), -- PUK Reference 9 +secondPUKAppl2(130), -- PUK Reference 10 +secondPUKAppl3(131), -- PUK Reference 11 +secondPUKAppl4(132), -- PUK Reference 12 +secondPUKAppl5(133), -- PUK Reference 13 +secondPUKAppl6(134), -- PUK Reference 14 +secondPUKAppl7(135), -- PUK Reference 15 +secondPUKAppl8(136) -- PUK Reference 16 +} + +PUKConfiguration ::= SEQUENCE { +/* +Any PUKKeyReferenceValue shall only be defined once within PE-PUKCodes. +*/ + keyReference PUKKeyReferenceValue, + pukValue OCTET STRING (SIZE (8)), + maxNumOfAttemps-retryNumLeft UInt8 DEFAULT 170 +/* maxNumOfAttemps-retryNumLeft is encoded as follows: max Number of Attempts is encoded in the high nibble of this value (Bits b8 to b5) and the Number of retry left is encoded in the low nibble of this value (Bits b4 to b1)*/ +} + +PE-PUKCodes ::= SEQUENCE { + puk-Header PEHeader, +pukCodes SEQUENCE (SIZE (1..16))OF PUKConfiguration +} + +PE-SecurityDomain ::= SEQUENCE { + sd-Header PEHeader, +instance ApplicationInstance, -- see section 8.7.3 +keyList SEQUENCE (SIZE (1..MAX)) OF KeyObject OPTIONAL, -- see section 8.6.3 +sdPersoData SEQUENCE (SIZE (1..MAX)) OF OCTET STRING OPTIONAL, /* see section 8.6.4 */ +openPersoData SEQUENCE { + restrictParameter [PRIVATE 25] OCTET STRING (SIZE(1)) OPTIONAL, + contactlessProtocolParameters OCTET STRING OPTIONAL +} OPTIONAL, /* see section 8.6.6 */ +catTpParameters SEQUENCE +{ catTpMaxSduSize UInt16, + catTpMaxPduSize UInt16 +} OPTIONAL -- see section 8.6.7 +} + +KeyObject::= SEQUENCE { +keyUsageQualifier [21] OCTET STRING (SIZE (1..2)), /* see [GPCS] section 11.1.9 */ +keyAccess [22] OCTET STRING (SIZE (1)) DEFAULT '00'H, +keyIdentifier [2] OCTET STRING (SIZE (1)), +keyVersionNumber [3] OCTET STRING (SIZE (1)), +keyCounterValue [5] OCTET STRING OPTIONAL, +keyCompontents SEQUENCE (SIZE (1..MAX)) OF SEQUENCE { + keyType [0] OCTET STRING, + keyData [6] OCTET STRING, + macLength[7] UInt8 DEFAULT 8 + } +} + +PE-Application ::= SEQUENCE { + app-Header PEHeader, +loadBlock ApplicationLoadPackage OPTIONAL, +instanceList SEQUENCE (SIZE (1..MAX)) OF ApplicationInstance OPTIONAL +} + +ApplicationLoadPackage ::= SEQUENCE { +loadPackageAID [APPLICATION 15] ApplicationIdentifier, +securityDomainAID [APPLICATION 15] ApplicationIdentifier OPTIONAL, +nonVolatileCodeLimitC6 [PRIVATE 6] OCTET STRING OPTIONAL, +volatileDataLimitC7 [PRIVATE 7] OCTET STRING OPTIONAL, +nonVolatileDataLimitC8 [PRIVATE 8] OCTET STRING OPTIONAL, +hashValue [PRIVATE 1] OCTET STRING OPTIONAL, +loadBlockObject [PRIVATE 4] OCTET STRING +} + +ApplicationInstance ::= SEQUENCE { +applicationLoadPackageAID [APPLICATION 15] ApplicationIdentifier, +classAID [APPLICATION 15] ApplicationIdentifier, +instanceAID [APPLICATION 15] ApplicationIdentifier, +extraditeSecurityDomainAID [APPLICATION 15] ApplicationIdentifier OPTIONAL, +applicationPrivileges [2] OCTET STRING, +lifeCycleState [3] OCTET STRING (SIZE(1)) DEFAULT '07'H, +/* Coding according to GP Life Cycle State. */ + +applicationSpecificParametersC9 [PRIVATE 9] OCTET STRING, +systemSpecificParameters [PRIVATE 15] ApplicationSystemParameters OPTIONAL, +applicationParameters [PRIVATE 10] UICCApplicationParameters OPTIONAL, +processData SEQUENCE (SIZE (1..MAX)) OF OCTET STRING OPTIONAL, +controlReferenceTemplate [16] ControlReferenceTemplate OPTIONAL +} + +ApplicationSystemParameters ::= SEQUENCE{ +volatileMemoryQuotaC7 [PRIVATE 7] OCTET STRING (SIZE (2..4)) OPTIONAL, +nonVolatileMemoryQuotaC8 [PRIVATE 8] OCTET STRING (SIZE (2..4)) OPTIONAL, +globalServiceParameters [PRIVATE 11] OCTET STRING OPTIONAL, +implicitSelectionParameter [PRIVATE 15] OCTET STRING OPTIONAL, +volatileReservedMemory [PRIVATE 23] OCTET STRING (SIZE (2..4)) OPTIONAL, +nonVolatileReservedMemory [PRIVATE 24] OCTET STRING (SIZE (2..4)) OPTIONAL, +ts102226SIMFileAccessToolkitParameter [PRIVATE 10] OCTET STRING OPTIONAL, +ts102226AdditionalContactlessParameters [0] TS102226AdditionalContactlessParameters OPTIONAL, +contactlessProtocolParameters [PRIVATE 25] OCTET STRING OPTIONAL, /* Coded according to Contactless Protocol Parameters Structure as defined in GP Amd. C */ +userInteractionContactlessParameters [PRIVATE 26] OCTET STRING OPTIONAL, /* Coded according to User Interaction Parameters Structure as defined in GP Amd. C */ +cumulativeGrantedVolatileMemory [2] OCTET STRING (SIZE (2..4)) OPTIONAL, /* +Coded according to Contactless Specific Parameters as defined in GP Amd. C */ + +cumulativeGrantedNonVolatileMemory [3] OCTET STRING (SIZE (2..4)) OPTIONAL /* +Coded according to Contactless Specific Parameters as defined in GP Amd. C */ +} + +UICCApplicationParameters ::= SEQUENCE { +uiccToolkitApplicationSpecificParametersField [0] OCTET STRING OPTIONAL, +uiccAccessApplicationSpecificParametersField [1] OCTET STRING OPTIONAL, +uiccAdministrativeAccessApplicationSpecificParametersField [2] OCTET STRING OPTIONAL +} + +TS102226AdditionalContactlessParameters ::= SEQUENCE{ +protocolParameterData OCTET STRING /* Parameters for contactless applications encoded according to TS 102 226 */ +} + +ControlReferenceTemplate ::= SEQUENCE{ +applicationProviderIdentifier [APPLICATION 32] OCTET STRING +} + + +PE-RFM ::= SEQUENCE { +rfm-header [0] PEHeader, + + /* instanceAID + AID of the RFM instance + */ + instanceAID [APPLICATION 15] ApplicationIdentifier, + + /* securityDomainAID to which the RFM instance is associated + */ + securityDomainAID [APPLICATION 15] ApplicationIdentifier OPTIONAL, + + tarList [0] SEQUENCE (SIZE (1..MAX)) OF OCTET STRING (SIZE(3)) OPTIONAL, + + minimumSecurityLevel [1] OCTET STRING (SIZE (1)), + +uiccAccessDomain OCTET STRING, + uiccAdminAccessDomain OCTET STRING, + + /* + If the following parameter is available the respective ADF shall be the directory selected by default within an RFM script. In case it is not available the MF shall be the default selection. + */ + adfRFMAccess ADFRFMAccess OPTIONAL +} + +ADFRFMAccess ::= SEQUENCE { + adfAID ApplicationIdentifier, + adfAccessDomain OCTET STRING, + adfAdminAccessDomain OCTET STRING +} + +PE-NonStandard ::= SEQUENCE { +nonStandard-header PEHeader, +issuerID OBJECT IDENTIFIER, +content OCTET STRING +} + +PE-End ::= SEQUENCE { +end-header PEHeader +} + +PEStatus ::= SEQUENCE { +status INTEGER { +ok(0), pe-not-supported(1), memory-failure(2),bad-values(3), +not-enough-memory(4),invalid-request-format(5), invalid-parameter(6), +runtime-not-supported (7), lib-not-supported (8), +template-not-supported (9), feature-not-supported (10), +pin-code-missing (11), +unsupported-profile-version(31) +/* ISO 7816 standard status values apply in the range of [24576...28671] +and [36864...40959] for reporting status values '6xxx'H and '9xxx'H +proprietary values apply in the range [40960...65535] +*/ +}, +identification UInt15 OPTIONAL, +-- Identification number of the PE triggering the error +additional-information UInt8 OPTIONAL, +-- Additional information related to the status code +offset UInt31 OPTIONAL +-- Position of the part of the PE generating this status code +} + +EUICCResponse ::= SEQUENCE { + peStatus SEQUENCE OF PEStatus, +profileInstallationAborted NULL OPTIONAL, +statusMessage UTF8String (SIZE (2..64)) OPTIONAL +} + +END diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py new file mode 100644 index 0000000..9b182e5 --- /dev/null +++ b/pySim/esim/saip/__init__.py @@ -0,0 +1,229 @@ +# Implementation of SimAlliance/TCA Interoperable Profile handling +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import abc +from typing import Tuple, List, Optional, Dict + +import asn1tools + +from pySim.utils import bertlv_parse_tag, bertlv_parse_len +from pySim.esim import compile_asn1_subdir + +asn1 = compile_asn1_subdir('saip') + +class oid: + class OID: + @staticmethod + def intlist_from_str(instr: str) -> List[int]: + return [int(x) for x in instr.split('.')] + + def __init__(self, initializer): + if type(initializer) == str: + self.intlist = self.intlist_from_str(initializer) + else: + self.intlist = initializer + + def __str__(self): + return '.'.join([str(x) for x in self.intlist]) + + def __repr__(self): + return 'OID(%s)' % (str(self)) + + + class eOID(OID): + """OID helper for TCA eUICC prefix""" + __prefix = [2,23,143,1] + def __init__(self, initializer): + if type(initializer) == str: + initializer = self.intlist_from_str(initializer) + super().__init__(self.__prefix + initializer) + + MF = eOID("2.1") + DF_CD = eOID("2.2") + DF_TELECOM = eOID("2.3") + DF_TELECOM_v2 = eOID("2.3.2") + ADF_USIM_by_default = eOID("2.4") + ADF_USIM_by_default_v2 = eOID("2.4.2") + ADF_USIM_not_by_default = eOID("2.5") + ADF_USIM_not_by_default_v2 = eOID("2.5.2") + ADF_USIM_not_by_default_v3 = eOID("2.5.3") + DF_PHONEBOOK_ADF_USIM = eOID("2.6") + DF_GSM_ACCESS_ADF_USIM = eOID("2.7") + ADF_ISIM_by_default = eOID("2.8") + ADF_ISIM_not_by_default = eOID("2.9") + ADF_ISIM_not_by_default_v2 = eOID("2.9.2") + ADF_CSIM_by_default = eOID("2.10") + ADF_CSIM_by_default_v2 = eOID("2.10.2") + ADF_CSIM_not_by_default = eOID("2.11") + ADF_CSIM_not_by_default_v2 = eOID("2.11.2") + DF_EAP = eOID("2.12") + DF_5GS = eOID("2.13") + DF_5GS_v2 = eOID("2.13.2") + DF_5GS_v3 = eOID("2.13.3") + DF_5GS_v4 = eOID("2.13.4") + DF_SAIP = eOID("2.14") + DF_SNPN = eOID("2.15") + DF_5GProSe = eOID("2.16") + IoT_default = eOID("2.17") + IoT_default = eOID("2.18") + + +class ProfileElement: + def _fixup_sqnInit_dec(self): + """asn1tools has a bug when working with SEQUENCE OF that have DEFAULT values. Let's work around + this.""" + if self.type != 'akaParameter': + return + sqn_init = self.decoded.get('sqnInit', None) + if not sqn_init: + return + # this weird '0x' value in a string is what we get from our (slightly hacked) ASN.1 syntax + if sqn_init == '0x000000000000': + # SEQUENCE (SIZE (32)) OF OCTET STRING (SIZE (6)) + self.decoded['sqnInit'] = [b'\x00'*6] * 32 + + def _fixup_sqnInit_enc(self): + """asn1tools has a bug when working with SEQUENCE OF that have DEFAULT values. Let's work around + this.""" + if self.type != 'akaParameter': + return + sqn_init = self.decoded.get('sqnInit', None) + if not sqn_init: + return + for s in sqn_init: + if any(s): + return + # none of the fields were initialized with a non-default (non-zero) value, so we can skip it + del self.decoded['sqnInit'] + + def parse_der(self, der: bytes): + """Parse a sequence of PE and store the result in instance attributes.""" + self.type, self.decoded = asn1.decode('ProfileElement', der) + # work around asn1tools bug regarding DEFAULT for a SEQUENCE OF + self._fixup_sqnInit_dec() + + @classmethod + def from_der(cls, der: bytes) -> 'ProfileElement': + """Construct an instance from given raw, DER encoded bytes.""" + inst = cls() + inst.parse_der(der) + return inst + + def to_der(self) -> bytes: + """Build an encoded DER representation of the instance.""" + # work around asn1tools bug regarding DEFAULT for a SEQUENCE OF + self._fixup_sqnInit_enc() + return asn1.encode('ProfileElement', (self.type, self.decoded)) + + def __str__(self): + return self.type + + +def bertlv_first_segment(binary: bytes) -> Tuple[bytes, bytes]: + """obtain the first segment of a binary concatenation of BER-TLV objects. + Returns: tuple of first TLV and remainder.""" + tagdict, remainder = bertlv_parse_tag(binary) + length, remainder = bertlv_parse_len(remainder) + tl_length = len(binary) - len(remainder) + tlv_length = tl_length + length + return binary[:tlv_length], binary[tlv_length:] + +class ProfileElementSequence: + """A sequence of ProfileElement objects, which is the overall representation of an eSIM profile.""" + def __init__(self): + self.pe_list: List[ProfileElement] = None + self.pe_by_type: Dict = {} + self.pes_by_naa: Dict = {} + + def get_pes_for_type(self, tname: str) -> List[ProfileElement]: + return self.pe_by_type.get(tname, []) + + def get_pe_for_type(self, tname: str) -> Optional[ProfileElement]: + l = self.get_pes_for_type(tname) + if len(l) == 0: + return None + assert len(l) == 1 + return l[0] + + def parse_der(self, der: bytes): + """Parse a sequence of PE and store the result in self.pe_list.""" + self.pe_list = [] + remainder = der + while len(remainder): + first_tlv, remainder = bertlv_first_segment(remainder) + self.pe_list.append(ProfileElement.from_der(first_tlv)) + self._process_pelist() + + def _process_pelist(self): + self._rebuild_pe_by_type() + self._rebuild_pes_by_naa() + + def _rebuild_pe_by_type(self): + self.pe_by_type = {} + # build a dict {pe_type: [pe, pe, pe]} + for pe in self.pe_list: + if pe.type in self.pe_by_type: + self.pe_by_type[pe.type].append(pe) + else: + self.pe_by_type[pe.type] = [pe] + + def _rebuild_pes_by_naa(self): + """rebuild the self.pes_by_naa dict {naa: [ [pe, pe, pe], [pe, pe] ]} form, + which basically means for every NAA there's a lsit of instances, and each consists + of a list of a list of PEs.""" + self.pres_by_naa = {} + petype_not_naa_related = ['securityDomain', 'rfm', 'application', 'end'] + naa = ['mf', 'usim', 'isim', 'csim'] + cur_naa = None + cur_naa_list = [] + for pe in self.pe_list: + # skip all PE that are not related to NAA + if pe.type in petype_not_naa_related: + continue + if pe.type in naa: + if cur_naa: + if not cur_naa in self.pes_by_naa: + self.pes_by_naa[cur_naa] = [] + self.pes_by_naa[cur_naa].append(cur_naa_list) + cur_naa = pe.type + cur_naa_list = [] + cur_naa_list.append(pe) + # append the final one + if cur_naa and len(cur_naa_list): + if not cur_naa in self.pes_by_naa: + self.pes_by_naa[cur_naa] = [] + self.pes_by_naa[cur_naa].append(cur_naa_list) + + @classmethod + def from_der(cls, der: bytes) -> 'ProfileElementSequence': + """Construct an instance from given raw, DER encoded bytes.""" + inst = cls() + inst.parse_der(der) + return inst + + def to_der(self) -> bytes: + """Build an encoded DER representation of the instance.""" + out = b'' + for pe in self.pe_list: + out += pe.to_der() + return out + + def __repr__(self): + return "PESequence(%s)" % ', '.join([str(x) for x in self.pe_list]) + + def __iter__(self): + yield from self.pe_list diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py new file mode 100644 index 0000000..32a53e6 --- /dev/null +++ b/pySim/esim/saip/personalization.py @@ -0,0 +1,150 @@ +# Implementation of SimAlliance/TCA Interoperable Profile handling +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import abc +from typing import List, Tuple, Optional + +from pySim.esim.saip import ProfileElement, ProfileElementSequence + +def remove_unwanted_tuples_from_list(l: List[Tuple], unwanted_key:str) -> List[Tuple]: + """In a list of tuples, remove all tuples whose first part equals 'unwanted_key'.""" + return list(filter(lambda x: x[0] != unwanted_key, l)) + +def file_replace_content(file: List[Tuple], new_content: bytes): + """Completely replace all fillFileContent of a decoded 'File' with the new_content.""" + file = remove_unwanted_tuples_from_list(file, 'fillFileContent') + file.append(('fillFileContent', new_content)) + return file + +class ClassVarMeta(abc.ABCMeta): + """Metaclass that puts all additional keyword-args into the class.""" + def __new__(metacls, name, bases, namespace, **kwargs): + #print("Meta_new_(metacls=%s, name=%s, bases=%s, namespace=%s, kwargs=%s)" % (metacls, name, bases, namespace, kwargs)) + x = super().__new__(metacls, name, bases, namespace) + for k, v in kwargs.items(): + setattr(x, k, v) + return x + +class ConfigurableParameter(abc.ABC, metaclass=ClassVarMeta): + """Base class representing a part of the eSIM profile that is configurable during the + personalization process (with dynamic data from elsewhere).""" + def __init__(self, value): + self.value = value + + @abc.abstractmethod + def apply(self, pe_seq: ProfileElementSequence): + pass + +class Iccid(ConfigurableParameter): + """Configurable ICCID. Expects the value to be in EF.ICCID format.""" + name = 'iccid' + def apply(self, pes: ProfileElementSequence): + # patch the header; FIXME: swap nibbles! + pes.get_pe_by_type('header').decoded['iccid'] = self.value + # patch MF/EF.ICCID + file_replace_content(pes.get_pe_by_type('mf').decoded['ef-iccid'], self.value) + +class Imsi(ConfigurableParameter): + """Configurable IMSI. Expects value to be n EF.IMSI format.""" + name = 'imsi' + def apply(self, pes: ProfileElementSequence): + # patch ADF.USIM/EF.IMSI + for pe in pes.get_pes_by_type('usim'): + file_replace_content(pe.decoded['ef-imsi'], self.value) + # TODO: DF.GSM_ACCESS if not linked? + +def obtain_singleton_pe_from_pelist(l: List[ProfileElement], wanted_type: str) -> ProfileElement: + filtered = list(filter(lambda x: x.type == wanted_type, l)) + assert len(filtered) == 1 + return filtered[0] + +def obtain_first_pe_from_pelist(l: List[ProfileElement], wanted_type: str) -> ProfileElement: + filtered = list(filter(lambda x: x.type == wanted_type, l)) + return filtered[0] + +class Puk(ConfigurableParameter, metaclass=ClassVarMeta): + keyReference = None + def apply(self, pes: ProfileElementSequence): + mf_pes = pes.pes_by_naa['mf'][0] + pukCodes = obtain_singleton_pe_from_pelist(mf_pes, 'pukCodes') + for pukCode in pukCodes.decoded['pukCodes']: + if pukCode['keyReference'] == self.keyReference: + pukCode['pukValue'] = self.value + return + raise ValueError('cannot find pukCode') +class Puk1(Puk, keyReference=0x01): + pass +class Puk2(Puk, keyReference=0x81): + pass + +class Pin(ConfigurableParameter, metaclass=ClassVarMeta): + keyReference = None + def apply(self, pes: ProfileElementSequence): + mf_pes = pes.pes_by_naa['mf'][0] + pinCodes = obtain_first_pe_from_pelist(mf_pes, 'pinCodes') + if pinCodes.decoded['pinCodes'][0] != 'pinconfig': + return + for pinCode in pinCodes.decoded['pinCodes'][1]: + if pinCode['keyReference'] == self.keyReference: + pinCode['pinValue'] = self.value + return + raise ValueError('cannot find pinCode') +class AppPin(ConfigurableParameter, metaclass=ClassVarMeta): + keyReference = None + def _apply_one(self, pe: ProfileElement): + pinCodes = obtain_first_pe_from_pelist(pe, 'pinCodes') + if pinCodes.decoded['pinCodes'][0] != 'pinconfig': + return + for pinCode in pinCodes.decoded['pinCodes'][1]: + if pinCode['keyReference'] == self.keyReference: + pinCode['pinValue'] = self.value + return + raise ValueError('cannot find pinCode') + + def apply(self, pes: ProfileElementSequence): + for naa in pes.pes_by_naa: + if naa not in ['usim','isim','csim','telecom']: + continue + for instance in pes.pes_by_naa[naa]: + self._apply_one(instance) +class Pin1(Pin, keyReference=0x01): + pass +# PIN2 is special: telecom + usim + isim + csim +class Pin2(AppPin, keyReference=0x81): + pass +class Adm1(Pin, keyReference=0x0A): + pass +class Adm2(Pin, keyReference=0x0B): + pass + + +class AlgoConfig(ConfigurableParameter, metaclass=ClassVarMeta): + key = None + def apply(self, pes: ProfileElementSequence): + for pe in pes.get_pes_for_type('akaParameter'): + algoConfiguration = pe.decoded['algoConfiguration'] + if algoConfiguration[0] != 'algoParameter': + continue + algoConfiguration[1][self.key] = self.value + +class K(AlgoConfig, key='key'): + pass +class Opc(AlgoConfig, key='opc'): + pass +class AlgorithmID(AlgoConfig, key='algorithmID'): + pass + diff --git a/pySim/esim/saip/validation.py b/pySim/esim/saip/validation.py new file mode 100644 index 0000000..2acc413 --- /dev/null +++ b/pySim/esim/saip/validation.py @@ -0,0 +1,96 @@ +# Implementation of SimAlliance/TCA Interoperable Profile handling +# +# (C) 2023-2024 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 Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +from pySim.esim.saip import * + +class ProfileError(Exception): + pass + +class ProfileConstraintChecker: + def check(self, pes: ProfileElementSequence): + for name in dir(self): + if name.startswith('check_'): + method = getattr(self, name) + method(pes) + +class CheckBasicStructure(ProfileConstraintChecker): + def _is_after_if_exists(self, pes: ProfileElementSequence, opt:str, after:str): + opt_pe = pes.get_pe_for_type(opt) + if opt_pe: + after_pe = pes.get_pe_for_type(after) + if not after_pe: + raise ProfileError('PE-%s without PE-%s' % (opt.upper(), after.upper())) + # FIXME: check order + + def check_start_and_end(self, pes: ProfileElementSequence): + if pes.pe_list[0].type != 'header': + raise ProfileError('first element is not header') + if pes.pe_list[1].type != 'mf': + # strictly speaking: permitted, but we don't support MF via GenericFileManagement + raise ProfileError('second element is not mf') + if pes.pe_list[-1].type != 'end': + raise ProfileError('last element is not end') + + def check_number_of_occurrence(self, pes: ProfileElementSequence): + # check for invalid number of occurrences + if len(pes.get_pes_for_type('header')) != 1: + raise ProfileError('multiple ProfileHeader') + if len(pes.get_pes_for_type('mf')) != 1: + # strictly speaking: 0 permitted, but we don't support MF via GenericFileManagement + raise ProfileError('multiple PE-MF') + for tn in ['end', 'cd', 'telecom', + 'usim', 'isim', 'csim', 'opt-usim','opt-isim','opt-csim', + 'df-saip', 'df-5gs']: + if len(pes.get_pes_for_type(tn)) > 1: + raise ProfileError('multiple PE-%s' % tn.upper()) + + def check_optional_ordering(self, pes: ProfileElementSequence): + # ordering and required depenencies + self._is_after_if_exists(pes,'opt-usim', 'usim') + self._is_after_if_exists(pes,'opt-isim', 'isim') + self._is_after_if_exists(pes,'gsm-access', 'usim') + self._is_after_if_exists(pes,'phonebook', 'usim') + self._is_after_if_exists(pes,'df-5gs', 'usim') + self._is_after_if_exists(pes,'df-saip', 'usim') + self._is_after_if_exists(pes,'opt-csim', 'csim') + + def check_mandatory_services(self, pes: ProfileElementSequence): + """Ensure that the PE for the mandatory services exist.""" + m_svcs = pes.get_pe_for_type('header').decoded['eUICC-Mandatory-services'] + if 'usim' in m_svcs and not pes.get_pe_for_type('usim'): + raise ProfileError('no PE-USIM for mandatory usim service') + if 'isim' in m_svcs and not pes.get_pe_for_type('isim'): + raise ProfileError('no PE-ISIM for mandatory isim service') + if 'csim' in m_svcs and not pes.get_pe_for_type('csim'): + raise ProfileError('no PE-ISIM for mandatory csim service') + if 'gba-usim' in m_svcs and not 'usim' in m_svcs: + raise ProfileError('gba-usim mandatory, but no usim') + if 'gba-isim' in m_svcs and not 'isim' in m_svcs: + raise ProfileError('gba-isim mandatory, but no isim') + if 'multiple-usim' in m_svcs and not 'usim' in m_svcs: + raise ProfileError('multiple-usim mandatory, but no usim') + if 'multiple-isim' in m_svcs and not 'isim' in m_svcs: + raise ProfileError('multiple-isim mandatory, but no isim') + if 'multiple-csim' in m_svcs and not 'csim' in m_svcs: + raise ProfileError('multiple-csim mandatory, but no csim') + if 'get-identity' in m_svcs and not ('usim' in m_svcs or 'isim' in m_svcs): + raise ProfileError('get-identity mandatory, but no usim or isim') + if 'profile-a-x25519' in m_svcs and not ('usim' in m_svcs or 'isim' in m_svcs): + raise ProfileError('profile-a-x25519 mandatory, but no usim or isim') + if 'profile-a-p256' in m_svcs and not not ('usim' in m_svcs or 'isim' in m_svcs): + raise ProfileError('profile-a-p256 mandatory, but no usim or isim') diff --git a/tests/test_esim_saip.py b/tests/test_esim_saip.py new file mode 100755 index 0000000..14c086b --- /dev/null +++ b/tests/test_esim_saip.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +# (C) 2023-2024 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 unittest +import logging +import copy + +from pySim.utils import h2b, b2h +from pySim.esim.saip import * +from pySim.esim.saip.personalization import * +from pprint import pprint as pp + + +class SaipTest(unittest.TestCase): + with open('smdpp-data/upp/TS48 V2 eSIM_GTP_SAIP2.3_NoBERTLV.rename2der', 'rb') as f: + per_input = f.read() + pes = ProfileElementSequence.from_der(per_input) + expected_pet_list = ['header', 'mf', 'pukCodes', 'pinCodes', 'telecom', 'pinCodes', 'genericFileManagement', 'usim', 'opt-usim', 'pinCodes', 'akaParameter', 'gsm-access', 'df-5gs', 'df-saip','csim', 'opt-csim', 'pinCodes', 'cdmaParameter', 'isim', 'opt-isim', 'pinCodes', 'akaParameter', 'genericFileManagement', 'genericFileManagement', 'securityDomain', 'rfm', 'rfm', 'rfm', 'rfm', 'end'] + + def test_reencode_sequence(self): + """Test that we can decode and re-encode the entire DER encoded UPP.""" + reencoded_der = self.pes.to_der() + self.assertEqual(reencoded_der, self.per_input) + + def test_reencode_pe(self): + """Test that we can decode and re-encode reach individual ProfileElement.""" + remainder = self.per_input + while len(remainder): + first_tlv, remainder = bertlv_first_segment(remainder) + pe = ProfileElement.from_der(first_tlv) + with self.subTest(pe.type): + reenc_tlv = pe.to_der() + self.assertEqual(reenc_tlv, first_tlv) + + + def test_sequence_helpers(self): + """Verify that the convenience helpers worked as expected.""" + self.assertEqual([x.type for x in self.pes.pe_list], self.expected_pet_list) + self.assertEqual(len(self.pes.pes_by_naa), 4) + + def test_personalization(self): + """Test some of the personalization operations.""" + pes = copy.deepcopy(self.pes) + params = [Puk1(value=b'01234567'), Puk2(value=b'98765432'), Pin1(b'1111'), Pin2(b'2222'), Adm1(b'11111111'), + K(h2b('000102030405060708090a0b0c0d0e0f')), Opc(h2b('101112131415161718191a1b1c1d1e1f'))] + for p in params: + p.apply(pes) + # TODO: we don't actually test the results here, but we just verify there is no exception + pes.to_der() + + +if __name__ == "__main__": + unittest.main() -- To view, visit https://gerrit.osmocom.org/c/pysim/+/35491?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: I71c252a214a634e1bd6f73472107efe2688ee6d2 Gerrit-Change-Number: 35491 Gerrit-PatchSet: 8 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-MessageType: merged
1 0
0 0
[XL] Change in pysim[master]: pySim.saip.*: Support for parsing / operating on eSIM profiles
by laforge 09 Jan '24

09 Jan '24
laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/35491?usp=email ) Change subject: pySim.saip.*: Support for parsing / operating on eSIM profiles ...................................................................... Patch Set 7: Code-Review+2 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/35491?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: I71c252a214a634e1bd6f73472107efe2688ee6d2 Gerrit-Change-Number: 35491 Gerrit-PatchSet: 7 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Comment-Date: Tue, 09 Jan 2024 21:37:09 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[XL] Change in pysim[master]: Initial proof-of-concept SM-DP+ for GSMA consumer eSIM RSP
by laforge 09 Jan '24

09 Jan '24
Attention is currently required from: dexter, fixeria, lynxis lazus. laforge has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/35461?usp=email ) Change subject: Initial proof-of-concept SM-DP+ for GSMA consumer eSIM RSP ...................................................................... Patch Set 11: Code-Review+2 (1 comment) Patchset: PS11: merging this now. It doesn't change anything in the exisitng pySim code, so we have very low risk of any regressions. -- 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: 11 Gerrit-Owner: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de> Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Attention: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Attention: dexter <pmaier(a)sysmocom.de> Gerrit-Comment-Date: Tue, 09 Jan 2024 21:37:05 +0000 Gerrit-HasComments: Yes Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
[M] Change in libosmocore[master]: Revert "logging: add log level cache"
by Hoernchen 09 Jan '24

09 Jan '24
Hoernchen has submitted this change. ( https://gerrit.osmocom.org/c/libosmocore/+/35524?usp=email ) Change subject: Revert "logging: add log level cache" ...................................................................... Revert "logging: add log level cache" This reverts commit 7dc6d4a629a37bb081d62f6ce61f4e5ee0237247. Reason for revert: other tests are failing Change-Id: Ife4c49d1bb933e983ac68c57970c9c49b40e08be --- M include/osmocom/core/logging.h M src/core/libosmocore.map M src/core/logging.c M src/vty/logging_vty.c M tests/ctrl/ctrl_test.c 5 files changed, 15 insertions(+), 123 deletions(-) Approvals: Hoernchen: Verified Jenkins Builder: Verified laforge: Looks good to me, approved diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h index e4859cd..e8433a1 100644 --- a/include/osmocom/core/logging.h +++ b/include/osmocom/core/logging.h @@ -409,7 +409,7 @@ /* filter on the targets */ void log_set_all_filter(struct log_target *target, int); -void log_cache_update(int mapped_subsys, uint8_t enabled, uint8_t level); + void log_set_use_color(struct log_target *target, int); void log_set_print_extended_timestamp(struct log_target *target, int); void log_set_print_timestamp(struct log_target *target, int); diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map index 06a3864..b66e37d 100644 --- a/src/core/libosmocore.map +++ b/src/core/libosmocore.map @@ -58,7 +58,6 @@ log_add_target; log_category_name; log_check_level; -log_cache_update; log_del_target; log_enable_multithread; log_fini; diff --git a/src/core/logging.c b/src/core/logging.c index 906d664..6941f9b 100644 --- a/src/core/logging.c +++ b/src/core/logging.c @@ -93,68 +93,6 @@ static __thread long int logging_tid; #if (!EMBEDDED) -/*! One global copy that contains the union of log levels for all targets -* for all categories, used for quick lock free checks of log targets. */ -static volatile uint8_t *log_level_lookup_cache; - -/*! Updates cache for all targets for all categies, caller must hold osmo_log_tgt_mutex. */ -static void log_cache_update_all(void) -{ - struct log_target *tgt; - uint8_t tmp_en[osmo_log_info->num_cat]; - uint8_t tmp_level[osmo_log_info->num_cat]; - memset(tmp_en, 0, osmo_log_info->num_cat); - memset(tmp_level, UINT8_MAX, osmo_log_info->num_cat); - - /* values can also decrease.. */ - llist_for_each_entry(tgt, &osmo_log_target_list, entry) { - for (int i = 0; i < osmo_log_info->num_cat; i++) { - struct log_category *cat = &tgt->categories[i]; - tmp_en[i] = OSMO_MAX(tmp_en[i], cat->enabled); - tmp_level[i] = OSMO_MIN(tmp_level[i], cat->loglevel); - tmp_level[i] = tgt->loglevel ? OSMO_MIN(tmp_level[i], tgt->loglevel) : tmp_level[i]; - } - } - - for (int i = 0; i < osmo_log_info->num_cat; i++) - log_level_lookup_cache[i] = tmp_en[i] ? tmp_level[i] : UINT8_MAX; -} - -/*! Updates single cache entry, caller must hold osmo_log_tgt_mutex. - * - * \param[in] mapped_subsys plain category index (after mapping) - * \param[in] enabled log category enabled? - * \param[in] level log level - */ -void log_cache_update(int mapped_subsys, uint8_t enabled, uint8_t level) -{ - struct log_target *tgt; - struct log_category tmp = { UINT8_MAX, 0 }; - - /* values can also decrease.. */ - llist_for_each_entry(tgt, &osmo_log_target_list, entry) { - struct log_category *cat = &tgt->categories[mapped_subsys]; - tmp.enabled = OSMO_MAX(tmp.enabled, cat->enabled); - tmp.loglevel = OSMO_MIN(tmp.loglevel, cat->loglevel); - tmp.loglevel = tgt->loglevel ? OSMO_MIN(tmp.loglevel, tgt->loglevel) : tmp.loglevel; - } - tmp.enabled = OSMO_MAX(tmp.enabled, enabled); - tmp.loglevel = OSMO_MIN(tmp.loglevel, level); - - log_level_lookup_cache[mapped_subsys] = tmp.enabled ? tmp.loglevel : UINT8_MAX; -} - -/*! Queries log level cache. - * - * \param[in] mapped_subsys plain category index (after mapping) - * \param[in] level log level - * \returns true if logging should happen for at least one log target -*/ -static bool log_cache_check(int mapped_subsys, int level) -{ - return (level < log_level_lookup_cache[mapped_subsys]) ? false : true; -} - /*! This mutex must be held while using osmo_log_target_list or any of its log_targets in a multithread program. Prevents race conditions between threads like producing unordered timestamps or VTY deleting a target while another @@ -488,10 +426,6 @@ } } while ((category_token = strtok(NULL, ":"))); -#if !defined(EMBEDDED) - log_cache_update_all(); -#endif - free(mask); } @@ -746,11 +680,6 @@ subsys = map_subsys(subsys); -#if !defined(EMBEDDED) - if (!log_cache_check(subsys, level)) - return; -#endif - log_tgt_mutex_lock(); llist_for_each_entry(tar, &osmo_log_target_list, entry) { @@ -825,9 +754,6 @@ void log_add_target(struct log_target *target) { llist_add_tail(&target->entry, &osmo_log_target_list); -#if (!EMBEDDED) - log_cache_update_all(); -#endif } /*! Unregister a log target from the logging core @@ -836,9 +762,6 @@ void log_del_target(struct log_target *target) { llist_del(&target->entry); -#if (!EMBEDDED) - log_cache_update_all(); -#endif } /*! Reset (clear) the logging context */ @@ -999,9 +922,6 @@ void log_set_log_level(struct log_target *target, int log_level) { target->loglevel = log_level; -#if !defined(EMBEDDED) - log_cache_update_all(); -#endif } /*! Set a category filter on a given log target @@ -1018,10 +938,6 @@ category = map_subsys(category); target->categories[category].enabled = !!enable; target->categories[category].loglevel = level; - -#if !defined(EMBEDDED) - log_cache_update(category, !!enable, level); -#endif } #if (!EMBEDDED) @@ -1130,15 +1046,6 @@ /* global log level */ target->loglevel = 0; - -#if !defined(EMBEDDED) - /* update cache */ - for (i = 0; i < osmo_log_info->num_cat; i++) { - const struct log_info_cat *c = &osmo_log_info->cat[i]; - log_cache_update(i, c->enabled, c->loglevel); - } -#endif - return target; } @@ -1517,15 +1424,6 @@ osmo_log_info->num_cat += inf->num_cat; } -#if !defined(EMBEDDED) - log_level_lookup_cache = talloc_zero_array(osmo_log_info, uint8_t, osmo_log_info->num_cat); - if (!log_level_lookup_cache) { - talloc_free(osmo_log_info); - osmo_log_info = NULL; - return -ENOMEM; - } -#endif - cat_ptr = talloc_zero_array(osmo_log_info, struct log_info_cat, osmo_log_info->num_cat); if (!cat_ptr) { @@ -1556,12 +1454,6 @@ osmo_log_info->cat = cat_ptr; -#if !defined(EMBEDDED) - /* copy everything for level lookup cache */ - for (i = 0; i < osmo_log_info->num_cat; i++) - log_level_lookup_cache[i] = cat_ptr[i].loglevel; -#endif - return 0; } @@ -1594,11 +1486,6 @@ subsys = map_subsys(subsys); -#if !defined(EMBEDDED) - if (!log_cache_check(subsys, level)) - return 0; -#endif - /* TODO: The following could/should be cached (update on config) */ log_tgt_mutex_lock(); diff --git a/src/vty/logging_vty.c b/src/vty/logging_vty.c index 678ae68..2a07422 100644 --- a/src/vty/logging_vty.c +++ b/src/vty/logging_vty.c @@ -382,10 +382,6 @@ tgt->categories[category].enabled = 1; tgt->categories[category].loglevel = level; -#if !defined(EMBEDDED) - log_cache_update(category, 1, level); -#endif - RET_WITH_UNLOCK(CMD_SUCCESS); } @@ -410,9 +406,6 @@ cat->enabled = 1; cat->loglevel = level; -#if !defined(EMBEDDED) - log_cache_update(i, 1, level); -#endif } RET_WITH_UNLOCK(CMD_SUCCESS); } diff --git a/tests/ctrl/ctrl_test.c b/tests/ctrl/ctrl_test.c index 7b7e6ce..1d4d4d7 100644 --- a/tests/ctrl/ctrl_test.c +++ b/tests/ctrl/ctrl_test.c @@ -482,7 +482,7 @@ test_deferred_cmd(); /* Expecting root ctx + msgb root ctx + 5 logging elements */ - if (talloc_total_blocks(ctx) != 8) { + if (talloc_total_blocks(ctx) != 7) { talloc_report_full(ctx, stdout); OSMO_ASSERT(false); } -- To view, visit https://gerrit.osmocom.org/c/libosmocore/+/35524?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Change-Id: Ife4c49d1bb933e983ac68c57970c9c49b40e08be Gerrit-Change-Number: 35524 Gerrit-PatchSet: 1 Gerrit-Owner: Hoernchen <ewild(a)sysmocom.de> Gerrit-Reviewer: Hoernchen <ewild(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-CC: arehbein <arehbein(a)sysmocom.de> Gerrit-CC: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 0
0 0
[M] Change in libosmocore[master]: Revert "logging: add log level cache"
by Hoernchen 09 Jan '24

09 Jan '24
Attention is currently required from: fixeria. Hoernchen has posted comments on this change. ( https://gerrit.osmocom.org/c/libosmocore/+/35524?usp=email ) Change subject: Revert "logging: add log level cache" ...................................................................... Patch Set 1: Verified+1 -- To view, visit https://gerrit.osmocom.org/c/libosmocore/+/35524?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Change-Id: Ife4c49d1bb933e983ac68c57970c9c49b40e08be Gerrit-Change-Number: 35524 Gerrit-PatchSet: 1 Gerrit-Owner: Hoernchen <ewild(a)sysmocom.de> Gerrit-Reviewer: Hoernchen <ewild(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-CC: arehbein <arehbein(a)sysmocom.de> Gerrit-CC: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Tue, 09 Jan 2024 16:39:11 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • ...
  • 156
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.