From 9a903d7a7457d10bfcd121c8e8a79c0556722b1c Mon Sep 17 00:00:00 2001 From: Alexandre Dulaunoy Date: Tue, 3 Jan 2017 12:14:13 +0100 Subject: [PATCH] ootp-release-1.03 imported --- basiccard/HOTP.DEF | 69 ++- basiccard/HOTPC.BAS | 840 ++++++++++++-------------- basiccard/HOTPC.IMG | Bin 16737 -> 13570 bytes bcload/bcload.c | 8 +- common/otplib.c | 343 +++++++++-- common/otplib.h | 50 +- common/otpsc.h | 10 +- common/scr.c | 97 ++- common/scr.h | 9 +- common/str.c | 130 +++- common/str.h | 19 +- doc/QUICKSTART | 54 +- doc/TODO | 28 +- doc/bcload.1 | 13 +- doc/bcload.html | 25 +- doc/bcload.sgml | 13 +- doc/htsoft-downloader.1 | 15 +- doc/htsoft-downloader.html | 25 +- doc/htsoft-downloader.sgml | 23 +- doc/otp-control.1 | 79 ++- doc/otp-control.html | 201 +++--- doc/otp-control.sgml | 156 +++-- doc/otp-ov-plugin.1 | 6 +- doc/otp-ov-plugin.html | 23 +- doc/otp-ov-plugin.sgml | 13 +- doc/otp-sca.1 | 39 +- doc/otp-sca.html | 61 +- doc/otp-sca.sgml | 39 +- doc/otp-sct.1 | 29 +- doc/otp-sct.html | 43 +- doc/otp-sct.sgml | 29 +- doc/pam_otp.1 | 4 +- doc/pam_otp.html | 15 +- doc/pam_otp.sgml | 11 +- doc/spyrus-par2.7 | 16 +- doc/spyrus-par2.html | 46 +- doc/spyrus-par2.sgml | 25 +- doc/urd.1 | 6 +- doc/urd.html | 23 +- doc/urd.sgml | 12 +- htsoft-downloader/htsoft-downloader.c | 42 +- otp-control/otp-control.c | 217 ++++--- otp-openvpn/otp-ov-plugin.c | 23 +- otp-pam/pam_otp.c | 30 +- otp-sca/otp-sca.c | 73 ++- otp-sct/otp-sct.c | 23 +- spyrus-par2/main.c | 228 ++++--- urd/urd.c | 44 +- 48 files changed, 2201 insertions(+), 1126 deletions(-) diff --git a/basiccard/HOTP.DEF b/basiccard/HOTP.DEF index 8ed96b3..adb65e3 100644 --- a/basiccard/HOTP.DEF +++ b/basiccard/HOTP.DEF @@ -24,7 +24,7 @@ ' OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ' SUCH DAMAGE. ' -' $Id: HOTP.DEF 13 2009-11-26 16:37:03Z maf $ +' $Id: HOTP.DEF 91 2009-12-28 02:45:25Z maf $ ' @@ -37,8 +37,8 @@ ' INS Name Format CapabilityID '------------------------------------------------------------------------ ' 00 PRDisplay (CLA=C8) - 00000001 -' RecordNumber(byte), DataFormat(byte), DigitCount(byte) -' DecimalPoint(byte), Delay(byte), MoreData(byte), +' RecordNumber(Byte), DataFormat(Byte), DigitCount(Byte) +' DecimalPoint(Byte), Delay(Byte), MoreData(Byte), ' Data(String) ' 40 SetHost Idx,Count,Hostname,HOTPKey 00000002 ' 42 GetHost Idx,Count,Hostname,HOTPKey 00000004 @@ -63,15 +63,26 @@ ' A1 SetEEBlock P1=Idx,eeBlock XXXXXXXX ' -' enable functions +' HOTP display formats ' +Const FMTHEX40 = 1 +Const FMTDEC316 = 2 +Const FMTDEC317 = 3 +Const FMTDEC318 = 4 +Const FMTDEC319 = 5 +Const FMTDEC3110 = 6 +Const FMTDHEX40 = 7 + +' +' enable minimal functions for Spyrus Reader +' 'Const ENABLECSETHOST = 1 'Const ENABLECGETHOST = 1 Const ENABLECGETHOSTNAME = 1 'Const ENABLECGETHOTP = 1 Const ENABLECSETADMINMODE = 1 -'Const ENABLECSETBALANCECARDINDEX = 1 +Const ENABLECSETBALANCECARDINDEX = 1 Const ENABLECSETPIN = 1 Const ENABLECTESTPIN = 1 Const ENABLECGETVERSION = 1 @@ -81,7 +92,7 @@ Const ENABLECGETHOST32 = 1 Const ENABLECGETHOTPCOUNT32 = 1 'Const ENABLECGETHOTPHOST = 1 Const ENABLECGETHOTPHOSTCOUNT32 = 1 -'Const ENABLECPRDISPLAY = 1 +Const ENABLECPRDISPLAY = 1 Const ENABLECCLEARALL = 1 Const ENABLESETREADERKEY = 1 @@ -197,55 +208,55 @@ Const CAPSETREADERKEY = &H00020000 Const CAPSETREADERKEY = &H00000000 #endif -declare command &HC8 &H00 PRDisplay(RecordNumber as Byte, DataFormat as Byte, _ +Declare Command &HC8 &H00 PRDisplay(RecordNumber as Byte, DataFormat as Byte, _ DigitCount as Byte,DecimalPoint as Byte, _ Delay as Byte, MoreData as Byte, _ Data as String) -declare command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _ +Declare Command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _ Hostname as String*12, HOTPKey as String*20) -declare command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _ +Declare Command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _ Hostname as String*12, HOTPKey as String*20) -declare command &H80 &H44 GetHostName(Idx as Byte, myPIN as string*5, _ +Declare Command &H80 &H44 GetHostName(Idx as Byte, myPIN as String*5, _ Hostname as String*12) -declare command &H80 &H46 GetHOTP(Idx as Byte, myPIN as String*5, _ - HOTP as string*5) +Declare Command &H80 &H46 GetHOTP(Idx as Byte, myPIN as String*5, _ + HOTP as String*5) -declare command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20) +Declare Command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20) -declare command &H80 &H4A SetBalanceCardIndex(Idx as Byte) +Declare Command &H80 &H4A SetBalanceCardIndex(Idx as Byte) -declare command &H80 &H4C SetPIN(myPIN as String*5, newPIN as string*5) +Declare Command &H80 &H4C SetPIN(myPIN as String*5, newPIN as String*5) -declare command &H80 &H4E TestPIN(myPIN as String*5) +Declare Command &H80 &H4E TestPIN(myPIN as String*5) -declare command &H80 &H50 GetVersion(V as Byte) +Declare Command &H80 &H50 GetVersion(V as Byte) -declare command &H80 &H52 SetAdminKey(K as String*20) +Declare Command &H80 &H52 SetAdminKey(K as String*20) -declare command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long, _ +Declare Command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long, _ Hostname as String*12, HOTPKey as String*20) -declare command &h80 &H56 GetHost32(Idx as Byte, Count32 as Long, _ +Declare Command &h80 &H56 GetHost32(Idx as Byte, Count32 as Long, _ Hostname as String*12, HOTPKey as String*20) -declare command &H80 &H58 GetHOTPCount32(Idx as Byte, myPIN as String*5, _ - Count32 as Long, HOTP as string*5) +Declare Command &H80 &H58 GetHOTPCount32(Idx as Byte, myPIN as String*5, _ + Count32 as Long, HOTP as String*5) -declare command &H80 &H5A GetHOTPHost(Idx as Byte, myPIN as String*5, _ - HOTP as string*5, Hostname as String*12) +Declare Command &H80 &H5A GetHOTPHost(Idx as Byte, myPIN as String*5, _ + HOTP as String*5, Hostname as String*12) -declare command &H80 &H5C GetHOTPHostCount32(Idx as Byte, myPIN as String*5, _ - Count32 as Long, HOTP as string*5, Hostname as String*12) +Declare Command &H80 &H5C GetHOTPHostCount32(Idx as Byte, myPIN as String*5, _ + Count32 as Long, HOTP as String*5, Hostname as String*12) -declare command &H80 &H5E ClearAll() +Declare Command &H80 &H5E ClearAll() -declare command &H80 &H60 SetReaderKey(readerKey as String*5) +Declare Command &H80 &H60 SetReaderKey(readerKey as String*5) -declare command &H80 &H90 GetCapabilities(Capabilities as Long) +Declare Command &H80 &H90 GetCapabilities(Capabilities as Long) ' ' error codes used diff --git a/basiccard/HOTPC.BAS b/basiccard/HOTPC.BAS index 8def68f..be1a352 100644 --- a/basiccard/HOTPC.BAS +++ b/basiccard/HOTPC.BAS @@ -24,33 +24,66 @@ ' OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ' SUCH DAMAGE. ' -' $Id: HOTPC.BAS 13 2009-11-26 16:37:03Z maf $ +' $Id: HOTPC.BAS 92 2009-12-28 02:45:54Z maf $ ' #include "sha-1.def" #include "preader.def" #include "AlgID.DEF" -#include "commands.def" +#include "Commands.def" #include "hotp.def" +' Disable filesystem +#files 0 + Option Explicit ' number of keys/hosts - max 254. 255 is reserved. Index is 8 bits. -Const HOTPNum = 85 +Const HOTPNum = 50 ' HOTPCodeVersion notes: ' Rev 1 - first production version - feb 2006 ' Rev 2 - disable AdminMode on first usage - safety net ' if left on by mistake. -' Rev 3 - Count32 commands -' - conditional compile commands +' Rev 3 - Count32 Commands +' - conditional compile Commands ' - Get/Set/Test naming standardize ' Rev 4 - release of Rev3 -' Rev 5 - renumber commands, readerKey, getCapabilities +' Rev 5 - renumber Commands, readerKey, getCapabilities ' - ClearALL, checkReaderKey ' Rev 6 - release Rev5 +' Rev 7 - dynamic truncate, decimal HOTP, readerKeyFailCount +' reset in ClearAll, HOTPCommon, move stack vars +' to global, reorg balance reader code +' naming consistency, default 50 systems +' Rev 8 - release Rev7 + +' 20 byte scratch area addressable as 5 32bit vars +public str20 as String*20 +public tmpb1 as Long at str20 +public tmpb2 as Long at str20+4 +public tmpb3 as Long at str20+8 +public tmpb4 as Long at str20+12 +public tmpb5 as Long at str20+16 + +' 32 bit HOTPCount stored 64 bits. Top 32 bits always 0 +public Count64 as String*8 +public Count64low as Long at Count64+4 + +' Truncated 4 or 5 byte HOTP +public HOTPTruncated as String*5 + +' HOTPTruncated aliases for 31 bit decimal formats +public u32 as Long at HOTPTruncated +public u32b0 as Byte at u32 +public u32b1 as Byte at u32+1 +public u32b2 as Byte at u32+2 +public u32b3 as Byte at u32+3 + +' HOTP Format +public HOTPfmt as Byte ' Code version -Const HOTPCodeVersion = 6 +Const HOTPCodeVersion = 8 ' Capabilities (conditionally compiled in functions) eeprom Capabilities as Long = CAPSETHOST + CAPGETHOST + CAPGETHOSTNAME + _ @@ -62,6 +95,7 @@ eeprom Capabilities as Long = CAPSETHOST + CAPGETHOST + CAPGETHOSTNAME + _ CAPGETHOTPHOST + CAPGETHOTPHOSTCOUNT32 + _ CAPPRDISPLAY + CAPCLEARALL + CAPSETREADERKEY +' Default PIN Const DefaultPIN = "28165" ' Default Admin Key @@ -81,22 +115,24 @@ eeprom AdminKey as String*20 = "00000000000000000000" ' this would use less EEPROM space at the cost of more ' CPU cycles (and less battery life) to compute a HOTP -eeprom HOTPKeyI(HOTPNum) as string*20 = &H06,&H06,&H06,&H06,&H06,&H06,&H06, _ +eeprom HOTPKeyI(HOTPNum) as String*20 = &H06,&H06,&H06,&H06,&H06,&H06,&H06, _ &H06,&H06,&H06,&H06,&H06,&H06,&H06, _ &H06,&H06,&H06,&H06,&H06,&H06 -eeprom HOTPKeyO(HOTPNum) as string*20 = &H6C,&H6C,&H6C,&H6C,&H6C,&H6C,&H6C, _ +eeprom HOTPKeyO(HOTPNum) as String*20 = &H6C,&H6C,&H6C,&H6C,&H6C,&H6C,&H6C, _ &H6C,&H6C,&H6C,&H6C,&H6C,&H6C,&H6C, _ &H6C,&H6C,&H6C,&H6C,&H6C,&H6C -eeprom HOTPHost(HOTPNum) as string*12 +' system hostname +eeprom HOTPHost(HOTPNum) as String*12 +' system count eeprom HOTPCount32(HOTPNum) as Long ' Input pad -eeprom IPAD44 as string*44 = &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ +eeprom IPAD44 as String*44 = &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ @@ -104,25 +140,25 @@ eeprom IPAD44 as string*44 = &H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36,&H36, _ ' Output pad -eeprom OPAD44 as string*44 = &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _ +eeprom OPAD44 as String*44 = &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _ &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _ &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _ &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C, _ &H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C,&H5C ' Temporary message digest (inner) -eeprom md1 as string*20 +eeprom eestr20 as String*20 ' PIN - used to deter unauthorized use -eeprom PIN as string*5 = DefaultPIN +eeprom PIN as String*5 = DefaultPIN ' Reader Key. Weak authentication for reader -eeprom readerKey as string*5 = "00000" +eeprom readerKey as String*5 = "00000" ' The balance card can only use one of the host definitions. eeprom BalanceCardIndex = 255 ' Disabled -' if AdminMode is not set some commands require a valid PIN to work. +' if AdminMode is not set some Commands require a valid PIN to work. eeprom AdminMode as Byte = 1 ' Keep track of PIN failures @@ -131,7 +167,136 @@ eeprom readerKeyFailCount as Byte = 0 Const MaxPINFail = 10 Const MaxReaderKeyFail = 2 -Function CheckPIN(myPIN as string*5) as Byte +declare Sub Truncate(Idx as Byte) + +declare Sub HOTPCommon(ReadOnly Idx as Byte, ReadOnly Count as Long, _ + ReadOnly myPIN as String*5, ReadOnly readerKey as String*5) + +declare Function CheckReaderKey(ReadOnly Idx as Byte, _ + ReadOnly myKey as String*5) as Byte + +declare Function CheckPIN(ReadOnly myPIN as String*5) as Byte + +declare Function CheckAdmin() as Byte + +declare Function CheckIndex(Idx as Byte) as Byte + + +' Common HOTP generation code +Sub HOTPCommon(ReadOnly Idx as Byte, ReadOnly Count32 as Long, _ + ReadOnly myPIN as String*5, ReadOnly readerKey as String*5) + + ' disable admin mode on first use. + if (AdminMode = 1) then + AdminMode = 0 + end if + + ' don't allow operations with default pin + if myPIN = DefaultPIN then + SW1SW2 = swAccessDenied + Exit + end if + + ' Check reader access + if CheckReaderKey(Idx, readerKey) <> 0 then + SW1SW2 = swAccessDenied + Exit + end if + + if CheckIndex(Idx) <> 0 then + SW1SW2 = swDataNotFound + Exit + end if + + ' when Count32 == 0, use stored count + if Count32 <> 0 then + Count64low = Count32 + else + Count64low = HOTPCount32(Idx) + end if + + Call ShaStart() + Call ShaAppend(HOTPKeyI(Idx)) + Call ShaAppend(IPAD44) + Call ShaAppend(Count64) + str20 = ShaEnd() + + Call ShaStart() + Call ShaAppend(HOTPKeyO(Idx)) + Call ShaAppend(OPAD44) + Call ShaAppend(str20) + str20 = ShaEnd() + + Disable OverflowCheck + HOTPCount32(Idx) = Count64low + 1 + Enable OverflowCheck + + ' Set HOTPTruncated + Call Truncate(Idx) + +End Sub ' HOTPCommon + +' Convert 160 bit String to 4 or 5 Bytes and format for reader +Sub Truncate(Idx as Byte) + private offset as Byte + + HOTPfmt = 0 + + if (asc(HOTPHost(Idx)(12)) AND &H80) then + HOTPfmt = 1 + end if + + if (asc(HOTPHost(Idx)(11)) AND &H80) then + HOTPfmt = HOTPfmt or 2 + end if + + if (asc(HOTPHost(Idx)(10)) AND &H80) then + HOTPfmt = HOTPfmt or 4 + end if + +' future? +' if (asc(HOTPHost(Idx)(9)) AND &H80) then +' HOTPfmt = HOTPfmt or 8 +' end if + +' not suport on ZC3.9 card +' HOTPfmt = (asc(HOTPHost(Idx)(12)) AND &H80) SHRL 7 +' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(11)) AND &H80) SHRL 6) +' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(10)) AND &H80) SHRL 5) +' HOTPfmt = fmt OR ((asc(HOTPHost(Idx)(9)) AND &H80) SHRL 4) + + if (HOTPfmt = FMTHEX40) or (HOTPfmt = 0) then + HOTPTruncated = Left$(str20,5) + Exit Sub + end if + + offset = asc(str20(20)) and &H0F + + if (HOTPfmt = FMTDHEX40) then + HOTPTruncated = Mid$(str20,offset+1,5) + Exit Sub + end if + + ' u32b0..3 are bytes of u32 alias for HOTPtruncated + u32b0 = asc(str20(offset+1)) and &H7F + u32b1 = asc(str20(offset+2)) + u32b2 = asc(str20(offset+3)) + u32b3 = asc(str20(offset+4)) + + if (HOTPfmt = FMTDEC316) then + u32 = u32 mod 1000000 + elseif (HOTPfmt = FMTDEC317) then + u32 = u32 mod 10000000 + elseif (HOTPfmt = FMTDEC318) then + u32 = u32 mod 100000000 + elseif (HOTPfmt = FMTDEC319) then + u32 = u32 mod 1000000000 + ' FMTDEC3110 does not require mod + end if + +End Sub ' Truncate + +Function CheckPIN(ReadOnly myPIN as String*5) as Byte if AdminMode = 1 then CheckPIN = 0 ' success @@ -149,10 +314,13 @@ Function CheckPIN(myPIN as string*5) as Byte end if end if end if -end Function -Function CheckReaderKey(idx as Byte, myKey as String*5) as Byte - if (Asc(HOTPHost(idx)(2)) AND &H80) then +End Function ' CheckPIN + +Function CheckReaderKey(ReadOnly Idx as Byte, _ + ReadOnly myKey as String*5) as Byte + + if (Asc(HOTPHost(Idx)(2)) AND &H80) then if myKey <> readerKey then readerKeyFailCount = readerKeyFailCount + 1 if (readerKeyFailCount >= MAXReaderKeyFail) then @@ -166,171 +334,33 @@ Function CheckReaderKey(idx as Byte, myKey as String*5) as Byte else CheckReaderKey = 0 'Success end if -end Function + +End Function ' CheckReaderKey Function CheckAdmin() as Byte + if AdminMode <> 1 then CheckAdmin = 1 ' fail else CheckAdmin = 0 ' success end if -end Function + +End Function ' CheckAdmin Function CheckIndex(Idx as Byte) as Byte + if Idx > HOTPNum then CheckIndex = 1 else CheckIndex = 0 end if -end function -' -' The balance reader doesn't wait long for a reponse so the HMAC must be -' broken up into steps -' -' HMAC as defined in RFC2104 is H(K XOR opad, H(K XOR ipad, text)) -' where K is the key -' ipad=0x36 -' opad=0x5c -' H=SHA-160 -' text=Count -' - -#ifdef ENABLEPRDISPLAY -Command &HC8 &H00 PRDisplay(RecordNumber as Byte, DataFormat as Byte, _ - DigitCount as Byte,DecimalPoint as Byte, _ - Delay as Byte, MoreData as Byte, _ - Data as String) - - private str11 as string*11 - private str8 as string*8 - private str4 as string*4 at str8+4 - private low as long at str8+4 - private high as long at str8 - - if BalanceCardIndex = 255 then - data = "Not Enabled" - dataFormat = PRAlpha - exit command - end if - - select case RecordNumber - - case 0 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 0 - Delay = 1 - MoreData = PRMoreData - - ' disable admin mode on first use. - if (AdminMode = 1) then - AdminMode = 0 - end if - - low = HOTPCount32(0) - - ' Display VER1-count - data = "VER1-" + hex$(low) - - ' start inner hash of HMAC SHA-160(K XOR ipad,text) - call ShaStart() - call ShaAppend(HOTPKeyI(0)) - - case 1 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 6 - Delay = 1 - MoreData = PRMoreData - data = "HOTP" - - low = HOTPcount(0) - - ' inner hash still working - call ShaAppend(IPAD44) - call ShaAppend(str8) - - case 2 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 5 - Delay = 1 - MoreData = PRMoreData - Data = "HOTP" - - ' done with inner hash. Store temp result in md1 - md1 = ShaEnd() - - case 3 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 4 - Delay = 1 - MoreData = PRMoreData - Data = "HOTP" - - ' start outer hash H(K XOR opad, inner) - call ShaStart() - call ShaAppend(HOTPKeyO(0)) - - case 4 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 3 - Delay = 1 - MoreData = PRMoreData - data = "HOTP" - - ' outer still working. - call ShaAppend(OPAD44) - - case 5 - DataFormat = PRAlpha - DigitCount = 0 - DecimalPoint = 2 - Delay = 1 - MoreData = PRMoreData - data = "HOTP" - - ' outer still working... - call ShaAppend(md1) - - ' Increment Count just before displaying result. - - Disable OverflowCheck - HOTPCount32(0) = HOTPCount32(0) + 1 - Enable OverflowCheck - - case 6 - DataFormat = PRHex - DigitCount = 10 - DecimalPoint = 0 - Delay = 10000 / PRDelayUnits ' display 10 seconds - MoreData = PRNoMoreData - - ' finish with outer, display top 40 bits in hex (no leading 0's). - str11 = "000" + left$(ShaEnd(),8) - data = left$(str11,8) - - case else - ' should not happen - SW1SW2=swDataNotFound - end select -End Command -#endif ' ENABLECPRDISPLAY +End Function ' CheckIndex #ifdef ENABLECSETHOST -command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _ +Command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _ HostName as String*12, HOTPKey as String*20) - private tmp as string*20 - private tmpb1 as long at tmp - private tmpb2 as long at tmp+4 - private tmpb3 as long at tmp+8 - private tmpb4 as long at tmp+12 - private tmpb5 as long at tmp+16 - if CheckAdmin() <> 0 then SW1SW2 = swAccessDenied Exit @@ -345,41 +375,33 @@ command &H80 &H40 SetHost(Idx as Byte, Count as Integer, _ ' HOTPKey(n) = K ' store K XOR IPAD - tmp = HOTPKey + str20 = HOTPKey tmpb1 = tmpb1 xor &H36363636 tmpb2 = tmpb2 xor &H36363636 tmpb3 = tmpb3 xor &H36363636 tmpb4 = tmpb4 xor &H36363636 tmpb5 = tmpb5 xor &H36363636 - HOTPKeyI(idx) = tmp + HOTPKeyI(Idx) = str20 ' store K XOR OPAD - tmp = HOTPKey + str20 = HOTPKey tmpb1 = tmpb1 xor &H5C5C5C5C tmpb2 = tmpb2 xor &H5C5C5C5C tmpb3 = tmpb3 xor &H5C5C5C5C tmpb4 = tmpb4 xor &H5C5C5C5C tmpb5 = tmpb5 xor &H5C5C5C5C - HOTPKeyO(idx) = tmp + HOTPKeyO(Idx) = str20 HOTPCount32(Idx) = Count HOTPHost(Idx) = HostName -end command +End Command ' SetHost #endif 'ENABLECSETHOST #ifdef ENABLECGETHOST -' GetHost -command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _ +Command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _ HostName as String*12, HOTPKey as String*20) - private tmp as string*20 - private tmpb1 as long at tmp - private tmpb2 as long at tmp+4 - private tmpb3 as long at tmp+8 - private tmpb4 as long at tmp+12 - private tmpb5 as long at tmp+16 - if CheckAdmin() <> 0 then sw1sw2 = swAccessDenied Exit @@ -395,20 +417,20 @@ command &H80 &H42 GetHost(Idx as Byte, Count as Integer, _ ' load K XOR IPAD ' could also do this with OPAD... - tmp = HOTPKeyI(Idx) + str20 = HOTPKeyI(Idx) tmpb1 = tmpb1 xor &H36363636 tmpb2 = tmpb2 xor &H36363636 tmpb3 = tmpb3 xor &H36363636 tmpb4 = tmpb4 xor &H36363636 tmpb5 = tmpb5 xor &H36363636 - HOTPKey = tmp + HOTPKey = str20 -end command +End Command ' GetHost #endif 'ENABLECGETHOST #ifdef ENABLECGETHOSTNAME -command &H80 &H44 GetHostName(Idx as Byte, myPIN as String*5,_ +Command &H80 &H44 GetHostName(Idx as Byte, myPIN as String*5,_ HostName as String*12) if CheckPIN(myPIN) <> 0 then @@ -421,68 +443,22 @@ command &H80 &H44 GetHostName(Idx as Byte, myPIN as String*5,_ Exit end if - HostName = HOTPHost(idx) + HostName = HOTPHost(Idx) -end command +End Command ' GetHostName #endif 'ENABLECGETHOSTNAME #ifdef ENABLECGETHOTP -command &H80 &H46 GetHOTP(Idx as Byte, myPIN as String*5, HOTP as String*5) +Command &H80 &H46 GetHOTP(Idx as Byte, myPIN as String*5, HOTP as String*5) - private str8 as string*8 - private low as long at str8+4 + Call HOTPCommon(Idx, 0, myPIN, HOTP) + HOTP = HOTPTruncated - if CheckPIN(myPIN) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - ' disable admin mode on first use. - if (AdminMode = 1) then - AdminMode = 0 - end if - - ' don't allow operations with default pin - if myPIN = DefaultPIN then - SW1SW2 = swAccessDenied - Exit - end if - - ' Check reader access - if CheckReaderKey(Idx, HOTP) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - if CheckIndex(Idx) <> 0 then - SW1SW2 = swDataNotFound - Exit - end if - - low = HOTPCount32(idx) - - call ShaStart() - call ShaAppend(HOTPKeyI(idx)) - call ShaAppend(IPAD44) - call ShaAppend(str8) - md1 = ShaEnd() - - call ShaStart() - call ShaAppend(HOTPKeyO(idx)) - call ShaAppend(OPAD44) - call ShaAppend(md1) - - Disable OverflowCheck - HOTPCount32(idx) = low + 1 - Enable OverflowCheck - - HOTP = left$(ShaEnd(),5) - -end command +End Command ' GetHOTP #endif 'ENABLECGETHOTP #ifdef ENABLECSETADMINMODE -command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20) +Command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20) if K <> AdminKey then SW1SW2 = swAccessDenied @@ -490,24 +466,24 @@ command &H80 &H48 SetAdminMode(Mode as Byte, K as String*20) AdminMode = Mode end if -end command +End Command ' SetAdminMode #endif 'ENABLECSETADMINMODE #ifdef ENABLECSETBALANCECARDINDEX -command &H80 &H4A SetBalanceCardIndex(Idx as Byte) +Command &H80 &H4A SetBalanceCardIndex(Idx as Byte) if CheckAdmin() <> 0 then SW1SW2 = swAccessDenied - exit + Exit else BalanceCardIndex = Idx end if -end command +End Command ' SetBalanceCardIndex #endif 'ENABLECSETBALANCECARDINDEX #ifdef ENABLECSETPIN -command &H80 &H4C SetPIN(myPIN as String*5, newPIN as String*5) +Command &H80 &H4C SetPIN(myPIN as String*5, newPIN as String*5) if CheckPIN(myPIN) <> 0 then SW1SW2 = swAccessDenied @@ -515,11 +491,11 @@ command &H80 &H4C SetPIN(myPIN as String*5, newPIN as String*5) PIN = newPIN end if -end command +End Command ' SetPIN #endif 'ENABLECSETPIN #ifdef ENABLECTESTPIN -command &H80 &H4E TestPIN(myPIN as String*5) +Command &H80 &H4E TestPIN(myPIN as String*5) private t as Byte t = CheckPIN(myPIN) @@ -532,19 +508,19 @@ command &H80 &H4E TestPIN(myPIN as String*5) end if end if -end command +End Command ' TestPIN #endif 'ENABLECTESTPIN #ifdef ENABLECGETVERSION -command &H80 &H50 GetVersion(V as Byte) +Command &H80 &H50 GetVersion(V as Byte) V = HOTPCodeVersion -end command +End Command ' GetVersion #endif 'ENABLECGETVERSION #ifdef ENABLECSETADMINKEY -command &H80 &H52 SetAdminKey(K as String*20) +Command &H80 &H52 SetAdminKey(K as String*20) if CheckAdmin() <> 0 then sw1sw2 = swAccessDenied @@ -552,20 +528,13 @@ command &H80 &H52 SetAdminKey(K as String*20) end if AdminKey = K -end command +End Command ' SetAdminKey #endif 'ENABLECSETADMINKEY #ifdef ENABLECSETHOST32 -command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long,_ +Command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long,_ HostName as String*12, HOTPKey as String*20) - private tmp as string*20 - private tmpb1 as long at tmp - private tmpb2 as long at tmp+4 - private tmpb3 as long at tmp+8 - private tmpb4 as long at tmp+12 - private tmpb5 as long at tmp+16 - if CheckAdmin() <> 0 then SW1SW2 = swAccessDenied Exit @@ -583,37 +552,30 @@ command &H80 &H54 SetHost32(Idx as Byte, Count32 as Long,_ ' HOTPKey(n) = K ' store K XOR IPAD - tmp = HOTPKey + str20 = HOTPKey tmpb1 = tmpb1 xor &H36363636 tmpb2 = tmpb2 xor &H36363636 tmpb3 = tmpb3 xor &H36363636 tmpb4 = tmpb4 xor &H36363636 tmpb5 = tmpb5 xor &H36363636 - HOTPKeyI(idx) = tmp + HOTPKeyI(Idx) = str20 ' store K XOR OPAD - tmp = HOTPKey + str20 = HOTPKey tmpb1 = tmpb1 xor &H5C5C5C5C tmpb2 = tmpb2 xor &H5C5C5C5C tmpb3 = tmpb3 xor &H5C5C5C5C tmpb4 = tmpb4 xor &H5C5C5C5C tmpb5 = tmpb5 xor &H5C5C5C5C - HOTPKeyO(idx) = tmp + HOTPKeyO(Idx) = str20 -end command +End Command ' SetHost32 #endif 'ENABLECSETHOST32 #ifdef ENABLECGETHOST32 -command &H80 &H56 GetHost32(Idx as Byte, Count32 as Long,_ +Command &H80 &H56 GetHost32(Idx as Byte, Count32 as Long,_ HostName as String*12, HOTPKey as String*20) - private tmp as string*20 - private tmpb1 as long at tmp - private tmpb2 as long at tmp+4 - private tmpb3 as long at tmp+8 - private tmpb4 as long at tmp+12 - private tmpb5 as long at tmp+16 - if CheckAdmin() <> 0 then sw1sw2 = swAccessDenied Exit @@ -629,200 +591,52 @@ command &H80 &H56 GetHost32(Idx as Byte, Count32 as Long,_ ' load K XOR IPAD ' could also do this with OPAD... - tmp = HOTPKeyI(Idx) + str20 = HOTPKeyI(Idx) tmpb1 = tmpb1 xor &H36363636 tmpb2 = tmpb2 xor &H36363636 tmpb3 = tmpb3 xor &H36363636 tmpb4 = tmpb4 xor &H36363636 tmpb5 = tmpb5 xor &H36363636 - HOTPKey = tmp + HOTPKey = str20 -end command +End Command ' GetHost32 #endif 'ENABLECGETHOST32 #ifdef ENABLECGETHOTPCOUNT32 -command &H80 &H58 GetHOTPCount32(Idx as Byte, myPIN as String*5,_ +Command &H80 &H58 GetHOTPCount32(Idx as Byte, myPIN as String*5,_ Count32 as Long, HOTP as String*5) - private str8 as string*8 - private low as long at str8+4 + Call HOTPCommon(Idx, Count32, myPIN, HOTP) + HOTP = HOTPTruncated - if CheckPIN(myPIN) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - ' disable admin mode on first use. - if (AdminMode = 1) then - AdminMode = 0 - end if - - ' don't allow operations with default pin - if myPIN = DefaultPIN then - SW1SW2 = swAccessDenied - Exit - end if - - ' Check reader access - if CheckReaderKey(Idx, HOTP) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - if CheckIndex(Idx) <> 0 then - SW1SW2 = swDataNotFound - Exit - end if - - ' when Count32 == 0, use stored count - if Count32 <> 0 then - low = Count32 - else - low = HOTPCount32(idx) - end if - - call ShaStart() - call ShaAppend(HOTPKeyI(idx)) - call ShaAppend(IPAD44) - call ShaAppend(str8) - md1 = ShaEnd() - - call ShaStart() - call ShaAppend(HOTPKeyO(idx)) - call ShaAppend(OPAD44) - call ShaAppend(md1) - - Disable OverflowCheck - HOTPCount32(idx) = low + 1 - Enable OverflowCheck - - HOTP = left$(ShaEnd(),5) - -end command +End Command ' GetHOTPCount32 #endif 'ENABE_GETHOTPCOUNT32 #ifdef ENABLECGETHOTPHOST -command &H80 &H5A GetHOTPHost(Idx as Byte, myPIN as String*5,_ +Command &H80 &H5A GetHOTPHost(Idx as Byte, myPIN as String*5,_ HOTP as String*5, HostName as String*12) - private str8 as string*8 - private low as long at str8+4 - - if CheckPIN(myPIN) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - ' disable admin mode on first use. - if (AdminMode = 1) then - AdminMode = 0 - end if - - ' don't allow operations with default pin - if myPIN = DefaultPIN then - SW1SW2 = swAccessDenied - Exit - end if - - ' Check reader access - if CheckReaderKey(Idx, HOTP) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - if CheckIndex(Idx) <> 0 then - SW1SW2 = swDataNotFound - Exit - end if - - low = HOTPCount32(idx) - - call ShaStart() - call ShaAppend(HOTPKeyI(idx)) - call ShaAppend(IPAD44) - call ShaAppend(str8) - md1 = ShaEnd() - - call ShaStart() - call ShaAppend(HOTPKeyO(idx)) - call ShaAppend(OPAD44) - call ShaAppend(md1) - - Disable OverflowCheck - HOTPCount32(idx) = low + 1 - Enable OverflowCheck - - HOTP = left$(ShaEnd(),5) + Call HOTPCommon(Idx, 0, myPIN, HOTP) + HOTP = HOTPTruncated HostName = HOTPHost(Idx) -end command +End Command ' GetHOTPHost #endif 'ENABLECGETHOTPHOST #ifdef ENABLECGETHOTPHOSTCOUNT32 -command &H80 &H5C GetHOTPHostCount32(Idx as Byte, myPIN as String*5,_ +Command &H80 &H5C GetHOTPHostCount32(Idx as Byte, myPIN as String*5,_ Count32 as Long, HOTP as String*5, HostName as String*12) - private str8 as string*8 - private low as long at str8+4 - - if CheckPIN(myPIN) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - ' disable admin mode on first use. - if (AdminMode = 1) then - AdminMode = 0 - end if - - ' don't allow operations with default pin - if myPIN = DefaultPIN then - SW1SW2 = swAccessDenied - Exit - end if - - ' Check reader access - if CheckReaderKey(Idx, HOTP) <> 0 then - SW1SW2 = swAccessDenied - Exit - end if - - if CheckIndex(Idx) <> 0 then - SW1SW2 = swDataNotFound - Exit - end if - - ' when Count32 == 0, use stored count - if Count32 <> 0 then - low = Count32 - else - low = HOTPCount32(idx) - end if - - call ShaStart() - call ShaAppend(HOTPKeyI(idx)) - call ShaAppend(IPAD44) - call ShaAppend(str8) - md1 = ShaEnd() - - call ShaStart() - call ShaAppend(HOTPKeyO(idx)) - call ShaAppend(OPAD44) - call ShaAppend(md1) - - Disable OverflowCheck - HOTPCount32(idx) = low + 1 - Enable OverflowCheck - - HOTP = left$(ShaEnd(),5) + Call HOTPCommon(Idx, Count32, myPIN, readerKey) + HOTP = HOTPTruncated HostName = HOTPHost(Idx) -end command +End Command ' GetHOTPHostCount32 #endif 'ENABLECGETHOTPHOSTCOUNT32 #ifdef ENABLECCLEARALL -command &H80 &H5E ClearAll() +Command &H80 &H5E ClearAll() private i,j as Integer if CheckAdmin() <> 0 then @@ -842,17 +656,19 @@ command &H80 &H5E ClearAll() PINFailCount = 0 + readerKeyFailCount = 0 + AdminMode = 1 AdminKey = "00000000000000000000" PIN = DefaultPIN -end command +End Command ' ClearAll #endif 'ENABLECCLEARALL #ifdef ENABLESETREADERKEY -command &H80 &H60 SetReaderKey(myKey as String*5) +Command &H80 &H60 SetReaderKey(myKey as String*5) if CheckAdmin() <> 0 then SW1SW2 = swAccessDenied @@ -861,15 +677,157 @@ command &H80 &H60 SetReaderKey(myKey as String*5) readerKey = myKey -end command - +End Command ' SetReaderKey #endif 'ENABLECSETREADERKEY - -command &H80 &H90 GetCapabilities(C as Long) +Command &H80 &H90 GetCapabilities(C as Long) C = Capabilities -end command +End Command ' GetCapabilities +' +' The balance reader doesn't wait Long for a reponse so the HMAC must be +' computed in steps +' +#ifdef ENABLECPRDISPLAY +Command &HC8 &H00 PRDisplay(RecordNumber as Byte, DataFormat as Byte, _ + DigitCount as Byte,DecimalPoint as Byte, _ + Delay as Byte, MoreData as Byte, _ + Data as String) + + select case RecordNumber + + case 0 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 0 + Delay = 1 + MoreData = PRMoreData + + ' disable admin mode on first use. + if (AdminMode = 1) then + AdminMode = 0 + end if + + if BalanceCardIndex = 255 then + data = "Not Enabled" + dataFormat = PRAlpha + Exit Command + end if + + Count64low = HOTPCount32(BalanceCardIndex) + + ' Display VER8-count + data = "VER8-" + hex$(Count64low) + + ' start inner hash of HMAC SHA-160(K XOR ipad,text) + Call ShaStart() + Call ShaAppend(HOTPKeyI(BalanceCardIndex)) + + case 1 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 6 + Delay = 1 + MoreData = PRMoreData + data = "HOTP" + + Count64low = HOTPcount32(BalanceCardIndex) + + ' inner hash still working + Call ShaAppend(IPAD44) + Call ShaAppend(Count64) + + case 2 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 5 + Delay = 1 + MoreData = PRMoreData + Data = "HOTP" + + ' done with inner hash. Store temp result in eestr20 while + ' balance reader resets + eestr20 = ShaEnd() + + case 3 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 4 + Delay = 1 + MoreData = PRMoreData + Data = "HOTP" + + ' start outer hash H(K XOR opad, inner) + Call ShaStart() + Call ShaAppend(HOTPKeyO(BalanceCardIndex)) + + case 4 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 3 + Delay = 1 + MoreData = PRMoreData + data = "HOTP" + + ' outer still working. + Call ShaAppend(OPAD44) + + case 5 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 2 + Delay = 1 + MoreData = PRMoreData + data = "HOTP" + + ' outer still working... + Call ShaAppend(eestr20) + + ' Increment Count just before displaying result. + + Disable OverflowCheck + HOTPCount32(BalanceCardIndex) = HOTPCount32(BalanceCardIndex) + 1 + Enable OverflowCheck + + case 6 + DataFormat = PRAlpha + DigitCount = 0 + DecimalPoint = 1 + Delay = 1 + MoreData = PRMoreData + data = "HOTP" + + ' finish with outer + eestr20 = ShaEnd() + + case 7 + Delay = 10000 / PRDelayUnits ' display 10 seconds + DecimalPoint = 0 + MoreData = PRNoMoreData + str20 = eestr20 + ' sets HOTPfmt, HOTPTruncated + Call Truncate(BalanceCardIndex) + + if (HOTPfmt = 0) or (HOTPfmt = FMTHEX40) or (HOTPfmt = FMTDHEX40) then + DataFormat = PRHex + DigitCount = 10 + ' data must be 8 Bytes Long. 3 high order Bytes ignored by reader + data = "000" + HOTPTruncated + else + DataFormat = PRNum + DigitCount = 10 + ' data must be 4 Bytes Long. + data = Left$(HOTPTruncated,4) + end if + + case else + ' should not happen + SW1SW2=swDataNotFound + end select + +End Command ' PRDisplay + +#endif ' ENABLECPRDISPLAY diff --git a/basiccard/HOTPC.IMG b/basiccard/HOTPC.IMG index fad9a2a8d1f89a88b9554cd2f171ced08b86e1b2..8b65ccf1fa02cccd0f5d2a89a44bf6659f4003cb 100644 GIT binary patch literal 13570 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 diff --git a/bcload/bcload.c b/bcload/bcload.c index 99d5e03..9d47365 100644 --- a/bcload/bcload.c +++ b/bcload/bcload.c @@ -26,7 +26,7 @@ * * Ported from ZeitControl bcload.bas and download.bas sample source * - * $Id: bcload.c 13 2009-11-26 16:37:03Z maf $ + * $Id: bcload.c 90 2009-12-28 02:44:52Z maf $ */ #include @@ -120,7 +120,7 @@ int main(int argc, char **argv) paranoid = 1; debug = 0; verbose = 0; - reader = SCR_DEFAULT_READER; + reader = (char*)0L; list_readers = 0; /* no */ scrctx = (struct scr_ctx*)0L; img_fname = "HOTPC.IMG"; @@ -700,8 +700,8 @@ void bcimg_read_version_section(struct bcimg *bcimg) * next two bytes are version number of oldest software that * can read the image file. Must be > 5.22 */ - if ((version[2] > 5) || ((version[2] == 5) && (version[3] > 22))) - xerr_errx(1, "bcimg_read_version_section(): Unknown image file version."); + if ((version[2] > 5) || ((version[2] == 5) && (version[3] > 71))) + xerr_errx(1, "bcimg_read_version_section(): Untested image file version."); } /* bcimg_read_version_section */ diff --git a/common/otplib.c b/common/otplib.c index 461860e..f5d6688 100644 --- a/common/otplib.c +++ b/common/otplib.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otplib.c 18 2009-11-26 19:40:06Z maf $ + * $Id: otplib.c 84 2009-12-27 17:29:51Z maf $ */ #include @@ -48,9 +48,12 @@ #include "str.h" #include "otpsc.h" -char *otp_l_status[] = {"error", "active", "inactive", "disabled"}; -char *otp_l_format[] = {"error", "hex40"}; -char *otp_l_type[] = {"error", "HOTP"}; +char *otp_status_l[] = {"error", "active", "inactive", "disabled"}; +char *otp_format_l[] = {"error", "hex40", "dhex40", "dec31.6", "dec31.7", + "dec31.8", "dec31.9", "dec31.10"}; +char *otp_type_l[] = {"error", "HOTP"}; + +char *otp_flags_l[] = {"display-count"}; /* * One Time Password library with HOTP implementation. @@ -66,6 +69,9 @@ char *otp_l_type[] = {"error", "HOTP"}; * otp_hotp_hex40_auth() HOTP 40 bit hex key authentication * otp_hotp_hex40_crsp() HOTP 40 bit hex key challenge response generator * + * otp_hotp_dec31_auth() HOTP 31 bit decimal key authentication + * otp_hotp_dec31_crsp() HOTP 31 bit decimal key challenge response generator + * **** * * otp_db_open() open OTP db @@ -355,9 +361,10 @@ int otp_hotp_hex40_auth(struct otp_ctx *otpctx, struct otp_user *ou, char *crsp, int window) { uint64_t tmp_count; + uint8_t offset; u_int rlen; int i; - u_char result[EVP_MAX_MD_SIZE], decoded[5]; + u_char result[EVP_MAX_MD_SIZE], decoded[5], dt[5]; if (otp_db_valid(otpctx, "otp_hotp_hex40_auth") < 0) return -1; @@ -398,9 +405,122 @@ int otp_hotp_hex40_auth(struct otp_ctx *otpctx, struct otp_user *ou, SWAP64(tmp_count) #endif /* BYTE_ORDER */ - /* compare the top 40 bits to authenticate user, match then return good */ - if (!bcmp(decoded, &result, 5)) { - ou->count = tmp_count+1; + if (ou->format == OTP_FORMAT_HEX40) { + + /* compare top 40 bits to authenticate user, match then AUTH_PASS */ + if (!bcmp(decoded, &result, 5)) { + ou->count = tmp_count+1; + return OTP_AUTH_PASS; + } + + } else if (ou->format == OTP_FORMAT_DHEX40) { + + offset = result[19] & 0xf; + + dt[0] = result[offset]; dt[1] = result[offset+1]; + dt[2] = result[offset+2]; dt[3] = result[offset+3]; + dt[4] = result[offset+4]; + + /* compare dynamic 40 bits to authenticate user, match then AUTH_PASS */ + if (!bcmp(decoded, &dt, 5)) { + ou->count = tmp_count+1; + return OTP_AUTH_PASS; + } + + } /* ou->format */ + + } /* window */ + + return OTP_AUTH_FAIL; + +} /* otp_hotp_hex40_auth */ + +/* + * function: otp_hotp_dec31_auth() + * + * validate challenge HOTP 31 bit decimal format challenge response + * for user ou with window. + * + * arguments: + * ou - otp user struct + * crsp - user response + * window - window of challenge responses to attempt + * + * return: OTP_ERROR - error + * OTP_AUTH_PASS - user authenticated + * OTP_AUTH_FAIL - user not authenticated + * + */ +int otp_hotp_dec31_auth(struct otp_ctx *otpctx, struct otp_user *ou, + char *crsp, int window) +{ + uint64_t tmp_count, mod64u; + uint32_t crsp32u, tmp32u, hotp32u; + uint8_t offset; + u_int rlen; + u_char result[EVP_MAX_MD_SIZE]; + int i; + char *endptr; + + if (otp_db_valid(otpctx, "otp_hotp_dec31_auth") < 0) + return -1; + + crsp32u = strtoul(crsp, &endptr, 10); + + if (*endptr) { + xerr_warnx("strtoul(%s): failed at %c.", crsp, *endptr); + return OTP_AUTH_FAIL; + } + + tmp_count = ou->count; + + /* try to authenticate with count, incrementing count up to count+window */ + for (i = 0; i < window; ++i, ++tmp_count) { + + /* HOTP is big endian */ +#if BYTE_ORDER == LITTLE_ENDIAN + SWAP64(tmp_count) +#endif /* BYTE_ORDER */ + + /* compute expected response to challenge */ + if (!HMAC(EVP_sha1(), ou->key, 20, (void*)&tmp_count, 8, + result, &rlen)) { + if (otpctx->verbose) + xerr_warnx("HMAC(): failed."); + return OTP_ERROR; + } + + /* restore from HOTP standard byte order */ +#if BYTE_ORDER == LITTLE_ENDIAN + SWAP64(tmp_count) +#endif /* BYTE_ORDER */ + + offset = result[19] & 0xf; + + tmp32u = (result[offset] & 0x7f) << 24 | + (result[offset+1]) << 16 | + (result[offset+2]) << 8 | + (result[offset+3]); + + if (ou->format == OTP_FORMAT_DEC31_6) + mod64u = 1000000LL; + else if (ou->format == OTP_FORMAT_DEC31_7) + mod64u = 10000000LL; + else if (ou->format == OTP_FORMAT_DEC31_8) + mod64u = 100000000LL; + else if (ou->format == OTP_FORMAT_DEC31_9) + mod64u = 1000000000LL; + else if (ou->format == OTP_FORMAT_DEC31_10) + mod64u = 10000000000LL; + else + xerr_errx(1, "assertion failure: ou->format invalid for dec31."); + + /* final OTP truncation */ + hotp32u = tmp32u % mod64u; + + /* computed HOTP == user reponse? */ + if (hotp32u == crsp32u) { + ou->count = tmp_count + 1; return OTP_AUTH_PASS; } @@ -408,13 +528,13 @@ int otp_hotp_hex40_auth(struct otp_ctx *otpctx, struct otp_user *ou, return OTP_AUTH_FAIL; -} /* otp_hotp_hex40_auth */ +} /* otp_hotp_dec31_auth */ /* * function: otp_hotp_hex40_crsp() * * generate HOTP challenge response in hex40 format from data in ou - * with optional * count_offset applied. Store results in buf as + * with optional count_offset applied. Store results in buf as * null terminated ASCII string. * * arguments: @@ -422,6 +542,7 @@ int otp_hotp_hex40_auth(struct otp_ctx *otpctx, struct otp_user *ou, * ou - otp_user struct source * count_offset - offset of count from current count in ou * buf - buffer with ASCII result. Min 11 bytes. + * buf_size - size of buf * * returns: <0 : fail * 0 : success @@ -431,7 +552,8 @@ int otp_hotp_hex40_crsp(struct otp_ctx *otpctx, struct otp_user *ou, int64_t count_offset, char *buf, size_t buf_size) { uint64_t tmp_count; - u_char result[EVP_MAX_MD_SIZE]; + uint8_t offset; + u_char result[EVP_MAX_MD_SIZE], dt[5]; u_int rlen; if (otp_db_valid(otpctx, "otp_hotp_hex40_crsp") < 0) @@ -458,13 +580,109 @@ int otp_hotp_hex40_crsp(struct otp_ctx *otpctx, struct otp_user *ou, xerr_warnx("buf_size < 11"); return OTP_ERROR; } - - str_hex_dump(buf, result, 5); + + if (ou->format == OTP_FORMAT_HEX40) { + + str_hex_dump(buf, result, 5); + + } else if (ou->format == OTP_FORMAT_DHEX40) { + + offset = result[19] & 0xf; + + dt[0] = result[offset]; dt[1] = result[offset+1]; + dt[2] = result[offset+2]; dt[3] = result[offset+3]; + dt[4] = result[offset+4]; + + str_hex_dump(buf, dt, 5); + + } return 0; } /* otp_hotp_hex40_crsp */ +/* + * function: otp_hotp_dec31_crsp() + * + * generate HOTP challenge response in dec31d* format from data in ou + * with optional count_offset applied. Store results in buf as + * null terminated ASCII string. + * + * arguments: + * otpctx - otp context from otp_db_open() + * ou - otp_user struct source + * count_offset - offset of count from current count in ou + * buf - buffer with ASCII result. Min 11 bytes. + * buf_size - size of buf + * + * returns: <0 : fail + * 0 : success + * + */ +int otp_hotp_dec31_crsp(struct otp_ctx *otpctx, struct otp_user *ou, + int64_t count_offset, char *buf, size_t buf_size) +{ + uint64_t tmp_count, mod64u; + uint32_t tmp32u, hotp32u; + uint8_t offset; + u_char result[EVP_MAX_MD_SIZE]; + u_int rlen; + + if (otp_db_valid(otpctx, "otp_hotp_dec31_crsp") < 0) + return -1; + + tmp_count = ou->count; + tmp_count += count_offset; + + /* HOTP is big endian */ +#if BYTE_ORDER == LITTLE_ENDIAN + SWAP64(tmp_count) +#endif /* BYTE_ORDER */ + + /* compute expected response to challenge */ + if (!HMAC(EVP_sha1(), ou->key, 20, (void*)&tmp_count, 8, + result, &rlen)) { + if (otpctx->verbose) + xerr_warnx("HMAC(): failed."); + return OTP_ERROR; + } + + offset = result[19] & 0xf; + + tmp32u = (result[offset] & 0x7f) << 24 | + (result[offset+1]) << 16 | + (result[offset+2]) << 8 | + (result[offset+3]); + + if (ou->format == OTP_FORMAT_DEC31_6) + mod64u = 1000000LL; + else if (ou->format == OTP_FORMAT_DEC31_7) + mod64u = 10000000LL; + else if (ou->format == OTP_FORMAT_DEC31_8) + mod64u = 100000000LL; + else if (ou->format == OTP_FORMAT_DEC31_9) + mod64u = 1000000000LL; + else if (ou->format == OTP_FORMAT_DEC31_10) + mod64u = 10000000000LL; + else + xerr_errx(1, "assertion failure: ou->format invalid for dec31."); + + /* final OTP truncation */ + hotp32u = tmp32u % mod64u; + + if (buf_size < STR_UINT32_LEN) { + if (otpctx->verbose) + xerr_warnx("buf_size=%d < %d.", buf_size, STR_UINT32_LEN); + return OTP_ERROR; + } + + str_uint32toa(buf, hotp32u); + + return 0; + +} /* otp_hotp_dec31_crsp */ + + /* * function: otp_db_open() * @@ -809,7 +1027,7 @@ otp_db_load_out: * u_count_ceil - count ceiling * u_status - status OTP_STATUS_* * u_type - type OTP_TYPE_HOTP (HOTP implemented) - * u_format - format OTP_FORMAT_HEX40 (HEX40 implemented) + * u_format - format OTP_FORMAT_* * u_version - version OTP_VERSION (version 1 implemented) * * @@ -1043,21 +1261,22 @@ int otp_user_auth(struct otp_ctx *otpctx, char *u_username, { time_t now; struct otp_user ou; - int ret, r, auth_status; + int ret, r, auth_status, crsp_max; if (otp_db_valid(otpctx, "otp_user_auth") < 0) return -1; - /* paranoia */ - str_safe(u_username, OTP_USER_NAME_LEN); - ret = -1; /* fail */ bzero(&ou, sizeof ou); auth_status = OTP_AUTH_FAIL; + /* max length of challenge response */ + crsp_max = (OTP_HOTP_HEX40_LEN<<1) < OTP_HOTP_DEC31_LEN ?\ + (OTP_HOTP_HEX40_LEN<<1) : OTP_HOTP_DEC31_LEN; + /* paranoia */ str_safe(u_username, OTP_USER_NAME_LEN); - str_safe(u_crsp, OTP_HOTP_HEX40_LEN<<1); + str_safe(u_crsp, crsp_max<<1); /* open user record */ if (otp_urec_open(otpctx, u_username, &ou, O_RDWR, FFDB_OP_LOCK_EX) < 0) { @@ -1093,12 +1312,21 @@ int otp_user_auth(struct otp_ctx *otpctx, char *u_username, ou.last = now; /* try to authenticate user */ - if (ou.status != OTP_STATUS_ACTIVE) + if (ou.status != OTP_STATUS_ACTIVE) { auth_status = OTP_AUTH_FAIL; - else if (ou.count >= ou.count_ceil) + } else if (ou.count >= ou.count_ceil) { auth_status = OTP_AUTH_FAIL; - else - auth_status = otp_hotp_hex40_auth(otpctx, &ou, u_crsp, u_window); + } else { + if ((ou.format == OTP_FORMAT_HEX40) || + (ou.format == OTP_FORMAT_DHEX40)) + auth_status = otp_hotp_hex40_auth(otpctx, &ou, u_crsp, u_window); + else if ((ou.format == OTP_FORMAT_DEC31_6) || + (ou.format == OTP_FORMAT_DEC31_7) || + (ou.format == OTP_FORMAT_DEC31_8) || + (ou.format == OTP_FORMAT_DEC31_9) || + (ou.format == OTP_FORMAT_DEC31_10)) + auth_status = otp_hotp_dec31_auth(otpctx, &ou, u_crsp, u_window); + } /* * regardless of authentication status update the db to reflect last access @@ -1368,9 +1596,15 @@ int otp_urec_sanity(struct otp_ctx *otpctx, struct otp_user *ou) return -1; } - if (ou->format != OTP_FORMAT_HEX40) { + if ((ou->format != OTP_FORMAT_HEX40) && + (ou->format != OTP_FORMAT_DHEX40) && + (ou->format != OTP_FORMAT_DEC31_6) && + (ou->format != OTP_FORMAT_DEC31_7) && + (ou->format != OTP_FORMAT_DEC31_8) && + (ou->format != OTP_FORMAT_DEC31_9) && + (ou->format != OTP_FORMAT_DEC31_10)) { if (otpctx->verbose) - xerr_warnx("format != OTP_FORMAT_HEX40."); + xerr_warnx("format invalid."); return -1; } @@ -1394,7 +1628,6 @@ int otp_urec_sanity(struct otp_ctx *otpctx, struct otp_user *ou) * function: otp_urec_crsp() * * generate challenge response for ou - * HOTP HEX40 implemented. * * arguments: * otpctx - otp db context returned by otp_db_open() @@ -1407,13 +1640,31 @@ int otp_urec_sanity(struct otp_ctx *otpctx, struct otp_user *ou) int otp_urec_crsp(struct otp_ctx *otpctx, struct otp_user *ou, int64_t count_offset, char *buf, size_t buf_size) { + int crsp_max; if (otp_db_valid(otpctx, "otp_urec_crsp") < 0) return -1; - if (buf_size < 5) { + /* max length of challenge response */ + if ((ou->format == OTP_FORMAT_HEX40) || + (ou->format == OTP_FORMAT_DHEX40)) + crsp_max = (OTP_HOTP_HEX40_LEN<<1); + else if (ou->format == OTP_FORMAT_DEC31_6) + crsp_max = 6; + else if (ou->format == OTP_FORMAT_DEC31_7) + crsp_max = 7; + else if (ou->format == OTP_FORMAT_DEC31_8) + crsp_max = 8; + else if (ou->format == OTP_FORMAT_DEC31_9) + crsp_max = 9; + else if (ou->format == OTP_FORMAT_DEC31_10) + crsp_max = 10; + else + xerr_errx(1, "assertion failure: ou->format invalid."); + + if (buf_size < (crsp_max+1)) { if (otpctx->verbose) - xerr_warnx("buf_size < 5."); + xerr_warnx("buf_size < %d.", (crsp_max+1)); goto otp_urec_crsp_out; } @@ -1423,7 +1674,17 @@ int otp_urec_crsp(struct otp_ctx *otpctx, struct otp_user *ou, goto otp_urec_crsp_out; } - return (otp_hotp_hex40_crsp(otpctx, ou, count_offset, buf, buf_size)); + if ((ou->format == OTP_FORMAT_HEX40) || + (ou->format == OTP_FORMAT_DHEX40)) + return (otp_hotp_hex40_crsp(otpctx, ou, count_offset, buf, buf_size)); + else if ((ou->format == OTP_FORMAT_DEC31_6) || + (ou->format == OTP_FORMAT_DEC31_7) || + (ou->format == OTP_FORMAT_DEC31_8) || + (ou->format == OTP_FORMAT_DEC31_9) || + (ou->format == OTP_FORMAT_DEC31_10)) + return (otp_hotp_dec31_crsp(otpctx, ou, count_offset, buf, buf_size)); + else + xerr_errx(1, "assertion failure: ou->format invalid."); otp_urec_crsp_out: @@ -1447,7 +1708,7 @@ otp_urec_crsp_out: */ void otp_urec_disp(struct otp_ctx *otpctx, struct otp_user *ou) { - char tmp[41]; + char tmp[41], buf[512]; if (otp_db_valid(otpctx, "otp_urec_disp") < 0) return; @@ -1461,18 +1722,16 @@ void otp_urec_disp(struct otp_ctx *otpctx, struct otp_user *ou) ou->count_ceil); printf("Version........%u\n", (u_int)ou->version); printf("Status.........%s (%u)\n", - otp_l_status[ou->status], (u_int)ou->status); + str_lookup8(otp_status_l, ou->status, 1, OTP_STATUS_MAX), + (u_int)ou->status); printf("Format.........%s (%u)\n", - otp_l_format[ou->format], (u_int)ou->format); - printf("Type...........%s (%u)\n", otp_l_type[ou->type], (u_int)ou->type); - printf("Flags..........%2.2x", (u_int)ou->flags); - if (ou->flags) - printf(" ["); - if (ou->flags & OTP_USER_FLAGS_DSPCNT) - printf(" display-count"); - if (ou->flags) - printf(" ]"); - printf("\n"); + str_lookup8(otp_format_l, ou->format, 1, OTP_FORMAT_MAX), + (u_int)ou->format); + printf("Type...........%s (%u)\n", + str_lookup8(otp_type_l, ou->type, 1, OTP_TYPE_MAX), (u_int)ou->type); + printf("Flags..........[%s] (0x%2.2x)\n", + str_flag8(otp_flags_l, ou->flags, OTP_FLAGS_BITS, buf, 512), + (u_int)ou->flags); } /* otp_urec_disp */ @@ -1591,7 +1850,7 @@ int main(int argc, char **argv) /* crsp[0] = 'F'; */ - ret = otp_user_auth(otpctx, "maf", crsp, OTP_HOTP_WINDOW); + ret = otp_user_auth(otpctx, "maf", crsp, OTP_WINDOW_DEFAULT); printf("otp_user_auth(): %d\n", ret); /* diff --git a/common/otplib.h b/common/otplib.h index 64d89d7..90bbd88 100644 --- a/common/otplib.h +++ b/common/otplib.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otplib.h 13 2009-11-26 16:37:03Z maf $ + * $Id: otplib.h 61 2009-12-17 03:57:22Z maf $ */ #include @@ -68,17 +68,30 @@ -#define OTP_DB_FNAME "/etc/otpdb" /* location of user database */ -#define OTP_HOTP_WINDOW 10 /* Window of challenges to try */ -#define OTP_VERSION 1 /* version of library */ -#define OTP_FORMAT_HEX40 1 /* 40 bits in hex */ -#define OTP_TYPE_HOTP 1 /* protocol type */ +#define OTP_DB_FNAME "/etc/otpdb" /* location of user database */ +#define OTP_VERSION 1 /* version of library */ + +#define OTP_FORMAT_HEX40 1 /* 40 bits in hex */ +#define OTP_FORMAT_DHEX40 2 /* 40 bits in hex w. RFC 4226 DT */ +#define OTP_FORMAT_DEC31_6 3 /* 31 bits 6 digits in decimal RFC */ +#define OTP_FORMAT_DEC31_7 4 /* 31 bits 7 digits in decimal */ +#define OTP_FORMAT_DEC31_8 5 /* 31 bits 8 digits in decimal */ +#define OTP_FORMAT_DEC31_9 6 /* 31 bits 9 digits in decimal */ +#define OTP_FORMAT_DEC31_10 7 /* 31 bits 10 digits in decimal */ +#define OTP_FORMAT_MAX 7 /* highest valid format enum */ + +#define OTP_TYPE_HOTP 1 /* protocol type */ +#define OTP_TYPE_MAX 1 /* highest valid type enum */ + +#define OTP_WINDOW_DEFAULT 10 /* default challenge window */ +#define OTP_WINDOW_MAX 255 /* max challenge window */ #define OTP_VERSION_MIN 1 /* min version for this code */ -#define OTP_VERSION_MAX 1 /* max version for this code */ +#define OTP_VERSION_MAX 1 /* max version for this code */ -#define OTP_HOTP_KEY_SIZE 20 /* HMAC SHA160 key length */ -#define OTP_HOTP_HEX40_LEN 5 /* HOTP challenge hex 40 bits */ +#define OTP_HOTP_KEY_SIZE 20 /* HMAC SHA160 key length */ +#define OTP_HOTP_HEX40_LEN 5 /* HOTP challenge hex 40 bits */ +#define OTP_HOTP_DEC31_LEN 10 /* max 10 digits */ #define OTP_AUTH_PASS 0 /* authenticated */ #define OTP_AUTH_FAIL 1 /* not authenticated */ @@ -89,11 +102,14 @@ #define OTP_STATUS_ACTIVE 1 /* user is active */ #define OTP_STATUS_INACTIVE 2 /* user is not active */ #define OTP_STATUS_DISABLED 3 /* user is locked (disabled) */ +#define OTP_STATUS_MAX 3 /* highest valid status enum */ + #define OTP_USER_N_FIELDS 10 /* n fields in ASCII encoding */ #define OTP_USER_ASCII_LEN 139 /* max ASCII encoded length (w/o null) */ -#define OTP_USER_FLAGS_DSPCNT 0x1 /* force display count */ +#define OTP_FLAGS_DSPCNT 0x1 /* force display count */ +#define OTP_FLAGS_BITS 1 /* bits used */ #define OTP_USER_NAME_LEN 32 /* max length of username (w/o null)*/ #define OTP_USER_KEY_LEN 64 /* key length */ @@ -103,8 +119,8 @@ #define OTP_DB_CREATE_SOFT 0x04 /* create database, soft fail on exist */ struct otp_user { - struct ffdb_key db_key; /* database key */ - struct ffdb_val db_val; /* database value (this struct in ASCII) */ + struct ffdb_key db_key; /* database key */ + struct ffdb_val db_val; /* database value (this struct in ASCII) */ uint64_t count; /* count */ uint64_t count_ceil; /* count ceiling */ uint64_t last; /* last access */ @@ -152,6 +168,10 @@ int otp_hotp_hex40_auth(struct otp_ctx *otpctx, struct otp_user *ou, char *crsp, int window); int otp_hotp_hex40_crsp(struct otp_ctx *otpctx, struct otp_user *ou, int64_t count_offset, char *buf, size_t buf_size); +int otp_hotp_dec31_auth(struct otp_ctx *otpctx, struct otp_user *ou, + char *crsp, int window); +int otp_hotp_dec31_crsp(struct otp_ctx *otpctx, struct otp_user *ou, + int64_t count_offset, char *buf, size_t buf_size); struct otp_ctx *otp_db_open(char *dbname, int flags); int otp_db_close(struct otp_ctx *otpctx); @@ -183,6 +203,12 @@ void otp_urec_dispsc(struct otp_ctx *otpctx, struct otp_user *ou, int otp_user_to_ascii(struct otp_ctx *otpctx, struct otp_user *ou); int otp_user_from_ascii(struct otp_ctx *otpctx, struct otp_user *ou); +char *otp_uflags_str(uint8_t flags, char *tmpbuf, size_t tmpbuf_size); + extern char *otp_status_l[]; +extern char *otp_format_l[]; +extern char *otp_type_l[]; +extern char *otp_flags_l[]; + #endif /* OTP_H */ diff --git a/common/otpsc.h b/common/otpsc.h index 7c02f24..ad45bf7 100644 --- a/common/otpsc.h +++ b/common/otpsc.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otpsc.h 23 2009-11-28 06:26:22Z maf $ + * $Id: otpsc.h 86 2009-12-28 00:05:24Z maf $ */ /* highest supported index */ @@ -209,5 +209,11 @@ #define HOSTNAME_FLAG_MASK 0x80 /* high bit set */ #define HOSTNAME_POS_CHALLENGE 0x00 /* require challenge input */ -#define HOSTNAME_POS_READERKEY 0x01 /* require reader key */ +#define HOSTNAME_POS_READERKEY 1 /* require reader key */ +#define HOSTNAME_POS_FMT 2 /* format, 0=hex, 1=decimal */ +#define HOSTNAME_POS_FMT3 8 /* 0000=HEX40, 0001=HEX40 */ +#define HOSTNAME_POS_FMT2 9 /* 0010=DEC31.6 0011=DEC31.7 */ +#define HOSTNAME_POS_FMT1 10 /* 0100=DEC31.8 0101=DEC31.9 */ +#define HOSTNAME_POS_FMT0 11 /* 0110=DEC31.10 0111=DHEX40 */ + diff --git a/common/scr.c b/common/scr.c index 13b331b..4b81b1e 100644 --- a/common/scr.c +++ b/common/scr.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: scr.c 29 2009-11-30 01:11:17Z maf $ + * $Id: scr.c 73 2009-12-21 05:14:46Z maf $ */ #include @@ -81,12 +81,11 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) { struct scr_ctx *scrctx; size_t ralloc; - int r, ret, cur_reader; + int i, r, ret, cur_reader; char *buf; #ifdef SCR_PCSC char *pcsc_rdr_buf, *p; DWORD pcsc_rdr_buf_len; - int pcsc_rdr_count; #endif /* SCR_PCSC */ ret = -1; /* fail */ @@ -104,25 +103,20 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) bzero(scrctx, sizeof *scrctx); scrctx->verbose = verbose; - if (valid_readers & SCR_READER_EMBEDDED_ACR30S) { - - ++ scrctx->num_readers; - - ralloc += strlen(SCR_EMBEDDED_ACR30S_NAME)+1; - - } - #ifdef SCR_PCSC if (valid_readers & SCR_READER_PCSC) { if ((r = SCardEstablishContext(SCARD_SCOPE_SYSTEM, (void*)0L, (void*)0L, &scrctx->hContext)) != SCARD_S_SUCCESS) { + if (scrctx->verbose) xerr_warnx("SCardEstablishContext(): %s.", pcsc_stringify_error(r)); - } - pcsc_rdr_buf = (char*)0L; + /* give up on PCSC readers */ + goto pcsc_done; + + } /* * SCARD_AUTOALLOCATE not portable. Do this in two steps @@ -130,9 +124,13 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) */ if ((r = SCardListReaders(scrctx->hContext, (void*)0L, (void*)0L, &pcsc_rdr_buf_len)) != SCARD_S_SUCCESS) { + if (scrctx->verbose) xerr_warnx("SCCardListReaders(): %s.", pcsc_stringify_error(r)); - goto scr_ctx_new_out; + + /* give up on PCSC readers */ + goto pcsc_done; + } if (!(pcsc_rdr_buf = malloc(pcsc_rdr_buf_len))) { @@ -149,23 +147,33 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) } /* run through PSCS reader names to get count */ - for (p = pcsc_rdr_buf, pcsc_rdr_count = 0;*p;++pcsc_rdr_count) + for (p = pcsc_rdr_buf;*p;++scrctx->pcsc_num_readers) p += strlen(p); /* first PCSC reader in the list */ - if (pcsc_rdr_count) + if (scrctx->pcsc_num_readers) scrctx->pcsc_reader_first = scrctx->num_readers; /* add PCSC readers to total available via scr */ - scrctx->num_readers += pcsc_rdr_count; + scrctx->num_readers += scrctx->pcsc_num_readers; /* resrve space for reader name + "PCSC:" */ - ralloc += pcsc_rdr_buf_len + (pcsc_rdr_count * 5); + ralloc += pcsc_rdr_buf_len + (scrctx->pcsc_num_readers * 5); } /* SCR_READER_PCSC */ #endif /* SCR_PCSC */ +pcsc_done: + + if (valid_readers & SCR_READER_EMBEDDED_ACR30S) { + + ++ scrctx->num_readers; + + ralloc += strlen(SCR_EMBEDDED_ACR30S_NAME)+1; + + } + /* foreach reader allocate char */ ralloc += (scrctx->num_readers) * sizeof (char*); @@ -179,18 +187,12 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) buf = (char*)scrctx->readers + (sizeof (char*))*scrctx->num_readers; cur_reader = 0; - if (valid_readers & SCR_READER_EMBEDDED_ACR30S) { - scrctx->readers[cur_reader++] = buf; - strcpy(buf, SCR_EMBEDDED_ACR30S_NAME); - buf += strlen(SCR_EMBEDDED_ACR30S_NAME) + 1; - } /* SCR_READER_PCSC */ - #ifdef SCR_PCSC if (valid_readers & SCR_READER_PCSC) { p = pcsc_rdr_buf; - while (*p) { + while (p && *p) { scrctx->readers[cur_reader++] = buf; bcopy("PCSC:", buf, 5); buf += 5; @@ -203,6 +205,13 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) #endif /* SCR_PCSC */ + if (valid_readers & SCR_READER_EMBEDDED_ACR30S) { + scrctx->readers[cur_reader++] = buf; + strcpy(buf, SCR_EMBEDDED_ACR30S_NAME); + buf += strlen(SCR_EMBEDDED_ACR30S_NAME) + 1; + } /* SCR_READER_PCSC */ + + scrctx->valid = 1; scrctx->valid_readers = valid_readers; @@ -210,6 +219,12 @@ struct scr_ctx* scr_ctx_new(int valid_readers, int verbose) scr_ctx_new_out: + /* dump list of readers? */ + if (scrctx->verbose) { + for (i = 0; i < scrctx->num_readers; ++i) + xerr_info("reader: %s", scrctx->readers[i]); + } + #ifdef SCR_PCSC if (pcsc_rdr_buf) free(pcsc_rdr_buf); @@ -329,6 +344,8 @@ void scr_ctx_free(struct scr_ctx *scrctx) * to the first reader, embedded:acr30s will default to * SCR_EMBEDDED_ACR30S_DEVICE * + * An empty reader string will default to the first available reader + * * returns: 0 success, connected to reader * <0 failure * @@ -343,6 +360,19 @@ int scr_ctx_connect(struct scr_ctx *scrctx, char *reader) if (scr_ctx_valid(scrctx, (char*)__FUNCTION__) == -1) goto scr_ctx_connect_out; + + /* empty or no reader string */ + if ((!reader) || (reader[0] == 0)) { + + if (scrctx->num_readers == 0) { + xerr_warnx("No readers."); + goto scr_ctx_connect_out; + } + + reader = scrctx->readers[0]; + + } + n = strlen(reader); if (!(scrctx->reader = (char*)malloc(n+1))) { @@ -387,10 +417,19 @@ int scr_ctx_connect(struct scr_ctx *scrctx, char *reader) /* skip PCSC: */ scrctx->pcsc_active_reader = scrctx->reader + 5; - /* PCSC: alone defaults to first PCSC reader */ - if (!*scrctx->pcsc_active_reader) - scrctx->pcsc_active_reader =\ - scrctx->readers[scrctx->pcsc_reader_first]+5; + /* PCSC: alone defaults to first PCSC reader if defined */ + if (!*scrctx->pcsc_active_reader) { + + /* if readers available, then default to first */ + if (scrctx->pcsc_num_readers) { + scrctx->pcsc_active_reader =\ + scrctx->readers[scrctx->pcsc_reader_first]+5; + } else { + xerr_warnx("No PCSC readers."); + goto scr_ctx_connect_out; + } + + } /* PSCS: */ if ((r = SCardConnect(scrctx->hContext, scrctx->pcsc_active_reader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T1, &scrctx->hCard, diff --git a/common/scr.h b/common/scr.h index 758260e..2b1ef16 100644 --- a/common/scr.h +++ b/common/scr.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: scr.h 26 2009-11-29 23:01:37Z maf $ + * $Id: scr.h 49 2009-12-14 22:03:08Z maf $ */ #include "acr30.h" @@ -43,11 +43,6 @@ #define SCR_EMBEDDED_ACR30S_NAME "embedded:acr30s" #define SCR_EMBEDDED_ACR30S_DEVICE "/dev/cuaU0" -#ifndef SCR_DEFAULT_READER -/* #define SCR_DEFAULT_READER "embedded:acr30s:/dev/cuaU0" */ -#define SCR_DEFAULT_READER "PCSC:" -#endif - #define SCR_TX_BUF_LEN 254 #define SCR_RX_BUF_LEN 254 @@ -66,12 +61,12 @@ struct scr_ctx SCARDHANDLE hCard; DWORD dwActiveProtocol; char *pcsc_active_reader; + int pcsc_reader_first, pcsc_num_readers; #endif /* SCR_PCSC */ int verbose, valid, valid_readers, active_reader; int num_readers; char **readers; char *reader; - int pcsc_reader_first; }; struct scr_io { diff --git a/common/str.c b/common/str.c index 1b30a17..8db0250 100644 --- a/common/str.c +++ b/common/str.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: str.c 15 2009-11-26 18:29:41Z maf $ + * $Id: str.c 87 2009-12-28 00:05:53Z maf $ */ #include @@ -36,6 +36,7 @@ #endif #include #include "str.h" +#include "xerr.h" /* * function: chr_hex_l() @@ -149,7 +150,7 @@ int chr_ishex(char d) * n - length of b in bytes * */ -void str_hex_dump(char *buf, u_char *b, size_t n) +int str_hex_dump(char *buf, u_char *b, size_t n) { int i, j; for (i = 0, j = 0; i < n; ++i) { @@ -157,6 +158,7 @@ void str_hex_dump(char *buf, u_char *b, size_t n) buf[j++] = chr_hex_r(*b++); } buf[j] = 0; + return j; } /* @@ -390,6 +392,130 @@ int str_safe(char *input, size_t len) } /* str_safe */ +/* + * function: str_uint32toa() + * + * convert unsigned 32 bit integer to ascii. Left align. + * + * arguments: + * s - pointer to output buffer. Must be at least 11 bytes. + * u - uint32_t to convert + * + * returns: length of string + * + */ +int str_uint32toa(char *s, uint32_t u) +{ + int len; + char *s1; + + len = 0; + s1 = s; + + /* 2^32-1 = 4294967295 = max 10 digits + NULL */ + s[10] = 0; + + do { + ++len; + *--s = '0' + (u % 10); + u /= 10; + } while (u); + + bcopy(s, s1, len); + s1[len] = 0; + + return len; + +} /* str_fmt_uint32 */ + +char *str_lookup8(char *list[], uint8_t id, uint8_t min, uint8_t max) +{ + if (id > max) { + xerr_warnx("str_lookup8(): id=%d, max=%d", (int)id, (int)max); + return "err"; + } + + if (id < min) { + xerr_warnx("str_lookup8(): id=%d, min=%d", (int)id, (int)min); + return "err"; + } + + return list[id]; + +} /* str_lookup8 */ + +char *str_flag8(char *list[], uint8_t flags, uint8_t bits, char *tmpbuf, + size_t tmpbuf_size) +{ + int i, l, u; + char *t; + + u = 0; + t = tmpbuf; + + for (i = 0; i < bits; ++i) { + if (flags & (1< diff --git a/common/str.h b/common/str.h index 35d9b61..77465e4 100644 --- a/common/str.h +++ b/common/str.h @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: str.h 15 2009-11-26 18:29:41Z maf $ + * $Id: str.h 85 2009-12-28 00:05:02Z maf $ */ #include @@ -38,10 +38,25 @@ int chr_ishex(char d); char chr_hex_l(u_char h); char chr_hex_r(u_char h); u_char chr_hex_decode(char h); -void str_hex_dump(char *buf, u_char *b, size_t n); +int str_hex_dump(char *buf, u_char *b, size_t n); int str_hex_decode(char *in, size_t in_len, u_char *out, size_t out_len); void str_ftoc(char *buf, char *f, size_t n); int str_input(const char *prompt, char *buf, size_t buf_size, int flags); int str_safe(char *input, size_t len); +int str_uint32toa(char *s, uint32_t u); + +char *str_lookup8(char *list[], uint8_t id, uint8_t min, uint8_t max); + +char *str_flag8(char *list[], uint8_t flags, uint8_t bits, char *tmpbuf, + size_t tmpbuf_size); + +int str_setflag8(char *list[], uint8_t *flags, char *s, uint8_t min, + uint8_t max); + +int str_find8(char *list[], uint8_t *id, char *s, uint8_t min, uint8_t max); #define STR_FLAGS_ECHO_OFF 0x1 + +#define STR_UINT32_LEN 11 /* 2^32-1=4294967295 + NULL = 11 bytes */ + + diff --git a/doc/QUICKSTART b/doc/QUICKSTART index 32af6db..4496c6c 100644 --- a/doc/QUICKSTART +++ b/doc/QUICKSTART @@ -1,5 +1,5 @@ # -# $Id: QUICKSTART 32 2009-11-30 01:18:29Z maf $ +# $Id: QUICKSTART 76 2009-12-26 21:04:01Z maf $ # OpenOTP is an implementation of the HOTP protocol using a ZeitControl @@ -10,7 +10,7 @@ Included is a C library implementation of the HOTP protocol and associated user database management, HOTP PAM library, OpenVPN plug-in module, micro RADIUS server with HOTP support, and utilties for managing the Smart Card, Spyrus reader, and host side HOTP user database. The PCSC-Lite -API provides reader support for Smart Card management under FreeBSD and Linux. +API provides reader support for Smart Card management. The card management, firmware loaders, C API, and authentication methods have been developed & tested for FreeBSD and Linux. @@ -25,7 +25,12 @@ downloading firmware to the reader with a Spyrus downloader cable. Source and Binary for the BasicCard firmware is supplied. Modification requires the Windows BasicCard development software available as a free download from ZeitControl. A Unix version of bcload implemented -with the PCSC-Lite interface is included. +with the PCSC-Lite interface and embedded ACR30S driver is included. + +The Smart Card based token generator is standards based and may be +used with other RFC compliant HOTP implementations. Other HOTP +token generators may be used with the Unix side HOTP library +and authentication modules. Distribution: @@ -319,9 +324,9 @@ semanage fcontext -a -t textrel_shlib_t /lib/security/pam_otp.so # to temporarily disable SELinux for testing use # setenforce 0 -# create the OTP database with one deactivated user (joe) +# create the OTP database with one inactive user (joe) otp-control -n -u joe -m add -otp-control -u joe -m deactivate +otp-control -u joe -m set-status inactive otp-control -u joe -m list >Username.......joe @@ -392,7 +397,7 @@ Password: Last login: Tue Sep 1 23:21:20 2009 from 10.1.0.26 # activate user -otp-control -u joe -m activate +otp-control -u joe -m set-status -s active # login with OTP generated earlier bastion.eng:~% ssh 10.1.0.25 @@ -420,22 +425,20 @@ arrow until the "DownloadApp" menu item is present. Start the htsoft-downloader utility using serial port at /dev/cuaU0 : # FreeBSD USB Serial Adapter -htsoft-downloader -v1 -f /dev/cuaU0 < $OOTP/firmware/spyrus1.3.hex +htsoft-downloader -v1 -i -f /dev/cuaU0 < $OOTP/firmware/spyrus1.3.hex # Linux USB Serial Adapter -htsoft-downloader -v1 -f /dev/ttyS0 < $OOTP/firmware/spyrus1.3.hex +htsoft-downloader -v1 -i -f /dev/ttyS0 < $OOTP/firmware/spyrus1.3.hex Press Enter on the spyrus reader to start the download application: Waiting for bootloader...... -DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDwTwwwwPIC reset failed. -htsoft-downloader: htsoft_v1bl_done(): failed +DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDwTwF +PIC reset sent, ignored last WOK timeout. -Note the htsoft_v1bl_done(): failed message is cosmetic. The bootloader code -in the spyrus reader does not appear to send a final ACK per the source code -documentation from htsoft/Microchip. Increase the verbosity level for more -debugging information if necessary. +Increase the verbosity level for more debugging information if necessary. +The -i option is required for the bootloader provided with the Spyrus reader. A Windows PIC downloader which will work with the Spyrus reader is available at http://www.ehl.cz/pic/pic_e.htm. It will also note an error when trying @@ -747,18 +750,19 @@ the high bit of the 2nd character in the hostname. See also: - This site http://www.splintered.net/sw/otp - HOTP ID http://www.ietf.org/internet-drafts/draft-mraihi-oath-hmac-otp-02.txt - IETF slides http://www3.ietf.org/proceedings/05mar/slides/saag-2/sld1.htm - SHA-1 http://www.itl.nist.gov/fipspubs/fip180-1.htm - HMAC http://www.faqs.org/rfcs/rfc2104.html - BasicCard http://www.basiccard.com/ - Linux PAM http://www.kernel.org/pub/linux/libs/pam/ - PAM S-Key http://kreator.esa.fer.hr/projects/tarballs/pam_skey-1.1.3.tar.gz + This site http://www.splintered.net/sw/otp + HOTP ID http://www.ietf.org/internet-drafts/draft-mraihi-oath-hmac-otp-02.txt + IETF slides http://www3.ietf.org/proceedings/05mar/slides/saag-2/sld1.htm + SHA-1 http://www.itl.nist.gov/fipspubs/fip180-1.htm + HMAC http://www.faqs.org/rfcs/rfc2104.html + BasicCard http://www.basiccard.com/ + Linux PAM http://www.kernel.org/pub/linux/libs/pam/ + PAM S-Key http://kreator.esa.fer.hr/projects/tarballs/pam_skey-1.1.3.tar.gz (used as a reference PAM module) - Spyrus http://www.spyrus.com - PCSC-LITE http://pcsclite.alioth.debian.org/ - Smart Cards http://www.smartcardfocus.com/ + Spyrus http://www.spyrus.com + PCSC-LITE http://pcsclite.alioth.debian.org/ + Smart Cards http://www.smartcardfocus.com/ + BalanceReader http://www.basiccard.com/chip/balanceR.pdf # # The HOTP database is not encrypted. For added security use an encrypted diff --git a/doc/TODO b/doc/TODO index 4c7924a..d8cd7a1 100644 --- a/doc/TODO +++ b/doc/TODO @@ -5,5 +5,31 @@ RADIUS dspcnt flag urd, force display count RADIUS proxy support -default no GetHost() in BasicCard +get documentation for the ACS balance reader +ACS balance reader support dec31.6? + +break out htsoft-downloader, urd, bcload? + +architecture document + formats + post + +basiccard build notes + +full coverage testing for otplib and ffdb + +otp-token (soft token) + +count use 64 bit current time option + +balance reader simulator + +Break out Linux/FreeBSD/MAC build notes into separate file from QUICKSTART + +Test with Linux PICC. Add spyrus Makefile to build without Windows + +Spyrus main.c missing + EE2LCD() + U8 Temp[4]; + RESP_INFO *respDump = (RESP_INFO*) Temp; diff --git a/doc/bcload.1 b/doc/bcload.1 index d42c296..126b4b0 100644 --- a/doc/bcload.1 +++ b/doc/bcload.1 @@ -79,7 +79,14 @@ Disable paranoid check for ZC3\&.9 hardware\&. Enhanced Smart Cards will probably work, support for the professional cards require changes to \fBbcload\&.c\fP\&. .IP "-r\fI reader\fP" 10 -Set the smart card reader\&. Use -l to list available readers\&. +Set Smart Card reader\&. Use -l to list available readers\&. A reader +is defined as class:reader:[option]\&. PCSC and embedded +are the two available classes\&. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]\&. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver\&. Use PCSC: for the first available PC/SC +reader\&. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0\&. .IP "-t" 10 Force card mode to TEST after programming\&. Defaults to the mode specified in the image file\&. @@ -87,7 +94,7 @@ specified in the image file\&. Display verbose status messages while programming the card\&. .SH "EXAMPLES" .PP -Download the HOTPC\&.IMG file to the default smart card reader\&. Display +Download the HOTPC\&.IMG file to the default Smart Card reader\&. Display verbose results\&. .PP .nf @@ -127,4 +134,4 @@ Mark Fullmer maf@splintered\&.net \fBotp-ov-plugin\fP(1) \fBurd\fP(1) spyrus-par2(7) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:15 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/bcload.html b/doc/bcload.html index 1851442..0733b90 100644 --- a/doc/bcload.html +++ b/doc/bcload.html @@ -150,7 +150,20 @@ CLASS="REPLACEABLE" >

