]>
git.zerfleddert.de Git - proxmark3-svn/blob - client/mifare/ndef.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2019 Merlok
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
7 //-----------------------------------------------------------------------------
8 // NFC Data Exchange Format (NDEF) functions
9 //-----------------------------------------------------------------------------
14 #include "crypto/asn1utils.h"
18 #define STRBOOL(p) ((p) ? "+" : "-")
20 static const char *TypeNameFormat_s
[] = {
24 "Absolute URI Record",
31 static const char *ndefSigType_s
[] = {
32 "Not present", // No signature present
33 "RSASSA_PSS_SHA_1", // PKCS_1
34 "RSASSA_PKCS1_v1_5_WITH_SHA_1", // PKCS_1
40 static const char *ndefCertificateFormat_s
[] = {
46 static const char *URI_s
[] = {
48 "http://www.", // 0x01
49 "https://www.", // 0x02
54 "ftp://anonymous:anonymous@", // 0x07
75 "irdaobex://", // 0x1C
77 "urn:epc:id:", // 0x1E
78 "urn:epc:tag:", // 0x1F
79 "urn:epc:pat:", // 0x20
80 "urn:epc:raw:", // 0x21
85 uint16_t ndefTLVGetLength(uint8_t *data
, size_t *indx
) {
87 if (data
[0] == 0xff) {
88 len
= (data
[1] << 8) + data
[2];
98 int ndefDecodeHeader(uint8_t *data
, size_t datalen
, NDEFHeader_t
*header
) {
100 header
->Payload
= NULL
;
103 header
->MessageBegin
= data
[0] & 0x80;
104 header
->MessageEnd
= data
[0] & 0x40;
105 header
->ChunkFlag
= data
[0] & 0x20;
106 header
->ShortRecordBit
= data
[0] & 0x10;
107 header
->IDLenPresent
= data
[0] & 0x08;
108 header
->TypeNameFormat
= data
[0] & 0x07;
109 header
->len
= 1 + 1 + (header
->ShortRecordBit
? 1 : 4) + (header
->IDLenPresent
? 1 : 0); // header + typelen + payloadlen + idlen
110 if (header
->len
> datalen
)
113 header
->TypeLen
= data
[1];
114 header
->Type
= data
+ header
->len
;
116 header
->PayloadLen
= (header
->ShortRecordBit
? (data
[2]) : ((data
[2] << 24) + (data
[3] << 16) + (data
[4] << 8) + data
[5]));
118 if (header
->IDLenPresent
) {
119 header
->IDLen
= (header
->ShortRecordBit
? (data
[3]) : (data
[6]));
120 header
->Payload
= header
->Type
+ header
->TypeLen
;
125 header
->Payload
= header
->Type
+ header
->TypeLen
+ header
->IDLen
;
127 header
->RecLen
= header
->len
+ header
->TypeLen
+ header
->PayloadLen
+ header
->IDLen
;
129 if (header
->RecLen
> datalen
)
135 int ndefPrintHeader(NDEFHeader_t
*header
) {
136 PrintAndLogEx(INFO
, "Header:");
138 PrintAndLogEx(NORMAL
, "\tMessage Begin: %s", STRBOOL(header
->MessageBegin
));
139 PrintAndLogEx(NORMAL
, "\tMessage End: %s", STRBOOL(header
->MessageEnd
));
140 PrintAndLogEx(NORMAL
, "\tChunk Flag: %s", STRBOOL(header
->ChunkFlag
));
141 PrintAndLogEx(NORMAL
, "\tShort Record Bit: %s", STRBOOL(header
->ShortRecordBit
));
142 PrintAndLogEx(NORMAL
, "\tID Len Present: %s", STRBOOL(header
->IDLenPresent
));
143 PrintAndLogEx(NORMAL
, "\tType Name Format: [0x%02x] %s", header
->TypeNameFormat
, TypeNameFormat_s
[header
->TypeNameFormat
]);
145 PrintAndLogEx(NORMAL
, "\tHeader length : %d", header
->len
);
146 PrintAndLogEx(NORMAL
, "\tType length : %d", header
->TypeLen
);
147 PrintAndLogEx(NORMAL
, "\tPayload length : %d", header
->PayloadLen
);
148 PrintAndLogEx(NORMAL
, "\tID length : %d", header
->IDLen
);
149 PrintAndLogEx(NORMAL
, "\tRecord length : %d", header
->RecLen
);
154 int ndefDecodeSig(uint8_t *sig
, size_t siglen
) {
156 PrintAndLogEx(NORMAL
, "\tsignature version: 0x%02x", sig
[0]);
157 if (sig
[0] != 0x01) {
158 PrintAndLogEx(ERR
, "signature version unknown.");
163 uint8_t sigType
= sig
[indx
] & 0x7f;
164 bool sigURI
= sig
[indx
] & 0x80;
166 PrintAndLogEx(NORMAL
, "\tsignature type: %s", ((sigType
< stNA
) ? ndefSigType_s
[sigType
] : ndefSigType_s
[stNA
]));
167 PrintAndLogEx(NORMAL
, "\tsignature uri: %s", (sigURI
? "present" : "not present"));
169 size_t intsiglen
= (sig
[indx
+ 1] << 8) + sig
[indx
+ 2];
171 if (sigType
== stECDSA
) {
173 PrintAndLogEx(NORMAL
, "\tsignature [%d]: %s", intsiglen
, sprint_hex_inrow(&sig
[indx
], intsiglen
));
175 uint8_t rval
[300] = {0};
176 uint8_t sval
[300] = {0};
177 int res
= ecdsa_asn1_get_signature(&sig
[indx
], intsiglen
, rval
, sval
);
179 PrintAndLogEx(NORMAL
, "\t\tr: %s", sprint_hex(rval
, 32));
180 PrintAndLogEx(NORMAL
, "\t\ts: %s", sprint_hex(sval
, 32));
186 size_t intsigurilen
= (sig
[indx
] << 8) + sig
[indx
+ 1];
188 PrintAndLogEx(NORMAL
, "\tsignature uri [%d]: %.*s", intsigurilen
, intsigurilen
, &sig
[indx
]);
189 indx
+= intsigurilen
;
192 uint8_t certFormat
= (sig
[indx
] >> 4) & 0x07;
193 uint8_t certCount
= sig
[indx
] & 0x0f;
194 bool certURI
= sig
[indx
] & 0x80;
196 PrintAndLogEx(NORMAL
, "\tcertificate format: %s", ((certFormat
< sfNA
) ? ndefCertificateFormat_s
[certFormat
] : ndefCertificateFormat_s
[sfNA
]));
197 PrintAndLogEx(NORMAL
, "\tcertificates count: %d", certCount
);
199 // print certificates
201 for (int i
= 0; i
< certCount
; i
++) {
202 size_t intcertlen
= (sig
[indx
+ 1] << 8) + sig
[indx
+ 2];
205 PrintAndLogEx(NORMAL
, "\tcertificate %d [%d]: %s", i
+ 1, intcertlen
, sprint_hex_inrow(&sig
[indx
], intcertlen
));
209 // have certificate uri
210 if ((indx
<= siglen
) && certURI
) {
211 size_t inturilen
= (sig
[indx
] << 8) + sig
[indx
+ 1];
213 PrintAndLogEx(NORMAL
, "\tcertificate uri [%d]: %.*s", inturilen
, inturilen
, &sig
[indx
]);
220 int ndefDecodePayload(NDEFHeader_t
*ndef
) {
222 switch (ndef
->TypeNameFormat
) {
223 case tnfWellKnownRecord
:
224 PrintAndLogEx(INFO
, "Well Known Record");
225 PrintAndLogEx(NORMAL
, "\ttype: %.*s", ndef
->TypeLen
, ndef
->Type
);
227 if (!strncmp((char *)ndef
->Type
, "T", ndef
->TypeLen
)) {
228 PrintAndLogEx(NORMAL
, "\ttext : %.*s", ndef
->PayloadLen
, ndef
->Payload
);
231 if (!strncmp((char *)ndef
->Type
, "U", ndef
->TypeLen
)) {
232 PrintAndLogEx(NORMAL
, "\turi : %s%.*s", (ndef
->Payload
[0] <= 0x23 ? URI_s
[ndef
->Payload
[0]] : "[err]"), ndef
->PayloadLen
, &ndef
->Payload
[1]);
235 if (!strncmp((char *)ndef
->Type
, "Sig", ndef
->TypeLen
)) {
236 ndefDecodeSig(ndef
->Payload
, ndef
->PayloadLen
);
240 case tnfAbsoluteURIRecord
:
241 PrintAndLogEx(INFO
, "Absolute URI Record");
242 PrintAndLogEx(NORMAL
, "\ttype: %.*s", ndef
->TypeLen
, ndef
->Type
);
243 PrintAndLogEx(NORMAL
, "\tpayload: %.*s", ndef
->PayloadLen
, ndef
->Payload
);
251 int ndefRecordDecodeAndPrint(uint8_t *ndefRecord
, size_t ndefRecordLen
) {
252 NDEFHeader_t NDEFHeader
= {0};
253 int res
= ndefDecodeHeader(ndefRecord
, ndefRecordLen
, &NDEFHeader
);
257 ndefPrintHeader(&NDEFHeader
);
259 if (NDEFHeader
.TypeLen
) {
260 PrintAndLogEx(INFO
, "Type data:");
261 dump_buffer(NDEFHeader
.Type
, NDEFHeader
.TypeLen
, stdout
, 1);
263 if (NDEFHeader
.IDLen
) {
264 PrintAndLogEx(INFO
, "ID data:");
265 dump_buffer(NDEFHeader
.ID
, NDEFHeader
.IDLen
, stdout
, 1);
267 if (NDEFHeader
.PayloadLen
) {
268 PrintAndLogEx(INFO
, "Payload data:");
269 dump_buffer(NDEFHeader
.Payload
, NDEFHeader
.PayloadLen
, stdout
, 1);
270 if (NDEFHeader
.TypeLen
)
271 ndefDecodePayload(&NDEFHeader
);
277 int ndefRecordsDecodeAndPrint(uint8_t *ndefRecord
, size_t ndefRecordLen
) {
278 bool firstRec
= true;
281 while (len
< ndefRecordLen
) {
282 NDEFHeader_t NDEFHeader
= {0};
283 int res
= ndefDecodeHeader(&ndefRecord
[len
], ndefRecordLen
- len
, &NDEFHeader
);
288 if (!NDEFHeader
.MessageBegin
) {
289 PrintAndLogEx(ERR
, "NDEF first record have MessageBegin=false!");
295 if (NDEFHeader
.MessageEnd
&& len
+ NDEFHeader
.RecLen
!= ndefRecordLen
) {
296 PrintAndLogEx(ERR
, "NDEF records have wrong length. Must be %d, calculated %d", ndefRecordLen
, len
+ NDEFHeader
.RecLen
);
300 ndefRecordDecodeAndPrint(&ndefRecord
[len
], NDEFHeader
.RecLen
);
302 len
+= NDEFHeader
.RecLen
;
304 if (NDEFHeader
.MessageEnd
)
311 int NDEFDecodeAndPrint(uint8_t *ndef
, size_t ndefLen
, bool verbose
) {
315 PrintAndLogEx(INFO
, "NDEF decoding:");
316 while (indx
< ndefLen
) {
317 switch (ndef
[indx
]) {
320 uint16_t len
= ndefTLVGetLength(&ndef
[indx
], &indx
);
321 PrintAndLogEx(INFO
, "-- NDEF NULL block.");
323 PrintAndLogEx(WARNING
, "NDEF NULL block size must be 0 instead of %d.", len
);
329 uint16_t len
= ndefTLVGetLength(&ndef
[indx
], &indx
);
330 PrintAndLogEx(INFO
, "-- NDEF message. len: %d", len
);
332 int res
= ndefRecordsDecodeAndPrint(&ndef
[indx
], len
);
341 uint16_t len
= ndefTLVGetLength(&ndef
[indx
], &indx
);
342 PrintAndLogEx(INFO
, "-- NDEF proprietary info. Skipped %d bytes.", len
);
347 PrintAndLogEx(INFO
, "-- NDEF Terminator. Done.");
352 PrintAndLogEx(ERR
, "unknown tag 0x%02x", ndef
[indx
]);