Android Question Smart card Public and Private key

Culjko

Member
Hi

Has anyone here tried to read public and private keys from a smart card reader. i write code to open and transmit APDU commands to smart card, but I also need to read public and private key.
With this code I read and send APDU commands to the card. Is there a way to read the certificate from the smart card?
Card Reader:
Sub Class_Globals
    ' ************
    ' JAVA VARS
    '*************
    Dim uManager As UsbManager
    Dim uDevice As UsbDevice

    Dim mReader As JavaObject
    Dim device As JavaObject
    Dim Manager As JavaObject
    Dim Reader As JavaObject
    Private EventName As String 'ignore
    Private CallBack As Object 'ignore
    Dim openState As Boolean
    Dim readerState As Boolean = False
    Dim slotNum As Int
    Dim prevState As Int
    Dim currState As Int
    Dim getState As Int
    Dim Unknown As Int
    Dim Absent As Int
    Dim Present As Int
    Dim Undefined As Int
    Dim SWA As String = ""
    Dim SWB As String = ""
    Dim numberOfUsb As Int = 0
    
    Dim error As Boolean = False
    Dim init As Boolean = False
    Dim usbdevices() As UsbDevice
    
    Dim CARD_POWER_DOWN As Int = 0
    Dim CARD_COLD_RESET As Int = 1
    Dim CARD_WARM_RESET As Int = 2
    Dim PROTOCOL_UNDEFINED As Int = 0
    Dim PROTOCOL_T0 As Int = 1
    Dim PROTOCOL_T1 As Int = 2
    Dim PROTOCOL_RAW  As Int = 65536
    Dim PROTOCOL_TX As Int = 3
    Dim PROTOCOL_DEFAULT As Int = -2147483648
    Dim PROTOCOL_OPTIMAL As Int = 0
    Dim CARD_UNKNOWN As Int = 0
    Dim CARD_ABSENT As Int = 1
    Dim CARD_PRESENT As Int = 2
    Dim CARD_SWALLOWED As Int = 3
    Dim CARD_POWERED As Int = 4
    Dim CARD_NEGOTIABLE As Int = 5
    Dim CARD_SPECIFIC As Int = 6
    Dim IOCTL_CCID_ESCAPE As Int = 3500
    Dim IOCTL_ACR128_READER_COMMAND As Int = 2079
    Dim IOCTL_ACR83_GET_FIRMWARE_VERSION As Int = 2078
    Dim IOCTL_ACR83_DISPLAY_LCD_MESSAGE As Int = 2079
    Dim IOCTL_ACR83_READ_KEY As Int = 2080
    Dim IOCTL_GET_FEATURE_REQUEST As Int = 3400
    Dim receiveLenght As Int = 0
    Private CallBackObj As Object
    Dim VUD As Boolean = False
    Dim cEvent As Boolean = False
    Dim usbDeviceName As String = ""

    Dim errorMessage As String = ""
    Dim errorCode As String = ""
    Dim card As JavaObject
    
    Dim SCard As CkCert
    
    
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(vCallback As Object, vEventName As String) As Boolean
    Log(init)
    If init Then Return True
    

    mReader.InitializeContext
    Reader.InitializeContext
    device.InitializeContext
    uManager.Initialize
    
    usbdevices = uManager.GetDevices
    VUD = verificaUsbDevice
    
    EventName = vEventName
    CallBack = vCallback
    GetBA
    
    If SetUpReader Then
        init = True
        Return True
    End If
    init = False
    Return False
End Sub


Sub SetUpReader As Boolean
    Try
        If Not(VUD) Then verificaUsbDevice
        Dim NR As Boolean = NewReader

        If VUD And NR Then
            init = True
            readerState = True
            Starter.errorStatus("0000","")
            Return True
        Else
            Starter.errorStatus("1300","")
            init = False
            readerState = False
            Return False
        End If
        
    Catch
        Log(LastException)
        init = False
        readerState = False
        Starter.errorStatus("1300","")
        Return False
    End Try
    init = False
    readerState = False
    Return False
