#
# SunRay Smart Card Config File for a Java Card loaded with the
# ActivCard Gold applet set.
# Based on Java Card 2.1 Open Platform 2.0.1
#
# ident "@(#)ActivCardGoldJavaCard.cfg	1.5 04/02/24 SMI"
#
# Copyright 2003-2004 Sun Microsystems, Inc.  All rights reserved.
#

########################################################################
#
# Administrative information - these properties are used by the
# SunRay smart card administration tools. All of the admin.*
# properties must be present in order for this file to be loaded
# into a SunRay system.
#
########################################################################

# admin.name - the name of this card
admin.name = ActivCardGoldJavaCard

# admin.model - the model name of the card supported by this config file
admin.model = Java Card 2.1

# admin.description - a short description of this card
admin.description = Java Card ActivCard Gold Smart Card

# admin.supplier - the name of the supplier of this config file
admin.supplier = Sun Microsystems, Inc.

# admin.version - the version of this config file
admin.version = 1.0

# admin.type - the type of device (smartcard, iButton, pseudo, etc...)
admin.type = smartcard

########################################################################
#
# The config file words start here. Tokens following the special
# token "--StartWords--" will be processed by the SunRay software.
# Anything following the special token "--EndWords--" will not be
# processed. Any number of "--StartWords--" and "--EndWords--"
# pairs can be present in a config file. An implicit "--EndWords--"
# is at the end of the file.
#
########################################################################

--StartWords--

