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

Error writing to ATMEL AT88SC1616C CryptoMemory Card #62

Closed
madsbrydegaard opened this issue Jan 10, 2019 · 9 comments
Closed

Error writing to ATMEL AT88SC1616C CryptoMemory Card #62

madsbrydegaard opened this issue Jan 10, 2019 · 9 comments
Assignees
Labels

Comments

@madsbrydegaard
Copy link

Hi,

It might be far-fetched but I am having an issue writing to a ATMEL AT88SC1616C CryptoMemory Card using Identive CLOUD 2700 F Smart Card Reader

I am following the instructions from this manual:
http:https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-5211-CryptoMem-Full-Specification-Datasheet.pdf

using reader.transmit method of nfc-pcsc

// in ES6
// import { NFC } from 'nfc-pcsc';

// without Babel in ES2015
const { NFC } = require('nfc-pcsc');

const nfc = new NFC(); // optionally you can pass logger

nfc.on('reader', reader => {

    console.log(`${reader.reader.name}  device attached`);
	reader.autoProcessing = false;

	reader.on('card', async card => {

		console.log(`${reader.reader.name} card detected`, card);

		try {

			const setZoneCMD = Buffer.from([
				0x00, 
				0xB4, 
				0x03, 
				0x00, // ZONE
				0x00
			]);

			const readZoneCMD = Buffer.from([
				0x00,
				0xB2,
				0x00,
				0x00, // ZONE
				0x126// 0x00 = all of zone = 128 bytes for card type
			]);

			const readConfigCMD = Buffer.from([
				0x00,
				0xB6,
				0x00,
				0x00, 
				0xF0
			]);

			const verifyPwd0CMD = Buffer.from([
				0x00,
				0xBA,
				0x00,
				0x00,
				0x03,
				0xXX, // Hidden for security
				0xXX,
				0xXX
			]);

                        // Works - return 9000 = OK
			console.log(`verifyPwd0CMD`, await reader.transmit(verifyPwd0CMD, 4));

                        // Throw error - see below
			console.log(`setZoneCMD`, await reader.transmit(setZoneCMD, 2));

                        // Works - return 6900 = Not authorized
			console.log(`readZoneCMD`, await reader.transmit(readZoneCMD, 130));

		} catch (err) {
			console.error(`error when reading data`, err);
		}

    });

    reader.on('card.off', card => {
        console.log(`${reader.reader.name}  card removed`, card);
    });

    reader.on('error', err => {
        console.log(`${reader.reader.name}  an error occurred`, err);
    });

    reader.on('end', () => {
        console.log(`${reader.reader.name}  device removed`);
    });

});

nfc.on('error', err => {
    console.log('an error occurred', err);
});

However I keep getting a transmission error from nfc-pcsc when setting the zone byte (write operation)

error when reading data { TransmitError: An error occurred while transmitting.
    at reader.transmit (C:\Users\mads\Source\Repos\electron-pcsc\node_modules\nfc-pcsc\dist\Reader.js:244:20)
  name: 'TransmitError',
  code: 'failure',
  previous:
   Error: SCardTransmit error: Communication error. Please try again (0x8010002f) 

Does anyone have hint to what the problem is?

NFC-PCSC 0.7.0, Node.js 10.11.0, Chromium 69.0.3497.106, and Electron 4.0.0

@pokusew pokusew self-assigned this Jan 10, 2019
@pokusew
Copy link
Owner

pokusew commented Jan 10, 2019

Hi @madsbrydegaard,

I have no experience with the ATMEL cards but according to the docs you posted, it seems you have to perform an ACK polling sequence after some commands (see page 32, Section 7.4 Acknowledge Polling, Table 7-2).

Citation from Verify Password: $BA, 7.6.5.2, page 41:

Once the sequence has been carried out, the device requires the host to perform an ACK polling sequence with the system read command $B6. In order to know whether the inserted password was correct, the host can read the corresponding password attempts counter and verify the value is $FF.

Hope it helps. 🙂

@madsbrydegaard
Copy link
Author

@pokusew
Thanks for the quick reply and the positive effort!

The page you are referring to are located in synchronous protocol - but I guess the lib are actually using the async protocol (T-0 / ISO 7816-3) starting at page 45 (However I am only guessing)

In that section there is no mentioning of any polling cmd since (i guess) the host are a(sync)waiting the device to complete any writes.

Can you confirm whether nfc-pcsc uses sync or async protocol?

@madsbrydegaard
Copy link
Author

madsbrydegaard commented Jan 11, 2019

On further investigation I found one similar incident as mine
https://stackoverflow.com/questions/29016120/getting-pcsc-exception-0x8010002f

which again led me to this stackpage
https://stackoverflow.com/questions/42652564/sim-javacard-cant-send-ins-69-or-96

It refers to the ISO 7816-3 standard and states that after sending the headers (instruction bytes) to the card - and before any data is transferred - a procedure byte is returned from the card. This byte can have a range of values - wherein 60 is a NULL byte that requires no further action.

This is what was causing the same exception as mine, in that other project (mentioned at top) and I suspect it might be the case for me as well.

The reason is, that the command which causes the exception is a set command that does not need to return anything. So I suspect that the card returns SW1=60 (in accordance with ISO 7816-3) and that is what causes the problem.

Any further help is greatly appreciated!

@pokusew
Copy link
Owner

pokusew commented Jan 14, 2019

Hi @madsbrydegaard,

nfc-pcsc is the wrapper around the PC/SC system API which is quite a high level API. The protocol is actually determined by the reader itself, in your case, the reader uTrust 2700 F supports ISO/IEC 7816 part 1-4, so the communication with your card is according to the ISO 7816-3 standard (which probably means async).

I got an idea where the issue might come from. 💡

Could you please log the value of reader.connection in card event handler (see the code below) and send me the output?

const { NFC } = require('nfc-pcsc');

const nfc = new NFC(); // optionally you can pass logger

nfc.on('reader', reader => {

    console.log(`${reader.reader.name}  device attached`);

    reader.autoProcessing = false;

    reader.on('card', async card => {

        console.log(`${reader.reader.name} card detected`, card);

        console.log('connection', reader.connection); // <- add this line and send me the output

    });

    // the rest of the handlers

});

nfc.on('error', err => {
    console.log('an error occurred', err);
});

Explanation: When a card is detected, nfc-pcsc connects to it (see here) with unspecified protocol and in SCARD_SHARE_SHARED mode (see here). So when we log the reader.connection, we will find out which protocol (T=0 or T=1) is actually used and eventually we can try hard coding it to T=0 and see if it has some effect.

Hope it helps. 🙂

@madsbrydegaard
Copy link
Author

connection { type: 2, protocol: 1 }

@madsbrydegaard
Copy link
Author

@pokusew

Good news - Being confirmed that protocol was 1 = sync I looked again and by pure coincidence I read in the documentation that set commands should consist of 4 bytes and not 5 - as in async.

I have previously followed some code from a earlier project where they used 5 bytes for set cmds so I assumed that 5 was the magic number. It wasnt...

And It did the trick - I can now set and read. Next I will try to write as well ;)

You can go ahead and close this.
Thnx a bunch...

@pokusew
Copy link
Owner

pokusew commented Jan 14, 2019

@madsbrydegaard Great you made it work! 👍Good job!

Just to make it clear: You removed the first byte (0x00 CLASS) and it started working?


BTW: I think that connection { type: 2, protocol: 1 } means that protocol = 1 = SCARD_PROTOCOL_T0, i.e., T=0.

You can verify it by printing:

console.log('constants', {
    raw: reader.reader.SCARD_PROTOCOL_RAW, // 4
    t0: reader.reader.SCARD_PROTOCOL_T0, // 1
    t1: reader.reader.SCARD_PROTOCOL_T1, // 2
    or: reader.reader.SCARD_PROTOCOL_T0 | reader.reader.SCARD_PROTOCOL_T1, // 3
});

And according to to card's docs, section 6.2 (page 27):

The Asynchronous T=0 Protocol defined by ISO 7816-3 is used for compatibility with the industry standard smart card readers. Selecting this mode requires the following power-up sequence which complies with ISO 7816-3 for a cold reset in smart card applications.

However, it doesn't matter! The important thing is that it works! 😄

@madsbrydegaard
Copy link
Author

madsbrydegaard commented Jan 14, 2019

Actually I removed the last byte, so that my set user zone cmd looks like this:

const setZoneCMD = Buffer.from([
	0x00	//CLASS,
	0xB4	//INS,
	0x03	//P1,
	0x00	//P2 = ZONE
]);

Which is strange since its only valid in sync mode.
And as you mention the reader are using async mode which I wrongly interpreted as sync.

I can also confirm that writing is successful without the need to wait and make ACK calls.
So it looks like its working properly now.

BTW Here is the output from your log cmd which confirms the use of T=0 protocol
constants { raw: 65536, t0: 1, t1: 2, or: 3 }

Thnx again for your time.

@pokusew
Copy link
Owner

pokusew commented Jan 14, 2019

@madsbrydegaard You're welcome! The behavior is really weird but I am happy it works. 🙂

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

No branches or pull requests

2 participants