Revision 111a38b0
b/Makefile | ||
---|---|---|
141 | 141 |
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS) |
142 | 142 |
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS) |
143 | 143 |
|
144 |
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user |
|
145 |
|
|
144 | 146 |
clean: |
145 | 147 |
# avoid old build problems by removing potentially incorrect old files |
146 | 148 |
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h |
... | ... | |
152 | 154 |
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp |
153 | 155 |
rm -f trace-dtrace.h trace-dtrace.h-timestamp |
154 | 156 |
$(MAKE) -C tests clean |
155 |
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser libdis libdis-user; do \
|
|
157 |
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
|
|
156 | 158 |
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \ |
157 | 159 |
rm -f $$d/qemu-options.def; \ |
158 | 160 |
done |
... | ... | |
163 | 165 |
rm -f roms/seabios/config.mak roms/vgabios/config.mak |
164 | 166 |
rm -f qemu-doc.info qemu-doc.aux qemu-doc.cp qemu-doc.dvi qemu-doc.fn qemu-doc.info qemu-doc.ky qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp qemu-doc.vr |
165 | 167 |
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr |
166 |
for d in $(TARGET_DIRS) libhw32 libhw64 libuser libdis libdis-user; do \
|
|
168 |
for d in $(TARGET_DIRS) $(QEMULIBS); do \
|
|
167 | 169 |
rm -rf $$d || exit 1 ; \ |
168 | 170 |
done |
169 | 171 |
|
b/Makefile.objs | ||
---|---|---|
352 | 352 |
endif |
353 | 353 |
endif |
354 | 354 |
|
355 |
###################################################################### |
|
356 |
# smartcard |
|
357 |
|
|
358 |
libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o |
|
359 |
|
|
355 | 360 |
vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) |
356 | 361 |
|
357 | 362 |
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) |
b/Makefile.target | ||
---|---|---|
358 | 358 |
|
359 | 359 |
endif # CONFIG_SOFTMMU |
360 | 360 |
|
361 |
ifndef CONFIG_LINUX_USER |
|
362 |
# libcacard needs qemu-thread support, and besides is only needed by devices |
|
363 |
# so not requires with linux-user targets |
|
364 |
obj-$(CONFIG_SMARTCARD_NSS) += $(addprefix ../libcacard/, $(libcacard-y)) |
|
365 |
endif # CONFIG_LINUX_USER |
|
366 |
|
|
361 | 367 |
obj-y += $(addprefix ../, $(trace-obj-y)) |
362 | 368 |
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o |
363 | 369 |
|
b/configure | ||
---|---|---|
176 | 176 |
spice="" |
177 | 177 |
rbd="" |
178 | 178 |
smartcard="" |
179 |
smartcard_nss="" |
|
179 | 180 |
|
180 | 181 |
# parse CC options first |
181 | 182 |
for opt do |
... | ... | |
729 | 730 |
;; |
730 | 731 |
--enable-smartcard) smartcard="yes" |
731 | 732 |
;; |
733 |
--disable-smartcard-nss) smartcard_nss="no" |
|
734 |
;; |
|
735 |
--enable-smartcard-nss) smartcard_nss="yes" |
|
736 |
;; |
|
732 | 737 |
*) echo "ERROR: unknown option $opt"; show_help="yes" |
733 | 738 |
;; |
734 | 739 |
esac |
... | ... | |
928 | 933 |
echo " --enable-rbd enable building the rados block device (rbd)" |
929 | 934 |
echo " --disable-smartcard disable smartcard support" |
930 | 935 |
echo " --enable-smartcard enable smartcard support" |
936 |
echo " --disable-smartcard-nss disable smartcard nss support" |
|
937 |
echo " --enable-smartcard-nss enable smartcard nss support" |
|
931 | 938 |
echo "" |
932 | 939 |
echo "NOTE: The object files are built at the place where configure is launched" |
933 | 940 |
exit 1 |
... | ... | |
2311 | 2318 |
fi |
2312 | 2319 |
fi |
2313 | 2320 |
|
2321 |
# check for libcacard for smartcard support |
|
2322 |
if test "$smartcard" != "no" ; then |
|
2323 |
smartcard="yes" |
|
2324 |
smartcard_cflags="" |
|
2325 |
# TODO - what's the minimal nss version we support? |
|
2326 |
if test "$smartcard_nss" != "no"; then |
|
2327 |
if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then |
|
2328 |
smartcard_nss="yes" |
|
2329 |
smartcard_cflags="-I\$(SRC_PATH)/libcacard" |
|
2330 |
libcacard_libs=$($pkg_config --libs nss 2>/dev/null) |
|
2331 |
libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null) |
|
2332 |
QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags" |
|
2333 |
LIBS="$libcacard_libs $LIBS" |
|
2334 |
else |
|
2335 |
if test "$smartcard_nss" = "yes"; then |
|
2336 |
feature_not_found "nss" |
|
2337 |
fi |
|
2338 |
smartcard_nss="no" |
|
2339 |
fi |
|
2340 |
fi |
|
2341 |
fi |
|
2342 |
if test "$smartcard" = "no" ; then |
|
2343 |
smartcard_nss="no" |
|
2344 |
fi |
|
2345 |
|
|
2314 | 2346 |
########################################## |
2315 | 2347 |
|
2316 | 2348 |
########################################## |
... | ... | |
2549 | 2581 |
echo "spice support $spice" |
2550 | 2582 |
echo "rbd support $rbd" |
2551 | 2583 |
echo "xfsctl support $xfs" |
2584 |
echo "nss used $smartcard_nss" |
|
2552 | 2585 |
|
2553 | 2586 |
if test $sdl_too_old = "yes"; then |
2554 | 2587 |
echo "-> Your SDL version is too old - please upgrade to have SDL support" |
... | ... | |
2835 | 2868 |
echo "CONFIG_SMARTCARD=y" >> $config_host_mak |
2836 | 2869 |
fi |
2837 | 2870 |
|
2871 |
if test "$smartcard_nss" = "yes" ; then |
|
2872 |
echo "CONFIG_SMARTCARD_NSS=y" >> $config_host_mak |
|
2873 |
fi |
|
2874 |
|
|
2838 | 2875 |
# XXX: suppress that |
2839 | 2876 |
if [ "$bsd" = "yes" ] ; then |
2840 | 2877 |
echo "CONFIG_BSD=y" >> $config_host_mak |
... | ... | |
3183 | 3220 |
if test "$target_darwin_user" = "yes" ; then |
3184 | 3221 |
echo "CONFIG_DARWIN_USER=y" >> $config_target_mak |
3185 | 3222 |
fi |
3223 |
if test "$smartcard_nss" = "yes" ; then |
|
3224 |
echo "subdir-$target: subdir-libcacard" >> $config_host_mak |
|
3225 |
echo "libcacard_libs=$libcacard_libs" >> $config_host_mak |
|
3226 |
echo "libcacard_cflags=$libcacard_cflags" >> $config_host_mak |
|
3227 |
fi |
|
3186 | 3228 |
list="" |
3187 | 3229 |
if test ! -z "$gdb_xml_files" ; then |
3188 | 3230 |
for x in $gdb_xml_files; do |
... | ... | |
3396 | 3438 |
echo "QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=$hwlib" > $d/config.mak |
3397 | 3439 |
done |
3398 | 3440 |
|
3441 |
if [ "$source_path" != `pwd` ]; then |
|
3442 |
# out of tree build |
|
3443 |
mkdir -p libcacard |
|
3444 |
rm -f libcacard/Makefile |
|
3445 |
ln -s "$source_path/libcacard/Makefile" libcacard/Makefile |
|
3446 |
fi |
|
3447 |
|
|
3399 | 3448 |
d=libuser |
3400 | 3449 |
mkdir -p $d |
3401 | 3450 |
symlink $source_path/Makefile.user $d/Makefile |
b/libcacard/Makefile | ||
---|---|---|
1 |
-include ../config-host.mak |
|
2 |
-include $(SRC_PATH)/Makefile.objs |
|
3 |
-include $(SRC_PATH)/rules.mak |
|
4 |
|
|
5 |
$(call set-vpath, $(SRC_PATH):$(SRC_PATH)/libcacard) |
|
6 |
|
|
7 |
ifeq ($(CONFIG_WIN32),y) |
|
8 |
QEMU_THREAD=qemu-thread-win32.o |
|
9 |
else |
|
10 |
QEMU_THREAD=qemu-thread-posix.o |
|
11 |
endif |
|
12 |
|
|
13 |
|
|
14 |
QEMU_OBJS=$(addprefix ../, $(QEMU_THREAD) $(oslib-obj-y) $(trace-obj-y) qemu-malloc.o qemu-timer-common.o) |
|
15 |
|
|
16 |
QEMU_CFLAGS+=-I../ |
|
17 |
|
|
18 |
clean: |
|
19 |
rm -f *.o */*.o *.d */*.d *.a */*.a *~ */*~ |
|
20 |
|
b/libcacard/cac.c | ||
---|---|---|
1 |
/* |
|
2 |
* implement the applets for the CAC card. |
|
3 |
* |
|
4 |
* This code is licensed under the GNU LGPL, version 2.1 or later. |
|
5 |
* See the COPYING.LIB file in the top-level directory. |
|
6 |
*/ |
|
7 |
|
|
8 |
#include "qemu-common.h" |
|
9 |
|
|
10 |
#include "cac.h" |
|
11 |
#include "vcard.h" |
|
12 |
#include "vcard_emul.h" |
|
13 |
#include "card_7816.h" |
|
14 |
|
|
15 |
#define CAC_GET_PROPERTIES 0x56 |
|
16 |
#define CAC_GET_ACR 0x4c |
|
17 |
#define CAC_READ_BUFFER 0x52 |
|
18 |
#define CAC_UPDATE_BUFFER 0x58 |
|
19 |
#define CAC_SIGN_DECRYPT 0x42 |
|
20 |
#define CAC_GET_CERTIFICATE 0x36 |
|
21 |
|
|
22 |
/* private data for PKI applets */ |
|
23 |
typedef struct CACPKIAppletDataStruct { |
|
24 |
unsigned char *cert; |
|
25 |
int cert_len; |
|
26 |
unsigned char *cert_buffer; |
|
27 |
int cert_buffer_len; |
|
28 |
unsigned char *sign_buffer; |
|
29 |
int sign_buffer_len; |
|
30 |
VCardKey *key; |
|
31 |
} CACPKIAppletData; |
|
32 |
|
|
33 |
/* |
|
34 |
* CAC applet private data |
|
35 |
*/ |
|
36 |
struct VCardAppletPrivateStruct { |
|
37 |
union { |
|
38 |
CACPKIAppletData pki_data; |
|
39 |
void *reserved; |
|
40 |
} u; |
|
41 |
}; |
|
42 |
|
|
43 |
/* |
|
44 |
* handle all the APDU's that are common to all CAC applets |
|
45 |
*/ |
|
46 |
static VCardStatus |
|
47 |
cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) |
|
48 |
{ |
|
49 |
int ef; |
|
50 |
|
|
51 |
switch (apdu->a_ins) { |
|
52 |
case VCARD7816_INS_SELECT_FILE: |
|
53 |
if (apdu->a_p1 != 0x02) { |
|
54 |
/* let the 7816 code handle applet switches */ |
|
55 |
return VCARD_NEXT; |
|
56 |
} |
|
57 |
/* handle file id setting */ |
|
58 |
if (apdu->a_Lc != 2) { |
|
59 |
*response = vcard_make_response( |
|
60 |
VCARD7816_STATUS_ERROR_DATA_INVALID); |
|
61 |
return VCARD_DONE; |
|
62 |
} |
|
63 |
/* CAC 1.0 only supports ef = 0 */ |
|
64 |
ef = apdu->a_body[0] | (apdu->a_body[1] << 8); |
|
65 |
if (ef != 0) { |
|
66 |
*response = vcard_make_response( |
|
67 |
VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); |
|
68 |
return VCARD_DONE; |
|
69 |
} |
|
70 |
*response = vcard_make_response(VCARD7816_STATUS_SUCCESS); |
|
71 |
return VCARD_DONE; |
|
72 |
case VCARD7816_INS_GET_RESPONSE: |
|
73 |
case VCARD7816_INS_VERIFY: |
|
74 |
/* let the 7816 code handle these */ |
|
75 |
return VCARD_NEXT; |
|
76 |
case CAC_GET_PROPERTIES: |
|
77 |
case CAC_GET_ACR: |
|
78 |
/* skip these for now, this will probably be needed */ |
|
79 |
*response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
|
80 |
return VCARD_DONE; |
|
81 |
} |
|
82 |
*response = vcard_make_response( |
|
83 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
84 |
return VCARD_DONE; |
|
85 |
} |
|
86 |
|
|
87 |
/* |
|
88 |
* reset the inter call state between applet selects |
|
89 |
*/ |
|
90 |
static VCardStatus |
|
91 |
cac_applet_pki_reset(VCard *card, int channel) |
|
92 |
{ |
|
93 |
VCardAppletPrivate *applet_private = NULL; |
|
94 |
CACPKIAppletData *pki_applet = NULL; |
|
95 |
applet_private = vcard_get_current_applet_private(card, channel); |
|
96 |
assert(applet_private); |
|
97 |
pki_applet = &(applet_private->u.pki_data); |
|
98 |
|
|
99 |
pki_applet->cert_buffer = NULL; |
|
100 |
if (pki_applet->sign_buffer) { |
|
101 |
qemu_free(pki_applet->sign_buffer); |
|
102 |
pki_applet->sign_buffer = NULL; |
|
103 |
} |
|
104 |
pki_applet->cert_buffer_len = 0; |
|
105 |
pki_applet->sign_buffer_len = 0; |
|
106 |
return VCARD_DONE; |
|
107 |
} |
|
108 |
|
|
109 |
static VCardStatus |
|
110 |
cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, |
|
111 |
VCardResponse **response) |
|
112 |
{ |
|
113 |
CACPKIAppletData *pki_applet = NULL; |
|
114 |
VCardAppletPrivate *applet_private = NULL; |
|
115 |
int size, next; |
|
116 |
unsigned char *sign_buffer; |
|
117 |
vcard_7816_status_t status; |
|
118 |
|
|
119 |
applet_private = vcard_get_current_applet_private(card, apdu->a_channel); |
|
120 |
assert(applet_private); |
|
121 |
pki_applet = &(applet_private->u.pki_data); |
|
122 |
|
|
123 |
switch (apdu->a_ins) { |
|
124 |
case CAC_UPDATE_BUFFER: |
|
125 |
*response = vcard_make_response( |
|
126 |
VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); |
|
127 |
return VCARD_DONE; |
|
128 |
case CAC_GET_CERTIFICATE: |
|
129 |
if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { |
|
130 |
*response = vcard_make_response( |
|
131 |
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
|
132 |
break; |
|
133 |
} |
|
134 |
assert(pki_applet->cert != NULL); |
|
135 |
size = apdu->a_Le; |
|
136 |
if (pki_applet->cert_buffer == NULL) { |
|
137 |
pki_applet->cert_buffer = pki_applet->cert; |
|
138 |
pki_applet->cert_buffer_len = pki_applet->cert_len; |
|
139 |
} |
|
140 |
size = MIN(size, pki_applet->cert_buffer_len); |
|
141 |
next = MIN(255, pki_applet->cert_buffer_len - size); |
|
142 |
*response = vcard_response_new_bytes( |
|
143 |
card, pki_applet->cert_buffer, size, |
|
144 |
apdu->a_Le, next ? |
|
145 |
VCARD7816_SW1_WARNING_CHANGE : |
|
146 |
VCARD7816_SW1_SUCCESS, |
|
147 |
next); |
|
148 |
pki_applet->cert_buffer += size; |
|
149 |
pki_applet->cert_buffer_len -= size; |
|
150 |
if ((*response == NULL) || (next == 0)) { |
|
151 |
pki_applet->cert_buffer = NULL; |
|
152 |
} |
|
153 |
if (*response == NULL) { |
|
154 |
*response = vcard_make_response( |
|
155 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
156 |
} |
|
157 |
return VCARD_DONE; |
|
158 |
case CAC_SIGN_DECRYPT: |
|
159 |
if (apdu->a_p2 != 0) { |
|
160 |
*response = vcard_make_response( |
|
161 |
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
|
162 |
break; |
|
163 |
} |
|
164 |
size = apdu->a_Lc; |
|
165 |
|
|
166 |
sign_buffer = realloc(pki_applet->sign_buffer, |
|
167 |
pki_applet->sign_buffer_len+size); |
|
168 |
if (sign_buffer == NULL) { |
|
169 |
qemu_free(pki_applet->sign_buffer); |
|
170 |
pki_applet->sign_buffer = NULL; |
|
171 |
pki_applet->sign_buffer_len = 0; |
|
172 |
*response = vcard_make_response( |
|
173 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
174 |
return VCARD_DONE; |
|
175 |
} |
|
176 |
memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size); |
|
177 |
size += pki_applet->sign_buffer_len; |
|
178 |
switch (apdu->a_p1) { |
|
179 |
case 0x80: |
|
180 |
/* p1 == 0x80 means we haven't yet sent the whole buffer, wait for |
|
181 |
* the rest */ |
|
182 |
pki_applet->sign_buffer = sign_buffer; |
|
183 |
pki_applet->sign_buffer_len = size; |
|
184 |
*response = vcard_make_response(VCARD7816_STATUS_SUCCESS); |
|
185 |
return VCARD_DONE; |
|
186 |
case 0x00: |
|
187 |
/* we now have the whole buffer, do the operation, result will be |
|
188 |
* in the sign_buffer */ |
|
189 |
status = vcard_emul_rsa_op(card, pki_applet->key, |
|
190 |
sign_buffer, size); |
|
191 |
if (status != VCARD7816_STATUS_SUCCESS) { |
|
192 |
*response = vcard_make_response(status); |
|
193 |
break; |
|
194 |
} |
|
195 |
*response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, |
|
196 |
VCARD7816_STATUS_SUCCESS); |
|
197 |
if (*response == NULL) { |
|
198 |
*response = vcard_make_response( |
|
199 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
200 |
} |
|
201 |
break; |
|
202 |
default: |
|
203 |
*response = vcard_make_response( |
|
204 |
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
|
205 |
break; |
|
206 |
} |
|
207 |
qemu_free(sign_buffer); |
|
208 |
pki_applet->sign_buffer = NULL; |
|
209 |
pki_applet->sign_buffer_len = 0; |
|
210 |
return VCARD_DONE; |
|
211 |
case CAC_READ_BUFFER: |
|
212 |
/* new CAC call, go ahead and use the old version for now */ |
|
213 |
/* TODO: implement */ |
|
214 |
*response = vcard_make_response( |
|
215 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
216 |
return VCARD_DONE; |
|
217 |
} |
|
218 |
return cac_common_process_apdu(card, apdu, response); |
|
219 |
} |
|
220 |
|
|
221 |
|
|
222 |
static VCardStatus |
|
223 |
cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, |
|
224 |
VCardResponse **response) |
|
225 |
{ |
|
226 |
switch (apdu->a_ins) { |
|
227 |
case CAC_UPDATE_BUFFER: |
|
228 |
*response = vcard_make_response( |
|
229 |
VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); |
|
230 |
return VCARD_DONE; |
|
231 |
case CAC_READ_BUFFER: |
|
232 |
/* new CAC call, go ahead and use the old version for now */ |
|
233 |
/* TODO: implement */ |
|
234 |
*response = vcard_make_response( |
|
235 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
236 |
return VCARD_DONE; |
|
237 |
} |
|
238 |
return cac_common_process_apdu(card, apdu, response); |
|
239 |
} |
|
240 |
|
|
241 |
|
|
242 |
/* |
|
243 |
* TODO: if we ever want to support general CAC middleware, we will need to |
|
244 |
* implement the various containers. |
|
245 |
*/ |
|
246 |
static VCardStatus |
|
247 |
cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, |
|
248 |
VCardResponse **response) |
|
249 |
{ |
|
250 |
switch (apdu->a_ins) { |
|
251 |
case CAC_READ_BUFFER: |
|
252 |
case CAC_UPDATE_BUFFER: |
|
253 |
*response = vcard_make_response( |
|
254 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
255 |
return VCARD_DONE; |
|
256 |
default: |
|
257 |
break; |
|
258 |
} |
|
259 |
return cac_common_process_apdu(card, apdu, response); |
|
260 |
} |
|
261 |
|
|
262 |
/* |
|
263 |
* utilities for creating and destroying the private applet data |
|
264 |
*/ |
|
265 |
static void |
|
266 |
cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) |
|
267 |
{ |
|
268 |
CACPKIAppletData *pki_applet_data = NULL; |
|
269 |
if (pki_applet_data == NULL) { |
|
270 |
return; |
|
271 |
} |
|
272 |
pki_applet_data = &(applet_private->u.pki_data); |
|
273 |
if (pki_applet_data->cert != NULL) { |
|
274 |
qemu_free(pki_applet_data->cert); |
|
275 |
} |
|
276 |
if (pki_applet_data->sign_buffer != NULL) { |
|
277 |
qemu_free(pki_applet_data->sign_buffer); |
|
278 |
} |
|
279 |
if (pki_applet_data->key != NULL) { |
|
280 |
vcard_emul_delete_key(pki_applet_data->key); |
|
281 |
} |
|
282 |
qemu_free(applet_private); |
|
283 |
} |
|
284 |
|
|
285 |
static VCardAppletPrivate * |
|
286 |
cac_new_pki_applet_private(const unsigned char *cert, |
|
287 |
int cert_len, VCardKey *key) |
|
288 |
{ |
|
289 |
CACPKIAppletData *pki_applet_data = NULL; |
|
290 |
VCardAppletPrivate *applet_private = NULL; |
|
291 |
applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate)); |
|
292 |
|
|
293 |
pki_applet_data = &(applet_private->u.pki_data); |
|
294 |
pki_applet_data->cert_buffer = NULL; |
|
295 |
pki_applet_data->cert_buffer_len = 0; |
|
296 |
pki_applet_data->sign_buffer = NULL; |
|
297 |
pki_applet_data->sign_buffer_len = 0; |
|
298 |
pki_applet_data->key = NULL; |
|
299 |
pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1); |
|
300 |
/* |
|
301 |
* if we want to support compression, then we simply change the 0 to a 1 |
|
302 |
* and compress the cert data with libz |
|
303 |
*/ |
|
304 |
pki_applet_data->cert[0] = 0; /* not compressed */ |
|
305 |
memcpy(&pki_applet_data->cert[1], cert, cert_len); |
|
306 |
pki_applet_data->cert_len = cert_len+1; |
|
307 |
|
|
308 |
pki_applet_data->key = key; |
|
309 |
return applet_private; |
|
310 |
} |
|
311 |
|
|
312 |
|
|
313 |
/* |
|
314 |
* create a new cac applet which links to a given cert |
|
315 |
*/ |
|
316 |
static VCardApplet * |
|
317 |
cac_new_pki_applet(int i, const unsigned char *cert, |
|
318 |
int cert_len, VCardKey *key) |
|
319 |
{ |
|
320 |
VCardAppletPrivate *applet_private = NULL; |
|
321 |
VCardApplet *applet = NULL; |
|
322 |
unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; |
|
323 |
int pki_aid_len = sizeof(pki_aid); |
|
324 |
|
|
325 |
pki_aid[pki_aid_len-1] = i; |
|
326 |
|
|
327 |
applet_private = cac_new_pki_applet_private(cert, cert_len, key); |
|
328 |
if (applet_private == NULL) { |
|
329 |
goto failure; |
|
330 |
} |
|
331 |
applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, |
|
332 |
pki_aid, pki_aid_len); |
|
333 |
if (applet == NULL) { |
|
334 |
goto failure; |
|
335 |
} |
|
336 |
vcard_set_applet_private(applet, applet_private, |
|
337 |
cac_delete_pki_applet_private); |
|
338 |
applet_private = NULL; |
|
339 |
|
|
340 |
return applet; |
|
341 |
|
|
342 |
failure: |
|
343 |
if (applet_private != NULL) { |
|
344 |
cac_delete_pki_applet_private(applet_private); |
|
345 |
} |
|
346 |
return NULL; |
|
347 |
} |
|
348 |
|
|
349 |
|
|
350 |
static unsigned char cac_default_container_aid[] = { |
|
351 |
0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; |
|
352 |
static unsigned char cac_id_aid[] = { |
|
353 |
0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; |
|
354 |
/* |
|
355 |
* Initialize the cac card. This is the only public function in this file. All |
|
356 |
* the rest are connected through function pointers. |
|
357 |
*/ |
|
358 |
VCardStatus |
|
359 |
cac_card_init(VReader *reader, VCard *card, |
|
360 |
const char *params, |
|
361 |
unsigned char * const *cert, |
|
362 |
int cert_len[], |
|
363 |
VCardKey *key[] /* adopt the keys*/, |
|
364 |
int cert_count) |
|
365 |
{ |
|
366 |
int i; |
|
367 |
VCardApplet *applet; |
|
368 |
|
|
369 |
/* CAC Cards are VM Cards */ |
|
370 |
vcard_set_type(card, VCARD_VM); |
|
371 |
|
|
372 |
/* create one PKI applet for each cert */ |
|
373 |
for (i = 0; i < cert_count; i++) { |
|
374 |
applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); |
|
375 |
if (applet == NULL) { |
|
376 |
goto failure; |
|
377 |
} |
|
378 |
vcard_add_applet(card, applet); |
|
379 |
} |
|
380 |
|
|
381 |
/* create a default blank container applet */ |
|
382 |
applet = vcard_new_applet(cac_applet_container_process_apdu, |
|
383 |
NULL, cac_default_container_aid, |
|
384 |
sizeof(cac_default_container_aid)); |
|
385 |
if (applet == NULL) { |
|
386 |
goto failure; |
|
387 |
} |
|
388 |
vcard_add_applet(card, applet); |
|
389 |
|
|
390 |
/* create a default blank container applet */ |
|
391 |
applet = vcard_new_applet(cac_applet_id_process_apdu, |
|
392 |
NULL, cac_id_aid, |
|
393 |
sizeof(cac_id_aid)); |
|
394 |
if (applet == NULL) { |
|
395 |
goto failure; |
|
396 |
} |
|
397 |
vcard_add_applet(card, applet); |
|
398 |
return VCARD_DONE; |
|
399 |
|
|
400 |
failure: |
|
401 |
return VCARD_FAIL; |
|
402 |
} |
|
403 |
|
b/libcacard/cac.h | ||
---|---|---|
1 |
/* |
|
2 |
* defines the entry point for the cac card. Only used by cac.c anc |
|
3 |
* vcard_emul_type.c |
|
4 |
* |
|
5 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later. |
|
6 |
* See the COPYING.LIB file in the top-level directory. |
|
7 |
*/ |
|
8 |
#ifndef CAC_H |
|
9 |
#define CAC_H 1 |
|
10 |
#include "vcard.h" |
|
11 |
#include "vreader.h" |
|
12 |
/* |
|
13 |
* Initialize the cac card. This is the only public function in this file. All |
|
14 |
* the rest are connected through function pointers. |
|
15 |
*/ |
|
16 |
VCardStatus cac_card_init(VReader *reader, VCard *card, const char *params, |
|
17 |
unsigned char * const *cert, int cert_len[], |
|
18 |
VCardKey *key[] /* adopt the keys*/, |
|
19 |
int cert_count); |
|
20 |
|
|
21 |
/* not yet implemented */ |
|
22 |
VCardStatus cac_is_cac_card(VReader *reader); |
|
23 |
#endif |
b/libcacard/card_7816.c | ||
---|---|---|
1 |
/* |
|
2 |
* Implement the 7816 portion of the card spec |
|
3 |
* |
|
4 |
* This code is licensed under the GNU LGPL, version 2.1 or later. |
|
5 |
* See the COPYING.LIB file in the top-level directory. |
|
6 |
*/ |
|
7 |
|
|
8 |
#include "qemu-common.h" |
|
9 |
|
|
10 |
#include "vcard.h" |
|
11 |
#include "vcard_emul.h" |
|
12 |
#include "card_7816.h" |
|
13 |
|
|
14 |
/* |
|
15 |
* set the status bytes based on the status word |
|
16 |
*/ |
|
17 |
static void |
|
18 |
vcard_response_set_status(VCardResponse *response, vcard_7816_status_t status) |
|
19 |
{ |
|
20 |
unsigned char sw1, sw2; |
|
21 |
response->b_status = status; /* make sure the status and swX representations |
|
22 |
* are consistent */ |
|
23 |
sw1 = (status >> 8) & 0xff; |
|
24 |
sw2 = status & 0xff; |
|
25 |
response->b_sw1 = sw1; |
|
26 |
response->b_sw2 = sw2; |
|
27 |
response->b_data[response->b_len] = sw1; |
|
28 |
response->b_data[response->b_len+1] = sw2; |
|
29 |
} |
|
30 |
|
|
31 |
/* |
|
32 |
* set the status bytes in a response buffer |
|
33 |
*/ |
|
34 |
static void |
|
35 |
vcard_response_set_status_bytes(VCardResponse *response, |
|
36 |
unsigned char sw1, unsigned char sw2) |
|
37 |
{ |
|
38 |
response->b_status = sw1 << 8 | sw2; |
|
39 |
response->b_sw1 = sw1; |
|
40 |
response->b_sw2 = sw2; |
|
41 |
response->b_data[response->b_len] = sw1; |
|
42 |
response->b_data[response->b_len+1] = sw2; |
|
43 |
} |
|
44 |
|
|
45 |
/* |
|
46 |
* allocate a VCardResponse structure, plus space for the data buffer, and |
|
47 |
* set up everything but the resonse bytes. |
|
48 |
*/ |
|
49 |
VCardResponse * |
|
50 |
vcard_response_new_data(unsigned char *buf, int len) |
|
51 |
{ |
|
52 |
VCardResponse *new_response; |
|
53 |
|
|
54 |
new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); |
|
55 |
new_response->b_data = qemu_malloc(len + 2); |
|
56 |
memcpy(new_response->b_data, buf, len); |
|
57 |
new_response->b_total_len = len+2; |
|
58 |
new_response->b_len = len; |
|
59 |
new_response->b_type = VCARD_MALLOC; |
|
60 |
return new_response; |
|
61 |
} |
|
62 |
|
|
63 |
static VCardResponse * |
|
64 |
vcard_init_buffer_response(VCard *card, unsigned char *buf, int len) |
|
65 |
{ |
|
66 |
VCardResponse *response; |
|
67 |
VCardBufferResponse *buffer_response; |
|
68 |
|
|
69 |
buffer_response = vcard_get_buffer_response(card); |
|
70 |
if (buffer_response) { |
|
71 |
vcard_set_buffer_response(card, NULL); |
|
72 |
vcard_buffer_response_delete(buffer_response); |
|
73 |
} |
|
74 |
buffer_response = vcard_buffer_response_new(buf, len); |
|
75 |
if (buffer_response == NULL) { |
|
76 |
return NULL; |
|
77 |
} |
|
78 |
response = vcard_response_new_status_bytes(VCARD7816_SW1_RESPONSE_BYTES, |
|
79 |
len > 255 ? 0 : len); |
|
80 |
if (response == NULL) { |
|
81 |
return NULL; |
|
82 |
} |
|
83 |
vcard_set_buffer_response(card, buffer_response); |
|
84 |
return response; |
|
85 |
} |
|
86 |
|
|
87 |
/* |
|
88 |
* general buffer to hold results from APDU calls |
|
89 |
*/ |
|
90 |
VCardResponse * |
|
91 |
vcard_response_new(VCard *card, unsigned char *buf, |
|
92 |
int len, int Le, vcard_7816_status_t status) |
|
93 |
{ |
|
94 |
VCardResponse *new_response; |
|
95 |
|
|
96 |
if (len > Le) { |
|
97 |
return vcard_init_buffer_response(card, buf, len); |
|
98 |
} |
|
99 |
new_response = vcard_response_new_data(buf, len); |
|
100 |
if (new_response == NULL) { |
|
101 |
return NULL; |
|
102 |
} |
|
103 |
vcard_response_set_status(new_response, status); |
|
104 |
return new_response; |
|
105 |
} |
|
106 |
|
|
107 |
/* |
|
108 |
* general buffer to hold results from APDU calls |
|
109 |
*/ |
|
110 |
VCardResponse * |
|
111 |
vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le, |
|
112 |
unsigned char sw1, unsigned char sw2) |
|
113 |
{ |
|
114 |
VCardResponse *new_response; |
|
115 |
|
|
116 |
if (len > Le) { |
|
117 |
return vcard_init_buffer_response(card, buf, len); |
|
118 |
} |
|
119 |
new_response = vcard_response_new_data(buf, len); |
|
120 |
if (new_response == NULL) { |
|
121 |
return NULL; |
|
122 |
} |
|
123 |
vcard_response_set_status_bytes(new_response, sw1, sw2); |
|
124 |
return new_response; |
|
125 |
} |
|
126 |
|
|
127 |
/* |
|
128 |
* get a new Reponse buffer that only has a status. |
|
129 |
*/ |
|
130 |
static VCardResponse * |
|
131 |
vcard_response_new_status(vcard_7816_status_t status) |
|
132 |
{ |
|
133 |
VCardResponse *new_response; |
|
134 |
|
|
135 |
new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); |
|
136 |
new_response->b_data = &new_response->b_sw1; |
|
137 |
new_response->b_len = 0; |
|
138 |
new_response->b_total_len = 2; |
|
139 |
new_response->b_type = VCARD_MALLOC_STRUCT; |
|
140 |
vcard_response_set_status(new_response, status); |
|
141 |
return new_response; |
|
142 |
} |
|
143 |
|
|
144 |
/* |
|
145 |
* same as above, but specify the status as separate bytes |
|
146 |
*/ |
|
147 |
VCardResponse * |
|
148 |
vcard_response_new_status_bytes(unsigned char sw1, unsigned char sw2) |
|
149 |
{ |
|
150 |
VCardResponse *new_response; |
|
151 |
|
|
152 |
new_response = (VCardResponse *)qemu_malloc(sizeof(VCardResponse)); |
|
153 |
new_response->b_data = &new_response->b_sw1; |
|
154 |
new_response->b_len = 0; |
|
155 |
new_response->b_total_len = 2; |
|
156 |
new_response->b_type = VCARD_MALLOC_STRUCT; |
|
157 |
vcard_response_set_status_bytes(new_response, sw1, sw2); |
|
158 |
return new_response; |
|
159 |
} |
|
160 |
|
|
161 |
|
|
162 |
/* |
|
163 |
* free the response buffer. The Buffer has a type to handle the buffer |
|
164 |
* allocated in other ways than through malloc. |
|
165 |
*/ |
|
166 |
void |
|
167 |
vcard_response_delete(VCardResponse *response) |
|
168 |
{ |
|
169 |
if (response == NULL) { |
|
170 |
return; |
|
171 |
} |
|
172 |
switch (response->b_type) { |
|
173 |
case VCARD_MALLOC: |
|
174 |
/* everything was malloc'ed */ |
|
175 |
if (response->b_data) { |
|
176 |
qemu_free(response->b_data); |
|
177 |
} |
|
178 |
qemu_free(response); |
|
179 |
break; |
|
180 |
case VCARD_MALLOC_DATA: |
|
181 |
/* only the data buffer was malloc'ed */ |
|
182 |
if (response->b_data) { |
|
183 |
qemu_free(response->b_data); |
|
184 |
} |
|
185 |
break; |
|
186 |
case VCARD_MALLOC_STRUCT: |
|
187 |
/* only the structure was malloc'ed */ |
|
188 |
qemu_free(response); |
|
189 |
break; |
|
190 |
case VCARD_STATIC: |
|
191 |
break; |
|
192 |
} |
|
193 |
} |
|
194 |
|
|
195 |
/* |
|
196 |
* decode the class bit and set our generic type field, channel, and |
|
197 |
* secure messaging values. |
|
198 |
*/ |
|
199 |
static vcard_7816_status_t |
|
200 |
vcard_apdu_set_class(VCardAPDU *apdu) { |
|
201 |
apdu->a_channel = 0; |
|
202 |
apdu->a_secure_messaging = 0; |
|
203 |
apdu->a_type = apdu->a_cla & 0xf0; |
|
204 |
apdu->a_gen_type = VCARD_7816_ISO; |
|
205 |
|
|
206 |
/* parse the class tables 8 & 9 of the 7816-4 Part 4 spec */ |
|
207 |
switch (apdu->a_type) { |
|
208 |
/* we only support the basic types */ |
|
209 |
case 0x00: |
|
210 |
case 0x80: |
|
211 |
case 0x90: |
|
212 |
case 0xa0: |
|
213 |
apdu->a_channel = apdu->a_cla & 3; |
|
214 |
apdu->a_secure_messaging = apdu->a_cla & 0xe; |
|
215 |
break; |
|
216 |
case 0xb0: |
|
217 |
case 0xc0: |
|
218 |
break; |
|
219 |
|
|
220 |
case 0x10: |
|
221 |
case 0x20: |
|
222 |
case 0x30: |
|
223 |
case 0x40: |
|
224 |
case 0x50: |
|
225 |
case 0x60: |
|
226 |
case 0x70: |
|
227 |
/* Reserved for future use */ |
|
228 |
apdu->a_gen_type = VCARD_7816_RFU; |
|
229 |
break; |
|
230 |
case 0xd0: |
|
231 |
case 0xe0: |
|
232 |
case 0xf0: |
|
233 |
default: |
|
234 |
apdu->a_gen_type = |
|
235 |
(apdu->a_cla == 0xff) ? VCARD_7816_PTS : VCARD_7816_PROPIETARY; |
|
236 |
break; |
|
237 |
} |
|
238 |
return VCARD7816_STATUS_SUCCESS; |
|
239 |
} |
|
240 |
|
|
241 |
/* |
|
242 |
* set the Le and Lc fiels according to table 5 of the |
|
243 |
* 7816-4 part 4 spec |
|
244 |
*/ |
|
245 |
static vcard_7816_status_t |
|
246 |
vcard_apdu_set_length(VCardAPDU *apdu) |
|
247 |
{ |
|
248 |
int L, Le; |
|
249 |
|
|
250 |
/* process according to table 5 of the 7816-4 Part 4 spec. |
|
251 |
* variable names match the variables in the spec */ |
|
252 |
L = apdu->a_len-4; /* fixed APDU header */ |
|
253 |
apdu->a_Lc = 0; |
|
254 |
apdu->a_Le = 0; |
|
255 |
apdu->a_body = NULL; |
|
256 |
switch (L) { |
|
257 |
case 0: |
|
258 |
/* 1 minimal apdu */ |
|
259 |
return VCARD7816_STATUS_SUCCESS; |
|
260 |
case 1: |
|
261 |
/* 2S only return values apdu */ |
|
262 |
/* zero maps to 256 here */ |
|
263 |
apdu->a_Le = apdu->a_header->ah_Le ? |
|
264 |
apdu->a_header->ah_Le : 256; |
|
265 |
return VCARD7816_STATUS_SUCCESS; |
|
266 |
default: |
|
267 |
/* if the ah_Le byte is zero and we have more than |
|
268 |
* 1 byte in the header, then we must be using extended Le and Lc. |
|
269 |
* process the extended now. */ |
|
270 |
if (apdu->a_header->ah_Le == 0) { |
|
271 |
if (L < 3) { |
|
272 |
/* coding error, need at least 3 bytes */ |
|
273 |
return VCARD7816_STATUS_ERROR_WRONG_LENGTH; |
|
274 |
} |
|
275 |
/* calculate the first extended value. Could be either Le or Lc */ |
|
276 |
Le = (apdu->a_header->ah_body[0] << 8) |
|
277 |
|| apdu->a_header->ah_body[1]; |
|
278 |
if (L == 3) { |
|
279 |
/* 2E extended, return data only */ |
|
280 |
/* zero maps to 65536 */ |
|
281 |
apdu->a_Le = Le ? Le : 65536; |
|
282 |
return VCARD7816_STATUS_SUCCESS; |
|
283 |
} |
|
284 |
if (Le == 0) { |
|
285 |
/* reserved for future use, probably for next time we need |
|
286 |
* to extend the lengths */ |
|
287 |
return VCARD7816_STATUS_ERROR_WRONG_LENGTH; |
|
288 |
} |
|
289 |
/* we know that the first extended value is Lc now */ |
|
290 |
apdu->a_Lc = Le; |
|
291 |
apdu->a_body = &apdu->a_header->ah_body[2]; |
|
292 |
if (L == Le+3) { |
|
293 |
/* 3E extended, only body parameters */ |
|
294 |
return VCARD7816_STATUS_SUCCESS; |
|
295 |
} |
|
296 |
if (L == Le+5) { |
|
297 |
/* 4E extended, parameters and return data */ |
|
298 |
Le = (apdu->a_data[apdu->a_len-2] << 8) |
|
299 |
|| apdu->a_data[apdu->a_len-1]; |
|
300 |
apdu->a_Le = Le ? Le : 65536; |
|
301 |
return VCARD7816_STATUS_SUCCESS; |
|
302 |
} |
|
303 |
return VCARD7816_STATUS_ERROR_WRONG_LENGTH; |
|
304 |
} |
|
305 |
/* not extended */ |
|
306 |
apdu->a_Lc = apdu->a_header->ah_Le; |
|
307 |
apdu->a_body = &apdu->a_header->ah_body[0]; |
|
308 |
if (L == apdu->a_Lc + 1) { |
|
309 |
/* 3S only body parameters */ |
|
310 |
return VCARD7816_STATUS_SUCCESS; |
|
311 |
} |
|
312 |
if (L == apdu->a_Lc + 2) { |
|
313 |
/* 4S parameters and return data */ |
|
314 |
Le = apdu->a_data[apdu->a_len-1]; |
|
315 |
apdu->a_Le = Le ? Le : 256; |
|
316 |
return VCARD7816_STATUS_SUCCESS; |
|
317 |
} |
|
318 |
break; |
|
319 |
} |
|
320 |
return VCARD7816_STATUS_ERROR_WRONG_LENGTH; |
|
321 |
} |
|
322 |
|
|
323 |
/* |
|
324 |
* create a new APDU from a raw set of bytes. This will decode all the |
|
325 |
* above fields. users of VCARDAPDU's can then depend on the already decoded |
|
326 |
* values. |
|
327 |
*/ |
|
328 |
VCardAPDU * |
|
329 |
vcard_apdu_new(unsigned char *raw_apdu, int len, vcard_7816_status_t *status) |
|
330 |
{ |
|
331 |
VCardAPDU *new_apdu; |
|
332 |
|
|
333 |
*status = VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE; |
|
334 |
if (len < 4) { |
|
335 |
*status = VCARD7816_STATUS_ERROR_WRONG_LENGTH; |
|
336 |
return NULL; |
|
337 |
} |
|
338 |
|
|
339 |
new_apdu = (VCardAPDU *)qemu_malloc(sizeof(VCardAPDU)); |
|
340 |
new_apdu->a_data = qemu_malloc(len); |
|
341 |
memcpy(new_apdu->a_data, raw_apdu, len); |
|
342 |
new_apdu->a_len = len; |
|
343 |
*status = vcard_apdu_set_class(new_apdu); |
|
344 |
if (*status != VCARD7816_STATUS_SUCCESS) { |
|
345 |
qemu_free(new_apdu); |
|
346 |
return NULL; |
|
347 |
} |
|
348 |
*status = vcard_apdu_set_length(new_apdu); |
|
349 |
if (*status != VCARD7816_STATUS_SUCCESS) { |
|
350 |
qemu_free(new_apdu); |
|
351 |
new_apdu = NULL; |
|
352 |
} |
|
353 |
return new_apdu; |
|
354 |
} |
|
355 |
|
|
356 |
void |
|
357 |
vcard_apdu_delete(VCardAPDU *apdu) |
|
358 |
{ |
|
359 |
if (apdu == NULL) { |
|
360 |
return; |
|
361 |
} |
|
362 |
if (apdu->a_data) { |
|
363 |
qemu_free(apdu->a_data); |
|
364 |
} |
|
365 |
qemu_free(apdu); |
|
366 |
} |
|
367 |
|
|
368 |
|
|
369 |
/* |
|
370 |
* declare response buffers for all the 7816 defined error codes |
|
371 |
*/ |
|
372 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_SUCCESS) |
|
373 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING) |
|
374 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_RET_CORUPT) |
|
375 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE) |
|
376 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED) |
|
377 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID) |
|
378 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_CHANGE) |
|
379 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_WARNING_FILE_FILLED) |
|
380 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR) |
|
381 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_CHANGE) |
|
382 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE) |
|
383 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_LENGTH) |
|
384 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED) |
|
385 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED) |
|
386 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED) |
|
387 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED) |
|
388 |
VCARD_RESPONSE_NEW_STATIC_STATUS( |
|
389 |
VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE) |
|
390 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED) |
|
391 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED) |
|
392 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_INVALID) |
|
393 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED) |
|
394 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NO_EF) |
|
395 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING) |
|
396 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT) |
|
397 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS) |
|
398 |
VCARD_RESPONSE_NEW_STATIC_STATUS( |
|
399 |
VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA) |
|
400 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED) |
|
401 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_FILE_NOT_FOUND) |
|
402 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND) |
|
403 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE) |
|
404 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT) |
|
405 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT) |
|
406 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT) |
|
407 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND) |
|
408 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2) |
|
409 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_INS_CODE_INVALID) |
|
410 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_CLA_INVALID) |
|
411 |
VCARD_RESPONSE_NEW_STATIC_STATUS(VCARD7816_STATUS_ERROR_GENERAL) |
|
412 |
|
|
413 |
/* |
|
414 |
* return a single response code. This function cannot fail. It will always |
|
415 |
* return a response. |
|
416 |
*/ |
|
417 |
VCardResponse * |
|
418 |
vcard_make_response(vcard_7816_status_t status) |
|
419 |
{ |
|
420 |
VCardResponse *response = NULL; |
|
421 |
|
|
422 |
switch (status) { |
|
423 |
/* known 7816 response codes */ |
|
424 |
case VCARD7816_STATUS_SUCCESS: |
|
425 |
return VCARD_RESPONSE_GET_STATIC( |
|
426 |
VCARD7816_STATUS_SUCCESS); |
|
427 |
case VCARD7816_STATUS_WARNING: |
|
428 |
return VCARD_RESPONSE_GET_STATIC( |
|
429 |
VCARD7816_STATUS_WARNING); |
|
430 |
case VCARD7816_STATUS_WARNING_RET_CORUPT: |
|
431 |
return VCARD_RESPONSE_GET_STATIC( |
|
432 |
VCARD7816_STATUS_WARNING_RET_CORUPT); |
|
433 |
case VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE: |
|
434 |
return VCARD_RESPONSE_GET_STATIC( |
|
435 |
VCARD7816_STATUS_WARNING_BUF_END_BEFORE_LE); |
|
436 |
case VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED: |
|
437 |
return VCARD_RESPONSE_GET_STATIC( |
|
438 |
VCARD7816_STATUS_WARNING_INVALID_FILE_SELECTED); |
|
439 |
case VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID: |
|
440 |
return VCARD_RESPONSE_GET_STATIC( |
|
441 |
VCARD7816_STATUS_WARNING_FCI_FORMAT_INVALID); |
|
442 |
case VCARD7816_STATUS_WARNING_CHANGE: |
|
443 |
return VCARD_RESPONSE_GET_STATIC( |
|
444 |
VCARD7816_STATUS_WARNING_CHANGE); |
|
445 |
case VCARD7816_STATUS_WARNING_FILE_FILLED: |
|
446 |
return VCARD_RESPONSE_GET_STATIC( |
|
447 |
VCARD7816_STATUS_WARNING_FILE_FILLED); |
|
448 |
case VCARD7816_STATUS_EXC_ERROR: |
|
449 |
return VCARD_RESPONSE_GET_STATIC( |
|
450 |
VCARD7816_STATUS_EXC_ERROR); |
|
451 |
case VCARD7816_STATUS_EXC_ERROR_CHANGE: |
|
452 |
return VCARD_RESPONSE_GET_STATIC( |
|
453 |
VCARD7816_STATUS_EXC_ERROR_CHANGE); |
|
454 |
case VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE: |
|
455 |
return VCARD_RESPONSE_GET_STATIC( |
|
456 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
457 |
case VCARD7816_STATUS_ERROR_WRONG_LENGTH: |
|
458 |
return VCARD_RESPONSE_GET_STATIC( |
|
459 |
VCARD7816_STATUS_ERROR_WRONG_LENGTH); |
|
460 |
case VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED: |
|
461 |
return VCARD_RESPONSE_GET_STATIC( |
|
462 |
VCARD7816_STATUS_ERROR_CLA_NOT_SUPPORTED); |
|
463 |
case VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED: |
|
464 |
return VCARD_RESPONSE_GET_STATIC( |
|
465 |
VCARD7816_STATUS_ERROR_CHANNEL_NOT_SUPPORTED); |
|
466 |
case VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED: |
|
467 |
return VCARD_RESPONSE_GET_STATIC( |
|
468 |
VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); |
|
469 |
case VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED: |
|
470 |
return VCARD_RESPONSE_GET_STATIC( |
|
471 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
472 |
case VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE: |
|
473 |
return VCARD_RESPONSE_GET_STATIC( |
|
474 |
VCARD7816_STATUS_ERROR_COMMAND_INCOMPATIBLE_WITH_FILE); |
|
475 |
case VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED: |
|
476 |
return VCARD_RESPONSE_GET_STATIC( |
|
477 |
VCARD7816_STATUS_ERROR_SECURITY_NOT_SATISFIED); |
|
478 |
case VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED: |
|
479 |
return VCARD_RESPONSE_GET_STATIC( |
|
480 |
VCARD7816_STATUS_ERROR_AUTHENTICATION_BLOCKED); |
|
481 |
case VCARD7816_STATUS_ERROR_DATA_INVALID: |
|
482 |
return VCARD_RESPONSE_GET_STATIC( |
|
483 |
VCARD7816_STATUS_ERROR_DATA_INVALID); |
|
484 |
case VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED: |
|
485 |
return VCARD_RESPONSE_GET_STATIC( |
|
486 |
VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); |
|
487 |
case VCARD7816_STATUS_ERROR_DATA_NO_EF: |
|
488 |
return VCARD_RESPONSE_GET_STATIC( |
|
489 |
VCARD7816_STATUS_ERROR_DATA_NO_EF); |
|
490 |
case VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING: |
|
491 |
return VCARD_RESPONSE_GET_STATIC( |
|
492 |
VCARD7816_STATUS_ERROR_SM_OBJECT_MISSING); |
|
493 |
case VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT: |
|
494 |
return VCARD_RESPONSE_GET_STATIC( |
|
495 |
VCARD7816_STATUS_ERROR_SM_OBJECT_INCORRECT); |
|
496 |
case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS: |
|
497 |
return VCARD_RESPONSE_GET_STATIC( |
|
498 |
VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); |
|
499 |
case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA: |
|
500 |
return VCARD_RESPONSE_GET_STATIC( |
|
501 |
VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_IN_DATA); |
|
502 |
case VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED: |
|
503 |
return VCARD_RESPONSE_GET_STATIC( |
|
504 |
VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); |
|
505 |
case VCARD7816_STATUS_ERROR_FILE_NOT_FOUND: |
|
506 |
return VCARD_RESPONSE_GET_STATIC( |
|
507 |
VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); |
|
508 |
case VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND: |
|
509 |
return VCARD_RESPONSE_GET_STATIC( |
|
510 |
VCARD7816_STATUS_ERROR_RECORD_NOT_FOUND); |
|
511 |
case VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE: |
|
512 |
return VCARD_RESPONSE_GET_STATIC( |
|
513 |
VCARD7816_STATUS_ERROR_NO_SPACE_FOR_FILE); |
|
514 |
case VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT: |
|
515 |
return VCARD_RESPONSE_GET_STATIC( |
|
516 |
VCARD7816_STATUS_ERROR_LC_TLV_INCONSISTENT); |
|
517 |
case VCARD7816_STATUS_ERROR_P1_P2_INCORRECT: |
|
518 |
return VCARD_RESPONSE_GET_STATIC( |
|
519 |
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
|
520 |
case VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT: |
|
521 |
return VCARD_RESPONSE_GET_STATIC( |
|
522 |
VCARD7816_STATUS_ERROR_LC_P1_P2_INCONSISTENT); |
|
523 |
case VCARD7816_STATUS_ERROR_DATA_NOT_FOUND: |
|
524 |
return VCARD_RESPONSE_GET_STATIC( |
|
525 |
VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); |
|
526 |
case VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2: |
|
527 |
return VCARD_RESPONSE_GET_STATIC( |
|
528 |
VCARD7816_STATUS_ERROR_WRONG_PARAMETERS_2); |
|
529 |
case VCARD7816_STATUS_ERROR_INS_CODE_INVALID: |
|
530 |
return VCARD_RESPONSE_GET_STATIC( |
|
531 |
VCARD7816_STATUS_ERROR_INS_CODE_INVALID); |
|
532 |
case VCARD7816_STATUS_ERROR_CLA_INVALID: |
|
533 |
return VCARD_RESPONSE_GET_STATIC( |
|
534 |
VCARD7816_STATUS_ERROR_CLA_INVALID); |
|
535 |
case VCARD7816_STATUS_ERROR_GENERAL: |
|
536 |
return VCARD_RESPONSE_GET_STATIC( |
|
537 |
VCARD7816_STATUS_ERROR_GENERAL); |
|
538 |
default: |
|
539 |
/* we don't know this status code, create a response buffer to |
|
540 |
* hold it */ |
|
541 |
response = vcard_response_new_status(status); |
|
542 |
if (response == NULL) { |
|
543 |
/* couldn't allocate the buffer, return memmory error */ |
|
544 |
return VCARD_RESPONSE_GET_STATIC( |
|
545 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
546 |
} |
|
547 |
} |
|
548 |
assert(response); |
|
549 |
return response; |
|
550 |
} |
|
551 |
|
|
552 |
/* |
|
553 |
* Add File card support here if you need it. |
|
554 |
*/ |
|
555 |
static VCardStatus |
|
556 |
vcard7816_file_system_process_apdu(VCard *card, VCardAPDU *apdu, |
|
557 |
VCardResponse **response) |
|
558 |
{ |
|
559 |
/* TODO: if we want to support a virtual file system card, we do it here. |
|
560 |
* It would probably be a pkcs #15 card type */ |
|
561 |
*response = vcard_make_response( |
|
562 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
563 |
return VCARD_DONE; |
|
564 |
} |
|
565 |
|
|
566 |
/* |
|
567 |
* VM card (including java cards) |
|
568 |
*/ |
|
569 |
static VCardStatus |
|
570 |
vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu, |
|
571 |
VCardResponse **response) |
|
572 |
{ |
|
573 |
int bytes_to_copy, next_byte_count, count; |
|
574 |
VCardApplet *current_applet; |
|
575 |
VCardBufferResponse *buffer_response; |
|
576 |
vcard_7816_status_t status; |
|
577 |
|
|
578 |
/* parse the class first */ |
|
579 |
if (apdu->a_gen_type != VCARD_7816_ISO) { |
|
580 |
*response = vcard_make_response( |
|
581 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
582 |
return VCARD_DONE; |
|
583 |
} |
|
584 |
|
|
585 |
/* use a switch so that if we need to support secure channel stuff later, |
|
586 |
* we know where to put it */ |
|
587 |
switch (apdu->a_secure_messaging) { |
|
588 |
case 0x0: /* no SM */ |
|
589 |
break; |
|
590 |
case 0x4: /* proprietary SM */ |
|
591 |
case 0x8: /* header not authenticated */ |
|
592 |
case 0xc: /* header authenticated */ |
|
593 |
default: |
|
594 |
/* for now, don't try to support secure channel stuff in the |
|
595 |
* virtual card. */ |
|
596 |
*response = vcard_make_response( |
|
597 |
VCARD7816_STATUS_ERROR_SECURE_NOT_SUPPORTED); |
|
598 |
return VCARD_DONE; |
|
599 |
} |
|
600 |
|
|
601 |
/* now parse the instruction */ |
|
602 |
switch (apdu->a_ins) { |
|
603 |
case VCARD7816_INS_MANAGE_CHANNEL: /* secure channel op */ |
|
604 |
case VCARD7816_INS_EXTERNAL_AUTHENTICATE: /* secure channel op */ |
|
605 |
case VCARD7816_INS_GET_CHALLENGE: /* secure channel op */ |
|
606 |
case VCARD7816_INS_INTERNAL_AUTHENTICATE: /* secure channel op */ |
|
607 |
case VCARD7816_INS_ERASE_BINARY: /* applet control op */ |
|
608 |
case VCARD7816_INS_READ_BINARY: /* applet control op */ |
|
609 |
case VCARD7816_INS_WRITE_BINARY: /* applet control op */ |
|
610 |
case VCARD7816_INS_UPDATE_BINARY: /* applet control op */ |
|
611 |
case VCARD7816_INS_READ_RECORD: /* file op */ |
|
612 |
case VCARD7816_INS_WRITE_RECORD: /* file op */ |
|
613 |
case VCARD7816_INS_UPDATE_RECORD: /* file op */ |
|
614 |
case VCARD7816_INS_APPEND_RECORD: /* file op */ |
|
615 |
case VCARD7816_INS_ENVELOPE: |
|
616 |
case VCARD7816_INS_PUT_DATA: |
|
617 |
*response = vcard_make_response( |
|
618 |
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
619 |
break; |
|
620 |
|
|
621 |
case VCARD7816_INS_SELECT_FILE: |
|
622 |
if (apdu->a_p1 != 0x04) { |
|
623 |
*response = vcard_make_response( |
|
624 |
VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED); |
|
625 |
break; |
|
626 |
} |
|
627 |
|
|
628 |
/* side effect, deselect the current applet if no applet has been found |
|
629 |
* */ |
|
630 |
current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc); |
|
631 |
vcard_select_applet(card, apdu->a_channel, current_applet); |
|
632 |
if (current_applet) { |
|
633 |
unsigned char *aid; |
|
634 |
int aid_len; |
|
635 |
aid = vcard_applet_get_aid(current_applet, &aid_len); |
|
636 |
*response = vcard_response_new(card, aid, aid_len, apdu->a_Le, |
|
637 |
VCARD7816_STATUS_SUCCESS); |
|
638 |
} else { |
|
639 |
*response = vcard_make_response( |
|
640 |
VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); |
|
641 |
} |
|
642 |
break; |
|
643 |
|
|
644 |
case VCARD7816_INS_VERIFY: |
|
645 |
if ((apdu->a_p1 != 0x00) || (apdu->a_p2 != 0x00)) { |
|
646 |
*response = vcard_make_response( |
|
647 |
VCARD7816_STATUS_ERROR_WRONG_PARAMETERS); |
|
648 |
} else { |
|
649 |
if (apdu->a_Lc == 0) { |
|
650 |
/* handle pin count if possible */ |
|
651 |
count = vcard_emul_get_login_count(card); |
|
652 |
if (count < 0) { |
|
653 |
*response = vcard_make_response( |
|
654 |
VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); |
|
655 |
} else { |
|
656 |
if (count > 0xf) { |
|
657 |
count = 0xf; |
|
658 |
} |
|
659 |
*response = vcard_response_new_status_bytes( |
|
660 |
VCARD7816_SW1_WARNING_CHANGE, |
|
661 |
0xc0 | count); |
|
662 |
if (*response == NULL) { |
|
663 |
*response = vcard_make_response( |
|
664 |
VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
665 |
} |
|
666 |
} |
|
667 |
} else { |
|
668 |
status = vcard_emul_login(card, apdu->a_body, apdu->a_Lc); |
|
669 |
*response = vcard_make_response(status); |
|
670 |
} |
|
671 |
} |
|
672 |
break; |
|
673 |
|
|
674 |
case VCARD7816_INS_GET_RESPONSE: |
|
675 |
buffer_response = vcard_get_buffer_response(card); |
|
676 |
if (!buffer_response) { |
|
677 |
*response = vcard_make_response( |
|
678 |
VCARD7816_STATUS_ERROR_DATA_NOT_FOUND); |
|
679 |
/* handle error */ |
|
680 |
break; |
|
681 |
} |
|
682 |
bytes_to_copy = MIN(buffer_response->len, apdu->a_Le); |
|
683 |
next_byte_count = MIN(256, buffer_response->len - bytes_to_copy); |
|
684 |
*response = vcard_response_new_bytes( |
|
685 |
card, buffer_response->current, bytes_to_copy, |
|
686 |
apdu->a_Le, |
|
687 |
next_byte_count ? |
|
688 |
VCARD7816_SW1_RESPONSE_BYTES : VCARD7816_SW1_SUCCESS, |
|
689 |
next_byte_count); |
|
690 |
buffer_response->current += bytes_to_copy; |
|
691 |
buffer_response->len -= bytes_to_copy; |
|
692 |
if (*response == NULL || (next_byte_count == 0)) { |
|
693 |
vcard_set_buffer_response(card, NULL); |
|
694 |
vcard_buffer_response_delete(buffer_response); |
|
695 |
} |
|
696 |
if (*response == NULL) { |
|
697 |
*response = |
|
698 |
vcard_make_response(VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
|
699 |
} |
|
700 |
break; |
|
701 |
|
|
702 |
case VCARD7816_INS_GET_DATA: |
|
703 |
*response = |
|
704 |
vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
705 |
break; |
|
706 |
|
|
707 |
default: |
|
708 |
*response = |
|
709 |
vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
710 |
break; |
|
711 |
} |
|
712 |
|
|
713 |
/* response should have been set somewhere */ |
|
714 |
assert(*response != NULL); |
|
715 |
return VCARD_DONE; |
|
716 |
} |
|
717 |
|
|
718 |
|
|
719 |
/* |
|
720 |
* APDU processing starts here. This routes the card processing stuff to the |
|
721 |
* right location. |
|
722 |
*/ |
|
723 |
VCardStatus |
|
724 |
vcard_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) |
|
725 |
{ |
|
726 |
VCardStatus status; |
|
727 |
VCardBufferResponse *buffer_response; |
|
728 |
|
|
729 |
/* first handle any PTS commands, which aren't really APDU's */ |
|
730 |
if (apdu->a_type == VCARD_7816_PTS) { |
|
731 |
/* the PTS responses aren't really responses either */ |
|
732 |
*response = vcard_response_new_data(apdu->a_data, apdu->a_len); |
|
733 |
/* PTS responses have no status bytes */ |
|
734 |
(*response)->b_total_len = (*response)->b_len; |
|
735 |
return VCARD_DONE; |
|
736 |
} |
|
737 |
buffer_response = vcard_get_buffer_response(card); |
|
738 |
if (buffer_response && apdu->a_ins != VCARD7816_INS_GET_RESPONSE) { |
|
739 |
/* clear out buffer_response, return an error */ |
|
740 |
vcard_set_buffer_response(card, NULL); |
|
741 |
vcard_buffer_response_delete(buffer_response); |
|
742 |
*response = vcard_make_response(VCARD7816_STATUS_EXC_ERROR); |
|
743 |
return VCARD_DONE; |
|
744 |
} |
|
745 |
|
|
746 |
status = vcard_process_applet_apdu(card, apdu, response); |
|
747 |
if (status != VCARD_NEXT) { |
|
748 |
return status; |
|
749 |
} |
|
750 |
switch (vcard_get_type(card)) { |
|
751 |
case VCARD_FILE_SYSTEM: |
|
752 |
return vcard7816_file_system_process_apdu(card, apdu, response); |
|
753 |
case VCARD_VM: |
|
754 |
return vcard7816_vm_process_apdu(card, apdu, response); |
|
755 |
case VCARD_DIRECT: |
|
756 |
/* if we are type direct, then the applet should handle everything */ |
|
757 |
assert("VCARD_DIRECT: applet failure"); |
|
758 |
break; |
|
759 |
} |
|
760 |
*response = |
|
761 |
vcard_make_response(VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
|
762 |
return VCARD_DONE; |
|
763 |
} |
b/libcacard/card_7816.h | ||
---|---|---|
1 |
/* |
|
2 |
* Implement the 7816 portion of the card spec |
|
3 |
* |
|
4 |
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later. |
|
5 |
* See the COPYING.LIB file in the top-level directory. |
|
6 |
*/ |
|
7 |
#ifndef CARD_7816_H |
|
8 |
#define CARD_7816_H 1 |
|
9 |
|
|
10 |
#include "card_7816t.h" |
|
11 |
#include "vcardt.h" |
|
12 |
|
Also available in: Unified diff