Set the smart card reader. Use -l to list available readers.

Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:[option]. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0.

-t

EXAMPLES

Download the HOTPC.IMG file to the default smart card reader. Display +>Download the HOTPC.IMG file to the default Smart Card reader. Display verbose results.

AUTHOR

SEE ALSO

- + @@ -95,7 +95,14 @@ to bcload.c. -r reader -Set the smart card reader. Use -l to list available readers. +Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:option. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:serial_port. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0. @@ -128,7 +135,7 @@ Display verbose status messages while programming the card. -Download the HOTPC.IMG file to the default smart card reader. Display +Download the HOTPC.IMG file to the default Smart Card reader. Display verbose results. diff --git a/doc/htsoft-downloader.1 b/doc/htsoft-downloader.1 index 1483a70..cf07cbc 100644 --- a/doc/htsoft-downloader.1 +++ b/doc/htsoft-downloader.1 @@ -69,6 +69,8 @@ on standard output and downloaded to a PIC on the .SH "OPTIONS" .IP "-h" 10 Help +.IP "-i" 10 +Ignore timeout for last WOK after sending reset\&. .IP "-f\fI serial_device\fP" 10 Serial device filename\&. Examples: .IP "" 10 @@ -93,7 +95,7 @@ Transfer the HEX file spyrus1\&.1\&.hex to a PIC connected to the bootloader in this device does not send the last WOK command, this appears to be harmless\&. .PP - \fBpic-downloader -v9 -f /dev/ttyUSB0 < spyrys1\&.1\&.hex\fP + \fBpic-downloader -v9 -i -f /dev/ttyUSB0 < spyrys1\&.1\&.hex\fP .PP .nf Waiting for bootloader\&.\&.\&.\&.\&.\&.\&.\&.\&.\&. @@ -108,11 +110,10 @@ write: data=202530A0008430E8202017833010008430362020120A118A2DBD060401800A84 \&.\&.\&. -upload block: load_offset=0x1FFA bytes_to_send=6 -Dwrite: cmd=E3 load=0FFD bytes=06 csum=AA -write: data=00CB30C42EBD -wDONE: reply=F8, expecting E4wwwwpic-downloader: htsoft_v1bl_done(): failed -PIC reset failed\&. +upload block: load_offset=0x1FF8 bytes_to_send=8 +Dwrite: cmd=E3 load=0FFC bytes=08 csum=7E +write: data=246B120A158A3400 +wDONE: reply=F0, expecting E4wPIC reset sent\&. .fi .SH "AUTHOR" .PP @@ -124,4 +125,4 @@ Intel Hexadecimal Object File Format Specification Rev A www\&.htsoft\&.com .PP http://www\&.ehl\&.cz/pic/pic_e\&.htm -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:15 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/htsoft-downloader.html b/doc/htsoft-downloader.html index 84cd513..02c7a0d 100644 --- a/doc/htsoft-downloader.html +++ b/doc/htsoft-downloader.html @@ -108,6 +108,12 @@ CLASS="VARIABLELIST" >Help