#
# The ActivCard Gold cards are based on a JavaCard 2.1
# card running the OpenPlatform (OP) 2.0.1 release. SunRay
# uses the Card Manager applet to provide a unique ID for
# hot desking. This unique ID is guaranteed to be unique
# among all OpenPlatform cards issued in the world.
#
# The card can be identified by the presence of specific
# applets on the card called Generic Container applets.
# In order to properly identify an ActivCard Gold card,
# we try to select the ID applet and two GC applets; the
# result of the selection APDUs determine whether or not
# we can identify this card.
#
# The ID applet AID is as follows:
#    ActivCard Gold ID applet AID:
#	   AID = A0 00 00 00 79 03 00
#	length = 0x7 bytes
#
# The GC applet AIDs are as follows:
#
#    ActivCard Gold GC1 applet AID:
#	   AID = A0 00 00 00 79 02 FD
#	length = 0x7 bytes
#
#    ActivCard Gold Public GC applet:
#	   AID = A0 00 00 00 79 02 FE
#	length = 0x7 bytes
#
# In order to extract the username of the cardholder, we
# need to get two data blocks from the public GC applet.
# One data block is called the T-buffer and it contains
# tags that represent property keys for various properties
# on the card. The other data block is called the V-buffer
# and it contains the actual property values associated with
# each kay in the T-buffer. We get the T-buffer and parse it
# looking for a specific tag that represents the username
# offset in the V-buffer, then we get the V-buffer and extract
# the username from that buffer.
#
# The card provides two possible IDs that are derived
# from the OpenPlatform Card Manager (OP CM) data area:
#
#    CUID - Card Unique Identification Number
#    CUDD - Card Unique Diversified Data
#
# The CUID is guaranteed to be unique across all OpenPlatform
# cards in the world.
# The CUDD is a 128-bit random number generated by a service
# bureau using a FIPS certified hardware device.
#
# This config file extracts both the CUID and CUDD data from
# the card. By default, the CUID data is used as the Token ID,
# and the CUDD data is discarded.
#
# To retrieve the CUID and CUDD data from the card, two
# operations must be performed:
#
#    1. Select the Card Manager by AID
#    2. Issue a GET DATA command
#
# The results of the GET DATA command will be a block of
# data that contains the CUID components and the CUDD.
#
# The CUID is made up of four components:
#
#    IC Fabricator Field
#	offset = 0x03
#	length = 0x02
#
#    IC Type Field
#	offset = 0x05
#	length = 0x02
#
#    IC Batch Field
#	offset = 0x13
#	length = 0x02
#
#    IC Serial Number Field
#	offset = 0x0f
#	length = 0x04
#
# These four fields are concatenated in the following order:
#
#	Fabricator + Type + Batch + Serial
#
# to produce the CUID. The derived CUID is stored in the
# property "id.CUDD".
#
# The CUDD is a single block of data:
#
#    CUDD Data
#	offset = 0x1d
#	length = 0x10
#
# The extracted CUDD is stored in the property "id.CUDD".
#
# There are two CM AIDs of interest to be used with this card:
#
#    Default OpenPlatform Card Manager AID:
#	   AID = a0 00 00 00 03 00 00
#	length = 0x7 bytes
#
#    SLB 32K Developer Card Manager AID:
#	   AID = a0 00 00 00 03 00 01
#	length = 0x7 bytes
#
# Only one of these AIDs is available on the card. This
# config file will try both of the CM AIDs and use the
# CM AID that is available on the card in order to get
# the CUID and CUDD data.
#

    # ==== user configuration section ================================
    #
    # This section contains user configurable parameters that affect
    # how the token type and token ID are constructed.
    #

    #
    # To return the card's type-specific name rather than the
    # generic name, set the useGenericNames property
    # to the value "false".
    #
    # To return the card's generic name rather than the
    # type-specific name, set the useGenericNames property
    # to the value "true". Doing this will cause this
    # config file to return the token types without appending
    # the underlying card platform to the name.
    #
    true useGenericNames setprop

    #
    # To try to determine if the card is personalized so that
    # the token ID returned will contain the cardhole's username
    # set the tryPersonalizedCards property to the value "true".
    # To always return a token ID that is derived from the card's
    # CUID value, set this property to "false".
    #
    true tryPersonalizedCards setprop

    #
    # To return the domain name appended to the token ID for
    # a personalized card, set the appendDomainName property
    # to the value "true". The domain name (if it exists on
    # the card) will be appended to the username thus:
    #
    #		<card_type>.<username>@<domainname>
    #
    false appendDomainName setprop

    #
    # To force user names or domain names to lower case, set the
    # appropriate property below to the value "true". To return
    # data as it is read from the card, set to "false".
    #
    # In general, usernames should be returned in the case in which
    # they are read from the card, and domainnames should be
    # returned in lowercase (by convention only, since domainnames
    # are case-insensitive).
    #
    false useLowercaseUsernames setprop
    true useLowercaseDomainnames setprop

    # ==== end of user configuration section =========================

    #
    # Setup the token type name and suffix that each card state
    # will use.
    # dup the token type so that it can be used in the message
    # farther down.
    #
    "ActivCardGoldJavaCard" dup tokenType setprop
    "-nonPers" tokenTypeNonPers setprop

    # username Tag value in the T-buffer
    00ff0d02c9 usernameTag setprop

    #
    # set the token type we are processing and display it
    # the card name will be set as each card in the family
    # is processed
    #
    useGenericNames getprop
    genNames jmpIfTrue
    " (Card Model Specific Names)" concat
genNames::
    "Trying " swap concat msg

    # ================================================================

    #
    # We need certain SwapDrop words in order to determine if the
    # card is personalized and to extract the personalization data
    # from the card. If this version of SwapDrop does not support
    # the required words, then fall back to only identifying this
    # card by it's CUID data. This allows this file to be used on
    # older versions of SwapDrop.
    #

    # test for "isWord" word - if not supported, then assume none
    # of the other required words are supported either
    "notAword" isWord
    "isWord" =
    isWordNotSupported jmpIfTrue
    clearstack

    # "isWord" is supported, now check for the other required words
    "isWord hasSession padLeft hexpadLeft toLower toUpper toASCII "
	"setupTbufferParser parseTbuffer findString" concat isWord
    unsupportedWords jmpIfFalse
	setupCardInfo jmp

    # required words not supported, don't look for personalization
    # information on card
isWordNotSupported::
    "isWord"
unsupportedWords::
    "    WARNING: required word: [" swap concat "] not supported" concat msg
    "    WARNING: will not try to determine if card is personalized" msg
    false tryPersonalizedCards setprop

    # ================================================================

