diff --git a/src/main.rs b/src/main.rs index fe8afc7..3165eca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -337,8 +337,8 @@ async fn run_auth( ) .unwrap(); - // We send a new SET AT along with a GENERAL AUTHENTICATE for internal/restricted identification. - // This has to be encrypted, for Reasons. + // Set up the first part of the terminal authentication: + // send a SET AT with reference id-TA-ECDSA-SHA-256. let mut set_at_params = ca_info.0.as_bytes().to_vec(); prepend_do(&mut set_at_params, 0x80); if let Some(v) = ca_info.1 { @@ -359,6 +359,11 @@ async fn run_auth( let resp = enc_crad.transmit(new_apdu).await?; assert_eq!(resp.status, 0x9000); + // Do a GENERAL AUTHENTICATE with all-0 parameters. + // This _seems_ to swap the ephemeral key we've been using to + // communicate with the card with that of the terminal's, and as side + // effect resets the session. Once this is transmitted, we can no + // longer communicate with the card in this session. prepend_do(&mut remote_ephemeral_key_bytes, 0x80); prepend_do(&mut remote_ephemeral_key_bytes, 0x7c); let new_apdu = OwnedCommandAPDU { @@ -376,6 +381,19 @@ async fn run_auth( assert_eq!(resp.status, 0x9000); } + // The APDUs sent by the terminal are to be sent now. + // Because there's not a lot of documentation, here's what seems to be + // happening: + // + // 1. The card-verifiable certificate chain between the one in EF.CVCA and + // the certificate used by the terminal to authenticate are transmitted and + // verified (SET DST, plus VERIFY CERTIFICATE). + // + // 2. A SET AT is issued with the terminal's certificate's subject. + // 3. A GET CHALLENGE is issued to the card, with the response being + // shuttled back to the terminal. + // + // This part follows standard BSI TR-03110, if you want to take a look. ctg_pipe .send(pipe::CardToGUI::ProcessingMessage { message: String::from("Running server-sent APDUs... (0/?)"), @@ -405,6 +423,27 @@ async fn run_auth( .extend_from_slice(&last_response.status.to_be_bytes()); let apdus = ctx.prepare_pca(counter, &last_response.data).await; + + // 1. The terminal uses the challenge, plus previously-cached information, + // to sign the challenge; this signature is sent back as a EXTERNAL + // AUTHENTICATE. The terminal is now authenticated. + // + // 2. The terminal transmits a SET AT, with an OID of { id-BSNk-scheme-nl 9 + // 3 3 } (assuming a PIP). This is immediately followed by a GENERAL + // AUTHENTICATE, which has no parameters (TODO: check) and returns the + // polymorphic identity, as a CardPolymorph. + // + // A CardPolymorph is: + // - 0x80 Point0 (ECPoint) + // - 0x81 Point1 (ECPoint, optional) + // - 0x82 Point2 (ECPoint, optional) + // - 0x85 Scheme version (INTEGER) + // - 0x86 Scheme key version (INTEGER) + // - 0x87 Creator (BCD string) + // - 0x88 Recipient (BCD String) + // - 0x89 Recipient key set version (INTEGER) + // - 0x8a Type (INTEGER) + // - 0x8b Sequence number (BCD string) let apdu_count = apdus.len() as isize + counter; for apdu in apdus { counter += 1;