Skip to content

Commit bec9151

Browse files
committed
card-piv.c Fix creation of serial number from FASC-N
The PIV CHUID object contains a FASC-N and a GUID. If the FASC-N is all zeros the GUID will be used to create a serial number. The FASC-N is a required field. Card issuers of non-US-government cards should add a FASC-N staring with ";9999" (in ISO 4bit + parity code). i.e. starts with "0xD4 0xE7 0x39" New Token2 tokens with PIV (and maybe others) have an all zero FASC-N which means without this patch the serial number is all zeros. This can lead to problems if more then one card is on the system. Note that the Yubico-piv-tool will create a FASC-N starting with ";9999" so does not have this problem and the serial number will be based on the GUID which is settable. The use of the CHUID goes back to 2005 when both Microsoft and OpenSC would use it for serial number and containerIds. Changes to be committed: modified: src/libopensc/card-piv.c
1 parent 22ac38c commit bec9151

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

src/libopensc/card-piv.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4284,7 +4284,8 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial)
42844284
{
42854285
int r;
42864286
int i;
4287-
u8 gbits;
4287+
u8 gbits = 0; /* 0 not present or wrong length or all zeros */
4288+
u8 fbits = 0; /* 0 not present or wrong length or all zeros */
42884289
u8 *rbuf = NULL;
42894290
const u8 *body;
42904291
const u8 *fascn;
@@ -4312,9 +4313,15 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial)
43124313
body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x53, &bodylen); /* Pass the outer wrapper asn1 */
43134314
if (body != NULL && bodylen != 0 && rbuf[0] == 0x53) {
43144315
fascn = sc_asn1_find_tag(card->ctx, body, bodylen, 0x30, &fascnlen); /* Find the FASC-N data */
4316+
4317+
if (fascn && fascnlen == 25) {
4318+
for (i = 0; i < 25; i++) {
4319+
fbits = fbits || fascn[i]; /* if all are zero, gbits will be zero */
4320+
}
4321+
}
4322+
43154323
guid = sc_asn1_find_tag(card->ctx, body, bodylen, 0x34, &guidlen);
43164324

4317-
gbits = 0; /* if guid is valid, gbits will not be zero */
43184325
if (guid && guidlen == 16) {
43194326
for (i = 0; i < 16; i++) {
43204327
gbits = gbits | guid[i]; /* if all are zero, gbits will be zero */
@@ -4324,8 +4331,9 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial)
43244331
"fascn=%p,fascnlen=%"SC_FORMAT_LEN_SIZE_T"u,guid=%p,guidlen=%"SC_FORMAT_LEN_SIZE_T"u,gbits=%2.2x",
43254332
fascn, fascnlen, guid, guidlen, gbits);
43264333

4327-
if (fascn && fascnlen == 25) {
4334+
if (fascn && fascnlen == 25 && fbits) {
43284335
/* test if guid and the fascn starts with ;9999 (in ISO 4bit + parity code) */
4336+
/* ;9999 is non-gov issued FASC-N, will use FASC-N for gov issued if no guid */
43294337
if (!(gbits && fascn[0] == 0xD4 && fascn[1] == 0xE7
43304338
&& fascn[2] == 0x39 && (fascn[3] | 0x7F) == 0xFF)) {
43314339
/* fascnlen is 25 */
@@ -4335,15 +4343,20 @@ piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t* serial)
43354343
gbits = 0; /* set to skip using guid below */
43364344
}
43374345
}
4338-
if (guid && gbits) {
4339-
/* guidlen is 16 */
4346+
if (guid && guidlen == 16 && gbits) {
43404347
serial->len = guidlen;
43414348
memcpy (serial->value, guid, serial->len);
43424349
r = SC_SUCCESS;
43434350
}
43444351
}
43454352
}
43464353

4354+
if (fbits == 0 && gbits == 0) { /* were not able to set the serial number */
4355+
serial->len = 16;
4356+
memset(serial->value, 0x00, serial->len);
4357+
r = SC_ERROR_INTERNAL;
4358+
}
4359+
43474360
card->serialnr = *serial;
43484361
LOG_FUNC_RETURN(card->ctx, r);
43494362
}

0 commit comments

Comments
 (0)