2 Java Card
2.3 O applet Java Card
O applet Java Card é uma subclasse de javacard.framework.Applet implementada sob as restrições impostas pela especificação Java Card. A conformidade de uma classe com a especi- ficação Java Card é verificada apenas durante a conversão do applet antes da sua instalação no cartão.
Nas versões iniciais da plataforma existia apenas um único meio de se desenvolver um ap- plet, no qual o desenvolvedor lidava diretamente com as estruturas do protocolo APDU. No entanto, a partir da versão 2.2, foi disponibilizado um applet que utiliza a comunicação por invocação remota de métodos (RMI), abstraindo os detalhes internos dos protocolos. Por intro- duzir uma camada adicional, essa última versão costuma ser menos eficiente e, por este motivo, ainda é menos utilizada que a versão APDU.
Nas subseções a seguir os modelos de aplicação APDU e RMI são exemplificados através de uma aplicação de bilhetagem eletrônica. O usuário da aplicação dispõe de uma quantidade de créditos em passagens (atributo balance) que são debitados a cada viagem. Observa-se que há três tipos de cartão: gratuidade, passagem inteira e estudante, sendo essa informação armazenada no atributo cardType. Foram implementados três métodos de serviço, são eles addCredit, debit e getCredits. O primeiro adiciona créditos no cartão, o segundo debita o valor de uma unidade de crédito de um cartão que não seja de gratuidade e o método getCredits pode ser utilizado para consultar o saldo atual do cartão.
2.3.1 Applet APDU
Nas figuras 2.3, 2.4 e 2.5 apresenta-se o código do applet na versão APDU para a aplicação de bilhetagem eletrônica Transport. É importante destacar a função de alguns métodos herdados da classe Applet e que são geralmente implementados na subclasse, são eles, install, process, select e deselect. Desses, apenas process é de implementação obrigatória, por se tratar de um método abstrato (abstract). No entanto, o método install, devido a sua importância para a aplicação, também é normalmente sobrescrito. A introdução dos métodos select e deselect na subclasse é opcional, uma vez que a implementação herdada é suficiente para permitir a
execução da aplicação.
O método install é chamado pelo Java Card Runtime Environment (JCRE) apenas na pri- meira vez em que o applet é executado. Em uma implementação mínima, deve-se criar uma instância da classe applet e registrá-la junto ao ambiente de execução, através da chamada a um dos métodos de registro da classe Applet. Apenas uma instância do applet é registrada, sendo a gerência dessa instância controlada pelo JCRE. Observa-se que o applet permanece em um estado inativo após ser registrado, aguardando até que seja selecionado.
p u b l i c c l a s s T r a n s p o r t A p p l e t e x t e n d s j a v a c a r d . framework . A p p l e t { s h o r t b a l a n c e ; C a r d s c a r d T y p e ; p u b l i c s t a t i c f i n a l s h o r t ENTIRE_CARD = ( s h o r t ) 0 x0 ; p u b l i c s t a t i c f i n a l b yt e OP_ADD_CREDIT = ( b y t e ) 0 x20 ; / / ( . . . ) p r i v a t e T r a n s p o r t A p p l e t ( by te [ ] b a r r a y , s h o r t b O f f s e t , by te bLength ) { super ( ) ; b a l a n c e = ( s h o r t ) 0 ; c a r d T y p e . s e t C a r d T y p e ( ENTIRE_CARD ) ; } p u b l i c s t a t i c vo id i n s t a l l ( by te [ ] bArray , s h o r t b O f f s e t , by te bLength ) { T r a n s p o r t A p p l e t t r a n s p o r t = new T r a n s p o r t A p p l e t ( bArray , b O f f s e t , bLength ) ; t r a n s p o r t . r e g i s t e r ( ) ;
}
p u b l i c vo id p r o c e s s (APDU apdu ) throws I S O E x c e p t i o n { by te b u f f e r [ ] = apdu . g e t B u f f e r ( ) ; / / ( . . . )
s w i t c h ( b u f f e r [ ISO7816 . OFFSET_INS ] ) {
c a s e OP_ADD_CREDIT : a d d C r e d i t ( apdu ) ; break ;
c a s e OP_DEBIT : d e b i t ( apdu ) ; break ;
c a s e OP_GET_CREDITS : g e t C r e d i t s ( apdu ) ; break ;
d e f a u l t : I S O E x c e p t i o n . t h r o w I t ( ISO7816 . SW_INS_NOT_SUPPORTED ) ; }
} / / ( métodos de s e r v i ç o . . . ) }
Figura 2.3: Um applet Java Card APDU para bilhetagem eletrônica - definição de atributos e métodos herdados da classe Applet.
Tendo em vista otimizar o uso da memória e minimizar operações de escrita de dados na memória persistente, é desejável que os objetos utilizados pelo applet sejam instanciados em seu construtor ou no método install diretamente. Uma vez que cada novo objeto ou array instan- ciado é salvo na memória persistente do cartão, a sua criação através do método install garante que essa operação será efetuada apenas uma vez, sendo o estado desses atributos recuperado em utilizações subsequentes. Outra boa prática é o uso de atributos transientes quando não houver a necessidade da persistência de determinado objeto ou array. Um objeto transiente é criado atra- vés de um dos métodos makeTransientArray da classe javacard.framework.JCSystem [Che00]. O método select é chamado sempre que um applet é requisitado para ser selecionado (apdu SELECT FILE). A implementação padrão fornecida pela classe Applet retorna true, dessa forma autorizando o acesso ao applet (a sua seleção para execução). Caso alguma restrição de acesso tenha que ser imposta antes da seleção do applet, ela deve ser feita em select, que irá autorizar
ou não a seleção. Por sua vez, o método deselect do applet selecionado (caso haja algum) é chamado sempre que um novo applet requisita ao JCRE a sua seleção. Dessa forma, ele pode ser utilizado para alguma operação de limpeza de memória ou de alteração do estado de algum atributo antes que o applet em execução seja retirado de seleção.
Uma vez selecionado, o applet encontra-se pronto para receber as requisições aos seus serviços através do seu método process. Ele recebe do JCRE um objeto APDU, o que permite o acesso ao buffer APDU, um array de bytes contendo os campos do comando que foram enviados na requisição pela aplicação host. Cada elemento do array contém a informação de um campo específico do comando APDU, sendo o índice desses campos no array facilmente acessado através de constantes presentes na interface javacard.framework.ISO7816. Observa-se que, por meio da instrução (INS) do buffer, a requisição é direcionada ao serviço apropriado, que obtém os dados necessários para a sua execução diretamente dos campos p1, p2 ou data contidos no array.
Os métodos de serviço do applet são específicos de cada aplicação. É importante obser- var que os serviços que necessitam acessar os campos do comando APDU devem fazer uma chamada ao método getBuffer de javacard.framework.APDU para obter o array buffer.
Um método que recebe algum dado encapsulado no campo data do comando APDU deve invocar o método setIncomingAndReceive para que o JCRE torne esse dado adicional acessível através do buffer APDU recebido. O número de bytes recebidos é retornado pelo método setIn- comingAndReceivee pode ser usado para verificar se esse número é igual ao número de bytes que se esperava receber. Como exemplo, na figura 2.4, tem-se a implementação do método addCredit, que deve receber a informação da quantidade de créditos que serão adicionados ao cartão.
p u b l i c voi d a d d C r e d i t (APDU apdu ) { by te [ ] b u f f e r = apdu . g e t B u f f e r ( ) ;
s h o r t c r = ( s h o r t ) U t i l . makeShort ( ( by te ) b u f f e r [ ISO7816 . OFFSET_P1 ] , ( b y t e ) b u f f e r [ ISO7816 . OFFSET_P2 ] ) ; s h o r t sum = ( s h o r t ) ( b a l a n c e + c r ) ; s h o r t c t = ( s h o r t ) c a r dT y p e . g e t C a r d T y p e ( ) ; i f ( ! ( c t != GRATUITOUS_CARD ) ) { I S O E x c e p t i o n . t h r o w I t ( EXCEPTIONS . CARD_TYPE_INVALID ) ; } e l s e i f ( ! ( sum <= 3 2 7 6 7 ) ) { I S O E x c e p t i o n . t h r o w I t ( EXCEPTIONS . BALANCE_EXCEEDED ) ; } e l s e i f ( ! ( c r > 0 ) ) { I S O E x c e p t i o n . t h r o w I t ( EXCEPTIONS . NEGATIVE_CREDIT ) ; } e l s e { b a l a n c e = sum ; } }
Caso um método precise enviar alguma informação para a aplicação host ele deve, inicial- mente, invocar o método setOutgoing, responsável por notificar o JCRE que algo será enviado no campo data da resposta APDU. O método setOutgoing também retorna o tamanho do dado que a aplicação host espera receber. Posteriormente, o método setOutgoingLength deve ser cha- mado para informar o número de bytes a serem enviados. Por fim, deve-se inserir a informação no buffer apdu. No método getCredits do exemplo (figura 2.5), a variável contendo a informa- ção da quantidade de créditos restantes no cartão é inserida no buffer apdu através do método setShort, da classe javacard.framework.Util. Finalmente, através da chamada a sendBytes, a resposta é enviada.
p u b l i c voi d g e t C r e d i t s (APDU apdu ) { by te [ ] b u f f e r = apdu . g e t B u f f e r ( ) ; s h o r t r e s = amount . g e t S h o r t V a l u e ( ) ; s h o r t l e = apdu . s e t O u t g o i n g ( ) ; apdu . s e t O u t g o i n g L e n g t h ( ( s h o r t ) 2 ) ; U t i l . s e t S h o r t ( b u f f e r , ( s h o r t ) 0 , ( s h o r t ) r e s ) ; apdu . s e n d B y t e s ( ( s h o r t ) 0 , ( s h o r t ) 2 ) ; }
Figura 2.5: Método de serviço getCredits do applet Transport.
2.3.2 Applet RMI
Destaca-se que a API Java Card para Invocação Remota de Métodos (RMI) foi introduzida somente na especificação Java Card 2.2, consistindo em um subconjunto da API RMI de Java e classes RMI específicas para Java Card.
No modelo RMI, a aplicação servidora (o applet Java Card) cria e torna acessíveis objetos que podem ser acessados remotamente através de uma interface pública. A aplicação cliente pode obter as referências a esses objetos e então invocar os seus métodos [Ort03b].
O desenvolvimento de um applet Java Card RMI compreende a especificação dos serviços providos pela aplicação remota como uma interface Java, a implementação dessa interface e o desenvolvimento do applet (subclasse de Applet) e demais classes auxiliares.
A interface remota (figura 2.6) especifica os serviços que serão fornecidos pelo applet para a aplicação host. Para tanto, ela deve estender a interface java.rmi.Remote. Observa-se que os métodos da interface remota são exatamente os mesmos encontrados no applet APDU. A diferença é que, agora, esses não serão mais implementados dentro da classe applet e que a sua assinatura foi modificada para incluir o lançamento de exceções. A RemoteException é exigência da interface Remote, sendo utilizada para reportar erros que por ventura ocorram
quando da execução de uma chamada remota de método. Já a especificação da UserException foi incluída para que se possa reportar os erros específicos da lógica de negócio da aplicação.
p u b l i c i n t e r f a c e T r a n s p o r t R e m o t e I n t e r f a c e e x t e n d s Remote {
p u b l i c vo id a d d C r e d i t ( s h o r t c r ) throws RemoteException , U s e r E x c e p t i o n ; p u b l i c vo id d e b i t ( ) throws RemoteException , U s e r E x c e p t i o n ;
p u b l i c s h o r t g e t C r e d i t s ( ) throws RemoteException , U s e r E x c e p t i o n ; }
Figura 2.6: Interface remota do Applet RMI
A implementação dos métodos da interface remota é feita pela classe TransportRemoteIm- plementation(figura 2.7), subclasse de javacard.framework.service.CardRemoteObject. Herdar de CardRemoteObject tem o efeito de exportar automaticamente o objeto remoto, possibilitando o acesso a ele e aos seus métodos pela aplicação host.
p u b l i c c l a s s T r a n s p o r t R e m o t e I m p l e m e n t a t i o n e x t e n d s CardRemoteObject implements T r a n s p o r t R e m o t e I n t e r f a c e { p r i v a t e s h o r t b a l a n c e ; C a r d s c a r d T y p e ; / / ( . . . ) p u b l i c vo id a d d C r e d i t ( s h o r t c r ) throws RemoteException , U s e r E x c e p t i o n { s h o r t c t = ( s h o r t ) c a r dT y p e . g e t C a r d T y p e ( ) ; i f ( ! ( c t != GRATUITOUS_CARD ) ) { U s e r E x c e p t i o n . t h r o w I t ( EXCEPTIONS . CARD_TYPE_INVALID ) ; } e l s e i f ( ! ( sum <= 3 2 7 6 7 ) ) { U s e r E x c e p t i o n . t h r o w I t ( EXCEPTIONS . BALANCE_EXCEEDED ) ; } e l s e i f ( ! ( c r > 0 ) ) { U s e r E x c e p t i o n . t h r o w I t ( EXCEPTIONS . NEGATIVE_CREDIT ) ; } e l s e { b a l a n c e = ( s h o r t ) ( b a l a n c e + c r ) ; } } / / ( . . . ) p u b l i c s h o r t g e t C r e d i t s ( ) throws RemoteException , U s e r E x c e p t i o n { r e t u r n b a l a n c e ; } }
Figura 2.7: Implementação dos serviços do applet RMI
Por fim, a figura 2.8 apresenta o código do applet Java Card na versão RMI. A estrutura do applet não é modificada com relação ao APDU. A principal diferença é a instanciação de classes específicas para implementação da comunicação por RMI. A classe Dispatcher regis- tra um serviço remoto e encaminha todo comando APDU para a classe de serviço registrada. Neste caso, temos a classe de serviço RMIService, que então recebe este APDU e o traduz em chamadas de métodos do objeto remoto passado em seu construtor [Ort03b].
p u b l i c c l a s s T r a n s p o r t A p p l e t e x t e n d s j a v a c a r d . framework . A p p l e t { p r i v a t e D i s p a t c h e r d i s p a t c h e r ; p r i v a t e R e m o t e S e r v i c e s e r v i c e ; p r i v a t e Remote r e m o t e I m p l ; p r i v a t e T r a n s p o r t A p p l e t ( by te [ ] bArray , s h o r t b O f f s e t , by te bLength ) { super ( ) ; r e m o t e I m p l = new T r a n s p o r t R e m o t e I m p l e m e n t a t i o n ( ) ; s e r v i c e = new RMIService ( r e m o t e I m p l ) ; d i s p a t c h e r = new D i s p a t c h e r ( ( s h o r t ) 1 ) ; d i s p a t c h e r . a d d S e r v i c e ( s e r v i c e , D i s p a t c h e r .PROCESS_COMMAND ) ; } p u b l i c s t a t i c vo id i n s t a l l ( by te [ ] bArray , s h o r t b O f f s e t , by te bLength ) { T r a n s p o r t A p p l e t t r a n s p o r t = new T r a n s p o r t A p p l e t ( bArray , b O f f s e t , bLength ) ; t r a n s p o r t . r e g i s t e r ( ) ;
}
p u b l i c vo id p r o c e s s (APDU apdu ) throws I S O E x c e p t i o n { d i s p a t c h e r . p r o c e s s ( apdu ) ;
} }
Figura 2.8: Implementação da classe applet na versão RMI