Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provisioning card without secure channel #68

Open
mistial-dev opened this issue Sep 26, 2023 · 5 comments
Open

Provisioning card without secure channel #68

mistial-dev opened this issue Sep 26, 2023 · 5 comments

Comments

@mistial-dev
Copy link

I'm working on some unit testing for use with OpenFIPS201, and am using jCardSim. The open source version does not support Global Platform or Secure Channel.

Looking through the code, I can see that administrative keys can be used for card administration, but I do not see a way to create an administrator key without using a secure channel.

Does the administrative user have to be defined in secure channel before it can be used for other operations?

@makinako
Copy link
Owner

Hi @mistial-dev, yes this is correct there is no way to avoid SCP at all in this case for a few reasons:

  • The file system must first be defined (since the existence of the '9B' key is just a configuration item for OF201)
  • Because of the above, default values aren't in place. This is further restricted by FIPS 140 which states that any default authentication data must be replaced on first use. There isn't an elegant solution to enforce this, though it's possible.
  • We have explicitly never permitted key material to be sent over plaintext, and again FIPS 140 cements this requirement by prohibiting it.

Philosophically speaking, we don't encourage the 9B key at all since it provides no encryption or integrity for the subsequent management commands. It is retained for backwards-compatibility, but as you have seen it really only helps you post-issuance.

I ran into the same issue with testing as you have. It is unfortunate that jCardSim doesn't support it but hey they have to make money somehow in a pretty niche market so I can't totally blame them :)

Our unit testing was all inside an old commercial tool and I tried a few different approaches, but ultimately the testing framework became Zephyr Scale (on JIRA) to define the tests generically and then export them to NXP JCShell scripts. This gave us SCP support ability to easily use the P71D600 simulator (which helps with FIPS testing).

It's a good tool, but I'm not happy that it is proprietary and requires an NXP NDA and a few hoops to get! The Zephyr Scale aspect gives the option to de-couple from this when a good solution is found/developed and one day we will, but for now it's a pragmatic option for testing.

@martinpaljak
Copy link

Looking at the use of GPSystem in this applet (GPSystem.getSecureChannel(), resetSecurity(), getSecurityLevel(), unwrap(), processSecurity()) then "mocking" this as a java code for jcardsim is max half day of effort. Don't know about CVM but probably the same.

@makinako
Copy link
Owner

Looking at the use of GPSystem in this applet (GPSystem.getSecureChannel(), resetSecurity(), getSecurityLevel(), unwrap(), processSecurity()) then "mocking" this as a java code for jcardsim is max half day of effort. Don't know about CVM but probably the same.

It's true, but only if we had a Java implementation of SCP to base it off :) For the accreditation process we are locked into the current JCShell path but if we had this available for JCardSim it would be a logical next step for the generic tests (Which are most of them)

@mistial-dev
Copy link
Author

Looking at the use of GPSystem in this applet (GPSystem.getSecureChannel(), resetSecurity(), getSecurityLevel(), unwrap(), processSecurity()) then "mocking" this as a java code for jcardsim is max half day of effort. Don't know about CVM but probably the same.

I put around that much time into trying to get mocking working before asking about alternate ways. I’m not an expert Java developer, and the techniques I use in dot net don’t really translate well. jCardSim seems to want a class, and mocking synthesizes a new class. I got as far as extracting the instantiated class from the jCardSim runtime, to use with the mocking framework, but then had no way to feed it back into jCardSim.

My plan was to just make a fake security domain that would pass through APDUs untouched. That way I could keep my Gpshell scripts otherwise unmodified.

@mistial-dev
Copy link
Author

mistial-dev commented Sep 28, 2023

ChatGPT proved surprisingly helpful.

    @org.junit.jupiter.api.Test
    void testConfiguration() {
        try (MockedStatic<GPSystem> mocked = Mockito.mockStatic(GPSystem.class)) {
            SecureChannel mockedSecureChannel = Mockito.mock(SecureChannel.class);

            // Mock getSecurityLevel() to return a value that indicates that the card is authenticated, has decryption, and has MAC
            Mockito.when(mockedSecureChannel.getSecurityLevel()).thenReturn((byte) (SecureChannel.AUTHENTICATED | SecureChannel.C_DECRYPTION | SecureChannel.C_MAC));

            // Mock getSecureChannel() to return the mocked SecureChannel
            mocked.when(GPSystem::getSecureChannel).thenReturn(mockedSecureChannel);

            // Mock `short processSecurity(APDU apdu)` to return 0 bytes of data.
            Mockito.when(mockedSecureChannel.processSecurity(Mockito.any())).thenReturn((short)0);
            
            // Mock `short unwrap(byte[] data, short offset, short length)` to return the length (from the third argument)
            Mockito.when(mockedSecureChannel.unwrap(Mockito.any(byte[].class), Mockito.anyShort(), Mockito.anyShort())).thenAnswer(invocation -> invocation.getArgument(2));

            // Check for a success response
            byte[] dataBytes = simulator.selectAppletWithResult(OF201_AID);

            // The last two bytes of the response should be 0x9000.  Verify that.
            assertArrayEquals(new byte[]{(byte) 0x90, (byte) 0x00}, new byte[]{dataBytes[dataBytes.length - 2], dataBytes[dataBytes.length - 1]});

            // Define the configuration command in hex
            String configurationCommand = "E4 DB 3F 00 5D 68 5B A0 24 80 01 FF 81 01 00 82 01 00 83 01 00 84 01 06 85 01 08 86 01 06 87 01 " +
                    "05 88 01 00 89 01 04 8A 01 00 8B 01 00 A1 12 80 01 FF 81 01 00 82 01 08 83 01 06 84 01 05 85 01 " +
                    "00 A2 03 80 01 00 A3 03 80 01 00 A4 15 80 01 00 81 01 00 82 01 00 83 01 00 84 01 FF 85 01 00 86 " +
                    "01 00";

            // Execute the configuration command and get the response
            CommandAPDU configurationCommandAPDU = new CommandAPDU(hexStringToByteArray(configurationCommand));
            ResponseAPDU configurationResponseAPDU = simulator.transmitCommand(configurationCommandAPDU);

            // Verify that the response is 0x9000
            assertArrayEquals(new byte[]{(byte) 0x90, (byte) 0x00}, configurationResponseAPDU.getBytes());
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants