@@ -29,6 +29,43 @@ use super::channel::CardChannelExt;
2929use super :: error:: ExchangeError ;
3030use super :: ids;
3131
32+ /// Defines which certificate file to read from the card.
33+ #[ derive( Clone , Copy , Debug ) ]
34+ pub enum CertificateFile {
35+ /// X.509 certificate stored in `DF.ESIGN/EF.C.CH.AUT.E256`.
36+ ChAutE256 ,
37+ /// CV certificate stored in `MF/EF.C.eGK.AUT_CVC.E256`.
38+ EgkAutCvcE256 ,
39+ }
40+
41+ fn select_certificate_file < S > ( session : & mut S , certificate : CertificateFile ) -> Result < ( ) , ExchangeError >
42+ where
43+ S : CardChannelExt ,
44+ {
45+ match certificate {
46+ CertificateFile :: ChAutE256 => {
47+ session. execute_command_success ( & HealthCardCommand :: select_aid ( & ids:: df_esign_aid ( ) ) ) ?;
48+ session. execute_command_success ( & HealthCardCommand :: select_fid_with_options (
49+ & ids:: ef_cch_aut_e256_fid ( ) ,
50+ false ,
51+ true ,
52+ EXPECTED_LENGTH_WILDCARD_EXTENDED as i32 ,
53+ ) ) ?;
54+ }
55+ CertificateFile :: EgkAutCvcE256 => {
56+ session. execute_command_success ( & HealthCardCommand :: select ( false , false ) ) ?;
57+ session. execute_command_success ( & HealthCardCommand :: select_fid_with_options (
58+ & ids:: ef_c_egk_aut_cvc_e256_fid ( ) ,
59+ false ,
60+ true ,
61+ EXPECTED_LENGTH_WILDCARD_EXTENDED as i32 ,
62+ ) ) ?;
63+ }
64+ }
65+
66+ Ok ( ( ) )
67+ }
68+
3269/// Retrieve the X.509 certificate stored in `DF.ESIGN/EF.C.CH.AUT.E256`.
3370///
3471/// The certificate is read in chunks using the READ BINARY command until the
@@ -37,13 +74,18 @@ pub fn retrieve_certificate<S>(session: &mut S) -> Result<Vec<u8>, ExchangeError
3774where
3875 S : CardChannelExt ,
3976{
40- session. execute_command_success ( & HealthCardCommand :: select_aid ( & ids:: df_esign_aid ( ) ) ) ?;
41- session. execute_command_success ( & HealthCardCommand :: select_fid_with_options (
42- & ids:: ef_cch_aut_e256_fid ( ) ,
43- false ,
44- true ,
45- EXPECTED_LENGTH_WILDCARD_EXTENDED as i32 ,
46- ) ) ?;
77+ retrieve_certificate_from ( session, CertificateFile :: ChAutE256 )
78+ }
79+
80+ /// Retrieve a certificate file from the card.
81+ ///
82+ /// The certificate is read in chunks using the READ BINARY command until the
83+ /// card indicates the end of the file.
84+ pub fn retrieve_certificate_from < S > ( session : & mut S , certificate : CertificateFile ) -> Result < Vec < u8 > , ExchangeError >
85+ where
86+ S : CardChannelExt ,
87+ {
88+ select_certificate_file ( session, certificate) ?;
4789
4890 let mut certificate = Vec :: new ( ) ;
4991 let mut offset: i32 = 0 ;
71113mod tests {
72114 use super :: * ;
73115 use crate :: command:: health_card_status:: HealthCardResponseStatus ;
116+ use crate :: command:: select_command:: SelectCommand ;
74117 use crate :: exchange:: test_utils:: MockSession ;
75118
76119 #[ test]
@@ -95,4 +138,31 @@ mod tests {
95138 other => panic ! ( "unexpected error {other:?}" ) ,
96139 }
97140 }
141+
142+ #[ test]
143+ fn cv_certificate_selects_master_file ( ) {
144+ let mut session = MockSession :: with_extended_support (
145+ vec ! [ vec![ 0x90 , 0x00 ] , vec![ 0x90 , 0x00 ] , vec![ 0xDE , 0xAD , 0x90 , 0x00 ] , vec![ 0xBE , 0xEF , 0x62 , 0x82 ] ] ,
146+ true ,
147+ ) ;
148+
149+ let cert = retrieve_certificate_from ( & mut session, CertificateFile :: EgkAutCvcE256 ) . unwrap ( ) ;
150+ assert_eq ! ( cert, vec![ 0xDE , 0xAD , 0xBE , 0xEF ] ) ;
151+ assert_eq ! (
152+ session. recorded[ 0 ] ,
153+ HealthCardCommand :: select( false , false ) . command_apdu( false ) . unwrap( ) . to_bytes( )
154+ ) ;
155+ assert_eq ! (
156+ session. recorded[ 1 ] ,
157+ HealthCardCommand :: select_fid_with_options(
158+ & ids:: ef_c_egk_aut_cvc_e256_fid( ) ,
159+ false ,
160+ true ,
161+ EXPECTED_LENGTH_WILDCARD_EXTENDED as i32 ,
162+ )
163+ . command_apdu( false )
164+ . unwrap( )
165+ . to_bytes( )
166+ ) ;
167+ }
98168}
0 commit comments