1

I followed the ICAO's 7th edition "Appendix D to Part 11 - Worked Example: Basic Access Control" in order to create an Android app with Xamarin.Android that reads the data from an ePassport. However, I'm getting a 6300 status code from the chip at the EXTERNAL AUTHENTICATE step and there is not much information about that error code. It is too vague...

Here is the log of the steps performed by the app:

Tag tech list from the chip: android.nfc.tech.IsoDep, android.nfc.tech.NfcA

Select AID command:
00A4040C07A0000002471001

Select AID response:
9000

GET_CHALLENGE command:
0084000008

GET_CHALLENGE response:
6211B520F00565DD9000

documentNumber:
HU1234560

dateOfBirth:
920229

dateOfExpiry:
150101

keySeed SHA1(documentNumber + checkDigit + dateOfBirth + checkDigit + dateOfExpiry + checkDigit):
F3B48FDEF6A2374676C6B8892AFA58FB

kEnc SHA1(keySeed + 00000001):
9F399B0855DAD12F04FB3CB84D1F9AB3

kMac SHA1(keySeed + 00000002):
51102BA4C6A69CEF26BD45C94537B103

rndIFD:
CC95C0CD499F6306

kIFD:
39D661B07605B175E8BEF948609556F1

rndICC:
6211B520F00565DD

S:
CC95C0CD499F63066211B520F00565DD39D661B07605B175E8BEF948609556F1

eIFD(DesEdeEngine/CBC/NoPadding):
EC95CF0953AF87CA7FE3059A4B89A018309E8FD60359F38C4BA3216E763DD1D4

mIFD(DesEngine/ISO9797Alg3Mac/ISO7816d4Padding):
CED0EA4979A35978

External Authenticate command:
0082000028EC95CF0953AF87CA7FE3059A4B89A018309E8FD60359F38C4BA3216E763DD1CED0EA4979A359780028

External Authenticate response:
6300

Any recommendations?

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Cleyton T.
  • 231
  • 3
  • 12
  • 1
    In principle the encoding seems correct, but I don't see any check digits defined, if the input is correctly ASCII encoded (or was it BCD encoded? I don't think so). Furthermore, I don't of course know if the input is correct. 6300 is the general error (well, warning officially) you get if the authentication fails. If you wrote the code yourself you need to compare with a known good implementation. – Maarten Bodewes Jan 27 '19 at 23:56
  • Hi @MaartenBodewes, here is the string including the check digits: HU1234560092022871501010. And yes, the input is encoded using .NET's System.Text.Encoding.ASCII.GetBytes(string). My code is based on the JAVA's library https://sourceforge.net/projects/jmrtd/. I couldn't identify yet what I'm missing... =/ – Cleyton T. Jan 28 '19 at 14:06
  • I can remember that the encryption is DESede with zero IV, but I cannot remember the calculation of the check digits. Please do indicate the input of the initial (and spurious, in case you didn't notice) SHA1 hash as well as the input of the MAC in hexadecimals; those are the most likely to fail. I'll try and refresh my memory by looking at the actual specs (my old friends) and doing some calculations. PACE is much more "fun" to implement :) – Maarten Bodewes Jan 28 '19 at 16:38
  • Yes, I'm using DESede with zero IV (8 bytes with zeros). The calculation of the check digit is by multiplying each digit of data by its correspondent multiplier (7,3,1,7,3,1,...), and dividing the sum of the products by 10. The remainder is the check digit. The input of the initial SHA1 is indicated above as KeySeed. I'll start to take a look on the PACE ;) – Cleyton T. Jan 29 '19 at 09:22

2 Answers2

3

Your EXTERNAL AUTHENTICATE command seems to be wrong. It looks as if you copy the M_IFD value to the wrong position (off-by-one). Consequently, you chop off the last byte of E_IFD and have a zero byte at the end:

00 82 0000 28 EC95CF0953AF87CA7FE3059A4B89A018309E8FD60359F38C4BA3216E763DD1 CED0EA4979A35978 00 28
                                                                           ^^                 ^^
                        Last byte of E_IFD missing (only 31 bytes here) <--/                  |
                                                                Additional zero byte here? <--/

Besides that your values (more or less) match the comuptations of my MRTD testbench. You did not correct the parity bits of K_ENC and K_MAC though, but that won't make any difference unless you would (in future) use a crypto library that actually checks the parity bits of DES keys. Your current crypto library seems to ignore them and gives the expected result.


UPDATE (summarizing discussion in the comments below)

Moreover, did you verify that the document number, date of birth, and date of expiry match exactly the form used in the machine-readable zone? Both, the document number and the date of expiry in your question don't seem to be plausible values for a real passport.

Finally, as Maarten explained, the status word 6300 indicates that authentication failed. You can't expect the document to reveal further details about why exactly authentication failed. That's certainly not a lack of the ICAO specifications but a necessity from a security perspective. Imagine, for example, that the passport would be able to report that the date of birth that you used as input was wrong. An attacker would then be able to brute-force only that part of the key input.

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • Good eyes Michael! Probably the issue is in the library that I'm using when I create an APDU Command. I'll test it again and check the missing last byte. Thanks! – Cleyton T. Jan 29 '19 at 12:53
  • I tested it now with the complete E_IFD and still I get same status code 6300. Example: 0082000028BBCD7B50829115F2C74CCF7C758757877905F2CF91378A073A45D96225F5FCD7C64CDD1796A86E8C28 – Cleyton T. Jan 29 '19 at 13:04
  • I'll implement the parity bits checking to see if it makes any difference. I didn't implement it because ICAO's documentation mentions that this step is optional. – Cleyton T. Jan 29 '19 at 13:07
  • 1
    Since your challenge computation was correct, parity bits won't change anything. I can't check that APDU without the complete trace that includes your random values. – Michael Roland Jan 29 '19 at 13:55
  • 1
    Btw. did you verify that the document number and the date of expiry match those in the machine-reable zone? – Michael Roland Jan 29 '19 at 14:05
  • 1
    I just updated the trace in the question. Oh man, I've mistyped the DateOfBirth. The correct date is 28/02/1992 and not 29/02/1992 and guess what!? It works now! =D – Cleyton T. Jan 29 '19 at 14:13
  • 1
    The missing byte issue is part of the solution but a wrong date of birth was the real issue. Shall I mark the green tick for this answer? – Cleyton T. Jan 30 '19 at 08:43
  • @CleytonT. I'd suggest to revert the question to show the original issue (I already did that now) and *undelete* your own answer. Then mark whichever of the two answers *you* think solved the original problem as accepted. – Michael Roland Jan 30 '19 at 09:06
1

As @Michael Roland's pointed out all steps and computation are correct but after double checking the MRZ (input) as suggested I noticed that I mistyped the DateOfBirth which caused the status code = 6300. So this status code may be returned when a wrong input is given.

Unfortunately, ICAO's documentation is not clear enough to indicate this scenario.

Cleyton T.
  • 231
  • 3
  • 12
  • 1
    So did Michael indeed fix a bug in your code? In that case I'd just *comment* that you mistyped the MRZ and upvote / accept his answer. I'm a bit astounded that you didn't even upvote his. Finally, I *did* warn you about the 6300 reason, right? Or didn't you connect "authentication failed" with "possible wrong input"? – Maarten Bodewes Jan 30 '19 at 00:55
  • Yeah, I'm still getting the etiquette here. My apologies. – Cleyton T. Jan 30 '19 at 08:28