Skip to content

Commit c414459

Browse files
authored
myeid: alternative way to unblock user PINs using another PIN marked with the unblockingPin flag (OpenSC#3811)
MyEID always has a PUK directly associated with each PIN. An alternative way for unblocking PINs can be configured, using another PIN object as an unblocking PIN. This commit adds special profiles files for enabling implicit unblocking and updates the MyEID driver to recognize and use this configuration for building the unblocking commands based on the PKCS#15 structures.
1 parent bfbf27b commit c414459

6 files changed

Lines changed: 789 additions & 5 deletions

File tree

src/libopensc/card-myeid.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* card-myeid.c
33
*
4-
* Copyright (C) 2008-2019 Aventra Ltd.
4+
* Copyright (C) 2008-2026 Aventra Ltd.
55
*
66
* This library is free software; you can redistribute it and/or
77
* modify it under the terms of the GNU Lesser General Public
@@ -669,15 +669,59 @@ static int myeid_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data)
669669

670670
LOG_FUNC_CALLED(card->ctx);
671671

672-
sc_log(card->ctx, "ref (%d), pin1 len(%zu), pin2 len (%zu)\n",
673-
data->pin_reference, data->pin1.len, data->pin2.len);
672+
sc_log(card->ctx, "cmd (%d), ref (%d), pin1 len(%zu), pin2 len (%zu), puk ref (%d)\n",
673+
data->cmd, data->pin_reference, data->pin1.len, data->pin2.len, data->puk_reference);
674674

675675
if(data->pin1.len > 8 || data->pin2.len > 8)
676676
LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_PIN_LENGTH);
677677

678678
data->pin1.pad_length = data->pin2.pad_length = 8;
679679
data->pin1.pad_char = data->pin2.pad_char = 0xFF;
680680

