Commit 4fe40fff authored by Josh Ji's avatar Josh Ji

implement IDSecret.java, dumpIDSecret(), getPuKxRx(), getPuKxCx()

parent 0bd67b09
......@@ -65,6 +65,22 @@ javacard{
name "getCertificate"
apdu "80100000014A"
}
script{
name "getFreeSpace"
apdu "80CAFF21"
}
script{
name "dumpIDSecret"
apdu "80100000015F"
}
script{
name "getPuKxRx"
apdu "80100000065050524C4142"
}
script{
name "getCx"
apdu "801000000151"
}
task{
name "getFidoInfo"
scripts "select applet", "getFidoInfo"
......@@ -85,5 +101,17 @@ javacard{
name 'reset'
scripts 'select applet', 'reset'
}
task{
name 'getFreeSpace'
scripts 'getFreeSpace'
}
task{
name 'dumpIDSecret'
scripts 'select applet', 'dumpIDSecret'
}
task{
name 'getPuKxRx'
scripts 'select applet', 'getPuKxRx'
}
}
}
This diff is collapsed.
......@@ -17,11 +17,7 @@
package com.josh.vku2f;
import javacard.framework.Util;
import javacard.security.ECKey;
import javacard.security.ECPublicKey;
import javacard.security.KeyBuilder;
import javacard.security.KeyPair;
import javacard.security.Signature;
import javacard.security.*;
/**
* Attestation keypair object.
......@@ -88,4 +84,7 @@ public class AttestationKeyPair {
public short getPubkey(byte[] outBuf, short outOff) {
return ((ECPublicKey) kp.getPublic()).getW(outBuf, outOff);
}
public PrivateKey getPrivate(){
return kp.getPrivate();
}
}
......@@ -26,6 +26,7 @@ import javacard.framework.UserException;
import javacard.framework.Util;
import javacard.security.*;
import javacardx.apdu.ExtendedLength;
import static com.josh.vku2f.CTAP2ErrorCode.*;
import static com.josh.vku2f.ClientPINSubCommand.*;
......@@ -40,7 +41,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
private final boolean[] isChaining;
private final boolean[] isOutChaining;
//transient memory, clear on reset
//transient memory, clear on reset(power off)
private final short[] nextAssertion;
private byte[] fidoInfo;
......@@ -87,9 +88,12 @@ public class CTAP2 extends Applet implements ExtendedLength {
public static final byte FIDO2_VENDOR_GET_CREDENTIAL_COUNT = (byte) 0x45;
public static final byte FIDO2_VENDOR_ATTEST_GETCERT = (byte) 0x4A;
//PRLAB
public static final byte PRLAB_GET_PUKX_RX = (byte) 0x50;
public static final byte PRLAB_GET_CX = (byte) 0x51;
//IDSecret
public final IDSecret idSecret;
public static final byte ID_SECRET_GET_PUKX_RX = (byte) 0x50;
public static final byte ID_SECRET_GET_CX = (byte) 0x51;
public static final byte ID_SECRET_GET_PUKX_CX = (byte) 0x52;
public static final byte ID_SECRET_DUMP_ALL = (byte) 0x5F;
// AAGUID - Authenticator Attestation Global Unique Identifier
......@@ -134,6 +138,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
clientPINCommand = new ClientPINCommand();
// ecDhKeyPair = new KeyPair(ecDhPub, ecDhPriv);
// ecDhSet = JCSystem.makeTransientBooleanArray((short) 1, JCSystem.CLEAR_ON_RESET);
idSecret = new IDSecret();
}
......@@ -265,7 +270,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
}
public void handle(APDU apdu) {
private void handle(APDU apdu) {
byte[] buffer = apdu.getBuffer();
tempCredential = null;
authenticatorMakeCredential = null;
......@@ -312,11 +317,18 @@ public class CTAP2 extends Applet implements ExtendedLength {
case FIDO2_VENDOR_GET_CREDENTIAL_COUNT: //0x45
getCredentialCount(apdu);
break;
case PRLAB_GET_PUKX_RX: // 0x50
getPuKxRx(apdu);
case ID_SECRET_GET_PUKX_RX: // 0x50
getPuKxRx(apdu, tempVars[3]);
break;
case ID_SECRET_GET_CX: // 0x51
getCx(apdu, tempVars[3]);
break;
case ID_SECRET_GET_PUKX_CX:
getPuKxCx(apdu, tempVars[3]);
break;
case PRLAB_GET_CX: // 0x51
getCx(apdu);
case ID_SECRET_DUMP_ALL: // 0x5F
// apdu.setOutgoingAndSend((short)0, (short)4); // testing, for break point setting
dumpIDSecret(apdu);
break;
case FIDO2_VENDOR_ATTEST_GETCERT: //0x4a
getCert(apdu);
......@@ -327,7 +339,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
}
public void personalizationComplete(APDU apdu) {
private void personalizationComplete(APDU apdu) {
if (attestationKeyPair.isCertSet() && !personalizeComplete) {
personalizeComplete = true;
returnError(apdu, CTAP1_ERR_SUCCESS);
......@@ -341,7 +353,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
*
* @param apdu apdu buffer
*/
public void getAttestPublic(APDU apdu) {
private void getAttestPublic(APDU apdu) {
if (personalizeComplete) {
returnError(apdu, CTAP1_ERR_INVALID_COMMAND);
return;
......@@ -354,23 +366,79 @@ public class CTAP2 extends Applet implements ExtendedLength {
}
/** get counter's value */
public void getCredentialCount(APDU apdu){
private void getCredentialCount(APDU apdu){
Util.setShort(apdu.getBuffer(), (short)0x00, credentialArray.getCount());
apdu.setOutgoingAndSend((short)0x00, (short)2);
}
/**
* for original framework purpose
*
* input: IDx String
* return: PuKx and Rx in CBOR form
*/
private void getPuKxRx(APDU apdu){
private void getPuKxRx(APDU apdu, short dataLength){
// TODO IDx have to get data from dataBuffer at index 1
idSecret.IDx = new DomString(dataBuffer, dataLength);
cborEncoder.init(dataBuffer, (short) 0, (short)1200);
cborEncoder.startArray((short)2);
cborEncoder.encodeUInt32(idSecret.Rx, (short)0);
tempVars[0] = attestationKeyPair.getPubkey(scratch, (short)0);
cborEncoder.encodeByteString(scratch, (short)0, tempVars[0]);
apdu.setOutgoing();
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short) 0, cborEncoder.getCurrentOffset());
}
/**
* pending
*/
private void getCx(APDU apdu, short dataLength){
}
/**
* for alternative framework purpose
*
* input: IDx , PuKp in CBOR form
* return: PuKx, encryptedCx in CBOR form
*/
private void getCx(APDU apdu){
private void getPuKxCx(APDU apdu, short dataLength){
cborDecoder.init(dataBuffer, (short)1, dataLength);
try{
cborDecoder.readMajorType(CBORBase.TYPE_ARRAY);
short length = cborDecoder.readTextString(scratch, (short)0);
idSecret.IDx = new DomString(scratch, length);
cborDecoder.readByteString(scratch, (short)0);
Util.arrayCopy(scratch, (short)8, idSecret.PuKp, (short)1, (short)64);
}catch(UserException e){
returnError(apdu, e.getReason());
}
KeyAgreement keyAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
keyAgreement.init(attestationKeyPair.getPrivate());
keyAgreement.generateSecret(idSecret.PuKp, (short)0, (short)65, idSecret.sharedSecret, (short)0);
idSecret.initAesKey();
idSecret.encryptCx();// this line will crash this applet
cborEncoder.init(dataBuffer, (short)0, (short)1200);
cborEncoder.startArray((short)2);
short length = attestationKeyPair.getPubkey(scratch, (short)0);
cborEncoder.encodeByteString(scratch, (short)0, length);
cborEncoder.encodeByteString(idSecret.encryptedCx, (short)0, (short)idSecret.encryptedCx.length);
apdu.setOutgoing();
apdu.setOutgoingLength(cborEncoder.getCurrentOffset());
apdu.sendBytesLong(dataBuffer, (short)0, cborEncoder.getCurrentOffset());
}
/**
*
*/
private void dumpIDSecret(APDU apdu){
tempVars[0] = idSecret.dump(dataBuffer, cborEncoder);
apdu.setOutgoing();
apdu.setOutgoingLength(tempVars[0]);
apdu.sendBytesLong(dataBuffer, (short)0, tempVars[0]);
}
/**
......@@ -797,7 +865,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
*
* @param apdu apdu buffer
*/
public void authGetInfo(APDU apdu) {
private void authGetInfo(APDU apdu) {
// Create the authenticator info if not present.
if (fidoInfo == null) {
// Create the authGetInfo - 0x00 is success
......
package com.josh.vku2f;
import javacard.framework.Util;
import javacard.security.AESKey;
import javacard.security.KeyBuilder;
import javacard.security.MessageDigest;
import javacardx.crypto.Cipher;
/**
* Hold some params about the identification binding framework
*/
public class IDSecret {
public DomString IDx;
public final byte[] Rx = new byte[4];
public final byte[] Rp = new byte[4];
private final byte[] RxRp = new byte[4];
public final byte[] PuKp = new byte[65];
public final byte[] sharedSecret = new byte[20];
public final byte[] Cx = new byte[16];
public final byte[] encryptedCx = new byte[16];
public final byte[] aesRawKey = new byte[32];
private AESKey aesKey;
private Cipher aesEncrypt;
private Cipher aesDecrypt;
private final byte[] IV_ZERO_AES = new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private MessageDigest sha256;
public IDSecret(){
IDx = new DomString(Utf8Strings.UTF8_NULL, (short)Utf8Strings.UTF8_NULL.length);
Random.getInstance().nextBytes(Rx, (short)0, (short)Rx.length);
Util.arrayFill(Rp, (short)0, (short)4, (byte)Rp.length);
Util.arrayFill(RxRp, (short)0, (short)4, (byte)RxRp.length);
PuKp[(byte)0] = (byte)0x04;
Util.arrayFill(PuKp, (short)1, (byte)(PuKp.length-1), (byte)0);
Util.arrayFill(sharedSecret, (short)0, (byte)sharedSecret.length, (byte)0);
Random.getInstance().nextBytes(Cx, (short)0, (short)Cx.length);
Util.arrayFill(encryptedCx, (short)0, (byte)encryptedCx.length, (byte)0);
Util.arrayFill(aesRawKey, (short)0, (byte)aesRawKey.length, (byte)0);
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);
}
private byte i = (short)0;
public byte[] getRxRp(){
for(i = (short)0; i < (short)4; i++){
RxRp[i] = (byte) (Rx[i] ^ Rp[i]);
}
return RxRp;
}
public void initAesKey(){
sha256.doFinal(sharedSecret, (short)0, (short)20, aesRawKey, (short)0);
aesKey.setKey(aesRawKey, (short)0);
aesEncrypt.init(aesKey, Cipher.MODE_ENCRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
aesDecrypt.init(aesKey, Cipher.MODE_DECRYPT, IV_ZERO_AES, (short)0, (short)IV_ZERO_AES.length);
}
public void encryptCx(){
aesEncrypt.doFinal(Cx, (short)0, (short)Cx.length, encryptedCx, (short)0);
}
/**
* put IDSecret data with CBOR form in dataBuffer
* return data length
*/
public short dump(byte[] dataBuffer, CBOREncoder encoder){
encoder.init(dataBuffer, (short)0, (short)1200);
encoder.startArray((short)9);
encoder.encodeTextString(IDx.str, (short)0, IDx.len);
encoder.encodeByteString(Rx, (short)0, (short)Rx.length);
encoder.encodeByteString(Rp, (short)0, (short)Rp.length);
encoder.encodeByteString(getRxRp(), (short)0, (short)RxRp.length);
encoder.encodeByteString(PuKp, (short)0, (short)PuKp.length);
encoder.encodeByteString(sharedSecret, (short)0, (short)sharedSecret.length);
encoder.encodeByteString(aesRawKey, (short)0 , (short)aesRawKey.length);
encoder.encodeByteString(Cx, (short)0, (short)Cx.length);
encoder.encodeByteString(encryptedCx, (short)0, (short)encryptedCx.length);
return encoder.getCurrentOffset();
}
}
......@@ -19,15 +19,15 @@ package com.josh.vku2f;
public class Utf8Strings {
public static final byte[] UTF8_UP = {'u', 'p'};
// Representation of "id" in UTF8
public static final byte[] UTF8_ID = {0x69, 0x64};
public static final byte[] UTF8_ID = {'i', 'd'};
// Representation of "name" in UTF8
public static final byte[] UTF8_NAME = {0x6e, 0x61, 0x6d, 0x65};
public static final byte[] UTF8_NAME = {'n', 'a', 'm', 'e'};
// Representation of "displayName" in UTF8
public static final byte[] UTF8_DISPLAYNAME = {0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65};
public static final byte[] UTF8_DISPLAYNAME = {'d', 'i', 's', 'p', 'l', 'a', 'y', 'n', 'a', 'm', 'e'};
// Representation of "alg" in UTF8
public static final byte[] UTF8_ALG = {0x61, 0x6c, 0x67};
public static final byte[] UTF8_ALG = {'a', 'l', 'g'};
public static final byte[] UTF8_UV = {'u', 'v'};
public static final byte[] UTF8_RK = {0x72, 0x6b};
public static final byte[] UTF8_RK = {'r', 'k'};
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_SIG = {'s', 'i', 'g'};
......@@ -35,4 +35,6 @@ public class Utf8Strings {
public static final byte[] UTF8_PUBLIC_KEY = {'p', 'u', 'b', 'l', 'i', 'c', '-', 'k', 'e', 'y'};
public static final byte[] UTF8_FIDO2 = {'F', 'I', 'D', 'O', '_', '2', '_', '0'};
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_EXTENSIONS = {'e', 'x', 't', 'e', 'n', 's', 'i', 'o', 'n', 's'};
}
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