forked from public/pysim
Compare commits
10 Commits
pmaier/ota
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0634f77308 | ||
|
|
a5a5865c7c | ||
|
|
3752aeb94e | ||
|
|
914abe3309 | ||
|
|
84754b6ebb | ||
|
|
c47005d408 | ||
|
|
2dfaac6e4f | ||
|
|
a615ba5138 | ||
|
|
8ee10ab1a5 | ||
|
|
f10af30aed |
@@ -128,7 +128,7 @@ class EF_AD(TransparentEF):
|
||||
cell_test = 0x04
|
||||
|
||||
def __init__(self, fid='6f43', sfid=None, name='EF.AD',
|
||||
desc='Service Provider Name', size=(3, None), **kwargs):
|
||||
desc='Administrative Data', size=(3, None), **kwargs):
|
||||
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
|
||||
self._construct = Struct(
|
||||
# Byte 1: Display Condition
|
||||
|
||||
@@ -19,7 +19,7 @@ import abc
|
||||
import requests
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple
|
||||
import base64
|
||||
from twisted.web.server import Request
|
||||
|
||||
@@ -180,7 +180,7 @@ class JsonHttpApiFunction(abc.ABC):
|
||||
# receives from the a requesting client. The same applies vice versa to class variables that have an "output_"
|
||||
# prefix.
|
||||
|
||||
# path of the API function (e.g. '/gsma/rsp2/es2plus/confirmOrder')
|
||||
# path of the API function (e.g. '/gsma/rsp2/es2plus/confirmOrder', see also method rewrite_url).
|
||||
path = None
|
||||
|
||||
# dictionary of input parameters. key is parameter name, value is ApiParam class
|
||||
@@ -336,6 +336,22 @@ class JsonHttpApiFunction(abc.ABC):
|
||||
output[p] = p_class.decode(v)
|
||||
return output
|
||||
|
||||
def rewrite_url(self, data: dict, url: str) -> Tuple[dict, str]:
|
||||
"""
|
||||
Rewrite a static URL using information passed in the data dict. This method may be overloaded by a derived
|
||||
class to allow fully dynamic URLs. The input parameters required for the URL rewriting may be passed using
|
||||
data parameter. In case those parameters are additional parameters that are not intended to be passed to
|
||||
the encode_client method later, they must be removed explcitly.
|
||||
|
||||
Args:
|
||||
data: (see JsonHttpApiClient and JsonHttpApiServer)
|
||||
url: statically generated URL string (see comment in JsonHttpApiClient)
|
||||
"""
|
||||
|
||||
# This implementation is a placeholder in which we do not perform any URL rewriting. We just pass through data
|
||||
# and url unmodified.
|
||||
return data, url
|
||||
|
||||
class JsonHttpApiClient():
|
||||
def __init__(self, api_func: JsonHttpApiFunction, url_prefix: str, func_req_id: Optional[str],
|
||||
session: requests.Session):
|
||||
@@ -352,8 +368,16 @@ class JsonHttpApiClient():
|
||||
self.session = session
|
||||
|
||||
def call(self, data: dict, func_call_id: Optional[str] = None, timeout=10) -> Optional[dict]:
|
||||
"""Make an API call to the HTTP API endpoint represented by this object. Input data is passed in `data` as
|
||||
json-serializable dict. Output data is returned as json-deserialized dict."""
|
||||
"""
|
||||
Make an API call to the HTTP API endpoint represented by this object. Input data is passed in `data` as
|
||||
json-serializable fields. `data` may also contain additional parameters required for URL rewriting (see
|
||||
rewrite_url in class JsonHttpApiFunction). Output data is returned as json-deserialized dict.
|
||||
|
||||
Args:
|
||||
data: Input data required to perform the request.
|
||||
func_call_id: Function Call Identifier, if present a header field is generated automatically.
|
||||
timeout: Maximum amount of time to wait for the request to complete.
|
||||
"""
|
||||
|
||||
# In case a function caller ID is supplied, use it together with the stored function requestor ID to generate
|
||||
# and prepend the header field according to SGP.22, section 6.5.1.1 and 6.5.1.3. (the presence of the header
|
||||
@@ -362,6 +386,11 @@ class JsonHttpApiClient():
|
||||
data = {'header' : {'functionRequesterIdentifier': self.func_req_id,
|
||||
'functionCallIdentifier': func_call_id}} | data
|
||||
|
||||
# The URL used for the HTTP request (see below) normally consists of the initially given url_prefix
|
||||
# concatenated with the path defined by the JsonHttpApiFunction definition. This static URL path may be
|
||||
# rewritten by rewrite_url method defined in the JsonHttpApiFunction.
|
||||
data, url = self.api_func.rewrite_url(data, self.url_prefix + self.api_func.path)
|
||||
|
||||
# Encode the message (the presence of mandatory fields is checked during encoding)
|
||||
encoded = json.dumps(self.api_func.encode_client(data))
|
||||
|
||||
@@ -373,7 +402,6 @@ class JsonHttpApiClient():
|
||||
req_headers.update(self.api_func.extra_http_req_headers)
|
||||
|
||||
# Perform HTTP request
|
||||
url = self.url_prefix + self.api_func.path
|
||||
logger.debug("HTTP REQ %s - hdr: %s '%s'" % (url, req_headers, encoded))
|
||||
response = self.session.request(self.api_func.http_method, url, data=encoded, headers=req_headers, timeout=timeout)
|
||||
logger.debug("HTTP RSP-STS: [%u] hdr: %s" % (response.status_code, response.headers))
|
||||
|
||||
@@ -151,6 +151,8 @@ class File:
|
||||
self.df_name = None
|
||||
self.fill_pattern = None
|
||||
self.fill_pattern_repeat = False
|
||||
self.pstdo = None # pinStatusTemplateDO, mandatory for DF/ADF
|
||||
self.lcsi = None # optional life cycle status indicator
|
||||
# apply some defaults from profile
|
||||
if self.template:
|
||||
self.from_template(self.template)
|
||||
@@ -278,6 +280,8 @@ class File:
|
||||
elif self.file_type in ['MF', 'DF', 'ADF']:
|
||||
fdb_dec['file_type'] = 'df'
|
||||
fdb_dec['structure'] = 'no_info_given'
|
||||
# pinStatusTemplateDO is mandatory for DF/ADF
|
||||
fileDescriptor['pinStatusTemplateDO'] = self.pstdo
|
||||
# build file descriptor based on above input data
|
||||
fd_dict = {}
|
||||
if len(fdb_dec):
|
||||
@@ -304,6 +308,8 @@ class File:
|
||||
# desired fill or repeat pattern in the "proprietaryEFInfo" element for the EF in Profiles
|
||||
# downloaded to a V2.2 or earlier eUICC.
|
||||
fileDescriptor['proprietaryEFInfo'] = pefi
|
||||
if self.lcsi:
|
||||
fileDescriptor['lcsi'] = self.lcsi
|
||||
logger.debug("%s: to_fileDescriptor(%s)" % (self, fileDescriptor))
|
||||
return fileDescriptor
|
||||
|
||||
@@ -323,6 +329,8 @@ class File:
|
||||
if efFileSize:
|
||||
self._file_size = self._decode_file_size(efFileSize)
|
||||
|
||||
self.pstdo = fileDescriptor.get('pinStatusTemplateDO', None)
|
||||
self.lcsi = fileDescriptor.get('lcsi', None)
|
||||
pefi = fileDescriptor.get('proprietaryEFInfo', {})
|
||||
securityAttributesReferenced = fileDescriptor.get('securityAttributesReferenced', None)
|
||||
if securityAttributesReferenced:
|
||||
|
||||
@@ -266,11 +266,13 @@ class SCP02(SCP):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def dek_encrypt(self, plaintext:bytes) -> bytes:
|
||||
cipher = DES.new(self.card_keys.dek[:8], DES.MODE_ECB)
|
||||
# See also GPC section B.1.1.2, E.4.7, and E.4.1
|
||||
cipher = DES3.new(self.sk.data_enc, DES.MODE_ECB)
|
||||
return cipher.encrypt(plaintext)
|
||||
|
||||
def dek_decrypt(self, ciphertext:bytes) -> bytes:
|
||||
cipher = DES.new(self.card_keys.dek[:8], DES.MODE_ECB)
|
||||
# See also GPC section B.1.1.2, E.4.7, and E.4.1
|
||||
cipher = DES3.new(self.sk.data_enc, DES.MODE_ECB)
|
||||
return cipher.decrypt(ciphertext)
|
||||
|
||||
def _compute_cryptograms(self, card_challenge: bytes, host_challenge: bytes):
|
||||
|
||||
Reference in New Issue
Block a user