keycard-go/types/application_info.go

127 lines
3.1 KiB
Go

package types
import (
"errors"
"github.com/status-im/keycard-go/apdu"
)
var ErrWrongApplicationInfoTemplate = errors.New("wrong application info template")
type Capability uint8
const (
TagSelectResponsePreInitialized uint8 = 0x80
TagApplicationStatusTemplate uint8 = 0xA3
TagApplicationInfoTemplate uint8 = 0xA4
TagApplicationInfoCapabilities uint8 = 0x8D
)
const (
CapabilitySecureChannel Capability = 1 << iota
CapabilityKeyManagement
CapabilityCredentialsManagement
CapabilityNDEF
CapabilityAll = CapabilitySecureChannel |
CapabilityKeyManagement |
CapabilityCredentialsManagement |
CapabilityNDEF
)
type ApplicationInfo struct {
Installed bool
Initialized bool
InstanceUID []byte
SecureChannelPublicKey []byte
Version []byte
AvailableSlots []byte
// KeyUID is the sha256 of of the master public key on the card.
// It's empty if the card doesn't contain any key.
KeyUID []byte
Capabilities Capability
}
func (a *ApplicationInfo) HasCapability(c Capability) bool {
return a.Capabilities&c == c
}
func (a *ApplicationInfo) HasSecureChannelCapability() bool {
return a.HasCapability(CapabilitySecureChannel)
}
func (a *ApplicationInfo) HasKeyManagementCapability() bool {
return a.HasCapability(CapabilityKeyManagement)
}
func (a *ApplicationInfo) HasCredentialsManagementCapability() bool {
return a.HasCapability(CapabilityCredentialsManagement)
}
func (a *ApplicationInfo) HasNDEFCapability() bool {
return a.HasCapability(CapabilityNDEF)
}
func ParseApplicationInfo(data []byte) (*ApplicationInfo, error) {
info := &ApplicationInfo{
Installed: true,
}
if data[0] == TagSelectResponsePreInitialized {
info.SecureChannelPublicKey = data[2:]
info.Capabilities = CapabilityCredentialsManagement
if len(info.SecureChannelPublicKey) > 0 {
info.Capabilities = info.Capabilities | CapabilitySecureChannel
}
return info, nil
}
info.Initialized = true
if data[0] != TagApplicationInfoTemplate {
return nil, ErrWrongApplicationInfoTemplate
}
instanceUID, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x8F})
if err != nil {
return nil, err
}
pubKey, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x80})
if err != nil {
return nil, err
}
appVersion, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x02})
if err != nil {
return nil, err
}
availableSlots, err := apdu.FindTagN(data, 1, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x02})
if err != nil {
return nil, err
}
keyUID, err := apdu.FindTagN(data, 0, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x8E})
if err != nil {
return nil, err
}
capabilities := CapabilityAll
capabilitiesBytes, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoCapabilities})
if err == nil && len(capabilitiesBytes) > 0 {
capabilities = Capability(capabilitiesBytes[0])
}
info.InstanceUID = instanceUID
info.SecureChannelPublicKey = pubKey
info.Version = appVersion
info.AvailableSlots = availableSlots
info.KeyUID = keyUID
info.Capabilities = capabilities
return info, nil
}