summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--card.bas234
-rw-r--r--card.def8
-rw-r--r--card.zcc50
-rw-r--r--project.zcp4
-rw-r--r--term.bas148
-rw-r--r--term.zct6
6 files changed, 317 insertions, 133 deletions
diff --git a/card.bas b/card.bas
index ae83b24..ca43734 100644
--- a/card.bas
+++ b/card.bas
@@ -1,9 +1,8 @@
Option Explicit
Option Base Explicit
-#Pragma T=1
-#Files 0
-Rem const ExtendedLcLe = true
+REM ExtendedLcLe should not be used. Only supported with very few card readers
+REM const ExtendedLcLe = true
#ifdef ExtendedLcLe
const ExtendedCapabilities = chr$(&H7C, 0, 8,0, 8,0, 8,0, 8,0)
@@ -15,15 +14,17 @@ const ATRHB = chr$(0, &H31, &HC5, &H73, &HC0, &H01, &H80, 0, &H90, 0)
const MaxChallengeLength = 256
#endif
-#Pragma ATR(HB=ATRHB)
+#Pragma ATR(T=1,HB=ATRHB)
+#Files 0
-#include misc.def ' LePresent(), SuspendSW1SW2Processing
+#include misc.def ' LePresent, SuspendSW1SW2Processing, CommParams
#include rsa.def ' RSAExGenerateKey, RSAExConstructKey, RSAExDecryptRaw, RSAExPublicKey
#include tlv.def ' TLV, TLVReadTagLength, TLVNextObject, TLVNextChild
' Definition of Status Codes
const swChannelNotSupported = &H6881
const swSMNotSupported = &H6882
+const swChainingError = &H6883
const swChainingNotSupported = &H6884
const swINSNotFound = &H6D00
const swCLANotFound = &H6E00
@@ -36,14 +37,24 @@ const swFileNotFound = &H6A82
const swWrongPIN = &H6982
const swPINBlocked = &H6983
const swAccessNotAllowed = &H6982
+const swConditionOfUseNotMet = &H6985
const swOK = &H9000
' Definitions for AID
const Version = chr$(2, 0)
-const Manufacturer = chr$(&HFF, &HFF)
-const SerialNo = chr$(0,0,0,1)
-const OpenPGPApp = Chr$(&HD2,&H76,&H00,&H01,&H24,&H01)+Version+Manufacturer+SerialNo+chr$(0,0)
+const Manufacturer = chr$(0, 0)
+const SerialNo = chr$(0,0,0,0)
+eeprom OpenPGPApp as string*16 = Chr$(&HD2,&H76,&H00,&H01,&H24,&H01)+Version+Manufacturer+SerialNo+chr$(0,0)
+eeprom PersAID as string*6 at OpenPGPApp+8
+
+' Type for algorithm attributes
+type AlgoAttr
+ algorithm as byte
+ nbits as integer
+ ebits as integer
+ format as byte
+end type
' Data stored on Card
eeprom PrivateData(1 to 4) as string ' DO 0101 - 0104 (max 254 each)
@@ -55,12 +66,6 @@ eeprom Sex as byte = 39 ' DO 5F35 (31=male, 32=femal
eeprom Login as string = "" ' DO 5E (max 254)
eeprom URL as string = "" ' DO 5F50 (max 254)
-type AlgoAttr
- algorithm as byte
- nbits as integer
- ebits as integer
- format as byte
-end type
eeprom AlgoAttributes(0 to 2) as AlgoAttr = 1,3072,32,0, 1,3072,32,0, 1,3072,32,0
eeprom privateKey(0 to 2) as string
@@ -74,14 +79,6 @@ eeprom SignatureCounter$ as string*4 at SignatureCounter
' Passwords
-eeprom PW1 as string = "123456"
-eeprom ResetCode as string = ""
-eeprom PW3 as string = "12345678"
-
-eeprom retries(0 to 2) as byte = 3,0,3
-
-eeprom PW1Status as byte = 1 ' Part of DO C4 (PW1 valid for one or more PSO:CDS operations
-
const PW1Min = 6
const PW1Max = 32
const RCMin = 8
@@ -89,6 +86,12 @@ const RCMax = 32
const PW3Min = 8
const PW3Max = 32
+eeprom PW1 as string = "123456"
+eeprom ResetCode as string = ""
+eeprom PW3 as string = "12345678"
+eeprom retries(0 to 2) as byte = 3,0,3
+eeprom PW1Status as byte = 1 ' Part of DO C4 (PW1 valid for one or more PSO:CDS operations)
+
' Status
public OpenPGPAppSelected as byte
@@ -96,18 +99,18 @@ public AuthStatus as byte
' Storage for complete I/O data
#ifnotdef ExtendedLcLe
-public cmdout$ as string
-public cmdin$ as string
+public cmdio$ as string
+public oldins as byte
+public oldp1p2 as integer
#endif
+
+
sub SelectFile(data$)
if P1P2 <> &H400 then SW1SW2 = swP1P2Error : exit sub
+ if len(data$) > 16 then SW1SW2 = swFileNotFound : exit sub
- if len(data$) > len(OpenPGPApp) then
- SW1SW2 = swFileNotFound : exit sub
- end if
-
- if data$ = mid$(OpenPGPApp,1,len(data$)) then
+ if data$ = left$(OpenPGPApp,len(data$)) then
OpenPGPAppSelected = 1
else
OpenPGPAppSelected = 0
@@ -125,7 +128,7 @@ sub Verify(ReadOnly data$)
select case P2
case &H81:
- if Lc < PW1Min or Lc > PW1Max then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < PW1Min) or (len(data$) > PW1Max) then SW1SW2 = swLcLeError: exit sub
if retries(0) = 0 then SW1SW2 = swPINBlocked: exit sub
if data$ = PW1 then
AuthStatus = AuthStatus or 1
@@ -137,7 +140,7 @@ sub Verify(ReadOnly data$)
end if
case &H82:
- if Lc < PW1Min or Lc > PW1Max then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < PW1Min) or (len(data$) > PW1Max) then SW1SW2 = swLcLeError: exit sub
if retries(0) = 0 then SW1SW2 = swPINBlocked: exit sub
if data$ = PW1 then
AuthStatus = AuthStatus or 2
@@ -149,7 +152,7 @@ sub Verify(ReadOnly data$)
end if
case &H83:
- if Lc < PW3Min or Lc > PW3Max then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < PW3Min) or (len(data$) > PW3Max) then SW1SW2 = swLcLeError: exit sub
if retries(2) = 0 then SW1SW2 = swPINBlocked: exit sub
if data$ = PW3 then
AuthStatus = AuthStatus or 4
@@ -168,13 +171,13 @@ sub ChangePIN(ReadOnly data$)
private old$
private new$
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound : exit sub
- if LePresent() or (Lc = 0) then SW1SW2 = swLcLeError: exit sub
+ if LePresent() or (len(data$) = 0) then SW1SW2 = swLcLeError: exit sub
if P1 <> 0 then SW1SW2 = swP1P2Error: exit sub
if P2 = &H81 then
- if Lc < 2*PW1Min or Lc > 2*PW1Max then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < 2*PW1Min) or (len(data$) > 2*PW1Max) then SW1SW2 = swLcLeError: exit sub
if retries(0) = 0 then SW1SW2 = swPINBlocked: exit sub
- old$ = mid$(data$, 1, len(PW1))
+ old$ = left$(data$, len(PW1))
new$ = mid$(data$, 1+len(PW1))
if old$ = PW1 then
if (len(new$) < PW1Min) or (len(new$) > PW1Max) then SW1SW2 = swLcLeError: exit sub
@@ -186,9 +189,9 @@ sub ChangePIN(ReadOnly data$)
end if
elseif P2 = &H83 then
- if Lc < 2*PW3Min or Lc > 2*PW3Max then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < 2*PW3Min) or (len(data$) > 2*PW3Max) then SW1SW2 = swLcLeError: exit sub
if retries(2) = 0 then SW1SW2 = swPINBlocked: exit sub
- old$ = mid$(data$, 1, len(PW3))
+ old$ = left$(data$, len(PW3))
new$ = mid$(data$, 1+len(PW3))
if old$ = PW3 then
if (len(new$) < PW3Min) or (len(new$) > PW3Max) then SW1SW2 = swLcLeError: exit sub
@@ -213,10 +216,10 @@ sub ResetCounter(ReadOnly data$)
select case P1
case 0:
- if (Lc < PW1Min+RCMin or Lc > PW1Max+RCMax) then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < PW1Min+RCMin or len(data$) > PW1Max+RCMax) then SW1SW2 = swLcLeError: exit sub
if retries(1) = 0 then SW1SW2 = swPINBlocked: exit sub
- if mid$(data$,1,len(ResetCode)) <> ResetCode then
+ if left$(data$,len(ResetCode)) <> ResetCode then
retries(1) = retries(1) - 1
SW1SW2 = swWrongPIN
exit sub
@@ -225,7 +228,7 @@ sub ResetCounter(ReadOnly data$)
if len(new$) < PW1min or len(new$) > PW1Max then SW1SW2 = swLcLeError: exit sub
PW1 = new$
case 2:
- if (Lc < PW1Min or Lc > PW1Max) then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) < PW1Min) or (len(data$) > PW1Max) then SW1SW2 = swLcLeError: exit sub
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
PW1 = data$
end select
@@ -242,7 +245,7 @@ function GetAlgoAttributes(index as byte) as string
end function
sub GetData(data$)
- if (Lc <> 0) or (not LePresent()) then SW1SW2 = swLcLeError : exit sub
+ if (len(data$) <> 0) or (not LePresent()) then SW1SW2 = swLcLeError : exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound : exit sub
select case P1P2
@@ -301,57 +304,64 @@ sub ChangeAlgoAttributes(ReadOnly algo as AlgoAttr, ReadOnly index as byte)
end sub
sub PutData(ReadOnly data$)
+ private length as integer
if LePresent() then SW1SW2 = swLcLeError : exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound : exit sub
ResponseLength = 0
+ length = len(data$)
+
select case P1P2
+ case &HDE:
+ if length <> 6 then SW1SW2 = swLcLeError: exit sub
+ if PersAID <> string$(6,0) then SW1SW2 = swConditionOfUseNotMet: exit sub
+ PersAID = data$
case &H0101:
if (AuthStatus and 2) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
PrivateData(1) = data$
case &H0102:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
PrivateData(2) = data$
case &H0103:
if (AuthStatus and 2) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
PrivateData(3) = data$
case &h0104:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
PrivateData(4) = data$
case &H5B:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 39 then SW1SW2 = swLcLeError: exit sub
+ if length > 39 then SW1SW2 = swLcLeError: exit sub
CardHolder = data$
case &H5E:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
Login = data$
case &H5F2D:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 8 then SW1SW2 = swLcLeError: exit sub
+ if length > 8 then SW1SW2 = swLcLeError: exit sub
Lang = data$
case &H5F35:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 1 then SW1SW2 = swLcLeError: exit sub
+ if length > 1 then SW1SW2 = swLcLeError: exit sub
if (data$ <> "1") and (data$ <> "2") and (data$ <> "9") then SW1SW2 = swDataInvalid: exit sub
Sex = asc(data$)
case &H5F50:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 254 then SW1SW2 = swLcLeError: exit sub
+ if length > 254 then SW1SW2 = swLcLeError: exit sub
URL = data$
case &H7F21:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc > 2048 then SW1SW2 = swLcLeError: exit sub
+ if length > 2048 then SW1SW2 = swLcLeError: exit sub
CardHolderCert = data$
case &HC1, &HC2, &HC3:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if (Lc <> 6) then SW1SW2 = swLcLeError: exit sub
+ if (length <> 6) then SW1SW2 = swLcLeError: exit sub
private algo$ as string*6
private algo as AlgoAttr at algo$
algo$ = data$
@@ -359,28 +369,28 @@ sub PutData(ReadOnly data$)
case &HC4:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if Lc <> 1 then SW1SW2 = swLcLeError: exit sub
+ if length <> 1 then SW1SW2 = swLcLeError: exit sub
if (asc(data$) <> 0) and (asc(data$) <> 1) then SW1SW2 = swDataInvalid: exit sub
PW1Status = asc(data$)
case &HC7, &HC8, &HC9:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if (Lc <> 0) and (Lc <> 20) then SW1SW2 = swLcLeError: exit sub
+ if (length <> 0) and (length <> 20) then SW1SW2 = swLcLeError: exit sub
Fingerprints(P1P2 - &HC7) = data$
case &HCA, &HCB, &HCC:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if (Lc <> 0) and (Lc <> 20) then SW1SW2 = swLcLeError: exit sub
+ if (length <> 0) and (length <> 20) then SW1SW2 = swLcLeError: exit sub
CAFingerprints(P1P2 - &HCA) = data$
case &HCE, &HCF, &HD0:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if (Lc <> 0) and (Lc <> 4) then SW1SW2 = swLcLeError: exit sub
+ if (length <> 0) and (length <> 4) then SW1SW2 = swLcLeError: exit sub
GenerationTime(P1P2 - &HCE) = data$
case &HD3:
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if (Lc <> 0) and (Lc < 8) and (Lc > RCmax) then SW1SW2 = swLcLeError: exit sub
+ if (length <> 0) and (length < 8) and (length > RCmax) then SW1SW2 = swLcLeError: exit sub
ResetCode = data$
retries(1) = 3
@@ -404,7 +414,7 @@ sub PutDataExtended(data$)
private pos as integer
private index as byte
- if (Lc = 0) or LePresent() then SW1SW2 = swLcLeError : exit sub
+ if (len(data$) = 0) or LePresent() then SW1SW2 = swLcLeError : exit sub
if P1P2 <> &H3FFF then SW1SW2 = swP1P2Error : exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound : exit sub
ResponseLength = 0
@@ -459,9 +469,8 @@ sub PutDataExtended(data$)
if len(p$) <> AlgoAttributes(index).nbits/8/2 then exit sub
if len(q$) <> AlgoAttributes(index).nbits/8/2 then exit sub
+ ' e should at least be 17 bit (65537) and ebits at max
if (len(e$) < 3) or len(e$) > AlgoAttributes(index).ebits/8 then exit sub
- ' Even with ebits=32 the value 65537 is accepted in the official OpenPGPCard V2
- ' therefore we simply make sure, that e is at least 17 bit and ebits at max
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
@@ -472,7 +481,7 @@ sub PutDataExtended(data$)
end sub
-sub CreateDSI(digestInfo$, index as byte)
+sub CreateDSI(digestInfo$, ByVal index as byte)
private max as integer
' digestInfo must be smaller then 40% of the RSA modulus
@@ -485,13 +494,12 @@ end sub
sub PSO(data$)
private pos as integer
- if Lc = 0 or not LePresent() then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) = 0) or (not LePresent()) then SW1SW2 = swLcLeError: exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound: exit sub
select case P1P2
case &H9E9A: ' signature
if (AuthStatus and 1) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if PW1Status = 0 then AuthStatus = 0
if privateKey(0) = "" then SW1SW2 = swDataNotFound: exit sub
call CreateDSI(data$, 0)
@@ -500,11 +508,13 @@ sub PSO(data$)
call RSAExDecryptRaw(data$, privateKey(0))
if LibError <> 0 then SW1SW2 = swDataInvalid: exit sub
+ ' Reset the AuthStatus after succesful signing operation
+ if PW1Status = 0 then AuthStatus = AuthStatus and 254
+
SignatureCounter = SignatureCounter + 1
- case &H8086: ' decrypt
+ case &H8086: ' decipher
if (AuthStatus and 2) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
- if PW1Status = 0 then AuthStatus = 0
if privateKey(1) = "" then SW1SW2 = swDataNotFound: exit sub
if data$(1) <> chr$(0) then SW1SW2 = swDataInvalid: exit sub
@@ -532,7 +542,7 @@ end sub
sub Authenticate(data$)
- if Lc = 0 or not LePresent() then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) = 0) or (not LePresent()) then SW1SW2 = swLcLeError: exit sub
if P1P2 <> 0 then SW1SW2 = swP1P2Error: exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound: exit sub
@@ -554,7 +564,7 @@ sub GenerateKey(data$)
private seq as TlvPointer
private child as TlvPointer
- if Lc <> 2 or not LePresent() then SW1SW2 = swLcLeError: exit sub
+ if (len(data$) <> 2) or (not LePresent()) then SW1SW2 = swLcLeError: exit sub
if P2 <> 0 or (P1 <> &H80 and P1 <> &H81) then SW1SW2 = swP1P2Error: exit sub
if not OpenPGPAppSelected then SW1SW2 = swDataNotFound : exit sub
@@ -571,8 +581,11 @@ sub GenerateKey(data$)
if P1 = &H80 then
if (AuthStatus and 4) = 0 then SW1SW2 = swAccessNotAllowed: exit sub
WTX 100
- call RSAExGenerateKey(AlgoAttributes(index).nbits,0,AlgoAttributes(index).ebits,"",privateKey(index))
+ ' 0 for ebits and "" for e --> e=65537
+ call RSAExGenerateKey(AlgoAttributes(index).nbits,0,0,"",privateKey(index))
if LibError <> 0 then SW1SW2 = swDataInvalid: exit sub
+
+ ' if we generated a new signing key reset the signature counter
if index = 0 then SignatureCounter = 0
end if
@@ -586,8 +599,10 @@ sub GenerateKey(data$)
call TLVReadTagLength(seq, publicKey, 1)
call TlvNextChild(seq, child, publicKey)
n$ = TLVGetValue(child, publicKey)
+ call LTrim0(n$)
call TlvNextChild(seq, child, publicKey)
e$ = TLVGetValue(child, publicKey)
+ call LTrim0(e$)
data$ = TLV(&H7F49, TLV(&H81, n$) + TLV(&H82, e$))
end sub
@@ -596,7 +611,7 @@ end sub
sub GetChallenge(data$)
private length as integer
if P1P2 <> 0 then SW1SW2 = swP1P2Error : exit sub
- if (Lc <> 0) Or (not LePresent()) then SW1SW2 = swLcLeError : exit sub
+ if (len(data$) <> 0) or (not LePresent()) then SW1SW2 = swLcLeError : exit sub
if Le > MaxChallengeLength then SW1SW2 = swLcLeError : exit sub
length = Le
@@ -612,67 +627,88 @@ sub GetResponse(data$)
length = Le
if Le = 0 then length = 256
- data$ = mid$(cmdout$, 1, length)
- cmdout$ = mid$(cmdout$, length+1)
- if len(cmdout$) > 255 then
+ data$ = left$(cmdio$, length)
+ cmdio$ = mid$(cmdio$, length+1)
+ if len(cmdio$) > 255 then
SW1SW2 = &H6100
- else if len(cmdout$) > 0 then
- SW1SW2 = &H6100 + len(cmdout$)
+ else if len(cmdio$) > 0 then
+ SW1SW2 = &H6100 + len(cmdio$)
end if
call SuspendSW1SW2Processing()
end sub
#endif
+
+#ifdef ExtendedLcLe
+command else CommandDispatcher(cmdio$)
+#else
command else CommandDispatcher(data$)
-#ifnotdef ExtendedLcLe
- if Lc > 255 or Le > 255 then SW1SW2 = swLcLeError: exit command
-Rem if LePresent() and Le = 0 then Le = 256
+ ' in case we do not support extended Lc Le make sure it is not used.
+ private protocol as byte
+ private speed as byte
+ private extended as byte
+ call CommParams(protocol, speed, extended)
+ if extended = 1 then SW1SW2 = swLcLeError: exit command
#endif
- ' Check for valid CLA
+
+ ' Check if CLA is valid
+ ' - only logical channel 0
+ ' - no secure messaging
+ ' - command chaining only in case of short Lc Le
if (CLA and &H03) <> 0 then SW1SW2 = swChannelNotSupported : exit command
if (CLA and &H0C) <> 0 then SW1SW2 = swSMNotSupported : exit command
if (CLA and &HE0) <> 0 then SW1SW2 = swCLANotFound : exit command
#ifdef ExtendedLcLe
if (CLA and &H10) <> 0 then SW1SW2 = swChainingNotSupported : exit command
#else
- ' TODO: error checking: max size for cmdin, INS and P1P2 always the same
- cmdin$ = cmdin$ + data$
- data$ = ""
- if (CLA and &H10) <> 0 then
- exit command
+ ' make sure INS, P1P2 are the same for one chain
+ if oldins = 0 then
+ oldins = INS
+ oldP1P2 = P1P2
+ ' clear cmdio$. It may contain output from previous command
+ if (INS <> &HC0) then cmdio$ = ""
else
- data$ = cmdin$
- cmdin$ = ""
+ if (INS <> oldins) or (oldp1p2 <> P1P2) then SW1SW2 = swChainingError: exit command
end if
+
+ ' skip this if command is GetResponse, otherwise we would destroy the old command output
+ if (INS <> &HC0) then
+ if len(cmdio$) + len(data$) > 2048 then SW1SW2 = swLcLeError: exit command
+ cmdio$ = cmdio$ + data$
+ data$ = ""
+ end if
+ ' is this is not the last part of the chain do nothing and wait for more data
+ if (CLA and &H10) <> 0 then exit command
+
+ oldins = 0
#endif
' Call apropriate subroutine
select case INS
- case &HA4: call SelectFile(data$)
- case &H20: call Verify(data$)
- case &H24: call ChangePIN(data$)
- case &H2C: call ResetCounter(data$)
- case &HCA: call GetData(data$)
- case &HDA: call PutData(data$)
- case &HDB: call PutDataExtended(data$)
- case &H2A: call PSO(data$)
- case &H88: call Authenticate(data$)
- case &H47: call GenerateKey(data$)
+ case &HA4: call SelectFile(cmdio$)
+ case &H20: call Verify(cmdio$)
+ case &H24: call ChangePIN(cmdio$)
+ case &H2C: call ResetCounter(cmdio$)
+ case &HCA: call GetData(cmdio$)
+ case &HDA: call PutData(cmdio$)
+ case &HDB: call PutDataExtended(cmdio$)
+ case &H2A: call PSO(cmdio$)
+ case &H88: call Authenticate(cmdio$)
+ case &H47: call GenerateKey(cmdio$)
#ifnotdef ExtendedLcLe
case &HC0:
call GetResponse(data$)
exit command
#endif
- case &H84: call GetChallenge(data$)
+ case &H84: call GetChallenge(cmdio$)
- case Else: SW1SW2 = swINSNotFound
+ case else: SW1SW2 = swINSNotFound
end select
if SW1SW2 <> swOK then exit command
#ifnotdef ExtendedLcLe
- if ResponseLength = 0 then data$ = ""
- cmdout$ = data$
+ if ResponseLength = 0 then cmdio$ = ""
if LePresent() then call GetResponse(data$)
#endif
diff --git a/card.def b/card.def
index c314065..7880379 100644
--- a/card.def
+++ b/card.def
@@ -1,19 +1,19 @@
Declare Command 0 &HA4 SelectFile(P1=4,P2=0,Data as String)
-Declare Command 0 &HCA GetData(Enable Long,LC=0, Data as String)
-
Declare Command 0 &H20 Verify(P1=0,Pin as String, Disable Le)
Declare Command 0 &H24 ChangePin(Pins as String, Disable Le)
declare command 0 &H2C ResetCounter(P2=&H81,data as string, Disable Le)
+Declare Command 0 &HCA GetData(Enable Long,LC=0, Data as String)
+
Declare Command 0 &HDA PutData(Enable Long, Data as String, Disable Le)
Declare Command 0 &HDB PutDataExtended(Enable Long,P1P2=&H3fff, Data as String, Disable Le)
-declare command 0 &H47 GenerateKey(Enable Long,P2=0, data as string)
declare command 0 &H2A PSO(Enable Long, data as string)
declare command 0 &H88 Authenticate(Enable Long,P1P2=0, data as string)
-Declare Command 0 &H84 GetChallenge(Enable Long,P1=0,P2=0,Lc=0, Data as String)
+declare command 0 &H47 GenerateKey(Enable Long,P2=0, data as string)
+Declare Command 0 &H84 GetChallenge(Enable Long,P1=0,P2=0,Lc=0, Data as String)
diff --git a/card.zcc b/card.zcc
index 04c0977..ec92c0c 100644
--- a/card.zcc
+++ b/card.zcc
@@ -1,28 +1,28 @@
[Main Window]
Left=525
Top=119
-Width=637
-Height=576
+Width=665
+Height=553
State=0
Visible=true
StayOnTop=false
[Watches Window]
-Left=330
-Top=230
-Width=400
-Height=150
+Left=50
+Top=471
+Width=698
+Height=426
State=0
-Visible=false
+Visible=true
StayOnTop=false
[Call Stack Window]
-Left=430
-Top=329
+Left=153
+Top=333
Width=357
Height=228
State=0
-Visible=false
+Visible=true
StayOnTop=false
[I/O Window]
@@ -43,15 +43,35 @@ State=0
Visible=false
StayOnTop=false
-[BasicCard]
-ConfigFile=C:\Programme\BasicCard\Pro\ZC75.zcf
-
[Compiler]
SourceFile=card.bas
ImageFile=true
ListingFile=true
MapFile=true
+[BasicCard]
+ConfigFile=C:\Programme\BasicCard\Pro\ZC75.zcf
+
[Card Reader]
-VirtualReader=1
-PhysicalReader=100
+PhysicalReader=4
+VirtualReader=201
+
+[Watches]
+Watch3=seq
+Watch5=data$
+Watch6=keytemplate
+Watch7=e$
+Watch1=p$
+Watch2=q$
+Watch8=pos
+Watch9=LibError
+Hexadecimal=true
+Watch10=privateKey
+Watch4=cmdio$
+
+[EEPROM]
+MaskCRC=7A473A82
+CRC=FA57A219
+Length=55
+Block0="_UEC{PiXt_/C'<E12>,KJF1AQW:RQ];[Tr|n^UgXy"~dlXq9!`[%;9ZvX:[_8e&?1RY
+StartCRC=E75D0116
diff --git a/project.zcp b/project.zcp
index ecf3958..65329ca 100644
--- a/project.zcp
+++ b/project.zcp
@@ -1,8 +1,8 @@
[ZCT]
-0=Term.zct
+0=term.zct
[ZCC]
-0=Card.zcc
+0=card.zcc
[StartZCT]
0=0
diff --git a/term.bas b/term.bas
index 2f35177..801f192 100644
--- a/term.bas
+++ b/term.bas
@@ -7,9 +7,14 @@ const NoISONames = true
#Include COMMERR.DEF
#include MISC.DEF
#Include CARDUTIL.DEF
+#include tlv.def
+#include rsa.def
declare function bin2hex(s$ as string) as string
declare sub printtlv(tlv as string, indent as byte, text as byte)
+declare sub printstatus(status as integer)
+declare function getPubKey(data$ as string) as string
+declare function genMessage(nbits as integer, data$) as string
' Execution starts here
' Wait for a card
@@ -17,24 +22,147 @@ Call WaitForCard()
public atr$
' Reset the card and check status code SW1SW2
-ResetCard(atr$) : Call CheckSW1SW2()
+ResetCard(atr$) : Call printstatus(SW1SW2)
print "ATR: " + bin2hex(atr$)
public data$
-call SelectFile(Chr$(&HD2,&H76, 0, 1, &H24,1,2,0)) : Call CheckSW1SW2()
+' Check status without SelectFile
+print "Status without SelectFile"
+call Verify(P2=&H83, "12345678"): call printstatus(SW1SW2)
+call ChangePIN(P1P2=&H81, "123456123456"): call printstatus(SW1SW2)
+call ResetCounter(P1=2, "123456"): call printstatus(SW1SW2)
-'call Verify(P2=&H83, "12345678")
-'print "Status:";hex$(SW1SW2)
-data$ = chr$(&Ha4,0)
-call GenerateKey(P1=&H81, data$,Le=512)
-print "Status: ";hex$(SW1SW2)
-call printtlv(data$,2,0)
+call SelectFile(chr$(&HD2,&H76,0,1,&H24,1,2,0)): call printstatus(SW1SW2)
-call PutData(P1P2=&H0101, "Hallo")
-print "Status:";hex$(SW1SW2)
+call PutData(P1P2=&HDE,chr$(0,5,&hde,&had,&hbe,&hef)): call printstatus(SW1SW2)
+exit
+
+call Verify(P2=&H83, "12345678"): call printstatus(SW1SW2)
+call PutData(P1P2=&HC1,chr$(1,4,0,0,32,0)): call printstatus(SW1SW2)
+call PutData(P1P2=&HC2,chr$(1,4,0,0,32,0)): call printstatus(SW1SW2)
+call PutData(P1P2=&HC3,chr$(1,4,0,0,32,0)): call printstatus(SW1SW2)
+
+public signkey$
+public cipherkey$
+public authkey$
+
+' Generate 3 Keys for further testing
+data$ = chr$(&HB6,0)
+call GenerateKey(P1=129,data$): call printstatus(SW1SW2)
+signkey$ = getpubkey(data$)
+
+data$ = chr$(&HB8,0)
+call GenerateKey(P1=129,data$): call printstatus(SW1SW2)
+cipherkey$ = getpubkey(data$)
+
+data$ = chr$(&HA4,0)
+call GenerateKey(P1=129,data$): call printstatus(SW1SW2)
+authkey$ = getpubkey(data$)
+
+' Test multiple signatures
+print "Multiple Signatures"
+call PutData(P1P2=&HC4,chr$(1)): call printstatus(SW1SW2)
+call Verify(P2=&H81,"123456"): call printstatus(SW1SW2)
+
+data$ = chr$(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51)
+call PSO(P1P2=&H9E9A,data$): call printstatus(SW1SW2)
+call RSAExEncryptRaw(data$, signkey$)
+print "Message: ";bin2hex(data$)
+
+data$ = chr$(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51)
+call PSO(P1P2=&H9E9A,data$): call printstatus(SW1SW2)
+
+print "data to long for signature"
+data$ = chr$(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52)
+call PSO(P1P2=&H9E9A,data$): call printstatus(SW1SW2)
+
+' Test single signature
+print "Single Signatures"
+call PutData(P1P2=&HC4,chr$(0)): call printstatus(SW1SW2)
+call Verify(P2=&H81,"123456"): call printstatus(SW1SW2)
+call Verify(P2=&H82,"123456"): call printstatus(SW1SW2)
+
+data$ = chr$(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51)
+call PSO(P1P2=&H9E9A,data$): call printstatus(SW1SW2)
+
+data$ = chr$(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51)
+call PSO(P1P2=&H9E9A,data$): call printstatus(SW1SW2)
+
+
+public testdata$
+
+testdata$ = genMessage(1024, "1234")
+call RSAExEncryptRaw(testdata$, cipherkey$)
+testdata$ = chr$(0)+testdata$
+
+' Test single decipher
+print "single decipher"
+'call Verify(P2=&H82,"123456"): call printstatus(SW1SW2)
+'call PutData(P1P2=&HC4,chr$(0)): call printstatus(SW1SW2)
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+
+' Test multiple decipher
+print "multiple decipher"
+call Verify(P2=&H82,"123456"): call printstatus(SW1SW2)
+call PutData(P1P2=&HC4,chr$(1)): call printstatus(SW1SW2)
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+data$=testdata$
+call PSO(P1P2=&H8086,data$): call printstatus(SW1SW2)
+print "Message: ";data$
+
+
+
+
+
+function genMessage(nbits as integer, data$) as string
+ private padding$
+
+ padding$ = string$(nbits/8-len(data$)-3,&HFF)
+
+ genMessage = chr$(0,2) + padding$ + chr$(0) + data$
+end function
+
+function getPubKey(data$ as string) as string
+ private seq as TlvPointer
+ private child as TlvPointer
+ private n$
+ private e$
+
+ seq.start = 1
+ child.info = 0
+ call TLVReadTagLength(seq, data$, 1)
+ call TlvNextChild(seq, child, data$)
+ n$ = TLVGetValue(child, data$)
+ call TlvNextChild(seq, child, data$)
+ e$ = TLVGetValue(child, data$)
+
+ getPubKey = TLV(&H30, TLV(2,n$)+TLV(2,e$))
+
+end function
+
+sub printstatus(status as integer)
+ private sw as long
+
+ sw = status
+ if sw < 0 then sw = sw and &Hffff
+ print "Status: ";hex$(sw)
+end sub
function bin2hex(s$ as string) as string
private i as integer
diff --git a/term.zct b/term.zct
index e4021b8..b93b6a7 100644
--- a/term.zct
+++ b/term.zct
@@ -1,7 +1,7 @@
[Main Window]
-Left=50
-Top=100
-Width=694
+Left=450
+Top=302
+Width=660
Height=439
State=0
Visible=true