From b78526df9bff0a228348491e85415e62565a0882 Mon Sep 17 00:00:00 2001 From: nganhkhoa Date: Mon, 12 Aug 2024 10:19:36 +0700 Subject: [PATCH] basic setup of card internal --- apdu.opam | 1 + bin/card.ml | 140 +++++++++++++++++++++++++++++++++++++ bin/dune | 3 +- bin/main.ml | 11 ++- dune-project | 2 +- lib/dune | 2 - smartcard/CardState.ml | 27 +++++++ smartcard/Command.ml | 13 ++++ smartcard/Filesystem.ml | 39 +++++++++++ smartcard/SecureMessage.ml | 3 + smartcard/dune | 2 + 11 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 bin/card.ml delete mode 100644 lib/dune create mode 100644 smartcard/CardState.ml create mode 100644 smartcard/Command.ml create mode 100644 smartcard/Filesystem.ml create mode 100644 smartcard/SecureMessage.ml create mode 100644 smartcard/dune diff --git a/apdu.opam b/apdu.opam index 36cd213..86f6571 100644 --- a/apdu.opam +++ b/apdu.opam @@ -12,6 +12,7 @@ bug-reports: "https://github.com/username/reponame/issues" depends: [ "ocaml" "dune" {>= "3.12"} + "hex" "odoc" {with-doc} ] build: [ diff --git a/bin/card.ml b/bin/card.ml new file mode 100644 index 0000000..44d7755 --- /dev/null +++ b/bin/card.ml @@ -0,0 +1,140 @@ +open SmartCard + +(** This file contains the default card data *) + +(* EF.CardAccess *) +let ef_cardacces = + Filesystem.ElementaryFile { + fid = Bytes.of_string "\x01\x1C"; + sid = Bytes.of_string "\x1C"; + data = Hex.to_bytes (Hex.of_string "3134300d060804007f0007020202020101300f060a04007f000702020302020201013012060a04007f0007020204020202010202010d"); + } + +(* EF.CardSecurity *) +let ef_cardsecurity = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x1D"; + data = Hex.to_bytes (Hex.of_string ""); + } + +(* EF.DIR *) +let ef_dir = + Filesystem.ElementaryFile { + fid = Bytes.of_string "\x01\x1E"; + sid = Bytes.of_string "\x1E"; + data = Hex.to_bytes (Hex.of_string ""); + } + +(* EF.ATR + +The EF.ATR/INFO may be called EF.ATR in contact card +standards or specifications, and may be called EF.INFO +in contactless card standards or specifications + +The contents of the EF.ATR/INFO can be freely retrieved by using a GET DATA command with +P1-P2 = '2F 01' and a command data field of '5C 00' ('00 CB 2F 01 02 5C 00'). The response data field for +the GET DATA command is the concatenation of all Data Objects (DO) which are present in EF.ATR/INFO. +It contains the BER-TLV content of the EF.ATR/INFO + +*) +let ef_atr = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x01"; + data = Hex.to_bytes (Hex.of_string ""); + } + + +(* EF.COM *) +let ef_com = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x1E"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.DG1 *) +let ef_dg1 = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x01"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.DG2 *) +let ef_dg2 = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x02"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.DG13 *) +let ef_dg13 = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x0D"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.DG14 *) +let ef_dg14 = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x0E"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.DG15 *) +let ef_dg15 = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x0F"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* EF.SOD *) +let ef_sod = + Filesystem.ElementaryFile { + fid = Bytes.of_string ""; + sid = Bytes.of_string "\x1D"; + data = Bytes.of_string (Base64.decode_exn ""); + } + +(* LDS1 eMRTD Application *) +let emrtd_application = + Filesystem.DelicatedFile { + fid = Bytes.of_string ""; + aid = Some (Bytes.of_string "\xA0\x00\x00\x02\x47\x10\x01"); + files = [ + ef_com; + ef_dg1; + ef_dg2; + ef_dg13; + ef_dg14; + ef_dg15; + ef_sod + ]; + } + +(** The masterfile MF for the card *) +let masterfile = Filesystem.DelicatedFile { + fid = Bytes.of_string "\x3F\x00"; + aid = None; + files = [ + ef_cardacces; + emrtd_application + ]; +} + +(** The card can have multiple files, MF included *) +let allfiles = [masterfile] + +let custom : CardState.t = { + masterfile = Some masterfile; + allfiles = allfiles; + sm = None; + current_file = None; +} + diff --git a/bin/dune b/bin/dune index 4a0136a..5dc3de3 100644 --- a/bin/dune +++ b/bin/dune @@ -1,4 +1,5 @@ +(env (dev (flags :standard -warn-error -27-32))) (executable (public_name apdu) (name main) - (libraries apdu)) + (libraries SmartCard hex base64)) diff --git a/bin/main.ml b/bin/main.ml index 7bf6048..de8d6b8 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1 +1,10 @@ -let () = print_endline "Hello, World!" +let main = + let f = SmartCard.Filesystem.find_by_fid (Bytes.of_string "\x01\x1C") Card.custom.allfiles + in + match f with + | Some _ -> print_endline "File found" + | None -> print_endline "File not found" + +let hmmge = + let command = Bytes.of_string "\x00\x86\x00\x00" in + SmartCard.CardState.process command Card.custom diff --git a/dune-project b/dune-project index 81639ce..b1c39c7 100644 --- a/dune-project +++ b/dune-project @@ -19,7 +19,7 @@ (name apdu) (synopsis "A short synopsis") (description "A longer description") - (depends ocaml dune) + (depends ocaml dune hex) (tags (topics "to describe" your project))) diff --git a/lib/dune b/lib/dune deleted file mode 100644 index d085764..0000000 --- a/lib/dune +++ /dev/null @@ -1,2 +0,0 @@ -(library - (name apdu)) diff --git a/smartcard/CardState.ml b/smartcard/CardState.ml new file mode 100644 index 0000000..0fc590e --- /dev/null +++ b/smartcard/CardState.ml @@ -0,0 +1,27 @@ +(** +ICAO 9303 communication is like a state machine, +we can make a state machine initialized and for +each subsequent commands, modifying the state. +So actually we can make an OCAML state machine. + *) + +type t = { + (* a MF may not exist *) + masterfile : Filesystem.t option; + (* a list of every files in the card *) + allfiles : Filesystem.t list; + (* encryption scheme *) + sm : SecureMessage.t option; + (* currently selected file *) + current_file : Filesystem.t option; +} + +let process command _state = + let cm = Command.parse command in + match cm.ins with + | 0x44 -> print_endline "ACTIVATE FILE" + | 0xE2 -> print_endline "APPEND RECORD" + | 0x82 -> print_endline "EXTERNAL / MUTUAL AUTHENTICATE" + | 0x86 -> print_endline "GENERAL AUTHENTICATE 0x86" + | 0x87 -> print_endline "GENERAL AUTHENTICATE 0x87" + | _ -> print_endline "NOT IMPLEMENTED" diff --git a/smartcard/Command.ml b/smartcard/Command.ml new file mode 100644 index 0000000..cb7bf24 --- /dev/null +++ b/smartcard/Command.ml @@ -0,0 +1,13 @@ +type t = { + cla : int; + ins : int; + p1 : int; + p2 : int; +} + +let parse command = { + cla = Bytes.get command 0 |> Char.code; + ins = Bytes.get command 1 |> Char.code; + p1 = Bytes.get command 2 |> Char.code; + p2 = Bytes.get command 3 |> Char.code; +} diff --git a/smartcard/Filesystem.ml b/smartcard/Filesystem.ml new file mode 100644 index 0000000..f90e0d8 --- /dev/null +++ b/smartcard/Filesystem.ml @@ -0,0 +1,39 @@ +type t + = DelicatedFile of { + fid : Bytes.t; + aid : Bytes.t option; + files : t list; + } + | ElementaryFile of { + fid : Bytes.t; + sid : Bytes.t; + data : Bytes.t; + } + +let find_by_fid fid files = + let rec eachfile = fun file -> + match file with + | DelicatedFile df -> if Bytes.equal fid df.fid + then true + else List.exists eachfile df.files + | ElementaryFile ef -> Bytes.equal fid ef.fid + in + List.find_opt eachfile files + +let find_by_aid aid files = + let rec eachfile = fun file -> + match file with + | ElementaryFile _ -> false + | DelicatedFile df -> match df.aid with + | Some id -> Bytes.equal aid id + | None -> List.exists eachfile df.files + in + List.find_opt eachfile files + +let find_by_sid sid files = + let rec eachfile = fun file -> + match file with + | DelicatedFile df -> List.exists eachfile df.files + | ElementaryFile ef -> Bytes.equal sid ef.sid + in + List.find_opt eachfile files diff --git a/smartcard/SecureMessage.ml b/smartcard/SecureMessage.ml new file mode 100644 index 0000000..692e498 --- /dev/null +++ b/smartcard/SecureMessage.ml @@ -0,0 +1,3 @@ +type t + = TripleDES + | AES diff --git a/smartcard/dune b/smartcard/dune new file mode 100644 index 0000000..42c9377 --- /dev/null +++ b/smartcard/dune @@ -0,0 +1,2 @@ +(library + (name SmartCard))