Ensure the APDUs are shaped like we expect
This is probably a tiny bit fragile, but the WOO source, as well as the fact that the counts of APDUs is hard-coded in the client, means this is plausibly safe. We leave the stage 1 (certificate validation) requests a bit more flexible, to allow for server-side changes in certificate authentication. Post-terminal authentication APDUs, however, are scrutinized more.
This commit is contained in:
parent
759b9ac93d
commit
1172e81b3a
1 changed files with 77 additions and 1 deletions
78
src/main.rs
78
src/main.rs
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{collections::HashMap, env::args, thread, time::Duration};
|
use std::{collections::HashMap, env::args, io::ErrorKind, thread, time::Duration};
|
||||||
|
|
||||||
use der::{Any, Decode, asn1::SetOfVec, oid::ObjectIdentifier};
|
use der::{Any, Decode, asn1::SetOfVec, oid::ObjectIdentifier};
|
||||||
use openssl::{bn::BigNumContext, ec::PointConversionForm, pkey::PKey};
|
use openssl::{bn::BigNumContext, ec::PointConversionForm, pkey::PKey};
|
||||||
|
|
@ -93,6 +93,53 @@ pub trait Card {
|
||||||
) -> impl Future<Output = std::io::Result<ResultAPDU>> + Send;
|
) -> impl Future<Output = std::io::Result<ResultAPDU>> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_stage_1_apdu_expected(apdu_buf: &[u8]) -> bool {
|
||||||
|
// MSE:Set DST, encrypted
|
||||||
|
if apdu_buf.starts_with(&[0x0c, 0x22, 0x81, 0xb6]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSO:Verify self-descriptive certificate, encrypted (start of chain)
|
||||||
|
if apdu_buf.starts_with(&[0x1c, 0x2a, 0x00, 0xbe]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Rest of the chain
|
||||||
|
if apdu_buf.starts_with(&[0x0c, 0x2a, 0x00, 0xbe]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set AT for external authentication
|
||||||
|
if apdu_buf.starts_with(&[0x0c, 0x22, 0x81, 0xa4]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get challenge (terminal authentication)
|
||||||
|
if apdu_buf.starts_with(&[0x0c, 0x84, 0x00, 0x00]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn are_stage_2_apdus_expected(apdus: &[Vec<u8>]) -> bool {
|
||||||
|
// External Authenticate
|
||||||
|
if !apdus[0].starts_with(&[0x0c, 0x82, 0x00, 0x00]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSE:Set AT, chip/restricted authentication
|
||||||
|
if !apdus[1].starts_with(&[0x0c, 0x22, 0x41, 0xa4]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// General Authenticate, unknown P1/P2
|
||||||
|
if !apdus[2].starts_with(&[0x0c, 0x86, 0x00, 0x83]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_auth(
|
async fn run_auth(
|
||||||
host: String,
|
host: String,
|
||||||
session_id: String,
|
session_id: String,
|
||||||
|
|
@ -446,6 +493,21 @@ async fn run_auth(
|
||||||
let apdu_count = apdus.len();
|
let apdu_count = apdus.len();
|
||||||
for apdu in apdus {
|
for apdu in apdus {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
if !is_stage_1_apdu_expected(&apdu) {
|
||||||
|
ctg_pipe
|
||||||
|
.send(pipe::CardToGUI::ProcessingMessage {
|
||||||
|
message: format!(
|
||||||
|
"Refusing to run APDU (unexpected command) ({}/{})",
|
||||||
|
counter, apdu_count
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
ctg_pipe.send(pipe::CardToGUI::Done).await;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
ctg_pipe
|
ctg_pipe
|
||||||
.send(pipe::CardToGUI::ProcessingMessage {
|
.send(pipe::CardToGUI::ProcessingMessage {
|
||||||
message: format!("Running server-sent APDUs... ({}/{})", counter, apdu_count),
|
message: format!("Running server-sent APDUs... ({}/{})", counter, apdu_count),
|
||||||
|
|
@ -483,6 +545,20 @@ async fn run_auth(
|
||||||
// - 0x89 Recipient key set version (INTEGER)
|
// - 0x89 Recipient key set version (INTEGER)
|
||||||
// - 0x8a Type (INTEGER)
|
// - 0x8a Type (INTEGER)
|
||||||
// - 0x8b Sequence number (BCD string)
|
// - 0x8b Sequence number (BCD string)
|
||||||
|
|
||||||
|
// Ensure we receive the APDUs we expected
|
||||||
|
if apdus.len() != 3 || !are_stage_2_apdus_expected(&apdus) {
|
||||||
|
ctg_pipe
|
||||||
|
.send(pipe::CardToGUI::ProcessingMessage {
|
||||||
|
message: format!("Refusing to run stage 2 APDUs ({}/{})", counter, apdu_count),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
tokio::time::sleep(Duration::from_secs(10)).await;
|
||||||
|
ctg_pipe.send(pipe::CardToGUI::Done).await;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let apdu_count = apdus.len() as isize + counter;
|
let apdu_count = apdus.len() as isize + counter;
|
||||||
for apdu in apdus {
|
for apdu in apdus {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue