pub enum ImageFormat {
Png,
Jpeg2000,
Unknown,
}Expand description
The format of an image the card stores.
Recognised from the magic bytes, because the card gives no other indication and the two are mixed within one file: the rendered text fields are PNG and the photograph is JPEG 2000.
Variants§
Png
PNG. The rendered card-face fields are 1-bit greyscale.
Jpeg2000
JPEG 2000, in the JP2 container. The photograph.
Unknown
Not recognised.
Implementations§
Source§impl ImageFormat
impl ImageFormat
Sourcepub const fn extension(self) -> &'static str
pub const fn extension(self) -> &'static str
The usual file extension.
Examples found in repository?
examples/read_card.rs (line 226)
39fn main() -> Result<(), Box<dyn std::error::Error>> {
40 let mut args: HashMap<String, String> = HashMap::new();
41 let mut rest = std::env::args().skip(1);
42 while let (Some(k), Some(v)) = (rest.next(), rest.next()) {
43 args.insert(k.trim_start_matches("--").to_owned(), v);
44 }
45 let get = |k: &str| args.get(k).map(String::as_str);
46 let out = std::path::PathBuf::from(get("out").unwrap_or("."));
47 // Kept so the 券面事項確認AP can be checked against it: two files, one municipality code,
48 // and nothing signs either of them.
49 let municipality;
50
51 let mut card = pcsc::connect_any(Sharing::Shared)?;
52
53 // The master file level answers only while no application is selected, so it goes first — and
54 // a power cycle is what puts the card back in that state.
55 println!("== master file ==");
56 {
57 card.transport_mut().power_cycle()?;
58 let mut mf = MasterFile::new(&mut card);
59 println!(
60 " card number {}",
61 String::from_utf8_lossy(&mf.data_object(mf::tag::CARD_IDENTIFICATION)?)
62 .trim_matches(|c: char| !c.is_ascii_graphic())
63 .to_owned()
64 );
65 let chain = mf.certificate_chain()?;
66 for (index, cert) in chain.iter().enumerate() {
67 println!(
68 " chain[{index}] {} -> {}",
69 cert.issuer_key_id, cert.subject_key_id
70 );
71 }
72 // Only the root needs a key from the table; the rest chain off it.
73 println!(
74 " chain [{}]",
75 outcome(CardVerifiableCertificate::verify_chain(&chain))
76 );
77 }
78
79 println!("\n== 共通カードAP ==");
80 {
81 let mut common = CommonAp::select(&mut card)?;
82 // Answers here on some cards and at the master file level on others.
83 let atr = common.card().contact_atr()?;
84 println!(
85 " contact ATR {}",
86 atr.iter()
87 .map(|b| format!("{b:02X}"))
88 .collect::<Vec<_>>()
89 .join(" ")
90 );
91 let info = common.read_card_info()?;
92 println!(" serial {}", info.serial);
93 println!(
94 " municipality {} (prefecture {})",
95 info.municipality_code,
96 info.prefecture_code()
97 );
98 println!(" expires {}", info.expiry);
99 municipality = info.municipality_code.clone();
100 }
101
102 println!("\n== 券面入力補助AP ==");
103 {
104 let mut text = TextAp::select(&mut card)?;
105 let cert = text.read_certificate()?;
106 println!(
107 " certificate 被証明者鍵ID {}, issued under {} [{}]",
108 cert.subject_key_id,
109 cert.issuer_key_id,
110 outcome(cert.verify())
111 );
112
113 // Free to read. The key it names is not the one the certificate above certifies, and
114 // what it is for is not established.
115 let basic = text.read_ap_basic_data()?;
116 println!(
117 " AP basic names key {}, {} B trailing",
118 basic.public_key_id,
119 basic.trailing.len()
120 );
121
122 if let Some(pin) = get("pin") {
123 text.verify_pin(&Pin::numeric(pin)?)?;
124
125 // Signed by the key the certificate certifies, and gated on the same credential.
126 let signed_key = text.read_signed_public_key()?;
127 println!(
128 " signed key {} bit [{}]",
129 signed_key.public_key.bits(),
130 outcome(signed_key.verify(&cert.public_key))
131 );
132
133 println!(" 個人番号 {}", text.read_my_number()?.as_str());
134 let a = text.read_attributes()?;
135 println!(" 氏名 {}", a.name);
136 println!(" 住所 {}", a.address);
137 println!(
138 " 生年月日 {}{}",
139 a.birth_date,
140 match a.birth_date.to_era() {
141 Some((era, year)) => format!(" ({}{}年)", era.name(), year),
142 None => String::new(),
143 }
144 );
145 println!(" 性別 {:?}", a.sex);
146
147 // EF 0003 signs a digest of each of the two files above, so it ties them together.
148 let integrity = text.read_integrity_record()?;
149 let my_number_file = text.read_my_number_file()?;
150 let attributes_file = text.read_ef(myna_card::ap::text::ef::ATTRIBUTES)?;
151 println!(
152 " integrity signature [{}], 個人番号 digest [{}], 基本4情報 digest [{}]",
153 outcome(integrity.verify(&cert.public_key)),
154 if integrity.matches_my_number_file(&my_number_file) {
155 "ok"
156 } else {
157 "MISMATCH"
158 },
159 match integrity.matches_attributes_file(&attributes_file) {
160 Ok(true) => "ok",
161 Ok(false) => "MISMATCH",
162 Err(_) => "unreadable",
163 }
164 );
165 } else {
166 println!(" (pass --pin to read the 個人番号 and 基本4情報)");
167 }
168 }
169
170 println!("\n== 券面事項確認AP ==");
171 {
172 let mut surface = SurfaceAp::select(&mut card)?;
173 let cert = surface.read_certificate()?;
174 println!(
175 " certificate 被証明者鍵ID {}, issued under {} [{}]",
176 cert.subject_key_id,
177 cert.issuer_key_id,
178 outcome(cert.verify())
179 );
180 let issuer = &cert.public_key;
181
182 // Also free to read, and it repeats the municipality code. Neither copy is independently
183 // authenticated here, so the agreement is only a consistency check.
184 let basic = surface.read_ap_basic_data()?;
185 println!(
186 " AP basic municipality {}{}, DF35 key reference {}",
187 basic.municipality_code,
188 if municipality == basic.municipality_code {
189 " (agrees with 共通カードAP)"
190 } else {
191 " (DISAGREES with 共通カードAP)"
192 },
193 basic.encrypted_reference_number.key_id
194 );
195
196 if let Some(dob) = get("birth-date") {
197 surface.verify_birth_date(&Pin::numeric(dob)?)?;
198 // The age verification record: the one field this credential is meant to reveal.
199 let age = surface.read_age_record()?;
200 println!(
201 " 年齢確認 生年月日 {} [{}]",
202 age.birth_date,
203 outcome(age.verify(issuer))
204 );
205 }
206 if let Some(code) = get("code-a").or_else(|| get("code-b")) {
207 let pin = Pin::numeric(code)?;
208 if get("code-a").is_some() {
209 surface.verify_code_a(&pin)?;
210 } else {
211 surface.verify_code_b(&pin)?;
212 }
213 let face = surface.read_card_face()?;
214 println!(
215 " 券面 生年月日 {}, 有効期限 {}, 性別 {:?} [{}]",
216 face.birth_date,
217 face.expiry,
218 face.sex,
219 outcome(face.verify(issuer))
220 );
221 for (label, image) in [
222 ("name", &face.name_image),
223 ("address", &face.address_image),
224 ("photo", &face.photo),
225 ] {
226 let path = out.join(format!("{label}.{}", image.format.extension()));
227 std::fs::write(&path, &image.data)?;
228 println!(
229 " {label:<12} {:?}, {} bytes -> {}",
230 image.format,
231 image.data.len(),
232 path.display()
233 );
234 }
235 // The record proves the data is authentic; a fresh signature proves the card that
236 // holds the matching private key is the one in the reader right now.
237 let challenge = surface.card().get_challenge(16)?;
238 let signature = surface.sign(&challenge)?;
239 println!(
240 " challenge 16 bytes signed by the card key [{}]",
241 outcome(SignatureScheme::Sha256DigestInfo.verify(
242 &face.public_key,
243 &challenge,
244 &signature
245 ))
246 );
247
248 if get("code-a").is_some() {
249 let n = surface.read_my_number_image()?;
250 println!(" my-number signature [{}]", outcome(n.verify(issuer)));
251 let path = out.join(format!("my-number.{}", n.image.format.extension()));
252 std::fs::write(&path, &n.image.data)?;
253 println!(
254 " my-number {:?}, {} bytes -> {}",
255 n.image.format,
256 n.image.data.len(),
257 path.display()
258 );
259 }
260 }
261 }
262
263 println!("\n== 公的個人認証AP ==");
264 {
265 let mut jpki = JpkiAp::select(&mut card)?;
266 println!(" token {:?}", jpki.read_token_type()?);
267 for (label, der) in [
268 ("auth", jpki.read_auth_certificate_der()?),
269 ("auth-ca", jpki.read_auth_ca_certificate_der()?),
270 ] {
271 let path = out.join(format!("{label}.der"));
272 std::fs::write(&path, &der)?;
273 println!(" {label:<12} {} bytes -> {}", der.len(), path.display());
274 }
275 // Two checks that look alike and are not. The first ends at the CA certificate in EF
276 // 000B — the same card, so it says only that the card is internally consistent. The
277 // second ends at a root the crate carries, which the card had no say in.
278 let chain = [
279 jpki.read_auth_certificate()?,
280 jpki.read_auth_ca_certificate()?,
281 ];
282 let (issued, _) = chain[0].validity();
283 println!(
284 " card's CA auth <- auth-ca [{}]",
285 outcome(Certificate::verify_chain(&chain, issued))
286 );
287 println!(
288 " to a root production only [{}]",
289 outcome(chain[0].verify_to_root(issued, Accept::ProductionOnly))
290 );
291 // A test card reaches no published root; asking for the test hierarchy is how you say so
292 // out loud. Never do this where the answer decides whether to believe a cardholder.
293 println!(
294 " test accepted [{}]",
295 outcome(chain[0].verify_to_root(issued, Accept::ProductionAndTest))
296 );
297
298 // Reported, never guessed at: an empty VERIFY costs nothing.
299 for (label, r) in [
300 ("利用者証明用", jpki.auth_pin_retries()?),
301 ("署名用", jpki.sign_pin_retries()?),
302 ] {
303 println!(
304 " {label} retries {}",
305 match r {
306 Retries::Remaining(n) => n.to_string(),
307 Retries::Blocked => "blocked".into(),
308 Retries::Unlimited => "unlimited".into(),
309 Retries::NotReported => "not reported".into(),
310 }
311 );
312 }
313 }
314
315 Ok(())
316}Trait Implementations§
Source§impl Clone for ImageFormat
impl Clone for ImageFormat
Source§fn clone(&self) -> ImageFormat
fn clone(&self) -> ImageFormat
Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreimpl Copy for ImageFormat
Source§impl Debug for ImageFormat
impl Debug for ImageFormat
impl Eq for ImageFormat
Source§impl PartialEq for ImageFormat
impl PartialEq for ImageFormat
impl StructuralPartialEq for ImageFormat
Auto Trait Implementations§
impl Freeze for ImageFormat
impl RefUnwindSafe for ImageFormat
impl Send for ImageFormat
impl Sync for ImageFormat
impl Unpin for ImageFormat
impl UnsafeUnpin for ImageFormat
impl UnwindSafe for ImageFormat
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more