setupCardInfo::
    #
    # SELECT ID Applet
    #
    00a4040007a0000000790300 00 exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check if ID applet exists
    # if not, this isn't an ActivCardGoldJavaCard
    9000 hexequals
    noID jmpIfFalse

    #
    # SELECT GC1 Applet
    #
    00a4040007a00000007902fd 00 exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check if GC1 applet exists
    # if not, this isn't an ActivCardGoldJavaCard
    9000 hexequals
    noID jmpIfFalse

    #
    # Select GC public container Applet
    #
    00a4040007a00000007902fe 00 exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check if applet exists
    # if not, this isn't an ActivCardGoldJavaCard
    9000 hexequals
    noID jmpIfFalse

    #
    # Identified the card type, now try to select the
    # Open Platform Card Manager applet.
    #

    #
    # SELECT Card Manager (default OP CM AID)
    #
    00a4040007a0000000030000 00 exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check if the CM responds to the default OP CM AID
    9000 hexequals
    noOPCMAID jmpIfFalse

    # modify the token type if we're not using generic names
    useGenericNames getprop
    getCUID jmpIfTrue
    tokenType getprop "-OP" concat tokenType setprop
    getCUID jmp

    #
    # Card has the ActivCardGold applets, but didn't respond
    # to the default OP CM AID, so try the SLB CM AID.
    #
noOPCMAID::

    #
    # SELECT Card Manager (SLB CM AID)
    #
    00a4040007a0000000030001 00 exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    #
    # Card didn't respond to the SLB CM AID, so this isn't a
    # card that we can identify properly.
    #
    9000 hexequals
    noID jmpIfFalse

    # modify the token type if we're not using generic names
    useGenericNames getprop
    getCUID jmpIfTrue
    tokenType getprop "-SLB" concat tokenType setprop

    #
    # Found and selected a CM applet, now setup the non-personalized
    # tokenType and get the CUID and CUDD data.
    #
getCUID::
    tokenType getprop tokenTypeNonPers getprop concat tokenTypeNP setprop

    #
    # GET DATA
    #
    80ca9f7f 2d exchangeAPDU
    badCard jmpIfFalse	# error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check for 9000 status - if not, card didn't understand this
    9000 hexequals
    noID jmpIfFalse

    # check for returned data
    noID jmpIfFalse

    # check for at least 0x2d (45 decimal) bytes returned
    dup
    hexlength 2d >=

    # if we didn't get at least 0x2d bytes, this isn't our card
    noID jmpIfFalse

    # dup GET DATA response so that we can operate on it
    dup dup dup dup

    # extract CUID fields
    03 02 hexchop id.fabricator setprop	# IC fabricator
    05 02 hexchop id.type setprop	# IC type
    13 02 hexchop id.batch setprop	# IC batch number
    0f 04 hexchop id.serial setprop	# IC serial number

    # create complete CUID from CUID fields
	id.fabricator getprop
	id.type getprop
	concat
	id.batch getprop
	concat
	id.serial getprop
	concat
    id.CUID setprop

    # extract CUDD field
    1d 10 hexchop id.CUDD setprop	# CUDD

    # use the CUID as the Token ID
    id.CUID getprop tokenID setprop

    # clear out all the cruft on the stack from the AID selections
    clearstack

    # ==== card personalization handling section =====================

    # if we get any type of exception while trying to determine if
    # the card is personalized or while trying to extract personalization
    # data, then just return the non-personalized token ID
    noUID onException

    # check to see if we should try to determine if the card is
    # personalzied or not
    tryPersonalizedCards getprop
    noUID jmpIfFalse

    #
    # Select GC public container to extract username TLV
    #
    00a4040007a00000007902fe 00 exchangeAPDU
    badCard jmpIfFalse  # error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check for 9000 status - if not, card didn't understand this
    9000 hexequals
    noUID jmpIfFalse

    # check for returned data
    noUID jmpIfFalse

    # drop the Select ID applet response data since we don't need it
    clearstack

    # get length of T-buffer
    #	two byte value in little endian format
    80520000020102 00 exchangeAPDU
    badCard jmpIfFalse  # error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check for 9000 status - if not, card didn't understand this
    9000 hexequals
    noUID jmpIfFalse

    # check for returned data
    noUID jmpIfFalse

    # check for at least one byte returned
    # if we didn't get at least 1 byte, this isn't our card or the
    # applet is broken
    dup
    hexlength 2 >=
    noUID jmpIfFalse

    # check for zero-length T-buffer values
    dup
    00 hexequals
    nextUID jmpIfFalse
    noUID jmp

