Commit fc423e41 authored by Josh Ji's avatar Josh Ji

clientPin_getPinRetries, clientPin_getKeyAgreement, clientPin_setPin

parent 8cfdaad1
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java/com/josh/vku2f/CTAP2.java" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -275,6 +275,7 @@ public class AuthenticatorMakeCredential { ...@@ -275,6 +275,7 @@ public class AuthenticatorMakeCredential {
// Extensions // Extensions
// We don't support any yet // We don't support any yet
// So check it's a map and skip // So check it's a map and skip
// TODO implement prlab extensions
if(decoder.getMajorType() != CBORBase.TYPE_MAP) { if(decoder.getMajorType() != CBORBase.TYPE_MAP) {
UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
break; break;
......
...@@ -87,7 +87,7 @@ public abstract class CBORBase { ...@@ -87,7 +87,7 @@ public abstract class CBORBase {
/** /**
* Initializes the encoder/decoder without buffer (use the APDU buffer instead). * Initializes the encoder/decoder without buffer (use the APDU buffer instead).
* *
* @param offset Offset in APDU buffer where content should be read * @ param offset Offset in APDU buffer where content should be read
* @param length Length in the APDU buffer * @param length Length in the APDU buffer
*/ */
final public void init(short off, short length) { final public void init(short off, short length) {
...@@ -98,7 +98,7 @@ public abstract class CBORBase { ...@@ -98,7 +98,7 @@ public abstract class CBORBase {
/** /**
* Initializes with a given array and the given offset. * Initializes with a given array and the given offset.
* @param buffer Buffer with CBOR content * @param buffer Buffer with CBOR content
* @param offset Offset in buffer where content should be read/written * @ param offset Offset in buffer where content should be read/written
*/ */
final public void init(byte[] buffer, short off, short length) { final public void init(byte[] buffer, short off, short length) {
if (buffer != APDU.getCurrentAPDUBuffer()) { // do not store the APDU buffer if (buffer != APDU.getCurrentAPDUBuffer()) { // do not store the APDU buffer
......
...@@ -58,10 +58,11 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -58,10 +58,11 @@ public class CTAP2 extends Applet implements ExtendedLength {
private StoredCredential[] assertionCredentials; private StoredCredential[] assertionCredentials;
private final ClientPINCommand clientPINCommand; private final ClientPINCommand clientPINCommand;
private boolean isClientPinSet = false;
private final byte MAX_PIN_RETRIES = (byte) 0x08; private final byte MAX_PIN_RETRIES = (byte) 0x08;
private final byte MAX_UV_RETRIES = (byte) 0x08; private final byte MAX_UV_RETRIES = (byte) 0x08;
private byte pinRetries; private byte pinRetries = MAX_PIN_RETRIES;
private byte uvRetries; private byte uvRetries = MAX_UV_RETRIES;
// private final KeyPair ecDhKeyPair; // private final KeyPair ecDhKeyPair;
// private final boolean[] ecDhSet; // private final boolean[] ecDhSet;
private PinUvAuthProtocolOne pinUvAuthProtocolOne; private PinUvAuthProtocolOne pinUvAuthProtocolOne;
...@@ -131,13 +132,15 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -131,13 +132,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
chainRam = JCSystem.makeTransientShortArray((short) 4, JCSystem.CLEAR_ON_DESELECT); chainRam = JCSystem.makeTransientShortArray((short) 4, JCSystem.CLEAR_ON_DESELECT);
outChainRam = JCSystem.makeTransientShortArray((short) 4, JCSystem.CLEAR_ON_DESELECT); outChainRam = JCSystem.makeTransientShortArray((short) 4, JCSystem.CLEAR_ON_DESELECT);
isOutChaining = JCSystem.makeTransientBooleanArray((short) 2, JCSystem.CLEAR_ON_DESELECT); isOutChaining = JCSystem.makeTransientBooleanArray((short) 2, JCSystem.CLEAR_ON_DESELECT);
ECPublicKey ecDhPub = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PUBLIC, // ECPublicKey ecDhPub = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PUBLIC,
JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false); // JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false);
ECPrivateKey ecDhPriv = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PRIVATE, // ECPrivateKey ecDhPriv = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.ALG_TYPE_EC_FP_PRIVATE,
JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false); // JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false);
clientPINCommand = new ClientPINCommand(); clientPINCommand = new ClientPINCommand();
// ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv); // ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv);
// ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET); // ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET);
pinUvAuthProtocolOne = new PinUvAuthProtocolOne();
pinUvAuthProtocolOne.initialize();
idSecret = new IDSecret(); idSecret = new IDSecret();
} }
...@@ -437,13 +440,14 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -437,13 +440,14 @@ public class CTAP2 extends Applet implements ExtendedLength {
} }
/** /**
* * dump secrets
*/ */
private void dumpIDSecret(APDU apdu){ private void dumpIDSecret(APDU apdu){
tempVars[0] = idSecret.dump(dataBuffer, cborEncoder); tempVars[0] = idSecret.dump(dataBuffer, cborEncoder);
apdu.setOutgoing(); // apdu.setOutgoing();
apdu.setOutgoingLength(tempVars[0]); // apdu.setOutgoingLength(tempVars[0]);
apdu.sendBytesLong(dataBuffer, (short)0, tempVars[0]); // apdu.sendBytesLong(dataBuffer, (short)0, tempVars[0]);
sendLongChaining(apdu, tempVars[0]);
} }
/** /**
...@@ -527,27 +531,54 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -527,27 +531,54 @@ public class CTAP2 extends Applet implements ExtendedLength {
tempVars[0] = cborEncoder.startMap((short) 3); // current offset tempVars[0] = cborEncoder.startMap((short) 3); // current offset
// Attestation stuff // Attestation stuff
// Attestation statement format : 0x01
cborEncoder.writeRawByte((byte) 0x01); cborEncoder.writeRawByte((byte) 0x01);
cborEncoder.encodeTextString(Utf8Strings.UTF8_PACKED, (short) 0, (short) 6); cborEncoder.encodeTextString(Utf8Strings.UTF8_PACKED, (short) 0, (short) 6);
// Put the authdata identifier there // Put the authenticatorData identifier(0x02) there
// Authenticator Data : 0x02
cborEncoder.writeRawByte((byte) 0x02); cborEncoder.writeRawByte((byte) 0x02);
// Allocate some space for the byte string // Allocate some space for the byte string
tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen())); /**
* add extensions byte string length
*/
// TODO fix the bug on extension byte string
// tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() + idSecret.getExtensionsLength() ));
// tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() + Utf8Strings.UTF8_PRLab.length ));
tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen() ));
/**
* end
*/
// Stash where it begins // Stash where it begins
tempVars[7] = tempVars[0]; tempVars[7] = tempVars[0];
// Create the SHA256 hash of the RP ID // Create the SHA256 hash of the RP ID
tempCredential.rpEntity.getRp(scratch, (short) 0); tempCredential.rpEntity.getRp(scratch, (short) 0);
tempVars[0] += sha256MessageDigest.doFinal(scratch, (short) 0, tempCredential.rpEntity.getRpLen(), dataBuffer, tempVars[0]); tempVars[0] += sha256MessageDigest.doFinal(scratch, (short) 0, tempCredential.rpEntity.getRpLen(), dataBuffer, tempVars[0]);
// Set flags - User presence, user verified, attestation present // Set flags - User presence, user verified, attestation present
dataBuffer[tempVars[0]++] = (byte) 0x45; dataBuffer[tempVars[0]++] = (byte) 0x45;
// Set the signature counter // Set the signature counter
tempVars[0] += tempCredential.readCounter(dataBuffer, tempVars[0]); tempVars[0] += tempCredential.readCounter(dataBuffer, tempVars[0]);
// Read the credential details in // Read the credential details in
// Just note down where this starts for future ref // Just note down where this starts for future ref
tempVars[0] += tempCredential.getAttestedData(dataBuffer, tempVars[0]); tempVars[0] += tempCredential.getAttestedData(dataBuffer, tempVars[0]);
// Generate and then attach the attestation /**
* put extensions here
*/
// TODO fix the bug on this
// tempVars[0] += idSecret.getExtensionsByteString(dataBuffer, tempVars[0]);
// Util.arrayCopy(Utf8Strings.UTF8_PRLab, (short)0, dataBuffer, tempVars[0], (short)Utf8Strings.UTF8_PRLab.length);
/**
* end extensions
*/
// Generate and then attach the attestation.
// Attestation Statement : 0x03
cborEncoder.writeRawByte((byte) 0x03); cborEncoder.writeRawByte((byte) 0x03);
// Start to build into the cbor array manually, to avoid arrayCopy // Start to build into the cbor array manually, to avoid arrayCopy
...@@ -591,6 +622,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -591,6 +622,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
// cborEncoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length); // cborEncoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short)0, (short)idSecret.encryptedCx.length); cborEncoder.encodeByteString(idSecret.encryptedCx, (short)0, (short)idSecret.encryptedCx.length);
/** /**
* end extension * end extension
*/ */
...@@ -699,13 +731,14 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -699,13 +731,14 @@ public class CTAP2 extends Applet implements ExtendedLength {
switch(clientPINCommand.getSubCommandCode()){ switch(clientPINCommand.getSubCommandCode()){
case SUBCOMMAND_GET_PIN_RETRIES: case SUBCOMMAND_GET_PIN_RETRIES:
dataBuffer[0] = 0x00; dataBuffer[0] = 0x00; // 0x00 : response success code
cborEncoder.init(dataBuffer, (short)1, (short)(1199)); cborEncoder.init(dataBuffer, (short)1, (short)(1199));
cborEncoder.startMap(ClientPINResponse.PIN_RETRIES); cborEncoder.startMap((short)1);
cborEncoder.encodeUInt8(ClientPINResponse.PIN_RETRIES);
cborEncoder.encodeUInt8(pinRetries); cborEncoder.encodeUInt8(pinRetries);
break; break;
case SUBCOMMAND_GET_KEY_AGREEMENT: case SUBCOMMAND_GET_KEY_AGREEMENT:
dataBuffer[0] = 0x00; dataBuffer[0] = 0x00; // 0x00 : response success code
cborEncoder.init(dataBuffer, (short) 1, (short) 1199); cborEncoder.init(dataBuffer, (short) 1, (short) 1199);
// Start a map // Start a map
cborEncoder.startMap((short) 1); cborEncoder.startMap((short) 1);
...@@ -720,7 +753,8 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -720,7 +753,8 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Alg tag // Alg tag
cborEncoder.encodeUInt8((byte) 0x03); cborEncoder.encodeUInt8((byte) 0x03);
// Alg value - ES256 (-7, 6 in negative format) // Alg value - ES256 (-7, 6 in negative format)
cborEncoder.encodeNegativeUInt8((byte) 0x06); // Alg value - ECDH (-25, 24 in negative format)
cborEncoder.encodeNegativeUInt8((byte) 0x18);
// Crv tag - negative // Crv tag - negative
cborEncoder.encodeNegativeUInt8((byte) 0x00); cborEncoder.encodeNegativeUInt8((byte) 0x00);
// Crv value - P-256 // Crv value - P-256
...@@ -728,13 +762,26 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -728,13 +762,26 @@ public class CTAP2 extends Applet implements ExtendedLength {
// X-coord tag // X-coord tag
cborEncoder.encodeNegativeUInt8((byte) 0x01); cborEncoder.encodeNegativeUInt8((byte) 0x01);
// X-coord value // X-coord value
cborEncoder.encodeByteString(pinUvAuthProtocolOne.getPublicKey(), (short) 1, (short) 32); cborEncoder.encodeByteString(pinUvAuthProtocolOne.getPublicKey(), (short) 1, (short) 32); // the first byte is 0x04, it means the key is uncompressed
// Y-coord tag // Y-coord tag
cborEncoder.encodeNegativeUInt8((byte) 0x02); cborEncoder.encodeNegativeUInt8((byte) 0x02);
// Y-coord value // Y-coord value
cborEncoder.encodeByteString(pinUvAuthProtocolOne.getPublicKey(), (short) 33, (short) 32); cborEncoder.encodeByteString(pinUvAuthProtocolOne.getPublicKey(), (short) 33, (short) 32);
// That's it
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
break; break;
case SUBCOMMAND_SET_PIN: case SUBCOMMAND_SET_PIN:
// idSecret.writeTempBuffer(pinUvAuthProtocolOne.ecdh(clientPINCommand.getKeyAgreement()));
idSecret.writeTempBuffer(
pinUvAuthProtocolOne.decrypt(
pinUvAuthProtocolOne.ecdh(
clientPINCommand.getKeyAgreement()),
clientPINCommand.getNewPinEnc()
)
);
isClientPinSet = true;
fidoInfo = null;
JCSystem.requestObjectDeletion();
break; break;
case SUBCOMMAND_CHANGE_PIN: case SUBCOMMAND_CHANGE_PIN:
break; break;
...@@ -747,8 +794,6 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -747,8 +794,6 @@ public class CTAP2 extends Applet implements ExtendedLength {
case SUBCOMMAND_GET_PIN_UV_AUTH_TOKEN_PIN: case SUBCOMMAND_GET_PIN_UV_AUTH_TOKEN_PIN:
break; break;
} }
// That's it
sendLongChaining(apdu, cborEncoder.getCurrentOffset());
} catch (UserException e) { } catch (UserException e) {
returnError(apdu, e.getReason()); returnError(apdu, e.getReason());
} }
...@@ -899,32 +944,43 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -899,32 +944,43 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Create the authGetInfo - 0x00 is success // Create the authGetInfo - 0x00 is success
dataBuffer[0] = 0x00; dataBuffer[0] = 0x00;
cborEncoder.init(dataBuffer, (short) 1, (short) 1199); cborEncoder.init(dataBuffer, (short) 1, (short) 1199);
cborEncoder.startMap((short) 4); cborEncoder.startMap((short) 6);
// 0x01, versions // 0x01, versions
cborEncoder.encodeUInt8((byte) 0x01); cborEncoder.encodeUInt8((byte) 0x01);
// Value is an array of strings // Value is an array of strings
cborEncoder.startArray((short) 1); cborEncoder.startArray((short) 1);
// Type 1, FIDO2 // Type 1, FIDO2
cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO2, (short) 0, (short) 8); cborEncoder.encodeTextString(Utf8Strings.UTF8_FIDO2, (short) 0, (short) 8);
// AAGUID, 0x03 // 0x02, Extensions
cborEncoder.encodeUInt8((byte) 0x02);
cborEncoder.startArray((short) 2);
cborEncoder.encodeTextString(Utf8Strings.UTF8_PRLab, (short)0, (short)Utf8Strings.UTF8_PRLab.length);
cborEncoder.encodeTextString(Utf8Strings.UTF8_credProtect, (short)0, (short)Utf8Strings.UTF8_credProtect.length);
// 0x03, AAGUID,
cborEncoder.encodeUInt8((byte) 0x03); cborEncoder.encodeUInt8((byte) 0x03);
cborEncoder.encodeByteString(aaguid, (short) 0, (short) 16); cborEncoder.encodeByteString(aaguid, (short) 0, (short) 16);
// Options, 0x04 // 0x04, Options,
cborEncoder.encodeUInt8((byte) 0x04); cborEncoder.encodeUInt8((byte) 0x04);
// Map of 3 // Map of 3
cborEncoder.startMap((short) 3); cborEncoder.startMap((short) 4);
// Rk // Rk
cborEncoder.encodeTextString(Utf8Strings.UTF8_RK, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_RK, (short) 0, (short)Utf8Strings.UTF8_RK.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// UP // UP
cborEncoder.encodeTextString(Utf8Strings.UTF8_UP, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_UP, (short) 0, (short)Utf8Strings.UTF8_UP.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// clientPin
cborEncoder.encodeTextString(Utf8Strings.UTF8_CLIENT_PIN, (short) 0, (short)Utf8Strings.UTF8_CLIENT_PIN.length);
cborEncoder.encodeBoolean(isClientPinSet);
// UV // UV
cborEncoder.encodeTextString(Utf8Strings.UTF8_UV, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_UV, (short) 0, (short)Utf8Strings.UTF8_UV.length);
cborEncoder.encodeBoolean(true); cborEncoder.encodeBoolean(true);
// Max msg size, 0x05 // Max msg size, 0x05
cborEncoder.encodeUInt8((byte) 0x05); cborEncoder.encodeUInt8((byte) 0x05);
cborEncoder.encodeUInt16((short) 1200); cborEncoder.encodeUInt16((short) 1200);
// minPINLength, 0x0D
cborEncoder.encodeUInt8((byte) 0x0D);
cborEncoder.encodeUInt8((byte) 0x04);
// Done // Done
JCSystem.beginTransaction(); JCSystem.beginTransaction();
fidoInfo = new byte[cborEncoder.getCurrentOffset()]; fidoInfo = new byte[cborEncoder.getCurrentOffset()];
......
package com.josh.vku2f; package com.josh.vku2f;
import javacard.framework.JCSystem;
import javacard.framework.UserException; import javacard.framework.UserException;
import javacard.framework.Util;
public class ClientPINCommand { public class ClientPINCommand {
public static final byte PARAMETER_PROTOCOL = 0x01; public static final byte PARAMETER_PROTOCOL = 0x01;
...@@ -14,19 +16,22 @@ public class ClientPINCommand { ...@@ -14,19 +16,22 @@ public class ClientPINCommand {
private byte protocol; // unsigned int private byte protocol; // unsigned int
private byte subCommandCode; // unsigned int private byte subCommandCode; // unsigned int
private byte[] keyAgreement; // COSE object private byte[] keyAgreement = new byte[65]; // COSE object or 0x04||x||y
private byte[] pinUvAuthParam; // byte string private byte[] x = new byte[32]; // x-coordinate
private byte[] newPinEnc; // byte string private byte[] y = new byte[32]; // y-coordinate
private byte[] pinHashEnc; // byte string private byte[] pinUvAuthParam = new byte[64]; // byte string
private byte[] newPinEnc = new byte[64]; // byte string
private byte[] pinHashEnc = new byte[32]; // byte string
private byte permissions; // unsigned int private byte permissions; // unsigned int
private byte[] rpId; // text string private byte[] rpId = new byte[64]; // text string
byte[] scratch = JCSystem.makeTransientByteArray((short)64, JCSystem.CLEAR_ON_RESET);
public void decodeCommand(CBORDecoder cborDecoder) throws UserException { public void decodeCommand(CBORDecoder cborDecoder) throws UserException {
short commandLength = cborDecoder.readMajorType(CBORBase.TYPE_MAP); short commandLength = cborDecoder.readMajorType(CBORBase.TYPE_MAP);
do {
byte commandKey = cborDecoder.readInt8(); while(commandLength > (short)0) {
short valueLength; short valueLength;
switch (commandKey) { switch (cborDecoder.readInt8()) {
case PARAMETER_PROTOCOL: case PARAMETER_PROTOCOL:
protocol = cborDecoder.readInt8(); protocol = cborDecoder.readInt8();
break; break;
...@@ -34,36 +39,50 @@ public class ClientPINCommand { ...@@ -34,36 +39,50 @@ public class ClientPINCommand {
subCommandCode = cborDecoder.readInt8(); subCommandCode = cborDecoder.readInt8();
break; break;
case PARAMETER_KEY_AGREEMENT: case PARAMETER_KEY_AGREEMENT:
valueLength = cborDecoder.readLength(); cborDecoder.readMajorType(CBORBase.TYPE_MAP);
keyAgreement = new byte[valueLength];
cborDecoder.readRawByteArray(keyAgreement, (short) 0, valueLength); cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
cborDecoder.skipEntry();
// cborDecoder.skipEntry();
cborDecoder.readByteString(x, (short)0);
cborDecoder.skipEntry();
// cborDecoder.skipEntry();
cborDecoder.readByteString(y, (short)0);
break; break;
case PARAMETER_PIN_UV_AUTH_PARAM: case PARAMETER_PIN_UV_AUTH_PARAM:
valueLength = cborDecoder.readLength(); // cborDecoder.readByteString(pinUvAuthParam, (short) 0);
pinUvAuthParam = new byte[valueLength]; cborDecoder.skipEntry();
cborDecoder.readRawByteArray(pinUvAuthParam, (short) 0, valueLength);
break; break;
case PARAMETER_NEW_PIN_ENC: case PARAMETER_NEW_PIN_ENC:
valueLength = cborDecoder.readLength(); cborDecoder.readByteString(newPinEnc, (short) 0);
newPinEnc = new byte[valueLength];
cborDecoder.readRawByteArray(newPinEnc, (short) 0, valueLength);
break; break;
case PARAMETER_PIN_HASH_ENC: case PARAMETER_PIN_HASH_ENC:
valueLength = cborDecoder.readLength(); // cborDecoder.readByteString(pinHashEnc, (short) 0);
pinHashEnc = new byte[valueLength]; cborDecoder.skipEntry();
cborDecoder.readRawByteArray(pinHashEnc, (short) 0, valueLength);
break; break;
case PARAMETER_PERMISSIONS: case PARAMETER_PERMISSIONS:
permissions = cborDecoder.readInt8(); // permissions = cborDecoder.readInt8();
cborDecoder.skipEntry();
break; break;
case PARAMETER_RP_ID: case PARAMETER_RP_ID:
valueLength = cborDecoder.readLength(); // cborDecoder.readByteString(rpId, (short) 0);
rpId = new byte[valueLength]; cborDecoder.skipEntry();
cborDecoder.readRawByteArray(rpId, (short) 0, valueLength);
break; break;
} }
commandLength--; commandLength--;
} while (commandLength >= 1); }
} }
public byte getProtocol() { public byte getProtocol() {
...@@ -75,6 +94,9 @@ public class ClientPINCommand { ...@@ -75,6 +94,9 @@ public class ClientPINCommand {
} }
public byte[] getKeyAgreement() { public byte[] getKeyAgreement() {
keyAgreement[0] = 0x04;
Util.arrayCopy(x, (short)0, keyAgreement, (short)1, (short)x.length);
Util.arrayCopy(y, (short)0, keyAgreement, (short)33, (short)y.length);
return keyAgreement; return keyAgreement;
} }
......
...@@ -30,6 +30,9 @@ public class IDSecret { ...@@ -30,6 +30,9 @@ public class IDSecret {
private MessageDigest sha256; private MessageDigest sha256;
private byte[] scratch; private byte[] scratch;
private final short SCRATCH_LENGTH = (short)128 ; private final short SCRATCH_LENGTH = (short)128 ;
private CBOREncoder encoder = new CBOREncoder();
public final byte[] tempBuffer = new byte[100];
public short tempBufferLength = (short)0;
public IDSecret(){ public IDSecret(){
IDx = new DomString(Utf8Strings.UTF8_NULL, (short)Utf8Strings.UTF8_NULL.length); IDx = new DomString(Utf8Strings.UTF8_NULL, (short)Utf8Strings.UTF8_NULL.length);
...@@ -45,6 +48,7 @@ public class IDSecret { ...@@ -45,6 +48,7 @@ public class IDSecret {
Random.getInstance().nextBytes(Cx, (short)0, (short)Cx.length); Random.getInstance().nextBytes(Cx, (short)0, (short)Cx.length);
Util.arrayFill(encryptedCx, (short)0, (byte)encryptedCx.length, (byte)0); Util.arrayFill(encryptedCx, (short)0, (byte)encryptedCx.length, (byte)0);
Util.arrayFill(hmac, (short)0, (byte)hmac.length, (byte)0); Util.arrayFill(hmac, (short)0, (byte)hmac.length, (byte)0);
Util.arrayFill(tempBuffer, (short)0, (byte)tempBuffer.length, (byte)0);
aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false); aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
...@@ -93,23 +97,81 @@ public class IDSecret { ...@@ -93,23 +97,81 @@ public class IDSecret {
Util.arrayCopy(outputBuffer, (short)0, hmac, (short)0, (short)32 ); Util.arrayCopy(outputBuffer, (short)0, hmac, (short)0, (short)32 );
} }
private short generateExtensions(){
// 69byte <- EXTENSIONS:10 + PRLAB:5 + HMAC:4 + hmac:32 + CX:2 + cx:16
encoder.init(tempBuffer, (short)0, (short) tempBuffer.length);
encoder.startMap((short)1);
encoder.encodeTextString(Utf8Strings.UTF8_PRLab, (short)0, (short)Utf8Strings.UTF8_PRLab.length);
encoder.startMap((short)2);
encoder.encodeTextString(Utf8Strings.UTF8_HMAC, (short)0, (short)Utf8Strings.UTF8_HMAC.length);
encoder.encodeByteString(hmac, (short)0, (short)hmac.length );
encoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
return encoder.getCurrentOffset();
}
public short getExtensionsLength(){
tempBufferLength = generateExtensions();
return tempBufferLength;
}
public short getExtensionsByteString(byte[] outputBuffer, short outputOffset){
Util.arrayCopy(tempBuffer, (short)0, outputBuffer, outputOffset, tempBufferLength);
return tempBufferLength;
}
public void writeTempBuffer(byte[] inputBuffer){
if((short)inputBuffer.length > (short)tempBuffer.length){
tempBuffer[0] = 'T'; // too
tempBuffer[1] = 'L'; // long
Util.setShort(tempBuffer, (short)2, (short)inputBuffer.length); // input length
return;
}
Util.arrayCopy(inputBuffer, (short)0, tempBuffer, (short)0, (short)inputBuffer.length);
}
/** /**
* put IDSecret data with CBOR form in dataBuffer * put IDSecret data with CBOR form in dataBuffer
* return data length * return data length
*/ */
public short dump(byte[] dataBuffer, CBOREncoder encoder){ public short dump(byte[] dataBuffer, CBOREncoder encoder){
encoder.init(dataBuffer, (short)0, (short)1200); encoder.init(dataBuffer, (short)0, (short)1200);
encoder.startArray((short)10); encoder.startMap((short)1);
encoder.encodeTextString(IDx.str, (short)0, IDx.len);
encoder.encodeByteString(Rx, (short)0, (short)Rx.length); // encoder.encodeTextString(Utf8Strings.UTF8_IDx, (short)0, (short)Utf8Strings.UTF8_IDx.length);
encoder.encodeByteString(Rp, (short)0, (short)Rp.length); // encoder.encodeTextString(IDx.str, (short)0, IDx.len);
encoder.encodeByteString(getRxRp(), (short)0, (short)RxRp.length); //
encoder.encodeByteString(PuKp, (short)0, (short)PuKp.length); // encoder.encodeTextString(Utf8Strings.UTF8_Rx, (short)0, (short)Utf8Strings.UTF8_Rx.length);
encoder.encodeByteString(sharedSecret, (short)0, (short)sharedSecret.length); // encoder.encodeByteString(Rx, (short)0, (short)Rx.length);
encoder.encodeByteString(hashedSharedSecret, (short)0 , (short) hashedSharedSecret.length); //
encoder.encodeByteString(Cx, (short)0, (short)Cx.length); // encoder.encodeTextString(Utf8Strings.UTF8_Rp, (short)0, (short)Utf8Strings.UTF8_Rp.length);
encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length); // encoder.encodeByteString(Rp, (short)0, (short)Rp.length);
encoder.encodeByteString(hmac, (short)0, (short)hmac.length ); //
// encoder.encodeTextString(Utf8Strings.UTF8_RxRp, (short)0, (short)Utf8Strings.UTF8_RxRp.length);
// encoder.encodeByteString(getRxRp(), (short)0, (short)RxRp.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_PuKp, (short)0, (short)Utf8Strings.UTF8_PuKp.length);
// encoder.encodeByteString(PuKp, (short)0, (short)PuKp.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_SHARED_SECRET, (short)0, (short)Utf8Strings.UTF8_SHARED_SECRET.length);
// encoder.encodeByteString(sharedSecret, (short)0, (short)sharedSecret.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_HASHED_SHARED_SECRET, (short)0, (short)Utf8Strings.UTF8_HASHED_SHARED_SECRET.length);
// encoder.encodeByteString(hashedSharedSecret, (short)0 , (short) hashedSharedSecret.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_Cx, (short)0, (short)Utf8Strings.UTF8_Cx.length);
// encoder.encodeByteString(Cx, (short)0, (short)Cx.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_ENCRYPTED_CX, (short)0, (short)Utf8Strings.UTF8_ENCRYPTED_CX.length);
// encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
//
// encoder.encodeTextString(Utf8Strings.UTF8_HMAC, (short)0, (short)Utf8Strings.UTF8_HMAC.length);
// encoder.encodeByteString(hmac, (short)0, (short)hmac.length );
// tempBufferLength = generateExtensions();
encoder.encodeTextString(Utf8Strings.UTF8_TEMP, (short)0, (short)Utf8Strings.UTF8_TEMP.length);
encoder.encodeByteString(tempBuffer, (short)0, (short)tempBuffer.length);
return encoder.getCurrentOffset(); return encoder.getCurrentOffset();
} }
......
...@@ -9,6 +9,6 @@ public abstract class PinUvAuthProtocol { ...@@ -9,6 +9,6 @@ public abstract class PinUvAuthProtocol {
public abstract void resetPinUvAuthToken(); public abstract void resetPinUvAuthToken();
public abstract byte[] getPublicKey(); public abstract byte[] getPublicKey();
public abstract byte[] decapsulate(COSEKey peerCoseKey); public abstract byte[] decapsulate(COSEKey peerCoseKey);
public abstract void decrypt(byte[] sharedSecret, byte[] cipherText); public abstract byte[] decrypt(byte[] sharedSecret, byte[] cipherText);
public abstract void verify(byte[] key, byte[] message, byte[] signature); public abstract void verify(byte[] key, byte[] message, byte[] signature);
} }
...@@ -2,11 +2,17 @@ package com.josh.vku2f; ...@@ -2,11 +2,17 @@ package com.josh.vku2f;
import javacard.framework.JCSystem; import javacard.framework.JCSystem;
import javacard.security.*; import javacard.security.*;
import javacardx.crypto.Cipher;
public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
private KeyPair ecDhKeyPair; private KeyPair ecDhKeyPair;
private boolean[] ecDhSet; private boolean[] ecDhSet;
private AESKey aesKey;
private Cipher aesEncrypt;
private Cipher aesDecrypt;
private MessageDigest sha256;
private final byte[] IV_ZERO_AES = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@Override @Override
public void initialize() { public void initialize() {
...@@ -16,6 +22,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -16,6 +22,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false); JCSystem.MEMORY_TYPE_TRANSIENT_RESET, KeyBuilder.LENGTH_EC_FP_256, false);
ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv); ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv);
ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET); ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET);
aesKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_256, false);
aesEncrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
aesDecrypt = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
} }
@Override @Override
...@@ -65,8 +78,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -65,8 +78,13 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
} }
@Override @Override
public void decrypt(byte[] sharedSecret, byte[] cipherText) { public byte[] decrypt(byte[] key, byte[] cipherText) {
byte[] plainText = new byte[64];
aesKey.setKey(key, (short)0);
aesDecrypt.init(aesKey, Cipher.MODE_DECRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
aesDecrypt.update(cipherText, (short)0, (short)32, plainText, (short)0);
aesDecrypt.doFinal(cipherText, (short)32, (short)32, plainText, (short)32);
return plainText;
} }
public byte[] authenticate(byte[] key, byte[] message){ public byte[] authenticate(byte[] key, byte[] message){
...@@ -77,10 +95,17 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{ ...@@ -77,10 +95,17 @@ public class PinUvAuthProtocolOne extends PinUvAuthProtocol{
public void verify(byte[] key, byte[] message, byte[] signature) { public void verify(byte[] key, byte[] message, byte[] signature) {
} }
private byte[] ecdh(COSEKey peerCoseKey){
return null; public byte[] ecdh(byte[] peerKey){
byte[] sharedKey = new byte[65];
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN_XY, false);
keyAgreement.init(ecDhKeyPair.getPrivate());
keyAgreement.generateSecret(peerKey, (short)0, (short)65, sharedKey, (short)0);
return kdf(sharedKey, (short)1);
} }
private byte[] kdf(byte[] Z){ public byte[] kdf(byte[] Z, short offset){
return null; byte[] hashed = new byte[32];
sha256.doFinal(Z, offset, (short)32, hashed, (short)0);
return hashed;
} }
} }
...@@ -66,8 +66,9 @@ public class StoredES256Credential extends StoredCredential { ...@@ -66,8 +66,9 @@ public class StoredES256Credential extends StoredCredential {
} }
((ECPublicKey) keyPair.getPublic()).getW(w, (short) 0); ((ECPublicKey) keyPair.getPublic()).getW(w, (short) 0);
// Form the common params // Form the common params (AAGUID||key handle Length||key handle)
doAttestationCommon(buf, off); doAttestationCommon(buf, off);
enc.init(buf, (short) (off + 34), (short) 1000); enc.init(buf, (short) (off + 34), (short) 1000);
enc.startMap((short) 5); enc.startMap((short) 5);
// We had to kinda hack the map labels - this is kty // We had to kinda hack the map labels - this is kty
......
...@@ -28,6 +28,7 @@ public class Utf8Strings { ...@@ -28,6 +28,7 @@ public class Utf8Strings {
public static final byte[] UTF8_ALG = {'a', 'l', 'g'}; public static final byte[] UTF8_ALG = {'a', 'l', 'g'};
public static final byte[] UTF8_UV = {'u', 'v'}; public static final byte[] UTF8_UV = {'u', 'v'};
public static final byte[] UTF8_RK = {'r', 'k'}; public static final byte[] UTF8_RK = {'r', 'k'};
public static final byte[] UTF8_CLIENT_PIN = {'c', 'l', 'i', 'e', 'n', 't', 'P', 'i', 'n'};
public static final byte[] UTF8_TYPE = {'t', 'y', 'p', 'e'}; public static final byte[] UTF8_TYPE = {'t', 'y', 'p', 'e'};
public static final byte[] UTF8_PACKED = {'p', 'a', 'c', 'k', 'e', 'd'}; public static final byte[] UTF8_PACKED = {'p', 'a', 'c', 'k', 'e', 'd'};
public static final byte[] UTF8_SIG = {'s', 'i', 'g'}; public static final byte[] UTF8_SIG = {'s', 'i', 'g'};
...@@ -37,7 +38,18 @@ public class Utf8Strings { ...@@ -37,7 +38,18 @@ public class Utf8Strings {
public static final byte[] UTF8_ICON = {'i', 'c', 'o', 'n'}; public static final byte[] UTF8_ICON = {'i', 'c', 'o', 'n'};
public static final byte[] UTF8_NULL = {'n', 'u', 'l', 'l'}; public static final byte[] UTF8_NULL = {'n', 'u', 'l', 'l'};
public static final byte[] UTF8_EXTENSIONS = {'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's'}; public static final byte[] UTF8_EXTENSIONS = {'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's'};
public static final byte[] UTF8_PRLab = {'P', 'R', 'L', 'a', 'b'};
public static final byte[] UTF8_credProtect = {'c','r','e','d','P','r','o','t','e','c','t'};
public static final byte[] UTF8_HMAC = {'H', 'M', 'A', 'C'}; public static final byte[] UTF8_HMAC = {'H', 'M', 'A', 'C'};
public static final byte[] UTF8_Cx = {'C', 'x'}; public static final byte[] UTF8_Cx = {'C', 'x'};
public static final byte[] UTF8_IDx = {'I', 'D', 'x'};
public static final byte[] UTF8_Rx = {'R', 'x'};
public static final byte[] UTF8_Rp = {'R', 'p'};
public static final byte[] UTF8_RxRp = {'R', 'x', 'R', 'p'};
public static final byte[] UTF8_PuKp = {'P', 'u', 'K', 'p'};
public static final byte[] UTF8_SHARED_SECRET = {'S', 'h', 'a', 'r', 'e', 'd', 'S', 'e', 'c', 'r', 'e', 't'};
public static final byte[] UTF8_HASHED_SHARED_SECRET = {'H', 'a', 's', 'h', 'e', 'd', 'S', 'h', 'a', 'r', 'e', 'd', 'S', 'e', 'c', 'r', 'e', 't'};
public static final byte[] UTF8_ENCRYPTED_CX = {'E', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', 'C', 'x', };
public static final byte[] UTF8_TEMP = {'T', 'E', 'M', 'P'};
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment