Scripting Server

Using Remote Smart Card Access

Remote smart card access in the Scripting Server allows you to connect a remote smart card to a web application on the server.

This mechanism allows you to do things like

The remote terminal support implements the Global Platform Remote Application Management over HTTP protocol (RAMOverHTTP). This protocol is widely implemented by Trusted Service Manager to securely manage JavaCard applications on a secure element. The protocol provides for a transparent APDU channel using HTTP. Despite it's name, it's perfectly suited to obtain transparent access to a smart card located at the client.

The protocol requires a server and a client component. While the Scripting Server provides the server side, the client component is part of the OpenCard Framework (OCF). The OpenCard Framework provides a client that can be integrated in a Java application, a command line client to connect from scripts or a tray application running as a daemon process.

Interaction between the Client and the Server

The RAMOverHTTP protocol defines a TLV container for a command and response template exchanged via HTTP POST. The client initiates the session with a connect to the server. The server responds with the first command template containing one or more APDUs.

APDUs are forwarded to the card at the client and the response APDUs are collected. If all commands in the template are executed by the card, then the response template is send to the server in a next HTTP POST. If the server wants to send more APDUs, then those are included in response to the POST request. If the server has no more commands to send, the response is empty and the session is closed.

Mapping the protocol to the Scripting Environment

Whenever the server receives a new session from the client, a card terminal instance under the session id is created and a new thread is started calling the performCardUpdate() method in the global scope:

function performCardUpdate(session, pathInfo) {
  GPSystem.trace("Request received for session " + session.id + " at " + pathInfo);
  var card = new Card(session.id);
  
  try  {
    var atr = card.reset(Card.RESET_COLD);
    print(atr);

    ctr = ctr = Packages.opencard.core.terminal.CardTerminalRegistry.getRegistry();
    ct = ctr.cardTerminalForName(session.id);
    ct.sendNotification(0, "Test");

    card.sendApdu(0x00, 0x20, 0x00, 0x81);
    if (card.SW != 0x9000) {
      var aid = new ByteString("E82B0601040181C31F0201", HEX);
      var rsp = card.sendApdu(0x00, 0xA4, 0x04, 0x04, aid, 0, [0x9000]);

      card.sendApdu(0x00, 0x20, 0x00, 0x81, new ByteString("648219", ASCII));
    }

    for (var i = 0; i <= 1; i++) {
      print(i);
      var rsp = card.sendApdu(0x00, 0x84, 0x00, 0x00, 0x45, [0x9000]);
    }
  }
  finally {
    card.close();
  }
}

The above example connects with the remote card in the var card = new Card(session.id) statement. It then sends a reset to the remote card reader and receives the ATR of the card inserted. It sends a notification to the remote user via the ct.sendNotification() mechanism. The message code and message string can be used to keep the user informed about the card transaction taking place.

The next couple of lines select a SmartCard-HSM inserted into the remote card reader and obtain a number of random numbers.

Finally the communication channel is closed in the card.close() statement. The card terminal is removed when the performCardUpdate() method returns.

In the script you can of course use all classes and mechanisms defined in the OpenSCDP scripting environment. The above example is contained in the js/cardupdate directory of the Scripting Server bundle.

Running the Client

The simplest way to perform a card session with the server is to connect to the server with the OCF command line tool:

C:\Projects\OpenSCDP\OCF\build\lib>java -jar ocf-cc.jar http://localhost:8080/rt
/test
Connecting to http://localhost:8080/rt/test
Test
78 C: 00 20 00 81 - VERIFY
   R: SW1/SW2=6E00 (Checking error: Class not supported) Lr=0
78 C: 00 A4 04 04 - SELECT Lc=11
      0005  E8 2B 06 01 04 01 81 C3 1F 02 01                 .+.........
      Le=0
   R: SW1/SW2=9000 (Normal processing: No error) Lr=9
      0000  62 07 82 01 78 85 02 01 02                       b...x....
78 C: 00 20 00 81 - VERIFY Lc=6
      0005  36 34 38 32 31 39                                648219
   R: SW1/SW2=6700 (Checking error: Wrong length) Lr=0
78 C: 00 84 00 00 - GET CHALLENGE      Le=69
   R: SW1/SW2=9000 (Normal processing: No error) Lr=69
      0000  6A 52 35 70 52 FA 0D 2F C0 59 64 CC 69 7A 73 0D  jR5pR../.Yd.izs.
      0010  11 56 F3 E3 3C E1 1A 0C B7 61 60 1E E8 89 B2 52  .V..<....a`....R
      0020  75 68 18 67 84 4A 37 41 4E 54 E8 8E CF CB E3 3E  uh.g.J7ANT.....>
      0030  86 1B B9 C6 A1 88 8F 3B FC C8 30 22 5D 77 A8 0E  .......;..0"]w..
      0040  D4 AD 2E 79 44                                   ...yD
78 C: 00 84 00 00 - GET CHALLENGE      Le=69
   R: SW1/SW2=9000 (Normal processing: No error) Lr=69
      0000  78 E2 A7 4E 65 0F BD 70 20 16 86 60 B0 F2 5F 33  x..Ne..p ..`.._3
      0010  73 43 11 AA 95 4B 76 C4 C7 73 9B 57 C9 81 4C 63  sC...Kv..s.W..Lc
      0020  51 D9 5D B3 3B 9E 43 C0 59 CC F3 E3 AA CA 02 90  Q.].;.C.Y.......
      0030  2D BB CE 51 71 45 AD AE 31 7B AF 81 47 B8 A5 6E  -..QqE..1{..G..n
      0040  2E 7D 63 61 E6                                   .}ca.
Update complete

Running the Client in Daemon Mode

As running the client manually does not provide good usablity for a web application, an alternative way of running the client is available with the OCF daemon mode.

In OCF daemon mode, the OCF client listens for local connects on port 27001, extracts parameters from the connecting URL and starts the session with the server. In a web application this local connect can be embedded in the web page e.g. using the <img> element:

<img height="16" width="16"
        onload="window.location.reload()"
        src="http://localhost:27001/1296065.png?url=http://localhost:8080/scriptingserver/rt/testappl&sessionId=1n6bij7b4v0di" />

When the browser renders the web page, it tries to load an image from the URL http://localhost:27001/1296065.png, passing the parameters url and sessionId to the OCF daemon. The name of the image resource is ignored by the OCF client, however the name should be a random value to prevent the browser from using a cached image.

The url parameter contains the URL the OCF client shall connect to.

The sessionId parameter is used by the OCF client to generate a session cookie that links the card update session with the browser session at the server. This way the server application can link card updates with a browser session.

The client also accepts the pinrequired parameter with a PIN number as argument. Using the pinrequired parameter in the URL, the OCF client will make sure that the requested PIN is verified before a connection to the server is started. This way the server can request a local PIN verification using a local pop-up windows or attached PIN pad reader.

A local request will return a small image that denotes a passed or failed operation.

The daemon can be started by running the ocf-cc.jar with a double-click or by entering

java -jar ocf-cc.jar

To test the daemon enter http://127.0.0.1:27001 in your browser to show the red failure icon.

If you are running the client from the desktop, then it will show an icon in the desktop tray. Click on the icon to stop the daemon or to open a trace log window.

For security reasons, the OCF client will request the user to approve the URL the client connects to. The URL can be approved once or for all subsequent session. The list of approved URLs is contained in the .card-update-servers text file in the user directory.