nextUID::
    # pad the T-buffer to a two-byte value
    00 2 hexpadLeft

    # decompose the T-buffer length value into MSB and LSB
    # the T-buffer length is in little endian format
    dup
    00 01 hexchop 00 1 hexpadLeft tbLSB setprop
    01 01 hexchop 00 1 hexpadLeft dup tbMSB setprop

    # the MSB must be 0x00 - we don't handle T-buffers that
    # are longer than 255 bytes at present
    00 hexequals
    readTbuffer jmpIfTrue
    "T-buffer is too long: "
	tbMSB getprop tbLSB getprop concat concat
	" bytes" concat msg
    noUID jmp

    #
    # Read the T-buffer
    #	The length is already on the stack.
    #
readTbuffer::
    tbLSB getprop 805200020201 swap concat 00 exchangeAPDU
    badCard jmpIfFalse  # error communicating with card

    # remove the procedure byte since we don't look at it
    swap drop

    # check for 9000 status - if not, card didn't understand this
    9000 hexequals
    noUID jmpIfFalse

    # check for returned data
    noUID jmpIfFalse

    # save the Tbuffer
    Tbuffer setprop

    # setupTbufferParser
    #	{tBuffer} {lengthEndian} {bigLengthFlag} \
    #		{lengthSize} {tagLength} setupTbufferParser --
    Tbuffer getprop littleEndian ff 2 useTag setupTbufferParser

    # parseTbuffer
    #	{tag} parseTbuffer -- {boolean} [{length} {vBufferOffset}]
    usernameTag getprop parseTbuffer
    noUID jmpIfFalse # no username found on card

    # save V-buffer values
    #	length is one byte
    #	offset is two bytes (T-buffer starts at +2 so add in offset)
    00 1 hexpadLeft usernameLength setprop
    2 + 00 2 hexpadLeft usernameOffset setprop

    #
    # Read the V-buffer
    #cmd offset      P3 (len)  type      length of username
    8052 # CMD INS
	usernameOffset getprop concat # P1 P2
	02 concat # P3 (length of following data)
	02 concat # type
	usernameLength getprop concat # username length
	00 exchangeAPDU
    badCard jmpIfFalse  # error communicating with card
 
    # remove the procedure byte since we don't look at it
    swap drop

    # check for 9000 status - if not, card didn't understand this
    9000 hexequals
    noUID jmpIfFalse

    # check for returned data
    noUID jmpIfFalse

    # got the username data, convert to ASCII and search for
    # the username/domain seperator
    # chop the first byte in the V-buffer since it's not part
    # of the user information
    dup
    hexlength 1 - 1 swap hexchop

    dup dup
    Vbuffer setprop
    length VbufferLength setprop
    5c findString
    noSeperator jmpIfFalse
    dup # offset of seperator
    sepOffset setprop
    Vbuffer getprop swap 0 swap chop toASCII username setprop

    # convert the username to lowercase if necessary
    useLowercaseUsernames getprop
    userUsernameAsIs jmpIfFalse
    username getprop toLower username setprop

userUsernameAsIs::
    # extract the domain name
    sepOffset getprop 2 + domainStart setprop
    VbufferLength getprop sepOffset getprop - 2 - domainLen setprop
    Vbuffer getprop domainStart getprop domainLen getprop chop
	toASCII domainname setprop

    # convert the domainname to lowercase if necessary
    useLowercaseDomainnames getprop
    useDomainnameAsIs jmpIfFalse
    domainname getprop toLower domainname setprop

