Skip to content

Commit 7d1c44c

Browse files
author
JC Martin
committed
Add set CHUID
1 parent 76725db commit 7d1c44c

File tree

1 file changed

+94
-11
lines changed

1 file changed

+94
-11
lines changed

piv/piv.go

+94-11
Original file line numberDiff line numberDiff line change
@@ -847,14 +847,47 @@ func ykSetProtectedMetadata(tx *scTx, key [24]byte, m *Metadata) error {
847847
return nil
848848
}
849849

850-
// Card Holder Unique Identifier
851-
type CardId []byte
852-
853-
func (yk *YubiKey) CardId() (CardId, error) {
854-
return ykGetCardId(yk.tx)
855-
856-
}
857-
func ykGetCardId(tx *scTx) (CardId, error) {
850+
// CardID is the Card Holder Unique Identifier with settable GUID
851+
// Raw contains the whole object
852+
// GUID contains the Card Universally Unique Identifier.
853+
type CardID struct {
854+
Raw []byte
855+
GUID [16]byte
856+
}
857+
858+
// CardID returns the card CHUID with the GUID extracted
859+
func (yk *YubiKey) CardID() (CardID, error) {
860+
return ykGetCardID(yk.tx)
861+
862+
}
863+
864+
/*
865+
* From https://github.com/Yubico/yubico-piv-tool/blob/ebee7f63b85fe4373efc4d8d44cbe5fe321c158c/lib/util.c#L44
866+
* Format defined in SP-800-73-4, Appendix A, Table 9
867+
*
868+
* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
869+
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
870+
* bytes. This CHUID has an expiry of 2030-01-01.
871+
*
872+
* Defined fields:
873+
* - 0x30: FASC-N (hard-coded)
874+
* - 0x34: Card UUID / GUID (settable)
875+
* - 0x35: Exp. Date (hard-coded)
876+
* - 0x3e: Signature (hard-coded, empty)
877+
* - 0xfe: Error Detection Code (hard-coded)
878+
*/
879+
880+
var chuidTemplate = []byte{
881+
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
882+
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xc8, 0x42, 0x10, 0xc3,
883+
0xeb, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30,
885+
0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
886+
}
887+
888+
const uuidOffset = 29
889+
890+
func ykGetCardID(tx *scTx) (id CardID, err error) {
858891
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=17
859892
// OID for CardId is 5FC102
860893

@@ -872,12 +905,62 @@ func ykGetCardId(tx *scTx) (CardId, error) {
872905
}
873906
resp, err := tx.Transmit(cmd)
874907
if err != nil {
875-
return nil, fmt.Errorf("command failed: %w", err)
908+
return id, fmt.Errorf("command failed: %w", err)
876909
}
877910
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=85
878911
obj, _, err := unmarshalASN1(resp, 1, 0x13) // tag 0x53
879912
if err != nil {
880-
return nil, fmt.Errorf("unmarshaling response: %v", err)
913+
return id, fmt.Errorf("unmarshaling response: %v", err)
881914
}
882-
return obj, nil
915+
id.Raw = obj
916+
if obj[27] == 0x34 {
917+
endPos := uuidOffset + int(obj[28])
918+
copy(id.GUID[:], obj[uuidOffset:endPos])
919+
}
920+
return
921+
}
922+
923+
// SetCardID initialize the CHUID card object using a predefined template defined as
924+
// * Defined fields:
925+
// - 0x30: FASC-N (hard-coded)
926+
// - 0x34: Card UUID / GUID (settable)
927+
// - 0x35: Exp. Date (hard-coded)
928+
// - 0x3e: Signature (hard-coded, empty)
929+
// - 0xfe: Error Detection Code (hard-coded)
930+
func (yk *YubiKey) SetCardID(GUID [16]byte, key [24]byte) (CardID, error) {
931+
return ykSetCardID(yk.tx, key, GUID)
932+
933+
}
934+
935+
func ykSetCardID(tx *scTx, key [24]byte, guid [16]byte) (id CardID, err error) {
936+
937+
id.Raw = make([]byte, len(chuidTemplate))
938+
copy(id.Raw, chuidTemplate)
939+
copy(id.Raw[uuidOffset:], guid[:])
940+
941+
data := append([]byte{
942+
0x5c, // Tag list
943+
0x03,
944+
0x5f,
945+
0xc1,
946+
0x02,
947+
}, marshalASN1(0x53, id.Raw)...)
948+
949+
cmd := apdu{
950+
instruction: insPutData,
951+
param1: 0x3f,
952+
param2: 0xff,
953+
data: data,
954+
}
955+
956+
if err := ykAuthenticate(tx, key, rand.Reader); err != nil {
957+
return id, fmt.Errorf("authenticating with key: %w", err)
958+
}
959+
960+
_, err = tx.Transmit(cmd)
961+
if err != nil {
962+
return id, fmt.Errorf("command failed: %w", err)
963+
}
964+
965+
return
883966
}

0 commit comments

Comments
 (0)