tananaev / passport-reader

e-Passport NFC Reader Android app
326 stars 126 forks source link

Add Passive Authentication and Chip Authentication #19

Closed RomainL972 closed 3 years ago

RomainL972 commented 4 years ago

I added the ability to validate that the passport is authentic and not a clone using passive authentication and chip authentication. For the passive authentication, I used a CSCA Master List from the Germany Government website : https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/ElekAusweise/CSCA/GermanMasterList.html

RomainL972 commented 4 years ago

This pull request is related to https://github.com/tananaev/passport-reader/issues/5

sertunc commented 4 years ago

Any update ? Can I use my country signing certificate file (.cer or .pem) with openssl or active authentication? thank you

RomainL972 commented 4 years ago

The modifications I made already authenticate your passport against all known country signing certificates. You can look at the code in MainActivity.java. If you want to use your own country signing certificate, you should give it to the CertPathValidator instead of the keystore.

sertunc commented 4 years ago

Hello @RomainL972 Thank you for quick response. I want to active authentication. Does it include this?

RomainL972 commented 4 years ago

Hello, Active Authentication isn't related to country certificates. It uses the private key in the passport to sign data, but it should be used with passive authentication. However Chip Authentication is a more secure version of Active Authentication and is included in this pull request

sertunc commented 4 years ago

I want to active authentication because I want to see if the card has been copied or not?

RomainL972 commented 4 years ago

You can use chip authentication which is almost the same. The code for Chip authentication is in this pull request

sertunc commented 4 years ago

@RomainL972 huge thanks for this pr but could you please add active authentication using dg15 and country certificate. please this is very important for us. Thank you

RomainL972 commented 4 years ago

Ok I can try to add it but my passport doesn't support it, so I won't be able to test it

sertunc commented 4 years ago

Thank you very much @RomainL972 I will test it and I will inform you

RomainL972 commented 4 years ago

@tananaev I updated my changes with yours so my pull request is compatible with the repository.

RomainL972 commented 4 years ago

I updated the pull request for the formatting. About automatically downloading the master list, I can tell you the process of downloading and parsing it but I don't know how to implement it in Java.

sertunc commented 4 years ago

@RomainL972 Will we make the 4th item on the phone? (Extract the data using openssl cms -inform DER -in AAAAMMDD_DEMasterList.ml -verify -noverify -out output.asn)

RomainL972 commented 4 years ago

I don't know how to use openssl on Java. I would need some time to learn. Is it really better to have one file or the other in the app assets?

tananaev commented 4 years ago

My main concern is keeping it up to date, so ideally device would download it automatically. If not possible, we can do it at the build time.

sertunc commented 4 years ago

maybe that link help us

sertunc commented 4 years ago

I don't know how to use openssl on Java. I would need some time to learn. Is it really better to have one file or the other in the app assets?

I want to learn how to verify the certificate of my passport with my country certificate using openssl