681+
if (data->cmd == SC_PIN_CMD_UNBLOCK) {
682+
/* In case the PUK reference is set, the PIN is being unblocked implicitly using a global unblocker PIN instead of the
683+
directly associated PUK. In this case, we must issue a VERIFY command first and then the RESET RETRY COUNTER command with only
684+
the new PIN in the data field. */
685+
686+
struct sc_pin_cmd_data global_unblocker_verif_data;
687+
int r;
688+
689+
if (data->puk_reference != 0) {
690+
/* Call the iso driver to do the VERIFY */
691+
memset(&global_unblocker_verif_data, 0, sizeof(global_unblocker_verif_data));
692+
global_unblocker_verif_data.pin_type = SC_AC_CHV;
693+
global_unblocker_verif_data.cmd = SC_PIN_CMD_VERIFY;
694+
global_unblocker_verif_data.pin1 = data->pin1;
695+
global_unblocker_verif_data.pin_reference = data->puk_reference;
696+
global_unblocker_verif_data.flags = data->flags;
697+
r = iso_ops->pin_cmd(card, &global_unblocker_verif_data);
698+
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
699+
700+
if (r != SC_SUCCESS)
701+
LOG_FUNC_RETURN(card->ctx, r);
702+
703+
memset(&data->pin1, 0, sizeof(struct sc_pin_cmd_pin));
704+
data->flags |= SC_PIN_CMD_IMPLICIT_CHANGE;
705+
struct sc_apdu apdu;
706+
u8 buf[SC_MAX_APDU_BUFFER_SIZE];
707+
708+
/* Let iso driver build the RESET RETRY COUNTER APDU, but we'll have to modify it before transmitting it. */
709+
r = iso7816_build_pin_apdu(card, &apdu, data, buf, sizeof(buf));
710+
711+
if (r != SC_SUCCESS)
712+
LOG_FUNC_RETURN(card->ctx, r);
713+
714+
/* MyEID's implementation of unblocking a PIN implicitly contradicts with ISO 7816-4 here. The iso driver properly sets P2=0x02
715+
while MyEID expects 0x00 */
716+
apdu.p1 = 0x00;
717+
718+
r = sc_transmit_apdu(card, &apdu);
719+
720+
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
721+
LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
722+
}
723+
}
724+
681725
if (data->cmd == SC_PIN_CMD_VERIFY && priv->card_state == SC_FILE_STATUS_CREATION) {
682726
sc_log(card->ctx, "Card in creation state, no need to verify");
683727
return SC_SUCCESS;

src/pkcs15init/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ dist_pkgdata_DATA = \
2020
epass2003.profile \
2121
rutoken_ecp.profile \
2222
rutoken_lite.profile \
23-
myeid.profile \
23+
myeid.profile myeid_so_unblock.profile myeid_unblock_with_other_pin.profile myeid_unblocking_pin.profile\
2424
authentic.profile \
2525
iasecc.profile \
2626
ias_adele_admin1.profile ias_adele_admin2.profile ias_adele_common.profile \
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#
2+
# PKCS15 r/w profile for MyEID cards
3+
#
4+
# This is a special version of the MyEID profile, which enables unblocking user PINs using the SO-PIN
5+
# This configuration is not strictly ISO 7816-15 compliant, because by the standard unblockingPin and soPin flags should not be set in the same authentication object
6+
# Use profiles "myeid_unblocking_pin" and "myeid_unblock_with_other_pin" to set up a card with a separate unblocking PIN.
7+
# The purpose of these special profiles is to enable configuring MyEID so that a PUK code associated with a user PIN can be changed after initialization.
8+
9+
cardinfo {
10+
label = "MyEID";
11+
manufacturer = "Aventra Ltd.";
12+
min-pin-length = 4;
13+
max-pin-length = 8;
14+
pin-encoding = ascii-numeric;
15+
pin-pad-char = 0xFF;
16+
}
17+
18+
#
19+
# The following controls some aspects of the PKCS15 we put onto
20+
# the card.
21+
#
22+
pkcs15 {
23+
# Put certificates into the CDF itself?
24+
direct-certificates = no;
25+
# Put the DF length into the ODF file?
26+
encode-df-length = no;
27+
# Have a lastUpdate field in the EF(TokenInfo)?
28+
do-last-update = no;
29+
}
30+
31+
option default {
32+
macros {
33+
#protected = READ=NONE, UPDATE=CHV1, DELETE=CHV2;
34+
#unprotected = READ=NONE, UPDATE=CHV1, DELETE=CHV1;
35+
36+
unusedspace-size = 510;
37+
odf-size = 255;
38+
aodf-size = 255;
39+
cdf-size = 1530;
40+
cdf-trusted-size = 510;
41+
prkdf-size = 1530;
42+
pukdf-size = 1530;
43+
skdf-size = 1530;
44+
dodf-size = 1530;
45+
}
46+
}
47+
48+
# Define reasonable limits for PINs and PUK
49+
# Note that we do not set a file path or reference
50+
# here; that is done dynamically.
51+
# This version of the profile sets the auth-if of user PIN to point to the SO-PIN. With this configuration, the driver applies the "allow global unblocking" flag to the PIN, allowing it to be unblocked with SO-PIN
52+
PIN user-pin {
53+
auth-id = FF;
54+
reference = 1;
55+
min-length = 4;
56+
max-length = 8;
57+
attempts = 3;
58+
flags = initialized, needs-padding;
59+
}
60+
61+
PIN user-puk {
62+
reference =3;
63+
min-length = 4;
64+
max-length = 8;
65+
attempts = 10;
66+
flags = needs-padding;
67+
}
68+
69+
# This version of the profile allows using so-pin to unblock other PINs.
70+
PIN so-pin {
71+
reference = 3;
72+
auth-id = FF;
73+
min-length = 4;
74+
max-length = 8;
75+
attempts = 3;
76+
flags = initialized, soPin, needs-padding, unblockingPin;
77+
}
78+
79+
PIN so-puk {
80+
min-length = 4;
81+
max-length = 8;
82+
attempts = 10;
83+
flags = needs-padding;
84+
}
85+
86+
# Additional filesystem info.
87+
# This is added to the file system info specified in the
88+
# main profile.
89+
filesystem {
90+
DF MF {
91+
path = 3F00;
92+
type = DF;
93+
acl = CREATE=$PIN, DELETE=$SOPIN;
94+
95+
# This is the DIR file
96+
EF DIR {
97+
file-id = 2F00;
98+
structure = transparent;
99+
size = 128;
100+
acl = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
101+
}
102+
DF PKCS15-AppDF {
103+
type = DF;
104+
file-id = 5015;
105+
aid = A0:00:00:00:63:50:4B:43:53:2D:31:35;
106+
acl = DELETE=$PIN, CREATE=$PIN;
107+
108+
EF PKCS15-ODF {
109+
file-id = 5031;
110+
structure = transparent;
111+
size = $odf-size;
112+
acl = READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
113+
}
114+
115+
EF PKCS15-TokenInfo {
116+
file-id = 5032;
117+
size = 160;
118+
structure = transparent;
119+
acl = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
120+
}
121+
122+
EF PKCS15-UnusedSpace {
123+
file-id = 5033;
124+
structure = transparent;
125+
size = $unusedspace-size;
126+
acl = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
127+
}
128+
129+
EF PKCS15-AODF {
130+
file-id = 4401;
131+
structure = transparent;
132+
size = $aodf-size;
133+
acl = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
134+
}
135+
136+
EF PKCS15-PrKDF {
137+
file-id = 4402;
138+
structure = transparent;
139+
size = $prkdf-size;
140+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
141+
}
142+
143+
EF PKCS15-PuKDF {
144+
file-id = 4404;
145+
structure = transparent;
146+
size = $pukdf-size;
147+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
148+
}
149+
150+
EF PKCS15-SKDF {
151+
file-id = 4407;
152+
structure = transparent;
153+
size = $skdf-size;
154+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
155+
}
156+
157+
EF PKCS15-CDF {
158+
file-id = 4403;
159+
structure = transparent;
160+
size = $cdf-size;
161+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
162+
}
163+
164+
EF PKCS15-CDF-TRUSTED {
165+
file-id = 4405;
166+
structure = transparent;
167+
size = $cdf-trusted-size;
168+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
169+
}
170+
171+
EF PKCS15-DODF {
172+
file-id = 4406;
173+
structure = transparent;
174+
size = $dodf-size;
175+
acl = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
176+
}
177+
178+
EF template-private-key {
179+
type = internal-ef;
180+
file-id = 4B01;
181+
acl = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
182+
}
183+
184+
EF template-secret-key {
185+
type = internal-ef;
186+
file-id = 4D01;
187+
acl = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
188+
}
189+
190+
EF template-public-key {
191+
structure = transparent;
192+
file-id = 5501;
193+
acl = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
194+
}
195+
196+
EF template-certificate {
197+
file-id = 4301;
198+
structure = transparent;
199+
acl = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
200+
}
201+
202+
template key-domain {
203+
# This is a dummy entry - pkcs15-init insists that
204+
# this is present
205+
EF private-key {
206+
file-id = 4B01;
207+
type = internal-ef;
208+
acl = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
209+
}
210+
EF public-key {
211+
file-id = 5501;
212+
structure = transparent;
213+
acl = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
214+
}
215+
EF secret-key {
216+
file-id = 4D01;
217+
type = internal-ef;
218+
acl = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
219+
}
220+
221+
# Certificate template
222+
EF certificate {
223+
file-id = 4301;
224+
structure = transparent;
225+
acl = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
226+
}
227+
EF privdata {
228+
file-id = 4501;
229+
structure = transparent;
230+
acl = READ=$PIN, UPDATE=$PIN, DELETE=$PIN;
231+
}
232+
EF data {
233+
file-id = 4601;
234+
structure = transparent;
235+
acl = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
236+
}
237+
}
238+
}
239+
}
240+
}

0 commit comments

Comments
 (0)