End Sub

Sub initialized As Boolean
    Return init
End Sub

Sub NewReader As Boolean
    
    'If Not (readerState) Then Return False
    Private jo As JavaObject
    jo.InitializeContext
    Manager= GetContext.RunMethod("getSystemService", Array("usb"))
    mReader = jo.InitializeNewInstance ("com.acs.smartcard.Reader",Array As Object (Manager))
    CreateEvent
    Return True

End Sub

Sub CreateEvent As JavaObject
    Log("create event")
    'Private CallBackObj As Object
    'If Not (cEvent) Then Return
    CallBackObj=mReader.CreateEvent  ("com.acs.smartcard.Reader.OnStateChangeListener", "status", Null)
    Private cObject As Object = mReader.RunMethod("setOnStateChangeListener",Array As Object  (CallBackObj))
    cEvent = True
    Return True
End Sub

Sub OpenReader As Boolean
    errorMessage = ""
    errorCode = ""
    If Not(init) Then Return False
    Private jo As JavaObject
    jo.InitializeContext
    
    Log(mReader.RunMethod ("isSupported",Array As Object(uDevice)))
    Manager= GetContext.RunMethod("getSystemService", Array("usb"))
    
    Try
        device = jo.InitializeNewInstance ("com.acs.smartcard.Reader",Array As Object (Manager))
        card = mReader.RunMethod ("open",Array As Object(uDevice))
        Dim isOpen As Boolean = mReader.RunMethod ("isOpened",Null)
        Starter.errorStatus("0000","")
    Catch
        Log("greska not open")
        Starter.errorStatus("1300","")
        readerState = False
        Return False
    End Try
    
    Log(isOpen)
    
    If  isOpen Then   
        powerCard(CARD_WARM_RESET)
        setProtocol(PROTOCOL_T1)
        openState = True
        Return True
    Else
        openState = False
        CloseReader
        Return False
    End If

    
    Return False
End Sub


Sub powerCard(cardattr As Int) As Int
    Try
        mReader.RunMethod ("power",Array  (slotNum, cardattr))
        Starter.errorStatus("0000","")
    Catch
        Starter.errorStatus("1300","")
        CloseReader
        openState = False
        readerState = False
        init = False
        Log(LastException)
    End Try
    

End Sub


Sub ReaderPresent
    usbdevices = uManager.GetDevices
    numberOfUsb = usbdevices.Length
    If numberOfUsb = 0 Then
        openState = False
        readerState = False
        init = False
        Return False
    End If
    Return True
End Sub


Sub CloseReader As JavaObject
    Log("close reader")
    If Not (openState) Then Return
    
    openState = False
    mReader.RunMethod ("close",Null)
End Sub

Sub status_event(MethodName As String, Args() As Object) As Object
Log("event")
    'Private slotNum As Int=Args(0)
    Private prevState As Int=Args(1)
    Private currState As Int=Args(2)
    Private getState1 As Object
    Private Unknown As Int=mReader.GetField ("CARD_UNKNOWN")
    Private Absent As Int =mReader.GetField ("CARD_ABSENT")
    Private Present As Int =mReader.GetField ("CARD_PRESENT")
    Private Undefined As Int=mReader.GetField ("PROTOCOL_UNDEFINED")
    Log( mReader.GetField ("CARD_UNKNOWN") )
    Log(  mReader )
    'getState1=mReader.RunMethod ("getState", Array As Object (slotNum))

    If currState=Unknown Then
        Msgbox("Card Unknown","Status")
    End If
    Log(prevState)
    Log(currState)
    If prevState > currState And currState<>Unknown Then
        Msgbox ("Card Removed","Status")
    Else
        If currState<>Unknown Then
            Log("kartica nepoznata")
        End If
    End If

End Sub