that project uses openssl but it is not java :(

RomainL972 commented 4 years ago

@tananaev In the mean time I can setup a GitHub action to automatically create the masterList file using a shell script

tananaev commented 4 years ago

I guess that also works.

RomainL972 commented 4 years ago

I have added a GitHub action that automatically downloads the new masterList and builds the apk with it. The apk files are then transfered to the transfer.sh website. The app-release.apk file is unsigned.

tananaev commented 4 years ago

Great, but can we have it a scheduled task that commits result to master?

RomainL972 commented 4 years ago

Great, but can we have it a scheduled task that commits result to master?

It's technically possible but I think it would be easier to have the apk file automatically generated by the github action. Otherwise it would need an always active service that checks if the masterList has been updated and has the right to make the commit

tananaev commented 4 years ago

If there was no change, I don't think it's possible to make a commit, so it shouldn't be a problem.

RomainL972 commented 3 years ago

@tananaev I have updated the GitHub action to download the masterList and create a commit if it's newer than the previous one. You just have to add a GitHub secret in the repository settings called USERNAME containing the value tananaev.

RomainL972 commented 3 years ago

I have updated the code according to your review @tananaev

RomainL972 commented 3 years ago

Hello @tananaev Is there anything else I can do for this pull request to be accepted?

RomainL972 commented 3 years ago

I have updated the pull request according to your reviews @tananaev

RomainL972 commented 3 years ago

The merge conflict was solved. For the action, you can see in GitHub Actions that the scripts are run by /bin/bash -e {0}. I use set +e to cancel the -e that is used by default.

wellbranding commented 3 years ago

@RomainL972 can you elaborate more about Active Authentication check? I could not found a difference between Chip authentication. I would be interested in contributing.

RomainL972 commented 3 years ago

Active Authentication is an older security protocol designed to make sure that the passport isn't a clone. It sends a public key to your terminal and you can then cryptographically check that the passport has the private key corresponding to the public key. Chip Authentication is a newer security protocol part of EAC (Extended Access Control), which also cryptographically proves that the passport isn't a clone. I chose to implement Chip Authentication instead of Active Authentication because my passport only supports Chip Authentication so I am not able to test Active Authentication. I did try to implement Active Authentication, and you can find the code here: https://github.com/RomainL972/passport-reader/tree/active-auth.

wellbranding commented 3 years ago

Thank you for your amazing explanation! Perhaps you saw the equivalent of this project for IOS? IOS also supports e-passports scanning, so this might be a great idea. If not, perhaps I would try to rewrite it in Swift. Would that be OK for you?

RomainL972 commented 3 years ago

If you want to contribute to an iOS passport reader app, there is https://github.com/AndyQ/NFCPassportReader. I don't know how it works but you can head there and see what you can do.

typelogic commented 3 years ago

Active Authentication is an older security protocol designed to make sure that the passport isn't a clone. It sends a public key to your terminal and you can then cryptographically check that the passport has the private key corresponding to the public key. Chip Authentication is a newer security protocol part of EAC (Extended Access Control), which also cryptographically proves that the passport isn't a clone. I chose to implement Chip Authentication instead of Active Authentication because my passport only supports Chip Authentication so I am not able to test Active Authentication. I did try to implement Active Authentication, and you can find the code here: https://github.com/RomainL972/passport-reader/tree/active-auth.

Thank you @RomainL972 for these works. I, too, am reading on this AA vs CA

rukshanfonseka commented 1 year ago

Any idea when I use my Aus passport I get this exception while doing chip authentication?

net.sf.scuba.smartcards.CardServiceException: File not found, CAPDU = 00A4020C02010E, RAPDU = 6A82 (SW = 0x6A82: FILE NOT FOUND)

caused by line:

                val dg14In = service.getInputStream(PassportService.EF_DG14)
Sophira commented 1 year ago

I'm also getting the same exception as @rukshanfonseka, with a UK passport issued in 2016. Actually, I get two slightly different exceptions, but only one of them is in doChipAuth. Regardless, here's the full text of both:

First exception (immediately upon scanning, not in doChipAuth):

06-08 04:33:30.428 11315 11358 W MainActivity: net.sf.scuba.smartcards.CardServiceException: File not found, CAPDU = 00A4020C02011C, RAPDU = 6A82 (SW = 0x6A82: FILE NOT FOUND)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.protocol.ReadBinaryAPDUSender.checkStatusWordAfterFileOperation(ReadBinaryAPDUSender.java:218)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.protocol.ReadBinaryAPDUSender.sendSelectFile(ReadBinaryAPDUSender.java:79)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.sendSelectFile(DefaultFileSystem.java:321)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.getFileInfo(DefaultFileSystem.java:272)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.getSelectedPath(DefaultFileSystem.java:129)
06-08 04:33:30.428 11315 11358 W MainActivity:  at net.sf.scuba.smartcards.CardFileInputStream.<init>(CardFileInputStream.java:60)
06-08 04:33:30.428 11315 11358 W MainActivity:  at org.jmrtd.PassportService.getInputStream(PassportService.java:595)
06-08 04:33:30.428 11315 11358 W MainActivity:  at com.tananaev.passportreader.MainActivity$ReadTask.doInBackground(MainActivity.kt:235)
06-08 04:33:30.428 11315 11358 W MainActivity:  at com.tananaev.passportreader.MainActivity$ReadTask.doInBackground(MainActivity.kt:207)
06-08 04:33:30.428 11315 11358 W MainActivity:  at android.os.AsyncTask$3.call(AsyncTask.java:394)
06-08 04:33:30.428 11315 11358 W MainActivity:  at java.util.concurrent.FutureTask.run(FutureTask.java:264)
06-08 04:33:30.428 11315 11358 W MainActivity:  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
06-08 04:33:30.428 11315 11358 W MainActivity:  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
06-08 04:33:30.428 11315 11358 W MainActivity:  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
06-08 04:33:30.428 11315 11358 W MainActivity:  at java.lang.Thread.run(Thread.java:1012)

The second exception happens six seconds later, just before the app displays the extracted information, and is almost exactly the same as the first except with a different CAPDU value (which matches @rukshanfonseka's) and the backtrace shows that doChipAuth was part of it:

06-08 04:33:36.109 11315 11358 W MainActivity: net.sf.scuba.smartcards.CardServiceException: File not found, CAPDU = 00A4020C02010E, RAPDU = 6A82 (SW = 0x6A82: FILE NOT FOUND)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.protocol.ReadBinaryAPDUSender.checkStatusWordAfterFileOperation(ReadBinaryAPDUSender.java:218)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.protocol.ReadBinaryAPDUSender.sendSelectFile(ReadBinaryAPDUSender.java:79)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.sendSelectFile(DefaultFileSystem.java:321)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.getFileInfo(DefaultFileSystem.java:272)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.DefaultFileSystem.getSelectedPath(DefaultFileSystem.java:129)
06-08 04:33:36.109 11315 11358 W MainActivity:  at net.sf.scuba.smartcards.CardFileInputStream.<init>(CardFileInputStream.java:60)
06-08 04:33:36.109 11315 11358 W MainActivity:  at org.jmrtd.PassportService.getInputStream(PassportService.java:600)
06-08 04:33:36.109 11315 11358 W MainActivity:  at com.tananaev.passportreader.MainActivity$ReadTask.doChipAuth(MainActivity.kt:291)
06-08 04:33:36.109 11315 11358 W MainActivity:  at com.tananaev.passportreader.MainActivity$ReadTask.doInBackground(MainActivity.kt:266)
06-08 04:33:36.109 11315 11358 W MainActivity:  at com.tananaev.passportreader.MainActivity$ReadTask.doInBackground(MainActivity.kt:207)
06-08 04:33:36.109 11315 11358 W MainActivity:  at android.os.AsyncTask$3.call(AsyncTask.java:394)
06-08 04:33:36.109 11315 11358 W MainActivity:  at java.util.concurrent.FutureTask.run(FutureTask.java:264)
06-08 04:33:36.109 11315 11358 W MainActivity:  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
06-08 04:33:36.109 11315 11358 W MainActivity:  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
06-08 04:33:36.109 11315 11358 W MainActivity:  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
06-08 04:33:36.109 11315 11358 W MainActivity:  at java.lang.Thread.run(Thread.java:1012)

I'm not entirely sure what might be happening here. I'm using the F-Droid build of e-Passport Reader 3.0 on GrapheneOS (Android 13) on a Pixel 7.