1 Commits

Author SHA1 Message Date
TanelOrumaa
b565f6846d MOB-55 Demo website 2021-12-07 00:05:06 +02:00
16 changed files with 76 additions and 116 deletions

View File

@@ -4,6 +4,7 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.nfc.NfcAdapter
import android.nfc.TagLostException
import android.nfc.tech.IsoDep
import android.os.Bundle
import android.os.CountDownTimer
@@ -17,16 +18,11 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.tarkvaraprojekt.mobileauthapp.NFC.Comms
import com.tarkvaraprojekt.mobileauthapp.auth.AuthAppException
import com.tarkvaraprojekt.mobileauthapp.auth.Authenticator
import com.tarkvaraprojekt.mobileauthapp.auth.InvalidCANException
import com.tarkvaraprojekt.mobileauthapp.auth.InvalidPINException
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentAuthBinding
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
import com.tarkvaraprojekt.mobileauthapp.model.SmartCardViewModel
import java.io.IOException
import java.lang.Exception
import java.security.GeneralSecurityException
import kotlin.system.exitProcess
/**
@@ -111,9 +107,6 @@ class AuthFragment : Fragment() {
requireActivity().runOnUiThread {
binding.timeCounter.text = getString(R.string.card_detected)
}
var msgCode = 0
var msgArg : Int? = null
val card = IsoDep.get(tag)
card.timeout = 32768
card.use {
@@ -126,48 +119,30 @@ class AuthFragment : Fragment() {
)
paramsModel.setToken(jws)
requireActivity().runOnUiThread {
binding.timeCounter.text = getString(R.string.data_read)
goToNextFragment()
}
} catch (e: android.nfc.TagLostException) {
msgCode = R.string.tag_lost
} catch (e: InvalidCANException) {
msgCode = R.string.wrong_can_text
// If the CAN is wrong we will also delete the saved CAN so that the user won't use it again.
viewModel.deleteCan(requireContext())
} catch (e: InvalidPINException) {
msgCode = R.string.wrong_pin
msgArg = e.remainingAttempts
viewModel.deletePin(requireContext())
} catch (e: AuthAppException) {
msgCode = when (e.code) {
400 -> R.string.err_parameter
401 -> R.string.err_authentication
446 -> R.string.err_card_locked
448 -> R.string.err_bad_data
500 -> R.string.err_internal
else -> R.string.err_unknown
}
} catch (e: GeneralSecurityException) {
msgCode = R.string.err_internal
} catch (e: IOException) {
msgCode = R.string.err_reading_card
} catch (e: Exception) {
msgCode = R.string.err_unknown
} finally {
adapter.disableReaderMode(activity)
when(e) {
is TagLostException -> requireActivity().runOnUiThread { binding!!.timeCounter.text = getString(R.string.id_card_removed_early) }
else -> {
when ("invalid pin") {
in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
val messagePieces = e.message.toString().split(" ")
binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
viewModel.deletePin(requireContext())
}
if (msgCode != 0) {
requireActivity().runOnUiThread {
var msg = getString(msgCode)
if (msgArg != null)
msg = String.format(msg, msgArg)
binding.timeCounter.text = msg
else -> requireActivity().runOnUiThread {
binding.timeCounter.text = getString(R.string.wrong_can_text)
viewModel.deleteCan(requireContext())
}
// Gives user some time to read the error message
}
}
}
// Give user some time to read the error message
Thread.sleep(2000)
cancelAuth()
} finally {
adapter.disableReaderMode(activity)
}
}
}, NfcAdapter.FLAG_READER_NFC_A, null)

View File

@@ -3,9 +3,6 @@ package com.tarkvaraprojekt.mobileauthapp.NFC;
import android.nfc.tech.IsoDep;
import android.util.Log;
import com.tarkvaraprojekt.mobileauthapp.auth.AuthAppException;
import com.tarkvaraprojekt.mobileauthapp.auth.InvalidPINException;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.macs.CMac;
@@ -159,7 +156,7 @@ public class Comms {
private byte[] getResponse(byte[] APDU, String log) throws IOException {
byte[] response = idCard.transceive(APDU);
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
throw new AuthAppException(String.format("%s failed.", log), 500);
throw new RuntimeException(String.format("%s failed.", log));
}
Log.i(log, Hex.toHexString(response));
return response;
@@ -207,7 +204,7 @@ public class Comms {
// verify chip's MAC and return session keys
MAC = getMAC(createAPDU(dataForMACIncomplete, publicKey.getEncoded(false), 65), keyMAC);
if (!Hex.toHexString(response, 4, 8).equals(Hex.toHexString(MAC))) {
throw new AuthAppException("Could not verify chip's MAC.", 448); // *Should* never happen.
throw new RuntimeException("Could not verify chip's MAC."); // *Should* never happen.
}
return new byte[][]{keyEnc, keyMAC};
@@ -224,7 +221,7 @@ public class Comms {
selectFile(FID, info);
byte[] response = getResponse(new byte[0], readFile, "Read binary");
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
throw new AuthAppException(String.format("Could not read %s", info), 500);
throw new RuntimeException(String.format("Could not read %s", info));
}
return encryptDecryptData(Arrays.copyOfRange(response, 3, 19), Cipher.DECRYPT_MODE);
}
@@ -293,7 +290,7 @@ public class Comms {
private void selectFile(byte[] FID, String info) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, IOException {
byte[] response = getResponse(FID, selectFile, String.format("Select %s", info));
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
throw new AuthAppException(String.format("Could not select %s", info), 500);
throw new RuntimeException(String.format("Could not select %s", info));
}
}
@@ -318,7 +315,7 @@ public class Comms {
// select and read the personal data elementary files
for (byte index : lastBytes) {
if (index > 15 || index < 1) throw new AuthAppException("Invalid personal data FID.", 500);
if (index > 15 || index < 1) throw new RuntimeException("Invalid personal data FID.");
FID[1] = index;
// store the decrypted datum
@@ -351,9 +348,9 @@ public class Comms {
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
if (response[response.length - 2] == 0x69 && response[response.length - 1] == (byte) 0x83) {
throw new AuthAppException("Invalid PIN. Authentication method blocked.", 446);
throw new RuntimeException("Invalid PIN. Authentication method blocked.");
} else {
throw new InvalidPINException(response[response.length - 1] + 64);
throw new RuntimeException(String.format("Invalid PIN. Attempts left: %d.", response[response.length - 1] + 64));
}
}
}
@@ -382,7 +379,7 @@ public class Comms {
readCert[3] = (byte) (certificate.length % 256);
byte[] response = getResponse(new byte[0], readCert, "Read the certificate");
if (response[response.length - 2] == 0x6b && response[response.length - 1] == 0x00) {
throw new AuthAppException("Wrong read parameters.", 400);
throw new RuntimeException("Wrong read parameters.");
}
// Set the range containing a portion of the certificate and decrypt it
@@ -417,7 +414,7 @@ public class Comms {
byte[] response = getResponse(Env, MSESetEnv, "Set environment");
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
throw new AuthAppException("Setting the environment failed.", 500);
throw new RuntimeException("Setting the environment failed.");
}
InternalAuthenticate[4] = (byte) (0x1d + 16 * (token.length / 16));
@@ -425,7 +422,7 @@ public class Comms {
response = getResponse(token, InternalAuthenticate, "Internal Authenticate");
if (response[response.length - 2] != (byte) 0x90 || response[response.length - 1] != 0x00) {
throw new AuthAppException("Signing the token failed.", 500);
throw new RuntimeException("Signing the token failed.");
}
byte[] signature = encryptDecryptData(Arrays.copyOfRange(response, 3, 115), Cipher.DECRYPT_MODE);

View File

@@ -1,10 +0,0 @@
package com.tarkvaraprojekt.mobileauthapp.auth
/**
* A specialised RuntimeException class for exceptions related to the mobile authentication app.
* Possible error codes can be found at
* https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/wiki/Error-codes
* @param message Error message
* @param code An error code defined in the project wiki
*/
open class AuthAppException(message: String, var code: Int) : RuntimeException(message)

