diff --git a/command/command.go b/command/command.go index 79ff722..79133e9 100755 --- a/command/command.go +++ b/command/command.go @@ -68,6 +68,32 @@ func DeleteCardContent(relatedObjects bool, elfOrAppAID aid.AID, token []byte, c return capdu } +// DeleteRootSecurityDomain returns a apdu.Capdu that contains a DELETE command that is used to delete a root security domain +// and all associated applications. +// +// Delete command will be rejected, if the aid.AID does not refer to a root security domain or the Global Delete Privilege is missing. +func DeleteRootSecurityDomain(sdAID aid.AID, token []byte, crtSignature *CRTDigitalSignature) apdu.Capdu { + builder := bertlv.Builder{}.AddBytes(tag.AID, sdAID) + if token != nil { + builder = builder.AddBytes(tag.DeleteToken, token) + } + + if crtSignature != nil { + builder = builder.AddRaw(crtSignature.Bytes()) + } + + capdu := apdu.Capdu{ + Cla: claGp, + Ins: deleteINS, + P1: 0x00, + P2: 0x00, + Data: builder.Bytes(), + Ne: apdu.MaxLenResponseDataStandard, + } + + return capdu +} + // DeleteKey returns a apdu.Capdu that contains a DELETE command that is used to delete a key // identified by the Key ID and Key Version Number. // @@ -452,11 +478,14 @@ const ( GetStatusP1ApplicationsAndSSD byte = 0x40 GetStatusP1ELF byte = 0x20 GetStatusP1ELFAndEM byte = 0x10 + GetStatusP1LogicallyDeleted byte = 0x08 + GetStatusP1OPEN byte = 0x04 GetStatusP2FormatGpTLV byte = 0x02 ) // GetStatus returns a apdu.Capdu that contains a GET STATUS command with P2 = format BER-TLV. // Data can be added if a GET STATUS command requires the passing of additional data (e.g. for filter). +// GetStatusCommandDataField can be used to construct data field. func GetStatus(p1 byte, next bool, data []byte) apdu.Capdu { p2 := byte(0x02) if next { @@ -473,6 +502,31 @@ func GetStatus(p1 byte, next bool, data []byte) apdu.Capdu { } } +const ( + GetStatusCRSP1Applications byte = 0x40 + GetStatusCRSP1OPEN byte = 0x04 +) + +// GetStatusCRS is used to retrieve information about applications that are registered in Contactless Registry Service (CRS). +// Information about non-contactless applications are not available through this command. +// Data can be added if a GET STATUS command requires the passing of additional data (e.g. for filter). +// GetStatusCRSCommandDataField can be used to construct data field. +func GetStatusCRS(p1 byte, next bool, data []byte) apdu.Capdu { + p2 := byte(0x00) + if next { + p2 += 0x01 + } + + return apdu.Capdu{ + Cla: claGp, + Ins: getStatusINS, + P1: p1, + P2: p2, + Data: data, + Ne: apdu.MaxLenResponseDataStandard, + } +} + const ( manageChannelP1CloseSupplementaryLogicalChannel byte = 0x80 manageChannelP1OpenNextAvailableSupplementaryLogicalChannel byte = 0x00 @@ -505,6 +559,23 @@ const ( SetStatusP1ISD byte = 0x80 SetStatusP1ApplicationOrSSD byte = 0x40 SetStatusP1SdAndAssociatedApplications byte = 0x60 + + SetStatusP1AvailabilityStateContactless byte = 0x01 // Availability State over Contactless Interface + SetStatusP1PriorityOrderApplicationSelection byte = 0x02 // Priority Order for Application Selection + SetStatusP1CommunicationInterfaceAccess byte = 0x04 // Communication Interface Access + SetStatusP1ContactlessProtocolTypeState byte = 0x08 // Contactless Protocol Type State + SetStatusP1RemainingResponseData byte = 0x80 // Remaining Response Data + + SetStatusP2NotAvailableContactless byte = 0x00 // OPEN shall not attempt to activate + SetStatusP2AvailableContactless byte = 0x01 // OPEN shall attempt to activate + SetStatusP2AssignHighestPriority byte = 0x01 // Assign Highest Priority + SetStatusP2AssignLowestPriority byte = 0x81 // Assign Lowest Priority + SetStatusP2AssignVolatilePriority byte = 0x02 // Assign Volatile Priority + SetStatusP2ResetVolatilePriority byte = 0x82 // Reset Volatile Priority + SetStatusP2CommunicationInterfaceON byte = 0x80 // Communication Interface switched ON + SetStatusP2CommunicationInterfaceOFF byte = 0x00 // Communication Interface switched OFF + SetStatusP2EnableContactlessProtocolType byte = 0x80 // Enable Contactless Protocol Type + SetStatusP2DisableContactlessProtocolType byte = 0x00 // Disable Contactless Protocol Type ) // SetStatus returns a apdu.Capdu that contains a SET STATUS command. @@ -569,330 +640,6 @@ func StoreData(p1, blockNumber byte, data []byte) apdu.Capdu { } } -// LoadFileStructure represents a GlobalPlatform Load File that can be loaded to a SE with a LOAD command. -type LoadFileStructure struct { - DAPBlocks []DAPBlock // Blocks to be verified by a Security Domain with the DAP Verification or Mandated DAP Verification privilege. - LoadFileDataBlock []byte // Plaintext platform specific code of a Load File - shall not be present when CipheredLoadFileDataBlock is present. - CipheredLoadFileDataBlock []byte // Ciphered platform specific code of a Load File that can be decrypted by a Security Domain with the Ciphered Load File Data Block privilege - shall not be present when LoadFileDataBlock is present - ICV []byte // May be present if CipheredLoadFileDataBlock is present and has been encrypted with an ICV other than the zero ICV. -} - -// Bytes returns LoadFileStructure as BER-TLV encoded bytes. -func (lfs LoadFileStructure) Bytes() []byte { - builder := &bertlv.Builder{} - - for _, dapBlock := range lfs.DAPBlocks { - d := dapBlock.Bytes() - builder = builder.AddRaw(d) - } - - if lfs.LoadFileDataBlock != nil { - builder = builder.AddBytes(tag.LoadFileDataBlock, lfs.LoadFileDataBlock) - } - - if lfs.ICV != nil { - builder = builder.AddBytes(tag.ICV, lfs.ICV) - } - - if lfs.CipheredLoadFileDataBlock != nil { - builder = builder.AddBytes(tag.CipheredLoadFileDataBlock, lfs.CipheredLoadFileDataBlock) - } - - return builder.Bytes() -} - -// DAPBlock represents a Data Authentication Pattern block (Load File Data Block Signature) and contains the AID of the Security Domain that shall verify -// this block as well as the signature over a Load File Data Block that shall be loaded. -type DAPBlock struct { - SDAID aid.AID // AID of the Security Domain with the (Mandated) DAP Verification privilege. - LFDBSignature []byte // Signature over the Load File Data Block. -} - -// Bytes returns DAPBlock as BER-TLV bytes. -func (dapBlock DAPBlock) Bytes() []byte { - return bertlv.Builder{}.AddBytes(tag.DAPBlock, - bertlv.Builder{}. - AddBytes(tag.AID, dapBlock.SDAID). - AddBytes(tag.LoadFileDataBlockSignature, dapBlock.LFDBSignature). - Bytes()). - Bytes() -} - -// CRTDigitalSignature is the Cryptographic Reference Template for Digital Signature and is especially recommended to use with SCP10. -type CRTDigitalSignature struct { - SDIdentificationNumber []byte // Identification Number of the Security Domain with the Token Verification privilege. - SDImageNumber []byte // Image Number of the Security Domain with the Token Verification privilege. - ApplicationProviderIdentifier []byte // Application Provider identifier. - TokenIdentifier []byte // Token identifier/number (digital signature counter). -} - -// Bytes returns CRTDigitalSignature as BER-TLV encoded bytes. -func (crt CRTDigitalSignature) Bytes() []byte { - builder := &bertlv.Builder{} - - if crt.SDIdentificationNumber != nil { - builder = builder.AddBytes(tag.SDIdentificationNumber, crt.SDIdentificationNumber) - } - - if crt.SDImageNumber != nil { - builder = builder.AddBytes(tag.SDImageNumber, crt.SDImageNumber) - } - - if crt.ApplicationProviderIdentifier != nil { - builder = builder.AddBytes(tag.ApplicationProviderIdentifier, crt.ApplicationProviderIdentifier) - } - - if crt.TokenIdentifier != nil { - builder = builder.AddBytes(tag.TokenIdentification, crt.TokenIdentifier) - } - - return bertlv.Builder{}.AddBytes(tag.ControlReferenceTemplateForDigitalSignature, builder.Bytes()).Bytes() -} - -// PrivacyRequirements may be specified for an Application using tag 'E0' as part of System Specific Install Parameters. -type PrivacyRequirements struct { - RequiredPrivacyStatus []RequiredPrivacyStatus // 0 to N occurrences allowed - RequiredPrivacyCondition *RequiredPrivacyCondition // structure is not specified by GPC Privacy Framework, 0 to 1 occurrences allowed -} - -// RequiredPrivacyStatus is the Privacy Status that must have been reached in the execution of the Global Privacy Protocol -// and is maintained by the GPP service. -type RequiredPrivacyStatus struct { - Constructed bool // indicates whether Value consists of constructed data objects or not - Value []byte // structure is not specified by GPC Privacy Framework -} - -// Bytes returns RequiredPrivacyStatus as BER-TLV encoded bytes. -func (req RequiredPrivacyStatus) Bytes() []byte { - builder := &bertlv.Builder{} - - if req.Constructed { - builder = builder.AddBytes(tag.RequiredPrivacyStatusConstructed, req.Value) - } else { - builder = builder.AddBytes(tag.RequiredPrivacyStatus, req.Value) - } - - return builder.Bytes() -} - -// RequiredPrivacyCondition defines a condition for an application about the Current Privacy Status before the OPEX allows the selection of that application. -type RequiredPrivacyCondition struct { - Constructed bool // indicates whether Value consists of constructed data objects or not - Value []byte // structure is not specified by GPC Privacy Framework -} - -// Bytes returns RequiredPrivacyCondition as BER-TLV encoded bytes. -func (req RequiredPrivacyCondition) Bytes() []byte { - builder := &bertlv.Builder{} - - if req.Constructed { - builder = builder.AddBytes(tag.RequiredPrivacyConditionConstructed, req.Value) - } else { - builder = builder.AddBytes(tag.RequiredPrivacyCondition, req.Value) - } - - return builder.Bytes() -} - -// Bytes returns PrivacyRequirements as BER-TLV encoded bytes. -func (req PrivacyRequirements) Bytes() []byte { - outerBuilder := &bertlv.Builder{} - innerBuilder := &bertlv.Builder{} - - for _, ps := range req.RequiredPrivacyStatus { - innerBuilder = innerBuilder.AddRaw(ps.Bytes()) - } - - if req.RequiredPrivacyCondition != nil { - innerBuilder = innerBuilder.AddRaw(req.RequiredPrivacyCondition.Bytes()) - } - - return outerBuilder.AddBytes(tag.PrivacyRequirements, innerBuilder.Bytes()).Bytes() -} - -// SystemSpecificParameters providee additional parameters that can be used for an INSTALL command, although their presence might be ignored. -// If both tag 'C6' and 'C8' are present and the implementation does not make any distinction between Non-Volatile Code and Non-Volatile Data Memory -// then the required minimum shall be the sum of both values. -type SystemSpecificParameters struct { - NonVolatileCodeMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 - VolatileMemoryMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 - NonVolatileMemoryMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 - VolatileReservedMemory []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 - NonVolatileReservedMemory []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 - GlobalServiceParameters []byte // One or more two-byte service parameters. - TS102226SpecificParameters []byte // UICC specific parameters. - LoadFileDataBlockFormatID util.NullByte // Proprietary Load File Data Block format ID. - LoadFileDataBlockParameters []byte // Proprietary Load File Data Block parameters. - RestrictParameter *open.Restrict // Lists functionalities that shall be disabled. - ImplicitSelectionParameter util.NullByte // Implicit selection parameter. - PrivacyRequirements *PrivacyRequirements // Privacy Requirements for an application. -} - -// Bytes returns SystemSpecificParameters as BER-TLV encoded bytes. -func (ssp SystemSpecificParameters) Bytes() []byte { - builder := &bertlv.Builder{} - - if ssp.NonVolatileCodeMinimumRequirement != nil { - builder = builder.AddBytes(tag.NonVolatileCodeMinimumRequirement, ssp.NonVolatileCodeMinimumRequirement) - } - - if ssp.VolatileMemoryMinimumRequirement != nil { - builder = builder.AddBytes(tag.VolatileMemoryQuota, ssp.VolatileMemoryMinimumRequirement) - } - - if ssp.NonVolatileMemoryMinimumRequirement != nil { - builder = builder.AddBytes(tag.NonVolatileMemoryQuota, ssp.NonVolatileMemoryMinimumRequirement) - } - - if ssp.GlobalServiceParameters != nil { - builder = builder.AddBytes(tag.GlobalServiceParameters, ssp.GlobalServiceParameters) - } - - if ssp.LoadFileDataBlockFormatID.Valid { - builder = builder.AddByte(tag.LoadFileDataBlockFormatID, ssp.LoadFileDataBlockFormatID.Byte) - } - - if ssp.VolatileReservedMemory != nil { - builder = builder.AddBytes(tag.VolatileReservedMemory, ssp.VolatileReservedMemory) - } - - if ssp.NonVolatileReservedMemory != nil { - builder = builder.AddBytes(tag.NonVolatileReservedMemory, ssp.NonVolatileReservedMemory) - } - - if ssp.RestrictParameter != nil { - builder = builder.AddByte(tag.Restrict, ssp.RestrictParameter.Byte()) - } - - if ssp.LoadFileDataBlockParameters != nil { - builder = builder.AddBytes(tag.LoadFileDataBlockParameter, ssp.LoadFileDataBlockParameters) - } - - if ssp.TS102226SpecificParameters != nil { - builder = builder.AddBytes(tag.TS102226SpecificParameters, ssp.TS102226SpecificParameters) - } - - if ssp.ImplicitSelectionParameter.Valid { - builder = builder.AddByte(tag.ImplicitSelectionParameter, ssp.ImplicitSelectionParameter.Byte) - } - - if ssp.PrivacyRequirements != nil { - builder = builder.AddRaw(ssp.PrivacyRequirements.Bytes()) - } - - return bertlv.Builder{}.AddBytes(tag.SystemSpecificParameter, builder.Bytes()).Bytes() -} - -// LoadParameters provide additional parameters that can be used for an INSTALL [for load] command. -type LoadParameters struct { - SystemSpecificParameters *SystemSpecificParameters - ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature -} - -// Bytes returns LoadParameters as BER-TLV encoded bytes. -func (lp LoadParameters) Bytes() []byte { - builder := &bertlv.Builder{} - - if lp.SystemSpecificParameters != nil { - builder = builder.AddRaw(lp.SystemSpecificParameters.Bytes()) - } - - if lp.ControlReferenceTemplateForDigitalSignature != nil { - builder = builder.AddRaw(lp.ControlReferenceTemplateForDigitalSignature.Bytes()) - } - - return builder.Bytes() -} - -// InstallParameters provide additional parameters that can be used for commands containing the INSTALL [for installation] step. -type InstallParameters struct { - ApplicationSpecificParameters []byte - SystemSpecificParameters *SystemSpecificParameters - TS102226SpecificTemplate []byte - ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature -} - -// Bytes returns InstallParameters as BER-TLV encoded bytes. -func (ip InstallParameters) Bytes() []byte { - builder := &bertlv.Builder{} - - if len(ip.ApplicationSpecificParameters) == 0 { - builder = builder.AddEmpty(tag.ApplicationSpecificParameters) - } else { - builder = builder.AddBytes(tag.ApplicationSpecificParameters, ip.ApplicationSpecificParameters) - } - - if ip.SystemSpecificParameters != nil { - builder = builder.AddRaw(ip.SystemSpecificParameters.Bytes()) - } - - if ip.TS102226SpecificTemplate != nil { - builder = builder.AddBytes(tag.TS102226SpecificTemplate, ip.TS102226SpecificTemplate) - } - - if ip.ControlReferenceTemplateForDigitalSignature != nil { - builder = builder.AddRaw(ip.ControlReferenceTemplateForDigitalSignature.Bytes()) - } - - return builder.Bytes() -} - -// MakeSelectableParameters provides additional parameters that can be used for an INSTALL [for make selectable] command. -type MakeSelectableParameters struct { - SystemSpecificParameters *SystemSpecificParameters - ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature -} - -// Bytes returns MakeSelectableParameters as BER-TLV encoded bytes. -func (mp MakeSelectableParameters) Bytes() []byte { - builder := &bertlv.Builder{} - - if mp.SystemSpecificParameters != nil { - builder = builder.AddRaw(mp.SystemSpecificParameters.Bytes()) - } - - if mp.ControlReferenceTemplateForDigitalSignature != nil { - builder = builder.AddRaw(mp.ControlReferenceTemplateForDigitalSignature.Bytes()) - } - - return builder.Bytes() -} - -// ExtraditionParameters provides additional parameters that can be used for an INSTALL [for extradition] command. -type ExtraditionParameters struct { - ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature -} - -// Bytes returns ExtraditionParameters as BER-TLV encoded bytes. -func (ep ExtraditionParameters) Bytes() []byte { - if ep.ControlReferenceTemplateForDigitalSignature != nil { - return bertlv.Builder{}.AddRaw(ep.ControlReferenceTemplateForDigitalSignature.Bytes()).Bytes() - } - - return nil -} - -// RegistryUpdateParameters provides additional parameters that can be used for an INSTALL [for registry update] command. -type RegistryUpdateParameters struct { - SystemSpecificParameters *SystemSpecificParameters - ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature -} - -// Bytes returns RegistryUpdateParameters as BER-TLV encoded bytes. -func (rup RegistryUpdateParameters) Bytes() []byte { - builder := &bertlv.Builder{} - - if rup.SystemSpecificParameters != nil { - builder = builder.AddRaw(rup.SystemSpecificParameters.Bytes()) - } - - if rup.ControlReferenceTemplateForDigitalSignature != nil { - builder = builder.AddRaw(rup.ControlReferenceTemplateForDigitalSignature.Bytes()) - } - - return builder.Bytes() -} - // OnLogicalChannel returns the modified CLA byte that indicates the specified logical channel ID. // Note: Values for channel ID > 0x13 (19) will be set to 0x13 since this is the highest supported value. func OnLogicalChannel(channelID, cla byte) byte { @@ -1129,7 +876,7 @@ func LookupResponseStatus(ins byte, resp apdu.Rapdu) ResponseStatus { return ResponseStatus{SW: resp.String(), Description: description} } -// ToString returns thee human readable response status. +// ToString returns the human-readable response status. func (rs ResponseStatus) ToString() string { return fmt.Sprintf("SW: %s Description: %s", rs.SW, rs.Description) } diff --git a/command/command_test.go b/command/command_test.go index b814e30..90102f7 100755 --- a/command/command_test.go +++ b/command/command_test.go @@ -1,9 +1,6 @@ package command import ( - "encoding/hex" - "fmt" - "strings" "testing" "github.com/google/go-cmp/cmp" @@ -79,6 +76,54 @@ func TestDeleteCardContent(t *testing.T) { } } +func TestDeleteRootSecurityDomain(t *testing.T) { + tests := []struct { + name string + inputAID aid.AID + inputToken []byte + inputSignature *CRTDigitalSignature + expected apdu.Capdu + }{ + { + name: "DELETE no token, no signatures", + inputAID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05}, + inputToken: nil, + inputSignature: nil, + expected: apdu.Capdu{ + Cla: 0x80, + Ins: 0xE4, + P1: 0x00, + P2: 0x00, + Data: []byte{0x4F, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05}, + Ne: 256, + }, + }, + { + name: "DELETE with token, with signatures", + inputAID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05}, + inputToken: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + inputSignature: &CRTDigitalSignature{SDIdentificationNumber: []byte{0x01, 0x02, 0x03, 0x04}}, + expected: apdu.Capdu{ + Cla: 0x80, + Ins: 0xE4, + P1: 0x00, + P2: 0x00, + Data: []byte{0x4F, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, 0x9E, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xB6, 0x06, 0x42, 0x04, 0x01, 0x02, 0x03, 0x04}, + Ne: 256, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := DeleteRootSecurityDomain(tc.inputAID, tc.inputToken, tc.inputSignature) + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + func TestDeleteKey(t *testing.T) { tests := []struct { name string @@ -1076,6 +1121,54 @@ func TestGetStatus(t *testing.T) { } } +func TestGetStatusCRS(t *testing.T) { + tests := []struct { + name string + inputP1 byte + inputData []byte + inputNext bool + expected apdu.Capdu + }{ + { + name: "GET STATUS CRS Applications", + inputP1: 0x40, + inputData: []byte{0x4F, 0x06, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00}, + inputNext: false, + expected: apdu.Capdu{ + Cla: 0x80, + Ins: 0xF2, + P1: 0x40, + P2: 0x00, + Data: []byte{0x4F, 0x06, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00}, + Ne: 256, + }, + }, + { + name: "GET STATUS CRS next", + inputP1: 0x40, + inputData: []byte{0x4F, 0x06, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00}, + inputNext: true, + expected: apdu.Capdu{ + Cla: 0x80, + Ins: 0xF2, + P1: 0x40, + P2: 0x01, + Data: []byte{0x4F, 0x06, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00}, + Ne: 256, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := GetStatusCRS(tc.inputP1, tc.inputNext, tc.inputData) + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + func TestSetStatus(t *testing.T) { tests := []struct { name string @@ -1171,323 +1264,6 @@ func TestStoreData(t *testing.T) { } } -func TestLoadFileStructure_Bytes(t *testing.T) { - tests := []struct { - name string - input LoadFileStructure - expected []byte - }{ - { - name: "convert to bytes", - input: LoadFileStructure{ - DAPBlocks: []DAPBlock{ - { - SDAID: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - LFDBSignature: []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, - }, - { - SDAID: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, - LFDBSignature: []byte{0xFF, 0xEE, 0xDD, 0xEE, 0xCC, 0xBB}, - }, - }, - LoadFileDataBlock: []byte{0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8}, - ICV: []byte{0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8}, - CipheredLoadFileDataBlock: []byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}, - }, - expected: []byte{ - 0xE2, 0x12, 0x4F, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xC3, 0x06, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, - 0xE2, 0x12, 0x4F, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xC3, 0x06, 0xFF, 0xEE, 0xDD, 0xEE, 0xCC, 0xBB, - 0xC4, 0x08, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, - 0xD3, 0x08, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xD4, 0x08, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}, - }, - } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.input.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestInstallParameters_Bytes(t *testing.T) { - tests := []struct { - name string - input InstallParameters - expected []byte - expectError bool - }{ - { - name: "convert to bytes ", - input: InstallParameters{ - ApplicationSpecificParameters: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, - SystemSpecificParameters: &SystemSpecificParameters{ - NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, - GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, - VolatileReservedMemory: []byte{0x02, 0x00}, - NonVolatileReservedMemory: []byte{0x03, 0x00}, - LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, - LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, - ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, - }, - }, - expected: []byte{ - 0xC9, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, - 0xEF, 0x1C, - 0xC6, 0x02, 0x01, 0x00, - 0xCB, 0x03, 0x04, 0x05, 0x06, - 0xCD, 0x01, 0xFF, - 0xD7, 0x02, 0x02, 0x00, - 0xD8, 0x02, 0x03, 0x00, - 0xDD, 0x03, 0x01, 0x02, 0x03, - 0xCF, 0x01, 0xEE, - }, - expectError: false, - }, - { - name: "empty application specific", - input: InstallParameters{ - ApplicationSpecificParameters: nil, - SystemSpecificParameters: &SystemSpecificParameters{ - NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, - GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, - VolatileReservedMemory: []byte{0x02, 0x00}, - NonVolatileReservedMemory: []byte{0x03, 0x00}, - LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, - LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, - ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, - }, - }, - expected: []byte{ - 0xC9, 0x00, // ApplicationSpecificParameters - 0xEF, 0x1C, // SystemSpecificParameters - 0xC6, 0x02, 0x01, 0x00, // NonVolatileCodeMinimumRequirement - 0xCB, 0x03, 0x04, 0x05, 0x06, // GlobalServiceParameters - 0xCD, 0x01, 0xFF, // LoadFileDataBlockFormatId - 0xD7, 0x02, 0x02, 0x00, // VolatileReservedMemory - 0xD8, 0x02, 0x03, 0x00, // NonVolatileReservedMemory - 0xDD, 0x03, 0x01, 0x02, 0x03, // LoadFileDataBlockParameters - 0xCF, 0x01, 0xEE, // ImplicitSelectionParameter - }, - expectError: false, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.input.Bytes() - fmt.Println(strings.ToUpper(hex.EncodeToString(received))) - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestSystemSpecificParameters_Bytes(t *testing.T) { - tests := []struct { - name string - input SystemSpecificParameters - expected []byte - expectError bool - }{ - { - name: "", - input: SystemSpecificParameters{ - NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, - GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, - VolatileReservedMemory: []byte{0x02, 0x00}, - NonVolatileReservedMemory: []byte{0x03, 0x00}, - LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, - LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, - ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, - PrivacyRequirements: &PrivacyRequirements{ - RequiredPrivacyStatus: nil, - RequiredPrivacyCondition: &RequiredPrivacyCondition{ - Constructed: false, - Value: []byte{0x01, 0x02}, - }, - }, - }, - expected: []byte{ - 0xEF, 0x22, // SystemSpecificParameters - 0xC6, 0x02, 0x01, 0x00, // NonVolatileCodeMinimumRequirement - 0xCB, 0x03, 0x04, 0x05, 0x06, // GlobalServiceParameters - 0xCD, 0x01, 0xFF, // LoadFileDataBlockFormatId - 0xD7, 0x02, 0x02, 0x00, // VolatileReservedMemory - 0xD8, 0x02, 0x03, 0x00, // NonVolatileReservedMemory - 0xDD, 0x03, 0x01, 0x02, 0x03, // LoadFileDataBlockParameters - 0xCF, 0x01, 0xEE, // ImplicitSelectionParameter - 0xE0, 0x04, 0x81, 0x02, 0x01, 0x02, // Privacy Requirements - }, - expectError: false, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.input.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestDapBlock_Bytes(t *testing.T) { - tests := []struct { - name string - dapBlock DAPBlock - expected []byte - }{ - { - name: "bytes", - dapBlock: DAPBlock{ - SDAID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05}, - LFDBSignature: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - }, - expected: []byte{0xE2, 0x11, 0x4F, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, 0xC3, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.dapBlock.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestRequiredPrivacyStatus_Bytes(t *testing.T) { - tests := []struct { - name string - inputRequiredPrivacyStatus RequiredPrivacyStatus - expected []byte - }{ - { - name: "not constructed bytes", - inputRequiredPrivacyStatus: RequiredPrivacyStatus{ - Constructed: false, - Value: []byte{0x00, 0x01, 0x02}, - }, - expected: []byte{0x80, 0x03, 0x00, 0x01, 0x02}, - }, - { - name: "constructed bytes", - inputRequiredPrivacyStatus: RequiredPrivacyStatus{ - Constructed: true, - Value: []byte{0x00, 0x01, 0x02}, - }, - expected: []byte{0xA0, 0x03, 0x00, 0x01, 0x02}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.inputRequiredPrivacyStatus.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestRequiredPrivacyCondition_Bytes(t *testing.T) { - tests := []struct { - name string - inputRequiredPrivacyCondition RequiredPrivacyCondition - expected []byte - }{ - { - name: "not constructed bytes", - inputRequiredPrivacyCondition: RequiredPrivacyCondition{ - Constructed: false, - Value: []byte{0x00, 0x01, 0x02}, - }, - expected: []byte{0x81, 0x03, 0x00, 0x01, 0x02}, - }, - { - name: "constructed bytes", - inputRequiredPrivacyCondition: RequiredPrivacyCondition{ - Constructed: true, - Value: []byte{0x00, 0x01, 0x02}, - }, - expected: []byte{0xA1, 0x03, 0x00, 0x01, 0x02}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.inputRequiredPrivacyCondition.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - -func TestPrivacyRequirements_Bytes(t *testing.T) { - tests := []struct { - name string - inputPrivacyRequirements PrivacyRequirements - expected []byte - }{ - { - name: "multiple status, no condition", - inputPrivacyRequirements: PrivacyRequirements{ - RequiredPrivacyStatus: []RequiredPrivacyStatus{ - { - Constructed: false, - Value: []byte{0xF1, 0xF2}, - }, - { - Constructed: true, - Value: []byte{0xE1, 0xE2}, - }, - }, - RequiredPrivacyCondition: nil, - }, - expected: []byte{0xE0, 0x08, 0x80, 0x02, 0xF1, 0xF2, 0xA0, 0x02, 0xE1, 0xE2}, - }, - { - name: "one status, with condition", - inputPrivacyRequirements: PrivacyRequirements{ - RequiredPrivacyStatus: []RequiredPrivacyStatus{ - { - Constructed: false, - Value: []byte{0xF1}, - }, - }, - RequiredPrivacyCondition: &RequiredPrivacyCondition{ - Constructed: true, - Value: []byte{0xE1, 0xE2}, - }, - }, - expected: []byte{0xE0, 0x07, 0x80, 0x01, 0xF1, 0xA1, 0x02, 0xE1, 0xE2}, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - received := tc.inputPrivacyRequirements.Bytes() - - if !cmp.Equal(tc.expected, received) { - t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) - } - }) - } -} - func TestOnLogicalChannel(t *testing.T) { tests := []struct { name string diff --git a/command/parameters.go b/command/parameters.go new file mode 100644 index 0000000..ae5b617 --- /dev/null +++ b/command/parameters.go @@ -0,0 +1,996 @@ +package command + +import ( + "github.com/skythen/bertlv" + "github.com/skythen/gobalplatform/aid" + "github.com/skythen/gobalplatform/internal/util" + "github.com/skythen/gobalplatform/open" + "github.com/skythen/gobalplatform/tag" +) + +// TagList indicates to the card how to construct the response data for each on-card entity matching the search criteria. +// It can be used as filter criteria in GetStatusCommandDataField. +type TagList struct { + AID bool + ApplicationLifecycleState bool + Privileges bool + ImplicitSelectionParameters bool + ApplicationElfAID bool + ElfVersionNumber bool + ListOfEmAIDs bool + AssociatedSdAID bool + DisplayControlTemplate bool + UniformResourceLocator bool + ApplicationImageTemplate bool + DisplayMessage bool + ApplicationGroupHeadApplication bool + ApplicationGroupAuthorizationList bool + CRELApplicationAIDList bool + PolicyRestrictedApplications bool + ApplicationGroupMembers bool + ApplicationDiscretionaryData bool + ApplicationFamily bool + AssignedProtocolsImplicitSelection bool + InitialContactlessActivationState bool + ContactlessProtocolTypeState bool + ContactlessProtocolParametersProfile bool + RecognitionAlgorithm bool + ContinuousProcessing bool + CommunicationInterfaceAccessParameters bool + ProtocolDataTypeA bool + ProtocolDataTypeB bool + CumulativeGrantedNonVolatileMemory bool + CumulativeGrantedVolatileMemory bool + CumulativeRemainingNonVolatileMemory bool + CumulativeRemainingVolatileMemory bool + ProtocolDataTypeF bool + PrivacySensitiveIndicator bool +} + +// Bytes returns TagList as BER encoded bytes. +func (tl TagList) Bytes() []byte { + outerBuilder := &bertlv.Builder{} + innerBuilder := &bertlv.Builder{} + + if tl.AID { + innerBuilder = innerBuilder.AddRaw(tag.AID) + } + + if tl.ApplicationLifecycleState { + innerBuilder = innerBuilder.AddRaw(tag.LifeCycleState) + } + + if tl.Privileges { + innerBuilder = innerBuilder.AddRaw(tag.Privileges) + } + + if tl.ImplicitSelectionParameters { + innerBuilder = innerBuilder.AddRaw(tag.ImplicitSelectionParameter) + } + + if tl.ApplicationElfAID { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationELFAID) + } + + if tl.ElfVersionNumber { + innerBuilder = innerBuilder.AddRaw(tag.ELFVersion) + } + + if tl.ListOfEmAIDs { + innerBuilder = innerBuilder.AddRaw(tag.EMAID) + } + + if tl.AssociatedSdAID { + innerBuilder = innerBuilder.AddRaw(tag.AssociatedSDAID) + } + + if tl.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.DisplayControlTemplate) + } + + // UniformResourceLocator is a sub-tag of DisplayControlTemplate + if tl.UniformResourceLocator && !tl.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.UniformResourceLocator) + } + + // ApplicationImageTemplate is a sub-tag of DisplayControlTemplate + if tl.ApplicationImageTemplate && !tl.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationImageTemplate) + } + + // DisplayMessage is a sub-tag of DisplayControlTemplate + if tl.DisplayMessage && !tl.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.DisplayMessage) + } + + if tl.ApplicationGroupHeadApplication { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationGroupHeadApplication) + } + + if tl.ApplicationGroupAuthorizationList { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationGroupAuthorizationList) + } + + if tl.CRELApplicationAIDList { + innerBuilder = innerBuilder.AddRaw(tag.CRELApplicationAIDList) + } + + if tl.PolicyRestrictedApplications { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfPolicyRestrictedApplications) + } + + if tl.ApplicationGroupMembers { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationGroupMembers) + } + + if tl.ApplicationDiscretionaryData { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfApplicationDiscretionaryData) + } + + if tl.ApplicationFamily { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfApplicationFamily) + } + + if tl.AssignedProtocolsImplicitSelection { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfAssignedProtocolsImplicitSelection) + } + + if tl.InitialContactlessActivationState { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfInitialContactlessActivationState) + } + + if tl.ContactlessProtocolTypeState { + innerBuilder = innerBuilder.AddRaw(tag.ContactlessProtocolTypeState) + } + + if tl.ContactlessProtocolParametersProfile { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfContactlessProtocolParametersProfile) + } + + if tl.RecognitionAlgorithm { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfRecognitionAlgorithm) + } + + if tl.ContinuousProcessing { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfContinuousProcessing) + } + + if tl.CommunicationInterfaceAccessParameters { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfCommunicationInterfaceAccessParameters) + } + + if tl.ProtocolDataTypeA { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeA) + } + + if tl.ProtocolDataTypeB { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeB) + } + + if tl.CumulativeGrantedNonVolatileMemory { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfCumulativeGrantedNonVolatileMemory) + } + + if tl.CumulativeGrantedVolatileMemory { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfCumulativeGrantedVolatileMemory) + } + + if tl.CumulativeRemainingNonVolatileMemory { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfCumulativeRemainingNonVolatileMemory) + } + + if tl.CumulativeRemainingVolatileMemory { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfCumulativeRemainingVolatileMemory) + } + + if tl.ProtocolDataTypeF { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeF) + } + + if tl.PrivacySensitiveIndicator { + innerBuilder = innerBuilder.AddRaw(tag.PrivacySensitiveIndicator) + } + + outerBuilder = outerBuilder.AddBytes(tag.TagList, innerBuilder.Bytes()) + + return outerBuilder.Bytes() +} + +// GetStatusCommandDataField must include at least aid.AID as search criteria. Other search criteria must be added TLV encoded. +// TagList can be used to indicate how response data shall be constructed. +type GetStatusCommandDataField struct { + AID aid.AID + OtherSearchCriteria []byte // Must be added TLV encoded. + TagList *TagList +} + +// Bytes returns GetStatusCommandDataField as BER-TLV encoded bytes. +func (gsdf GetStatusCommandDataField) Bytes() []byte { + builder := &bertlv.Builder{} + + builder = builder.AddBytes(tag.AID, gsdf.AID) + + if gsdf.OtherSearchCriteria != nil { + builder = builder.AddRaw(gsdf.OtherSearchCriteria) + } + + if gsdf.TagList != nil { + builder = builder.AddRaw(gsdf.TagList.Bytes()) + } + + return builder.Bytes() +} + +// TagListCRS indicates to the card how to construct the response data for each on-card entity matching the search criteria. +// It is only applicable for CRS applications. Can be used as filter criteria in GetStatusCRSCommandDataField. +type TagListCRS struct { + AID bool + ApplicationLifecycleState bool + DisplayControlTemplate bool + UniformResourceLocator bool + ApplicationImageTemplate bool + DisplayMessage bool + ApplicationUpdateCounter bool + SelectionPriority bool + GroupHeadApplication bool + GroupMembersApplication bool + CRELApplicationAIDList bool + PolicyRestrictedApplications bool + ApplicationDiscretionaryData bool + ApplicationFamily bool + DisplayRequiredIndicator bool + ContactlessProtocolTypeState bool + ContinuousProcessing bool + RecognitionAlgorithmForImplicitSelection bool + AssignedProtocolsForImplicitSelection bool + ProtocolDataTypeA bool + ProtocolDataTypeB bool + ProtocolDataTypeF bool + ProtocolDataTypeFSystemCode bool + CommunicationInterfaceAvailability bool + PrivacySensitiveIndicator bool +} + +// Bytes returns TagListCRS as BER-TLV encoded bytes. +func (tlcrs TagListCRS) Bytes() []byte { + outerBuilder := &bertlv.Builder{} + innerBuilder := &bertlv.Builder{} + + if tlcrs.AID { + innerBuilder = innerBuilder.AddRaw(tag.AID) + } + + if tlcrs.ApplicationLifecycleState { + innerBuilder = innerBuilder.AddRaw(tag.LifeCycleState) + } + + if tlcrs.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.DisplayControlTemplate) + } + + // UniformResourceLocator is a sub-tag of DisplayControlTemplate + if tlcrs.UniformResourceLocator && !tlcrs.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.UniformResourceLocator) + } + + // ApplicationImageTemplate is a sub-tag of DisplayControlTemplate + if tlcrs.ApplicationImageTemplate && !tlcrs.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationImageTemplate) + } + + // DisplayMessage is a sub-tag of DisplayControlTemplate + if tlcrs.DisplayMessage && !tlcrs.DisplayControlTemplate { + innerBuilder = innerBuilder.AddRaw(tag.DisplayMessage) + } + + if tlcrs.ApplicationUpdateCounter { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationUpdateCounter) + } + + if tlcrs.SelectionPriority { + innerBuilder = innerBuilder.AddRaw(tag.SelectionPriority) + } + + if tlcrs.GroupHeadApplication { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfHeadApplication) + } + + if tlcrs.GroupMembersApplication { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfGroupMemberApplication) + } + + if tlcrs.CRELApplicationAIDList { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfCRELApplicationAIDList) + } + + if tlcrs.PolicyRestrictedApplications { + innerBuilder = innerBuilder.AddRaw(tag.PolicyRestrictedApplications) + } + + if tlcrs.ApplicationDiscretionaryData { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationDiscretionaryData) + } + + if tlcrs.ApplicationFamily { + innerBuilder = innerBuilder.AddRaw(tag.ApplicationFamily) + } + + if tlcrs.DisplayRequiredIndicator { + innerBuilder = innerBuilder.AddRaw(tag.DisplayRequiredIndicator) + } + + if tlcrs.ContactlessProtocolTypeState { + innerBuilder = innerBuilder.AddRaw(tag.ContactlessProtocolTypeState) + } + + if tlcrs.ContinuousProcessing { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfContinuousProcessing) + } + + if tlcrs.RecognitionAlgorithmForImplicitSelection { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSRecognitionAlgorithmForImplicitSelection) + } + + if tlcrs.AssignedProtocolsForImplicitSelection { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSAssignedProtocolsForImplicitSelection) + } + + if tlcrs.ProtocolDataTypeA { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeA) + } + + if tlcrs.ProtocolDataTypeB { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeB) + } + + if tlcrs.ProtocolDataTypeF { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusOfProtocolDataTypeF) + } + + if tlcrs.ProtocolDataTypeFSystemCode { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfProtocolDataTypeFSystemCode) + } + + if tlcrs.CommunicationInterfaceAvailability { + innerBuilder = innerBuilder.AddRaw(tag.GetStatusCRSOfCommunicationInterfaceAvailability) + } + + if tlcrs.PrivacySensitiveIndicator { + innerBuilder = innerBuilder.AddRaw(tag.PrivacySensitiveIndicator) + } + + outerBuilder = outerBuilder.AddBytes(tag.TagList, innerBuilder.Bytes()) + + return outerBuilder.Bytes() +} + +// GetStatusCRSCommandDataField must include at least aid.AID as search criteria. Other search criteria must be added TLV encoded. +// TagListCRS can be used to indicate how response data shall be constructed. +type GetStatusCRSCommandDataField struct { + AID aid.AID + OtherSearchCriteria []byte // must be added TLV encoded + TagListCRS *TagListCRS +} + +// Bytes returns GetStatusCommandDataField as BER-TLV encoded bytes. +func (cdf GetStatusCRSCommandDataField) Bytes() []byte { + builder := &bertlv.Builder{} + + builder = builder.AddBytes(tag.AID, cdf.AID) + + if cdf.OtherSearchCriteria != nil { + builder = builder.AddRaw(cdf.OtherSearchCriteria) + } + + if cdf.TagListCRS != nil { + builder = builder.AddRaw(cdf.TagListCRS.Bytes()) + } + + return builder.Bytes() +} + +// LoadFileStructure represents a GlobalPlatform Load File that can be loaded to a SE with a LOAD command. +type LoadFileStructure struct { + DAPBlocks []DAPBlock // Blocks to be verified by a Security Domain with the DAP Verification or Mandated DAP Verification privilege. + LoadFileDataBlock []byte // Plaintext platform specific code of a Load File - shall not be present when CipheredLoadFileDataBlock is present. + CipheredLoadFileDataBlock []byte // Ciphered platform specific code of a Load File that can be decrypted by a Security Domain with the Ciphered Load File Data Block privilege - shall not be present when LoadFileDataBlock is present + ICV []byte // May be present if CipheredLoadFileDataBlock is present and has been encrypted with an ICV other than the zero ICV. +} + +// Bytes returns LoadFileStructure as BER-TLV encoded bytes. +func (lfs LoadFileStructure) Bytes() []byte { + builder := &bertlv.Builder{} + + for _, dapBlock := range lfs.DAPBlocks { + d := dapBlock.Bytes() + builder = builder.AddRaw(d) + } + + if lfs.LoadFileDataBlock != nil { + builder = builder.AddBytes(tag.LoadFileDataBlock, lfs.LoadFileDataBlock) + } + + if lfs.ICV != nil { + builder = builder.AddBytes(tag.ICV, lfs.ICV) + } + + if lfs.CipheredLoadFileDataBlock != nil { + builder = builder.AddBytes(tag.CipheredLoadFileDataBlock, lfs.CipheredLoadFileDataBlock) + } + + return builder.Bytes() +} + +// DAPBlock represents a Data Authentication Pattern block (Load File Data Block Signature) and contains the AID of the Security Domain that shall verify +// this block as well as the signature over a Load File Data Block that shall be loaded. +type DAPBlock struct { + SDAID aid.AID // AID of the Security Domain with the (Mandated) DAP Verification privilege. + LFDBSignature []byte // Signature over the Load File Data Block. +} + +// Bytes returns DAPBlock as BER-TLV bytes. +func (dapBlock DAPBlock) Bytes() []byte { + return bertlv.Builder{}.AddBytes(tag.DAPBlock, + bertlv.Builder{}. + AddBytes(tag.AID, dapBlock.SDAID). + AddBytes(tag.LoadFileDataBlockSignature, dapBlock.LFDBSignature). + Bytes()). + Bytes() +} + +// CRTDigitalSignature is the Cryptographic Reference Template for Digital Signature and is especially recommended to use with SCP10. +type CRTDigitalSignature struct { + SDIdentificationNumber []byte // Identification Number of the Security Domain with the Token Verification privilege. + SDImageNumber []byte // Image Number of the Security Domain with the Token Verification privilege. + ApplicationProviderIdentifier []byte // Application Provider identifier. + TokenIdentifier []byte // Token identifier/number (digital signature counter). +} + +// Bytes returns CRTDigitalSignature as BER-TLV encoded bytes. +func (crt CRTDigitalSignature) Bytes() []byte { + builder := &bertlv.Builder{} + + if crt.SDIdentificationNumber != nil { + builder = builder.AddBytes(tag.SDIdentificationNumber, crt.SDIdentificationNumber) + } + + if crt.SDImageNumber != nil { + builder = builder.AddBytes(tag.SDImageNumber, crt.SDImageNumber) + } + + if crt.ApplicationProviderIdentifier != nil { + builder = builder.AddBytes(tag.ApplicationProviderIdentifier, crt.ApplicationProviderIdentifier) + } + + if crt.TokenIdentifier != nil { + builder = builder.AddBytes(tag.TokenIdentification, crt.TokenIdentifier) + } + + return bertlv.Builder{}.AddBytes(tag.ControlReferenceTemplateForDigitalSignature, builder.Bytes()).Bytes() +} + +// PrivacyRequirements may be specified for an Application using tag 'E0' as part of System Specific Install Parameters. +type PrivacyRequirements struct { + RequiredPrivacyStatus []RequiredPrivacyStatus // 0 to N occurrences allowed + RequiredPrivacyCondition *RequiredPrivacyCondition // structure is not specified by GPC Privacy Framework, 0 to 1 occurrences allowed +} + +// RequiredPrivacyStatus is the Privacy Status that must have been reached in the execution of the Global Privacy Protocol +// and is maintained by the GPP service. +type RequiredPrivacyStatus struct { + Constructed bool // indicates whether Value consists of constructed data objects or not + Value []byte // structure is not specified by GPC Privacy Framework +} + +// Bytes returns RequiredPrivacyStatus as BER-TLV encoded bytes. +func (req RequiredPrivacyStatus) Bytes() []byte { + builder := &bertlv.Builder{} + + if req.Constructed { + builder = builder.AddBytes(tag.RequiredPrivacyStatusConstructed, req.Value) + } else { + builder = builder.AddBytes(tag.RequiredPrivacyStatus, req.Value) + } + + return builder.Bytes() +} + +// RequiredPrivacyCondition defines a condition for an application about the Current Privacy Status before the OPEX allows the selection of that application. +type RequiredPrivacyCondition struct { + Constructed bool // indicates whether Value consists of constructed data objects or not + Value []byte // structure is not specified by GPC Privacy Framework +} + +// Bytes returns RequiredPrivacyCondition as BER-TLV encoded bytes. +func (req RequiredPrivacyCondition) Bytes() []byte { + builder := &bertlv.Builder{} + + if req.Constructed { + builder = builder.AddBytes(tag.RequiredPrivacyConditionConstructed, req.Value) + } else { + builder = builder.AddBytes(tag.RequiredPrivacyCondition, req.Value) + } + + return builder.Bytes() +} + +// Bytes returns PrivacyRequirements as BER-TLV encoded bytes. +func (req PrivacyRequirements) Bytes() []byte { + outerBuilder := &bertlv.Builder{} + innerBuilder := &bertlv.Builder{} + + for _, ps := range req.RequiredPrivacyStatus { + innerBuilder = innerBuilder.AddRaw(ps.Bytes()) + } + + if req.RequiredPrivacyCondition != nil { + innerBuilder = innerBuilder.AddRaw(req.RequiredPrivacyCondition.Bytes()) + } + + return outerBuilder.AddBytes(tag.PrivacyRequirements, innerBuilder.Bytes()).Bytes() +} + +// Protocols for Implicit Selection +const ( + ImplicitSelectionProtocolTypeA byte = 0x81 // Protocol Type A + ImplicitSelectionProtocolTypeB byte = 0x82 // Protocol Type B + ImplicitSelectionProtocolTypeF byte = 0x84 // Protocol Type F +) + +// Initial Contactless Activation State +const ( + InitialDeactivated byte = 0x00 // OPEN shall not attempt to activate the application. + InitialActivated byte = 0x01 // OPEN shall attempt to activate the application when transitioning to SELECTABLE state for the first time or unlocking. +) + +// Communication Interface Access +const ( + ContactBasedCommunication byte = 0x80 // Contact-based communication (e.g. ISO/IEC 7816) is supported. + ProximityBasedCommunication byte = 0x40 // Proximity-based communication (e.g. ISO/IEC 14443) is supported. + ContactAndProximityBasedCommunication byte = 0xC0 // Contact-based and Proximity-based communication are supported. +) + +// CommunicationInterfaceAccessParameters are used to configure interface accessibility. +type CommunicationInterfaceAccessParameters struct { + CommunicationInterfaceAccessRestriction util.NullByte // Set of communication interfaces that an application may use. Security Domain only. + CommunicationInterfaceAccessDefault util.NullByte // Accessibility configuration of an application which is installed under the hierarchy of the SD. Security Domain only. + CommunicationInterfaceAccessPerInstance util.NullByte // Defines the accessibility configuration of the application. +} + +// Bytes returns CommunicationInterfaceAccessParameters as BER-TLV encoded bytes. +func (ciap CommunicationInterfaceAccessParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if ciap.CommunicationInterfaceAccessRestriction.Valid { + builder = builder.AddByte(tag.CommunicationInterfaceAccessRestriction, ciap.CommunicationInterfaceAccessRestriction.Byte) + } + + if ciap.CommunicationInterfaceAccessDefault.Valid { + builder = builder.AddByte(tag.CommunicationInterfaceAccessDefault, ciap.CommunicationInterfaceAccessDefault.Byte) + } + + if ciap.CommunicationInterfaceAccessPerInstance.Valid { + builder = builder.AddByte(tag.CommunicationInterfaceAccessPerInstance, ciap.CommunicationInterfaceAccessPerInstance.Byte) + } + + return builder.Bytes() +} + +// ProtocolData is the value part of the Protocol Data TLV for type A, B or F. +type ProtocolData struct { + ProtocolParameterData []byte + ProtocolParameterMandatoryMask []byte +} + +// Bytes returns ProtocolData as BER-TLV encoded bytes. +func (pd ProtocolData) Bytes() []byte { + builder := &bertlv.Builder{} + + if pd.ProtocolParameterData != nil { + builder = builder.AddBytes(tag.ProtocolParameterData, pd.ProtocolParameterData) + } + + if pd.ProtocolParameterMandatoryMask != nil { + builder = builder.AddBytes(tag.ProtocolParameterMandatoryMask, pd.ProtocolParameterMandatoryMask) + } + + return builder.Bytes() +} + +// Contactless Protocol Type State +const ( + ContactlessProtocolTypeA byte = 0x80 // Contactless Protocol Type A RF activated (Card Emulation Mode) - Type B,F deactivated. + ContactlessProtocolTypeB byte = 0x40 // Contactless Protocol Type B RF activated (Card Emulation Mode) - Type A,F deactivated. + ContactlessProtocolTypeF byte = 0x20 // Contactless Protocol Type F RF activated (Card Emulation Mode) - Type A,B deactivated. + ContactlessProtocolTypeAB byte = 0xC0 // Contactless Protocol Type A,B RF activated (Card Emulation Mode) - Type F deactivated. + ContactlessProtocolTypeAF byte = 0xA0 // Contactless Protocol Type A,F RF activated (Card Emulation Mode) - Type B deactivated. + ContactlessProtocolTypeBF byte = 0x60 // Contactless Protocol Type B,F RF activated (Card Emulation Mode) - Type A deactivated. +) + +// ContactlessProtocolParameters for managing an application on the contactless interface. +type ContactlessProtocolParameters struct { + AssignedProtocolsImplicitSelection []byte // Protocols of type A, B or F that are assigned for the application. + InitialContactlessActivationState util.NullByte // Initial Contactless Activation State when an application is installed and made selectable. + ContactlessProtocolParametersProfile []byte // Profiles that are used to facilitate initialization of the Contactless Application. + RecognitionAlgorithm []byte // Provides the capability of the contactless interface to identify and select a legacy Contactless Application not supporting the SELECT by AID command. + ContinuousProcessing []byte // Continuous Processing for applications and the OPEN. + CommunicationInterfaceAccessParameters *CommunicationInterfaceAccessParameters // Communication Interface Access Configuration + ProtocolDataTypeA *ProtocolData // Protocol Data Type A TLV + ProtocolDataTypeB *ProtocolData // Protocol Data Type B TLV + ProtocolDataTypeF *ProtocolData // Protocol Data Type F TLV + ContactlessProtocolTypeState util.NullByte // Used to set the new Contactless Protocol Type State of the contactless interface. +} + +// Bytes returns ContactlessProtocolParameters as BER-TLV encoded bytes. +func (cpp ContactlessProtocolParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if cpp.AssignedProtocolsImplicitSelection != nil { + builder = builder.AddRaw(tag.AssignedProtocolsImplicitSelection) + + // add length of protocol tags + builder = builder.AddRaw([]byte{byte(len(cpp.AssignedProtocolsImplicitSelection))}) + + for _, protocol := range cpp.AssignedProtocolsImplicitSelection { + builder = builder.AddRaw([]byte{protocol}) + } + } + + if cpp.InitialContactlessActivationState.Valid { + builder = builder.AddByte(tag.InitialContactlessActivationState, cpp.InitialContactlessActivationState.Byte) + } + + if cpp.ContactlessProtocolParametersProfile != nil { + builder = builder.AddBytes(tag.ContactlessProtocolParametersProfile, cpp.ContactlessProtocolParametersProfile) + } + + if cpp.RecognitionAlgorithm != nil { + builder = builder.AddBytes(tag.RecognitionAlgorithm, cpp.RecognitionAlgorithm) + } + + if cpp.ContinuousProcessing != nil { + builder = builder.AddBytes(tag.ContinuousProcessing, cpp.ContinuousProcessing) + } + + if cpp.CommunicationInterfaceAccessParameters != nil { + builder = builder.AddBytes(tag.CommunicationInterfaceAccessParameters, cpp.CommunicationInterfaceAccessParameters.Bytes()) + } + + if cpp.ProtocolDataTypeA != nil { + builder = builder.AddBytes(tag.ProtocolDataTypeA, cpp.ProtocolDataTypeA.Bytes()) + } + + if cpp.ProtocolDataTypeB != nil { + builder = builder.AddBytes(tag.ProtocolDataTypeB, cpp.ProtocolDataTypeB.Bytes()) + } + + if cpp.ProtocolDataTypeF != nil { + builder = builder.AddBytes(tag.ProtocolDataTypeF, cpp.ProtocolDataTypeF.Bytes()) + } + + if cpp.ContactlessProtocolTypeState.Valid { + builder = builder.AddByte(tag.ContactlessProtocolTypeState, cpp.ContactlessProtocolTypeState.Byte) + } + + return builder.Bytes() +} + +// Display Required Indicator +const ( + DisplayRequired byte = 0x00 // Application requires a display + DisplayNotRequired byte = 0x01 // Application does not require a display +) + +// UserInteractionParameters provide parameters for user interaction. +type UserInteractionParameters struct { + DisplayControlTemplate []byte // Used to manage an off-card GUI by providing information for a logo, a URL or any related display information. + HeadApplication aid.AID // Allows an application to request to be member of a group. + AddToGroupAuthorizationList []aid.AID // Establishes the target application as a head application by creating its Group Authorization List. + RemoveFromGroupAuthorizationList []aid.AID // Used to remove one or more AIDs from Group Authorization List. + AddToCRELList []aid.AID // List of AIDs of CREL applications that shall be notified by the OPEN upon any change in the GPRegistryEntry of the target application. + RemoveFromCRELList []aid.AID // List of AIDs of CREL applications that shall be removed from the notification list of an application. + PolicyRestrictedApplications []aid.AID // List of AIDs of applications that should not be activated on the contactless interface at the same time as the application that has this TLV in its registry. + ApplicationDiscretionaryData []byte // Is accessible to the CRS application and CREL applications, if any, for proprietary usage. + ApplicationFamily util.NullByte // May be used to group together the applications for a similar process. + DisplayRequiredIndicator util.NullByte // Indicates whether the application is able to perform a contactless transaction even when the display is not available. +} + +// Bytes returns UserInteractionParameters as BER-TLV encoded bytes. +func (uip UserInteractionParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if uip.DisplayControlTemplate != nil { + builder = builder.AddBytes(tag.DisplayControlTemplate, uip.DisplayControlTemplate) + } + + if uip.HeadApplication != nil { + aidBuilder := &bertlv.Builder{} + + aidBuilder = aidBuilder.AddBytes(tag.AID, uip.HeadApplication) + + builder = builder.AddBytes(tag.HeadApplication, aidBuilder.Bytes()) + } + + if uip.AddToGroupAuthorizationList != nil { + groupAuthorizationListBuilder := &bertlv.Builder{} + + for _, aidToAdd := range uip.AddToGroupAuthorizationList { + groupAuthorizationListBuilder = groupAuthorizationListBuilder.AddBytes(tag.AID, aidToAdd) + } + + builder = builder.AddBytes(tag.AddToGroupAuthorizationList, groupAuthorizationListBuilder.Bytes()) + } + + if uip.RemoveFromGroupAuthorizationList != nil { + groupAuthorizationListBuilder := &bertlv.Builder{} + + for _, aidToRemove := range uip.RemoveFromGroupAuthorizationList { + groupAuthorizationListBuilder = groupAuthorizationListBuilder.AddBytes(tag.AID, aidToRemove) + } + + builder = builder.AddBytes(tag.RemoveFromGroupAuthorizationList, groupAuthorizationListBuilder.Bytes()) + } + + if uip.AddToCRELList != nil { + crelListBuilder := &bertlv.Builder{} + + for _, aidToAdd := range uip.AddToCRELList { + crelListBuilder = crelListBuilder.AddBytes(tag.AID, aidToAdd) + } + + builder = builder.AddBytes(tag.AddToCRELList, crelListBuilder.Bytes()) + } + + if uip.RemoveFromCRELList != nil { + crelListBuilder := &bertlv.Builder{} + + for _, aidToRemove := range uip.RemoveFromCRELList { + crelListBuilder = crelListBuilder.AddBytes(tag.AID, aidToRemove) + } + + builder = builder.AddBytes(tag.RemoveFromCRELList, crelListBuilder.Bytes()) + } + + if uip.PolicyRestrictedApplications != nil { + policyRestrictedBuilder := &bertlv.Builder{} + + for _, aidToAdd := range uip.PolicyRestrictedApplications { + policyRestrictedBuilder = policyRestrictedBuilder.AddBytes(tag.AID, aidToAdd) + } + + builder = builder.AddBytes(tag.PolicyRestrictedApplications, policyRestrictedBuilder.Bytes()) + } + + if uip.ApplicationDiscretionaryData != nil { + builder = builder.AddBytes(tag.ApplicationDiscretionaryData, uip.ApplicationDiscretionaryData) + } + + if uip.ApplicationFamily.Valid { + builder = builder.AddByte(tag.ApplicationFamily, uip.ApplicationFamily.Byte) + } + + if uip.DisplayRequiredIndicator.Valid { + builder = builder.AddByte(tag.DisplayRequiredIndicator, uip.DisplayRequiredIndicator.Byte) + } + + return builder.Bytes() +} + +// Privacy Sensitive Indicator +const ( + NotPrivacySensitive byte = 0x00 // Application is not Privacy-Sensitive + PrivacySensitive byte = 0x01 // Application is Privacy-Sensitive +) + +// SystemSpecificParameters provide additional parameters that can be used for an INSTALL command, although their presence might be ignored. +// If both tag 'C6' and 'C8' are present and the implementation does not make any distinction between Non-Volatile Code and Non-Volatile Data Memory +// then the required minimum shall be the sum of both values. +type SystemSpecificParameters struct { + NonVolatileCodeMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 + VolatileMemoryMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 + NonVolatileMemoryMinimumRequirement []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 + VolatileReservedMemory []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 + NonVolatileReservedMemory []byte // 2-byte integer for values up to 32767 and a 4-byte integer above 32767 + GlobalServiceParameters []byte // One or more two-byte service parameters. + TS102226SpecificParameters []byte // UICC specific parameters. + LoadFileDataBlockFormatID util.NullByte // Proprietary Load File Data Block format ID. + LoadFileDataBlockParameters []byte // Proprietary Load File Data Block parameters. + RestrictParameter *open.Restrict // Lists functionalities that shall be disabled. + ImplicitSelectionParameter util.NullByte // Implicit selection parameter. + PrivacyRequirements *PrivacyRequirements // Privacy Requirements for an application. + ContactlessProtocolParameters *ContactlessProtocolParameters // Contains tags for managing an application on the contactless interface. + UserInteractionParameters *UserInteractionParameters // Parameters that are relevant for end-user interaction. + ETSIParameters []byte // Assigned to ETSI. + CumulativeGrantedVolatileMemory []byte // Specifies the exact amount of volatile memory granted to Security Domain, to its applications and its entire sub-hierarchy. + CumulativeGrantedNonVolatileMemory []byte // Specifies the exact amount of non-volatile memory granted to Security Domain, to its applications and its entire sub-hierarchy. + PrivacySensitiveIndicator util.NullByte // Indicates whether the application is privacy-sensitive or not. +} + +// Bytes returns SystemSpecificParameters as BER-TLV encoded bytes. +func (ssp SystemSpecificParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if ssp.NonVolatileCodeMinimumRequirement != nil { + builder = builder.AddBytes(tag.NonVolatileCodeMinimumRequirement, ssp.NonVolatileCodeMinimumRequirement) + } + + if ssp.VolatileMemoryMinimumRequirement != nil { + builder = builder.AddBytes(tag.VolatileMemoryQuota, ssp.VolatileMemoryMinimumRequirement) + } + + if ssp.NonVolatileMemoryMinimumRequirement != nil { + builder = builder.AddBytes(tag.NonVolatileMemoryQuota, ssp.NonVolatileMemoryMinimumRequirement) + } + + if ssp.GlobalServiceParameters != nil { + builder = builder.AddBytes(tag.GlobalServiceParameters, ssp.GlobalServiceParameters) + } + + if ssp.LoadFileDataBlockFormatID.Valid { + builder = builder.AddByte(tag.LoadFileDataBlockFormatID, ssp.LoadFileDataBlockFormatID.Byte) + } + + if ssp.VolatileReservedMemory != nil { + builder = builder.AddBytes(tag.VolatileReservedMemory, ssp.VolatileReservedMemory) + } + + if ssp.NonVolatileReservedMemory != nil { + builder = builder.AddBytes(tag.NonVolatileReservedMemory, ssp.NonVolatileReservedMemory) + } + + if ssp.RestrictParameter != nil { + builder = builder.AddByte(tag.Restrict, ssp.RestrictParameter.Byte()) + } + + if ssp.LoadFileDataBlockParameters != nil { + builder = builder.AddBytes(tag.LoadFileDataBlockParameter, ssp.LoadFileDataBlockParameters) + } + + if ssp.TS102226SpecificParameters != nil { + builder = builder.AddBytes(tag.TS102226SpecificParameters, ssp.TS102226SpecificParameters) + } + + if ssp.ImplicitSelectionParameter.Valid { + builder = builder.AddByte(tag.ImplicitSelectionParameter, ssp.ImplicitSelectionParameter.Byte) + } + + if ssp.PrivacyRequirements != nil { + builder = builder.AddRaw(ssp.PrivacyRequirements.Bytes()) + } + + if ssp.ContactlessProtocolParameters != nil { + builder = builder.AddBytes(tag.ContactlessProtocolParameters, ssp.ContactlessProtocolParameters.Bytes()) + } + + if ssp.UserInteractionParameters != nil { + builder = builder.AddBytes(tag.UserInteractionParameters, ssp.UserInteractionParameters.Bytes()) + } + + if ssp.ETSIParameters != nil { + builder = builder.AddBytes(tag.ETSIAssigned, ssp.ETSIParameters) + } + + if ssp.CumulativeGrantedVolatileMemory != nil { + builder = builder.AddBytes(tag.CumulativeGrantedVolatileMemory, ssp.CumulativeGrantedVolatileMemory) + } + + if ssp.CumulativeGrantedNonVolatileMemory != nil { + builder = builder.AddBytes(tag.CumulativeGrantedNonVolatileMemory, ssp.CumulativeGrantedNonVolatileMemory) + } + + if ssp.PrivacySensitiveIndicator.Valid { + builder = builder.AddByte(tag.PrivacySensitiveIndicator, ssp.PrivacySensitiveIndicator.Byte) + } + + return bertlv.Builder{}.AddBytes(tag.SystemSpecificParameter, builder.Bytes()).Bytes() +} + +// LoadParameters provide additional parameters that can be used for an INSTALL [for load] command. +type LoadParameters struct { + SystemSpecificParameters *SystemSpecificParameters + ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature +} + +// Bytes returns LoadParameters as BER-TLV encoded bytes. +func (lp LoadParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if lp.SystemSpecificParameters != nil { + builder = builder.AddRaw(lp.SystemSpecificParameters.Bytes()) + } + + if lp.ControlReferenceTemplateForDigitalSignature != nil { + builder = builder.AddRaw(lp.ControlReferenceTemplateForDigitalSignature.Bytes()) + } + + return builder.Bytes() +} + +// InstallParameters provide additional parameters that can be used for commands containing the INSTALL [for installation] step. +type InstallParameters struct { + ApplicationSpecificParameters []byte + SystemSpecificParameters *SystemSpecificParameters + TS102226SpecificTemplate []byte + ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature +} + +// Bytes returns InstallParameters as BER-TLV encoded bytes. +func (ip InstallParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if len(ip.ApplicationSpecificParameters) == 0 { + builder = builder.AddEmpty(tag.ApplicationSpecificParameters) + } else { + builder = builder.AddBytes(tag.ApplicationSpecificParameters, ip.ApplicationSpecificParameters) + } + + if ip.SystemSpecificParameters != nil { + builder = builder.AddRaw(ip.SystemSpecificParameters.Bytes()) + } + + if ip.TS102226SpecificTemplate != nil { + builder = builder.AddBytes(tag.TS102226SpecificTemplate, ip.TS102226SpecificTemplate) + } + + if ip.ControlReferenceTemplateForDigitalSignature != nil { + builder = builder.AddRaw(ip.ControlReferenceTemplateForDigitalSignature.Bytes()) + } + + return builder.Bytes() +} + +// MakeSelectableParameters provides additional parameters that can be used for an INSTALL [for make selectable] command. +type MakeSelectableParameters struct { + SystemSpecificParameters *SystemSpecificParameters + ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature +} + +// Bytes returns MakeSelectableParameters as BER-TLV encoded bytes. +func (mp MakeSelectableParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if mp.SystemSpecificParameters != nil { + builder = builder.AddRaw(mp.SystemSpecificParameters.Bytes()) + } + + if mp.ControlReferenceTemplateForDigitalSignature != nil { + builder = builder.AddRaw(mp.ControlReferenceTemplateForDigitalSignature.Bytes()) + } + + return builder.Bytes() +} + +// ExtraditionParameters provides additional parameters that can be used for an INSTALL [for extradition] command. +type ExtraditionParameters struct { + ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature +} + +// Bytes returns ExtraditionParameters as BER-TLV encoded bytes. +func (ep ExtraditionParameters) Bytes() []byte { + if ep.ControlReferenceTemplateForDigitalSignature != nil { + return bertlv.Builder{}.AddRaw(ep.ControlReferenceTemplateForDigitalSignature.Bytes()).Bytes() + } + + return nil +} + +// RegistryUpdateParameters provides additional parameters that can be used for an INSTALL [for registry update] command. +type RegistryUpdateParameters struct { + SystemSpecificParameters *SystemSpecificParameters + ControlReferenceTemplateForDigitalSignature *CRTDigitalSignature +} + +// Bytes returns RegistryUpdateParameters as BER-TLV encoded bytes. +func (rup RegistryUpdateParameters) Bytes() []byte { + builder := &bertlv.Builder{} + + if rup.SystemSpecificParameters != nil { + builder = builder.AddRaw(rup.SystemSpecificParameters.Bytes()) + } + + if rup.ControlReferenceTemplateForDigitalSignature != nil { + builder = builder.AddRaw(rup.ControlReferenceTemplateForDigitalSignature.Bytes()) + } + + return builder.Bytes() +} diff --git a/command/parameters_test.go b/command/parameters_test.go new file mode 100644 index 0000000..112a00f --- /dev/null +++ b/command/parameters_test.go @@ -0,0 +1,865 @@ +package command + +import ( + "encoding/hex" + "fmt" + "github.com/google/go-cmp/cmp" + "github.com/skythen/gobalplatform/aid" + "github.com/skythen/gobalplatform/internal/util" + "strings" + "testing" +) + +func TestLoadFileStructure_Bytes(t *testing.T) { + tests := []struct { + name string + input LoadFileStructure + expected []byte + }{ + { + name: "convert to bytes", + input: LoadFileStructure{ + DAPBlocks: []DAPBlock{ + { + SDAID: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + LFDBSignature: []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, + }, + { + SDAID: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}, + LFDBSignature: []byte{0xFF, 0xEE, 0xDD, 0xEE, 0xCC, 0xBB}, + }, + }, + LoadFileDataBlock: []byte{0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8}, + ICV: []byte{0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8}, + CipheredLoadFileDataBlock: []byte{0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}, + }, + expected: []byte{ + 0xE2, 0x12, 0x4F, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xC3, 0x06, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, + 0xE2, 0x12, 0x4F, 0x08, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xC3, 0x06, 0xFF, 0xEE, 0xDD, 0xEE, 0xCC, 0xBB, + 0xC4, 0x08, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, + 0xD3, 0x08, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xD4, 0x08, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.input.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestDapBlock_Bytes(t *testing.T) { + tests := []struct { + name string + dapBlock DAPBlock + expected []byte + }{ + { + name: "bytes", + dapBlock: DAPBlock{ + SDAID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05}, + LFDBSignature: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + }, + expected: []byte{0xE2, 0x11, 0x4F, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, 0xC3, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.dapBlock.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestInstallParameters_Bytes(t *testing.T) { + tests := []struct { + name string + input InstallParameters + expected []byte + expectError bool + }{ + { + name: "convert to bytes ", + input: InstallParameters{ + ApplicationSpecificParameters: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, + SystemSpecificParameters: &SystemSpecificParameters{ + NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, + GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, + VolatileReservedMemory: []byte{0x02, 0x00}, + NonVolatileReservedMemory: []byte{0x03, 0x00}, + LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, + LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, + ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, + }, + }, + expected: []byte{ + 0xC9, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, + 0xEF, 0x1C, + 0xC6, 0x02, 0x01, 0x00, + 0xCB, 0x03, 0x04, 0x05, 0x06, + 0xCD, 0x01, 0xFF, + 0xD7, 0x02, 0x02, 0x00, + 0xD8, 0x02, 0x03, 0x00, + 0xDD, 0x03, 0x01, 0x02, 0x03, + 0xCF, 0x01, 0xEE, + }, + expectError: false, + }, + { + name: "empty application specific", + input: InstallParameters{ + ApplicationSpecificParameters: nil, + SystemSpecificParameters: &SystemSpecificParameters{ + NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, + GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, + VolatileReservedMemory: []byte{0x02, 0x00}, + NonVolatileReservedMemory: []byte{0x03, 0x00}, + LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, + LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, + ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, + }, + }, + expected: []byte{ + 0xC9, 0x00, // ApplicationSpecificParameters + 0xEF, 0x1C, // SystemSpecificParameters + 0xC6, 0x02, 0x01, 0x00, // NonVolatileCodeMinimumRequirement + 0xCB, 0x03, 0x04, 0x05, 0x06, // GlobalServiceParameters + 0xCD, 0x01, 0xFF, // LoadFileDataBlockFormatId + 0xD7, 0x02, 0x02, 0x00, // VolatileReservedMemory + 0xD8, 0x02, 0x03, 0x00, // NonVolatileReservedMemory + 0xDD, 0x03, 0x01, 0x02, 0x03, // LoadFileDataBlockParameters + 0xCF, 0x01, 0xEE, // ImplicitSelectionParameter + }, + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.input.Bytes() + fmt.Println(strings.ToUpper(hex.EncodeToString(received))) + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestSystemSpecificParameters_Bytes(t *testing.T) { + tests := []struct { + name string + input SystemSpecificParameters + expected []byte + expectError bool + }{ + { + name: "SystemSpecificParameters with two byte length encoding", + input: SystemSpecificParameters{ + NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, + GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, + VolatileReservedMemory: []byte{0x02, 0x00}, + NonVolatileReservedMemory: []byte{0x03, 0x00}, + LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, + LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, + ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, + PrivacyRequirements: &PrivacyRequirements{ + RequiredPrivacyStatus: nil, + RequiredPrivacyCondition: &RequiredPrivacyCondition{ + Constructed: false, + Value: []byte{0x01, 0x02}, + }, + }, + ContactlessProtocolParameters: &ContactlessProtocolParameters{ + AssignedProtocolsImplicitSelection: []byte{ImplicitSelectionProtocolTypeF}, + InitialContactlessActivationState: util.NullByte{Byte: InitialActivated, Valid: true}, + ContactlessProtocolParametersProfile: []byte{0xA1, 0x03, 0x81, 0x01, 0x01}, + RecognitionAlgorithm: []byte{0x01, 0x01, 0x02, 0x03, 0x04, 0x05}, + ContinuousProcessing: []byte{0x02}, + CommunicationInterfaceAccessParameters: &CommunicationInterfaceAccessParameters{CommunicationInterfaceAccessPerInstance: util.NullByte{Byte: ContactBasedCommunication, Valid: true}}, + ProtocolDataTypeF: &ProtocolData{ + ProtocolParameterData: []byte{0x80, 0x04, 0x01, 0x02, 0x03, 0x04}, + ProtocolParameterMandatoryMask: []byte{0x80, 0x01, 0x00}, + }, + ContactlessProtocolTypeState: util.NullByte{Byte: ContactlessProtocolTypeF, Valid: true}, + }, + UserInteractionParameters: &UserInteractionParameters{ + DisplayControlTemplate: []byte{0x5F, 0x45, 0x01}, + HeadApplication: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + AddToGroupAuthorizationList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, + }, + RemoveFromGroupAuthorizationList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + AddToCRELList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + RemoveFromCRELList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + PolicyRestrictedApplications: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + ApplicationDiscretionaryData: []byte{0x01, 0x01, 0x01}, + ApplicationFamily: util.NullByte{Byte: 0x01, Valid: true}, + DisplayRequiredIndicator: util.NullByte{Byte: DisplayRequired, Valid: true}, + }, + ETSIParameters: []byte{0x04, 0x05, 0x06}, + CumulativeGrantedVolatileMemory: []byte{0x0A, 0x0B}, + CumulativeGrantedNonVolatileMemory: []byte{0x0A, 0x0B}, + PrivacySensitiveIndicator: util.NullByte{Byte: NotPrivacySensitive, Valid: true}, + }, + expected: []byte{ + 0xEF, 0x81, 0xBB, // SystemSpecificParameters + 0xC6, 0x02, 0x01, 0x00, // NonVolatileCodeMinimumRequirement + 0xCB, 0x03, 0x04, 0x05, 0x06, // GlobalServiceParameters + 0xCD, 0x01, 0xFF, // LoadFileDataBlockFormatId + 0xD7, 0x02, 0x02, 0x00, // VolatileReservedMemory + 0xD8, 0x02, 0x03, 0x00, // NonVolatileReservedMemory + 0xDD, 0x03, 0x01, 0x02, 0x03, // LoadFileDataBlockParameters + 0xCF, 0x01, 0xEE, // ImplicitSelectionParameter + 0xE0, 0x04, 0x81, 0x02, 0x01, 0x02, // Privacy Requirements + 0xA0, 0x2F, // Contactless Protocol Parameters + 0x80, 0x01, 0x84, // Assigned Protocols for implicit selection + 0x81, 0x01, 0x01, // Initial Contactless Activation State + 0xA2, 0x05, 0xA1, 0x03, 0x81, 0x01, 0x01, // Contactless Protocol Parameters Profile + 0x83, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, // Recognition Algorithm + 0x84, 0x01, 0x02, // Continuous Processing + 0xA5, 0x03, 0x82, 0x01, 0x80, // Communication Interface Access Parameters + 0x88, 0x0D, 0xA0, 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0xA1, 0x03, 0x80, 0x01, 0x00, // Protocol Data Type F + 0x89, 0x01, 0x20, // Contactless Protocol Type State + 0xA1, 0x56, // User Interaction Parameters + 0x7F, 0x20, 0x03, 0x5F, 0x45, 0x01, // Display Control Template + 0xA0, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Head Application + 0xA1, 0x11, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x4F, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Add to Group Authorization List + 0xA2, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Remove from Group Authorization List + 0xA3, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Add to CREL List + 0xA4, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Remove from CREL List + 0xA5, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Policy Restricted Applications + 0xA6, 0x03, 0x01, 0x01, 0x01, // Application Discretionary Data + 0x87, 0x01, 0x01, // Application Family + 0x88, 0x01, 0x00, // Display Required Indicator + 0xB0, 0x03, 0x04, 0x05, 0x06, // ETSI + 0x82, 0x02, 0x0A, 0x0B, // Cumulative Granted Volatile Memory + 0x83, 0x02, 0x0A, 0x0B, // Cumulative Granted Non-Volatile Memory + 0x96, 0x01, 0x00, // Privacy Sensitive Indicator + }, + expectError: false, + }, + { + name: "SystemSpecificParameters with one byte length encoding", + input: SystemSpecificParameters{ + NonVolatileCodeMinimumRequirement: []byte{0x01, 0x00}, + GlobalServiceParameters: []byte{0x04, 0x05, 0x06}, + VolatileReservedMemory: []byte{0x02, 0x00}, + NonVolatileReservedMemory: []byte{0x03, 0x00}, + LoadFileDataBlockFormatID: util.NullByte{Byte: 0xFF, Valid: true}, + LoadFileDataBlockParameters: []byte{0x01, 0x02, 0x03}, + ImplicitSelectionParameter: util.NullByte{Byte: 0xEE, Valid: true}, + PrivacyRequirements: &PrivacyRequirements{ + RequiredPrivacyStatus: nil, + RequiredPrivacyCondition: &RequiredPrivacyCondition{ + Constructed: false, + Value: []byte{0x01, 0x02}, + }, + }, + ContactlessProtocolParameters: &ContactlessProtocolParameters{ + AssignedProtocolsImplicitSelection: []byte{ImplicitSelectionProtocolTypeF}, + InitialContactlessActivationState: util.NullByte{Byte: InitialActivated, Valid: true}, + ContactlessProtocolParametersProfile: []byte{0xA1, 0x03, 0x81, 0x01, 0x01}, + RecognitionAlgorithm: []byte{0x01, 0x01, 0x02, 0x03, 0x04, 0x05}, + ContinuousProcessing: []byte{0x02}, + CommunicationInterfaceAccessParameters: &CommunicationInterfaceAccessParameters{CommunicationInterfaceAccessPerInstance: util.NullByte{Byte: ContactBasedCommunication, Valid: true}}, + ProtocolDataTypeF: &ProtocolData{ + ProtocolParameterData: []byte{0x80, 0x04, 0x01, 0x02, 0x03, 0x04}, + ProtocolParameterMandatoryMask: []byte{0x80, 0x01, 0x00}, + }, + ContactlessProtocolTypeState: util.NullByte{Byte: ContactlessProtocolTypeF, Valid: true}, + }, + ETSIParameters: []byte{0x04, 0x05, 0x06}, + CumulativeGrantedVolatileMemory: []byte{0x0A, 0x0B}, + CumulativeGrantedNonVolatileMemory: []byte{0x0A, 0x0B}, + PrivacySensitiveIndicator: util.NullByte{Byte: NotPrivacySensitive, Valid: true}, + }, + expected: []byte{ + 0xEF, 0x63, // SystemSpecificParameters + 0xC6, 0x02, 0x01, 0x00, // NonVolatileCodeMinimumRequirement + 0xCB, 0x03, 0x04, 0x05, 0x06, // GlobalServiceParameters + 0xCD, 0x01, 0xFF, // LoadFileDataBlockFormatId + 0xD7, 0x02, 0x02, 0x00, // VolatileReservedMemory + 0xD8, 0x02, 0x03, 0x00, // NonVolatileReservedMemory + 0xDD, 0x03, 0x01, 0x02, 0x03, // LoadFileDataBlockParameters + 0xCF, 0x01, 0xEE, // ImplicitSelectionParameter + 0xE0, 0x04, 0x81, 0x02, 0x01, 0x02, // Privacy Requirements + 0xA0, 0x2F, // Contactless Protocol Parameters + 0x80, 0x01, 0x84, // Assigned Protocols for implicit selection + 0x81, 0x01, 0x01, // Initial Contactless Activation State + 0xA2, 0x05, 0xA1, 0x03, 0x81, 0x01, 0x01, // Contactless Protocol Parameters Profile + 0x83, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, // Recognition Algorithm + 0x84, 0x01, 0x02, // Continuous Processing + 0xA5, 0x03, 0x82, 0x01, 0x80, // Communication Interface Access Parameters + 0x88, 0x0D, 0xA0, 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0xA1, 0x03, 0x80, 0x01, 0x00, // Protocol Data Type F + 0x89, 0x01, 0x20, // Contactless Protocol Type State + 0xB0, 0x03, 0x04, 0x05, 0x06, // ETSI + 0x82, 0x02, 0x0A, 0x0B, // Cumulative Granted Volatile Memory + 0x83, 0x02, 0x0A, 0x0B, // Cumulative Granted Non-Volatile Memory + 0x96, 0x01, 0x00, // Privacy Sensitive Indicator + }, + expectError: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.input.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestRequiredPrivacyStatus_Bytes(t *testing.T) { + tests := []struct { + name string + inputRequiredPrivacyStatus RequiredPrivacyStatus + expected []byte + }{ + { + name: "not constructed bytes", + inputRequiredPrivacyStatus: RequiredPrivacyStatus{ + Constructed: false, + Value: []byte{0x00, 0x01, 0x02}, + }, + expected: []byte{0x80, 0x03, 0x00, 0x01, 0x02}, + }, + { + name: "constructed bytes", + inputRequiredPrivacyStatus: RequiredPrivacyStatus{ + Constructed: true, + Value: []byte{0x00, 0x01, 0x02}, + }, + expected: []byte{0xA0, 0x03, 0x00, 0x01, 0x02}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.inputRequiredPrivacyStatus.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestRequiredPrivacyCondition_Bytes(t *testing.T) { + tests := []struct { + name string + inputRequiredPrivacyCondition RequiredPrivacyCondition + expected []byte + }{ + { + name: "not constructed bytes", + inputRequiredPrivacyCondition: RequiredPrivacyCondition{ + Constructed: false, + Value: []byte{0x00, 0x01, 0x02}, + }, + expected: []byte{0x81, 0x03, 0x00, 0x01, 0x02}, + }, + { + name: "constructed bytes", + inputRequiredPrivacyCondition: RequiredPrivacyCondition{ + Constructed: true, + Value: []byte{0x00, 0x01, 0x02}, + }, + expected: []byte{0xA1, 0x03, 0x00, 0x01, 0x02}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.inputRequiredPrivacyCondition.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestPrivacyRequirements_Bytes(t *testing.T) { + tests := []struct { + name string + inputPrivacyRequirements PrivacyRequirements + expected []byte + }{ + { + name: "multiple status, no condition", + inputPrivacyRequirements: PrivacyRequirements{ + RequiredPrivacyStatus: []RequiredPrivacyStatus{ + { + Constructed: false, + Value: []byte{0xF1, 0xF2}, + }, + { + Constructed: true, + Value: []byte{0xE1, 0xE2}, + }, + }, + RequiredPrivacyCondition: nil, + }, + expected: []byte{0xE0, 0x08, 0x80, 0x02, 0xF1, 0xF2, 0xA0, 0x02, 0xE1, 0xE2}, + }, + { + name: "one status, with condition", + inputPrivacyRequirements: PrivacyRequirements{ + RequiredPrivacyStatus: []RequiredPrivacyStatus{ + { + Constructed: false, + Value: []byte{0xF1}, + }, + }, + RequiredPrivacyCondition: &RequiredPrivacyCondition{ + Constructed: true, + Value: []byte{0xE1, 0xE2}, + }, + }, + expected: []byte{0xE0, 0x07, 0x80, 0x01, 0xF1, 0xA1, 0x02, 0xE1, 0xE2}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.inputPrivacyRequirements.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestTagList_Bytes(t *testing.T) { + tests := []struct { + name string + inputTagList TagList + expected []byte + }{ + { + name: "All tags", + inputTagList: TagList{ + AID: true, + ApplicationLifecycleState: true, + Privileges: true, + ImplicitSelectionParameters: true, + ApplicationElfAID: true, + ElfVersionNumber: true, + ListOfEmAIDs: true, + AssociatedSdAID: true, + DisplayControlTemplate: true, + UniformResourceLocator: true, + ApplicationImageTemplate: true, + DisplayMessage: true, + ApplicationGroupHeadApplication: true, + ApplicationGroupAuthorizationList: true, + CRELApplicationAIDList: true, + PolicyRestrictedApplications: true, + ApplicationGroupMembers: true, + ApplicationDiscretionaryData: true, + ApplicationFamily: true, + AssignedProtocolsImplicitSelection: true, + InitialContactlessActivationState: true, + ContactlessProtocolTypeState: true, + ContactlessProtocolParametersProfile: true, + RecognitionAlgorithm: true, + ContinuousProcessing: true, + CommunicationInterfaceAccessParameters: true, + ProtocolDataTypeA: true, + ProtocolDataTypeB: true, + CumulativeGrantedNonVolatileMemory: true, + CumulativeGrantedVolatileMemory: true, + CumulativeRemainingNonVolatileMemory: true, + CumulativeRemainingVolatileMemory: true, + ProtocolDataTypeF: true, + PrivacySensitiveIndicator: true, + }, + expected: []byte{0x5C, 0x21, 0x4F, 0x9F, 0x70, 0xC5, 0xCF, 0xC4, 0xCE, 0x84, 0xCC, 0x7F, 0x20, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0x86, 0x87, 0x88, 0x89, 0xA9, 0x8A, 0x8B, 0xAC, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x96}, + }, + { + name: "URL, Application Image Template, Display Message", + inputTagList: TagList{ + UniformResourceLocator: true, + ApplicationImageTemplate: true, + DisplayMessage: true, + }, + expected: []byte{0x5C, 0x05, 0x5F, 0x50, 0x6D, 0x5F, 0x45}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.inputTagList.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestGetStatusCommandDataField_Bytes(t *testing.T) { + tests := []struct { + name string + cdf GetStatusCommandDataField + expected []byte + }{ + { + name: "AID as search criteria - without TagList", + cdf: GetStatusCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + { + name: "AID and other search criteria - without TagList", + cdf: GetStatusCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + OtherSearchCriteria: []byte{0xC5, 0x03, 0x00, 0x00, 0x10}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xC5, 0x03, 0x00, 0x00, 0x10}, + }, + { + name: "AID and other search criteria - with TagList", + cdf: GetStatusCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + OtherSearchCriteria: []byte{0xC5, 0x03, 0x00, 0x00, 0x10}, + TagList: &TagList{AssociatedSdAID: true}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xC5, 0x03, 0x00, 0x00, 0x10, 0x5C, 0x01, 0xCC}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.cdf.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestTagListCRS_Bytes(t *testing.T) { + tests := []struct { + name string + inputTagList TagListCRS + expected []byte + }{ + { + name: "All tags", + inputTagList: TagListCRS{ + AID: true, + ApplicationLifecycleState: true, + DisplayControlTemplate: true, + UniformResourceLocator: true, + ApplicationImageTemplate: true, + DisplayMessage: true, + ApplicationUpdateCounter: true, + SelectionPriority: true, + GroupHeadApplication: true, + GroupMembersApplication: true, + CRELApplicationAIDList: true, + PolicyRestrictedApplications: true, + ApplicationDiscretionaryData: true, + ApplicationFamily: true, + DisplayRequiredIndicator: true, + ContactlessProtocolTypeState: true, + ContinuousProcessing: true, + RecognitionAlgorithmForImplicitSelection: true, + AssignedProtocolsForImplicitSelection: true, + ProtocolDataTypeA: true, + ProtocolDataTypeB: true, + ProtocolDataTypeF: true, + ProtocolDataTypeFSystemCode: true, + CommunicationInterfaceAvailability: true, + PrivacySensitiveIndicator: true, + }, + expected: []byte{0x5C, 0x18, 0x4F, 0x9F, 0x70, 0x7F, 0x20, 0x80, 0x81, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x93, 0x94, 0x95, 0x96}, + }, + { + name: "URL, Application Image Template, Display Message", + inputTagList: TagListCRS{ + UniformResourceLocator: true, + ApplicationImageTemplate: true, + DisplayMessage: true, + }, + expected: []byte{0x5C, 0x05, 0x5F, 0x50, 0x6D, 0x5F, 0x45}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.inputTagList.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestGetStatusCRSCommandDataField_Bytes(t *testing.T) { + tests := []struct { + name string + cdf GetStatusCRSCommandDataField + expected []byte + }{ + { + name: "AID as search criteria - without TagList", + cdf: GetStatusCRSCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + { + name: "AID and other search criteria - without TagList", + cdf: GetStatusCRSCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + OtherSearchCriteria: []byte{0x9F, 0x70, 0x02, 0x07, 0x01}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x9F, 0x70, 0x02, 0x07, 0x01}, + }, + { + name: "AID and other search criteria - with TagList", + cdf: GetStatusCRSCommandDataField{ + AID: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + OtherSearchCriteria: []byte{0x9F, 0x70, 0x02, 0x07, 0x01}, + TagListCRS: &TagListCRS{CommunicationInterfaceAvailability: true}, + }, + expected: []byte{0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x9F, 0x70, 0x02, 0x07, 0x01, 0x5C, 0x01, 0x95}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.cdf.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestCommunicationInterfaceAccessParameters_Bytes(t *testing.T) { + tests := []struct { + name string + ciap CommunicationInterfaceAccessParameters + expected []byte + }{ + { + name: "Restriction", + ciap: CommunicationInterfaceAccessParameters{ + CommunicationInterfaceAccessRestriction: util.NullByte{ + Byte: ContactBasedCommunication, + Valid: true, + }, + }, + expected: []byte{0x80, 0x01, 0x80}, + }, + { + name: "Default", + ciap: CommunicationInterfaceAccessParameters{ + CommunicationInterfaceAccessDefault: util.NullByte{ + Byte: ProximityBasedCommunication, + Valid: true, + }, + }, + expected: []byte{0x81, 0x01, 0x40}, + }, + { + name: "Per Instance", + ciap: CommunicationInterfaceAccessParameters{ + CommunicationInterfaceAccessPerInstance: util.NullByte{ + Byte: ContactAndProximityBasedCommunication, + Valid: true, + }, + }, + expected: []byte{0x82, 0x01, 0xC0}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.ciap.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestContactlessProtocolParameters_Bytes(t *testing.T) { + tests := []struct { + name string + cpp ContactlessProtocolParameters + expected []byte + }{ + { + name: "Protocol Data Type A", + cpp: ContactlessProtocolParameters{ + AssignedProtocolsImplicitSelection: []byte{ImplicitSelectionProtocolTypeA}, + InitialContactlessActivationState: util.NullByte{Byte: InitialActivated, Valid: true}, + ContactlessProtocolParametersProfile: []byte{0xA0, 0x03, 0x81, 0x01, 0x01}, + RecognitionAlgorithm: []byte{0x01, 0x01, 0x02, 0x03, 0x04, 0x05}, + ContinuousProcessing: []byte{0x02}, + CommunicationInterfaceAccessParameters: &CommunicationInterfaceAccessParameters{CommunicationInterfaceAccessPerInstance: util.NullByte{Byte: ProximityBasedCommunication, Valid: true}}, + ProtocolDataTypeA: &ProtocolData{ + ProtocolParameterData: []byte{0x80, 0x04, 0x01, 0x02, 0x03, 0x04}, + ProtocolParameterMandatoryMask: []byte{0x80, 0x01, 0x00}, + }, + ContactlessProtocolTypeState: util.NullByte{Byte: ContactlessProtocolTypeA, Valid: true}, + }, + expected: []byte{ + 0x80, 0x01, 0x81, // Assigned Protocols for implicit selection + 0x81, 0x01, 0x01, // Initial Contactless Activation State + 0xA2, 0x05, 0xA0, 0x03, 0x81, 0x01, 0x01, // Contactless Protocol Parameters Profile + 0x83, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, // Recognition Algorithm + 0x84, 0x01, 0x02, // Continuous Processing + 0xA5, 0x03, 0x82, 0x01, 0x40, // Communication Interface Access Parameters + 0x86, 0x0D, 0xA0, 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0xA1, 0x03, 0x80, 0x01, 0x00, // Protocol Data Type A + 0x89, 0x01, 0x80}, // Contactless Protocol Type State + }, + { + name: "Protocol Data Type B", + cpp: ContactlessProtocolParameters{ + AssignedProtocolsImplicitSelection: []byte{ImplicitSelectionProtocolTypeB}, + InitialContactlessActivationState: util.NullByte{Byte: InitialActivated, Valid: true}, + ContactlessProtocolParametersProfile: []byte{0xA1, 0x03, 0x81, 0x01, 0x01}, + RecognitionAlgorithm: []byte{0x01, 0x01, 0x02, 0x03, 0x04, 0x05}, + ContinuousProcessing: []byte{0x02}, + CommunicationInterfaceAccessParameters: &CommunicationInterfaceAccessParameters{CommunicationInterfaceAccessPerInstance: util.NullByte{Byte: ContactBasedCommunication, Valid: true}}, + ProtocolDataTypeB: &ProtocolData{ + ProtocolParameterData: []byte{0x80, 0x04, 0x01, 0x02, 0x03, 0x04}, + ProtocolParameterMandatoryMask: []byte{0x80, 0x01, 0x00}, + }, + ContactlessProtocolTypeState: util.NullByte{Byte: ContactlessProtocolTypeB, Valid: true}, + }, + expected: []byte{ + 0x80, 0x01, 0x82, // Assigned Protocols for implicit selection + 0x81, 0x01, 0x01, // Initial Contactless Activation State + 0xA2, 0x05, 0xA1, 0x03, 0x81, 0x01, 0x01, // Contactless Protocol Parameters Profile + 0x83, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, // Recognition Algorithm + 0x84, 0x01, 0x02, // Continuous Processing + 0xA5, 0x03, 0x82, 0x01, 0x80, // Communication Interface Access Parameters + 0x87, 0x0D, 0xA0, 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0xA1, 0x03, 0x80, 0x01, 0x00, // Protocol Data Type B + 0x89, 0x01, 0x40}, // Contactless Protocol Type State + }, + { + name: "Protocol Data Type F", + cpp: ContactlessProtocolParameters{ + AssignedProtocolsImplicitSelection: []byte{ImplicitSelectionProtocolTypeF}, + InitialContactlessActivationState: util.NullByte{Byte: InitialActivated, Valid: true}, + ContactlessProtocolParametersProfile: []byte{0xA1, 0x03, 0x81, 0x01, 0x01}, + RecognitionAlgorithm: []byte{0x01, 0x01, 0x02, 0x03, 0x04, 0x05}, + ContinuousProcessing: []byte{0x02}, + CommunicationInterfaceAccessParameters: &CommunicationInterfaceAccessParameters{CommunicationInterfaceAccessPerInstance: util.NullByte{Byte: ContactBasedCommunication, Valid: true}}, + ProtocolDataTypeF: &ProtocolData{ + ProtocolParameterData: []byte{0x80, 0x04, 0x01, 0x02, 0x03, 0x04}, + ProtocolParameterMandatoryMask: []byte{0x80, 0x01, 0x00}, + }, + ContactlessProtocolTypeState: util.NullByte{Byte: ContactlessProtocolTypeF, Valid: true}, + }, + expected: []byte{ + 0x80, 0x01, 0x84, // Assigned Protocols for implicit selection + 0x81, 0x01, 0x01, // Initial Contactless Activation State + 0xA2, 0x05, 0xA1, 0x03, 0x81, 0x01, 0x01, // Contactless Protocol Parameters Profile + 0x83, 0x06, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, // Recognition Algorithm + 0x84, 0x01, 0x02, // Continuous Processing + 0xA5, 0x03, 0x82, 0x01, 0x80, // Communication Interface Access Parameters + 0x88, 0x0D, 0xA0, 0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0xA1, 0x03, 0x80, 0x01, 0x00, // Protocol Data Type F + 0x89, 0x01, 0x20}, // Contactless Protocol Type State + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.cpp.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} + +func TestUserInteractionParameters_Bytes(t *testing.T) { + tests := []struct { + name string + uip UserInteractionParameters + expected []byte + }{ + { + name: "bytes", + uip: UserInteractionParameters{ + DisplayControlTemplate: []byte{0x5F, 0x45, 0x01}, + HeadApplication: aid.AID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + AddToGroupAuthorizationList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, + }, + RemoveFromGroupAuthorizationList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + AddToCRELList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + RemoveFromCRELList: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + PolicyRestrictedApplications: []aid.AID{ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}, + }, + ApplicationDiscretionaryData: []byte{0x01, 0x01, 0x01}, + ApplicationFamily: util.NullByte{Byte: 0x01, Valid: true}, + DisplayRequiredIndicator: util.NullByte{Byte: DisplayRequired, Valid: true}, + }, + expected: []byte{ + 0x7F, 0x20, 0x03, 0x5F, 0x45, 0x01, // Display Control Template + 0xA0, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Head Application + 0xA1, 0x11, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x4F, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // Add to Group Authorization List + 0xA2, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Remove from Group Authorization List + 0xA3, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Add to CREL List + 0xA4, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Remove from CREL List + 0xA5, 0x08, 0x4F, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // Policy Restricted Applications + 0xA6, 0x03, 0x01, 0x01, 0x01, // Application Discretionary Data + 0x87, 0x01, 0x01, // Application Family + 0x88, 0x01, 0x00}, // Display Required Indicator + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + received := tc.uip.Bytes() + + if !cmp.Equal(tc.expected, received) { + t.Errorf("Expected: '%v', got: '%v'", tc.expected, received) + } + }) + } +} diff --git a/tag/tag.go b/tag/tag.go index d0a0d77..a86a459 100755 --- a/tag/tag.go +++ b/tag/tag.go @@ -4,93 +4,158 @@ package tag import "github.com/skythen/bertlv" var ( - AID = bertlv.NewOneByteTag(0x4F) - AllRefDo = bertlv.NewTwoByteTag(0xFF, 0x40) - ApduArDo = bertlv.NewOneByteTag(0xD0) - ApplicationELFAID = bertlv.NewOneByteTag(0xC4) - ApplicationPrivileges = bertlv.NewOneByteTag(0x82) - ApplicationProductionLifeCycleData = bertlv.NewTwoByteTag(0x9F, 0x6E) - ApplicationProviderIdentifier = bertlv.NewTwoByteTag(0x5F, 0x20) - ApplicationSpecificParameters = bertlv.NewOneByteTag(0xC9) - AramConfigDo = bertlv.NewOneByteTag(0xE5) - ArDo = bertlv.NewOneByteTag(0xE3) - AssociatedSDAID = bertlv.NewOneByteTag(0xCC) - CardAndChipDetails = bertlv.NewOneByteTag(0x66) - CardCapabilityInformation = bertlv.NewOneByteTag(0x67) - CardData = bertlv.NewOneByteTag(0x66) - CardRecognitionData = bertlv.NewOneByteTag(0x73) - CipheredLoadFileDataBlock = bertlv.NewOneByteTag(0xD4) - CipherSuitesForDAPs = bertlv.NewOneByteTag(0x87) - CipherSuitesForLFDBEncryption = bertlv.NewOneByteTag(0x84) - CipherSuitesForReceipts = bertlv.NewOneByteTag(0x86) - CipherSuitesForTokens = bertlv.NewOneByteTag(0x85) - ControlReferenceTemplateForDigitalSignature = bertlv.NewOneByteTag(0xB6) - DAPBlock = bertlv.NewOneByteTag(0xE2) - DeleteToken = bertlv.NewOneByteTag(0x9E) - DeviceAppIDRefDo = bertlv.NewOneByteTag(0xC1) - DeviceConfigDo = bertlv.NewOneByteTag(0xE4) - DeviceInterfaceVersionDo = bertlv.NewOneByteTag(0xE6) - ELFVersion = bertlv.NewOneByteTag(0xCE) - EMAID = bertlv.NewOneByteTag(0x84) - ExtendedCardResourcesInformation = bertlv.NewTwoByteTag(0xFF, 0x21) - FCI = bertlv.NewOneByteTag(0x6F) - FileAID = bertlv.NewOneByteTag(0x84) - GlobalServiceParameters = bertlv.NewOneByteTag(0xCB) - GPCardConfigurationDetails = bertlv.NewOneByteTag(0x65) - GPOID2 = bertlv.NewOneByteTag(0x60) - GPOID3 = bertlv.NewOneByteTag(0x63) - GPOID4 = bertlv.NewOneByteTag(0x64) - ICV = bertlv.NewOneByteTag(0xD3) - ImplicitlySelectedApplication = bertlv.NewOneByteTag(0xC0) - ImplicitSelectionParameter = bertlv.NewOneByteTag(0xCF) - ETSIInstalledApplications = bertlv.NewOneByteTag(0x81) - ETSIFreeNonVolatileMemory = bertlv.NewOneByteTag(0x82) - ETSIFreeVolatileMemory = bertlv.NewOneByteTag(0x83) - ISDCertificateInformation = bertlv.NewOneByteTag(0x68) - ISDTrustPoint = bertlv.NewOneByteTag(0x67) - KeyIdentifier = bertlv.NewOneByteTag(0xD0) - KeyInformationData = bertlv.NewOneByteTag(0xC0) - KeyInformationTemplate = bertlv.NewOneByteTag(0xE0) - KeyParameterReferenceList = bertlv.NewOneByteTag(0x88) - KeyVersionNumber = bertlv.NewOneByteTag(0xD2) - LFDBHAlgorithms = bertlv.NewOneByteTag(0x83) - LifeCycleState = bertlv.NewTwoByteTag(0x9F, 0x70) - LoadFileDataBlock = bertlv.NewOneByteTag(0xC4) - LoadFileDataBlockFormatID = bertlv.NewOneByteTag(0xCD) - LoadFileDataBlockParameter = bertlv.NewOneByteTag(0xDD) - LoadFileDataBlockSignature = bertlv.NewOneByteTag(0xC3) - MaximumCommandDataLength = bertlv.NewTwoByteTag(0x9F, 0x65) - NfcArDo = bertlv.NewOneByteTag(0xD1) - NonVolatileCodeMinimumRequirement = bertlv.NewOneByteTag(0xC6) - NonVolatileMemoryQuota = bertlv.NewOneByteTag(0xC8) - NonVolatileReservedMemory = bertlv.NewOneByteTag(0xD8) - OID = bertlv.NewOneByteTag(0x06) - PrivacyRequirements = bertlv.NewOneByteTag(0xE0) - Privileges = bertlv.NewOneByteTag(0xC5) - ProprietaryData = bertlv.NewOneByteTag(0xA5) - RefArDo = bertlv.NewOneByteTag(0xE2) - RefDo = bertlv.NewOneByteTag(0xE1) - RefreshTag = bertlv.NewTwoByteTag(0xDF, 0x20) - RegistryRelatedData = bertlv.NewOneByteTag(0xE3) - RequiredPrivacyCondition = bertlv.NewOneByteTag(0x81) - RequiredPrivacyConditionConstructed = bertlv.NewOneByteTag(0xA1) - RequiredPrivacyStatus = bertlv.NewOneByteTag(0x80) - RequiredPrivacyStatusConstructed = bertlv.NewOneByteTag(0xA0) - Restrict = bertlv.NewOneByteTag(0xD9) - SCP03SupportedKeys = bertlv.NewOneByteTag(0x82) - SCP81PreSharedKeyMaxLength = bertlv.NewOneByteTag(0x84) - SCP81SupportedCipherSuites = bertlv.NewOneByteTag(0x83) - SCPInformation = bertlv.NewOneByteTag(0xA0) - SCPOptions = bertlv.NewOneByteTag(0x81) - SCPType = bertlv.NewOneByteTag(0x80) - SDIdentificationNumber = bertlv.NewOneByteTag(0x42) - SDImageNumber = bertlv.NewOneByteTag(0x45) - SpecificRefDo = bertlv.NewTwoByteTag(0xFF, 0x50) - SSDPrivileges = bertlv.NewOneByteTag(0x81) - SystemSpecificParameter = bertlv.NewOneByteTag(0xEF) - TokenIdentification = bertlv.NewOneByteTag(0x93) - TS102226SpecificParameters = bertlv.NewOneByteTag(0xCA) - TS102226SpecificTemplate = bertlv.NewOneByteTag(0xEA) - VolatileMemoryQuota = bertlv.NewOneByteTag(0xC7) - VolatileReservedMemory = bertlv.NewOneByteTag(0xD7) + AID = bertlv.NewOneByteTag(0x4F) + AddToCRELList = bertlv.NewOneByteTag(0xA3) + AddToGroupAuthorizationList = bertlv.NewOneByteTag(0xA1) + AllRefDo = bertlv.NewTwoByteTag(0xFF, 0x40) + ApduArDo = bertlv.NewOneByteTag(0xD0) + ApplicationDiscretionaryData = bertlv.NewOneByteTag(0xA6) + ApplicationELFAID = bertlv.NewOneByteTag(0xC4) + ApplicationFamily = bertlv.NewOneByteTag(0x87) + ApplicationGroupAuthorizationList = bertlv.NewOneByteTag(0xA1) + ApplicationGroupHeadApplication = bertlv.NewOneByteTag(0xA0) + ApplicationGroupMembers = bertlv.NewOneByteTag(0xA4) + ApplicationImageTemplate = bertlv.NewOneByteTag(0x6D) + ApplicationPrivileges = bertlv.NewOneByteTag(0x82) + ApplicationProductionLifeCycleData = bertlv.NewTwoByteTag(0x9F, 0x6E) + ApplicationProviderIdentifier = bertlv.NewTwoByteTag(0x5F, 0x20) + ApplicationSpecificParameters = bertlv.NewOneByteTag(0xC9) + ApplicationUpdateCounter = bertlv.NewOneByteTag(0x80) + ArDo = bertlv.NewOneByteTag(0xE3) + AramConfigDo = bertlv.NewOneByteTag(0xE5) + AssignedProtocolsImplicitSelection = bertlv.NewOneByteTag(0x80) + AssociatedSDAID = bertlv.NewOneByteTag(0xCC) + CRELApplicationAIDList = bertlv.NewOneByteTag(0xA2) + CardAndChipDetails = bertlv.NewOneByteTag(0x66) + CardCapabilityInformation = bertlv.NewOneByteTag(0x67) + CardData = bertlv.NewOneByteTag(0x66) + CardRecognitionData = bertlv.NewOneByteTag(0x73) + CipherSuitesForDAPs = bertlv.NewOneByteTag(0x87) + CipherSuitesForLFDBEncryption = bertlv.NewOneByteTag(0x84) + CipherSuitesForReceipts = bertlv.NewOneByteTag(0x86) + CipherSuitesForTokens = bertlv.NewOneByteTag(0x85) + CipheredLoadFileDataBlock = bertlv.NewOneByteTag(0xD4) + CommunicationInterfaceAccessDefault = bertlv.NewOneByteTag(0x81) + CommunicationInterfaceAccessParameters = bertlv.NewOneByteTag(0xA5) + CommunicationInterfaceAccessPerInstance = bertlv.NewOneByteTag(0x82) + CommunicationInterfaceAccessRestriction = bertlv.NewOneByteTag(0x80) + ContactlessProtocolParameters = bertlv.NewOneByteTag(0xA0) + ContactlessProtocolParametersProfile = bertlv.NewOneByteTag(0xA2) + ContactlessProtocolTypeState = bertlv.NewOneByteTag(0x89) + ContinuousProcessing = bertlv.NewOneByteTag(0x84) + ControlReferenceTemplateForDigitalSignature = bertlv.NewOneByteTag(0xB6) + CumulativeGrantedNonVolatileMemory = bertlv.NewOneByteTag(0x83) + CumulativeGrantedVolatileMemory = bertlv.NewOneByteTag(0x82) + DAPBlock = bertlv.NewOneByteTag(0xE2) + DeleteToken = bertlv.NewOneByteTag(0x9E) + DeviceAppIDRefDo = bertlv.NewOneByteTag(0xC1) + DeviceConfigDo = bertlv.NewOneByteTag(0xE4) + DeviceInterfaceVersionDo = bertlv.NewOneByteTag(0xE6) + DisplayControlTemplate = bertlv.NewTwoByteTag(0x7F, 0x20) + DisplayMessage = bertlv.NewTwoByteTag(0x5F, 0x45) + DisplayRequiredIndicator = bertlv.NewOneByteTag(0x88) + ELFVersion = bertlv.NewOneByteTag(0xCE) + EMAID = bertlv.NewOneByteTag(0x84) + ETSIAssigned = bertlv.NewOneByteTag(0xB0) + ETSIFreeNonVolatileMemory = bertlv.NewOneByteTag(0x82) + ETSIFreeVolatileMemory = bertlv.NewOneByteTag(0x83) + ETSIInstalledApplications = bertlv.NewOneByteTag(0x81) + ExtendedCardResourcesInformation = bertlv.NewTwoByteTag(0xFF, 0x21) + FCI = bertlv.NewOneByteTag(0x6F) + FileAID = bertlv.NewOneByteTag(0x84) + GPCardConfigurationDetails = bertlv.NewOneByteTag(0x65) + GPOID2 = bertlv.NewOneByteTag(0x60) + GPOID3 = bertlv.NewOneByteTag(0x63) + GPOID4 = bertlv.NewOneByteTag(0x64) + GetStatusCRSAssignedProtocolsForImplicitSelection = bertlv.NewOneByteTag(0x8C) + GetStatusCRSOfCRELApplicationAIDList = bertlv.NewOneByteTag(0xA4) + GetStatusCRSOfCommunicationInterfaceAvailability = bertlv.NewOneByteTag(0x95) + GetStatusCRSOfContinuousProcessing = bertlv.NewOneByteTag(0x8A) + GetStatusCRSOfGroupMemberApplication = bertlv.NewOneByteTag(0xA3) + GetStatusCRSOfHeadApplication = bertlv.NewOneByteTag(0xA2) + GetStatusCRSOfProtocolDataTypeFSystemCode = bertlv.NewOneByteTag(0x94) + GetStatusCRSRecognitionAlgorithmForImplicitSelection = bertlv.NewOneByteTag(0x8B) + GetStatusOfApplicationDiscretionaryData = bertlv.NewOneByteTag(0xA5) + GetStatusOfApplicationFamily = bertlv.NewOneByteTag(0x86) + GetStatusOfAssignedProtocolsImplicitSelection = bertlv.NewOneByteTag(0x87) + GetStatusOfCommunicationInterfaceAccessParameters = bertlv.NewOneByteTag(0xAC) + GetStatusOfContactlessProtocolParametersProfile = bertlv.NewOneByteTag(0xA9) + GetStatusOfContinuousProcessing = bertlv.NewOneByteTag(0x8B) + GetStatusOfCumulativeGrantedNonVolatileMemory = bertlv.NewOneByteTag(0x8F) + GetStatusOfCumulativeGrantedVolatileMemory = bertlv.NewOneByteTag(0x90) + GetStatusOfCumulativeRemainingNonVolatileMemory = bertlv.NewOneByteTag(0x91) + GetStatusOfCumulativeRemainingVolatileMemory = bertlv.NewOneByteTag(0x92) + GetStatusOfInitialContactlessActivationState = bertlv.NewOneByteTag(0x88) + GetStatusOfPolicyRestrictedApplications = bertlv.NewOneByteTag(0xA3) + GetStatusOfProtocolDataTypeA = bertlv.NewOneByteTag(0x8D) + GetStatusOfProtocolDataTypeB = bertlv.NewOneByteTag(0x8E) + GetStatusOfProtocolDataTypeF = bertlv.NewOneByteTag(0x93) + GetStatusOfRecognitionAlgorithm = bertlv.NewOneByteTag(0x8A) + GlobalServiceParameters = bertlv.NewOneByteTag(0xCB) + HeadApplication = bertlv.NewOneByteTag(0xA0) + ICV = bertlv.NewOneByteTag(0xD3) + ISDCertificateInformation = bertlv.NewOneByteTag(0x68) + ISDTrustPoint = bertlv.NewOneByteTag(0x67) + ImplicitSelectionParameter = bertlv.NewOneByteTag(0xCF) + ImplicitlySelectedApplication = bertlv.NewOneByteTag(0xC0) + InitialContactlessActivationState = bertlv.NewOneByteTag(0x81) + KeyIdentifier = bertlv.NewOneByteTag(0xD0) + KeyInformationData = bertlv.NewOneByteTag(0xC0) + KeyInformationTemplate = bertlv.NewOneByteTag(0xE0) + KeyParameterReferenceList = bertlv.NewOneByteTag(0x88) + KeyVersionNumber = bertlv.NewOneByteTag(0xD2) + LFDBHAlgorithms = bertlv.NewOneByteTag(0x83) + LifeCycleState = bertlv.NewTwoByteTag(0x9F, 0x70) + LoadFileDataBlock = bertlv.NewOneByteTag(0xC4) + LoadFileDataBlockFormatID = bertlv.NewOneByteTag(0xCD) + LoadFileDataBlockParameter = bertlv.NewOneByteTag(0xDD) + LoadFileDataBlockSignature = bertlv.NewOneByteTag(0xC3) + MaximumCommandDataLength = bertlv.NewTwoByteTag(0x9F, 0x65) + NfcArDo = bertlv.NewOneByteTag(0xD1) + NonVolatileCodeMinimumRequirement = bertlv.NewOneByteTag(0xC6) + NonVolatileMemoryQuota = bertlv.NewOneByteTag(0xC8) + NonVolatileReservedMemory = bertlv.NewOneByteTag(0xD8) + OID = bertlv.NewOneByteTag(0x06) + PolicyRestrictedApplications = bertlv.NewOneByteTag(0xA5) + PrivacyRequirements = bertlv.NewOneByteTag(0xE0) + PrivacySensitiveIndicator = bertlv.NewOneByteTag(0x96) + Privileges = bertlv.NewOneByteTag(0xC5) + ProprietaryData = bertlv.NewOneByteTag(0xA5) + ProtocolDataTypeA = bertlv.NewOneByteTag(0x86) + ProtocolDataTypeB = bertlv.NewOneByteTag(0x87) + ProtocolDataTypeF = bertlv.NewOneByteTag(0x88) + ProtocolParameterData = bertlv.NewOneByteTag(0xA0) + ProtocolParameterMandatoryMask = bertlv.NewOneByteTag(0xA1) + RecognitionAlgorithm = bertlv.NewOneByteTag(0x83) + RefArDo = bertlv.NewOneByteTag(0xE2) + RefDo = bertlv.NewOneByteTag(0xE1) + RefreshTag = bertlv.NewTwoByteTag(0xDF, 0x20) + RegistryRelatedData = bertlv.NewOneByteTag(0xE3) + RemoveFromCRELList = bertlv.NewOneByteTag(0xA4) + RemoveFromGroupAuthorizationList = bertlv.NewOneByteTag(0xA2) + RequiredPrivacyCondition = bertlv.NewOneByteTag(0x81) + RequiredPrivacyConditionConstructed = bertlv.NewOneByteTag(0xA1) + RequiredPrivacyStatus = bertlv.NewOneByteTag(0x80) + RequiredPrivacyStatusConstructed = bertlv.NewOneByteTag(0xA0) + Restrict = bertlv.NewOneByteTag(0xD9) + SCP03SupportedKeys = bertlv.NewOneByteTag(0x82) + SCP81PreSharedKeyMaxLength = bertlv.NewOneByteTag(0x84) + SCP81SupportedCipherSuites = bertlv.NewOneByteTag(0x83) + SCPInformation = bertlv.NewOneByteTag(0xA0) + SCPOptions = bertlv.NewOneByteTag(0x81) + SCPType = bertlv.NewOneByteTag(0x80) + SDIdentificationNumber = bertlv.NewOneByteTag(0x42) + SDImageNumber = bertlv.NewOneByteTag(0x45) + SSDPrivileges = bertlv.NewOneByteTag(0x81) + SelectionPriority = bertlv.NewOneByteTag(0x81) + SpecificRefDo = bertlv.NewTwoByteTag(0xFF, 0x50) + SystemSpecificParameter = bertlv.NewOneByteTag(0xEF) + TS102226SpecificParameters = bertlv.NewOneByteTag(0xCA) + TS102226SpecificTemplate = bertlv.NewOneByteTag(0xEA) + TagList = bertlv.NewOneByteTag(0x5C) + TokenIdentification = bertlv.NewOneByteTag(0x93) + UniformResourceLocator = bertlv.NewTwoByteTag(0x5F, 0x50) + UserInteractionParameters = bertlv.NewOneByteTag(0xA1) + VolatileMemoryQuota = bertlv.NewOneByteTag(0xC7) + VolatileReservedMemory = bertlv.NewOneByteTag(0xD7) )