Tuesday, June 1, 2010

PCSC sample in OCaml

Here is the PCSC sample in OCaml language I promised in PC/SC sample in different languages.

Manuel Preliteiro wrote a OCaml PC/SC OCaml PC/SC
Binding to the PCSC standard
started in 2003 and still active in 2007. The latest version of the project is 0.6 and is still in beta but works fine according to my tests.

Installation


You first need to install OCaml. A simple apt-get install ocaml is enough on a Debian (or derivative like Ubuntu) system. Then get the ocamlpcsc-0.6.tar.gz archive from OCaml PC/SC
Binding to the PCSC standard
.

ocamlpcsc-0.6$ make
cc `pkg-config libpcsclite --cflags` -c convert.c
ocamlopt -c pcscmacros.ml
ocamlc -c pcscmacros.ml
cc -I /usr/lib/ocaml/3.10.2 `pkg-config libpcsclite --cflags` -c pcscC.c
ocamlopt -pp camlp4o -c pcscML.ml
ocamlc -custom -pp camlp4o -c pcscML.ml

Source code


I am not a Caml or OCaml expert. The example is just a modification of the example from Manuel to use my applet.

open Pcscmacros;;
open Printf;;
open PcscML;;
open Str;;

let func () =
  let (rvEstablishContext, hContext) = sCardEstablishContext scard_scope_system () () in

    if (rvEstablishContext != scard_s_success) then (
      printf "SCardEstablishContext: Cannot Connect to Resource Manager %d\n" rvEstablishContext;
      flush(stdout);
      ()
    );

    let (rvListReaders, readers) = sCardListReaders () in

      printf "Readers List: \n";
      Array.iter (fun z -> print_string (z ^ " : ")) readers;
      printf "\n";
      flush(stdout);

      let reader1 = readers.(0) in

      let (rvSCardConnect, hCard, dwActiveProtocol) = sCardConnect reader1 scard_share_shared scard_protocol_t1 in

        if (rvSCardConnect != scard_s_success) then (
          printf "SCardConnect: Cannot connect to card %d\n" rvSCardConnect;
          flush(stdout);
          ()
        );

        let pioSendPci = (scard_protocol_t1, 0) in
        let commande1 = [|0x00; 0xA4; 0x04; 0x00; 0x0A; 0xA0; 0x00; 0x00; 0x00; 0x62; 0x03; 0x01; 0x0C; 0x06; 0x01|] in
        let dwSendLength = Array.length commande1 in

        let (rvSCardTransmit, pioRecvPci, pcRecvBuffer) = sCardTransmit hCard pioSendPci commande1 dwSendLength in

          if (rvSCardTransmit != scard_s_success) then (
            printf "SCardTransmit: Cannot transmit to card %d\n" rvSCardTransmit;
            flush(stdout);
            ()
          )
          else (
            let (_, _) =  pioRecvPci in
              printf "Data transmited with success: ";
              Array.iter (fun z -> print_string ((string_of_int z) ^ " : ")) pcRecvBuffer;
              print_string "\n";
              flush(stdout)
          );

          let commande2 = [|0x00; 0x00; 0x00; 0x00|] in
          let dwSendLength = Array.length commande2 in

          let (rvSCardTransmit, pioRecvPci, pcRecvBuffer) = sCardTransmit hCard pioSendPci commande2 dwSendLength in
  
            if (rvSCardTransmit != scard_s_success) then (
              printf "SCardTransmit: Cannot transmit to card %d\n" rvSCardTransmit;
              flush(stdout);
              ()
            )
            else (
              let (_, _) =  pioRecvPci in
                printf "Data transmited with success: ";
                Array.iter (fun z -> print_string ((string_of_int z) ^ " : ")) pcRecvBuffer;
                print_string "\n";
                Array.iter (fun z -> print_char (char_of_int z)) pcRecvBuffer;
                print_string "\n";
                flush(stdout)
            );
  
            let rvSCardDisconnect = sCardDisconnect hCard scard_leave_card in
  
              if (rvSCardDisconnect != scard_s_success) then (
                printf "SCardDisconnect: Cannot disconect card %d\n" rvSCardDisconnect;
                flush(stdout);
                ()
              );

;;

let _ = func ();;

(** ocamlopt -c demo.ml **)
(** ocamlopt -pp camlp4o str.cmxa -cclib '-lpcsclite convert.o pcscC.o' -o demo pcscML.cmx pcscmacros.cmx demo.cmx **)


The last two line are the commands to execute to compile the program.

Output


Readers List: 
Gemplus GemPC Twin 00 00 : 
Data transmited with success: 144 : 0 : 
Data transmited with success: 72 : 101 : 108 : 108 : 111 : 32 : 119 : 111 : 114 : 108 : 100 : 33 : 144 : 0 : 
Hello world!?

You can see a ? character at the end. It is the status word 0x90 0x90 badly converted in ASCII. An improvement would be to only display n-2 first characters. This is left as an exercise to the reader.

Conclusion


Nothing much to say. If you are a OCaml user you may be interested by this wrapper.

This blog entry is dedicated to Alexandre.


Flattr this