laforge submitted this change.

View Change


Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved
osmo-smdpp: Don't re-encode euiccSigned1/euiccSigned2

We used to re-encode those parts of a decoded ASN.1 struct that is
cryptographically signed in the GSMA SGP.22 specification. However, if
the received data follows a later spec and contains new/unknown records,
then our poor-man's attempt at re-encoding will render a different
binary, which in turn means the signature check will fail.

Let's instead do a manual step-by-step raw decode of the DER TLV
structure to extract the actual binary information of parts of ASN.1
objects.

Change-Id: I4e31fd4b23ec3be15b9d07c2c30a3e31e22bdda1
Closes: OS#6473
---
M osmo-smdpp.py
M pySim/esim/rsp.py
2 files changed, 61 insertions(+), 4 deletions(-)

diff --git a/osmo-smdpp.py b/osmo-smdpp.py
index 3dc6131..9ed1e39 100755
--- a/osmo-smdpp.py
+++ b/osmo-smdpp.py
@@ -292,8 +292,7 @@

r_ok = authenticateServerResp[1]
euiccSigned1 = r_ok['euiccSigned1']
- # TODO: use original data, don't re-encode?
- euiccSigned1_bin = rsp.asn1.encode('EuiccSigned1', euiccSigned1)
+ euiccSigned1_bin = rsp.extract_euiccSigned1(authenticateServerResp_bin)
euiccSignature1_bin = r_ok['euiccSignature1']
euiccCertificate_dec = r_ok['euiccCertificate']
# TODO: use original data, don't re-encode?
@@ -422,8 +421,7 @@

# 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)
+ euiccSigned2_bin = rsp.extract_euiccSigned2(prepDownloadResp_bin)
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')

diff --git a/pySim/esim/rsp.py b/pySim/esim/rsp.py
index ec317fc..a032031 100644
--- a/pySim/esim/rsp.py
+++ b/pySim/esim/rsp.py
@@ -24,6 +24,7 @@
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography import x509

+from pySim.utils import bertlv_parse_one, bertlv_encode_tag, bertlv_encode_len, b2h
from pySim.esim import compile_asn1_subdir

asn1 = compile_asn1_subdir('rsp')
@@ -96,3 +97,41 @@
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."""
+
+def extract_euiccSigned1(authenticateServerResponse: bytes) -> bytes:
+ """Extract the raw, DER-encoded binary euiccSigned1 field from the given AuthenticateServerResponse. This
+ is needed due to the very peculiar SGP.22 notion of signing sections of DER-encoded ASN.1 objects."""
+ tdict, l, v, remainder = bertlv_parse_one(authenticateServerResponse)
+ rawtag = bertlv_encode_tag(tdict)
+ if len(remainder):
+ raise ValueError('Excess data at end of TLV')
+ if b2h(rawtag) != 'bf38':
+ raise ValueError('Unexpected outer tag: %s' % b2h(rawtag))
+ tdict, l, v1, remainder = bertlv_parse_one(v)
+ rawtag = bertlv_encode_tag(tdict)
+ if b2h(rawtag) != 'a0':
+ raise ValueError('Unexpected tag where CHOICE was expected')
+ tdict, l, v2, remainder = bertlv_parse_one(v1)
+ rawtag = bertlv_encode_tag(tdict)
+ if b2h(rawtag) != '30':
+ raise ValueError('Unexpected tag where SEQUENCE was expected')
+ return rawtag + bertlv_encode_len(l) + v2
+
+def extract_euiccSigned2(prepareDownloadResponse: bytes) -> bytes:
+ """Extract the raw, DER-encoded binary euiccSigned2 field from the given prepareDownloadrResponse. This is
+ needed due to the very peculiar SGP.22 notion of signing sections of DER-encoded ASN.1 objects."""
+ tdict, l, v, remainder = bertlv_parse_one(prepareDownloadResponse)
+ rawtag = bertlv_encode_tag(tdict)
+ if len(remainder):
+ raise ValueError('Excess data at end of TLV')
+ if b2h(rawtag) != 'bf21':
+ raise ValueError('Unexpected outer tag: %s' % b2h(rawtag))
+ tdict, l, v1, remainder = bertlv_parse_one(v)
+ rawtag = bertlv_encode_tag(tdict)
+ if b2h(rawtag) != 'a0':
+ raise ValueError('Unexpected tag where CHOICE was expected')
+ tdict, l, v2, remainder = bertlv_parse_one(v1)
+ rawtag = bertlv_encode_tag(tdict)
+ if b2h(rawtag) != '30':
+ raise ValueError('Unexpected tag where SEQUENCE was expected')
+ return rawtag + bertlv_encode_len(l) + v2

To view, visit change 36954. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I4e31fd4b23ec3be15b9d07c2c30a3e31e22bdda1
Gerrit-Change-Number: 36954
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge@osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier@sysmocom.de>
Gerrit-Reviewer: laforge <laforge@osmocom.org>
Gerrit-MessageType: merged