Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
dist
.vscode
.aider*
lib/oid/test
*.swp
application.fam
bsearch_test
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ Build the ASN.1 code (optional, required for development):
asn1c -D ./lib/asn1 -no-gen-example -pdu=all eMRTD.asn1
```

qsort is not available in the Flipper Zero firmware, but is used by parts of the ASN.1 SET_OF code. This needs to be disabled again after running `asn1c`:

```bash
./hack_asn1_no_qsort.py lib/asn1/constr_SET_OF.c
```

---

## Roadmap / To Do
Expand Down
2 changes: 1 addition & 1 deletion bsearch.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
static char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/stdlib/bsearch.c,v 1.4 2007/01/09 00:28:09 imp Exp $");
//__FBSDID("$FreeBSD: src/lib/libc/stdlib/bsearch.c,v 1.4 2007/01/09 00:28:09 imp Exp $");

#include <stddef.h>
#include <stdlib.h>
Expand Down
42 changes: 42 additions & 0 deletions eMRTD.asn1
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,46 @@ COM ::= [APPLICATION 0] IMPLICIT SEQUENCE {
dataGroups [APPLICATION 28] IMPLICIT DataGroups
}

SecurityInfos ::= SET OF SecurityInfo

SecurityInfo ::= SEQUENCE {
protocol OBJECT IDENTIFIER,
requiredData ANY DEFINED BY protocol,
optionalData ANY DEFINED BY protocol OPTIONAL
}

bsi-de OBJECT IDENTIFIER ::= {
itu-t(0) identified-organization(4) etsi(0)
reserved(127) etsi-identified-organization(0) 7
}

id-PACE OBJECT IDENTIFIER ::= {
bsi-de protocols(2) smartcard(2) 4
}

id-PACE-DH-GM OBJECT IDENTIFIER ::= {id-PACE 1}
id-PACE-DH-GM-3DES-CBC-CBC OBJECT IDENTIFIER ::= {id-PACE-DH-GM 1}
id-PACE-DH-GM-AES-CBC-CMAC-128 OBJECT IDENTIFIER ::= {id-PACE-DH-GM 2}
id-PACE-DH-GM-AES-CBC-CMAC-192 OBJECT IDENTIFIER ::= {id-PACE-DH-GM 3}
id-PACE-DH-GM-AES-CBC-CMAC-256 OBJECT IDENTIFIER ::= {id-PACE-DH-GM 4}
id-PACE-ECDH-GM OBJECT IDENTIFIER ::= {id-PACE 2}
id-PACE-ECDH-GM-3DES-CBC-CBC OBJECT IDENTIFIER ::= {id-PACE-ECDH-GM 1}
id-PACE-ECDH-GM-AES-CBC-CMAC-128 OBJECT IDENTIFIER ::= {id-PACE-ECDH-GM 2}
id-PACE-ECDH-GM-AES-CBC-CMAC-192 OBJECT IDENTIFIER ::= {id-PACE-ECDH-GM 3}
id-PACE-ECDH-GM-AES-CBC-CMAC-256 OBJECT IDENTIFIER ::= {id-PACE-ECDH-GM 4}
id-PACE-DH-IM OBJECT IDENTIFIER ::= {id-PACE 3}
id-PACE-DH-IM-3DES-CBC-CBC OBJECT IDENTIFIER ::= {id-PACE-DH-IM 1}
id-PACE-DH-IM-AES-CBC-CMAC-128 OBJECT IDENTIFIER ::= {id-PACE-DH-IM 2}
id-PACE-DH-IM-AES-CBC-CMAC-192 OBJECT IDENTIFIER ::= {id-PACE-DH-IM 3}
id-PACE-DH-IM-AES-CBC-CMAC-256 OBJECT IDENTIFIER ::= {id-PACE-DH-IM 4}
id-PACE-ECDH-IM OBJECT IDENTIFIER ::= {id-PACE 4}
id-PACE-ECDH-IM-3DES-CBC-CBC OBJECT IDENTIFIER ::= {id-PACE-ECDH-IM 1}
id-PACE-ECDH-IM-AES-CBC-CMAC-128 OBJECT IDENTIFIER ::= {id-PACE-ECDH-IM 2}
id-PACE-ECDH-IM-AES-CBC-CMAC-192 OBJECT IDENTIFIER ::= {id-PACE-ECDH-IM 3}
id-PACE-ECDH-IM-AES-CBC-CMAC-256 OBJECT IDENTIFIER ::= {id-PACE-ECDH-IM 4}
id-PACE-ECDH-CAM OBJECT IDENTIFIER ::= {id-PACE 6}
id-PACE-ECDH-CAM-AES-CBC-CMAC-128 OBJECT IDENTIFIER ::= {id-PACE-ECDH-CAM 2}
id-PACE-ECDH-CAM-AES-CBC-CMAC-192 OBJECT IDENTIFIER ::= {id-PACE-ECDH-CAM 3}
id-PACE-ECDH-CAM-AES-CBC-CMAC-256 OBJECT IDENTIFIER ::= {id-PACE-ECDH-CAM 4}

END
159 changes: 159 additions & 0 deletions gen_oid_nid_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python3

#TODO: read and parse these OIDs from eMRTD.asn1

oids = {
'itu_t': [0],
'iso': [1],
'joint_iso_itu_t': [2],
'member_body': ['iso', 2],
'identified_organization': ['iso', 3],
'etsi': ['itu_t', 4, 0],
'etsi_identified_organization': ['etsi', 127, 0],
'bsi_de': [0, 4, 0, 127, 0, 7],
'id_PACE': ['bsi_de', 2, 2, 4],
'id_PACE_DH_GM': ['id_PACE', 1],
'id_PACE_DH_GM_3DES_CBC_CBC': ['id_PACE_DH_GM', 1],
'id_PACE_DH_GM_AES_CBC_CMAC_128': ['id_PACE_DH_GM', 2],
'id_PACE_DH_GM_AES_CBC_CMAC_192': ['id_PACE_DH_GM', 3],
'id_PACE_DH_GM_AES_CBC_CMAC_256': ['id_PACE_DH_GM', 4],
'id_PACE_ECDH_GM': ['id_PACE', 2],
'id_PACE_ECDH_GM_3DES_CBC_CBC': ['id_PACE_ECDH_GM', 1],
'id_PACE_ECDH_GM_AES_CBC_CMAC_128': ['id_PACE_ECDH_GM', 2],
'id_PACE_ECDH_GM_AES_CBC_CMAC_192': ['id_PACE_ECDH_GM', 3],
'id_PACE_ECDH_GM_AES_CBC_CMAC_256': ['id_PACE_ECDH_GM', 4],
'id_PACE_DH_IM': ['id_PACE', 3],
'id_PACE_DH_IM_3DES_CBC_CBC': ['id_PACE_DH_IM', 1],
'id_PACE_DH_IM_AES_CBC_CMAC_128': ['id_PACE_DH_IM', 2],
'id_PACE_DH_IM_AES_CBC_CMAC_192': ['id_PACE_DH_IM', 3],
'id_PACE_DH_IM_AES_CBC_CMAC_256': ['id_PACE_DH_IM', 4],
'id_PACE_ECDH_IM': ['id_PACE', 4],
'id_PACE_ECDH_IM_3DES_CBC_CBC': ['id_PACE_ECDH_IM', 1],
'id_PACE_ECDH_IM_AES_CBC_CMAC_128': ['id_PACE_ECDH_IM', 2],
'id_PACE_ECDH_IM_AES_CBC_CMAC_192': ['id_PACE_ECDH_IM', 3],
'id_PACE_ECDH_IM_AES_CBC_CMAC_256': ['id_PACE_ECDH_IM', 4],
'id_PACE_ECDH_CAM': ['id_PACE', 6],
'id_PACE_ECDH_CAM_AES_CBC_CMAC_128': ['id_PACE_ECDH_CAM', 2],
'id_PACE_ECDH_CAM_AES_CBC_CMAC_192': ['id_PACE_ECDH_CAM', 3],
'id_PACE_ECDH_CAM_AES_CBC_CMAC_256': ['id_PACE_ECDH_CAM', 4],
}

import re
re_numeric = re.compile(r'\d+')

def numeric_arcs(oids, arcs):
ret = []

offset = 0
if isinstance(arcs[0], str):
base_oid = oids[arcs[0]]
ret.extend(numeric_arcs(oids, base_oid))
offset = 1

ret.extend(arcs[offset:])
return ret

def oid_bytes(arcs):
ret = b''

if len(arcs) == 0:
return ret

if len(arcs) == 1:
ret += bytes([40*arcs[0]])
return ret

ret += bytes([40*arcs[0] + arcs[1]])

ret += bytes(arcs[2:])

return ret

def bytes_to_c_array(data):
return [format(b, '#04x') for b in data]

def cmp_arcs(a, b):
a = a[1]
b = b[1]
if len(a) != len(b):
return len(a) - len(b)

for (va, vb) in zip(a, b):
if va != vb:
return va - vb

return 0

oids = {k: numeric_arcs(oids, v) for k, v in oids.items()}

from functools import cmp_to_key
sorted_oids = {k: v for k, v in sorted(oids.items(), key=cmp_to_key(cmp_arcs))}

c_offset = 0
nid_count = 0
so_data = ''
defines = '#define NID_undef 0\n'
c_offsets = {}
c_lengths = {}
for name, value in oids.items():
#print(name, value)
#print(num_arcs)
#print(oid_bytes(num_arcs))

if len(value) < 2: continue

arc_bytes = oid_bytes(value)

c_offsets[name] = c_offset
c_lengths[name] = len(arc_bytes)

nid_count += 1
defines += f'#define NID_{name} {nid_count}\n';

c_data = ', '.join(bytes_to_c_array(arc_bytes)) + ','
so_data += f' {c_data.ljust(60)} /* [{str(c_offset).rjust(5)}] NID_{name} = {nid_count} */\n'
c_offset += len(arc_bytes)

with open('oid_nids.h', 'w') as f:
f.write('''#ifndef PASSY_OID_NIDS_H
#define PASSY_OID_NIDS_H

/* DO NOT MODIFY THIS FILE
* This file was generated by gen_oid_nid_list.py
*/

#include <OBJECT_IDENTIFIER.h>

typedef struct OID_NID_s {
OBJECT_IDENTIFIER_t oid;
int nid;
} OID_NID_t;

''')
f.write(f'#define NUM_NID {nid_count}\n\n')
f.write(defines)
f.write('''
#endif''')

with open('oid_data.h', 'w') as f:

f.write('''
/* DO NOT MODIFY THIS FILE
* This file was generated by gen_oid_nid_list.py
*/

#include "oid_nids.h"

''')

#TODO: make const, but conflicts with non const in OBJECT_IDENTIFIER_t
f.write(f'static unsigned char so[{c_offset}] = {{\n{so_data}}};\n')
f.write('\n\n')

f.write('static const OID_NID_t obj_nids[NUM_NID] = {\n')
for name, value in sorted_oids.items():
if len(value) < 2: continue
offset = c_offsets[name]
length = c_lengths[name]
f.write(f' {{{{&so[{offset}], {length}}}, NID_{name}}},\n')
f.write('};\n')
21 changes: 21 additions & 0 deletions hack_asn1_no_qsort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python3

import sys
import re

r_qsort = re.compile('(\s*)([^/]*qsort.*)')

data = []
with open(sys.argv[1], 'r+') as f:
for line in f:
m = r_qsort.match(line)
if m:
data.append(m.group(1) + "assert(false);\n")
data.append(m.group(1) + "//" + m.group(2) + "\n")
else:
data.append(line)

f.seek(0)
for d in data:
f.write(d)
f.truncate()
Loading