-i

Ignore timeout for last WOK after sending reset.

-f

EXAMPLE

Transfer the HEX file spyrus1.1.hex to a PIC connected to @@ -197,7 +203,7 @@ appears to be harmless.

pic-downloader -v9 -f /dev/ttyUSB0 < spyrys1.1.hexpic-downloader -v9 -i -f /dev/ttyUSB0 < spyrys1.1.hex

AUTHOR

SEE ALSO

- + @@ -58,6 +58,15 @@ Help + +-i + + +Ignore timeout for last WOK after sending reset. + + + + -f serial_device @@ -120,7 +129,7 @@ the bootloader in this device does not send the last WOK command, this appears to be harmless. - pic-downloader -v9 -f /dev/ttyUSB0 < spyrys1.1.hex + pic-downloader -v9 -i -f /dev/ttyUSB0 < spyrys1.1.hex Waiting for bootloader.......... @@ -135,12 +144,10 @@ write: data=202530A0008430E8202017833010008430362020120A118A2DBD060401800A84 ... -upload block: load_offset=0x1FFA bytes_to_send=6 -Dwrite: cmd=E3 load=0FFD bytes=06 csum=AA -write: data=00CB30C42EBD -wDONE: reply=F8, expecting E4wwwwpic-downloader: htsoft_v1bl_done(): failed -PIC reset failed. - +upload block: load_offset=0x1FF8 bytes_to_send=8 +Dwrite: cmd=E3 load=0FFC bytes=08 csum=7E +write: data=246B120A158A3400 +wDONE: reply=F0, expecting E4wPIC reset sent. diff --git a/doc/otp-control.1 b/doc/otp-control.1 index 67bed65..7cea6fe 100644 --- a/doc/otp-control.1 +++ b/doc/otp-control.1 @@ -56,7 +56,7 @@ \fBotp-control\fP \(em Local user database configuration for One Time Password package\&. .SH "SYNOPSIS" .PP -\fBotp-control\fP [-?hnv] [-c\fI count\fP] [-C\fI count_ceil\fP] [-F\fI sc_flags\fP] [-H\fI sc_hostname\fP] [-I\fI sc_index\fP] [-k\fI key\fP] [-m\fI command_mode\fP] [-o\fI otpdb_pathname\fP] [-u\fI username\fP] [-w\fI window\fP] +\fBotp-control\fP [-?hnv] [-c\fI count\fP] [-C\fI count_ceil\fP] [-f\fI format\fP] [-F\fI flags\fP] [-H\fI sc_hostname\fP] [-I\fI sc_index\fP] [-k\fI key\fP] [-m\fI command_mode\fP] [-o\fI otpdb_pathname\fP] [-s\fI status\fP] [-S\fI sc_flags\fP] [-t\fI type\fP] [-u\fI username\fP] [-w\fI window\fP] .SH "DESCRIPTION" .PP The \fBotp-control\fP command is a front end to the @@ -86,10 +86,23 @@ must be presented to the OTP generator\&. The additional step of entering the count to the OTP generator is not necessary when keys are not shared, as the currrent count will increase on the OTP generator and system database during authentication\&. +.IP "-f" 10 +OTP format\&. One of hex40 dhex40 dec31\&.6 dec31\&.7 dec31\&.8 dec31\&.9 dec31\&.10\&. +hex40 (40 bit hex) is the default\&. dec31\&.6 (31 bit decimal truncated to 6 +digits) is suggested by RFC 4226 and may be required to interoperate with +other HOTP implementations\&. dhex40 uses the dynamic truncate function +in RFC 4226, where hex40 always uses the top 40 bits\&. dhex40 may be the +default in future releases\&. +.IP "-F" 10 +OTP flags\&. All flags are unset by default\&. +.PP +.nf + Flag Description + ----------------------------------------------------------------- + display-count : Display HOTP count when prompted for challenge\&. +.fi .IP "-h" 10 Help\&. -.IP "-F\fI sc_flags\fP" 10 -Set the SC flags with the list-sc command mode\&. 0=CHALLENGE, 1=READERKEY\&. .IP "-H\fI sc_hostname\fP" 10 Set the SC hostname with the list-sc command mode\&. .IP "-I\fI sc_index\fP" 10 @@ -106,26 +119,42 @@ C0C3D47F1CC68ECE0DF81D008F0C0D72D43EB745 Mode Description ------------------------------------------------- add - Add user - activate - Activate user create - Create database - deactivate - Deactivate user - disable - Disable user dump - ASCII dump user record(s) - flags-dspcnt - Set user display count flag\&. - flags-no-dspcnt - Clear user display count flag\&. generate - Generate HOTP for user list - List user record (printable) list-sc - List user record (SC friendly) load - ASCII load user record(s) remove - Remove user - set-count - Reset count for user - set-count-ceil - Reset count ceiling for user + set-count - Set user count + set-count-ceil - Set user count ceiling + set-flags - Set user flags + set-format - Set user format + set-status - Set user status + set-type - Set user OTP type test - Test user .fi .IP "-n" 10 Create new database if one does not exist\&. .IP "-o\fI otp_pathname\fP" 10 Pathname of OTP database\&. +.IP "-s\fI otp_pathname\fP" 10 +OTP Status\&. The default status is active\&. +.PP +.nf + Status Description + ----------------------------------------------------------------- + active : OTP is required for succesful authentication\&. + inactive : OTP may not be required for successful authentication\&. + The OTP authentication module may be configured to allow + inactive accounts to authenticate\&. This may be used to + temporarily remove the OTP authentication method for a user\&. + disabled : Account is disabled\&. OTP authentication will fail\&. +.fi +.IP "-S\fI sc_flags\fP" 10 +Set the SC flags with the list-sc command mode\&. 0=CHALLENGE, 1=READERKEY\&. +.IP "-t\fI type\fP" 10 +OTP Type\&. RFC 4226 HOTP is only supported type\&. .IP "-u\fI username\fP" 10 Username to perform database operation on\&. .IP "-v" 10 @@ -144,32 +173,18 @@ of tokens generated\&. .PP \fBadd\fP : add user to OTP database\&. count_cur and count_ceiling may optionally be specified with -c and -C respectively\&. A random key will be generated -if no key is specified with -k\&. -.PP -\fBactivate\fP : activate user\&. An active user must provide a OTP for successful -authentication\&. An inactive user _may_ be successfully authenticated -without a OTP depending on the application configuration\&. The pam_otp -module can be configured to use this flag with the "allow_inactive" option\&. +if no key is specified with -k\&. The format, flags, status, and type +may be altered from the defaults with -f, -F, -s, and -t respectively\&. .PP \fBcreate\fP : create OTP database\&. The OTP database is a base directory with each user stored in a separate ASCII : delimited file in base_dir/d\&. .PP -\fBdeactivate\fP : deactivate user\&. See activate\&. -.PP -\fBdisable\fP : disable user\&. A disabled user can not successfully authenticate\&. -.PP \fBdump\fP : dump user database in ASCII\&. User records are separated by a newline\&. Fields are : separated\&. All fields except the username are HEX encoded\&. .PP #version:user:key:status:format:type:flags:count_cur:count_ceil:last 01:test:1111111111111111111111111111111111111111:01:01:01:00:00000000000003E8:00000000000007D0:0000000000000000 .PP -\fBflags-dspcnt\fP : set the display count flag\&. An application such as pam_otp will use -this flag to control the display of the OTP count when challenging a -user\&. -.PP -\fBflags-no-dspcnt\fP : clear the display count flag\&. -.PP \fBgenerate\fP : generate OTP for user\&. The -w flag may be used to generate multiple OTP tokens\&. .PP @@ -188,6 +203,14 @@ specified with -I and -F\&. \fBset-count-ceil\fP : set count_ceiling for user\&. A OTP will not authenticate when count_cur >= count_cieiling\&. .PP +\fBset-flags\fP : set flags for user\&. See option -F\&. +.PP +\fBset-format\fP : set format for user\&. See option -f\&. +.PP +\fBset-status\fP : set status for user\&. See option -s\&. +.PP +\fBset-type\fP : set status for user\&. See option -t\&. +.PP \fBtest\fP : test OTP authentication for user\&. .SH "EXAMPLES" .PP @@ -213,7 +236,7 @@ Version\&.\&.\&.\&.\&.\&.\&.\&.1 Status\&.\&.\&.\&.\&.\&.\&.\&.\&.active (1) Format\&.\&.\&.\&.\&.\&.\&.\&.\&.hex40 (1) Type\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.HOTP (1) -Flags\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.00 +Flags\&.\&.\&.\&.\&.\&.\&.\&.\&.\&.[] (0x00) .fi .PP Generate OTP for user bob\&. @@ -267,4 +290,4 @@ Mark Fullmer maf@splintered\&.net \fBurd\fP(1) \fBbcload\fP(1) spyrus-par2(7) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:16 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/otp-control.html b/doc/otp-control.html index e0ed52f..f9d434c 100644 --- a/doc/otp-control.html +++ b/doc/otp-control.html @@ -53,10 +53,15 @@ CLASS="REPLACEABLE" > count_ceil
] [-f format] [-F sc_flags flags
] [-H otpdb_pathname] [-s status] [-S sc_flags] [-t type] [-u

DESCRIPTION

OPTIONS

-f

OTP format. One of hex40 dhex40 dec31.6 dec31.7 dec31.8 dec31.9 dec31.10. +hex40 (40 bit hex) is the default. dec31.6 (31 bit decimal truncated to 6 +digits) is suggested by RFC 4226 and may be required to interoperate with +other HOTP implementations. dhex40 uses the dynamic truncate function +in RFC 4226, where hex40 always uses the top 40 bits. dhex40 may be the +default in future releases.

-F

OTP flags. All flags are unset by default. +

   Flag              Description
+   -----------------------------------------------------------------
+   display-count  :  Display HOTP count when prompted for challenge.

-h

Help.

-F sc_flags

Set the SC flags with the list-sc command mode. 0=CHALLENGE, 1=READERKEY.

-H Mode Description ------------------------------------------------- add - Add user - activate - Activate user create - Create database - deactivate - Deactivate user - disable - Disable user dump - ASCII dump user record(s) - flags-dspcnt - Set user display count flag. - flags-no-dspcnt - Clear user display count flag. generate - Generate HOTP for user list - List user record (printable) list-sc - List user record (SC friendly) load - ASCII load user record(s) remove - Remove user - set-count - Reset count for user - set-count-ceil - Reset count ceiling for user + set-count - Set user count + set-count-ceil - Set user count ceiling + set-flags - Set user flags + set-format - Set user format + set-status - Set user status + set-type - Set user OTP type test - Test user
Pathname of OTP database.

-s otp_pathname

OTP Status. The default status is active. +

   Status     Description
+   -----------------------------------------------------------------
+   active   : OTP is required for succesful authentication.
+   inactive : OTP may not be required for successful authentication.
+              The OTP authentication module may be configured to allow
+              inactive accounts to authenticate.  This may be used to
+              temporarily remove the OTP authentication method for a user.
+   disabled : Account is disabled.  OTP authentication will fail.

-S sc_flags

Set the SC flags with the list-sc command mode. 0=CHALLENGE, 1=READERKEY.

-t type

OTP Type. RFC 4226 HOTP is only supported type.

-u

OTP-CONTROL COMMANDS

: add user to OTP database. count_cur and count_ceiling may optionally be specified with -c and -C respectively. A random key will be generated -if no key is specified with -k.

activate -: activate user. An active user must provide a OTP for successful -authentication. An inactive user _may_ be successfully authenticated -without a OTP depending on the application configuration. The pam_otp -module can be configured to use this flag with the "allow_inactive" option.

deactivate -: deactivate user. See activate.

disable -: disable user. A disabled user can not successfully authenticate.

dump : dump user database in ASCII. User records are separated by a newline. @@ -363,20 +418,6 @@ Fields are : separated. All fields except the username are HEX encoded.

flags-dspcnt -: set the display count flag. An application such as pam_otp will use -this flag to control the display of the OTP count when challenging a -user.

flags-no-dspcnt -: clear the display count flag.

generate : generate OTP for user. The -w flag may be used to generate multiple @@ -423,6 +464,30 @@ count_cur >= count_cieiling.

set-flags +: set flags for user. See option -F.

set-format +: set format for user. See option -f.

set-status +: set status for user. See option -s.

set-type +: set status for user. See option -t.

test : test OTP authentication for user.

EXAMPLES

Create a new OTP database /etc/otpdb. Add user bob with random key.

Display user bob OTP database entry.

Generate OTP for user bob.

Test OTP for user bob.

Dump OTP database to stdout. Fields other than username are hex encoded. @@ -552,7 +617,7 @@ CLASS="INFORMALEXAMPLE" >

Dump OTP user to stdout in format friendly to

AUTHOR

SEE ALSO

- + @@ -26,12 +26,16 @@ Local user database configuration for One Time Password package. -?hnv -c count -C count_ceil --F sc_flags +-f format +-F flags -H sc_hostname -I sc_index -k key -m command_mode -o otpdb_pathname +-s status +-S sc_flags +-t type -u username -w window @@ -88,6 +92,35 @@ system database during authentication. + +-f + + +OTP format. One of hex40 dhex40 dec31.6 dec31.7 dec31.8 dec31.9 dec31.10. +hex40 (40 bit hex) is the default. dec31.6 (31 bit decimal truncated to 6 +digits) is suggested by RFC 4226 and may be required to interoperate with +other HOTP implementations. dhex40 uses the dynamic truncate function +in RFC 4226, where hex40 always uses the top 40 bits. dhex40 may be the +default in future releases. + + + + + +-F + + +OTP flags. All flags are unset by default. + + Flag Description + ----------------------------------------------------------------- + display-count : Display HOTP count when prompted for challenge. + + + + + + -h @@ -97,14 +130,6 @@ Help. - --F sc_flags - - -Set the SC flags with the list-sc command mode. 0=CHALLENGE, 1=READERKEY. - - - -H sc_hostname @@ -146,20 +171,19 @@ C0C3D47F1CC68ECE0DF81D008F0C0D72D43EB745 Mode Description ------------------------------------------------- add - Add user - activate - Activate user create - Create database - deactivate - Deactivate user - disable - Disable user dump - ASCII dump user record(s) - flags-dspcnt - Set user display count flag. - flags-no-dspcnt - Clear user display count flag. generate - Generate HOTP for user list - List user record (printable) list-sc - List user record (SC friendly) load - ASCII load user record(s) remove - Remove user - set-count - Reset count for user - set-count-ceil - Reset count ceiling for user + set-count - Set user count + set-count-ceil - Set user count ceiling + set-flags - Set user flags + set-format - Set user format + set-status - Set user status + set-type - Set user OTP type test - Test user @@ -183,6 +207,44 @@ Pathname of OTP database. + +-s otp_pathname + + +OTP Status. The default status is active. + + Status Description + ----------------------------------------------------------------- + active : OTP is required for succesful authentication. + inactive : OTP may not be required for successful authentication. + The OTP authentication module may be configured to allow + inactive accounts to authenticate. This may be used to + temporarily remove the OTP authentication method for a user. + disabled : Account is disabled. OTP authentication will fail. + + + + + + + +-S sc_flags + + +Set the SC flags with the list-sc command mode. 0=CHALLENGE, 1=READERKEY. + + + + + +-t type + + +OTP Type. RFC 4226 HOTP is only supported type. + + + + -u username @@ -228,28 +290,16 @@ of tokens generated. add : add user to OTP database. count_cur and count_ceiling may optionally be specified with -c and -C respectively. A random key will be generated -if no key is specified with -k. - - -activate -: activate user. An active user must provide a OTP for successful -authentication. An inactive user _may_ be successfully authenticated -without a OTP depending on the application configuration. The pam_otp -module can be configured to use this flag with the "allow_inactive" option. +if no key is specified with -k. The format, flags, status, and type +may be altered from the defaults with -f, -F, -s, and -t respectively. + create : create OTP database. The OTP database is a base directory with each user stored in a separate ASCII : delimited file in base_dir/d. - -deactivate -: deactivate user. See activate. - - -disable -: disable user. A disabled user can not successfully authenticate. - + dump : dump user database in ASCII. User records are separated by a newline. @@ -258,48 +308,66 @@ Fields are : separated. All fields except the username are HEX encoded. #version:user:key:status:format:type:flags:count_cur:count_ceil:last 01:test:1111111111111111111111111111111111111111:01:01:01:00:00000000000003E8:00000000000007D0:0000000000000000 - -flags-dspcnt -: set the display count flag. An application such as pam_otp will use -this flag to control the display of the OTP count when challenging a -user. - - -flags-no-dspcnt -: clear the display count flag. - + generate : generate OTP for user. The -w flag may be used to generate multiple OTP tokens. + list : list user record in user friendly format. + list-sc : list user record in otp-sc import friendly format. The SC hostname must be specified with -H. The SC index and SC flags may optionally be specified with -I and -F. + load : load user record(s)s in ASCII format. See dump. + remove : remove user from OTP database. + set-count : set count_current for user. + set-count-ceil : set count_ceiling for user. A OTP will not authenticate when count_cur >= count_cieiling. + + +set-flags +: set flags for user. See option -F. + + + +set-format +: set format for user. See option -f. + + + +set-status +: set status for user. See option -s. + + + +set-type +: set status for user. See option -t. + + test : test OTP authentication for user. @@ -339,7 +407,7 @@ Version........1 Status.........active (1) Format.........hex40 (1) Type...........HOTP (1) -Flags..........00 +Flags..........[] (0x00) diff --git a/doc/otp-ov-plugin.1 b/doc/otp-ov-plugin.1 index 0e2899a..ab03f3c 100644 --- a/doc/otp-ov-plugin.1 +++ b/doc/otp-ov-plugin.1 @@ -56,7 +56,7 @@ \fBotp-ov-plugin\fP \(em OpenVPN plug-in authentication module for OTP database\&. .SH "SYNOPSIS" .PP -\fBotp-ov-plugin\fP [-?hv] [-o\fI otpdb_fname\fP] +\fBotp-ov-plugin\fP [-?hv] [-o\fI otpdb_fname\fP] [-w\fI otp_window\fP] .SH "DESCRIPTION" .PP The \fBotp-ov-plugin\fP command is plug-in authentication @@ -74,6 +74,8 @@ Help Pathname of OTP database\&. .IP "-v" 10 Verbose +.IP "-w" 10 +Set the OTP challenge window\&. .SH "EXAMPLES" .PP Test the module with user bob\&. @@ -101,4 +103,4 @@ Mark Fullmer maf@splintered\&.net \fBbcload\fP(1) \fBOpenVPN\fP(8) spyrus-par2(7) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:16 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/otp-ov-plugin.html b/doc/otp-ov-plugin.html index 94fa380..0225b88 100644 --- a/doc/otp-ov-plugin.html +++ b/doc/otp-ov-plugin.html @@ -48,12 +48,17 @@ CLASS="REPLACEABLE" > otpdb_fname
] [-w otp_window]