Public Sub getStateReader As Int
    
    Dim ud As UsbDevice
    
    numberOfUsb = usbdevices.Length
    
    Log(numberOfUsb)
    If numberOfUsb = 0 Then
        readerState = False
        openState = False
        Return -2
    End If
    ud = usbdevices(slotNum)
    
    Try
        Log(ud.DeviceName)
    Catch
        readerState = False
        openState = False
        Return -2
    End Try

    If uManager.HasPermission(uDevice) = False Then
        readerState = False
        openState = False
        Return -1
    End If
    ' = usbdevices(slotNum)
'    Log(ud.DeviceName)
    
    Return 0
    
    If Not (readerState) Then Return 2
    If Not (openState) Then Return 3
    Try
        Return mReader.RunMethod ("getState", Array As Object (slotNum))
    Catch
        Log(LastException)
        Dim errormsg As String = LastException
        If errormsg.IndexOf("The reader is not opened.") Then Return 1

    End Try
    Return 0
End Sub



Sub devicesNumber As Int
    usbdevices = uManager.GetDevices
    
    
'    Log("device number " & usbdevices.Length)
    
    If usbdevices.Length = 0 Or Not(readerState) Then
        Dim resetvars() As Byte
'        Starter.TaxCorePublicKey = resetvars
'        Starter.Certificate = resetvars
        If verificaUsbDevice Then
            readerState = True
        Else
            readerState = False
            init = False
            openState = False
        End If
        
    End If
    Return usbdevices.Length
End Sub



Sub verificaUsbDevice As Boolean
    
    
    usbdevices = uManager.GetDevices

    numberOfUsb = usbdevices.Length
    If usbdevices.Length = 0 Then Return False
    For i = 0 To usbdevices.Length - 1
        ' Dim ud As UsbDevice
        Dim ud As UsbDevice = usbdevices(i)
        Dim inter As UsbInterface
        inter = ud.GetInterface(i)

        uDevice = ud
        Log(i)
        If inter.InterfaceClass = 11 And inter.InterfaceSubclass = 0 Then
            'found our device and interface
            ''interface = inter
            uDevice = ud
            Log(uDevice.DeviceName)
            
            slotNum = i
            'Find correct endpoints
'            For b = 0 To interface.EndpointCount - 1
'                Dim endpoint As UsbEndpoint
'                endpoint = interface.GetEndpoint(b)
'                If endpoint.Type = Manager.USB_ENDPOINT_XFER_BULK Then
'                    If endpoint.Direction = Manager.USB_DIR_IN Then
'                        inEndpoint = endpoint
'                    Else If endpoint.Direction = Manager.USB_DIR_OUT Then
'                        outEndpoint = endpoint
'                    End If
'                End If
'            Next
        End If

    Next
    If uManager.HasPermission(uDevice) = False Then
        uManager.RequestPermission(uDevice)
        Return False
    End If
    
    Return True
End Sub



Sub transmit(cmd() As Byte) As Byte()
    If readerState = False Or init = False Or openState = False Then
        readerState = False
        init = False
        openState = False
        Return  Array As Byte()
    End If
    Log("transmit")
    error = False
    Dim recvBuffer(2048) As Byte
    Dim adpuAnswer() As Byte
    Try
        Dim receiveLenght As Int = mReader.RunMethod ("transmit",Array(slotNum, cmd, cmd.Length, recvBuffer, recvBuffer.Length))
    Catch
        Log(LastException)
        readerState = False
        init = False
        openState = False
        receiveLenght = 0
        Return Array As Byte()
    End Try

    If receiveLenght = 0 Then Return adpuAnswer
    Dim Switch As String = bytesToHexString(CopyArray(recvBuffer, receiveLenght-2, 2))
    adpuAnswer = CopyArray(recvBuffer, 0, receiveLenght-2)
    Log("OVO je vraceno " & bytesToHexString(recvBuffer))
    SWA = Switch.SubString2(Switch.Length-4, Switch.Length-2)
    SWB = Switch.SubString(Switch.Length-2)
    Log(SWA)
    Log(SWB)
    Starter.errorStatus(SWA&SWB,"")
    
    If bytesToHexString(adpuAnswer) <> "9000" Or receiveLenght = 0 Then
        error = True
    End If
    
    Return adpuAnswer

