1 /*
2  * APDU handling
3  *
4  * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5  */
6 
7 #include "internal.h"
8 #include <string.h>
9 
10 /*
11  * Check the APDU type and length
12  */
__ifd_apdu_check(const void * sbuf,size_t len,ifd_iso_apdu_t * iso)13 static int __ifd_apdu_check(const void *sbuf, size_t len, ifd_iso_apdu_t * iso)
14 {
15 	unsigned char *data = (unsigned char *)sbuf;
16 	unsigned int b;
17 
18 	memset(iso, 0, sizeof(*iso));
19 	if (len < 5) {
20 		iso->cse = IFD_APDU_CASE_1;
21 		return 0;
22 	}
23 
24 	b = data[4];
25 	len -= 5;
26 
27 	/* APDU + Le */
28 	if (len == 0) {
29 		iso->cse = IFD_APDU_CASE_2S;
30 		iso->le = b ? b : 256;
31 		return 0;
32 	}
33 
34 	data += 5;
35 	if (b == 0)
36 		b = 256;
37 
38 	iso->lc = b;
39 	iso->len = len;
40 	iso->data = data;
41 
42 	/* APDU + Lc + data */
43 	if (len == b) {
44 		iso->cse = IFD_APDU_CASE_3S;
45 		return 0;
46 	}
47 
48 	/* APDU + Lc + data + Le */
49 	if (len == b + 1) {
50 		iso->cse = IFD_APDU_CASE_4S;
51 		iso->le = data[b] ? data[b] : 256;
52 		iso->len--;
53 		return 0;
54 	}
55 
56 	return -1;
57 }
58 
ifd_apdu_case(const void * buf,size_t len)59 int ifd_apdu_case(const void *buf, size_t len)
60 {
61 	ifd_iso_apdu_t iso;
62 
63 	if (__ifd_apdu_check(buf, len, &iso) < 0)
64 		return -1;
65 	return iso.cse;
66 }
67 
68 /*
69  * Convert internal APDU type to an ISO-7816-4 APDU
70  */
ifd_iso_apdu_parse(const void * data,size_t len,ifd_iso_apdu_t * iso)71 int ifd_iso_apdu_parse(const void *data, size_t len, ifd_iso_apdu_t * iso)
72 {
73 	unsigned char *p;
74 
75 	if (len < 4)
76 		return -1;
77 
78 	if (__ifd_apdu_check(data, len, iso) < 0)
79 		return -1;
80 
81 	p = (unsigned char *)data;
82 	iso->cla = *p++;
83 	iso->ins = *p++;
84 	iso->p1 = *p++;
85 	iso->p2 = *p++;
86 
87 	return 0;
88 }
89