DESCRIPTION

OPTIONS

Verbose

-w

Set the OTP challenge window.

EXAMPLES

Test the module with user bob.

AUTHOR

SEE ALSO

- + @@ -25,6 +25,7 @@ OpenVPN plug-in authentication module for OTP database. otp-ov-plugin -?hv -o otpdb_fname +-w otp_window @@ -74,6 +75,16 @@ Verbose + +-w + + +Set the OTP challenge window. + + + + + diff --git a/doc/otp-sca.1 b/doc/otp-sca.1 index cc9249a..6c329db 100644 --- a/doc/otp-sca.1 +++ b/doc/otp-sca.1 @@ -60,15 +60,15 @@ .SH "DESCRIPTION" .PP The \fBotp-sca\fP command implements a terminal for an MCU based -smart card loaded with the OTP firmware (HOTPC\&.IMG)\&. Host entries consisting -of {hostname,count,shared_key} are downloaded to the smart card using +Smart Card loaded with the OTP firmware (HOTPC\&.IMG)\&. Host entries consisting +of {hostname,count,shared_key} are downloaded to the Smart Card using \fBotp-sca\fP\&. Additionally commands implemented on the -smart card such as HOTP generation and PIN maintenance can be executed +Smart Card such as HOTP generation and PIN maintenance can be executed with the appropriate administratative key\&. .SH "OPTIONS" .IP "-a\fI admin_keyfile\fP" 10 Smart Card administratative key\&. The admin-enable command and -administratative key are used to toggle the smart card into admin mode\&. +administratative key are used to toggle the Smart Card into admin mode\&. Once in admin mode commands admin-disable, adminkey-set, balancecard-set, host-get, host-set, pin-set, and sc-clear can be executed\&. The default admin key, "3030303030303030303030303030303030303030" (HEX), should be changed to @@ -80,10 +80,10 @@ Set debug level\&. .IP "-h" 10 Help\&. .IP "-i\fI index\fP" 10 -Set the 8 bit index\&. The smart card contains numerically indexed records +Set the 8 bit index\&. The Smart Card contains numerically indexed records for each host of the form {hostname,count,shared_key}\&. The firmware will support indexes in the range 0\&.\&.254\&. 255 is reserved\&. Memory -capacity on the smart card may further restrict the index range\&. The +capacity on the Smart Card may further restrict the index range\&. The ZC3\&.9 BasicCard with firmware revision 3 supports up to 85 records\&. .IP "-l" 10 List SC Readers @@ -125,11 +125,18 @@ List SC Readers Configure command_mode modifiers\&. Modifier d applied to the host-get command will generate output in otpdb format\&. Count (c) and Host (h) used with hotp-gen allow passing the Count and Host parameters -respectively\&. The smart card may not be configured to support +respectively\&. The Smart Card may not be configured to support all variations of a command\&. variations .IP "-r\fI reader\fP" 10 -Set the smart card reader\&. Use -l to list available readers\&. +Set Smart Card reader\&. Use -l to list available readers\&. A reader +is defined as class:reader:[option]\&. PCSC and embedded +are the two available classes\&. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]\&. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver\&. Use PCSC: for the first available PC/SC +reader\&. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0\&. .IP "-R\fI reader_keyfile\fP" 10 Smart Card Reader key\&. The reader-key-set command can be used to set this key in the Smart Card\&. To emulate the behavior of @@ -145,10 +152,10 @@ PAR II reader this is set in the PAR II EEProm\&. Set username\&. The username is used with the host-get command and d modifier\&. .IP "-v\fI card_api_version\fP" 10 -Set the smart card API version\&. The binary API between the terminal -and smart card changed between version 2 and 3\&. See command_mode notes +Set the Smart Card API version\&. The binary API between the terminal +and Smart Card changed between version 2 and 3\&. See command_mode notes above\&. The default version is 3\&. Configuring version 2 will allow -maintenance of smart card with version 2 firmware\&. +maintenance of Smart Card with version 2 firmware\&. .SH "SMART CARD COMMANDS" .PP \fBadmin-enable\fP : enable administrative mode\&. The commands admin-disable, admin-key-set, @@ -168,7 +175,7 @@ disable admin mode\&. this command\&. Using a balance reader to generate a HOTP does not require the use of a PIN, and is disabled by default\&. .PP -\fBcapabilities-get\fP : each command on the smart card is represented by a capabilities bit and +\fBcapabilities-get\fP : each command on the Smart Card is represented by a capabilities bit and conditionally compiled into HOTPC\&.IMG\&. capabilities-get will return the available, compiled-in commands\&. Commands are defined in \fBHOTP\&.DEF\fP: @@ -254,7 +261,7 @@ to unlock a SC\&. SC when executing the GetHOTP* commands\&. If the F1 (flag 1) bit of the hostname is set, this key must match the key provided by the reader\&. This functionality allows the reader to weakly authenticate -itself to the smart card and may be used to restrict HOTP generation to +itself to the Smart Card and may be used to restrict HOTP generation to a Spyrus PAR II reader\&. .PP \fBsc-clear\fP : reset the SC to defaults, erase all host entries\&. @@ -337,7 +344,7 @@ when done\&. .fi .PP Use \fBotp-control\fP to create a new database for system dev1 with -user test, store the test user database entry to the smart card with +user test, store the test user database entry to the Smart Card with \fBotp-sca\fP\&. .PP .nf @@ -350,7 +357,7 @@ user test, store the test user database entry to the smart card with # list user test entry in format ready for otp-sca to import\&. Hostname # of system is dev1 \fBotp-control -o /tmp/otpdb -u test -m list-sc -H dev1 | tail -1 > /tmp/test\&.list\fP -# copy card entry to smart card as index 0 +# copy card entry to Smart Card as index 0 \fBecho -n "00:"| cat - /tmp/test\&.list | \&./otp-sca -m host-set\fP \f(CWSetHost (0): Done\fP .fi @@ -410,4 +417,4 @@ Mark Fullmer maf@splintered\&.net \fBbcload\fP(1) \fBurd\fP(1) spyrus-par2(7) -...\" created by instant / docbook-to-man, Tue 01 Dec 2009, 17:12 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/otp-sca.html b/doc/otp-sca.html index 9500104..8d84380 100644 --- a/doc/otp-sca.html +++ b/doc/otp-sca.html @@ -107,13 +107,13 @@ NAME="AEN34" CLASS="COMMAND" >otp-sca
command implements a terminal for an MCU based -smart card loaded with the OTP firmware (HOTPC.IMG). Host entries consisting -of {hostname,count,shared_key} are downloaded to the smart card using +Smart Card loaded with the OTP firmware (HOTPC.IMG). Host entries consisting +of {hostname,count,shared_key} are downloaded to the Smart Card using otp-sca. Additionally commands implemented on the -smart card such as HOTP generation and PIN maintenance can be executed +Smart Card such as HOTP generation and PIN maintenance can be executed with the appropriate administratative key.