End Sub
 

drgottjr

Expert
Licensed User
Longtime User
my experience is with nfc tags. perhaps chip/strip cards are different in this regard: i could be mistaken, but if you could simply ask for the private key in my smart card, it wouldn't be private.
as to the public key and/or certificate, you need to know the cryptographic application aid and the file where those data are kept. this would differ from card type to card type. once you selected the correct aid and file, the apdu command for getdata is standard enough. but it has to be used in context. in some cases, in addition to knowing where the public key/certificate are stored, you may well have to be authenticated before the card will even give up that information. plus, if you did get the public key or certificate, it would most likely be DER encoded, you you'll have to parse through that.
 
Last edited:
Upvote 0

Culjko

Member
I need to authorize myself on the https api to download the token for further communication with the service, the actual APDU command that can be used to download the public key, but when I add it to the ckcert, and I call the api https://api.sandbox.suf.purs.gov.rs/api/v3/sdc/token and look at the error returned to me it says that I am missing the private key, there must be some way to read it or somehow different to get the token.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
Last edited:
Upvote 0

Culjko

Member
I got this as one of the possible solutions, but the libraries don't support some methods.
B4X:
Sub InitializePKCS11(tokenPath As String, pin As String) As JavaObject
    ' Create object PKCS#11
 
    Dim jo As JavaObject
    jo.InitializeStatic("sun.security.pkcs11.SunPKCS11")
    
    
    ' config InputStream
    Dim config As String
    config = $"name=SmartCard
              library=/_b4a Source/unicersal@LPFR/B4A/libpkcs11wrapper.so"$
              
    Dim inputStream As JavaObject
    inputStream.InitializeNewInstance("java.io.ByteArrayInputStream", Array(config.GetBytes("UTF8")))

    ' Initialize PKCS#11 provider with config
    'Dim pkcs11Provider As JavaObject = jo.RunMethod("New", Array(inputStream))
    Try
        Dim pkcs11Provider As JavaObject = jo.InitializeNewInstance("sun.security.pkcs11.SunPKCS11", Array(inputStream))
    Catch
        Log(LastException)
    End Try
    
    
    ' Register provider
    Dim security As JavaObject
    security.InitializeStatic("java.security.Security")
    security.RunMethod("addProvider", Array(pkcs11Provider))
    
    ' Vraćamo inicijalizovani provider
    Return pkcs11Provider
End Sub

Sub LoadCertificateFromSmartCard(provider As JavaObject, pin As String) As JavaObject
    ' Create KeyStore object (Smart Card)
    Dim keyStore As JavaObject
    keyStore.InitializeStatic("java.security.KeyStore")
    keyStore = keyStore.RunMethod("getInstance", Array("PKCS11", provider))
    
    ' Open KeyStore with PIN
    keyStore.RunMethod("load", Array(Null, pin))
    
    ' ADD certificate
    Dim aliases As JavaObject = keyStore.RunMethod("aliases", Null)
    Dim aliasName As String = aliases.RunMethod("nextElement", Null)
    
    ' Load Certificate
    Dim certificate As JavaObject = keyStore.RunMethod("getCertificate", Array(aliasName))
    
    ' return certificate object
    Return certificate
End Sub
 

Attachments

  • PKCS11.rar
    281.9 KB · Views: 140
Upvote 0

Culjko

Member
this is right line

B4X:
   ' Initialize PKCS#11 provider with config

    Dim pkcs11Provider As JavaObject = jo.RunMethod("New", Array(inputStream))
' i Add this line to try another way because upper line not work
    Try
        Dim pkcs11Provider As JavaObject = jo.InitializeNewInstance("sun.security.pkcs11.SunPKCS11", Array(inputStream))
    Catch
        Log(LastException)
    End Try
 
Upvote 0
Top