Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 139 additions & 2 deletions euicc/es8p.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,137 @@
#include <string.h>
#include <unistd.h>

static void es8p_metadata_access_rules_free(struct es8p_metadata_access_rule **access_rules) {
struct es8p_metadata_access_rule *rule = *access_rules;

while (rule) {
struct es8p_metadata_access_rule *next = rule->next;
free(rule->certificateHash);
free(rule->packageName);
free(rule);
rule = next;
}

*access_rules = NULL;
}

static int es8p_metadata_parse_access_rules(struct es8p_metadata_access_rule **access_rules, const uint8_t *buffer,
uint32_t buffer_len) {
struct euicc_derutil_node n_ref_ar_do_entry = {0};
struct es8p_metadata_access_rule *last = NULL;
struct es8p_metadata_access_rule *rule = NULL;

*access_rules = NULL;

n_ref_ar_do_entry.self.ptr = buffer;
n_ref_ar_do_entry.self.length = 0;

// Each 0xBF76 tag may contain multiple REF-AR-DO (0xE2) entries
while (euicc_derutil_unpack_next(&n_ref_ar_do_entry, &n_ref_ar_do_entry, buffer, buffer_len) == 0) {
struct euicc_derutil_node n_ref_ar_do_child = {0};
struct euicc_derutil_node n_ref_do_child = {0};
struct euicc_derutil_node n_ref_do = {0};
int found_ref_do = 0;

if (n_ref_ar_do_entry.tag != 0xE2) {
continue;
}

rule = calloc(1, sizeof(*rule));
if (!rule) {
goto err;
}

n_ref_ar_do_child.self.ptr = n_ref_ar_do_entry.value;
n_ref_ar_do_child.self.length = 0;

// Each REF-AR-DO must contain EXACTLY 1 REF-DO (0xE1)
while (euicc_derutil_unpack_next(&n_ref_ar_do_child, &n_ref_ar_do_child, n_ref_ar_do_entry.value,
n_ref_ar_do_entry.length)
== 0) {
if (n_ref_ar_do_child.tag == 0xE1) {
if (found_ref_do) {
// We can't have multiple REF-DO's per REF-AR-DO
goto err;
} else {
n_ref_do = n_ref_ar_do_child;
found_ref_do = 1;
}
}
}

// If we don't find REF-DO, abort
if (!found_ref_do) {
goto err;
}

n_ref_do_child.self.ptr = n_ref_do.value;
n_ref_do_child.self.length = 0;

// Now we have REF-DO, each MUST contain a 0xC1 (cert hash)
// Optionally, a 0xCA (package name)
while (euicc_derutil_unpack_next(&n_ref_do_child, &n_ref_do_child, n_ref_do.value, n_ref_do.length) == 0) {
switch (n_ref_do_child.tag) {
case 0xC1:
// There can only be one 0xC1 (cert hash) per REF-DO
if (rule->certificateHash) {
goto err;
}

rule->certificateHash = malloc((n_ref_do_child.length * 2) + 1);
if (!rule->certificateHash) {
goto err;
}

if (euicc_hexutil_bin2hex(rule->certificateHash, (n_ref_do_child.length * 2) + 1, n_ref_do_child.value,
n_ref_do_child.length)
< 0) {
goto err;
}
break;
case 0xCA:
// There can only be one 0xCA (package name)
if (rule->packageName) {
goto err;
}

rule->packageName = malloc(n_ref_do_child.length + 1);
if (!rule->packageName) {
goto err;
}

memcpy(rule->packageName, n_ref_do_child.value, n_ref_do_child.length);
rule->packageName[n_ref_do_child.length] = '\0';
break;
}
}

// Each REF-DO child must at least contain a cert hash
if (!rule->certificateHash) {
goto err;
}

if (!*access_rules) {
*access_rules = rule;
} else {
last->next = rule;
}
last = rule;
rule = NULL;
}

return 0;

err:
if (rule) {
free(rule->certificateHash);
free(rule->packageName);
free(rule);
}
es8p_metadata_access_rules_free(access_rules);
return -1;
}