Smart Card administratative key. The admin-enable command and -administratative key are used to toggle the smart card into admin mode. +administratative key are used to toggle the Smart Card into admin mode. Once in admin mode commands admin-disable, adminkey-set, balancecard-set, host-get, host-set, pin-set, and sc-clear can be executed. The default admin key, "3030303030303030303030303030303030303030" (HEX), should be changed to @@ -181,10 +181,10 @@ CLASS="REPLACEABLE" >

Set the 8 bit index. The smart card contains numerically indexed records +>Set the 8 bit index. The Smart Card contains numerically indexed records for each host of the form {hostname,count,shared_key}. The firmware will support indexes in the range 0..254. 255 is reserved. Memory -capacity on the smart card may further restrict the index range. The +capacity on the Smart Card may further restrict the index range. The ZC3.9 BasicCard with firmware revision 3 supports up to 85 records.

Configure command_mode modifiers. Modifier d applied to the host-get command will generate output in otpdb format. Count (c) and Host (h) used with hotp-gen allow passing the Count and Host parameters -respectively. The smart card may not be configured to support +respectively. The Smart Card may not be configured to support all variations of a command. variations

Set the smart card reader. Use -l to list available readers.

Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:[option]. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0.

-R

Set the smart card API version. The binary API between the terminal -and smart card changed between version 2 and 3. See command_mode notes +>Set the Smart Card API version. The binary API between the terminal +and Smart Card changed between version 2 and 3. See command_mode notes above. The default version is 3. Configuring version 2 will allow -maintenance of smart card with version 2 firmware.

