Skip to content

Commit

Permalink
Add set CHUID
Browse files Browse the repository at this point in the history
  • Loading branch information
JC Martin committed May 17, 2020
1 parent 76725db commit 1a5d84f
Showing 1 changed file with 90 additions and 7 deletions.
97 changes: 90 additions & 7 deletions piv/piv.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,14 +847,47 @@ func ykSetProtectedMetadata(tx *scTx, key [24]byte, m *Metadata) error {
return nil
}

// Card Holder Unique Identifier
type CardId []byte
// CardID is the Card Holder Unique Identifier with settable GUID
// Raw contains the whole object
// GUID contains the Card Universally Unique Identifier.
type CardID struct {
Raw []byte
GUID [16]byte
}

func (yk *YubiKey) CardId() (CardId, error) {
// CardID returns the card CHUID with the GUID extracted
func (yk *YubiKey) CardID() (CardID, error) {
return ykGetCardId(yk.tx)

}
func ykGetCardId(tx *scTx) (CardId, error) {

/*
* From https://github.com/Yubico/yubico-piv-tool/blob/ebee7f63b85fe4373efc4d8d44cbe5fe321c158c/lib/util.c#L44
* Format defined in SP-800-73-4, Appendix A, Table 9
*
* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
* bytes. This CHUID has an expiry of 2030-01-01.
*
* Defined fields:
* - 0x30: FASC-N (hard-coded)
* - 0x34: Card UUID / GUID (settable)
* - 0x35: Exp. Date (hard-coded)
* - 0x3e: Signature (hard-coded, empty)
* - 0xfe: Error Detection Code (hard-coded)
*/

var chuidTemplate = []byte{
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xc8, 0x42, 0x10, 0xc3,
0xeb, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30,
0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
}

const uuidOffset = 29

func ykGetCardId(tx *scTx) (id CardID, err error) {
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=17
// OID for CardId is 5FC102

Expand All @@ -872,12 +905,62 @@ func ykGetCardId(tx *scTx) (CardId, error) {
}
resp, err := tx.Transmit(cmd)
if err != nil {
return nil, fmt.Errorf("command failed: %w", err)
return id, fmt.Errorf("command failed: %w", err)
}
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=85
obj, _, err := unmarshalASN1(resp, 1, 0x13) // tag 0x53
if err != nil {
return nil, fmt.Errorf("unmarshaling response: %v", err)
return id, fmt.Errorf("unmarshaling response: %v", err)
}
id.Raw = obj
if obj[27] == 0x34 {
endPos := uuidOffset + int(obj[28])
copy(id.GUID[:], obj[uuidOffset:endPos])
}
return
}

// SetCardID initialize the CHUID card object using a predefined template defined as
// * Defined fields:
// - 0x30: FASC-N (hard-coded)
// - 0x34: Card UUID / GUID (settable)
// - 0x35: Exp. Date (hard-coded)
// - 0x3e: Signature (hard-coded, empty)
// - 0xfe: Error Detection Code (hard-coded)
func (yk *YubiKey) SetCardID(GUID [16]byte, key [24]byte) (CardID, error) {
return ykSetCardId(yk.tx, key, GUID)

}

func ykSetCardId(tx *scTx, key [24]byte, guid [16]byte) (id CardID, err error) {

id.Raw = make([]byte, len(chuidTemplate))
copy(id.Raw, chuidTemplate)
copy(id.Raw[uuidOffset:], guid[:])

data := append([]byte{
0x5c, // Tag list
0x03,
0x5f,
0xc1,
0x02,
}, marshalASN1(0x53, id.Raw)...)

cmd := apdu{
instruction: insPutData,
param1: 0x3f,
param2: 0xff,
data: data,
}
return obj, nil

if err := ykAuthenticate(tx, key, rand.Reader); err != nil {
return id, fmt.Errorf("authenticating with key: %w", err)
}

_, err = tx.Transmit(cmd)
if err != nil {
return id, fmt.Errorf("command failed: %w", err)
}

return
}

0 comments on commit 1a5d84f

Please sign in to comment.