OTG: Remove obsolete Pin classes, reenable changeKey method
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
package org.sufficientlysecure.keychain.smartcard;
|
|
||||||
|
|
||||||
public class PinException extends CardException {
|
|
||||||
public PinException(final String detailMessage, final short responseCode) {
|
|
||||||
super(detailMessage, responseCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package org.sufficientlysecure.keychain.smartcard;
|
|
||||||
|
|
||||||
public enum PinType {
|
|
||||||
BASIC(0x81),
|
|
||||||
ADMIN(0x83),;
|
|
||||||
|
|
||||||
private final int mMode;
|
|
||||||
|
|
||||||
PinType(final int mode) {
|
|
||||||
this.mMode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getmMode() {
|
|
||||||
return mMode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,6 +17,11 @@ import java.security.interfaces.RSAPrivateCrtKey;
|
|||||||
|
|
||||||
import nordpol.Apdu;
|
import nordpol.Apdu;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant
|
||||||
|
* NFC devices.
|
||||||
|
* For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf
|
||||||
|
*/
|
||||||
public class SmartcardDevice {
|
public class SmartcardDevice {
|
||||||
// Fidesmo constants
|
// Fidesmo constants
|
||||||
private static final String FIDESMO_APPS_AID_PREFIX = "A000000617";
|
private static final String FIDESMO_APPS_AID_PREFIX = "A000000617";
|
||||||
@@ -30,7 +35,6 @@ public class SmartcardDevice {
|
|||||||
private boolean mPw1ValidatedForSignature;
|
private boolean mPw1ValidatedForSignature;
|
||||||
private boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming?
|
private boolean mPw1ValidatedForDecrypt; // Mode 82 does other things; consider renaming?
|
||||||
private boolean mPw3Validated;
|
private boolean mPw3Validated;
|
||||||
private boolean mTagHandlingEnabled;
|
|
||||||
|
|
||||||
protected SmartcardDevice() {
|
protected SmartcardDevice() {
|
||||||
}
|
}
|
||||||
@@ -39,6 +43,10 @@ public class SmartcardDevice {
|
|||||||
return LazyHolder.mSmartcardDevice;
|
return LazyHolder.mSmartcardDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getHex(byte[] raw) {
|
||||||
|
return new String(Hex.encode(raw));
|
||||||
|
}
|
||||||
|
|
||||||
private String getHolderName(String name) {
|
private String getHolderName(String name) {
|
||||||
try {
|
try {
|
||||||
String slength;
|
String slength;
|
||||||
@@ -59,10 +67,6 @@ public class SmartcardDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getHex(byte[] raw) {
|
|
||||||
return new String(Hex.encode(raw));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Passphrase getPin() {
|
public Passphrase getPin() {
|
||||||
return mPin;
|
return mPin;
|
||||||
}
|
}
|
||||||
@@ -79,7 +83,6 @@ public class SmartcardDevice {
|
|||||||
this.mAdminPin = adminPin;
|
this.mAdminPin = adminPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW MY METHOD
|
|
||||||
public void changeKey(CanonicalizedSecretKey secretKey, Passphrase passphrase) throws IOException {
|
public void changeKey(CanonicalizedSecretKey secretKey, Passphrase passphrase) throws IOException {
|
||||||
long keyGenerationTimestamp = secretKey.getCreationTime().getTime() / 1000;
|
long keyGenerationTimestamp = secretKey.getCreationTime().getTime() / 1000;
|
||||||
byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) keyGenerationTimestamp).array();
|
byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) keyGenerationTimestamp).array();
|
||||||
@@ -90,8 +93,9 @@ public class SmartcardDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Slot is empty, or contains this key already. PUT KEY operation is safe
|
// Slot is empty, or contains this key already. PUT KEY operation is safe
|
||||||
boolean canPutKey = !containsKey(keyType)
|
boolean canPutKey = isSlotEmpty(keyType)
|
||||||
|| keyMatchesFingerPrint(keyType, secretKey.getFingerprint());
|
|| keyMatchesFingerPrint(keyType, secretKey.getFingerprint());
|
||||||
|
|
||||||
if (!canPutKey) {
|
if (!canPutKey) {
|
||||||
throw new IOException(String.format("Key slot occupied; card must be reset to put new %s key.",
|
throw new IOException(String.format("Key slot occupied; card must be reset to put new %s key.",
|
||||||
keyType.toString()));
|
keyType.toString()));
|
||||||
@@ -102,8 +106,12 @@ public class SmartcardDevice {
|
|||||||
putData(keyType.getTimestampObjectId(), timestampBytes);
|
putData(keyType.getTimestampObjectId(), timestampBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsKey(KeyType keyType) throws IOException {
|
private boolean isSlotEmpty(KeyType keyType) throws IOException {
|
||||||
return !keyMatchesFingerPrint(keyType, BLANK_FINGERPRINT);
|
// Note: special case: This should not happen, but happens with
|
||||||
|
// https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
|
||||||
|
if (getMasterKeyFingerprint(keyType.getIdx()) == null) return true;
|
||||||
|
|
||||||
|
return keyMatchesFingerPrint(keyType, BLANK_FINGERPRINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean keyMatchesFingerPrint(KeyType keyType, byte[] fingerprint) throws IOException {
|
public boolean keyMatchesFingerPrint(KeyType keyType, byte[] fingerprint) throws IOException {
|
||||||
@@ -248,7 +256,6 @@ public class SmartcardDevice {
|
|||||||
* @param mode For PW1, this is 0x81 for signing, 0x82 for everything else.
|
* @param mode For PW1, this is 0x81 for signing, 0x82 for everything else.
|
||||||
* For PW3 (Admin PIN), mode is 0x83.
|
* For PW3 (Admin PIN), mode is 0x83.
|
||||||
*/
|
*/
|
||||||
// METHOD UPDATED [OK]
|
|
||||||
private void verifyPin(int mode) throws IOException {
|
private void verifyPin(int mode) throws IOException {
|
||||||
if (mPin != null || mode == 0x83) {
|
if (mPin != null || mode == 0x83) {
|
||||||
|
|
||||||
@@ -285,7 +292,7 @@ public class SmartcardDevice {
|
|||||||
* @param dataObject The data object to be stored.
|
* @param dataObject The data object to be stored.
|
||||||
* @param data The data to store in the object
|
* @param data The data to store in the object
|
||||||
*/
|
*/
|
||||||
public void putData(int dataObject, byte[] data) throws IOException {
|
private void putData(int dataObject, byte[] data) throws IOException {
|
||||||
if (data.length > 254) {
|
if (data.length > 254) {
|
||||||
throw new IOException("Cannot PUT DATA with length > 254");
|
throw new IOException("Cannot PUT DATA with length > 254");
|
||||||
}
|
}
|
||||||
@@ -319,7 +326,7 @@ public class SmartcardDevice {
|
|||||||
* 0xB8: Decipherment Key
|
* 0xB8: Decipherment Key
|
||||||
* 0xA4: Authentication Key
|
* 0xA4: Authentication Key
|
||||||
*/
|
*/
|
||||||
public void putKey(int slot, CanonicalizedSecretKey secretKey, Passphrase passphrase)
|
private void putKey(int slot, CanonicalizedSecretKey secretKey, Passphrase passphrase)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (slot != 0xB6 && slot != 0xB8 && slot != 0xA4) {
|
if (slot != 0xB6 && slot != 0xB8 && slot != 0xA4) {
|
||||||
throw new IOException("Invalid key slot");
|
throw new IOException("Invalid key slot");
|
||||||
@@ -577,6 +584,10 @@ public class SmartcardDevice {
|
|||||||
return mTransport;
|
return mTransport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTransport(Transport mTransport) {
|
||||||
|
this.mTransport = mTransport;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFidesmoToken() {
|
public boolean isFidesmoToken() {
|
||||||
if (isConnected()) { // Check if we can still talk to the card
|
if (isConnected()) { // Check if we can still talk to the card
|
||||||
try {
|
try {
|
||||||
@@ -636,7 +647,6 @@ public class SmartcardDevice {
|
|||||||
return output.substring(0, output.length() - 4);
|
return output.substring(0, output.length() - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NEW METHOD [OK]
|
|
||||||
private String tryPin(int mode, byte[] pin) throws IOException {
|
private String tryPin(int mode, byte[] pin) throws IOException {
|
||||||
// Command APDU for VERIFY command (page 32)
|
// Command APDU for VERIFY command (page 32)
|
||||||
String login =
|
String login =
|
||||||
@@ -709,10 +719,6 @@ public class SmartcardDevice {
|
|||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTransport(Transport mTransport) {
|
|
||||||
this.mTransport = mTransport;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPersistentConnectionAllowed() {
|
public boolean isPersistentConnectionAllowed() {
|
||||||
return mTransport != null && mTransport.isPersistentConnectionAllowed();
|
return mTransport != null && mTransport.isPersistentConnectionAllowed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
|||||||
|
|
||||||
private RequiredInputParcel mRequiredInput;
|
private RequiredInputParcel mRequiredInput;
|
||||||
|
|
||||||
private static final byte[] BLANK_FINGERPRINT = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
private CryptoInputParcel mInputParcel;
|
private CryptoInputParcel mInputParcel;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,10 +224,6 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
|||||||
long subkeyId = buf.getLong();
|
long subkeyId = buf.getLong();
|
||||||
|
|
||||||
CanonicalizedSecretKey key = secretKeyRing.getSecretKey(subkeyId);
|
CanonicalizedSecretKey key = secretKeyRing.getSecretKey(subkeyId);
|
||||||
|
|
||||||
long keyGenerationTimestampMillis = key.getCreationTime().getTime();
|
|
||||||
long keyGenerationTimestamp = keyGenerationTimestampMillis / 1000;
|
|
||||||
byte[] timestampBytes = ByteBuffer.allocate(4).putInt((int) keyGenerationTimestamp).array();
|
|
||||||
byte[] tokenSerialNumber = Arrays.copyOf(mSmartcardDevice.getAid(), 16);
|
byte[] tokenSerialNumber = Arrays.copyOf(mSmartcardDevice.getAid(), 16);
|
||||||
|
|
||||||
Passphrase passphrase;
|
Passphrase passphrase;
|
||||||
@@ -240,33 +234,7 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
|||||||
throw new IOException("Unable to get cached passphrase!");
|
throw new IOException("Unable to get cached passphrase!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.canSign() || key.canCertify()) {
|
mSmartcardDevice.changeKey(key, passphrase);
|
||||||
if (shouldPutKey(key.getFingerprint(), 0)) {
|
|
||||||
mSmartcardDevice.putKey(0xB6, key, passphrase);
|
|
||||||
mSmartcardDevice.putData(0xCE, timestampBytes);
|
|
||||||
mSmartcardDevice.putData(0xC7, key.getFingerprint());
|
|
||||||
} else {
|
|
||||||
throw new IOException("Key slot occupied; token must be reset to put new signature key.");
|
|
||||||
}
|
|
||||||
} else if (key.canEncrypt()) {
|
|
||||||
if (shouldPutKey(key.getFingerprint(), 1)) {
|
|
||||||
mSmartcardDevice.putKey(0xB8, key, passphrase);
|
|
||||||
mSmartcardDevice.putData(0xCF, timestampBytes);
|
|
||||||
mSmartcardDevice.putData(0xC8, key.getFingerprint());
|
|
||||||
} else {
|
|
||||||
throw new IOException("Key slot occupied; token must be reset to put new decryption key.");
|
|
||||||
}
|
|
||||||
} else if (key.canAuthenticate()) {
|
|
||||||
if (shouldPutKey(key.getFingerprint(), 2)) {
|
|
||||||
mSmartcardDevice.putKey(0xA4, key, passphrase);
|
|
||||||
mSmartcardDevice.putData(0xD0, timestampBytes);
|
|
||||||
mSmartcardDevice.putData(0xC9, key.getFingerprint());
|
|
||||||
} else {
|
|
||||||
throw new IOException("Key slot occupied; token must be reset to put new authentication key.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IOException("Inappropriate key flags for Security Token key.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Is this really used anywhere?
|
// TODO: Is this really used anywhere?
|
||||||
mInputParcel.addCryptoData(subkeyBytes, tokenSerialNumber);
|
mInputParcel.addCryptoData(subkeyBytes, tokenSerialNumber);
|
||||||
@@ -357,24 +325,4 @@ public class SecurityTokenOperationActivity extends BaseSecurityTokenNfcActivity
|
|||||||
PassphraseCacheService.clearCachedPassphrase(
|
PassphraseCacheService.clearCachedPassphrase(
|
||||||
this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
|
this, mRequiredInput.getMasterKeyId(), mRequiredInput.getSubKeyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldPutKey(byte[] fingerprint, int idx) throws IOException {
|
|
||||||
byte[] tokenFingerprint = mSmartcardDevice.getMasterKeyFingerprint(idx);
|
|
||||||
|
|
||||||
// Note: special case: This should not happen, but happens with
|
|
||||||
// https://github.com/FluffyKaon/OpenPGP-Card, thus for now assume true
|
|
||||||
if (tokenFingerprint == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slot is empty, or contains this key already. PUT KEY operation is safe
|
|
||||||
if (Arrays.equals(tokenFingerprint, BLANK_FINGERPRINT) ||
|
|
||||||
Arrays.equals(tokenFingerprint, fingerprint)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slot already contains a different key; don't overwrite it.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user