SMART CARD COMMANDS

capabilities-get
-: each command on the smart card is represented by a capabilities bit and +: each command on the Smart Card is represented by a capabilities bit and conditionally compiled into HOTPC.IMG. capabilities-get will return the available, compiled-in commands. Commands are defined in

EXAMPLES

Change the administratative key from the default. Disable admin mode @@ -623,14 +636,14 @@ CLASS="INFORMALEXAMPLE" >

Use otp-control to create a new database for system dev1 with -user test, store the test user database entry to the smart card with +user test, store the test user database entry to the Smart Card with otp-scaotp-control -o /tmp/otpdb -u test -m list-sc -H dev1 | tail -1 > /tmp/test.list -# copy card entry to smart card as index 0 +# copy card entry to Smart Card as index 0 echo -n "00:"| cat - /tmp/test.list | ./otp-sca -m host-set

Dump card contents to stdout. Note fields are encoded in HEX including @@ -712,7 +725,7 @@ CLASS="INFORMALEXAMPLE" >

Reset user PIN for card with secret.key as the admin key.

Generate HOTP for dev1. Use hostname-get to find the index for dev1. Use @@ -798,7 +811,7 @@ HOTP: 52DCD05FE5 -- dev1

AUTHOR

SEE ALSO

- + @@ -42,10 +42,10 @@ Smart Card Administration for One Time Password package. DESCRIPTION The otp-sca command implements a terminal for an MCU based -smart card loaded with the OTP firmware (HOTPC.IMG). Host entries consisting -of {hostname,count,shared_key} are downloaded to the smart card using +Smart Card loaded with the OTP firmware (HOTPC.IMG). Host entries consisting +of {hostname,count,shared_key} are downloaded to the Smart Card using otp-sca. Additionally commands implemented on the -smart card such as HOTP generation and PIN maintenance can be executed +Smart Card such as HOTP generation and PIN maintenance can be executed with the appropriate administratative key. @@ -59,7 +59,7 @@ with the appropriate administratative key. Smart Card administratative key. The admin-enable command and -administratative key are used to toggle the smart card into admin mode. +administratative key are used to toggle the Smart Card into admin mode. Once in admin mode commands admin-disable, adminkey-set, balancecard-set, host-get, host-set, pin-set, and sc-clear can be executed. The default admin key, "3030303030303030303030303030303030303030" (HEX), should be changed to @@ -99,10 +99,10 @@ Help. -i index -Set the 8 bit index. The smart card contains numerically indexed records +Set the 8 bit index. The Smart Card contains numerically indexed records for each host of the form {hostname,count,shared_key}. The firmware will support indexes in the range 0..254. 255 is reserved. Memory -capacity on the smart card may further restrict the index range. The +capacity on the Smart Card may further restrict the index range. The ZC3.9 BasicCard with firmware revision 3 supports up to 85 records. @@ -164,7 +164,7 @@ List SC Readers Configure command_mode modifiers. Modifier d applied to the host-get command will generate output in otpdb format. Count (c) and Host (h) used with hotp-gen allow passing the Count and Host parameters -respectively. The smart card may not be configured to support +respectively. The Smart Card may not be configured to support all variations of a command. variations @@ -175,7 +175,14 @@ variations -r reader -Set the smart card reader. Use -l to list available readers. +Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:option. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:serial_port. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0. @@ -214,10 +221,10 @@ d modifier. -v card_api_version -Set the smart card API version. The binary API between the terminal -and smart card changed between version 2 and 3. See command_mode notes +Set the Smart Card API version. The binary API between the terminal +and Smart Card changed between version 2 and 3. See command_mode notes above. The default version is 3. Configuring version 2 will allow -maintenance of smart card with version 2 firmware. +maintenance of Smart Card with version 2 firmware. @@ -256,7 +263,7 @@ the use of a PIN, and is disabled by default. capabilities-get -: each command on the smart card is represented by a capabilities bit and +: each command on the Smart Card is represented by a capabilities bit and conditionally compiled into HOTPC.IMG. capabilities-get will return the available, compiled-in commands. Commands are defined in HOTP.DEF: @@ -354,7 +361,7 @@ to unlock a SC. SC when executing the GetHOTP* commands. If the F1 (flag 1) bit of the hostname is set, this key must match the key provided by the reader. This functionality allows the reader to weakly authenticate -itself to the smart card and may be used to restrict HOTP generation to +itself to the Smart Card and may be used to restrict HOTP generation to a Spyrus PAR II reader. @@ -464,7 +471,7 @@ when done. Use otp-control to create a new database for system dev1 with -user test, store the test user database entry to the smart card with +user test, store the test user database entry to the Smart Card with otp-sca. @@ -482,7 +489,7 @@ user test, store the test user database entry to the smart card with # of system is dev1 otp-control -o /tmp/otpdb -u test -m list-sc -H dev1 | tail -1 > /tmp/test.list -# copy card entry to smart card as index 0 +# copy card entry to Smart Card as index 0 echo -n "00:"| cat - /tmp/test.list | ./otp-sca -m host-set SetHost (0): Done diff --git a/doc/otp-sct.1 b/doc/otp-sct.1 index d4ae618..1d5bef2 100644 --- a/doc/otp-sct.1 +++ b/doc/otp-sct.1 @@ -60,33 +60,40 @@ .SH "DESCRIPTION" .PP The \fBotp-sct\fP command is a user interface to generating -One Time Passwords with a smart card loaded with OTP software\&. +One Time Passwords with a Smart Card loaded with OTP software\&. .SH "OPTIONS" .IP "-c\fI count\fP" 10 -Configure the optional count parameter to sync a smart card to a challenge\&. +Configure the optional count parameter to sync a Smart Card to a challenge\&. .IP "-d\fI debug_level\fP" 10 Set debug level\&. .IP "-h" 10 Help\&. .IP "-i\fI index\fP" 10 -Set the 8 bit index\&. The smart card contains numerically indexed records +Set the 8 bit index\&. The Smart Card contains numerically indexed records for each host system\&. Use the -l option to list hostnames associated with the index\&. The default index is 0\&. .IP "-l" 10 List SC Readers .IP "-L" 10 -List host systems configured on the smart card\&. The index is used with the -i option\&. +List host systems configured on the Smart Card\&. The index is used with the -i option\&. .IP "-o" 10 Set new PIN\&. .IP "-r\fI reader\fP" 10 -Set the smart card reader\&. Use -l to list available readers\&. +Set Smart Card reader\&. Use -l to list available readers\&. A reader +is defined as class:reader:[option]\&. PCSC and embedded +are the two available classes\&. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]\&. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver\&. Use PCSC: for the first available PC/SC +reader\&. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0\&. .IP "-v\fI card_api_version\fP" 10 -Set the smart card API version\&. The binary API between the terminal -and smart card changed between version 2 and 3\&. See command mode notes +Set the Smart Card API version\&. The binary API between the terminal +and Smart Card changed between version 2 and 3\&. See command mode notes above\&. The default version is 3\&. Configuring version 2 will allow -maintenance of smart card with version 2 firmware\&. +maintenance of Smart Card with version 2 firmware\&. .IP "-V" 10 -List the smart card firmware version\&. +List the Smart Card firmware version\&. .IP "-1" 10 Use the version 1 GetHOTP command instead of the default GetHOTPHostCount32\&. The latter is not available on firmware revision 1\&. GetHOTP may be conditionally @@ -101,7 +108,7 @@ Generate a HOTP for the first system on the first PCSC reader found\&. HOTP: dev1\&.eng 2A5AB4B78D\fP .fi .PP -List systems configured on smart card in default reader\&. Generate HOTP +List systems configured on Smart Card in default reader\&. Generate HOTP for dev3\&.eng with count 32\&. .PP .nf @@ -131,4 +138,4 @@ Mark Fullmer maf@splintered\&.net \fBbcload\fP(1) \fBurd\fP(1) spyrus-par2(7) -...\" created by instant / docbook-to-man, Tue 01 Dec 2009, 17:12 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/otp-sct.html b/doc/otp-sct.html index e67a467..8e33249 100644 --- a/doc/otp-sct.html +++ b/doc/otp-sct.html @@ -82,7 +82,7 @@ NAME="AEN24" CLASS="COMMAND" >otp-sct command is a user interface to generating -One Time Passwords with a smart card loaded with OTP software.

Configure the optional count parameter to sync a smart card to a challenge.

Configure the optional count parameter to sync a Smart Card to a challenge.

-d

Set the 8 bit index. The smart card contains numerically indexed records +>Set the 8 bit index. The Smart Card contains numerically indexed records for each host system. Use the -l option to list hostnames associated with the index. The default index is 0.

-L

List host systems configured on the smart card. The index is used with the -i option.

List host systems configured on the Smart Card. The index is used with the -i option.

-o

Set the smart card reader. Use -l to list available readers.

Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:[option]. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:[serial_port]. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0.

-v

Set the smart card API version. The binary API between the terminal -and smart card changed between version 2 and 3. See command mode notes +>Set the Smart Card API version. The binary API between the terminal +and Smart Card changed between version 2 and 3. See command mode notes above. The default version is 3. Configuring version 2 will allow -maintenance of smart card with version 2 firmware.

-V

List the smart card firmware version.

List the Smart Card firmware version.

-1

EXAMPLES

Generate a HOTP for the first system on the first PCSC reader found.

List systems configured on smart card in default reader. Generate HOTP +>List systems configured on Smart Card in default reader. Generate HOTP for dev3.eng with count 32.

AUTHOR

SEE ALSO

- + @@ -37,7 +37,7 @@ Smart Card Terminal for One Time Password package. DESCRIPTION The otp-sct command is a user interface to generating -One Time Passwords with a smart card loaded with OTP software. +One Time Passwords with a Smart Card loaded with OTP software. @@ -49,7 +49,7 @@ One Time Passwords with a smart card loaded with OTP software. -c count -Configure the optional count parameter to sync a smart card to a challenge. +Configure the optional count parameter to sync a Smart Card to a challenge. @@ -76,7 +76,7 @@ Help. -i index -Set the 8 bit index. The smart card contains numerically indexed records +Set the 8 bit index. The Smart Card contains numerically indexed records for each host system. Use the -l option to list hostnames associated with the index. The default index is 0. @@ -95,7 +95,7 @@ List SC Readers -L -List host systems configured on the smart card. The index is used with the -i option. +List host systems configured on the Smart Card. The index is used with the -i option. @@ -113,7 +113,14 @@ Set new PIN. -r reader -Set the smart card reader. Use -l to list available readers. +Set Smart Card reader. Use -l to list available readers. A reader +is defined as class:reader:option. PCSC and embedded +are the two available classes. The embedded class contains the acr30s driver +which is specified as embedded:acr30s:serial_port. +If pcscd is running the first PC/SC reader will be the default followed by +the embedded acr30s driver. Use PCSC: for the first available PC/SC +reader. Use embedded:acr30s:/dev/cuaU0 for the embedded acr30s driver +with serial port /dev/cuaU0. @@ -122,10 +129,10 @@ Set the smart card reader. Use -l to list available readers. -v card_api_version -Set the smart card API version. The binary API between the terminal -and smart card changed between version 2 and 3. See command mode notes +Set the Smart Card API version. The binary API between the terminal +and Smart Card changed between version 2 and 3. See command mode notes above. The default version is 3. Configuring version 2 will allow -maintenance of smart card with version 2 firmware. +maintenance of Smart Card with version 2 firmware. @@ -134,7 +141,7 @@ maintenance of smart card with version 2 firmware. -V -List the smart card firmware version. +List the Smart Card firmware version. @@ -171,7 +178,7 @@ HOTP: dev1.eng 2A5AB4B78D -List systems configured on smart card in default reader. Generate HOTP +List systems configured on Smart Card in default reader. Generate HOTP for dev3.eng with count 32. diff --git a/doc/pam_otp.1 b/doc/pam_otp.1 index 9f9aa1b..712f19e 100644 --- a/doc/pam_otp.1 +++ b/doc/pam_otp.1 @@ -79,6 +79,8 @@ require_db_entry option is set\&. By default users not in the OTP database are permitted\&. .IP "\fIotpdb=\fP\fBalternate_otpdb\fP" 10 \fBalternate_otpdb\fP is used as the OTP database\&. +.IP "\fIwindow=window\fP" 10 +Set OTP challenge window\&. .SH "AUTHOR" .PP Mark Fullmer maf@splintered\&.net @@ -93,4 +95,4 @@ Mark Fullmer maf@splintered\&.net \fBbcload\fP(1) \fBpam\fP(8) spyrus-par2(7) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:16 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/pam_otp.html b/doc/pam_otp.html index 73a6ab6..b98f8c1 100644 --- a/doc/pam_otp.html +++ b/doc/pam_otp.html @@ -148,13 +148,24 @@ CLASS="FILENAME" >alternate_otpdb
is used as the OTP database.

window=window

Set OTP challenge window.

AUTHOR

SEE ALSO

- + @@ -95,6 +95,15 @@ database are permitted. + +window=window + + +Set OTP challenge window. + + + + diff --git a/doc/spyrus-par2.7 b/doc/spyrus-par2.7 index d8a5771..0828952 100644 --- a/doc/spyrus-par2.7 +++ b/doc/spyrus-par2.7 @@ -65,8 +65,12 @@ menu and two digit shortcut methods are provided for host selection\&. Additional functionality includes Smart Card PIN change, overriding default increment-on-generate per-host HOTP count behavior, and firmware management\&. .PP -With the HOTP displayed, press Enter to repeat the host selection process -for additional token generation\&. +With the HOTP displayed, press Enter to repeat the host +selection process for additional token generation or Down Arrow +to generate a token for the next host\&. +.PP +The HOTP token is displayed as 40 bit hexadecimal or 6-10 digit decimal +based on the format bit field provided by the Smart Card\&. .PP Use the host selection shortcut to extend battery life\&. .SS "Basic Functions:" @@ -107,6 +111,12 @@ with this option\&. \fB\fP Cursor up one line\&. .PP \fB\fP Cursor down one line\&. +.SS "HOTP Display" +.PP +.PP +\fB\fP Jump back to host selection\&. +.PP +\fB\fP Generate token for next host\&. .SH "LOADING FIRMWARE" .PP The PAR II is factory loaded with the @@ -191,4 +201,4 @@ may not\&. \fBurd\fP(1) \fBbcload\fP(1) \fBOpenVPN\fP(8) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:16 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/spyrus-par2.html b/doc/spyrus-par2.html index 2df7913..fe997f2 100644 --- a/doc/spyrus-par2.html +++ b/doc/spyrus-par2.html @@ -58,14 +58,18 @@ menu and two digit shortcut methods are provided for host selection. Additional functionality includes Smart Card PIN change, overriding default increment-on-generate per-host HOTP count behavior, and firmware management.

With the HOTP displayed, press Enter to repeat the host selection process -for additional token generation.

With the HOTP displayed, press Enter to repeat the host +selection process for additional token generation or Down Arrow +to generate a token for the next host.

The HOTP token is displayed as 40 bit hexadecimal or 6-10 digit decimal +based on the format bit field provided by the Smart Card.

Use the host selection shortcut to extend battery life.

Basic Functions:

PIN Entry:

Host Selection:

Host Selection With Menu:

DOWN Cursor down one line.

HOTP Display

Enter Jump back to host selection.

DOWN Generate token for next host.

LOADING FIRMWARE

EEPROM CUSTOMIZATION

AUTHOR

BUGS

SEE ALSO