View File

@@ -1,7 +0,0 @@
package com.tarkvaraprojekt.mobileauthapp.auth
/**
* An AuthAppException for when the user entered CAN does not match the one read from the ID-card
* @see AuthAppException
*/
class InvalidCANException : AuthAppException("Invalid CAN", 400)

View File

@@ -1,10 +0,0 @@
package com.tarkvaraprojekt.mobileauthapp.auth
/**
* An AuthAppException for when the user entered PIN is not correct
* @see AuthAppException
*/
class InvalidPINException(val remainingAttempts: Int) : AuthAppException(
"Invalid PIN" + (if (remainingAttempts>0) "" else ". Authentication method blocked."),
if (remainingAttempts>0) 401 else 446
)

View File

@@ -19,7 +19,7 @@
<string name="nfc_not_available">NFC is not turned on or is not supported by the phone</string>
<string name="nfc_reading_error">The provided CAN does not match the ID card</string>
<string name="id_card_removed_early">ID card was removed too early</string>
<string name="wrong_pin">Wrong PIN 1. %s tries left on the card</string>
<string name="wrong_pin">Wrong PIN 1. Tries on the card left %s</string>
<!-- string resources for HomeFragment -->
<string name="pin_status_saved">PIN 1 saved</string>
@@ -75,8 +75,8 @@
<string name="saved_can">CAN: %s</string>
<string name="can_delete">Delete CAN</string>
<string name="saved_pin">PIN1: %s</string>
<string name="pin1_add">Add PIN 1</string>
<string name="pin1_delete">Delete PIN 1</string>
<string name="pin1_add">Add PIN1</string>
<string name="pin1_delete">Delete PIN1</string>
<string name="missing">not saved</string>
<string name="show">SHOW</string>
<string name="hide">HIDE</string>
@@ -84,13 +84,4 @@
<string name="menu_unavailable_message">Settings are currently unavailable</string>
<string name="can_deleted">CAN deleted</string>
<string name="pin_deleted">PIN 1 deleted</string>
<string name="err_unknown">Unknown error</string>
<string name="tag_lost">Connection between device and ID-card lost</string>
<string name="err_reading_card">Failed to read data from the ID-card</string>
<string name="err_internal">Internal error</string>
<string name="err_bad_data">Read bad data from the ID-card, try using the card again</string>
<string name="err_parameter">Required parameter is missing or invalid</string>
<string name="err_authentication">Failed to authenticate</string>
<string name="err_card_locked">Card locked</string>
</resources>