useDomainnameAsIs::
    true hasDomainName setprop

    trySession jmp

    # no seperator between username and domainname, so assume that
    # the complete V-buffer is the username
noSeperator::
    Vbuffer getprop toASCII username setprop
    "(none)" domainname setprop
    false hasDomainName setprop

    # convert the username to lowercase if necessary
    useLowercaseUsernames getprop
    trySession jmpIfFalse
    username getprop toLower username setprop

    # got the username from the card, now see if the non-personalized
    # version of the card has an existing session
trySession::
    tokenTypeNP getprop "." concat tokenID getprop concat
	dup
	tokenTypeNP.full setprop
	hasSession
    yesGotIt jmpIfTrue
    false cardHasSession setprop
    displayCardInfo jmp

yesGotIt::
    true cardHasSession setprop

displayCardInfo::

    "Personalized Card Information:" msg
    "     tokenType: [" tokenType getprop concat "]" concat msg
    "       tokenID: [" tokenID getprop concat "]" concat msg
    "      username: [" username getprop concat "]" concat msg
    "    domainname: [" domainname getprop concat "]" concat msg
    "    hasSession: [" cardHasSession getprop concat "] (" concat
	tokenTypeNP.full getprop concat ")" concat msg

    # set the DTU property "username" to the extracted username
    username getprop "dtu.username" setprop

    # if the non-personalized version of the card has an existing
    # session, then return that token type rather than the token
    # type that contains the user name. this is to handle the case
    # where the user has started with an unpersonalized card and
    # then personalized it. we don't want to orphan the session
    # that is based on the non-personalized token, so ignore
    # personalization until the card has no session.
    cardHasSession getprop
    noUID jmpIfTrue

    # no existing session, so return the personalized token
    username getprop tokenID setprop

    appendDomainName getprop
    noDomainAppend jmpIfFalse

    hasDomainName getprop
    noDomainAppend jmpIfFalse

    tokenID getprop "@" concat domainname getprop concat
	tokenID setprop

noDomainAppend::
    # string for returnTokenInfo
    "personalized"
    returnTokenInfo jmp

#
# Couldn't find a UID on the card or we don't need to look
# for personalization info, so just return the non-personalized
# token ID.
#
noUID::

    tryPersonalizedCards getprop
    noUIDnoPers jmpIfFalse
	# string for returnTokenInfo
	"not personalized"
	consUpnoUIDinfo jmp

noUIDnoPers::
	# string for returnTokenInfo
	"not checking personalization info"

consUpnoUIDinfo::
    tokenTypeNP getprop tokenType setprop

#
# Display token identification and return token info.
# String at TOS will be appended to ID message.
#
returnTokenInfo::

    # if we get any errors trying to display or return the
    # token info then error out of this
    noID onException

    # display token info
    "    Identified: ["
	tokenType getprop concat
	"." concat
	tokenID getprop concat
	"]" concat
	# string at TOS
	" (" concat swap concat ")" concat
	msg

    # return the Token ID and Token Type
    tokenID getprop tokenType getprop returnID

#
# This card isn't an ActivCardGoldJavaCard card that we
# could identify.
#
noID::
    noIDreturn onException
    "Unable to determine ID for " tokenType getprop concat msg
noIDreturn::
    return

#
# An error occurred while accessing the card.
#
badCard::
    "Error accessing " tokenType getprop concat
    msg
    return

#
# output debug information
# must have return label on the stack
#
displayInfo::

    # display extracted information
    "CUID: " id.CUID getprop concat msg
	"  IC fabricator: " id.fabricator getprop concat msg
	"  IC type:       " id.type getprop concat msg
	"  IC batch:      " id.batch getprop concat msg
	"  IC serial:     " id.serial getprop concat msg

    "CUDD: " id.CUDD getprop concat msg
    jmp

########################################################################
#
# End of the config file. The special token "--EndWords--" is not
# required but is included here for completeness.
#
########################################################################

--EndWords--
