Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding CLI support #1

Merged
merged 8 commits into from
Feb 20, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Parsing commands from text file on run mode
  • Loading branch information
caiotavares committed Feb 16, 2021
commit cb5a22f5e8360eb81c1eb025b7baa6415f55b028
6 changes: 2 additions & 4 deletions examples/transaction.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# emv run --input transaction.txt

select --application A0000000043060
select A0000000043060
get_processing_options
generate_ac --cryptogram-type 80 --cdol 0000000000100000000000100986000000000009861504280030901B6A2300001EABC126F85499760000000000000000000000000000000000000000000000000000
generate_ac 80 0000000000100000000000100986000000000009861504280030901B6A2300001EABC126F85499760000000000000000000000000000000000000000000000000000
27 changes: 24 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use structopt::StructOpt;
use std::path::PathBuf;
use hex::FromHex;

#[derive(StructOpt)]
pub struct Emv {
Expand All @@ -16,9 +17,10 @@ pub enum Mode {
},
}

enum Commands {
#[derive(Debug)]
pub enum Command {
Select {
application: String
application: Vec<u8>
},
GetProcessingOptions,
ReadRecord {
Expand All @@ -27,7 +29,7 @@ enum Commands {
},
GenerateAC {
cryptogram_type: u8,
cdol: String,
cdol: Vec<u8>,
},
PutData {
tag: String,
Expand All @@ -37,3 +39,22 @@ enum Commands {
tag: String
},
}

impl Command {
pub fn from_str(str: String) -> Command {
let parts: Vec<&str> = str.split(' ').collect();
let name = parts[0];

match name {
"select" => Command::Select {
application: Vec::from_hex(parts[1]).expect("Error reading Application")
},
"get_processing_options" => Command::GetProcessingOptions,
"generate_ac" => Command::GenerateAC {
cryptogram_type: hex::decode(parts[1]).expect("Error reading Cryptogram Type").first().cloned().expect(""),
cdol: Vec::from_hex(parts[2]).expect("Error reading CDOL value"),
},
_ => panic!("Unknown command when parsing file")
}
}
}
12 changes: 2 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ pub fn get_processing_options(card: &pcsc::Card) {
send(card, apdu)
}

/// Generate the First AC requesting an ARQC from the ICC
pub fn generate_first_ac(card: &pcsc::Card, cdol1: Vec<u8>) {
let apdu = capdu::generate_ac(CryptogramType::ARQC, cdol1);
pub fn generate_ac(card: &pcsc::Card, cryptogram_type: CryptogramType, cdol: Vec<u8>) {
let apdu = capdu::generate_ac(cryptogram_type, cdol);
send(card, apdu)
}

Expand All @@ -79,13 +78,6 @@ pub fn external_authenticate(card: &pcsc::Card, issuer_authentication_data: Vec<
send(card, apdu)
}

/// Generate the Second AC approving (TC) or declining (AAC) the transaction
pub fn generate_second_ac(approve: bool, card: &pcsc::Card, cdol2: Vec<u8>) {
let cryptogram_type = if approve { CryptogramType::TC } else { CryptogramType::AAC };
let apdu = capdu::generate_ac(cryptogram_type, cdol2);
send(card, apdu)
}

pub fn unblock_pin(card: &pcsc::Card, mac: Vec<u8>) {
let apdu = capdu::reset_pin_try_counter(mac);
send(card, apdu)
Expand Down
58 changes: 42 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
extern crate hex;
extern crate pcsc;

use std::io::{self, Read, Write};
use std::fs::File;
use std::io::{self, BufRead, Read, Write};
use std::path::PathBuf;
use std::process;

use hex::FromHex;
use structopt::StructOpt;

use cli::Emv;
use cli::Mode;
use cli::{Command, Emv, Mode};

mod cli;

fn main() {
let card = emv::connect();
emv::announcement();
let args: Emv = Emv::from_args();
match args.mode {
Mode::Shell => { println!("Shell mode") }
Mode::Run { input } => { println!("Run Mode") }
}

let card = emv::connect();
match card {
Some(card) => {
emv::select_application(&card, emv::MASTERCARD_MAESTRO.to_vec());
emv::get_processing_options(&card);
emv::read_record(&card, 0x01, 0x1C);
emv::generate_first_ac(&card, read_input("Input the CDOL1 value: "));
emv::generate_second_ac(true, &card, read_input("Input the CDOL2 value: "));
emv::update_linked_application_v0(&card, emv::MASTERCARD_CREDIT.to_vec(), vec![0x00, 0xA5], read_input("Input the new value: "), read_input("Input the MAC: "));
let args: Emv = Emv::from_args();
match args.mode {
Mode::Shell => { shell(card) }
Mode::Run { input } => run(input, card)
}
}
None => {
println!("No card detected!");
Expand All @@ -37,6 +31,38 @@ fn main() {
}
}

fn run(input: PathBuf, card: pcsc::Card) {
let file = File::open(input).expect("deu ruim");
for line in io::BufReader::new(file).lines() {
if let Ok(cmd) = line {
let command = Command::from_str(cmd);
execute_command(command, &card);
}
}
}

fn execute_command(command: Command, card: &pcsc::Card) {
match command {
Command::Select { application} => emv::select_application(card, application),
Command::GetProcessingOptions => emv::get_processing_options(card),
_ => panic!("OPS")
// Command::GenerateAC { cryptogram_type, cdol} => emv::generate_ac(card, cryptogram_type, cdol)
//
// Some(card) => {
// emv::select_application(&card, emv::MASTERCARD_MAESTRO.to_vec());
// emv::get_processing_options(&card);
// emv::read_record(&card, 0x01, 0x1C);
// emv::generate_first_ac(&card, read_input("Input the CDOL1 value: "));
// emv::generate_second_ac(true, &card, read_input("Input the CDOL2 value: "));
// emv::update_linked_application_v0(&card, emv::MASTERCARD_CREDIT.to_vec(), vec![0x00, 0xA5], read_input("Input the new value: "), read_input("Input the MAC: "));
// }
}
}

fn shell(card: pcsc::Card) {
println!("Shell mode")
}

fn read_input(question: &'static str) -> Vec<u8> {
let mut buffer = String::new();
print!("{}", question);
Expand Down