- + @@ -37,8 +37,13 @@ Additional functionality includes Smart Card PIN change, overriding default increment-on-generate per-host HOTP count behavior, and firmware management. -With the HOTP displayed, press Enter to repeat the host selection process -for additional token generation. +With the HOTP displayed, press Enter to repeat the host +selection process for additional token generation or Down Arrow +to generate a token for the next host. + + +The HOTP token is displayed as 40 bit hexadecimal or 6-10 digit decimal +based on the format bit field provided by the Smart Card. Use the host selection shortcut to extend battery life. @@ -126,6 +131,20 @@ Host Selection With Menu: + + +HOTP Display + + + + +Enter Jump back to host selection. + + + +DOWN Generate token for next host. + + diff --git a/doc/urd.1 b/doc/urd.1 index 2d04b62..6f27218 100644 --- a/doc/urd.1 +++ b/doc/urd.1 @@ -56,7 +56,7 @@ \fBurd\fP \(em Micro footprint RADIUS daemon with One Time Password support\&. .SH "SYNOPSIS" .PP -\fBurd\fP [-?AhdDOux] [-a\fI allowed_users_file\fP] [-b\fI local_ip\fP] [-B\fI local_port\fP] [-o\fI otp_db\fP] [-p\fI passwd_file\fP] [-P\fI pid_file\fP] [-s\fI secret_file\fP] +\fBurd\fP [-?AhdDOux] [-a\fI allowed_users_file\fP] [-b\fI local_ip\fP] [-B\fI local_port\fP] [-o\fI otp_db\fP] [-p\fI passwd_file\fP] [-P\fI pid_file\fP] [-s\fI secret_file\fP] [-w\fI otp_window\fP] .SH "DESCRIPTION" .PP The \fBurd\fP daemon implements a minimal subset @@ -139,6 +139,8 @@ will be required\&. Drop every other RADIUS request from a NAS\&. This is a debugging feature intended to stress test the reply cache code\&. The reply cache implements state retention required for the use of One Time Passwords\&. +.IP "-w" 10 +Set the OTP challenge window\&. .SH "EXAMPLES" .PP The following command will start the urd server, bind it to IP address @@ -166,4 +168,4 @@ Mark Fullmer maf@splintered\&.net \fBbcload\fP(1) \fBotp-ov-plugin\fP(1) spyrus-par2(7) -...\" created by instant / docbook-to-man, Mon 30 Nov 2009, 13:16 +...\" created by instant / docbook-to-man, Sun 27 Dec 2009, 22:01 diff --git a/doc/urd.html b/doc/urd.html index 22a4c51..5abf064 100644 --- a/doc/urd.html +++ b/doc/urd.html @@ -78,12 +78,17 @@ CLASS="REPLACEABLE" > secret_file] [-w otp_window]

DESCRIPTION

OPTIONS

-w

Set the OTP challenge window.

EXAMPLES

The following command will start the urd server, bind it to IP address @@ -408,7 +419,7 @@ CLASS="SCREEN" >

AUTHOR

SEE ALSO

- + @@ -31,6 +31,7 @@ Micro footprint RADIUS daemon with One Time Password support. -p passwd_file -P pid_file -s secret_file +-w otp_window @@ -226,6 +227,15 @@ implements state retention required for the use of One Time Passwords. + +-w + + +Set the OTP challenge window. + + + + diff --git a/htsoft-downloader/htsoft-downloader.c b/htsoft-downloader/htsoft-downloader.c index eedb431..049e9db 100644 --- a/htsoft-downloader/htsoft-downloader.c +++ b/htsoft-downloader/htsoft-downloader.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: htsoft-downloader.c 13 2009-11-26 16:37:03Z maf $ + * $Id: htsoft-downloader.c 75 2009-12-26 20:59:23Z maf $ */ #include @@ -82,7 +82,7 @@ void help(void); int htsoft_v1bl_idack(int fd, int verbose); int htsoft_v1bl_upload(int fd, uint16_t load_offset, uint8_t *buf, uint8_t buf_len, int verbose, int max_retries); -int htsoft_v1bl_done(int fd, int verbose, int retries); +int htsoft_v1bl_done(int fd, int verbose, int retries, int ignore_wok_timeout); int n22b(char *h, u_char *b); int n2b(char *h, u_char *b); @@ -97,7 +97,7 @@ int main(int argc, char **argv) uint8_t ld_buf[256], ld_buf_len; uint16_t h_load_offset, tmp_load_offset, buf_load_offset; int i, r, pic_fd, lineno, lbuf_len, got_eof, pic_tmout, verbose; - int max_retries; + int max_retries, ignore_last_wok_timeout; char *pic_dev; xerr_setid(argv[0]); @@ -110,8 +110,9 @@ int main(int argc, char **argv) max_retries = HTSOFT_RETRIES; h_load_offset = 0; buf_load_offset = 0; + ignore_last_wok_timeout = 0; - while ((i = getopt(argc, argv, "f:h?r:t:v:")) != -1) { + while ((i = getopt(argc, argv, "f:h?ir:t:v:")) != -1) { switch (i) { @@ -125,6 +126,10 @@ int main(int argc, char **argv) exit(0); break; /* notreached */ + case 'i': + ignore_last_wok_timeout = 1; + break; + case 'r': max_retries = atoi(optarg); break; @@ -380,7 +385,8 @@ int main(int argc, char **argv) if (!got_eof) xerr_warnx("Warning: Short file, no EOF."); - if (htsoft_v1bl_done(pic_fd, verbose, max_retries) < 0) + if (htsoft_v1bl_done(pic_fd, verbose, max_retries, + ignore_last_wok_timeout) < 0) xerr_errx(1, "htsoft_v1bl_done(): failed"); close(pic_fd); @@ -680,20 +686,23 @@ int htsoft_v1bl_upload(int fd, uint16_t load_offset, uint8_t *buf, * * function will not return until WOK is received. * - * fd - serial com port - * verbose - verbosity level + * fd - serial com port + * verbose - verbosity level + * retries - number of retries + * ignore_wok_timeout - ignore last WOK -- some devices do not send this * * returns 0 success * <0 failure * */ -int htsoft_v1bl_done(int fd, int verbose, int retries) +int htsoft_v1bl_done(int fd, int verbose, int retries, int ignore_wok_timeout) { uint8_t t,r; - int n, good_write, i; + int n, good_write, i, timeout; t = HTSOFT_V1BL_DONE; good_write = 0; + timeout = 0; for (i = 0; i < retries; ++i) { @@ -708,6 +717,13 @@ int htsoft_v1bl_done(int fd, int verbose, int retries) if ((n = read(fd, &r, 1)) < 0) xerr_err(1, "read()"); + /* some devices may not send this */ + if (ignore_wok_timeout && n == 0) { + timeout = 1; + good_write = 1; + break; + } + /* timeout? */ if (n == 0) continue; @@ -734,8 +750,12 @@ int htsoft_v1bl_done(int fd, int verbose, int retries) fflush(stdout); } - if (verbose && !good_write) + if (verbose && !good_write) printf("PIC reset failed.\n"); + else if (verbose && good_write && ignore_wok_timeout && timeout) + printf("PIC reset sent, ignored last WOK timeout.\n"); + else + printf("PIC reset complete.\n"); if (good_write) return 0; /* success */ @@ -747,7 +767,7 @@ int htsoft_v1bl_done(int fd, int verbose, int retries) void help(void) { fprintf(stderr, - "htsoft-downloader [-h?v] [-f serial_device] [-r retries]\n"); + "htsoft-downloader [-hi?v] [-f serial_device] [-r retries]\n"); fprintf(stderr, " [-t timeout (.1 second/timeout)] [-v verbose_level]\n"); } /* help */ diff --git a/otp-control/otp-control.c b/otp-control/otp-control.c index 214374b..63a0c77 100644 --- a/otp-control/otp-control.c +++ b/otp-control/otp-control.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otp-control.c 13 2009-11-26 16:37:03Z maf $ + * $Id: otp-control.c 55 2009-12-17 01:59:35Z maf $ */ #include @@ -39,24 +39,23 @@ #include "ffdb.h" #include "str.h" -#define MODE_ADD 1 -#define MODE_ACTIVATE 2 -#define MODE_DEACTIVATE 3 -#define MODE_DISABLE 4 -#define MODE_DUMP 5 -#define MODE_GENERATE 6 -#define MODE_LIST 7 -#define MODE_LOAD 8 -#define MODE_REMOVE 9 -#define MODE_SET_COUNT 10 -#define MODE_SET_COUNT_CEIL 11 -#define MODE_TEST 12 -#define MODE_CREATE 13 -#define MODE_FLAGS_DSPCNT_SET 14 -#define MODE_FLAGS_DSPCNT_CLEAR 15 -#define MODE_LIST_SC 18 +#define MODE_ADD 1 +#define MODE_DUMP 5 +#define MODE_GENERATE 6 +#define MODE_LIST 7 +#define MODE_LOAD 8 +#define MODE_REMOVE 9 +#define MODE_SET_COUNT 10 +#define MODE_SET_COUNT_CEIL 11 +#define MODE_TEST 12 +#define MODE_CREATE 13 +#define MODE_LIST_SC 18 +#define MODE_SET_STATUS 19 +#define MODE_SET_TYPE 20 +#define MODE_SET_FORMAT 21 +#define MODE_SET_FLAGS 22 -#define KEY_HEX160_LEN 40 +#define KEY_HEX160_LEN 40 #define DEV_RANDOM "/dev/urandom" @@ -71,13 +70,13 @@ int main (int argc, char **argv) int i, j, r, mode, window, db_flags, open_mode, open_op, verbose; char *otpdb_fname; uint64_t u_count, u_count_ceil, count_offset, tmp64u; - uint8_t u_version, u_status, u_format, u_type, sc_index; + uint8_t u_version, u_status, u_format, u_type, u_flags, sc_index; uint8_t sc_flags[SC_HOSTNAME_LEN]; unsigned char u_key160[20]; char key_hex160[KEY_HEX160_LEN+1]; char crsp_tmp[11]; char *u_username, *u_key_ascii, *sc_hostname; - char *endptr; + char *endptr, *i_status, *i_format, *i_type, *i_flags; otpdb_fname = OTP_DB_FNAME; sc_index = 0; @@ -92,16 +91,18 @@ int main (int argc, char **argv) u_format = OTP_FORMAT_HEX40; u_type = OTP_TYPE_HOTP; u_status = OTP_STATUS_ACTIVE; + u_flags = 0; u_username = (char*)0L; u_key_ascii = (char*)0L; endptr = (char*)0L; sc_hostname = (char*)0L; bzero(sc_flags, SC_HOSTNAME_LEN); + i_status = i_type = i_format = i_flags = (char*)0L; /* init xerr */ xerr_setid(argv[0]); - while ((i = getopt(argc, argv, "c:C:hF:H:I:?k:m:no:u:w:v")) != -1) { + while ((i = getopt(argc, argv, "c:C:hf:F:H:I:?k:m:no:s:S:t:u:w:v")) != -1) { switch (i) { @@ -117,15 +118,13 @@ int main (int argc, char **argv) xerr_errx(1, "strtoull(%s): failed at %c.", optarg, *endptr); break; - case 'F' : - for (j = 0; j < strlen(optarg); ++j) { - if (optarg[j] == '0') - sc_flags[HOSTNAME_POS_CHALLENGE] = HOSTNAME_FLAG_MASK; - else if (optarg[j] == '1') - sc_flags[HOSTNAME_POS_READERKEY] = HOSTNAME_FLAG_MASK; - else - xerr_errx(1, "Unknown sc_flag %c.", optarg[j]); - } /* j */ + case 'f': + i_format = optarg; + break; + + case 'F': + if (str_setflag8(otp_flags_l, &u_flags, optarg, 0, OTP_FLAGS_BITS) < 0) + xerr_errx(1, "Invalid flag %s.", optarg); break; case 'H': @@ -153,20 +152,10 @@ int main (int argc, char **argv) if (!strcasecmp(optarg, "add")) { mode = MODE_ADD; - } else if (!strcasecmp(optarg, "activate")) { - mode = MODE_ACTIVATE; } else if (!strcasecmp(optarg, "create")) { mode = MODE_CREATE; - } else if (!strcasecmp(optarg, "deactivate")) { - mode = MODE_DEACTIVATE; - } else if (!strcasecmp(optarg, "disable")) { - mode = MODE_DISABLE; } else if (!strcasecmp(optarg, "dump")) { mode = MODE_DUMP; - } else if (!strcasecmp(optarg, "flags-dspcnt")) { - mode = MODE_FLAGS_DSPCNT_SET; - } else if (!strcasecmp(optarg, "flags-no-dspcnt")) { - mode = MODE_FLAGS_DSPCNT_CLEAR; } else if (!strcasecmp(optarg, "generate")) { mode = MODE_GENERATE; } else if (!strcasecmp(optarg, "list")) { @@ -181,6 +170,14 @@ int main (int argc, char **argv) mode = MODE_SET_COUNT; } else if (!strcasecmp(optarg, "set-count-ceil")) { mode = MODE_SET_COUNT_CEIL; + } else if (!strcasecmp(optarg, "set-flags")) { + mode = MODE_SET_FLAGS; + } else if (!strcasecmp(optarg, "set-format")) { + mode = MODE_SET_FORMAT; + } else if (!strcasecmp(optarg, "set-status")) { + mode = MODE_SET_STATUS; + } else if (!strcasecmp(optarg, "set-type")) { + mode = MODE_SET_TYPE; } else if (!strcasecmp(optarg, "test")) { mode = MODE_TEST; } else { @@ -188,6 +185,25 @@ int main (int argc, char **argv) } break; + case 's': + i_status = optarg; + break; + + case 'S' : + for (j = 0; j < strlen(optarg); ++j) { + if (optarg[j] == '0') + sc_flags[HOSTNAME_POS_CHALLENGE] = HOSTNAME_FLAG_MASK; + else if (optarg[j] == '1') + sc_flags[HOSTNAME_POS_READERKEY] = HOSTNAME_FLAG_MASK; + else + xerr_errx(1, "Unknown sc_flag %c.", optarg[j]); + } /* j */ + break; + + case 't': + i_type = optarg; + break; + case 'n': db_flags |= OTP_DB_CREATE_SOFT; break; @@ -232,12 +248,38 @@ int main (int argc, char **argv) if ((mode == MODE_LIST_SC) && (!sc_hostname)) xerr_errx(1, "Hostname required."); + /* check username length */ if (u_username && (strlen(u_username) > OTP_USER_NAME_LEN)) xerr_errx(1, "Username > OTP_USER_NAME_LEN."); + /* input key */ if (u_key_ascii && u_key_ascii[0] != '-') xerr_errx(1, "Key not accepted on command line, use - for stdin"); + /* format */ + if (i_format) + if (str_find8(otp_format_l, &u_format, i_format, 1, OTP_FORMAT_MAX)) + xerr_errx(1, "Invalid format %s.", i_format); + + if ((mode == MODE_SET_FORMAT) && (!i_format)) + xerr_errx(1, "Format value not specified."); + + /* status */ + if (i_status) + if (str_find8(otp_status_l, &u_status, i_status, 1, OTP_STATUS_MAX)) + xerr_errx(1, "Invalid status %s.", i_status); + + if ((mode == MODE_SET_STATUS) && (!i_status)) + xerr_errx(1, "Status value not specified."); + + /* type */ + if (i_type) + if (str_find8(otp_type_l, &u_type, i_type, 1, OTP_TYPE_MAX)) + xerr_errx(1, "Invalid type %s.", i_type); + + if ((mode == MODE_SET_TYPE) && (!i_type)) + xerr_errx(1, "Type value not specified."); + /* user specified key? need key material? */ if (mode == MODE_ADD) { @@ -307,20 +349,16 @@ int main (int argc, char **argv) /* * modes requiring open and get of user record: - * ACTIVATE, DEACTIVATE, DISABLE, GENERATE, LIST, SET_COUNT, - * SET_COUNT_CEIL, TEST, FLAGS_DSPCNT_SET, FLAGS_DSPCNT_CLEAR */ - - if ((mode == MODE_ACTIVATE) || - (mode == MODE_DEACTIVATE) || - (mode == MODE_DISABLE) || - (mode == MODE_FLAGS_DSPCNT_SET) || - (mode == MODE_FLAGS_DSPCNT_CLEAR) || - (mode == MODE_GENERATE) || + if ((mode == MODE_GENERATE) || (mode == MODE_LIST) || (mode == MODE_LIST_SC) || (mode == MODE_SET_COUNT) || (mode == MODE_SET_COUNT_CEIL) || + (mode == MODE_SET_FLAGS) || + (mode == MODE_SET_FORMAT) || + (mode == MODE_SET_STATUS) || + (mode == MODE_SET_TYPE) || (mode == MODE_TEST)) { /* rw or ro? */ @@ -381,29 +419,25 @@ int main (int argc, char **argv) } /* MODE_GENERATE */ - if ((mode == MODE_ACTIVATE) || - (mode == MODE_DEACTIVATE) || - (mode == MODE_DISABLE) || - (mode == MODE_FLAGS_DSPCNT_SET) || - (mode == MODE_FLAGS_DSPCNT_CLEAR) || - (mode == MODE_SET_COUNT) || - (mode == MODE_SET_COUNT_CEIL)) { + if ((mode == MODE_SET_COUNT) || + (mode == MODE_SET_COUNT_CEIL) || + (mode == MODE_SET_FLAGS) || + (mode == MODE_SET_FORMAT) || + (mode == MODE_SET_STATUS) || + (mode == MODE_SET_TYPE)) { - if (mode == MODE_ACTIVATE) - ou.status = OTP_STATUS_ACTIVE; - else if (mode == MODE_DEACTIVATE) - ou.status = OTP_STATUS_INACTIVE; - else if (mode == MODE_DISABLE) - ou.status = OTP_STATUS_DISABLED; - else if (mode == MODE_SET_COUNT) + if (mode == MODE_SET_COUNT) ou.count = u_count; else if (mode == MODE_SET_COUNT_CEIL) ou.count_ceil = u_count_ceil; - else if (mode == MODE_FLAGS_DSPCNT_SET) - ou.flags |= OTP_USER_FLAGS_DSPCNT; - else if (mode == MODE_FLAGS_DSPCNT_CLEAR) - ou.flags &= ~OTP_USER_FLAGS_DSPCNT; - + else if (mode == MODE_SET_FLAGS) + ou.flags = u_flags; + else if (mode == MODE_SET_FORMAT) + ou.format = u_format; + else if (mode == MODE_SET_STATUS) + ou.status = u_status; + else if (mode == MODE_SET_TYPE) + ou.type = u_type; if (otp_urec_put(otpctx, &ou) < 0) xerr_errx(1, "otp_urec_put(): failed."); @@ -435,35 +469,58 @@ mode_done: return 0; -} +} /* main */ void help(void) { - fprintf(stderr, "otp-control [-?hnv] [-c count] [-C count_ceil] [-F sc_flags] [-H sc_hostname]\n"); - fprintf(stderr, " [-I sc_index] [-k key] [ -m command_mode] [-o otbdb_pathname]\n"); - fprintf(stderr, " [-u username] [-w window]\n\n"); + int i; + + fprintf(stderr, "otp-control [-?hnv] [-c count] [-C count_ceil] [-f format] [-F flags]\n"); + fprintf(stderr, " [-H sc_hostname] [-I sc_index] [-k key] [-m command_mode]\n"); + fprintf(stderr, " [-o otbdb_pathname] [-s status] [-S sc_flags] [ -t type]\n"); + fprintf(stderr, " [-u username] [-w window]\n"); fprintf(stderr, " -h : help\n"); fprintf(stderr, " -n : create database\n"); fprintf(stderr, " -v : enable verbose output\n\n"); - fprintf(stderr, " sc_flags : 0=CHALLENGE, 1=READERKEY\n"); + fprintf(stderr, " sc_flags : 0=CHALLENGE 1=READERKEY\n"); + + fprintf(stderr, " flags : "); + for (i = 0; i < OTP_FLAGS_BITS; ++i) + fprintf(stderr, "%s ", otp_flags_l[i]); + fprintf(stderr, "\n"); + + fprintf(stderr, " format list : "); + for (i = 1; i <= OTP_FORMAT_MAX; ++i) + fprintf(stderr, "%s ", otp_format_l[i]); + fprintf(stderr, "\n"); + + fprintf(stderr, " type list : "); + for (i = 1; i <= OTP_TYPE_MAX; ++i) + fprintf(stderr, "%s ", otp_type_l[i]); + fprintf(stderr, "\n"); + + fprintf(stderr, " status list : "); + for (i = 1; i <= OTP_STATUS_MAX; ++i) + fprintf(stderr, "%s ", otp_status_l[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "\n"); fprintf(stderr, " Mode Description\n"); fprintf(stderr, " -------------------------------------------------\n"); fprintf(stderr, " add - Add user\n"); - fprintf(stderr, " activate - Activate user\n"); fprintf(stderr, " create - Create database\n"); - fprintf(stderr, " deactivate - Deactivate user\n"); - fprintf(stderr, " disable - Disable user\n"); fprintf(stderr, " dump - ASCII dump user record(s)\n"); - fprintf(stderr, " flags-dspcnt - Set user display count flag.\n"); - fprintf(stderr, " flags-no-dspcnt - Clear user display count flag.\n"); fprintf(stderr, " generate - Generate HOTP for user\n"); fprintf(stderr, " list - List user record (printable)\n"); fprintf(stderr, " list-sc - List user record (SC friendly)\n"); fprintf(stderr, " load - ASCII load user record(s)\n"); fprintf(stderr, " remove - Remove user\n"); - fprintf(stderr, " set-count - Reset count for user\n"); - fprintf(stderr, " set-count-ceil - Reset count ceiling for user\n"); + fprintf(stderr, " set-count - Set user count\n"); + fprintf(stderr, " set-count-ceil - Set user count ceiling\n"); + fprintf(stderr, " set-flags - Set user flags\n"); + fprintf(stderr, " set-format - Set user format\n"); + fprintf(stderr, " set-status - Set user status\n"); + fprintf(stderr, " set-type - Set user OTP type\n"); fprintf(stderr, " test - Test user\n"); } diff --git a/otp-openvpn/otp-ov-plugin.c b/otp-openvpn/otp-ov-plugin.c index 5ece211..760aeff 100644 --- a/otp-openvpn/otp-ov-plugin.c +++ b/otp-openvpn/otp-ov-plugin.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otp-ov-plugin.c 13 2009-11-26 16:37:03Z maf $ + * $Id: otp-ov-plugin.c 50 2009-12-15 01:37:19Z maf $ */ #include @@ -41,17 +41,19 @@ void help(void); int main (int argc, char **argv) { struct otp_ctx *otpctx; - char *otpdb_fname, *username, *pass; - int db_flags, i, r, ret; + u_long tmpul; + char *otpdb_fname, *username, *pass, *endptr; + int db_flags, i, r, ret, otp_window; /* init xerr */ xerr_setid(argv[0]); otpdb_fname = OTP_DB_FNAME; db_flags = 0; + otp_window = OTP_WINDOW_DEFAULT; ret = -1; /* fail */ - while ((i = getopt(argc, argv, "h?o:v")) != -1) { + while ((i = getopt(argc, argv, "h?o:vw:")) != -1) { switch (i) { @@ -68,6 +70,15 @@ int main (int argc, char **argv) db_flags |= OTP_DB_VERBOSE; break; + case 'w': + tmpul = strtoul(optarg, &endptr, 0); + if (*endptr) + xerr_errx(1, "stroul(%s): failed at %c.", optarg, *endptr); + if (tmpul > OTP_WINDOW_MAX) + xerr_errx(1, "Challenge window %lu > %lu.", tmpul, OTP_WINDOW_MAX); + otp_window = tmpul; + break; + default: help(); exit(1); @@ -91,7 +102,7 @@ int main (int argc, char **argv) if (r != 0) xerr_errx(1, "User %s does not exist in otp database.", username); - if ((r = otp_user_auth(otpctx, username, pass, OTP_HOTP_WINDOW)) < 0) + if ((r = otp_user_auth(otpctx, username, pass, otp_window)) < 0) xerr_errx(1, "otp_user_auth(): failed."); if (otp_db_close(otpctx) < 0) @@ -114,7 +125,7 @@ int main (int argc, char **argv) void help() { - fprintf(stderr, "otp-ov-plugin [-?hv] [-o otpdb_pathname]\n"); + fprintf(stderr, "otp-ov-plugin [-?hv] [-o otpdb_pathname] [-w otp_window]\n"); fprintf(stderr, " -h : help\n"); fprintf(stderr, " -v : enable verbose output\n"); } /* help */ diff --git a/otp-pam/pam_otp.c b/otp-pam/pam_otp.c index f011074..1c6b8d8 100644 --- a/otp-pam/pam_otp.c +++ b/otp-pam/pam_otp.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: pam_otp.c 13 2009-11-26 16:37:03Z maf $ + * $Id: pam_otp.c 56 2009-12-17 02:08:05Z maf $ */ #include @@ -80,10 +80,11 @@ struct opts { int display_count; int allow_inactive; int require_db_entry; + int otp_window; char *otpdb_fname; }; -int load_opts(struct opts *opts, int argc, const char **argv); +void load_opts(struct opts *opts, int argc, const char **argv); PAM_EXTERN int pam_sm_authenticate(pam_handle_t *ph, int flags, int argc, @@ -212,7 +213,7 @@ int pam_sm_authenticate(pam_handle_t *ph, int flags, int argc, pam_msg.msg = (char *)&message; /* prompt for challenge with optional count */ - if (opts.display_count || (ou.flags & OTP_USER_FLAGS_DSPCNT)) + if (opts.display_count || (ou.flags & OTP_FLAGS_DSPCNT)) sprintf(message, "HOTP Challenge (%" PRIu64 "): ", ou.count); else sprintf(message, "HOTP Challenge: "); @@ -236,10 +237,11 @@ int pam_sm_authenticate(pam_handle_t *ph, int flags, int argc, } if (opts.expose_account) - xerr_info("OTP: user=%s response=%s", user, pam_resp->resp); + xerr_info("OTP: user=%s response=%s window=%d", user, + pam_resp->resp, opts.otp_window); if ((r = otp_user_auth(otpctx, (char*)user, pam_resp->resp, - OTP_HOTP_WINDOW)) < 0) { + opts.otp_window)) < 0) { xerr_warnx("otp_user_auth(): failed."); ret = PAM_SERVICE_ERR; goto cleanup; @@ -321,12 +323,14 @@ struct pam_module _pam_test_modstruct = { #endif -int load_opts(struct opts *opts, int argc, const char **argv) +void load_opts(struct opts *opts, int argc, const char **argv) { - int ret = 0; + u_long tmpul; + char *endptr; bzero(opts, sizeof *opts); opts->otpdb_fname = OTP_DB_FNAME; + opts->otp_window = OTP_WINDOW_DEFAULT; /* foreach argument */ while (argc--) { @@ -347,9 +351,15 @@ int load_opts(struct opts *opts, int argc, const char **argv) opts->require_db_entry = 1; } else if (!strncmp(*argv, "otpdb=", 6)) { opts->otpdb_fname=(char*)(*argv)+6; + } else if (!strncmp(*argv, "window=", 7)) { + tmpul = strtoul(optarg, &endptr, 0); + if (*endptr) + xerr_errx(1, "stroul(%s): failed at %c.", *argv, *endptr); + if (tmpul > OTP_WINDOW_MAX) + xerr_errx(1, "Challenge window %lu > %lu.", tmpul, OTP_WINDOW_MAX); + opts->otp_window = tmpul; } else { - xerr_warnx("Unrecognized argument - %s", argv); - ret = -1; + xerr_errx(1, "Unrecognized argument - %s", argv); } ++argv; @@ -362,6 +372,4 @@ int load_opts(struct opts *opts, int argc, const char **argv) opts->otpdb_fname); } - return ret; - } /* load_opts */ diff --git a/otp-sca/otp-sca.c b/otp-sca/otp-sca.c index 37eab62..9881bb9 100644 --- a/otp-sca/otp-sca.c +++ b/otp-sca/otp-sca.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otp-sca.c 13 2009-11-26 16:37:03Z maf $ + * $Id: otp-sca.c 88 2009-12-28 00:12:01Z maf $ */ #include @@ -118,7 +118,7 @@ int main(int argc, char **argv) struct scr_ctx *scrctx; int i, j, k, r, mode, sc_idx_set, j_start, j_end, done, sc_idx_tmp, opt_mod; int no_PIN, list_readers; - uint32_t tmp_count, tmp_cap; + uint32_t tmp_count, tmp_cap, tmp32u; uint64_t tmp64u; char sc_hostname[SC_HOSTNAME_LEN+1], sc_PIN[SC_PIN_LEN+1]; char sc_newPIN[SC_PIN_LEN+1], sc_newPIN2[SC_PIN_LEN+1]; @@ -149,9 +149,9 @@ int main(int argc, char **argv) sc_fv = 5; tmp_count = 0; username = "USER"; - reader = SCR_DEFAULT_READER; list_readers = 0; /* no */ scrctx = (struct scr_ctx*)0L; + reader = (char*)0L; BZS(sc_hotp); BZS(sc_idx); @@ -673,6 +673,19 @@ int main(int argc, char **argv) /* successful SC transaction? */ if (r == 0) { + if (sc_hostname[HOSTNAME_POS_FMT] & HOSTNAME_FLAG_MASK) { + + tmp32u = (sc_hotp[0] << 24) | (sc_hotp[1] << 16) | + (sc_hotp[2] << 8) | sc_hotp[3]; + + k = str_uint32toa(fmt_buf, tmp32u); + + } else { + + k = str_hex_dump(fmt_buf, sc_hotp, 5); + + } + for (i = 0, j = 0; i < SC_HOSTNAME_LEN; ++i) { /* high bit flag set? */ @@ -686,7 +699,12 @@ int main(int argc, char **argv) xerr_warnx("readerkey flag set and key not in SC transaction."); } else if ((i != HOSTNAME_POS_CHALLENGE) && - (i != HOSTNAME_POS_READERKEY)) { + (i != HOSTNAME_POS_READERKEY) && + (i != HOSTNAME_POS_FMT) && + (i != HOSTNAME_POS_FMT3) && + (i != HOSTNAME_POS_FMT2) && + (i != HOSTNAME_POS_FMT1) && + (i != HOSTNAME_POS_FMT0)) { xerr_warnx("sc_hostname high bit set on byte %d.", i); } } @@ -696,20 +714,22 @@ int main(int argc, char **argv) } - str_hex_dump(fmt_buf, sc_hotp, 5); - if (opt_mod & OPT_MOD_HOST) { - strcpy(fmt_buf+10, " -- "); - str_ftoc(fmt_buf+14, sc_hostname, SC_HOSTNAME_LEN); + strcpy(fmt_buf+k, " -- "); + str_ftoc(fmt_buf+k+4, sc_hostname, SC_HOSTNAME_LEN); } printf("HOTP: %s\n", fmt_buf); } else if (r == 1) { + printf("HOTP: rejected\n"); + } else { + xerr_errx(1, err_msg); - } + + } } /* MODE_HOTP_GEN */ @@ -820,9 +840,9 @@ int main(int argc, char **argv) xerr_errx(1, "sccmd_SetAdminKey(): failed."); if (r == 0) - printf("Set AdminKey: Done\n"); + printf("Set AdminKey: Done.\n"); else if (r == 1) - printf("Set AdminKey: Fail\n"); + printf("Set AdminKey: Fail.\n"); else xerr_errx(1, "sccmd_SetAdminKey(): fatal."); @@ -832,18 +852,29 @@ int main(int argc, char **argv) if (mode == MODE_BALANCECARD_SET) { - sc_idx[0] = SC_BALANCECARD_DISABLE; + if (!sc_idx_set) + sc_idx[0] = SC_BALANCECARD_DISABLE; if ((r = sccmd_SetBalanceCardIndex(scrctx, sc_fv, sc_idx)) < 0) xerr_errx(1, "sccmd_SetBalanceCardIndex(): failed."); - if (r == 0) - printf("Set BalanceCardIndex: Disabled\n"); - else if (r == 1) - printf("Set BalanceCardIndex: Fail\n"); - else + if (r == 0) { + + if (sc_idx[0] == SC_BALANCECARD_DISABLE) + printf("Disable BalanceCard: Done.\n"); + else + printf("Set BalanceCardIndex: Done.\n"); + + } else if (r == 1) { + + printf("Set BalanceCardIndex: Fail.\n"); + + } else { + xerr_errx(1, "sccmd_SetBalanceCardIndex(): fatal."); + } + } /* MODE_BALANCECARD_SET */ /****************/ @@ -1027,9 +1058,9 @@ int main(int argc, char **argv) } if (r == 0) - printf("SetHost (%d): Done\n", (int)sc_idx[0]); + printf("SetHost (%d): Done.\n", (int)sc_idx[0]); else if (r == 1) - printf("SetHost (%d): Fail\n", (int)sc_idx[0]); + printf("SetHost (%d): Fail.\n", (int)sc_idx[0]); else xerr_errx(1, err_msg); @@ -1060,10 +1091,10 @@ int main(int argc, char **argv) if (r == 0) - printf("SetSpyrusEEBlock (%d): Done\n", + printf("SetSpyrusEEBlock (%d): Done.\n", (int)sc_spyrusee_idx[0] & ~HOSTNAME_FLAG_MASK); else if (r == 1) - printf("SetSpyrusEEBlock (%d): Fail\n", + printf("SetSpyrusEEBlock (%d): Fail.\n", (int)sc_spyrusee_idx[0] & ~HOSTNAME_FLAG_MASK); else xerr_errx(1, err_msg); diff --git a/otp-sct/otp-sct.c b/otp-sct/otp-sct.c index 6d6ae29..ef2803c 100644 --- a/otp-sct/otp-sct.c +++ b/otp-sct/otp-sct.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: otp-sct.c 13 2009-11-26 16:37:03Z maf $ + * $Id: otp-sct.c 88 2009-12-28 00:12:01Z maf $ */ #include @@ -80,7 +80,7 @@ int main(int argc, char **argv) struct scr_ctx *scrctx; int i, j, k, r, sc_idx_set, sc_idx_tmp, j_start, j_end; int reset_pin, list_readers, list_version, get_hotp_version, list_hostnames; - uint32_t tmp_count; + uint32_t tmp_count, tmp32u; uint64_t tmp64u; char sc_hostname[SC_HOSTNAME_LEN+1], sc_pin[SC_PIN_LEN+1]; char sc_newpin[SC_PIN_LEN+1], sc_newpin2[SC_PIN_LEN+1]; @@ -98,7 +98,7 @@ int main(int argc, char **argv) sc_idx_set = 0; reset_pin = 0; /* no */ tmp_count = 0; - reader = SCR_DEFAULT_READER; + reader = (char*)0L; list_readers = 0; /* no */ list_version = 0; /* no */ list_hostnames = 0; /* no */ @@ -217,7 +217,8 @@ int main(int argc, char **argv) } /* need PIN */ - if (!(scrctx = scr_ctx_new(SCR_READER_EMBEDDED_ACR30S|SCR_READER_PCSC, debug))) { + if (!(scrctx = scr_ctx_new(SCR_READER_EMBEDDED_ACR30S|SCR_READER_PCSC, + debug))) { xerr_errx(1, "scr_ctx_new(): failed"); } @@ -389,6 +390,19 @@ int main(int argc, char **argv) /* successful SC transaction? */ if (r == 0) { + if (sc_hostname[HOSTNAME_POS_FMT] & HOSTNAME_FLAG_MASK) { + + tmp32u = (sc_hotp[0] << 24) | (sc_hotp[1] << 16) | + (sc_hotp[2] << 8) | sc_hotp[3]; + + str_uint32toa(fmt_buf, tmp32u); + + } else { + + str_hex_dump(fmt_buf, sc_hotp, 5); + + } + for (i = 0, j = 0; i < SC_HOSTNAME_LEN; ++i) { /* clear high bit for display */ @@ -396,7 +410,6 @@ int main(int argc, char **argv) } - str_hex_dump(fmt_buf, sc_hotp, 5); if (get_hotp_version == 3) { str_ftoc(fmt_buf2, sc_hostname, SC_HOSTNAME_LEN); diff --git a/spyrus-par2/main.c b/spyrus-par2/main.c index a8b819f..600b2ce 100644 --- a/spyrus-par2/main.c +++ b/spyrus-par2/main.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: main.c 13 2009-11-26 16:37:03Z maf $ + * $Id: main.c 89 2009-12-28 01:35:00Z maf $ */ #include @@ -65,7 +65,6 @@ GOTO 0x04; Jump to startup #define SC_GETHOTPHOSTCOUNT32_CLA 0x80 #define SC_GETSPYRUSEEBLOCK_CLA 0x80 - #define SC_GETHOSTNAME_INS 0x44 #define SC_GETHOTP_INS 0x46 #define SC_SETPIN_INS 0x4C @@ -75,12 +74,11 @@ GOTO 0x04; Jump to startup #define SC_GETHOTPHOSTCOUNT32_INS 0x5C #define SC_GETSPYRUSEEBLOCK_INS 0xA2 - U8 protocol = 0x03; RESP_INFO *Resp; bank1 U8 Buf[72]; /* Spyrus I/O buffer */ bank2 U8 dbuf[2][16]; /* two current hostnames for menu */ -bank2 U8 obuf[2][1]; /* option buffer for menu items */ +bank2 U8 obuf[2]; /* option buffer for menu items */ U8 myPIN[5]; /* PIN */ U8 newPIN[5]; /* newPIN if set */ @@ -216,12 +214,12 @@ const U8 VERSION[] = { /* Serial # */ 0x0A, 'm', 'a', 'f', ' ', 'H', 'O', 'T', 'P', ' ', ' ',\ /* AE kernel version / program access (unused) */ - 0x13, 0x22, 0x33 + 0x14, 0x22, 0x33 }; U8 getPIN(U8 *dest, U8 pos); void getCount(void); -void dispHOTP(void); +U8 dispHOTP(U8 fmt); U8 hexdigit(U8 d); @@ -236,6 +234,7 @@ void cmdSCGetSpyrusEEBlock(U8 i); U8 doSCGetHostname(U8 idx, U8 row); void powerdown(void); +void msg_powerdown(void); void menuUpdateCursor(void); void menuUpdate(void); @@ -254,13 +253,19 @@ U8 EELen(U8 addr, U8 len); #define HOSTNAME_FLAG_MASK 0x80 /* high bit set */ #define HOSTNAME_POS_CHALLENGE 0x00 /* require challenge input */ -#define HOSTNAME_POS_READERKEY 0x01 /* require reader key */ +#define HOSTNAME_POS_READERKEY 1 /* require reader key */ +#define HOSTNAME_POS_FMT 2 /* format, 0=hex, 1=decimal */ +#define HOSTNAME_POS_FMT3 8 /* 0000=HEX40, 0001=HEX40 */ +#define HOSTNAME_POS_FMT2 9 /* 0010=DEC31.6 0011=DEC31.7 */ +#define HOSTNAME_POS_FMT1 10 /* 0100=DEC31.8 0101=DEC31.9 */ +#define HOSTNAME_POS_FMT0 11 /* 0110=DEC31.10 0111=DHEX40 */ #define OPTION_FLAG_CHALLENGE 0x01 /* option set to request challenge */ +#define OPTION_FLAG_FMT 0x02 /* option to format HOTP */ int main(void) { - U8 i, c, j, addr; + U8 i, c, j, addr, fmt; /* init */ Resp = (RESP_INFO*)Buf; @@ -278,7 +283,7 @@ int main(void) Str2Lcd(0,0,&Resp->data[2]); #else EE2LCD(0, 0, EE_CALC_MSG_ADDR, EE_CALC_MSG_LEN); - powerdown(); + msg_powerdown(); #endif /* NO_CALC */ } /* SQ_CALC */ @@ -301,7 +306,7 @@ int main(void) /* initial greeting */ EE2LCD(0, 0, EE_L1GREET_ADDR, EE_L1GREET_LEN); EE2LCD(1, 0, EE_L2GREET_ADDR, EE_L2GREET_LEN); - + /* Get PIN */ i = getPIN(myPIN,4); @@ -405,7 +410,7 @@ int main(void) /* no hosts on card then nothing to do */ if (menu_active == 0) { EE2LCD(0, 0, EE_NOHOSTS_ADDR, EE_NOHOSTS_LEN); - powerdown(); + msg_powerdown(); } /* display menu */ @@ -479,7 +484,7 @@ int main(void) sc_idx = menu_idx - menu_active + menu_cursor; /* challenge input? */ - if ((obuf[menu_cursor][0] & OPTION_FLAG_CHALLENGE) || + if ((obuf[menu_cursor] & OPTION_FLAG_CHALLENGE) || (ml_flags & FLAGS_INPUT_COUNT)) getCount(); @@ -503,16 +508,23 @@ int main(void) dbuf[0][i] = dbuf[menu_cursor][i+3]; dbuf[0][12] = 0; - /* display HOTP screen */ - dispHOTP(); + /* Binary/Hex HOTP format */ + (obuf[menu_cursor] & OPTION_FLAG_FMT) ? fmt = 1 : fmt = 0; + + /* display HOTP and maybe cycle to next system */ + if (dispHOTP(fmt)) { + + ClearLcd(); + sc_idx ++; + goto enter_shortcut; + + } /* dispHOTP() */ } else { /* Failure */ - Str2Lcd(0,0,"GHPC32 Fail"); - - /* any key to continue */ - GetRawKey(Resp); + Str2Lcd(0,0,"GHPC32:fail"); + msg_powerdown(); } /* SC transaction */ @@ -521,7 +533,8 @@ int main(void) /* next input */ continue; - } + + } /* RAW_ENTER */ /****** CHANGE PIN ****/ if (key == RAW_STAR) { @@ -544,7 +557,7 @@ int main(void) ClearLcd(); EE2LCD(0, 0, EE_TRYHARDER_ADDR, EE_TRYHARDER_LEN); Beep(2); - GetRawKey(Resp); + keyGet(); continue; } @@ -579,14 +592,15 @@ int main(void) myPIN[4] = newPIN[4]; } else { /* Failure */ - Str2Lcd(0,0,"SetPIN Fail"); + Str2Lcd(0,0,"SetPIN:fail"); + msg_powerdown(); } /* go back to initial screen */ ml_flags |= FLAGS_SCREEN0_UPDATE; /* any key to continue */ - GetRawKey(Resp); + keyGet(); /* success / next input */ continue; @@ -596,10 +610,12 @@ int main(void) /***** CLEAN INPUT DIGITS */ if (key == RAW_CANCEL) { + short_d0 = 0; ml_flags &= ~FLAGS_MENU_SHORT_D0; continue; - } + + } /* RAW_CANCEL */ /****** MENU SHORTCUT WITH DIGIT ENTRY ***** */ @@ -637,48 +653,75 @@ int main(void) enter_shortcut: - /* input count first? */ - if (ml_flags & FLAGS_INPUT_COUNT) - getCount(); + /* the next sequential HOTP can be selected with the down arrow */ + while (1) { - /* GetHOTPHostCount32 command */ - cmdSCGetHOTPHostCount32(); + /* input count first? */ + if (ml_flags & FLAGS_INPUT_COUNT) + getCount(); - /* initiate SC transaction */ - if (SCTransact() == 0) { + /* GetHOTPHostCount32 command */ + cmdSCGetHOTPHostCount32(); - /* - * 2 byte resp (2) : 0,1 - * NAD,PCB,LEN (3) : 2,3,4 - * idx (1) : 5 - * PIN (5) : 6,7,8,9,10 - * count (4) : 11,12,13,14 - * HOTP (5) : 15,16,17,18,19 - * HostName(12) : 20..31 - */ + /* initiate SC transaction */ + if (SCTransact() == 0) { - /* skip display for empty hostname */ - if (Buf[20] != 0) { + /* + * 2 byte resp (2) : 0,1 + * NAD,PCB,LEN (3) : 2,3,4 + * idx (1) : 5 + * PIN (5) : 6,7,8,9,10 + * count (4) : 11,12,13,14 + * HOTP (5) : 15,16,17,18,19 + * HostName(12) : 20..31 + */ - /* display hostname on top */ - for (i = 0; i < 12; ++i) - dbuf[0][i] = (Buf[20+i]&0x7F); - dbuf[0][12] = 0; + /* skip display for empty hostname */ + if (Buf[20] != 0) { - /* display HOTP screen */ - dispHOTP(); + /* display hostname on top */ + for (i = 0; i < 12; ++i) + dbuf[0][i] = (Buf[20+i]&0x7F); + dbuf[0][12] = 0; - } + /* Binary/Hex HOTP format */ + (Buf[20+HOSTNAME_POS_FMT] & HOSTNAME_FLAG_MASK) ? fmt = 1 : fmt = 0; - } else { + /* display HOTP and maybe cycle to next system */ + if(dispHOTP(fmt)) { - /* Failure */ - Str2Lcd(0,0,"GHPHC32 Fail"); + sc_idx ++; + ClearLcd(); + continue; - /* any key to continue */ - GetRawKey(Resp); + } else { - } /* SC transaction */ + break; /* done */ + + } + + + } else { + + Str2Lcd(0,0,"GHPHC32:empt"); + + /* fatal */ + msg_powerdown(); + + } /* hostname not empty */ + + + } else { + + /* Failure */ + Str2Lcd(0,0,"GHPHC32:fail"); + + /* fatal */ + msg_powerdown(); + + } /* SC transaction */ + + } /* while 1 */ /* initialize for main screen input */ menuInit(); @@ -814,7 +857,8 @@ U8 getPIN(U8 *dest, U8 pos) void keyGet(void) { - GetRawKey(Resp); + if (GetRawKey(Resp)) + powerdown(); key = *Resp->data; } /* keyGet */ @@ -1017,6 +1061,7 @@ U8 SCTransact(void) if (CardPowerOn(Resp)) { ClearLcd(); EE2LCD(0, 0, EE_NOCARD_ADDR, EE_NOCARD_LEN); + CardPowerOff(); r = 1; /* no card */ goto SCTransact_err2; } @@ -1070,7 +1115,7 @@ SCTransact_err: /* get any key */ SCTransact_err2: - GetRawKey(Resp); + keyGet(); ClearLcd(); @@ -1128,9 +1173,12 @@ U8 doSCGetHostname(U8 idx, U8 row) /* high bit set on first character signals challenge required */ if (Buf[11+HOSTNAME_POS_CHALLENGE] & HOSTNAME_FLAG_MASK) - obuf[row][0] = OPTION_FLAG_CHALLENGE; + obuf[row] = OPTION_FLAG_CHALLENGE; else - obuf[row][0] = 0; + obuf[row] = 0; + + if (Buf[11+HOSTNAME_POS_FMT] & HOSTNAME_FLAG_MASK) + obuf[row] |= OPTION_FLAG_FMT; /* empty hostname is last */ if (Buf[11] == 0) @@ -1150,7 +1198,8 @@ U8 doSCGetHostname(U8 idx, U8 row) } else { - powerdown(); + Str2Lcd(0,0,"GHN:fail"); + msg_powerdown(); } @@ -1158,13 +1207,17 @@ U8 doSCGetHostname(U8 idx, U8 row) } /* doSCGetHostname */ -void powerdown(void) +void msg_powerdown(void) { - CardPowerOff(); GetRawKey(Resp); DeactivateRdr(); } /* off */ +void powerdown(void) +{ + DeactivateRdr(); +} + void menuUpdate(void) { ClearLcd(); @@ -1197,17 +1250,40 @@ void menuUpdateCursor(void) } /* menuUpdateCursor() */ -void dispHOTP(void) +U8 dispHOTP(U8 fmt) { U8 i, j, c; + U32 u32; + char *s; + + + if (fmt == 0) { /* HEX */ + for (i = 0, j = 0; i < 5; ++i) { + c = Buf[15+i]; + dbuf[1][j++] = hexdigit(c>>4); + dbuf[1][j++] = hexdigit(c&0x0F); + } + dbuf[1][j] = 0; + } else { /* decimal */ + + s = (char*)&u32; + + s[3] = Buf[15]; + s[2] = Buf[16]; + s[1] = Buf[17]; + s[0] = Buf[18]; + + s = Buf; /* starts at Buf+1 */ + + do { + *++s = u32 % 10 + '0'; + } while ((u32 /= 10) > 0); + + for (i = 0; s != Buf; --s, ++i) + dbuf[1][i] = *s; + dbuf[1][i] = 0; - /* HOTP to hex */ - for (i = 0, j = 0; i < 5; ++i) { - c = Buf[15+i]; - dbuf[1][j++] = hexdigit(c>>4); - dbuf[1][j++] = hexdigit(c&0x0F); } - dbuf[1][j] = 0; /* * note the following code will not compile properly. certain @@ -1237,9 +1313,18 @@ void dispHOTP(void) } } - /* any key will return, timeout to powerdown */ - if (j == 0) - powerdown(); + if (j == 1) { + key = *Resp->data; + if (key == RAW_DOWN) + return 1; /* again */ + else + return 0; + } + + /* timeout */ + powerdown(); + + return 0; /* unreached */ } /* dispHOTP */ @@ -1315,3 +1400,4 @@ U8 EELen(U8 addr, U8 len) return i; } /* EELen */ + diff --git a/urd/urd.c b/urd/urd.c index dbb3f59..3e8743c 100644 --- a/urd/urd.c +++ b/urd/urd.c @@ -24,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: urd.c 13 2009-11-26 16:37:03Z maf $ + * $Id: urd.c 50 2009-12-15 01:37:19Z maf $ */ #include @@ -59,7 +59,6 @@ * urd_rep_msg in access-challenge hard coded to ABC.. * copy proxy variables into reply packet per RFC? * packet stress testing - * rc.d script */ static void usage(void); @@ -77,18 +76,19 @@ int main(int argc, char **argv) struct otp_ctx *otpctx; struct otp_user ou; char *otpdb_fname; - int otp_skip_unknown, otpdb_flags; + int otp_skip_unknown, otpdb_flags, otp_enable; #endif /* OOTP_ENABLE */ fd_set rfd; + u_long tmpul; uint64_t rep_state; - uint32_t local_ip, tmp32u; + uint32_t local_ip; uint16_t local_port; uint8_t rep_code; uint rem_addr_len; char *authorized_users_fname, *pwfile_fname, *server_secret_fname, *endptr; char server_secret[URD_SECRET_LEN+1], buf[1024], *pid_fname; int rep_enc_flags, rep_cache_flags, debug, daemon_mode; - int drop, drop_mode, req_cache_hit, buf_l, pkt_fd, r, i; + int drop, drop_mode, req_cache_hit, buf_l, pkt_fd, r, i, otp_window; bzero(&loc_addr, sizeof loc_addr); bzero(&pkt_fd, sizeof pkt_fd); @@ -103,19 +103,21 @@ int main(int argc, char **argv) local_port = URD_PORT; drop = 1; drop_mode = 0; + otp_window = OTP_WINDOW_DEFAULT; #ifdef OOTP_ENABLE otpctx = (struct otp_ctx*)0L; otpdb_fname = OTP_DB_FNAME; otp_skip_unknown = 0; otpdb_flags = 0; + otp_enable = 1; #endif /* OOTP_ENABLE */ xerr_setid(argv[0]); #ifdef OOTP_ENABLE - while ((i = getopt(argc, argv, "AhduDOx?a:b:B:o:p:s:P:")) != -1) { + while ((i = getopt(argc, argv, "AhduDOx?a:b:B:o:p:s:P:w:")) != -1) { #else - while ((i = getopt(argc, argv, "AhdDx?a:b:B:p:s:P:")) != -1) { + while ((i = getopt(argc, argv, "AhdDx?a:b:B:p:s:P:w:")) != -1) { #endif /* OOTP_ENABLE */ switch (i) { @@ -134,12 +136,12 @@ int main(int argc, char **argv) break; case 'B': - tmp32u = strtoul(optarg, &endptr, 0); + tmpul = strtoul(optarg, &endptr, 0); if (*endptr) xerr_errx(1, "stroul(%s): failed at %c.", optarg, *endptr); - if (tmp32u > 0xFFFF) + if (tmpul > 0xFFFF) xerr_errx(1, "UDP port out of range 0..65535."); - local_port = tmp32u; + local_port = tmpul; break; case 'd': @@ -165,7 +167,7 @@ int main(int argc, char **argv) break; case 'O': - otpdb_fname = (char*)0L; + otp_enable = 0; break; #endif /* OOTP_ENABLE */ @@ -187,6 +189,15 @@ int main(int argc, char **argv) break; #endif /* OOTP_ENABLE */ + case 'w': + tmpul = strtoul(optarg, &endptr, 0); + if (*endptr) + xerr_errx(1, "stroul(%s): failed at %c.", optarg, *endptr); + if (tmpul > OTP_WINDOW_MAX) + xerr_errx(1, "Challenge window %lu > %lu.", tmpul, OTP_WINDOW_MAX); + otp_window = tmpul; + break; + case 'x': drop_mode = 1; break; @@ -264,7 +275,7 @@ int main(int argc, char **argv) #ifdef OOTP_ENABLE /* creat OTP context */ - if (otpdb_fname) + if (otp_enable) if (!(otpctx = otp_db_open(otpdb_fname, otpdb_flags))) xerr_errx(1, "otp_db_open(%s): failed", otpdb_fname); #endif /* OOTP_ENABLE */ @@ -487,7 +498,7 @@ int main(int argc, char **argv) * */ - if (!otpdb_fname) { + if (!otp_enable) { rep_code = RADIUS_CODE_ACCESS_ACCEPT; rep_enc_flags = 0x0; @@ -720,7 +731,7 @@ int main(int argc, char **argv) } if ((r = otp_user_auth(otpctx, urdctx->req.user_name, - urdctx->req.user_pass, OTP_HOTP_WINDOW)) < 0) + urdctx->req.user_pass, otp_window)) < 0) xerr_errx(1, "otp_user_auth(): failed."); if (r == OTP_AUTH_PASS) { @@ -989,14 +1000,15 @@ void usage(void) fprintf(stderr, "urd [-AhdDOux?] [-a allowed_users_file] [-b local_ip] [-B local_port ]\n"); fprintf(stderr, - " [-o otp_db] [-p passwd_file] [-P pid_file] [-s secret_file]\n\n"); + " [-o otp_db] [-p passwd_file] [-P pid_file] [-s secret_file]\n"); #else fprintf(stderr, "urd [-AhdDx?] [-a allowed_users_file] [-b local_ip] [-B local_port ]\n"); fprintf(stderr, - " [-p passwd_file] [-P pid_file] [-s secret_file]\n\n"); + " [-p passwd_file] [-P pid_file] [-s secret_file]\n"); #endif /* OOTP_ENABLE */ + fprintf(stderr, " [-w otp_window]\n\n"); fprintf(stderr, " -A disable authorized_users file (all users in passwd_file valid)\n"); fprintf(stderr, " -h help\n"); fprintf(stderr, " -d enable debugging\n");