int es8p_metadata_parse(struct es8p_metadata **stru_metadata, const char *b64_Metadata) {
int ret;
uint8_t *metadata = NULL;
Expand Down Expand Up @@ -97,6 +228,12 @@ int es8p_metadata_parse(struct es8p_metadata **stru_metadata, const char *b64_Me
break;
}
break;
case 0xBF76:
// Android's extension, AR-DO in profile metadata
if (es8p_metadata_parse_access_rules(&p->accessRules, n_iter.value, n_iter.length) < 0) {
goto err;
}
break;
case 0xB6:
case 0xB7:
case 0x99:
Expand All @@ -113,8 +250,7 @@ int es8p_metadata_parse(struct es8p_metadata **stru_metadata, const char *b64_Me
ret = -1;
free(*stru_metadata);
*stru_metadata = NULL;
free(p);
p = NULL;
es8p_metadata_free(&p);
exit:
free(metadata);
metadata = NULL;
Expand All @@ -132,6 +268,7 @@ void es8p_metadata_free(struct es8p_metadata **stru_metadata) {
free(p->serviceProviderName);
free(p->profileName);
free(p->icon);
es8p_metadata_access_rules_free(&p->accessRules);
free(p);

*stru_metadata = NULL;
Expand Down
7 changes: 7 additions & 0 deletions euicc/es8p.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ struct es8p_metadata {
char *dpOid;
} dpProprietaryData;
char **profilePolicyRules;
struct es8p_metadata_access_rule *accessRules;
};

struct es8p_metadata_access_rule {
char *certificateHash;
char *packageName;
struct es8p_metadata_access_rule *next;
};

int es8p_metadata_parse(struct es8p_metadata **metadata, const char *b64_Metadata);
Expand Down
33 changes: 33 additions & 0 deletions src/applet/profile/download.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,31 @@ static cJSON *build_download_result_json(const struct es10b_load_bound_profile_p
return jdata;
}

static cJSON *build_access_rules_json(const struct es8p_metadata_access_rule *rules) {
cJSON *jrules = cJSON_CreateArray();
const struct es8p_metadata_access_rule *rule = rules;

if (!jrules) {
return NULL;
}

while (rule) {
cJSON *jrule = cJSON_CreateObject();
if (!jrule) {
cJSON_Delete(jrules);
return NULL;
}

cJSON_AddStringOrNullToObject(jrule, "certificateHash", rule->certificateHash);
cJSON_AddStringOrNullToObject(jrule, "packageName", rule->packageName);
cJSON_AddItemToArray(jrules, jrule);

rule = rule->next;
}

return jrules;
}

static int applet_main(int argc, char **argv) {
int fret;
const char *error_function_name = NULL;
Expand All @@ -83,6 +108,7 @@ static int applet_main(int argc, char **argv) {
struct es10b_load_bound_profile_package_result download_result = {0};

cJSON *jmetadata = NULL;
cJSON *jaccessRules = NULL;
_cleanup_(es8p_metadata_free) struct es8p_metadata *profile_metadata = NULL;

while ((opt = getopt(argc, argv, opt_string)) != -1) {
Expand Down Expand Up @@ -239,6 +265,13 @@ static int applet_main(int argc, char **argv) {
cJSON_AddStringOrNullToObject(jmetadata, "icon", profile_metadata->icon);
cJSON_AddStringOrNullToObject(jmetadata, "profileClass",
euicc_profileclass2str(profile_metadata->profileClass));
if (profile_metadata->accessRules) {
jaccessRules = build_access_rules_json(profile_metadata->accessRules);
if (jaccessRules) {
cJSON_AddItemToObject(jmetadata, "accessRules", jaccessRules);
jaccessRules = NULL;
}
}

jprint_progress_obj("es8p_metadata_parse", jmetadata);

Expand Down
Loading