Commit 1612c7e3 authored by Josh Ji's avatar Josh Ji

code review

rename variables
parent f2fb5073
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<Languages>
<language minSize="56" name="Java" />
</Languages>
</inspection_tool>
<inspection_tool class="GroovyAssignabilityCheck" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>
\ No newline at end of file
...@@ -69,6 +69,5 @@ javacard{ ...@@ -69,6 +69,5 @@ javacard{
name "getCertificate" name "getCertificate"
scripts "select applet", "getCertificate" scripts "select applet", "getCertificate"
} }
} }
} }
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -19,6 +19,7 @@ package com.josh.vku2f; ...@@ -19,6 +19,7 @@ package com.josh.vku2f;
import javacard.framework.JCSystem; import javacard.framework.JCSystem;
import javacard.framework.UserException; import javacard.framework.UserException;
import javacard.framework.Util; import javacard.framework.Util;
import static com.josh.vku2f.CTAP2ErrorCode.*;
public class AuthenticatorGetAssertion { public class AuthenticatorGetAssertion {
public byte[] rpId; public byte[] rpId;
...@@ -73,7 +74,7 @@ public class AuthenticatorGetAssertion { ...@@ -73,7 +74,7 @@ public class AuthenticatorGetAssertion {
// Read the map. It has 2 things in it. // Read the map. It has 2 things in it.
vars[3] = decoder.readMajorType(CBORBase.TYPE_MAP); vars[3] = decoder.readMajorType(CBORBase.TYPE_MAP);
if(vars[3] != 2) { if(vars[3] != 2) {
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
break; break;
} }
for(vars[5] = 0; vars[5] < (short) 2; vars[5]++) { for(vars[5] = 0; vars[5] < (short) 2; vars[5]++) {
...@@ -88,7 +89,7 @@ public class AuthenticatorGetAssertion { ...@@ -88,7 +89,7 @@ public class AuthenticatorGetAssertion {
// It doesn't matter what it is, just check it's string and exists. // It doesn't matter what it is, just check it's string and exists.
} else { } else {
// If it's not these two, throw an error // If it's not these two, throw an error
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
break; break;
} }
} }
...@@ -131,7 +132,7 @@ public class AuthenticatorGetAssertion { ...@@ -131,7 +132,7 @@ public class AuthenticatorGetAssertion {
} }
// We should check we have our "mandatory" options // We should check we have our "mandatory" options
if(rpId == null || clientDataHash == null) { if(rpId == null || clientDataHash == null) {
UserException.throwIt(CTAP2.CTAP2_ERR_MISSING_PARAMETER); UserException.throwIt(CTAP2_ERR_MISSING_PARAMETER);
} }
// Good to go I guess // Good to go I guess
......
...@@ -19,6 +19,7 @@ package com.josh.vku2f; ...@@ -19,6 +19,7 @@ package com.josh.vku2f;
import javacard.framework.JCSystem; import javacard.framework.JCSystem;
import javacard.framework.UserException; import javacard.framework.UserException;
import javacard.framework.Util; import javacard.framework.Util;
import static com.josh.vku2f.CTAP2ErrorCode.*;
public class AuthenticatorMakeCredential { public class AuthenticatorMakeCredential {
public byte[] dataHash; public byte[] dataHash;
...@@ -33,7 +34,7 @@ public class AuthenticatorMakeCredential { ...@@ -33,7 +34,7 @@ public class AuthenticatorMakeCredential {
* Parses a CBOR structure to create an AuthenticatorMakeCredential object * Parses a CBOR structure to create an AuthenticatorMakeCredential object
* *
* @param decoder the initialised decoder on the CBOR structure * @param decoder the initialised decoder on the CBOR structure
* @param vars a short array to store variables in * @ param vars a short array to store variables in
*/ */
public AuthenticatorMakeCredential(CBORDecoder decoder) throws UserException { public AuthenticatorMakeCredential(CBORDecoder decoder) throws UserException {
short[] vars; short[] vars;
...@@ -81,7 +82,7 @@ public class AuthenticatorMakeCredential { ...@@ -81,7 +82,7 @@ public class AuthenticatorMakeCredential {
len2 = decoder.readMajorType(CBORBase.TYPE_MAP); len2 = decoder.readMajorType(CBORBase.TYPE_MAP);
// If less than 2, error // If less than 2, error
if (len2 < (short) 2) { if (len2 < (short) 2) {
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
} }
// Read the map iteratively // Read the map iteratively
for (short j = 0; j < len2; j++) { for (short j = 0; j < len2; j++) {
...@@ -163,7 +164,7 @@ public class AuthenticatorMakeCredential { ...@@ -163,7 +164,7 @@ public class AuthenticatorMakeCredential {
// Read the map length - should be 2 // Read the map length - should be 2
short len3 = decoder.readMajorType(CBORBase.TYPE_MAP); short len3 = decoder.readMajorType(CBORBase.TYPE_MAP);
if(len3 != 2) { if(len3 != 2) {
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
} }
// Iterate over the map // Iterate over the map
for (short k = 0; k < (short) 2; k++) { for (short k = 0; k < (short) 2; k++) {
...@@ -197,10 +198,10 @@ public class AuthenticatorMakeCredential { ...@@ -197,10 +198,10 @@ public class AuthenticatorMakeCredential {
// Check it // Check it
decoder.readTextString(scratch1, (short) 0); decoder.readTextString(scratch1, (short) 0);
if(Util.arrayCompare(scratch1, (short) 0, Utf8Strings.UTF8_PUBLIC_KEY, (short) 0, (short) 10) != (byte) 0) { if(Util.arrayCompare(scratch1, (short) 0, Utf8Strings.UTF8_PUBLIC_KEY, (short) 0, (short) 10) != (byte) 0) {
UserException.throwIt(CTAP2.CTAP2_ERR_UNSUPPORTED_ALGORITHM); UserException.throwIt(CTAP2_ERR_UNSUPPORTED_ALGORITHM);
} }
} else { } else {
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
} }
} }
// Done // Done
...@@ -216,7 +217,7 @@ public class AuthenticatorMakeCredential { ...@@ -216,7 +217,7 @@ public class AuthenticatorMakeCredential {
// Read the map. It has 2 things in it. // Read the map. It has 2 things in it.
short len3 = decoder.readMajorType(CBORBase.TYPE_MAP); short len3 = decoder.readMajorType(CBORBase.TYPE_MAP);
if (len3 != 2) { if (len3 != 2) {
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
} }
// Parse it, properly // Parse it, properly
for(short k = 0; k < (short) 2; k++) { for(short k = 0; k < (short) 2; k++) {
...@@ -231,7 +232,7 @@ public class AuthenticatorMakeCredential { ...@@ -231,7 +232,7 @@ public class AuthenticatorMakeCredential {
// It doesn't matter what it is, just check it's string and exists. // It doesn't matter what it is, just check it's string and exists.
} else { } else {
// If it's not these two, throw an error // If it's not these two, throw an error
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
break; break;
} }
} }
...@@ -243,7 +244,7 @@ public class AuthenticatorMakeCredential { ...@@ -243,7 +244,7 @@ public class AuthenticatorMakeCredential {
// Parse the two rk and uv objects // Parse the two rk and uv objects
// Read the map // Read the map
if(decoder.getMajorType() != CBORBase.TYPE_MAP) { if(decoder.getMajorType() != CBORBase.TYPE_MAP) {
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
break; break;
} }
len2 = decoder.readMajorType(CBORBase.TYPE_MAP); len2 = decoder.readMajorType(CBORBase.TYPE_MAP);
...@@ -261,7 +262,7 @@ public class AuthenticatorMakeCredential { ...@@ -261,7 +262,7 @@ public class AuthenticatorMakeCredential {
decoder.readBoolean(); decoder.readBoolean();
} else if (Util.arrayCompare(scratch1, (short) 0, Utf8Strings.UTF8_UP, (short) 0, (short) 2) == (short) 0) { } else if (Util.arrayCompare(scratch1, (short) 0, Utf8Strings.UTF8_UP, (short) 0, (short) 2) == (short) 0) {
// Error out // Error out
UserException.throwIt(CTAP2.CTAP2_ERR_INVALID_OPTION); UserException.throwIt(CTAP2_ERR_INVALID_OPTION);
break; break;
} else { } else {
// Skip it // Skip it
...@@ -275,7 +276,7 @@ public class AuthenticatorMakeCredential { ...@@ -275,7 +276,7 @@ public class AuthenticatorMakeCredential {
// 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
if(decoder.getMajorType() != CBORBase.TYPE_MAP) { if(decoder.getMajorType() != CBORBase.TYPE_MAP) {
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
break; break;
} }
decoder.skipEntry(); decoder.skipEntry();
...@@ -291,7 +292,7 @@ public class AuthenticatorMakeCredential { ...@@ -291,7 +292,7 @@ public class AuthenticatorMakeCredential {
} }
// Check we've got stuff like the clientDataHash // Check we've got stuff like the clientDataHash
if(dataHash == null || rp == null || user == null || params == null) { if(dataHash == null || rp == null || user == null || params == null) {
UserException.throwIt(CTAP2.CTAP2_ERR_MISSING_PARAMETER); UserException.throwIt(CTAP2_ERR_MISSING_PARAMETER);
} }
// We're done, I guess // We're done, I guess
......
...@@ -22,7 +22,7 @@ import javacard.framework.ISO7816; ...@@ -22,7 +22,7 @@ import javacard.framework.ISO7816;
import javacard.framework.ISOException; import javacard.framework.ISOException;
import javacard.framework.UserException; import javacard.framework.UserException;
import javacard.framework.Util; import javacard.framework.Util;
import static com.josh.vku2f.CTAP2ErrorCode.*;
public class CBORDecoder extends CBORBase { public class CBORDecoder extends CBORBase {
/** /**
...@@ -101,7 +101,7 @@ public class CBORDecoder extends CBORBase { ...@@ -101,7 +101,7 @@ public class CBORDecoder extends CBORBase {
*/ */
public short readMajorType(byte majorType) throws UserException { public short readMajorType(byte majorType) throws UserException {
if (majorType != getMajorType()) { if (majorType != getMajorType()) {
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
return 0; return 0;
} }
return readLength(); return readLength();
...@@ -210,7 +210,7 @@ public class CBORDecoder extends CBORBase { ...@@ -210,7 +210,7 @@ public class CBORDecoder extends CBORBase {
*/ */
public short readByteString(byte[] outBuffer, short outOffset) throws UserException { public short readByteString(byte[] outBuffer, short outOffset) throws UserException {
if(getMajorType() != TYPE_BYTE_STRING) { if(getMajorType() != TYPE_BYTE_STRING) {
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
return 0; return 0;
} }
short length = readLength(); short length = readLength();
...@@ -228,7 +228,7 @@ public class CBORDecoder extends CBORBase { ...@@ -228,7 +228,7 @@ public class CBORDecoder extends CBORBase {
*/ */
public short readTextString(byte[] outBuffer, short outOffset) throws UserException { public short readTextString(byte[] outBuffer, short outOffset) throws UserException {
if(getMajorType() != TYPE_TEXT_STRING) { if(getMajorType() != TYPE_TEXT_STRING) {
UserException.throwIt(CTAP2.CTAP2_ERR_CBOR_UNEXPECTED_TYPE); UserException.throwIt(CTAP2_ERR_CBOR_UNEXPECTED_TYPE);
return 0; return 0;
} }
short length = readLength(); short length = readLength();
......
...@@ -32,102 +32,63 @@ import javacard.security.KeyPair; ...@@ -32,102 +32,63 @@ import javacard.security.KeyPair;
import javacard.security.MessageDigest; import javacard.security.MessageDigest;
import javacard.security.Signature; import javacard.security.Signature;
import javacardx.apdu.ExtendedLength; import javacardx.apdu.ExtendedLength;
import static com.josh.vku2f.CTAP2ErrorCode.*;
public class CTAP2 extends Applet implements ExtendedLength { public class CTAP2 extends Applet implements ExtendedLength {
private static final byte FIDO2_VENDOR_GET_COUNT = (byte)0x45; private final CBORDecoder cborDecoder;
private CBORDecoder cborDecoder; private final CBOREncoder cborEncoder;
private CBOREncoder cborEncoder;
private byte[] inBuf; private byte[] inputBuffer;
private byte[] scratch; private byte[] scratch;
private short[] vars;
private CredentialArray discoverableCreds;
private MessageDigest sha;
private AttestationKeyPair attestationKeyPair;
private byte[] info; private byte[] info;
private StoredCredential[] assertionCreds;
private short[] nextAssertion; private final short[] tempVars;
AuthenticatorGetAssertion assertion; private final short[] chainRam;
private boolean persoComplete; private final short[] outChainRam;
private boolean[] isChaining; private final short[] nextAssertion;
private short[] chainRam;
private short[] outChainRam; private final MessageDigest sha256MessageDigest;
private boolean[] isOutChaining; private final AttestationKeyPair attestationKeyPair;
private AuthenticatorMakeCredential cred;
private CredentialArray credentialArray;
private KeyPair ecDhKey; private AuthenticatorGetAssertion authenticatorGetAssertion;
private boolean[] ecDhSet; private AuthenticatorMakeCredential authenticatorMakeCredential;
private StoredCredential tempCred; private final KeyPair ecDhKeyPair;
private final boolean[] ecDhSet;
private static final byte ISO_INS_GET_DATA = (byte) 0xC0; private final boolean[] isChaining;
private static final byte FIDO2_INS_NFCCTAP_MSG = (byte) 0x10; private final boolean[] isOutChaining;
private boolean personalizeComplete;
public static final byte CTAP1_ERR_SUCCESS = (byte) 0x00;
public static final byte CTAP1_ERR_INVALID_COMMAND = (byte) 0x01; private StoredCredential tempCredential;
public static final byte CTAP1_ERR_INVALID_PARAMETER = (byte) 0x02; private StoredCredential[] assertionCredentials;
public static final byte CTAP1_ERR_INVALID_LENGTH = (byte) 0x03;
public static final byte CTAP1_ERR_INVALID_SEQ = (byte) 0x04; public static final byte ISO_INS_GET_DATA = (byte) 0xC0;
public static final byte CTAP1_ERR_TIMEOUT = (byte) 0x05; public static final byte FIDO2_INS_NFCCTAP_MSG = (byte) 0x10;
public static final byte CTAP1_ERR_CHANNEL_BUSY = (byte) 0x06;
public static final byte CTAP1_ERR_LOCK_REQUIRED = (byte) 0x0A; public static final byte FIDO2_AUTHENTICATOR_MAKE_CREDENTIAL = (byte) 0x01;
public static final byte CTAP1_ERR_INVALID_CHANNEL = (byte) 0x0B; public static final byte FIDO2_AUTHENTICATOR_GET_ASSERTION = (byte) 0x02;
public static final byte CTAP1_ERR_OTHER = (byte) 0x7F; public static final byte FIDO2_AUTHENTICATOR_GET_NEXT_ASSERTION = (byte) 0x08;
public static final byte FIDO2_AUTHENTICATOR_GET_INFO = (byte) 0x04;
public static final byte CTAP2_ERR_CBOR_UNEXPECTED_TYPE = (byte) 0x11; public static final byte FIDO2_AUTHENTICATOR_CLIENT_PIN = (byte) 0x06;
public static final byte CTAP2_ERR_INVALID_CBOR = (byte) 0x12; public static final byte FIDO2_AUTHENTICATOR_RESET = (byte) 0x07;
public static final byte CTAP2_ERR_MISSING_PARAMETER = (byte) 0x14;
public static final byte CTAP2_ERR_LIMIT_EXCEEDED = (byte) 0x15;
public static final byte CTAP2_ERR_UNSUPPORTED_EXTENSION = (byte) 0x16;
public static final byte CTAP2_ERR_CREDENTIAL_EXCLUDED = (byte) 0x19;
public static final byte CTAP2_ERR_PROCESSING = (byte) 0x21;
public static final byte CTAP2_ERR_INVALID_CREDENTIAL = (byte) 0x22;
public static final byte CTAP2_ERR_USER_ACTION_PENDING = (byte) 0x23;
public static final byte CTAP2_ERR_OPERATION_PENDING = (byte) 0x24;
public static final byte CTAP2_ERR_NO_OPERATIONS = (byte) 0x25;
public static final byte CTAP2_ERR_UNSUPPORTED_ALGORITHM = (byte) 0x26;
public static final byte CTAP2_ERR_OPERATION_DENIED = (byte) 0x27;
public static final byte CTAP2_ERR_KEY_STORE_FULL = (byte) 0x28;
public static final byte CTAP2_ERR_NO_OPERATION_PENDING = (byte) 0x2A;
public static final byte CTAP2_ERR_UNSUPPORTED_OPTION = (byte) 0x2B;
public static final byte CTAP2_ERR_INVALID_OPTION = (byte) 0x2C;
public static final byte CTAP2_ERR_KEEPALIVE_CANCEL = (byte) 0x2D;
public static final byte CTAP2_ERR_NO_CREDENTIALS = (byte) 0x2E;
public static final byte CTAP2_ERR_USER_ACTION_TIMEOUT = (byte) 0x2F;
public static final byte CTAP2_ERR_NOT_ALLOWED = (byte) 0x30;
public static final byte CTAP2_ERR_PIN_INVALID = (byte) 0x31;
public static final byte CTAP2_ERR_PIN_BLOCKED = (byte) 0x32;
public static final byte CTAP2_ERR_PIN_AUTH_INVALID = (byte) 0x33;
public static final byte CTAP2_ERR_PIN_AUTH_BLOCKED = (byte) 0x34;
public static final byte CTAP2_ERR_PIN_NOT_SET = (byte) 0x35;
public static final byte CTAP2_ERR_PIN_REQUIRED = (byte) 0x36;
public static final byte CTAP2_ERR_PIN_POLICY_VIOLATION = (byte) 0x37;
public static final byte CTAP2_ERR_PIN_TOKEN_EXPIRED = (byte) 0x38;
public static final byte CTAP2_ERR_REQUEST_TOO_LARGE = (byte) 0x39;
public static final byte CTAP2_ERR_ACTION_TIMEOUT = (byte) 0x3A;
public static final byte CTAP2_ERR_UP_REQUIRED = (byte) 0x3B;
public static final byte FIDO2_AUTHENTICATOR_MAKE_CREDENTIAL = (byte) 0x01;
public static final byte FIDO2_AUTHENTICATOR_GET_ASSERTION = (byte) 0x02;
public static final byte FIDO2_AUTHENTICATOR_GET_NEXT_ASSERTION = (byte) 0x08;
public static final byte FIDO2_AUTHENTICATOR_GET_INFO = (byte) 0x04;
public static final byte FIDO2_AUTHENTICATOR_CLIENT_PIN = (byte) 0x06;
public static final byte FIDO2_AUTHENTICATOR_RESET = (byte) 0x07;
// Vendor specific - for attestation cert loading. // Vendor specific - for attestation cert loading.
public static final byte FIDO2_VENDOR_ATTEST_SIGN = (byte) 0x41; public static final byte FIDO2_VENDOR_ATTEST_SIGN = (byte) 0x41;
public static final byte FIDO2_VENDOR_ATTEST_LOADCERT = (byte) 0x42; public static final byte FIDO2_VENDOR_ATTEST_LOADCERT = (byte) 0x42;
public static final byte FIDO2_VENDOR_PERSO_COMPLETE = (byte) 0x43; public static final byte FIDO2_VENDOR_PERSO_COMPLETE = (byte) 0x43;
public static final byte FIDO2_VENDOR_ATTEST_GETPUB = (byte) 0x44; public static final byte FIDO2_VENDOR_ATTEST_GETPUB = (byte) 0x44;
public static final byte FIDO2_VENDOR_ATTEST_GETCERT = (byte) 0x4A; public static final byte FIDO2_VENDOR_GET_COUNT = (byte) 0x45;
public static final byte FIDO2_VENDOR_ATTEST_GETCERT = (byte) 0x4A;
public static final byte FIDO2_DESELECT = 0x12; public static final byte FIDO2_DESELECT = 0x12;
// AAGUID - this uniquely identifies the type of authenticator we have built. // AAGUID - Authenticator Attestation Global Unique Identifier
// this uniquely identifies the type of authenticator we have built.
// If you're reusing this code, please generate your own GUID and put it here - // If you're reusing this code, please generate your own GUID and put it here -
// this is unique to manufacturer and device model. // this is unique to manufacturer and device model.
public static final byte[] aaguid = { public static final byte[] aaguid = {
(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 't', (byte) 'e', (byte) 's', (byte) 't', (byte) 'g', (byte) 'u', (byte) 'i', (byte) 'd',
(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
private CTAP2() { private CTAP2() {
...@@ -135,24 +96,24 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -135,24 +96,24 @@ public class CTAP2 extends Applet implements ExtendedLength {
// 1210 bytes of a transient buffer for read-in and out // 1210 bytes of a transient buffer for read-in and out
// We advertise 1200 bytes supported, but 10 bytes for protocol nonsense // We advertise 1200 bytes supported, but 10 bytes for protocol nonsense
try { try {
inBuf = JCSystem.makeTransientByteArray((short) 1210, JCSystem.CLEAR_ON_DESELECT); inputBuffer = JCSystem.makeTransientByteArray((short) 1210, JCSystem.CLEAR_ON_DESELECT);
} catch (Exception e) { } catch (Exception e) {
inBuf = new byte[1210]; inputBuffer = new byte[1210];
} }
try { try {
scratch = JCSystem.makeTransientByteArray((short) 512, JCSystem.CLEAR_ON_DESELECT); scratch = JCSystem.makeTransientByteArray((short) 512, JCSystem.CLEAR_ON_DESELECT);
} catch (Exception e) { } catch (Exception e) {
scratch = new byte[512]; scratch = new byte[512];
} }
vars = JCSystem.makeTransientShortArray((short) 8, JCSystem.CLEAR_ON_DESELECT); tempVars = JCSystem.makeTransientShortArray((short) 8, JCSystem.CLEAR_ON_DESELECT);
// Create the CBOR decoder // Create the CBOR decoder
cborDecoder = new CBORDecoder(); cborDecoder = new CBORDecoder();
cborEncoder = new CBOREncoder(); cborEncoder = new CBOREncoder();
discoverableCreds = new CredentialArray((short) 5); credentialArray = new CredentialArray((short) 5);
sha = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false); sha256MessageDigest = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
attestationKeyPair = new AttestationKeyPair(); attestationKeyPair = new AttestationKeyPair();
nextAssertion = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET); nextAssertion = JCSystem.makeTransientShortArray((short) 1, JCSystem.CLEAR_ON_RESET);
persoComplete = false; personalizeComplete = false;
isChaining = JCSystem.makeTransientBooleanArray((short) 2, JCSystem.CLEAR_ON_DESELECT); isChaining = JCSystem.makeTransientBooleanArray((short) 2, JCSystem.CLEAR_ON_DESELECT);
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);
...@@ -161,29 +122,29 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -161,29 +122,29 @@ public class CTAP2 extends Applet implements ExtendedLength {
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);
ecDhKey = 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);
} }
public void handle(APDU apdu) { public void handle(APDU apdu) {
byte[] buffer = apdu.getBuffer(); byte[] buffer = apdu.getBuffer();
tempCred = null; tempCredential = null;
cred = null; authenticatorMakeCredential = null;
vars[3] = doApduIngestion(apdu); tempVars[3] = doApduIngestion(apdu);
if (vars[3] == 0) { if (tempVars[3] == 0) {
// If zero, we had no ISO error, but there might be a CTAP error to return. // If zero, we had no ISO error, but there might be a CTAP error to return.
// Throw either way. // Throw either way.
ISOException.throwIt(ISO7816.SW_NO_ERROR); ISOException.throwIt(ISO7816.SW_NO_ERROR);
return; return;
} }
// Need to grab the CTAP command byte // Need to grab the CTAP command byte
switch (inBuf[0]) { switch (inputBuffer[0]) {
case FIDO2_AUTHENTICATOR_MAKE_CREDENTIAL: case FIDO2_AUTHENTICATOR_MAKE_CREDENTIAL:
authMakeCredential(apdu, vars[3]); authMakeCredential(apdu, tempVars[3]);
break; break;
case FIDO2_AUTHENTICATOR_GET_ASSERTION: case FIDO2_AUTHENTICATOR_GET_ASSERTION:
authGetAssertion(apdu, vars[3]); authGetAssertion(apdu, tempVars[3]);
break; break;
case FIDO2_AUTHENTICATOR_GET_INFO: case FIDO2_AUTHENTICATOR_GET_INFO:
authGetInfo(apdu); authGetInfo(apdu);
...@@ -192,10 +153,13 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -192,10 +153,13 @@ public class CTAP2 extends Applet implements ExtendedLength {
authGetNextAssertion(apdu, buffer); authGetNextAssertion(apdu, buffer);
break; break;
case FIDO2_VENDOR_ATTEST_SIGN: //0x41 case FIDO2_VENDOR_ATTEST_SIGN: //0x41
attestSignRaw(apdu, vars[3]); attestSignRaw(apdu, tempVars[3]);
break;
case FIDO2_AUTHENTICATOR_CLIENT_PIN:
clientPin(apdu, tempVars[3]);
break; break;
case FIDO2_VENDOR_ATTEST_LOADCERT: //0x42 case FIDO2_VENDOR_ATTEST_LOADCERT: //0x42
attestSetCert(apdu, vars[3]); attestSetCert(apdu, tempVars[3]);
break; break;
case FIDO2_VENDOR_PERSO_COMPLETE: //0x43 case FIDO2_VENDOR_PERSO_COMPLETE: //0x43
persoComplete(apdu); persoComplete(apdu);
...@@ -210,7 +174,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -210,7 +174,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
getCount(apdu); getCount(apdu);
break; break;
case FIDO2_AUTHENTICATOR_RESET: //0x07 case FIDO2_AUTHENTICATOR_RESET: //0x07
// Need to finish doing this, we can, i mean, but I don't like it // Need to finish doing this, we can, I mean, but I don't like it
doReset(apdu); doReset(apdu);
break; break;
default: default:
...@@ -220,8 +184,8 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -220,8 +184,8 @@ public class CTAP2 extends Applet implements ExtendedLength {
} }
public void persoComplete(APDU apdu) { public void persoComplete(APDU apdu) {
if (attestationKeyPair.isCertSet() && !persoComplete) { if (attestationKeyPair.isCertSet() && !personalizeComplete) {
persoComplete = true; personalizeComplete = true;
returnError(apdu, CTAP1_ERR_SUCCESS); returnError(apdu, CTAP1_ERR_SUCCESS);
} else { } else {
returnError(apdu, CTAP1_ERR_INVALID_COMMAND); returnError(apdu, CTAP1_ERR_INVALID_COMMAND);
...@@ -231,113 +195,108 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -231,113 +195,108 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Gets the attestation public key. * Gets the attestation public key.
* *
* @param apdu * @param apdu apdu buffer
* @ param buffer
* @ param inBuf
* @ param bufLen
*/ */
public void getAttestPublic(APDU apdu) { public void getAttestPublic(APDU apdu) {
if (persoComplete) { if (personalizeComplete) {
returnError(apdu, CTAP1_ERR_INVALID_COMMAND); returnError(apdu, CTAP1_ERR_INVALID_COMMAND);
return; return;
} }
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
vars[0] = (short) (attestationKeyPair.getPubkey(inBuf, (short) 1) + 1); tempVars[0] = (short) (attestationKeyPair.getPubkey(inputBuffer, (short) 1) + 1);
apdu.setOutgoing(); apdu.setOutgoing();
apdu.setOutgoingLength(vars[0]); apdu.setOutgoingLength(tempVars[0]);
apdu.sendBytesLong(inBuf, (short) 0, vars[0]); apdu.sendBytesLong(inputBuffer, (short) 0, tempVars[0]);
} }
/** get counter's value */ /** get counter's value */
public void getCount(APDU apdu){ public void getCount(APDU apdu){
short count = discoverableCreds.getCount(); short count = credentialArray.getCount();
apdu.setOutgoing(); apdu.setOutgoing();
apdu.setOutgoingLength((short)2); apdu.setOutgoingLength((short)2);
Util.setShort(inBuf,(short)0, count); Util.setShort(inputBuffer,(short)0, count);
apdu.sendBytesLong(inBuf,(short)0,(short)2); apdu.sendBytesLong(inputBuffer,(short)0,(short)2);
} }
/** /**
* Performs raw signatures, may only occur when personalisation is not complete. * Performs raw signatures, may only occur when personalisation is not complete.
* *
* @param apdu * @param apdu apdu buffer
* @ param buffer * @param bufLen buffer length
* @ param inBuf
* @param bufLen
*/ */
public void attestSignRaw(APDU apdu, short bufLen) { public void attestSignRaw(APDU apdu, short bufLen) {
if (persoComplete) { if (personalizeComplete) {
returnError(apdu, CTAP1_ERR_INVALID_COMMAND); returnError(apdu, CTAP1_ERR_INVALID_COMMAND);
return; return;
} }
Util.arrayCopy(inBuf, (short) 1, scratch, (short) 0, (short) (bufLen - 1)); Util.arrayCopy(inputBuffer, (short) 1, scratch, (short) 0, (short) (bufLen - 1));
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
vars[2] = attestationKeyPair.sign(scratch, (short) 0, vars[1], inBuf, (short) 1); tempVars[2] = attestationKeyPair.sign(scratch, (short) 0, tempVars[1], inputBuffer, (short) 1);
apdu.setOutgoing(); apdu.setOutgoing();
apdu.setOutgoingLength((short) (vars[2] + 1)); apdu.setOutgoingLength((short) (tempVars[2] + 1));
apdu.sendBytesLong(inBuf, (short) 0, (short) (vars[2] + 1)); apdu.sendBytesLong(inputBuffer, (short) 0, (short) (tempVars[2] + 1));
} }
public void attestSetCert(APDU apdu, short bufLen) { public void attestSetCert(APDU apdu, short bufLen) {
if (persoComplete) { if (personalizeComplete) {
returnError(apdu, CTAP1_ERR_INVALID_COMMAND); returnError(apdu, CTAP1_ERR_INVALID_COMMAND);
return; return;
} }
// We don't actually use any CBOR here, simplify copying // We don't actually use any CBOR here, simplify copying
attestationKeyPair.setCert(inBuf, (short) 1, (short) (bufLen - 1)); attestationKeyPair.setCert(inputBuffer, (short) 1, (short) (bufLen - 1));
MessageDigest dig = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false); MessageDigest dig = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
short len = (short) (dig.doFinal(attestationKeyPair.x509cert, (short) 0, attestationKeyPair.x509len, inBuf, (short) 3) + 3); short len = (short) (dig.doFinal(attestationKeyPair.x509cert, (short) 0, attestationKeyPair.x509len, inputBuffer, (short) 3) + 3);
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
Util.setShort(inBuf, (short) 1, attestationKeyPair.x509len); Util.setShort(inputBuffer, (short) 1, attestationKeyPair.x509len);
apdu.setOutgoing(); apdu.setOutgoing();
apdu.setOutgoingLength(len); apdu.setOutgoingLength(len);
apdu.sendBytesLong(inBuf, (short) 0, len); apdu.sendBytesLong(inputBuffer, (short) 0, len);
} }
public void authMakeCredential(APDU apdu, short bufLen) { public void authMakeCredential(APDU apdu, short bufLen) {
// Init the decoder // Init the decoder
cborDecoder.init(inBuf, (short) 1, bufLen); cborDecoder.init(inputBuffer, (short) 1, bufLen);
// create a credential object // create a credential object
try { try {
cred = new AuthenticatorMakeCredential(cborDecoder); authenticatorMakeCredential = new AuthenticatorMakeCredential(cborDecoder);
} catch (UserException e) { } catch (UserException e) {
returnError(apdu, e.getReason()); returnError(apdu, e.getReason());
return; return;
} }
// Create the actual credential // Create the actual credential
switch (cred.getAlgorithm()) { switch (authenticatorMakeCredential.getAlgorithm()) {
case Signature.ALG_ECDSA_SHA_256: case Signature.ALG_ECDSA_SHA_256:
tempCred = new StoredES256Credential(cred); tempCredential = new StoredES256Credential(authenticatorMakeCredential);
break; break;
case Signature.ALG_RSA_SHA_256_PKCS1: case Signature.ALG_RSA_SHA_256_PKCS1:
tempCred = new StoredRS256Credential(cred); tempCredential = new StoredRS256Credential(authenticatorMakeCredential);
break; break;
case Signature.ALG_RSA_SHA_256_PKCS1_PSS: case Signature.ALG_RSA_SHA_256_PKCS1_PSS:
tempCred = new StoredPS256Credential(cred); tempCredential = new StoredPS256Credential(authenticatorMakeCredential);
break; break;
default: default:
returnError(apdu, CTAP2_ERR_UNSUPPORTED_ALGORITHM); returnError(apdu, CTAP2_ERR_UNSUPPORTED_ALGORITHM);
return; return;
} }
if (cred.isResident()) { if (authenticatorMakeCredential.isResident()) {
// Check if a credential exists on the exclude list // Check if a credential exists on the excluded list
if (cred.isExclude() && isPresent(cred.exclude)) { if (authenticatorMakeCredential.isExclude() && isPresent(authenticatorMakeCredential.exclude)) {
// Throw the error // Throw the error
returnError(apdu, CTAP2_ERR_CREDENTIAL_EXCLUDED); returnError(apdu, CTAP2_ERR_CREDENTIAL_EXCLUDED);
return; return;
} }
// Add the credential to the resident storage, overwriting if necessary // Add the credential to the resident storage, overwriting if necessary
addResident(apdu, tempCred); addResident(apdu, tempCredential);
// Initialise the output buffer, for CBOR writing. // Initialise the output buffer, for CBOR writing.
// output buffer needs 0x00 as first byte as status code // output buffer needs 0x00 as first byte as status code
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
cborEncoder.init(inBuf, (short) 1, (short) 1199); cborEncoder.init(inputBuffer, (short) 1, (short) 1199);
// Create a map in the buffer // Create a map in the buffer
vars[0] = cborEncoder.startMap((short) 3); tempVars[0] = cborEncoder.startMap((short) 3);
// Attestation stuff // Attestation stuff
cborEncoder.writeRawByte((byte) 0x01); cborEncoder.writeRawByte((byte) 0x01);
...@@ -346,19 +305,19 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -346,19 +305,19 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Put the authdata identifier there // Put the authdata identifier there
cborEncoder.writeRawByte((byte) 0x02); cborEncoder.writeRawByte((byte) 0x02);
// Allocate some space for the byte string // Allocate some space for the byte string
vars[0] = cborEncoder.startByteString((short) (37 + tempCred.getAttestedLen())); tempVars[0] = cborEncoder.startByteString((short) (37 + tempCredential.getAttestedLen()));
// Stash where it begins // Stash where it begins
vars[7] = vars[0]; tempVars[7] = tempVars[0];
// Create the SHA256 hash of the RP ID // Create the SHA256 hash of the RP ID
tempCred.rp.getRp(scratch, (short) 0); tempCredential.rpEntity.getRp(scratch, (short) 0);
vars[0] += sha.doFinal(scratch, (short) 0, tempCred.rp.getRpLen(), inBuf, vars[0]); tempVars[0] += sha256MessageDigest.doFinal(scratch, (short) 0, tempCredential.rpEntity.getRpLen(), inputBuffer, tempVars[0]);
// Set flags - User presence, user verified, attestation present // Set flags - User presence, user verified, attestation present
inBuf[vars[0]++] = (byte) 0x45; inputBuffer[tempVars[0]++] = (byte) 0x45;
// Set the signature counter // Set the signature counter
vars[0] += tempCred.readCounter(inBuf, vars[0]); tempVars[0] += tempCredential.readCounter(inputBuffer, 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
vars[0] += tempCred.getAttestedData(inBuf, vars[0]); tempVars[0] += tempCredential.getAttestedData(inputBuffer, tempVars[0]);
// Generate and then attach the attestation // Generate and then attach the attestation
cborEncoder.writeRawByte((byte) 0x03); cborEncoder.writeRawByte((byte) 0x03);
...@@ -378,11 +337,11 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -378,11 +337,11 @@ public class CTAP2 extends Applet implements ExtendedLength {
// We sign over the client data hash and the attested data. // We sign over the client data hash and the attested data.
// AuthenticatorData is first. We noted down where it begins and know how long // AuthenticatorData is first. We noted down where it begins and know how long
// it is. // it is.
attestationKeyPair.update(inBuf, vars[7], (short) (tempCred.getAttestedLen() + 37)); attestationKeyPair.update(inputBuffer, tempVars[7], (short) (tempCredential.getAttestedLen() + 37));
// The client data hash is next, which we use to finish off the signature. // The client data hash is next, which we use to finish off the signature.
vars[4] = attestationKeyPair.sign(cred.dataHash, (short) 0, (short) cred.dataHash.length, scratch, (short) 0); tempVars[4] = attestationKeyPair.sign(authenticatorMakeCredential.dataHash, (short) 0, (short) authenticatorMakeCredential.dataHash.length, scratch, (short) 0);
// Create the byte string for the signature // Create the byte string for the signature
cborEncoder.encodeByteString(scratch, (short) 0, vars[4]); cborEncoder.encodeByteString(scratch, (short) 0, tempVars[4]);
// Set the x509 cert now // Set the x509 cert now
cborEncoder.encodeTextString(Utf8Strings.UTF8_X5C, (short) 0, (short) 3); cborEncoder.encodeTextString(Utf8Strings.UTF8_X5C, (short) 0, (short) 3);
// Supposedly we need an array here // Supposedly we need an array here
...@@ -402,41 +361,41 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -402,41 +361,41 @@ public class CTAP2 extends Applet implements ExtendedLength {
public void authGetAssertion(APDU apdu, short bufLen) { public void authGetAssertion(APDU apdu, short bufLen) {
nextAssertion[0] = (short) 0; nextAssertion[0] = (short) 0;
// Decode the CBOR array for the assertion // Decode the CBOR array for the assertion
cborDecoder.init(inBuf, (short) 1, bufLen); cborDecoder.init(inputBuffer, (short) 1, bufLen);
try { try {
assertion = new AuthenticatorGetAssertion(cborDecoder); authenticatorGetAssertion = new AuthenticatorGetAssertion(cborDecoder);
} catch (UserException e) { } catch (UserException e) {
returnError(apdu, e.getReason()); returnError(apdu, e.getReason());
return; return;
} }
// Match the assertion to the credential // Match the assertion to the credential
// Get a list of matching credentials // Get a list of matching credentials
assertionCreds = findCredentials(apdu, assertion); assertionCredentials = findCredentials(apdu, authenticatorGetAssertion);
// Use the first one; this complies with both ideas - use the most recent match // Use the first one; this complies with both ideas - use the most recent match
// if no allow list, use any if an allow list existed // if no allow list, use any if an allowing list existed
if (assertionCreds.length == 0 || assertionCreds[0] == null) { if (assertionCredentials.length == 0 || assertionCredentials[0] == null) {
returnError(apdu, CTAP2_ERR_NO_CREDENTIALS); returnError(apdu, CTAP2_ERR_NO_CREDENTIALS);
return; return;
} }
// Create the authenticatorData to sign // Create the authenticatorData to sign
sha.doFinal(assertion.rpId, (short) 0, (short) assertion.rpId.length, scratch, (short) 0); sha256MessageDigest.doFinal(authenticatorGetAssertion.rpId, (short) 0, (short) authenticatorGetAssertion.rpId.length, scratch, (short) 0);
if (assertion.options[1]) { if (authenticatorGetAssertion.options[1]) {
scratch[32] = 0x05; scratch[32] = 0x05;
} else { } else {
scratch[32] = 0x01; scratch[32] = 0x01;
} }
assertionCreds[0].readCounter(scratch, (short) 33); assertionCredentials[0].readCounter(scratch, (short) 33);
// Copy the hash in // Copy the hash in
assertion.getHash(scratch, (short) 37); authenticatorGetAssertion.getHash(scratch, (short) 37);
// Create the output // Create the output
// Status flags first // Status flags first
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
// Create the encoder // Create the encoder
cborEncoder.init(inBuf, (short) 1, (short) 1199); cborEncoder.init(inputBuffer, (short) 1, (short) 1199);
// Determine if we need 4 or 5 in the array // Determine if we need 4 or 5 in the array
if (assertionCreds.length > 1) { if (assertionCredentials.length > 1) {
doAssertionCommon(cborEncoder, (short) 5); doAssertionCommon(cborEncoder, (short) 5);
} else { } else {
doAssertionCommon(cborEncoder, (short) 4); doAssertionCommon(cborEncoder, (short) 4);
...@@ -449,30 +408,28 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -449,30 +408,28 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Get the next assertion in a list of multiple. * Get the next assertion in a list of multiple.
* *
* @param apdu * @param apdu apdu buffer
* @param buffer * @param buffer buffer
* @ param inBuf
* @ param inLen
*/ */
private void authGetNextAssertion(APDU apdu, byte[] buffer) { private void authGetNextAssertion(APDU apdu, byte[] buffer) {
// Confirm that we have more assertions to do // Confirm that we have more assertions to do
if (nextAssertion[0] != (short) 0 && nextAssertion[0] < assertionCreds.length) { if (nextAssertion[0] != (short) 0 && nextAssertion[0] < assertionCredentials.length) {
// Create the authenticatorData to sign // Create the authenticatorData to sign
sha.doFinal(assertion.rpId, (short) 0, (short) assertion.rpId.length, scratch, (short) 0); sha256MessageDigest.doFinal(authenticatorGetAssertion.rpId, (short) 0, (short) authenticatorGetAssertion.rpId.length, scratch, (short) 0);
if (assertion.options[1]) { if (authenticatorGetAssertion.options[1]) {
scratch[32] = 0x05; scratch[32] = 0x05;
} else { } else {
scratch[32] = 0x01; scratch[32] = 0x01;
} }
assertionCreds[nextAssertion[0]].readCounter(scratch, (short) 33); assertionCredentials[nextAssertion[0]].readCounter(scratch, (short) 33);
// Copy the hash in // Copy the hash in
assertion.getHash(scratch, (short) 37); authenticatorGetAssertion.getHash(scratch, (short) 37);
// Create the output // Create the output
// Status flags first // Status flags first
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
// Create the encoder // Create the encoder
cborEncoder.init(inBuf, (short) 1, (short) 1199); cborEncoder.init(inputBuffer, (short) 1, (short) 1199);
doAssertionCommon(cborEncoder, (short) 4); doAssertionCommon(cborEncoder, (short) 4);
nextAssertion[0]++; nextAssertion[0]++;
...@@ -485,15 +442,15 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -485,15 +442,15 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Note: we only implement the keyAgreement bit // Note: we only implement the keyAgreement bit
public void clientPin(APDU apdu, short bufLen) { public void clientPin(APDU apdu, short bufLen) {
try { try {
cborDecoder.init(inBuf, (short) 1, bufLen); cborDecoder.init(inputBuffer, (short) 1, bufLen);
// Start reading // Start reading
cborDecoder.readMajorType(CBORBase.TYPE_MAP); cborDecoder.readMajorType(CBORBase.TYPE_MAP);
// Read PIN protocol tag // Read pinUvAuthProtocol
if (cborDecoder.readInt8() != (byte) 0x01) { if (cborDecoder.readInt8() != (byte) 0x01) {
UserException.throwIt(CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
return; return;
} }
// Read the actual protocol // Read subCommand
if (cborDecoder.readInt8() != (byte) 0x01) { if (cborDecoder.readInt8() != (byte) 0x01) {
UserException.throwIt(CTAP2_ERR_INVALID_CBOR); UserException.throwIt(CTAP2_ERR_INVALID_CBOR);
return; return;
...@@ -511,7 +468,6 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -511,7 +468,6 @@ public class CTAP2 extends Applet implements ExtendedLength {
break; break;
default: default:
UserException.throwIt(CTAP2_ERR_UNSUPPORTED_OPTION); UserException.throwIt(CTAP2_ERR_UNSUPPORTED_OPTION);
return;
} }
} catch (UserException e) { } catch (UserException e) {
returnError(apdu, e.getReason()); returnError(apdu, e.getReason());
...@@ -521,14 +477,14 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -521,14 +477,14 @@ public class CTAP2 extends Applet implements ExtendedLength {
private void addResident(APDU apdu, StoredCredential cred) { private void addResident(APDU apdu, StoredCredential cred) {
// Add a Discoverable Credential (resident) // Add a Discoverable Credential (resident)
try { try {
discoverableCreds.addCredential(cred); credentialArray.addCredential(cred);
} catch (UserException e) { } catch (UserException e) {
returnError(apdu, e.getReason()); returnError(apdu, e.getReason());
} }
} }
// Generate a session-specific ECDH P-256 key for Diffie-Hellman with the // Generate a session-specific ECDH P-256 key for Diffie-Hellman with the
// platform (Used for PIN but we only ever do it for hmac-secret) // platform (Used for PIN ,but we only ever do it for hmac-secret)
private void generateDH(APDU apdu) { private void generateDH(APDU apdu) {
byte[] w; byte[] w;
try { try {
...@@ -540,16 +496,16 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -540,16 +496,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
if (!ecDhSet[0]) { if (!ecDhSet[0]) {
// Grab the public key and set it's parameters // Grab the public key and set its parameters
KeyParams.sec256r1params((ECKey) ecDhKey.getPublic()); KeyParams.sec256r1params((ECKey) ecDhKeyPair.getPublic());
// Generate a new key-pair // Generate a new key-pair
ecDhKey.genKeyPair(); ecDhKeyPair.genKeyPair();
} }
((ECPublicKey) ecDhKey.getPublic()).getW(w, (short) 0); ((ECPublicKey) ecDhKeyPair.getPublic()).getW(w, (short) 0);
// Return the data requested // Return the data requested
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
cborEncoder.init(inBuf, (short) 1, (short) 1199); cborEncoder.init(inputBuffer, (short) 1, (short) 1199);
// Start a map // Start a map
cborEncoder.startMap((short) 1); cborEncoder.startMap((short) 1);
// Encode the COSE key identifier // Encode the COSE key identifier
...@@ -595,21 +551,21 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -595,21 +551,21 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Our list can be no bigger than the allowList // Our list can be no bigger than the allowList
list = new StoredCredential[(short) assertion.allow.length]; list = new StoredCredential[(short) assertion.allow.length];
vars[6] = 0; tempVars[6] = 0;
for (vars[7] = (short) (discoverableCreds.getLength() - 1); vars[7] >= 0; vars[7]--) { for (tempVars[7] = (short) (credentialArray.getLength() - 1); tempVars[7] >= 0; tempVars[7]--) {
temp = discoverableCreds.getCred(vars[7]); temp = credentialArray.get(tempVars[7]);
// Check if null or doesn't match rpId // Check if null or doesn't match rpId
if (temp != null && temp.rp.checkId(assertion.rpId, (short) 0, (short) assertion.rpId.length)) { if (temp != null && temp.rpEntity.checkId(assertion.rpId, (short) 0, (short) assertion.rpId.length)) {
for (vars[5] = 0; vars[5] < (short) assertion.allow.length; vars[5]++) { for (tempVars[5] = 0; tempVars[5] < (short) assertion.allow.length; tempVars[5]++) {
// Check the list // Check the list
// Does length match? // Does length match?
if ((short) assertion.allow[vars[5]].id.length != (short) temp.id.length) { if ((short) assertion.allow[tempVars[5]].id.length != (short) temp.credentialId.length) {
continue; continue;
} }
if (Util.arrayCompare(assertion.allow[vars[5]].id, (short) 0, temp.id, (short) 0, if (Util.arrayCompare(assertion.allow[tempVars[5]].id, (short) 0, temp.credentialId, (short) 0,
(short) temp.id.length) == 0) { (short) temp.credentialId.length) == 0) {
// Add it to the list // Add it to the list
list[vars[6]++] = temp; list[tempVars[6]++] = temp;
} }
} }
...@@ -619,23 +575,23 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -619,23 +575,23 @@ public class CTAP2 extends Applet implements ExtendedLength {
} else { } else {
// Old code path, works fine for me // Old code path, works fine for me
list = new StoredCredential[discoverableCreds.getLength()]; list = new StoredCredential[credentialArray.getLength()];
vars[6] = 0; tempVars[6] = 0;
for (vars[7] = (short) (discoverableCreds.getLength() - 1); vars[7] >= 0; vars[7]--) { for (tempVars[7] = (short) (credentialArray.getLength() - 1); tempVars[7] >= 0; tempVars[7]--) {
temp = discoverableCreds.getCred(vars[7]); temp = credentialArray.get(tempVars[7]);
// Check for null or doesn't match rpId // Check for null or doesn't match rpId
if (temp != null && temp.rp.checkId(assertion.rpId, (short) 0, (short) assertion.rpId.length)) { if (temp != null && temp.rpEntity.checkId(assertion.rpId, (short) 0, (short) assertion.rpId.length)) {
// Then valid // Then valid
list[vars[6]++] = temp; list[tempVars[6]++] = temp;
} }
} }
} }
// Trim the list // Trim the list
StoredCredential[] ret = new StoredCredential[vars[6]]; StoredCredential[] ret = new StoredCredential[tempVars[6]];
// Trim // Trim
for (vars[7] = 0; vars[7] < vars[6]; vars[7]++) { for (tempVars[7] = 0; tempVars[7] < tempVars[6]; tempVars[7]++) {
ret[vars[7]] = list[vars[7]]; ret[tempVars[7]] = list[tempVars[7]];
} }
// Null out the unused stuff // Null out the unused stuff
JCSystem.requestObjectDeletion(); JCSystem.requestObjectDeletion();
...@@ -646,18 +602,18 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -646,18 +602,18 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Check if anything in the list is present * Check if anything in the list is present
* *
* @param list * @param list list
* @return * @return if is present
*/ */
private boolean isPresent(PublicKeyCredentialDescriptor[] list) { private boolean isPresent(PublicKeyCredentialDescriptor[] list) {
StoredCredential temp; StoredCredential temp;
for (vars[7] = (short) 0; vars[7] < discoverableCreds.getLength(); vars[7]++) { for (tempVars[7] = (short) 0; tempVars[7] < credentialArray.getLength(); tempVars[7]++) {
temp = discoverableCreds.getCred(vars[7]); temp = credentialArray.get(tempVars[7]);
if (temp == null) { if (temp == null) {
continue; continue;
} }
for (vars[6] = (short) 0; vars[6] < (short) list.length; vars[6]++) { for (tempVars[6] = (short) 0; tempVars[6] < (short) list.length; tempVars[6]++) {
if (temp.checkId(list[vars[6]].id, (short) 0, (short) list[vars[6]].id.length)) { if (temp.checkId(list[tempVars[6]].id, (short) 0, (short) list[tempVars[6]].id.length)) {
return true; return true;
} }
} }
...@@ -667,21 +623,21 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -667,21 +623,21 @@ public class CTAP2 extends Applet implements ExtendedLength {
} }
/** /**
* Reset the authenticator. This doesn't actually take much. TODO: Implement * Reset the authenticator. This doesn't actually take much.
* checking. This is just so testing doesn't crap out. * checking. This is just so testing doesn't crap out.
*/ */
private void doReset(APDU apdu) { private void doReset(APDU apdu) {
discoverableCreds = new CredentialArray((short) 5); // TODO: Implement Resetting
credentialArray = new CredentialArray((short) 5);
JCSystem.requestObjectDeletion(); JCSystem.requestObjectDeletion();
returnError(apdu, CTAP1_ERR_SUCCESS); returnError(apdu, CTAP1_ERR_SUCCESS);
} }
/** /**
* Return an error via APDU - an error on the FIDO2 side is considered a success * Return an error via APDU - an error on the FIDO2 side is considered a success
* in APDU-land so we send a response. * in APDU-land ,so we send a response.
* *
* @param apdu shared APDU object * @param apdu shared APDU object
* @ param buffer APDU buffer
* @param err error code * @param err error code
*/ */
public void returnError(APDU apdu, byte err) { public void returnError(APDU apdu, byte err) {
...@@ -692,10 +648,9 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -692,10 +648,9 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Return an error via APDU - an error on the FIDO2 side is considered a success * Return an error via APDU - an error on the FIDO2 side is considered a success
* in APDU-land so we send a response. * in APDU-land ,so we send a response.
* *
* @param apdu shared APDU object * @param apdu shared APDU object
* @ param buffer APDU buffer
* @param err error code * @param err error code
*/ */
public void returnError(APDU apdu, short err) { public void returnError(APDU apdu, short err) {
...@@ -706,19 +661,16 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -706,19 +661,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
} }
/** /**
* Get authenticator-specific informtion, and return it to the platform. * Get authenticator-specific information, and return it to the platform.
* *
* @param apdu * @param apdu apdu buffer
* @ param buffer
* @ param inBuf
* @ param bufLen
*/ */
public void authGetInfo(APDU apdu) { public void authGetInfo(APDU apdu) {
// Create the authenticator info if not present. // Create the authenticator info if not present.
if (info == null) { if (info == null) {
// Create the authGetInfo - 0x00 is success // Create the authGetInfo - 0x00 is success
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
cborEncoder.init(inBuf, (short) 1, (short) 1199); cborEncoder.init(inputBuffer, (short) 1, (short) 1199);
cborEncoder.startMap((short) 4); cborEncoder.startMap((short) 4);
// 0x01, versions // 0x01, versions
cborEncoder.encodeUInt8((byte) 0x01); cborEncoder.encodeUInt8((byte) 0x01);
...@@ -748,38 +700,38 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -748,38 +700,38 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Done // Done
JCSystem.beginTransaction(); JCSystem.beginTransaction();
info = new byte[cborEncoder.getCurrentOffset()]; info = new byte[cborEncoder.getCurrentOffset()];
Util.arrayCopy(inBuf, (short) 0, info, (short) 0, cborEncoder.getCurrentOffset()); Util.arrayCopy(inputBuffer, (short) 0, info, (short) 0, cborEncoder.getCurrentOffset());
JCSystem.commitTransaction(); JCSystem.commitTransaction();
} }
// Send it // Send it
Util.arrayCopyNonAtomic(info, (short) 0, inBuf, (short) 0, (short) info.length); Util.arrayCopyNonAtomic(info, (short) 0, inputBuffer, (short) 0, (short) info.length);
sendLongChaining(apdu, (short) info.length); sendLongChaining(apdu, (short) info.length);
} }
/** /**
* Covers the common assertion building process. * Covers the common assertion building process.
* *
* @param enc * @param encoder CBOR Encoder
* @param mapLen * @param mapLength Map Length
*/ */
private void doAssertionCommon(CBOREncoder enc, short mapLen) { private void doAssertionCommon(CBOREncoder encoder, short mapLength) {
// Determine if we need 4 or 5 in the array // Determine if we need 4 or 5 in the array
if (mapLen == 4) { if (mapLength == 4) {
enc.startMap((short) 4); encoder.startMap((short) 4);
} else { } else {
enc.startMap((short) 5); encoder.startMap((short) 5);
} }
// Tag 1, credential data // Tag 1, credential data
enc.encodeUInt8((byte) 0x01); encoder.encodeUInt8((byte) 0x01);
// Start a map, which is all the PublicKeyCredentialDescriptor is // Start a map, which is all the PublicKeyCredentialDescriptor is
enc.startMap((short) 2); encoder.startMap((short) 2);
// Put the id key // Put the id key
cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2);
// Put the value, which is a byte array // Put the value, which is a byte array
cborEncoder.encodeByteString(assertionCreds[nextAssertion[0]].id, (short) 0, cborEncoder.encodeByteString(assertionCredentials[nextAssertion[0]].credentialId, (short) 0,
(short) assertionCreds[nextAssertion[0]].id.length); (short) assertionCredentials[nextAssertion[0]].credentialId.length);
// Put the key for the type // Put the key for the type
cborEncoder.encodeTextString(Utf8Strings.UTF8_TYPE, (short) 0, (short) 4); cborEncoder.encodeTextString(Utf8Strings.UTF8_TYPE, (short) 0, (short) 4);
// Put the value // Put the value
...@@ -795,57 +747,57 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -795,57 +747,57 @@ public class CTAP2 extends Applet implements ExtendedLength {
// Turns out this is DER encoding, again // Turns out this is DER encoding, again
// Sign the data // Sign the data
vars[3] = assertionCreds[nextAssertion[0]].performSignature(scratch, (short) 0, (short) 69, scratch, tempVars[3] = assertionCredentials[nextAssertion[0]].performSignature(scratch, (short) 0, (short) 69, scratch,
(short) 69); (short) 69);
// Create the ByteString to put it into // Create the ByteString to put it into
cborEncoder.encodeByteString(scratch, (short) 69, vars[3]); cborEncoder.encodeByteString(scratch, (short) 69, tempVars[3]);
// Tag 4, user details // Tag 4, user details
cborEncoder.encodeUInt8((byte) 0x04); cborEncoder.encodeUInt8((byte) 0x04);
// Start the PublicKeyCredentialUserEntity map // Start the PublicKeyCredentialUserEntity map
// If we have "UV" enabled, then we do all the info we have. // If we have "UV" enabled, then we do all the info we have.
if (assertion.options[1]) { if (authenticatorGetAssertion.options[1]) {
cborEncoder.startMap(assertionCreds[nextAssertion[0]].user.numData); cborEncoder.startMap(assertionCredentials[nextAssertion[0]].userEntity.numData);
// We need to check what we have for users // We need to check what we have for users
// Iterate over the bit flags // Iterate over the bit flags
boolean[] usrFlags = assertionCreds[nextAssertion[0]].getPresentUser(); boolean[] usrFlags = assertionCredentials[nextAssertion[0]].getPresentUser();
// This actually // This actually
if (usrFlags[2]) { if (usrFlags[2]) {
// Has the 'displayName' tag // Has the 'displayName' tag
cborEncoder.encodeTextString(Utf8Strings.UTF8_DISPLAYNAME, (short) 0, (short) 11); cborEncoder.encodeTextString(Utf8Strings.UTF8_DISPLAYNAME, (short) 0, (short) 11);
cborEncoder.encodeTextString(assertionCreds[nextAssertion[0]].user.displayName.str, (short) 0, cborEncoder.encodeTextString(assertionCredentials[nextAssertion[0]].userEntity.displayName.str, (short) 0,
assertionCreds[nextAssertion[0]].user.displayName.len); assertionCredentials[nextAssertion[0]].userEntity.displayName.len);
} }
if (usrFlags[1]) { if (usrFlags[1]) {
// The 'id' tag // The 'id' tag
cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2);
cborEncoder.encodeByteString(assertionCreds[nextAssertion[0]].user.id, (short) 0, cborEncoder.encodeByteString(assertionCredentials[nextAssertion[0]].userEntity.id, (short) 0,
(short) assertionCreds[nextAssertion[0]].user.id.length); (short) assertionCredentials[nextAssertion[0]].userEntity.id.length);
} }
if (usrFlags[0]) { if (usrFlags[0]) {
// The 'name' // The 'name'
cborEncoder.encodeTextString(Utf8Strings.UTF8_NAME, (short) 0, (short) 4); cborEncoder.encodeTextString(Utf8Strings.UTF8_NAME, (short) 0, (short) 4);
cborEncoder.encodeTextString(assertionCreds[nextAssertion[0]].user.name.str, (short) 0, cborEncoder.encodeTextString(assertionCredentials[nextAssertion[0]].userEntity.name.str, (short) 0,
assertionCreds[nextAssertion[0]].user.name.len); assertionCredentials[nextAssertion[0]].userEntity.name.len);
} }
if (usrFlags[3]) { if (usrFlags[3]) {
// Has the 'icon' tag // Has the 'icon' tag
cborEncoder.encodeTextString(Utf8Strings.UTF8_ICON, (short) 0, (short) 4); cborEncoder.encodeTextString(Utf8Strings.UTF8_ICON, (short) 0, (short) 4);
cborEncoder.encodeTextString(assertionCreds[nextAssertion[0]].user.icon, (short) 0, cborEncoder.encodeTextString(assertionCredentials[nextAssertion[0]].userEntity.icon, (short) 0,
(short) assertionCreds[nextAssertion[0]].user.icon.length); (short) assertionCredentials[nextAssertion[0]].userEntity.icon.length);
} }
} else { } else {
// UV not enabled. Don't send extra info apart from the id field // UV not enabled. Don't send extra info apart from the id field
cborEncoder.startMap((short) 1); cborEncoder.startMap((short) 1);
cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2); cborEncoder.encodeTextString(Utf8Strings.UTF8_ID, (short) 0, (short) 2);
cborEncoder.encodeByteString(assertionCreds[nextAssertion[0]].user.id, (short) 0, cborEncoder.encodeByteString(assertionCredentials[nextAssertion[0]].userEntity.id, (short) 0,
(short) assertionCreds[nextAssertion[0]].user.id.length); (short) assertionCredentials[nextAssertion[0]].userEntity.id.length);
} }
// Done tag 4 // Done tag 4
if (mapLen == 5) { if (mapLength == 5) {
cborEncoder.encodeUInt8((byte) 0x05); cborEncoder.encodeUInt8((byte) 0x05);
cborEncoder.encodeUInt8((byte) assertionCreds.length); cborEncoder.encodeUInt8((byte) assertionCredentials.length);
} }
} }
...@@ -865,17 +817,17 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -865,17 +817,17 @@ public class CTAP2 extends Applet implements ExtendedLength {
* I didn't want to pollute the logic over in the process function, and it makes * I didn't want to pollute the logic over in the process function, and it makes
* sense to do both here. * sense to do both here.
* *
* @param apdu * @param apdu apdu buffer
* @return length of data to be processed. 0 if command chaining's not finished. * @return length of data to be processed. 0 if command chaining is not finished.
*/ */
private short doApduIngestion(APDU apdu) { private short doApduIngestion(APDU apdu) {
byte[] buffer = apdu.getBuffer(); byte[] buffer = apdu.getBuffer();
// Receive the APDU // Receive the APDU
vars[4] = apdu.setIncomingAndReceive(); tempVars[4] = apdu.setIncomingAndReceive();
// Get true incoming data length // Get true incoming data length
vars[3] = apdu.getIncomingLength(); tempVars[3] = apdu.getIncomingLength();
// Check if the APDU is too big, we only handle 1200 byte // Check if the APDU is too big, we only handle 1200 byte
if (vars[3] > 1200) { if (tempVars[3] > 1200) {
returnError(apdu, CTAP2_ERR_REQUEST_TOO_LARGE); returnError(apdu, CTAP2_ERR_REQUEST_TOO_LARGE);
return 0; return 0;
} }
...@@ -891,44 +843,44 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -891,44 +843,44 @@ public class CTAP2 extends Applet implements ExtendedLength {
chainRam[0] = 0; chainRam[0] = 0;
} }
// Copy buffer // Copy buffer
chainRam[1] = vars[4]; chainRam[1] = tempVars[4];
// chainRam[0] is the current point in the buffer we start from // chainRam[0] is the current point in the buffer we start from
chainRam[0] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inBuf, chainRam[0], chainRam[1]); chainRam[0] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inputBuffer, chainRam[0], chainRam[1]);
return 0x00; return 0x00;
} else if (isChaining[0]) { } else if (isChaining[0]) {
// Must be the last of the chaining - make the copy and return the length. // Must be the last of the chaining - make the copy and return the length.
chainRam[1] = vars[4]; chainRam[1] = tempVars[4];
chainRam[0] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inBuf, chainRam[0], chainRam[1]); chainRam[0] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inputBuffer, chainRam[0], chainRam[1]);
isChaining[0] = false; isChaining[0] = false;
isChaining[1] = true; isChaining[1] = true;
return chainRam[0]; return chainRam[0];
} else if (vars[3] == 0x01) { } else if (tempVars[3] == 0x01) {
inBuf[0] = buffer[apdu.getOffsetCdata()]; inputBuffer[0] = buffer[apdu.getOffsetCdata()];
return 0x01; return 0x01;
} else if (apdu.getCurrentState() == APDU.STATE_FULL_INCOMING) { } else if (apdu.getCurrentState() == APDU.STATE_FULL_INCOMING) {
// We need to do no more // We need to do no more
// Read the entirety of the buffer into the inBuf // Read the entirety of the buffer into the inBuf
Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inBuf, (short) 0, vars[3]); Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inputBuffer, (short) 0, tempVars[3]);
return vars[4]; return tempVars[4];
} else { } else {
// The APDU needs a multi-stage copy // The APDU needs a multi-stage copy
// First, copy the current data buffer in // First, copy the current data buffer in
// Get the number of bytes in the data buffer that are the Lc, vars[5] will do // Get the number of bytes in the data buffer that are the Lc, vars[5] will do
vars[5] = vars[4]; tempVars[5] = tempVars[4];
// Make the copy, vars[3] is bytes remaining to get // Make the copy, vars[3] is bytes remaining to get
vars[4] = 0; tempVars[4] = 0;
while (vars[3] > 0) { while (tempVars[3] > 0) {
// Copy data // Copy data
vars[4] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inBuf, vars[4], vars[5]); tempVars[4] = Util.arrayCopyNonAtomic(buffer, apdu.getOffsetCdata(), inputBuffer, tempVars[4], tempVars[5]);
// Decrement vars[3] by the bytes copied // Decrement vars[3] by the bytes copied
vars[3] -= vars[5]; tempVars[3] -= tempVars[5];
// Pull more bytes // Pull more bytes
vars[5] = apdu.receiveBytes(apdu.getOffsetCdata()); tempVars[5] = apdu.receiveBytes(apdu.getOffsetCdata());
} }
// Now we're at the end, here, and the commands expect us to give them a data // Now we're at the end, here, and the commands expect us to give them a data
// length. Turns out Le bytes aren't anywhere to be found here. // length. Turns out Le bytes aren't anywhere to be found here.
// The commands use vars[3], so vars[4] will be fine to copy to vars[3]. // The commands use vars[3], so vars[4] will be fine to copy to vars[3].
return vars[4]; return tempVars[4];
} }
} }
...@@ -936,14 +888,14 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -936,14 +888,14 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Gets 256 or fewer bytes from inBuf. * Gets 256 or fewer bytes from inBuf.
* *
* @param apdu * @param apdu apdu buffer
*/ */
public void getData(APDU apdu) { public void getData(APDU apdu) {
if (outChainRam[0] > 256) { if (outChainRam[0] > 256) {
// More to go after this // More to go after this
outChainRam[0] -= 256; outChainRam[0] -= 256;
byte[] buf = apdu.getBuffer(); byte[] buf = apdu.getBuffer();
Util.arrayCopyNonAtomic(inBuf, outChainRam[1], buf, (short) 0, (short) 256); Util.arrayCopyNonAtomic(inputBuffer, outChainRam[1], buf, (short) 0, (short) 256);
apdu.setOutgoingAndSend((short) 0, (short) 256); apdu.setOutgoingAndSend((short) 0, (short) 256);
outChainRam[1] += 256; outChainRam[1] += 256;
if (outChainRam[0] > 255) { if (outChainRam[0] > 255) {
...@@ -956,7 +908,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -956,7 +908,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
} else { } else {
// This is the last message // This is the last message
byte[] buf = apdu.getBuffer(); byte[] buf = apdu.getBuffer();
Util.arrayCopyNonAtomic(inBuf, outChainRam[1], buf, (short) 0, outChainRam[0]); Util.arrayCopyNonAtomic(inputBuffer, outChainRam[1], buf, (short) 0, outChainRam[0]);
apdu.setOutgoingAndSend((short) 0, outChainRam[0]); apdu.setOutgoingAndSend((short) 0, outChainRam[0]);
isOutChaining[0] = false; isOutChaining[0] = false;
outChainRam[0] = 0; outChainRam[0] = 0;
...@@ -969,7 +921,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -969,7 +921,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
* Set chaining flags to send dataLen bytes from inLen via chaining, if * Set chaining flags to send dataLen bytes from inLen via chaining, if
* necessary. * necessary.
* *
* @param apdu * @param apdu apdu buffer
*/ */
public void sendLongChaining(APDU apdu, short dataLen) { public void sendLongChaining(APDU apdu, short dataLen) {
if (dataLen > 256) { if (dataLen > 256) {
...@@ -980,7 +932,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -980,7 +932,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
outChainRam[0] = (short) (dataLen - 256); outChainRam[0] = (short) (dataLen - 256);
// Send the first 256 bytes out // Send the first 256 bytes out
byte[] buf = apdu.getBuffer(); byte[] buf = apdu.getBuffer();
Util.arrayCopyNonAtomic(inBuf, (short) 0, buf, (short) 0, (short) 256); Util.arrayCopyNonAtomic(inputBuffer, (short) 0, buf, (short) 0, (short) 256);
apdu.setOutgoingAndSend((short) 0, (short) 256); apdu.setOutgoingAndSend((short) 0, (short) 256);
outChainRam[1] = 256; outChainRam[1] = 256;
// Throw the 61 xx // Throw the 61 xx
...@@ -996,7 +948,7 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -996,7 +948,7 @@ public class CTAP2 extends Applet implements ExtendedLength {
isOutChaining[0] = false; isOutChaining[0] = false;
apdu.setOutgoing(); apdu.setOutgoing();
apdu.setOutgoingLength(dataLen); apdu.setOutgoingLength(dataLen);
apdu.sendBytesLong(inBuf, (short) 0, dataLen); apdu.sendBytesLong(inputBuffer, (short) 0, dataLen);
ISOException.throwIt(ISO7816.SW_NO_ERROR); ISOException.throwIt(ISO7816.SW_NO_ERROR);
} }
} }
...@@ -1004,16 +956,16 @@ public class CTAP2 extends Applet implements ExtendedLength { ...@@ -1004,16 +956,16 @@ public class CTAP2 extends Applet implements ExtendedLength {
/** /**
* Checks if chaining is set for U2FApplet * Checks if chaining is set for U2FApplet
* *
* @return * @return if it is chaining
*/ */
public boolean isChaining() { public boolean isChaining() {
return isOutChaining[0]; return isOutChaining[0];
} }
private void getCert(APDU apdu) { private void getCert(APDU apdu) {
inBuf[0] = 0x00; inputBuffer[0] = 0x00;
vars[0] = (short) (attestationKeyPair.getCert(inBuf, (short) 1) + 1); tempVars[0] = (short) (attestationKeyPair.getCert(inputBuffer, (short) 1) + 1);
sendLongChaining(apdu, vars[0]); sendLongChaining(apdu, tempVars[0]);
} }
public void process(APDU apdu) throws ISOException { public void process(APDU apdu) throws ISOException {
......
package com.josh.vku2f;
public class CTAP2ErrorCode {
public static final byte CTAP1_ERR_SUCCESS = (byte) 0x00;
public static final byte CTAP1_ERR_INVALID_COMMAND = (byte) 0x01;
public static final byte CTAP1_ERR_INVALID_PARAMETER = (byte) 0x02;
public static final byte CTAP1_ERR_INVALID_LENGTH = (byte) 0x03;
public static final byte CTAP1_ERR_INVALID_SEQ = (byte) 0x04;
public static final byte CTAP1_ERR_TIMEOUT = (byte) 0x05;
public static final byte CTAP1_ERR_CHANNEL_BUSY = (byte) 0x06;
public static final byte CTAP1_ERR_LOCK_REQUIRED = (byte) 0x0A;
public static final byte CTAP1_ERR_INVALID_CHANNEL = (byte) 0x0B;
public static final byte CTAP1_ERR_OTHER = (byte) 0x7F;
public static final byte CTAP2_ERR_CBOR_UNEXPECTED_TYPE = (byte) 0x11;
public static final byte CTAP2_ERR_INVALID_CBOR = (byte) 0x12;
public static final byte CTAP2_ERR_MISSING_PARAMETER = (byte) 0x14;
public static final byte CTAP2_ERR_LIMIT_EXCEEDED = (byte) 0x15;
public static final byte CTAP2_ERR_UNSUPPORTED_EXTENSION = (byte) 0x16;
public static final byte CTAP2_ERR_CREDENTIAL_EXCLUDED = (byte) 0x19;
public static final byte CTAP2_ERR_PROCESSING = (byte) 0x21;
public static final byte CTAP2_ERR_INVALID_CREDENTIAL = (byte) 0x22;
public static final byte CTAP2_ERR_USER_ACTION_PENDING = (byte) 0x23;
public static final byte CTAP2_ERR_OPERATION_PENDING = (byte) 0x24;
public static final byte CTAP2_ERR_NO_OPERATIONS = (byte) 0x25;
public static final byte CTAP2_ERR_UNSUPPORTED_ALGORITHM = (byte) 0x26;
public static final byte CTAP2_ERR_OPERATION_DENIED = (byte) 0x27;
public static final byte CTAP2_ERR_KEY_STORE_FULL = (byte) 0x28;
public static final byte CTAP2_ERR_NO_OPERATION_PENDING = (byte) 0x2A;
public static final byte CTAP2_ERR_UNSUPPORTED_OPTION = (byte) 0x2B;
public static final byte CTAP2_ERR_INVALID_OPTION = (byte) 0x2C;
public static final byte CTAP2_ERR_KEEPALIVE_CANCEL = (byte) 0x2D;
public static final byte CTAP2_ERR_NO_CREDENTIALS = (byte) 0x2E;
public static final byte CTAP2_ERR_USER_ACTION_TIMEOUT = (byte) 0x2F;
public static final byte CTAP2_ERR_NOT_ALLOWED = (byte) 0x30;
public static final byte CTAP2_ERR_PIN_INVALID = (byte) 0x31;
public static final byte CTAP2_ERR_PIN_BLOCKED = (byte) 0x32;
public static final byte CTAP2_ERR_PIN_AUTH_INVALID = (byte) 0x33;
public static final byte CTAP2_ERR_PIN_AUTH_BLOCKED = (byte) 0x34;
public static final byte CTAP2_ERR_PIN_NOT_SET = (byte) 0x35;
public static final byte CTAP2_ERR_PIN_REQUIRED = (byte) 0x36;
public static final byte CTAP2_ERR_PIN_POLICY_VIOLATION = (byte) 0x37;
public static final byte CTAP2_ERR_PIN_TOKEN_EXPIRED = (byte) 0x38;
public static final byte CTAP2_ERR_REQUEST_TOO_LARGE = (byte) 0x39;
public static final byte CTAP2_ERR_ACTION_TIMEOUT = (byte) 0x3A;
public static final byte CTAP2_ERR_UP_REQUIRED = (byte) 0x3B;
}
...@@ -18,38 +18,40 @@ package com.josh.vku2f; ...@@ -18,38 +18,40 @@ package com.josh.vku2f;
import javacard.framework.JCSystem; import javacard.framework.JCSystem;
import javacard.framework.UserException; import javacard.framework.UserException;
import static com.josh.vku2f.CTAP2ErrorCode.*;
/** /**
* Dynamically resizable credential storage array. Gracefully handles space errors. * Dynamically resizable credential storage array. Gracefully handles space errors.
*/ */
public class CredentialArray { public class CredentialArray {
private StoredCredential[] creds; private StoredCredential[] credentials;
private boolean[] slotStatus; private boolean[] slotStatus;
private short size; private short size;
private short counter; private short i; // for loop counter
private short count = 0;//the number of creds in the array private short count = 0;//the number of creds in the array
/** /**
* Constructor for a CredentialArray. * Constructor for a CredentialArray.
* @param initialSize Initial sizing for the CredentialArray. * @param initialSize Initial sizing for the CredentialArray.
*/ */
public CredentialArray(short initialSize) { public CredentialArray(short initialSize) {
creds = new StoredCredential[initialSize]; credentials = new StoredCredential[initialSize];
slotStatus = new boolean[initialSize]; slotStatus = new boolean[initialSize];
size = initialSize; size = initialSize;
} }
/** /**
* Adds a new credential to the first free slot, or overwrites if a matching rp and user id matches. * Adds a new credential to the first free slot, or overwrites if a matching rp and user id matches.
* @param in the StoredCredential object to be stored. * @param newCredential the StoredCredential object to be stored.
*/ */
public void addCredential(StoredCredential in) throws UserException{ public void addCredential(StoredCredential newCredential) throws UserException{
try { try {
short slot = alreadyExists(in); short slot = checkExists(newCredential);
creds[slot] = in; credentials[slot] = newCredential;
slotStatus[slot] = true; slotStatus[slot] = true;
count = (short)(slot + 1); count = (short)(slot + 1);
} catch (Exception e) { } catch (Exception e) {
UserException.throwIt(CTAP2.CTAP2_ERR_KEY_STORE_FULL); UserException.throwIt(CTAP2_ERR_KEY_STORE_FULL);
} }
} }
/** /**
...@@ -60,10 +62,10 @@ public class CredentialArray { ...@@ -60,10 +62,10 @@ public class CredentialArray {
* @ return * @ return
*/ */
public StoredCredential getCredential(byte[] rpId, short rpOff, short rpLen, byte[] userId, short userOff, short userLen) { public StoredCredential getCredential(byte[] rpId, short rpOff, short rpLen, byte[] userId, short userOff, short userLen) {
for(counter = 0; counter < size; counter++) { for(i = 0; i < size; i++) {
// Check the slot status, if the RP matches, and then if the user matches. If so, return the credential. // Check the slot status, if the RP matches, and then if the user matches. If so, return the credential.
if(slotStatus[counter] && creds[counter].rp.checkId(rpId, rpOff, rpLen) && creds[counter].user.checkId(userId, userOff, userLen)) { if(slotStatus[i] && credentials[i].rpEntity.checkId(rpId, rpOff, rpLen) && credentials[i].userEntity.checkId(userId, userOff, userLen)) {
return creds[counter]; return credentials[i];
} }
} }
return null; return null;
...@@ -75,42 +77,43 @@ public class CredentialArray { ...@@ -75,42 +77,43 @@ public class CredentialArray {
* Confirms there is no already existing discoverable credential - if it finds one, it returns its location for overwriting. * Confirms there is no already existing discoverable credential - if it finds one, it returns its location for overwriting.
* @return the location of a discoverable credential already matching the RP and User IDs, or the first free slot otherwise. * @return the location of a discoverable credential already matching the RP and User IDs, or the first free slot otherwise.
*/ */
public short alreadyExists(StoredCredential cred) { public short checkExists(StoredCredential newCredential) {
for(counter = 0; counter < size; counter++) { for(i = 0; i < size; i++) {
// Check the slot status, if the RP matches, and then if the user matches. If so, return the slot to use. // Check the slot status, if the RP matches, and then if the user matches. If so, return the slot to use.
if(slotStatus[counter] && creds[counter].rp.checkId(cred.rp) && creds[counter].user.checkId(cred.user)) { if(slotStatus[i] &&
return counter; credentials[i].rpEntity.checkId(newCredential.rpEntity) &&
credentials[i].userEntity.checkId(newCredential.userEntity)) {
return i;
} }
} }
// Find the first free slot // Find the first free slot
for(counter = 0; counter < size; counter++) { for(i = 0; i < size; i++) {
if(!slotStatus[counter]) { if(!slotStatus[i]) {
return counter; return i;
} }
} }
// No free slots // No free slots
// Add more // Add more
StoredCredential[] tmp = new StoredCredential[size]; StoredCredential[] tmp = new StoredCredential[size];
boolean[] tmpStatus = new boolean[size]; boolean[] tmpStatus = new boolean[size];
for(counter = 0; counter < size; counter++) { for(i = 0; i < size; i++) {
// SonarLint throws an error here, but JavaCard can only copy byte arrays // SonarLint throws an error here, but JavaCard can only copy byte arrays
tmp[counter] = creds[counter]; tmp[i] = credentials[i];
tmpStatus[counter] = slotStatus[counter]; tmpStatus[i] = slotStatus[i];
} }
creds = new StoredCredential[(short) (size*2)]; credentials = new StoredCredential[(short) (size*2)];
slotStatus = new boolean[(short) (size*2)]; slotStatus = new boolean[(short) (size*2)];
for(counter = 0; counter < size; counter++) { for(i = 0; i < size; i++) {
creds[counter] = tmp[counter]; credentials[i] = tmp[i];
slotStatus[counter] = tmpStatus[counter]; slotStatus[i] = tmpStatus[i];
} }
// Actually double the size.... // Actually double the size....
size *= (short) 2; size *= (short) 2;
// Delete objects we used to copy // Delete objects we used to copy
JCSystem.requestObjectDeletion(); JCSystem.requestObjectDeletion();
// Return the first free slot in the new array, which is going to be the counter plus 1 // Return the first free slot in the new array, which is going to be the counter plus 1
return (short) (counter + (short) 1); return ++i;
} }
/** /**
* Get the size of the array. * Get the size of the array.
...@@ -128,8 +131,8 @@ public class CredentialArray { ...@@ -128,8 +131,8 @@ public class CredentialArray {
* @param position the position to get. * @param position the position to get.
* @return the credential, or null. * @return the credential, or null.
*/ */
public StoredCredential getCred(short position) { public StoredCredential get(short position) {
return creds[position]; return credentials[position];
} }
} }
...@@ -21,10 +21,10 @@ import javacard.security.RandomData; ...@@ -21,10 +21,10 @@ import javacard.security.RandomData;
/** /**
* Provide a way to handle static RNGs. * Provide a way to handle static RNGs.
*/ */
public class ServerKeyCrypto { public class Random {
private static RandomData rng; private static RandomData rng;
public static RandomData getRng() { public static RandomData getInstance() {
if(rng == null) { if(rng == null) {
rng = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); rng = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
} }
......
...@@ -23,27 +23,26 @@ import javacard.security.RandomData; ...@@ -23,27 +23,26 @@ import javacard.security.RandomData;
// Abstract class to represent and perform actions with a stored credential // Abstract class to represent and perform actions with a stored credential
public abstract class StoredCredential { public abstract class StoredCredential {
private static RandomData rng; private static RandomData randomData;
byte[] id; byte[] credentialId;
KeyPair kp; KeyPair keyPair;
PublicKeyCredentialUserEntity user; PublicKeyCredentialUserEntity userEntity;
PublicKeyCredentialRpEntity rp; PublicKeyCredentialRpEntity rpEntity;
private byte[] sigCounter; private final byte[] signingCounter;
protected boolean initialised; protected boolean initialised;
protected byte[] credRandom; protected byte[] credRandom;
protected boolean hmacEnabled; protected boolean hmacEnabled;
protected StoredCredential() { protected StoredCredential() {
if(rng == null) { if(randomData == null) {
rng = ServerKeyCrypto.getRng(); randomData = Random.getInstance();
} }
id = new byte[16]; credentialId = new byte[16];
rng.generateData(id, (short) 0, (short) 16); randomData.generateData(credentialId, (short) 0, (short) 16);
sigCounter = new byte[4]; signingCounter = new byte[4];
initialised = false; initialised = false;
hmacEnabled = false; hmacEnabled = false;
} }
// Does the HMAC secret stuff // Does the HMAC secret stuff
public short doHmacSecret(byte[] inBuf, short inOff, short inLen) { public short doHmacSecret(byte[] inBuf, short inOff, short inLen) {
...@@ -55,7 +54,7 @@ public abstract class StoredCredential { ...@@ -55,7 +54,7 @@ public abstract class StoredCredential {
public boolean initialiseCredSecret() { public boolean initialiseCredSecret() {
// Generate the actual credRandom - this is the same across all credentials // Generate the actual credRandom - this is the same across all credentials
credRandom = new byte[32]; credRandom = new byte[32];
rng.generateData(credRandom, (short) 0, (short) 32); randomData.generateData(credRandom, (short) 0, (short) 32);
hmacEnabled = true; hmacEnabled = true;
return true; return true;
} }
...@@ -66,11 +65,11 @@ public abstract class StoredCredential { ...@@ -66,11 +65,11 @@ public abstract class StoredCredential {
if(inLen != (short) 16) { if(inLen != (short) 16) {
return false; return false;
} }
return Util.arrayCompare(id, (short) 0, inBuf, inOff, inLen) == 0; return Util.arrayCompare(credentialId, (short) 0, inBuf, inOff, inLen) == 0;
} }
public boolean[] getPresentUser() { public boolean[] getPresentUser() {
return user.dataPresent; return userEntity.dataPresent;
} }
/** /**
* Increment the counter. * Increment the counter.
...@@ -80,20 +79,20 @@ public abstract class StoredCredential { ...@@ -80,20 +79,20 @@ public abstract class StoredCredential {
JCSystem.beginTransaction(); JCSystem.beginTransaction();
for(short i = 3; i > 1; i--) { for(short i = 3; i > 1; i--) {
if(sigCounter[i] == 0xFF) { if(signingCounter[i] == 0xFF) {
sigCounter[(short) (i-1)]++; signingCounter[(short) (i-1)]++;
sigCounter[i] = 0x00; signingCounter[i] = 0x00;
JCSystem.commitTransaction(); JCSystem.commitTransaction();
return; return;
} }
} }
if(sigCounter[0] == 0xFF && sigCounter[1] == 0xFF && sigCounter[2] == 0xFF && sigCounter[3] == 0xFF) { if(signingCounter[0] == 0xFF && signingCounter[1] == 0xFF && signingCounter[2] == 0xFF && signingCounter[3] == 0xFF) {
// Overflow, roll to 0 // Overflow, roll to 0
Util.arrayFillNonAtomic(sigCounter, (short) 0, (short) 4, (byte) 0x00); Util.arrayFillNonAtomic(signingCounter, (short) 0, (short) 4, (byte) 0x00);
JCSystem.commitTransaction(); JCSystem.commitTransaction();
return; return;
} }
sigCounter[3]++; signingCounter[3]++;
JCSystem.commitTransaction(); JCSystem.commitTransaction();
} }
/** /**
...@@ -103,7 +102,7 @@ public abstract class StoredCredential { ...@@ -103,7 +102,7 @@ public abstract class StoredCredential {
* @returns length * @returns length
*/ */
public short readCounter(byte[] buf, short bufOff) { public short readCounter(byte[] buf, short bufOff) {
Util.arrayCopy(sigCounter, (short) 0, buf, bufOff, (short) 4); Util.arrayCopy(signingCounter, (short) 0, buf, bufOff, (short) 4);
return (short) 4; return (short) 4;
} }
...@@ -145,7 +144,7 @@ public abstract class StoredCredential { ...@@ -145,7 +144,7 @@ public abstract class StoredCredential {
buf[(short) (off+16)] = 0x00; buf[(short) (off+16)] = 0x00;
buf[(short) (off+17)] = 0x10; buf[(short) (off+17)] = 0x10;
// Copy the credential ID // Copy the credential ID
Util.arrayCopy(id, (short) 0, buf, (short) (off+18), (short) 16); Util.arrayCopy(credentialId, (short) 0, buf, (short) (off+18), (short) 16);
} }
} }
...@@ -29,13 +29,13 @@ public class StoredES256Credential extends StoredCredential { ...@@ -29,13 +29,13 @@ public class StoredES256Credential extends StoredCredential {
public StoredES256Credential(AuthenticatorMakeCredential inputData) { public StoredES256Credential(AuthenticatorMakeCredential inputData) {
// Generate a new ES256 credential // Generate a new ES256 credential
kp = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256); keyPair = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
KeyParams.sec256r1params((ECKey) kp.getPublic()); KeyParams.sec256r1params((ECKey) keyPair.getPublic());
kp.genKeyPair(); keyPair.genKeyPair();
user = inputData.getUser(); userEntity = inputData.getUser();
rp = inputData.getRp(); rpEntity = inputData.getRp();
sig = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false); sig = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
sig.init(kp.getPrivate(), Signature.MODE_SIGN); sig.init(keyPair.getPrivate(), Signature.MODE_SIGN);
} }
...@@ -65,7 +65,7 @@ public class StoredES256Credential extends StoredCredential { ...@@ -65,7 +65,7 @@ public class StoredES256Credential extends StoredCredential {
w = new byte[65]; w = new byte[65];
} }
((ECPublicKey) kp.getPublic()).getW(w, (short) 0); ((ECPublicKey) keyPair.getPublic()).getW(w, (short) 0);
// Form the common params // Form the common params
doAttestationCommon(buf, off); doAttestationCommon(buf, off);
enc.init(buf, (short) (off + 34), (short) 1000); enc.init(buf, (short) (off + 34), (short) 1000);
......
...@@ -26,12 +26,12 @@ public class StoredPS256Credential extends StoredCredential { ...@@ -26,12 +26,12 @@ public class StoredPS256Credential extends StoredCredential {
public StoredPS256Credential(AuthenticatorMakeCredential inputData) { public StoredPS256Credential(AuthenticatorMakeCredential inputData) {
// Generate a new RS256 credential // Generate a new RS256 credential
kp = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_2048); keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_2048);
kp.genKeyPair(); keyPair.genKeyPair();
user = inputData.getUser(); userEntity = inputData.getUser();
rp = inputData.getRp(); rpEntity = inputData.getRp();
kpSignature = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1_PSS, false); kpSignature = Signature.getInstance(Signature.ALG_RSA_SHA_256_PKCS1_PSS, false);
kpSignature.init(kp.getPrivate(), Signature.MODE_SIGN); kpSignature.init(keyPair.getPrivate(), Signature.MODE_SIGN);
} }
...@@ -69,12 +69,12 @@ public class StoredPS256Credential extends StoredCredential { ...@@ -69,12 +69,12 @@ public class StoredPS256Credential extends StoredCredential {
enc.encodeNegativeUInt8((byte) 0x00); enc.encodeNegativeUInt8((byte) 0x00);
// Write the modulus // Write the modulus
short start = enc.startByteString((short) 256); short start = enc.startByteString((short) 256);
((RSAPublicKey) kp.getPublic()).getModulus(buf, start); ((RSAPublicKey) keyPair.getPublic()).getModulus(buf, start);
// Exponent tag // Exponent tag
enc.encodeNegativeUInt8((byte) 0x01); enc.encodeNegativeUInt8((byte) 0x01);
// Write the exponent // Write the exponent
start = enc.startByteString((short) 3); start = enc.startByteString((short) 3);
((RSAPublicKey) kp.getPublic()).getExponent(buf, start); ((RSAPublicKey) keyPair.getPublic()).getExponent(buf, start);
return 305; return 305;
} }
......
...@@ -26,12 +26,12 @@ public class StoredRS256Credential extends StoredCredential { ...@@ -26,12 +26,12 @@ public class StoredRS256Credential extends StoredCredential {
public StoredRS256Credential(AuthenticatorMakeCredential inputData) { public StoredRS256Credential(AuthenticatorMakeCredential inputData) {
// Generate a new RS256 credential // Generate a new RS256 credential
kp = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_2048); keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, KeyBuilder.LENGTH_RSA_2048);
kp.genKeyPair(); keyPair.genKeyPair();
user = inputData.getUser(); userEntity = inputData.getUser();
rp = inputData.getRp(); rpEntity = inputData.getRp();
kpSignature = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false); kpSignature = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
kpSignature.init(kp.getPrivate(), Cipher.MODE_ENCRYPT); kpSignature.init(keyPair.getPrivate(), Cipher.MODE_ENCRYPT);
} }
...@@ -66,12 +66,12 @@ public class StoredRS256Credential extends StoredCredential { ...@@ -66,12 +66,12 @@ public class StoredRS256Credential extends StoredCredential {
enc.encodeNegativeUInt8((byte) 0x00); enc.encodeNegativeUInt8((byte) 0x00);
// Write the modulus // Write the modulus
short start = enc.startByteString((short) 256); short start = enc.startByteString((short) 256);
((RSAPublicKey) kp.getPublic()).getModulus(buf, start); ((RSAPublicKey) keyPair.getPublic()).getModulus(buf, start);
// Exponent tag // Exponent tag
enc.encodeNegativeUInt8((byte) 0x01); enc.encodeNegativeUInt8((byte) 0x01);
// Write the exponent // Write the exponent
start = enc.startByteString((short) 3); start = enc.startByteString((short) 3);
((RSAPublicKey) kp.getPublic()).getExponent(buf, start); ((RSAPublicKey) keyPair.getPublic()).getExponent(buf, start);
return 306; return 306;
} }
......
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