Merge pull request #14 from AndrewPau/ap/add-commands
Add commands, better conform with yubiHSM docs
This commit is contained in:
commit
278b0ae2f2
|
@ -15,6 +15,10 @@ Currently the following commands are implemented:
|
|||
* DeriveEcdh
|
||||
* Echo
|
||||
* ChangeAuthenticationKey
|
||||
* PutAuthenticationKey
|
||||
* GetOpaque
|
||||
* PutOpaque
|
||||
* SignAttestationCertificate
|
||||
* Authentication & Session related commands
|
||||
* GetPseudoRandom
|
||||
|
||||
|
|
|
@ -151,6 +151,26 @@ func NewIDOption(id uint16) ListCommandOption {
|
|||
}
|
||||
}
|
||||
|
||||
func NewDomainOption(domain uint16) ListCommandOption {
|
||||
return func(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, ListObjectParamDomains)
|
||||
binary.Write(w, binary.BigEndian, domain)
|
||||
}
|
||||
}
|
||||
|
||||
func NewLabelOption(label []byte) (ListCommandOption, error) {
|
||||
if len(label) > LabelLength {
|
||||
return nil, errors.New("label is too long")
|
||||
}
|
||||
if len(label) < LabelLength {
|
||||
label = append(label, bytes.Repeat([]byte{0x00}, LabelLength-len(label))...)
|
||||
}
|
||||
return func(w io.Writer) {
|
||||
binary.Write(w, binary.BigEndian, ListObjectParamLabel)
|
||||
binary.Write(w, binary.BigEndian, label)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CreateListObjectsCommand(options ...ListCommandOption) (*CommandMessage, error) {
|
||||
command := &CommandMessage{
|
||||
CommandType: CommandTypeListObjects,
|
||||
|
@ -251,6 +271,43 @@ func CreateChangeAuthenticationKeyCommand(objID uint16, newPassword string) (*Co
|
|||
return command, nil
|
||||
}
|
||||
|
||||
func CreatePutOpaqueCommand(objID uint16, label []byte, domains uint16, capabilities uint64, algorithm Algorithm, data []byte) (*CommandMessage, error) {
|
||||
if len(label) > LabelLength {
|
||||
return nil, errors.New("label is too long")
|
||||
}
|
||||
if len(label) < LabelLength {
|
||||
label = append(label, bytes.Repeat([]byte{0x00}, LabelLength-len(label))...)
|
||||
}
|
||||
|
||||
command := &CommandMessage{
|
||||
CommandType: CommandTypePutOpaque,
|
||||
}
|
||||
|
||||
payload := bytes.NewBuffer(nil)
|
||||
binary.Write(payload, binary.BigEndian, objID)
|
||||
payload.Write(label)
|
||||
binary.Write(payload, binary.BigEndian, domains)
|
||||
binary.Write(payload, binary.BigEndian, capabilities)
|
||||
binary.Write(payload, binary.BigEndian, algorithm)
|
||||
payload.Write(data)
|
||||
|
||||
command.Data = payload.Bytes()
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
func CreateGetOpaqueCommand(objID uint16) (*CommandMessage, error) {
|
||||
command := &CommandMessage{
|
||||
CommandType: CommandTypeGetOpaque,
|
||||
}
|
||||
|
||||
payload := bytes.NewBuffer(nil)
|
||||
binary.Write(payload, binary.BigEndian, objID)
|
||||
command.Data = payload.Bytes()
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
func CreateGetPseudoRandomCommand(numBytes uint16) *CommandMessage {
|
||||
command := &CommandMessage{
|
||||
CommandType: CommandTypeGetPseudoRandom,
|
||||
|
@ -340,3 +397,22 @@ func CreatePutAuthkeyCommand(objID uint16, label []byte, domains uint16, capabil
|
|||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
func CreatePutDerivedAuthenticationKeyCommand(objID uint16, label []byte, domains uint16, capabilities uint64, delegated uint64, password string) (*CommandMessage, error) {
|
||||
authKey := authkey.NewFromPassword(password)
|
||||
return CreatePutAuthkeyCommand(objID, label, domains, capabilities, delegated, authKey.GetEncKey(), authKey.GetMacKey())
|
||||
}
|
||||
|
||||
func CreateSignAttestationCertCommand(keyObjID, attestationObjID uint16) (*CommandMessage, error) {
|
||||
command := &CommandMessage{
|
||||
CommandType: CommandTypeAttestAsymmetric,
|
||||
}
|
||||
|
||||
payload := bytes.NewBuffer([]byte{})
|
||||
binary.Write(payload, binary.BigEndian, keyObjID)
|
||||
binary.Write(payload, binary.BigEndian, attestationObjID)
|
||||
|
||||
command.Data = payload.Bytes()
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
|
|
@ -95,6 +95,18 @@ type (
|
|||
PutAuthkeyResponse struct {
|
||||
ObjectID uint16
|
||||
}
|
||||
|
||||
PutOpaqueResponse struct {
|
||||
ObjectID uint16
|
||||
}
|
||||
|
||||
GetOpaqueResponse struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
SignAttestationCertResponse struct {
|
||||
Cert []byte
|
||||
}
|
||||
)
|
||||
|
||||
// ParseResponse parses the binary response from the card to the relevant Response type.
|
||||
|
@ -157,6 +169,12 @@ func ParseResponse(data []byte) (Response, error) {
|
|||
return parsePutWrapkeyResponse(payload)
|
||||
case CommandTypePutAuthKey:
|
||||
return parsePutAuthkeyResponse(payload)
|
||||
case CommandTypePutOpaque:
|
||||
return parsePutOpaqueResponse(payload)
|
||||
case CommandTypeGetOpaque:
|
||||
return parseGetOpaqueResponse(payload)
|
||||
case CommandTypeAttestAsymmetric:
|
||||
return parseAttestationCertResponse(payload)
|
||||
case ErrorResponseCode:
|
||||
return nil, parseErrorResponse(payload)
|
||||
default:
|
||||
|
@ -217,6 +235,10 @@ func parseSignDataEddsaResponse(payload []byte) (Response, error) {
|
|||
}
|
||||
|
||||
func parseSignDataPkcs1Response(payload []byte) (Response, error) {
|
||||
if len(payload) < 1 {
|
||||
return nil, errors.New("invalid response payload length")
|
||||
}
|
||||
|
||||
return &SignDataPkcs1Response{
|
||||
Signature: payload,
|
||||
}, nil
|
||||
|
@ -335,9 +357,46 @@ func parsePutAuthkeyResponse(payload []byte) (Response, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PutAuthkeyResponse{ObjectID: objectID}, nil
|
||||
}
|
||||
|
||||
func parsePutOpaqueResponse(payload []byte) (Response, error) {
|
||||
if len(payload) != 2 {
|
||||
return nil, errors.New("invalid response payload length")
|
||||
}
|
||||
|
||||
var objectID uint16
|
||||
err := binary.Read(bytes.NewReader(payload), binary.BigEndian, &objectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PutOpaqueResponse{
|
||||
ObjectID: objectID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseGetOpaqueResponse(payload []byte) (Response, error) {
|
||||
if len(payload) < 1 {
|
||||
return nil, errors.New("invalid response payload length")
|
||||
}
|
||||
|
||||
return &GetOpaqueResponse{
|
||||
Data: payload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseAttestationCertResponse(payload []byte) (Response, error) {
|
||||
if len(payload) < 1 {
|
||||
return nil, errors.New("invalid response payload length")
|
||||
}
|
||||
|
||||
return &SignAttestationCertResponse{
|
||||
Cert: payload,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Error formats a card error message into a human readable format
|
||||
func (e *Error) Error() string {
|
||||
message := ""
|
||||
|
@ -366,12 +425,20 @@ func (e *Error) Error() string {
|
|||
message = "Log full"
|
||||
case ErrorCodeObjectNotFound:
|
||||
message = "Object not found"
|
||||
case ErrorCodeIDIllegal:
|
||||
message = "ID illegal"
|
||||
case ErrorCodeInvalidID:
|
||||
message = "Invalid ID"
|
||||
case ErrorCodeCommandUnexecuted:
|
||||
message = "Command unexecuted"
|
||||
case ErrorCodeSSHCAConstraintViolation:
|
||||
message = "SSH CA constraint violation"
|
||||
case ErrorCodeInvalidOTP:
|
||||
message = "Invalid OTP"
|
||||
case ErrorCodeDemoMode:
|
||||
message = "Demo mode"
|
||||
case ErrorCodeObjectExists:
|
||||
message = "Object exists"
|
||||
default:
|
||||
message = "unknown"
|
||||
message = "Unknown"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("card responded with error: %s", message)
|
||||
|
|
|
@ -64,78 +64,87 @@ const (
|
|||
CommandTypeChangeAuthenticationKey CommandType = 0x6c
|
||||
|
||||
// Errors
|
||||
ErrorCodeOK ErrorCode = 0x00
|
||||
ErrorCodeInvalidCommand ErrorCode = 0x01
|
||||
ErrorCodeInvalidData ErrorCode = 0x02
|
||||
ErrorCodeInvalidSession ErrorCode = 0x03
|
||||
ErrorCodeAuthFail ErrorCode = 0x04
|
||||
ErrorCodeSessionFull ErrorCode = 0x05
|
||||
ErrorCodeSessionFailed ErrorCode = 0x06
|
||||
ErrorCodeStorageFailed ErrorCode = 0x07
|
||||
ErrorCodeWrongLength ErrorCode = 0x08
|
||||
ErrorCodeInvalidPermission ErrorCode = 0x09
|
||||
ErrorCodeLogFull ErrorCode = 0x0a
|
||||
ErrorCodeObjectNotFound ErrorCode = 0x0b
|
||||
ErrorCodeIDIllegal ErrorCode = 0x0c
|
||||
ErrorCodeCommandUnexecuted ErrorCode = 0xff
|
||||
ErrorCodeOK ErrorCode = 0x00
|
||||
ErrorCodeInvalidCommand ErrorCode = 0x01
|
||||
ErrorCodeInvalidData ErrorCode = 0x02
|
||||
ErrorCodeInvalidSession ErrorCode = 0x03
|
||||
ErrorCodeAuthFail ErrorCode = 0x04
|
||||
ErrorCodeSessionFull ErrorCode = 0x05
|
||||
ErrorCodeSessionFailed ErrorCode = 0x06
|
||||
ErrorCodeStorageFailed ErrorCode = 0x07
|
||||
ErrorCodeWrongLength ErrorCode = 0x08
|
||||
ErrorCodeInvalidPermission ErrorCode = 0x09
|
||||
ErrorCodeLogFull ErrorCode = 0x0a
|
||||
ErrorCodeObjectNotFound ErrorCode = 0x0b
|
||||
ErrorCodeInvalidID ErrorCode = 0x0c
|
||||
ErrorCodeSSHCAConstraintViolation ErrorCode = 0x0e
|
||||
ErrorCodeInvalidOTP ErrorCode = 0x0f
|
||||
ErrorCodeDemoMode ErrorCode = 0x10
|
||||
ErrorCodeObjectExists ErrorCode = 0x11
|
||||
ErrorCodeCommandUnexecuted ErrorCode = 0xff
|
||||
|
||||
// Algorithms
|
||||
AlgorithmRSA2048 Algorithm = 9
|
||||
AlgorithmP256 Algorithm = 12
|
||||
AlgorithmSecp256k1 Algorithm = 15
|
||||
AlgorithmOpaqueData Algorithm = 30
|
||||
AlgorithmOpaqueX509Certificate Algorithm = 31
|
||||
AlgorithmYubicoAESAuthentication Algorithm = 38
|
||||
AlgorighmED25519 Algorithm = 46
|
||||
AlgorithmAES128CCMWrap Algorithm = 29
|
||||
AlgorithmAES192CCMWrap Algorithm = 41
|
||||
AlgorithmAES256CCMWrap Algorithm = 42
|
||||
AlgorithmED25519 Algorithm = 46
|
||||
|
||||
// Capabilities
|
||||
CapabilityGetOpaque uint64 = 0x0000000000000001
|
||||
CapabilityPutOpaque uint64 = 0x0000000000000002
|
||||
CapabilityPutAuthKey uint64 = 0x0000000000000004
|
||||
CapabilityPutAsymmetric uint64 = 0x0000000000000008
|
||||
CapabilityAsymmetricGen uint64 = 0x0000000000000010
|
||||
CapabilityAsymmetricSignPkcs uint64 = 0x0000000000000020
|
||||
CapabilityAsymmetricSignPss uint64 = 0x0000000000000040
|
||||
CapabilityAsymmetricSignEcdsa uint64 = 0x0000000000000080
|
||||
CapabilityAsymmetricSignEddsa uint64 = 0x0000000000000100
|
||||
CapabilityAsymmetricDecryptPkcs uint64 = 0x0000000000000200
|
||||
CapabilityAsymmetricDecryptOaep uint64 = 0x0000000000000400
|
||||
CapabilityAsymmetricDecryptEcdh uint64 = 0x0000000000000800 // here for backwards compatibility
|
||||
CapabilityAsymmetricDeriveEcdh uint64 = 0x0000000000000800
|
||||
CapabilityExportWrapped uint64 = 0x0000000000001000
|
||||
CapabilityImportWrapped uint64 = 0x0000000000002000
|
||||
CapabilityPutWrapKey uint64 = 0x0000000000004000
|
||||
CapabilityGenerateWrapKey uint64 = 0x0000000000008000
|
||||
CapabilityExportUnderWrap uint64 = 0x0000000000010000
|
||||
CapabilityPutOption uint64 = 0x0000000000020000
|
||||
CapabilityGetOption uint64 = 0x0000000000040000
|
||||
CapabilityGetRandomness uint64 = 0x0000000000080000
|
||||
CapabilityPutHmacKey uint64 = 0x0000000000100000
|
||||
CapabilityHmacKeyGenerate uint64 = 0x0000000000200000
|
||||
CapabilityHmacData uint64 = 0x0000000000400000
|
||||
CapabilityHmacVerify uint64 = 0x0000000000800000
|
||||
CapabilityAudit uint64 = 0x0000000001000000
|
||||
CapabilitySshCertify uint64 = 0x0000000002000000
|
||||
CapabilityGetTemplate uint64 = 0x0000000004000000
|
||||
CapabilityPutTemplate uint64 = 0x0000000008000000
|
||||
CapabilityReset uint64 = 0x0000000010000000
|
||||
CapabilityOtpDecrypt uint64 = 0x0000000020000000
|
||||
CapabilityOtpAeadCreate uint64 = 0x0000000040000000
|
||||
CapabilityOtpAeadRandom uint64 = 0x0000000080000000
|
||||
CapabilityOtpAeadRewrapFrom uint64 = 0x0000000100000000
|
||||
CapabilityOtpAeadRewrapTo uint64 = 0x0000000200000000
|
||||
CapabilityAttest uint64 = 0x0000000400000000
|
||||
CapabilityPutOtpAeadKey uint64 = 0x0000000800000000
|
||||
CapabilityGenerateOtpAeadKey uint64 = 0x0000001000000000
|
||||
CapabilityWrapData uint64 = 0x0000002000000000
|
||||
CapabilityUnwrapData uint64 = 0x0000004000000000
|
||||
CapabilityDeleteOpaque uint64 = 0x0000008000000000
|
||||
CapabilityDeleteAuthKey uint64 = 0x0000010000000000
|
||||
CapabilityDeleteAsymmetric uint64 = 0x0000020000000000
|
||||
CapabilityDeleteWrapKey uint64 = 0x0000040000000000
|
||||
CapabilityDeleteHmacKey uint64 = 0x0000080000000000
|
||||
CapabilityDeleteTemplate uint64 = 0x0000100000000000
|
||||
CapabilityDeleteOtpAeadKey uint64 = 0x0000200000000000
|
||||
CapabilityNone uint64 = 0x0000000000000000
|
||||
CapabilityGetOpaque uint64 = 0x0000000000000001
|
||||
CapabilityPutOpaque uint64 = 0x0000000000000002
|
||||
CapabilityPutAuthenticationKey uint64 = 0x0000000000000004
|
||||
CapabilityPutAsymmetric uint64 = 0x0000000000000008
|
||||
CapabilityAsymmetricGen uint64 = 0x0000000000000010
|
||||
CapabilityAsymmetricSignPkcs uint64 = 0x0000000000000020
|
||||
CapabilityAsymmetricSignPss uint64 = 0x0000000000000040
|
||||
CapabilityAsymmetricSignEcdsa uint64 = 0x0000000000000080
|
||||
CapabilityAsymmetricSignEddsa uint64 = 0x0000000000000100
|
||||
CapabilityAsymmetricDecryptPkcs uint64 = 0x0000000000000200
|
||||
CapabilityAsymmetricDecryptOaep uint64 = 0x0000000000000400
|
||||
CapabilityAsymmetricDecryptEcdh uint64 = 0x0000000000000800 // here for backwards compatibility
|
||||
CapabilityAsymmetricDeriveEcdh uint64 = 0x0000000000000800
|
||||
CapabilityExportWrapped uint64 = 0x0000000000001000
|
||||
CapabilityImportWrapped uint64 = 0x0000000000002000
|
||||
CapabilityPutWrapKey uint64 = 0x0000000000004000
|
||||
CapabilityGenerateWrapKey uint64 = 0x0000000000008000
|
||||
CapabilityExportableUnderWrap uint64 = 0x0000000000010000
|
||||
CapabilityPutOption uint64 = 0x0000000000020000
|
||||
CapabilityGetOption uint64 = 0x0000000000040000
|
||||
CapabilityGetRandomness uint64 = 0x0000000000080000
|
||||
CapabilityPutHmacKey uint64 = 0x0000000000100000
|
||||
CapabilityHmacKeyGenerate uint64 = 0x0000000000200000
|
||||
CapabilityHmacData uint64 = 0x0000000000400000
|
||||
CapabilityHmacVerify uint64 = 0x0000000000800000
|
||||
CapabilityAudit uint64 = 0x0000000001000000
|
||||
CapabilitySshCertify uint64 = 0x0000000002000000
|
||||
CapabilityGetTemplate uint64 = 0x0000000004000000
|
||||
CapabilityPutTemplate uint64 = 0x0000000008000000
|
||||
CapabilityReset uint64 = 0x0000000010000000
|
||||
CapabilityOtpDecrypt uint64 = 0x0000000020000000
|
||||
CapabilityOtpAeadCreate uint64 = 0x0000000040000000
|
||||
CapabilityOtpAeadRandom uint64 = 0x0000000080000000
|
||||
CapabilityOtpAeadRewrapFrom uint64 = 0x0000000100000000
|
||||
CapabilityOtpAeadRewrapTo uint64 = 0x0000000200000000
|
||||
CapabilityAttest uint64 = 0x0000000400000000
|
||||
CapabilityPutOtpAeadKey uint64 = 0x0000000800000000
|
||||
CapabilityGenerateOtpAeadKey uint64 = 0x0000001000000000
|
||||
CapabilityWrapData uint64 = 0x0000002000000000
|
||||
CapabilityUnwrapData uint64 = 0x0000004000000000
|
||||
CapabilityDeleteOpaque uint64 = 0x0000008000000000
|
||||
CapabilityDeleteAuthKey uint64 = 0x0000010000000000
|
||||
CapabilityDeleteAsymmetric uint64 = 0x0000020000000000
|
||||
CapabilityDeleteWrapKey uint64 = 0x0000040000000000
|
||||
CapabilityDeleteHmacKey uint64 = 0x0000080000000000
|
||||
CapabilityDeleteTemplate uint64 = 0x0000100000000000
|
||||
CapabilityDeleteOtpAeadKey uint64 = 0x0000200000000000
|
||||
CapabilityChangeAuthenticationKey uint64 = 0x0000400000000000
|
||||
|
||||
// Domains
|
||||
Domain1 uint16 = 0x0001
|
||||
|
@ -165,8 +174,12 @@ const (
|
|||
ObjectTypeOtpAeadKey uint8 = 0x07
|
||||
|
||||
// list objects params
|
||||
ListObjectParamID uint8 = 0x01
|
||||
ListObjectParamType uint8 = 0x02
|
||||
ListObjectParamID uint8 = 0x01
|
||||
ListObjectParamType uint8 = 0x02
|
||||
ListObjectParamDomains uint8 = 0x03
|
||||
ListObjectParamCapabilities uint8 = 0x04
|
||||
ListObjectParamAlgorithm uint8 = 0x05
|
||||
ListObjectParamLabel uint8 = 0x06
|
||||
)
|
||||
|
||||
// CapabilityPrimitiveFromSlice OR's all the capabilitites together.
|
||||
|
|
4
go.mod
4
go.mod
|
@ -1,6 +1,8 @@
|
|||
module github.com/certusone/yubihsm-go
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/enceve/crypto v0.0.0-20160707101852-34d48bb93815
|
||||
golang.org/x/crypto v0.0.0-20180830192347-182538f80094
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
|
||||
)
|
||||
|
|
7
go.sum
7
go.sum
|
@ -2,3 +2,10 @@ github.com/enceve/crypto v0.0.0-20160707101852-34d48bb93815 h1:D22EM5TeYZJp43hGD
|
|||
github.com/enceve/crypto v0.0.0-20160707101852-34d48bb93815/go.mod h1:wYFFK4LYXbX7j+76mOq7aiC/EAw2S22CrzPHqgsisPw=
|
||||
golang.org/x/crypto v0.0.0-20180830192347-182538f80094 h1:rVTAlhYa4+lCfNxmAIEOGQRoD23UqP72M3+rSWVGDTg=
|
||||
golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
@ -85,6 +85,8 @@ const (
|
|||
MaxMessagesPerSession = 10000
|
||||
)
|
||||
|
||||
var ErrAuthCryptogram = errors.New("authentication failed: device sent wrong cryptogram")
|
||||
|
||||
// NewSecureChannel initiates a new secure channel to communicate with an HSM using the given authKey
|
||||
// Call Authenticate next to establish a session.
|
||||
func NewSecureChannel(connector connector.Connector, authKeySlot uint16, password string) (*SecureChannel, error) {
|
||||
|
@ -143,7 +145,7 @@ func (s *SecureChannel) Authenticate() error {
|
|||
}
|
||||
|
||||
if !bytes.Equal(deviceCryptogram, createSessionResp.CardCryptogram) {
|
||||
return errors.New("authentication failed: device sent wrong cryptogram")
|
||||
return ErrAuthCryptogram
|
||||
}
|
||||
|
||||
// Create host cryptogram
|
||||
|
|
Loading…
Reference in New Issue