View File

@@ -18,7 +18,7 @@
<string name="nfc_not_available">NFC ei ole sisse lülitatud või puudub telefonil NFC võimekus</string>
<string name="nfc_reading_error">Sisestatud CAN ei ole vastavuses ID kaardiga</string>
<string name="id_card_removed_early">ID kaart eemaldati liiga vara</string>
<string name="wrong_pin">Vale PIN 1. ID kaardil PIN 1 sisetamise katseid järel: %s</string>
<string name="wrong_pin">Vale PIN 1. ID kaardil PIN 1 sisetamise kordi alles: %s</string>
<!-- string resources for HomeFragment -->
<string name="pin_status_saved">PIN 1 on salvestatud</string>
@@ -83,13 +83,4 @@
<string name="menu_unavailable_message">Seaded pole hetkel saadaval</string>
<string name="can_deleted">CAN kustatud</string>
<string name="pin_deleted">PIN 1 kustatud</string>
<string name="err_unknown">Tundmatu viga</string>
<string name="tag_lost">Ühendus seadme ja kaardi vahel katkes</string>
<string name="err_reading_card">Ei saanud ID-kaardilt andmeid lugeda</string>
<string name="err_internal">Rakendusesisene viga</string>
<string name="err_bad_data">ID-kaardilt loeti vigased andmed, proovi uuesti kaarti kasutada</string>
<string name="err_parameter">Vigane või puuduv parameeter</string>
<string name="err_authentication">Autentimine ebaõnnestus</string>
<string name="err_card_locked">Kaart lukus</string>
</resources>

View File

@@ -17,7 +17,7 @@
<string name="nfc_not_available">NFC is not turned on or is not supported by the phone</string>
<string name="nfc_reading_error">The provided CAN does not match the ID card</string>
<string name="id_card_removed_early">ID card was removed too early</string>
<string name="wrong_pin">Wrong PIN 1. %s tries left on the card</string>
<string name="wrong_pin">Wrong PIN 1. Tries on the card left %s</string>
<!-- string resources for HomeFragment -->
<string name="pin_status_saved">PIN 1 saved</string>
@@ -82,13 +82,4 @@
<string name="menu_unavailable_message">Settings are currently unavailable</string>
<string name="can_deleted">CAN deleted</string>
<string name="pin_deleted">PIN 1 deleted</string>
<string name="err_unknown">Unknown error</string>
<string name="tag_lost">Connection between device and ID-card lost</string>
<string name="err_reading_card">Failed to read data from the ID-card</string>
<string name="err_internal">Internal error</string>
<string name="err_bad_data">Read bad data from the ID-card, try using the card again</string>
<string name="err_parameter">Required parameter is missing or invalid</string>
<string name="err_authentication">Failed to authenticate</string>
<string name="err_card_locked">Card locked</string>
</resources>

View File

@@ -0,0 +1 @@
#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50}#nav{padding:30px}#nav a{font-weight:700;color:#2c3e50}#nav a.router-link-exact-active{color:#42b983}.container>div[data-v-2dcb24ca]{margin-top:2vh}.loginButton[data-v-2dcb24ca]{height:4vh;width:20vh;line-height:3vh}.loginButton>p[data-v-2dcb24ca]{font-size:3vh;text-align:center}#canvas[data-v-2dcb24ca]{height:30vh;width:30vh}nav[data-v-21165a6a]{height:5vh}div[data-v-cd8fea1a]{margin-top:2vh}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>demo-website</title><link href="/css/app.eb039c1f.css" rel="preload" as="style"><link href="/css/chunk-vendors.a251e031.css" rel="preload" as="style"><link href="/js/app.c2a68e49.js" rel="preload" as="script"><link href="/js/chunk-vendors.22b03028.js" rel="preload" as="script"><link href="/css/chunk-vendors.a251e031.css" rel="stylesheet"><link href="/css/app.eb039c1f.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but demo-website doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/js/chunk-vendors.22b03028.js"></script><script src="/js/app.c2a68e49.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long