@@ -992,6 +992,17 @@ private short truncateRPId(byte[] rpIdBuf, short rpIdIdx, short rpIdLen, byte[]
992992 return rpIdLen ;
993993 }
994994
995+ /**
996+ * Handspun implementation of HMAC-SHA256, to work around lack of hardware support
997+ *
998+ * @param keyBuff Buffer containing 32-byte-long private key
999+ * @param keyOff Offset of private key in key buffer
1000+ * @param content Buffer containing arbitrary-length content to be HMACed
1001+ * @param contentOff Offset of content in buffer
1002+ * @param contentLen Length of content
1003+ * @param outputBuff Buffer into which output should be written - must have 32 bytes available
1004+ * @param outputOff Write index into output buffer
1005+ */
9951006 private void hmacSha256 (byte [] keyBuff , short keyOff ,
9961007 byte [] content , short contentOff , short contentLen ,
9971008 byte [] outputBuff , short outputOff ) {
@@ -1023,6 +1034,16 @@ private void hmacSha256(byte[] keyBuff, short keyOff,
10231034 scratchRelease (scratchAmt );
10241035 }
10251036
1037+ /**
1038+ * Uses the currently-set pinToken to hash some data and compare against a verification value
1039+ *
1040+ * @param apdu Request/response object
1041+ * @param content Buffer containing content to HMAC using the pinToken
1042+ * @param contentIdx Index of content in given buffer
1043+ * @param contentLen Length of content
1044+ * @param checkAgainst Buffer containing "correct" hash we're looking for
1045+ * @param checkIdx Index of correct hash in corresponding buffer
1046+ */
10261047 private void checkPinTokenProtocolOne (APDU apdu , byte [] content , short contentIdx , short contentLen ,
10271048 byte [] checkAgainst , short checkIdx ) {
10281049 short scratchAmt = (short ) 32 ;
@@ -1049,11 +1070,19 @@ private void checkPinTokenProtocolOne(APDU apdu, byte[] content, short contentId
10491070 scratchRelease (scratchAmt );
10501071 }
10511072
1073+ /**
1074+ * Consumes an incoming pinAuth block and checks it matches our set pinToken.
1075+ *
1076+ * @param apdu Request/response object
1077+ * @param readIdx Read index into bufferMem pointing to a 16-byte array (pinAuth)
1078+ * @param clientDataHashIdx Index in bufferMem of the hash of the clientData object, as given by the platform
1079+ *
1080+ * @return New read index into bufferMem after consuming the pinAuth options block
1081+ */
10521082 private short verifyPinAuth (APDU apdu , short readIdx , short clientDataHashIdx ) {
1053- if (bufferMem [readIdx ] != 0x50 ) { // byte array, 16 bytes long
1083+ if (bufferMem [readIdx ++ ] != 0x50 ) { // byte array, 16 bytes long
10541084 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_CBOR_UNEXPECTED_TYPE );
10551085 }
1056- readIdx ++;
10571086
10581087 checkPinTokenProtocolOne (apdu , bufferMem , clientDataHashIdx , CLIENT_DATA_HASH_LEN ,
10591088 bufferMem , readIdx );
@@ -1063,6 +1092,17 @@ private short verifyPinAuth(APDU apdu, short readIdx, short clientDataHashIdx) {
10631092 return readIdx ;
10641093 }
10651094
1095+ /**
1096+ * Consumes a CBOR block of public key data, and checks if it represents a supported algorithm.
1097+ * After call, tempShorts[IDX_RESET_FOUND_KEY_MATCH] will be true if the key is compatible. It should be set
1098+ * to false prior to call
1099+ *
1100+ * @param apdu Request/response object
1101+ * @param readIdx Read index into bufferMem
1102+ * @param lc Length of incoming request, as sent by the platform
1103+ *
1104+ * @return New read index into bufferMem after consuming public key block
1105+ */
10661106 private short checkIfPubKeyBlockSupported (APDU apdu , short readIdx , short lc ) {
10671107 if (bufferMem [readIdx ++] != (byte ) 0xA2 ) {
10681108 sendErrorByte (apdu , FIDOConstants .CTAP2_ERR_CBOR_UNEXPECTED_TYPE );
@@ -1114,29 +1154,40 @@ private short checkIfPubKeyBlockSupported(APDU apdu, short readIdx, short lc) {
11141154 return readIdx ;
11151155 }
11161156
1117- private short writeADBasic (short adLen , short outputLen , byte flags , byte [] rpIdBuffer , short rpIdOffset ) {
1157+ /**
1158+ * Write the portions of an authData block that are used for both makeCredential and getAssertion
1159+ *
1160+ * @param adLen Length of the overall AD block
1161+ * @param writeIdx Write index into bufferMem
1162+ * @param flags CTAP2 "flags" byte value
1163+ * @param rpIdBuffer Buffer containing a hash of the RP ID
1164+ * @param rpIdOffset Offset of the RP ID hash in the given buffer
1165+ *
1166+ * @return New write index into bufferMem after serializing AD block
1167+ */
1168+ private short writeADBasic (short adLen , short writeIdx , byte flags , byte [] rpIdBuffer , short rpIdOffset ) {
11181169 short adAddlBytes ;
11191170
11201171 if (adLen < 24 ) {
1121- bufferMem [outputLen ++] = (byte )(0x50 + adLen );
1172+ bufferMem [writeIdx ++] = (byte )(0x50 + adLen );
11221173 adAddlBytes = 1 ;
11231174 } else if (adLen < 256 ) {
1124- bufferMem [outputLen ++] = 0x58 ; // byte string, with one-byte length
1125- bufferMem [outputLen ++] = (byte ) adLen ;
1175+ bufferMem [writeIdx ++] = 0x58 ; // byte string, with one-byte length
1176+ bufferMem [writeIdx ++] = (byte ) adLen ;
11261177 adAddlBytes = 2 ;
11271178 } else {
1128- bufferMem [outputLen ++] = 0x59 ; // byte string, with two-byte length
1129- outputLen = Util .setShort (bufferMem , outputLen , adLen );
1179+ bufferMem [writeIdx ++] = 0x59 ; // byte string, with two-byte length
1180+ writeIdx = Util .setShort (bufferMem , writeIdx , adLen );
11301181 adAddlBytes = 3 ;
11311182 }
11321183
11331184 // RPID hash
1134- outputLen = Util .arrayCopyNonAtomic (rpIdBuffer , rpIdOffset , bufferMem , outputLen , RP_HASH_LEN );
1185+ writeIdx = Util .arrayCopyNonAtomic (rpIdBuffer , rpIdOffset , bufferMem , writeIdx , RP_HASH_LEN );
11351186
1136- bufferMem [outputLen ++] = flags ; // flags
1187+ bufferMem [writeIdx ++] = flags ; // flags
11371188
11381189 // counter
1139- outputLen = encodeCounter (bufferMem , outputLen );
1190+ writeIdx = encodeCounter (bufferMem , writeIdx );
11401191 incrementCounter ();
11411192
11421193 return adAddlBytes ;
@@ -2424,6 +2475,13 @@ private void credManagementSubcommand(APDU apdu, short lc, short readIdx) {
24242475 }
24252476 }
24262477
2478+ /**
2479+ * Deletes a resident key by its credential ID blob, and updates bookkeeping state to match
2480+ *
2481+ * @param apdu Request/response object
2482+ * @param readOffset Read index into bufferMem
2483+ * @param lc Length of incoming request, as sent by the platform
2484+ */
24272485 private void handleDeleteCred (APDU apdu , short readOffset , short lc ) {
24282486 tempShorts [IDX_CRED_ITERATION_POINTER ] = 0 ;
24292487 tempShorts [IDX_RP_ITERATION_POINTER ] = 0 ;
@@ -2518,10 +2576,11 @@ private void handleDeleteCred(APDU apdu, short readOffset, short lc) {
25182576 /**
25192577 * Enumerates creds
25202578 *
2521- * @param apdu
2522- * @param bufferIdx
2523- * @param startCredIdx
2524- * @param lc
2579+ * @param apdu Request/response object
2580+ * @param bufferIdx Read index into bufferMem
2581+ * @param startCredIdx Offset of the first credential to consider, in the resident key slots.
2582+ * If zero, we're starting a new iteration
2583+ * @param lc Length of the incoming request, as sent by the platform
25252584 */
25262585 private void handleEnumerateCreds (APDU apdu , short bufferIdx , short startCredIdx , short lc ) {
25272586 tempShorts [IDX_CRED_ITERATION_POINTER ] = 0 ;
0 commit comments