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
This commit is contained in:
Harald Welte
2024-05-30 19:23:15 +02:00
parent 3dabbafdba
commit 56912caac7
2 changed files with 41 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ from cryptography.hazmat.primitives.asymmetric import ec
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 RspSessionState:
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