From d630363608770abfef641a22c0a4cd155a61d333 Mon Sep 17 00:00:00 2001 From: TNEd Date: Tue, 6 Jun 2017 11:22:47 +0200 Subject: [PATCH] Fixed OTP and fuses to avoid clonedetection --- .../Application/MifareUltralight.c | 83 +++++++++++++++++-- 1 file changed, 74 insertions(+), 9 deletions(-) diff --git a/Firmware/Chameleon-Mini/Application/MifareUltralight.c b/Firmware/Chameleon-Mini/Application/MifareUltralight.c index a7bb3d16..1d4d6def 100644 --- a/Firmware/Chameleon-Mini/Application/MifareUltralight.c +++ b/Firmware/Chameleon-Mini/Application/MifareUltralight.c @@ -50,6 +50,9 @@ #define PAGE_WRITE_MIN 0x02 #define PAGE_WRITE_MAX 0x0F +#define PAGE_LOCK_BYTES 0x02 +#define PAGE_OTP_FUSE 0x03 + #define BYTES_PER_COMPAT_WRITE 16 static enum { @@ -83,6 +86,7 @@ void MifareUltralightAppTask(void) uint16_t MifareUltralightAppProcess(uint8_t* Buffer, uint16_t BitCount) { + uint8_t lockbytes[BYTES_PER_READ]; uint8_t Cmd = Buffer[0]; switch(State) { @@ -167,25 +171,86 @@ uint16_t MifareUltralightAppProcess(uint8_t* Buffer, uint16_t BitCount) Buffer[0] = NAK_CRC_ERROR; return NAK_FRAME_SIZE; } - } else if (Cmd == CMD_WRITE) { + } else if (Cmd == CMD_WRITE ) { /* This is a write command containing 4 bytes of data that * should be written to the given page address. */ uint8_t PageAddress = Buffer[1]; if (ISO14443ACheckCRCA(Buffer, CMD_WRITE_FRAME_SIZE)) { /* CRC check passed */ + /* READ page 2 & 3 for LockBytes and fuses */ + MemoryReadBlock(&lockbytes, PAGE_LOCK_BYTES * BYTES_PER_PAGE , BYTES_PER_READ); + /* test if lockbytes are not reset */ + if ( PageAddress== PAGE_LOCK_BYTES) { + /* test if block 4-9 lockbits are writable if not aspect the same bits*/ + if ( ((lockbytes[2]& 0x02)== 0x02) + && ((Buffer[4] & 0xF0) ^ (lockbytes[2] & 0xF0)) == 0 + && ((Buffer[5] & 0x03) ^ (lockbytes[3] & 0x03)) == 0){ + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + /* test if block 10-15 lockbits are writable if not aspect the same bits*/ + if ( ((lockbytes[2]&0x04)==0x04) + && ((Buffer[5] & 0xFC) ^ (lockbytes[3] & 0xFC)) == 0){ + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + /* test if no lockbits are reset to 0 */ + if ( ((Buffer[4] ^ lockbytes[2]) & lockbytes[2])!=0 + || ((Buffer[5] ^ lockbytes[3]) & lockbytes[3])!=0) { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + /* ToDo: should only write after a next WUPA or REQA statement */ + /* Only write OTP structure */ + MemoryWriteBlock(&Buffer[4], (PageAddress * BYTES_PER_PAGE) + 2, 2); + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } + if ( PageAddress== PAGE_OTP_FUSE) { + /* test if no Fuse bits are locked */ + if ( (lockbytes[2]&1)==1 ){ + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + /* OR the bytes to fuse to 1*/ + Buffer[2] = Buffer[2] | lockbytes[4]; + Buffer[3] = Buffer[3] | lockbytes[5]; + Buffer[4] = Buffer[4] | lockbytes[6]; + Buffer[5] = Buffer[5] | lockbytes[7]; + MemoryWriteBlock(&Buffer[2], PageAddress * BYTES_PER_PAGE, BYTES_PER_WRITE); + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } if ( (PageAddress >= PAGE_WRITE_MIN) && (PageAddress <= PAGE_WRITE_MAX) ) { /* PageAddress is within bounds. */ - if (!ActiveConfiguration.ReadOnly) { - MemoryWriteBlock(&Buffer[2], PageAddress * BYTES_PER_PAGE, BYTES_PER_WRITE); - } else { - /* If the chameleon is in read only mode, it silently - * ignores any attempt to write data. */ - } + /* respect OTP */ + if ( ((((int)0x0001 << PageAddress) & ((int)lockbytes[2] + ((int)lockbytes[3] <<8 ))) & 0xFFFF) == 0x0000 ) { + if (!ActiveConfiguration.ReadOnly) { + MemoryWriteBlock(&Buffer[2], PageAddress * BYTES_PER_PAGE, BYTES_PER_WRITE); + } else { + /* If the chameleon is in read only mode, it silently + * ignores any attempt to write data. */ + } + + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + + } else { + + Buffer[0] = NAK_INVALID_ARG; + Buffer[1] = (((int)lockbytes[2] + ((int)lockbytes[3] <<8 )) & 0xFF00) >> 8; + Buffer[2] = (((int)lockbytes[2] + ((int)lockbytes[3] <<8 )) & 0x00FF) >> 0; + Buffer[3] = (((int)0x0001 << PageAddress) & 0xFF00) >> 8; + Buffer[4] = (((int)0x0001 << PageAddress) & 0x00FF) >> 0; + Buffer[5] = (((int)0x0001 << PageAddress) & ((int)lockbytes[2] + ((int)lockbytes[3] <<8 )) & 0xFF00) >> 8; + Buffer[6] = (((int)0x0001 << PageAddress) & ((int)lockbytes[2] + ((int)lockbytes[3] <<8 )) & 0x00FF) >> 0; + return 7*8; + + } + - Buffer[0] = ACK_VALUE; - return ACK_FRAME_SIZE; } else { Buffer[0] = NAK_INVALID_ARG;