root / libcacard / cac.c @ fc27eefe
History | View | Annotate | Download (12.6 kB)
1 | 111a38b0 | Robert Relyea | /*
|
---|---|---|---|
2 | 111a38b0 | Robert Relyea | * implement the applets for the CAC card.
|
3 | 111a38b0 | Robert Relyea | *
|
4 | 111a38b0 | Robert Relyea | * This code is licensed under the GNU LGPL, version 2.1 or later.
|
5 | 111a38b0 | Robert Relyea | * See the COPYING.LIB file in the top-level directory.
|
6 | 111a38b0 | Robert Relyea | */
|
7 | 111a38b0 | Robert Relyea | |
8 | 111a38b0 | Robert Relyea | #include "qemu-common.h" |
9 | 111a38b0 | Robert Relyea | |
10 | 111a38b0 | Robert Relyea | #include "cac.h" |
11 | 111a38b0 | Robert Relyea | #include "vcard.h" |
12 | 111a38b0 | Robert Relyea | #include "vcard_emul.h" |
13 | 111a38b0 | Robert Relyea | #include "card_7816.h" |
14 | 111a38b0 | Robert Relyea | |
15 | 111a38b0 | Robert Relyea | #define CAC_GET_PROPERTIES 0x56 |
16 | 111a38b0 | Robert Relyea | #define CAC_GET_ACR 0x4c |
17 | 111a38b0 | Robert Relyea | #define CAC_READ_BUFFER 0x52 |
18 | 111a38b0 | Robert Relyea | #define CAC_UPDATE_BUFFER 0x58 |
19 | 111a38b0 | Robert Relyea | #define CAC_SIGN_DECRYPT 0x42 |
20 | 111a38b0 | Robert Relyea | #define CAC_GET_CERTIFICATE 0x36 |
21 | 111a38b0 | Robert Relyea | |
22 | 111a38b0 | Robert Relyea | /* private data for PKI applets */
|
23 | 111a38b0 | Robert Relyea | typedef struct CACPKIAppletDataStruct { |
24 | 111a38b0 | Robert Relyea | unsigned char *cert; |
25 | 111a38b0 | Robert Relyea | int cert_len;
|
26 | 111a38b0 | Robert Relyea | unsigned char *cert_buffer; |
27 | 111a38b0 | Robert Relyea | int cert_buffer_len;
|
28 | 111a38b0 | Robert Relyea | unsigned char *sign_buffer; |
29 | 111a38b0 | Robert Relyea | int sign_buffer_len;
|
30 | 111a38b0 | Robert Relyea | VCardKey *key; |
31 | 111a38b0 | Robert Relyea | } CACPKIAppletData; |
32 | 111a38b0 | Robert Relyea | |
33 | 111a38b0 | Robert Relyea | /*
|
34 | 111a38b0 | Robert Relyea | * CAC applet private data
|
35 | 111a38b0 | Robert Relyea | */
|
36 | 111a38b0 | Robert Relyea | struct VCardAppletPrivateStruct {
|
37 | 111a38b0 | Robert Relyea | union {
|
38 | 111a38b0 | Robert Relyea | CACPKIAppletData pki_data; |
39 | 111a38b0 | Robert Relyea | void *reserved;
|
40 | 111a38b0 | Robert Relyea | } u; |
41 | 111a38b0 | Robert Relyea | }; |
42 | 111a38b0 | Robert Relyea | |
43 | 111a38b0 | Robert Relyea | /*
|
44 | 111a38b0 | Robert Relyea | * handle all the APDU's that are common to all CAC applets
|
45 | 111a38b0 | Robert Relyea | */
|
46 | 111a38b0 | Robert Relyea | static VCardStatus
|
47 | 111a38b0 | Robert Relyea | cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) |
48 | 111a38b0 | Robert Relyea | { |
49 | 111a38b0 | Robert Relyea | int ef;
|
50 | 111a38b0 | Robert Relyea | |
51 | 111a38b0 | Robert Relyea | switch (apdu->a_ins) {
|
52 | 111a38b0 | Robert Relyea | case VCARD7816_INS_SELECT_FILE:
|
53 | 111a38b0 | Robert Relyea | if (apdu->a_p1 != 0x02) { |
54 | 111a38b0 | Robert Relyea | /* let the 7816 code handle applet switches */
|
55 | 111a38b0 | Robert Relyea | return VCARD_NEXT;
|
56 | 111a38b0 | Robert Relyea | } |
57 | 111a38b0 | Robert Relyea | /* handle file id setting */
|
58 | 111a38b0 | Robert Relyea | if (apdu->a_Lc != 2) { |
59 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
60 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_DATA_INVALID); |
61 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
62 | 111a38b0 | Robert Relyea | } |
63 | 111a38b0 | Robert Relyea | /* CAC 1.0 only supports ef = 0 */
|
64 | 111a38b0 | Robert Relyea | ef = apdu->a_body[0] | (apdu->a_body[1] << 8); |
65 | 111a38b0 | Robert Relyea | if (ef != 0) { |
66 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
67 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); |
68 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
69 | 111a38b0 | Robert Relyea | } |
70 | 111a38b0 | Robert Relyea | *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); |
71 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
72 | 111a38b0 | Robert Relyea | case VCARD7816_INS_GET_RESPONSE:
|
73 | 111a38b0 | Robert Relyea | case VCARD7816_INS_VERIFY:
|
74 | 111a38b0 | Robert Relyea | /* let the 7816 code handle these */
|
75 | 111a38b0 | Robert Relyea | return VCARD_NEXT;
|
76 | 111a38b0 | Robert Relyea | case CAC_GET_PROPERTIES:
|
77 | 111a38b0 | Robert Relyea | case CAC_GET_ACR:
|
78 | 111a38b0 | Robert Relyea | /* skip these for now, this will probably be needed */
|
79 | 111a38b0 | Robert Relyea | *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
80 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
81 | 111a38b0 | Robert Relyea | } |
82 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
83 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
84 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
85 | 111a38b0 | Robert Relyea | } |
86 | 111a38b0 | Robert Relyea | |
87 | 111a38b0 | Robert Relyea | /*
|
88 | 111a38b0 | Robert Relyea | * reset the inter call state between applet selects
|
89 | 111a38b0 | Robert Relyea | */
|
90 | 111a38b0 | Robert Relyea | static VCardStatus
|
91 | 111a38b0 | Robert Relyea | cac_applet_pki_reset(VCard *card, int channel)
|
92 | 111a38b0 | Robert Relyea | { |
93 | 111a38b0 | Robert Relyea | VCardAppletPrivate *applet_private = NULL;
|
94 | 111a38b0 | Robert Relyea | CACPKIAppletData *pki_applet = NULL;
|
95 | 111a38b0 | Robert Relyea | applet_private = vcard_get_current_applet_private(card, channel); |
96 | 111a38b0 | Robert Relyea | assert(applet_private); |
97 | 111a38b0 | Robert Relyea | pki_applet = &(applet_private->u.pki_data); |
98 | 111a38b0 | Robert Relyea | |
99 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer = NULL;
|
100 | 111a38b0 | Robert Relyea | if (pki_applet->sign_buffer) {
|
101 | 111a38b0 | Robert Relyea | qemu_free(pki_applet->sign_buffer); |
102 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer = NULL;
|
103 | 111a38b0 | Robert Relyea | } |
104 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer_len = 0;
|
105 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer_len = 0;
|
106 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
107 | 111a38b0 | Robert Relyea | } |
108 | 111a38b0 | Robert Relyea | |
109 | 111a38b0 | Robert Relyea | static VCardStatus
|
110 | 111a38b0 | Robert Relyea | cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, |
111 | 111a38b0 | Robert Relyea | VCardResponse **response) |
112 | 111a38b0 | Robert Relyea | { |
113 | 111a38b0 | Robert Relyea | CACPKIAppletData *pki_applet = NULL;
|
114 | 111a38b0 | Robert Relyea | VCardAppletPrivate *applet_private = NULL;
|
115 | 111a38b0 | Robert Relyea | int size, next;
|
116 | 111a38b0 | Robert Relyea | unsigned char *sign_buffer; |
117 | 111a38b0 | Robert Relyea | vcard_7816_status_t status; |
118 | 111a38b0 | Robert Relyea | |
119 | 111a38b0 | Robert Relyea | applet_private = vcard_get_current_applet_private(card, apdu->a_channel); |
120 | 111a38b0 | Robert Relyea | assert(applet_private); |
121 | 111a38b0 | Robert Relyea | pki_applet = &(applet_private->u.pki_data); |
122 | 111a38b0 | Robert Relyea | |
123 | 111a38b0 | Robert Relyea | switch (apdu->a_ins) {
|
124 | 111a38b0 | Robert Relyea | case CAC_UPDATE_BUFFER:
|
125 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
126 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); |
127 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
128 | 111a38b0 | Robert Relyea | case CAC_GET_CERTIFICATE:
|
129 | 111a38b0 | Robert Relyea | if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { |
130 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
131 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
132 | 111a38b0 | Robert Relyea | break;
|
133 | 111a38b0 | Robert Relyea | } |
134 | 111a38b0 | Robert Relyea | assert(pki_applet->cert != NULL);
|
135 | 111a38b0 | Robert Relyea | size = apdu->a_Le; |
136 | 111a38b0 | Robert Relyea | if (pki_applet->cert_buffer == NULL) { |
137 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer = pki_applet->cert; |
138 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer_len = pki_applet->cert_len; |
139 | 111a38b0 | Robert Relyea | } |
140 | 111a38b0 | Robert Relyea | size = MIN(size, pki_applet->cert_buffer_len); |
141 | 111a38b0 | Robert Relyea | next = MIN(255, pki_applet->cert_buffer_len - size);
|
142 | 111a38b0 | Robert Relyea | *response = vcard_response_new_bytes( |
143 | 111a38b0 | Robert Relyea | card, pki_applet->cert_buffer, size, |
144 | 111a38b0 | Robert Relyea | apdu->a_Le, next ? |
145 | 111a38b0 | Robert Relyea | VCARD7816_SW1_WARNING_CHANGE : |
146 | 111a38b0 | Robert Relyea | VCARD7816_SW1_SUCCESS, |
147 | 111a38b0 | Robert Relyea | next); |
148 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer += size; |
149 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer_len -= size; |
150 | 111a38b0 | Robert Relyea | if ((*response == NULL) || (next == 0)) { |
151 | 111a38b0 | Robert Relyea | pki_applet->cert_buffer = NULL;
|
152 | 111a38b0 | Robert Relyea | } |
153 | 111a38b0 | Robert Relyea | if (*response == NULL) { |
154 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
155 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
156 | 111a38b0 | Robert Relyea | } |
157 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
158 | 111a38b0 | Robert Relyea | case CAC_SIGN_DECRYPT:
|
159 | 111a38b0 | Robert Relyea | if (apdu->a_p2 != 0) { |
160 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
161 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
162 | 111a38b0 | Robert Relyea | break;
|
163 | 111a38b0 | Robert Relyea | } |
164 | 111a38b0 | Robert Relyea | size = apdu->a_Lc; |
165 | 111a38b0 | Robert Relyea | |
166 | 111a38b0 | Robert Relyea | sign_buffer = realloc(pki_applet->sign_buffer, |
167 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer_len+size); |
168 | 111a38b0 | Robert Relyea | if (sign_buffer == NULL) { |
169 | 111a38b0 | Robert Relyea | qemu_free(pki_applet->sign_buffer); |
170 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer = NULL;
|
171 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer_len = 0;
|
172 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
173 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
174 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
175 | 111a38b0 | Robert Relyea | } |
176 | 111a38b0 | Robert Relyea | memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size); |
177 | 111a38b0 | Robert Relyea | size += pki_applet->sign_buffer_len; |
178 | 111a38b0 | Robert Relyea | switch (apdu->a_p1) {
|
179 | 111a38b0 | Robert Relyea | case 0x80: |
180 | 111a38b0 | Robert Relyea | /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
|
181 | 111a38b0 | Robert Relyea | * the rest */
|
182 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer = sign_buffer; |
183 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer_len = size; |
184 | 111a38b0 | Robert Relyea | *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); |
185 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
186 | 111a38b0 | Robert Relyea | case 0x00: |
187 | 111a38b0 | Robert Relyea | /* we now have the whole buffer, do the operation, result will be
|
188 | 111a38b0 | Robert Relyea | * in the sign_buffer */
|
189 | 111a38b0 | Robert Relyea | status = vcard_emul_rsa_op(card, pki_applet->key, |
190 | 111a38b0 | Robert Relyea | sign_buffer, size); |
191 | 111a38b0 | Robert Relyea | if (status != VCARD7816_STATUS_SUCCESS) {
|
192 | 111a38b0 | Robert Relyea | *response = vcard_make_response(status); |
193 | 111a38b0 | Robert Relyea | break;
|
194 | 111a38b0 | Robert Relyea | } |
195 | 111a38b0 | Robert Relyea | *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, |
196 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_SUCCESS); |
197 | 111a38b0 | Robert Relyea | if (*response == NULL) { |
198 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
199 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); |
200 | 111a38b0 | Robert Relyea | } |
201 | 111a38b0 | Robert Relyea | break;
|
202 | 111a38b0 | Robert Relyea | default:
|
203 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
204 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); |
205 | 111a38b0 | Robert Relyea | break;
|
206 | 111a38b0 | Robert Relyea | } |
207 | 111a38b0 | Robert Relyea | qemu_free(sign_buffer); |
208 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer = NULL;
|
209 | 111a38b0 | Robert Relyea | pki_applet->sign_buffer_len = 0;
|
210 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
211 | 111a38b0 | Robert Relyea | case CAC_READ_BUFFER:
|
212 | 111a38b0 | Robert Relyea | /* new CAC call, go ahead and use the old version for now */
|
213 | 111a38b0 | Robert Relyea | /* TODO: implement */
|
214 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
215 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
216 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
217 | 111a38b0 | Robert Relyea | } |
218 | 111a38b0 | Robert Relyea | return cac_common_process_apdu(card, apdu, response);
|
219 | 111a38b0 | Robert Relyea | } |
220 | 111a38b0 | Robert Relyea | |
221 | 111a38b0 | Robert Relyea | |
222 | 111a38b0 | Robert Relyea | static VCardStatus
|
223 | 111a38b0 | Robert Relyea | cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, |
224 | 111a38b0 | Robert Relyea | VCardResponse **response) |
225 | 111a38b0 | Robert Relyea | { |
226 | 111a38b0 | Robert Relyea | switch (apdu->a_ins) {
|
227 | 111a38b0 | Robert Relyea | case CAC_UPDATE_BUFFER:
|
228 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
229 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); |
230 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
231 | 111a38b0 | Robert Relyea | case CAC_READ_BUFFER:
|
232 | 111a38b0 | Robert Relyea | /* new CAC call, go ahead and use the old version for now */
|
233 | 111a38b0 | Robert Relyea | /* TODO: implement */
|
234 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
235 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
236 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
237 | 111a38b0 | Robert Relyea | } |
238 | 111a38b0 | Robert Relyea | return cac_common_process_apdu(card, apdu, response);
|
239 | 111a38b0 | Robert Relyea | } |
240 | 111a38b0 | Robert Relyea | |
241 | 111a38b0 | Robert Relyea | |
242 | 111a38b0 | Robert Relyea | /*
|
243 | 111a38b0 | Robert Relyea | * TODO: if we ever want to support general CAC middleware, we will need to
|
244 | 111a38b0 | Robert Relyea | * implement the various containers.
|
245 | 111a38b0 | Robert Relyea | */
|
246 | 111a38b0 | Robert Relyea | static VCardStatus
|
247 | 111a38b0 | Robert Relyea | cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, |
248 | 111a38b0 | Robert Relyea | VCardResponse **response) |
249 | 111a38b0 | Robert Relyea | { |
250 | 111a38b0 | Robert Relyea | switch (apdu->a_ins) {
|
251 | 111a38b0 | Robert Relyea | case CAC_READ_BUFFER:
|
252 | 111a38b0 | Robert Relyea | case CAC_UPDATE_BUFFER:
|
253 | 111a38b0 | Robert Relyea | *response = vcard_make_response( |
254 | 111a38b0 | Robert Relyea | VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); |
255 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
256 | 111a38b0 | Robert Relyea | default:
|
257 | 111a38b0 | Robert Relyea | break;
|
258 | 111a38b0 | Robert Relyea | } |
259 | 111a38b0 | Robert Relyea | return cac_common_process_apdu(card, apdu, response);
|
260 | 111a38b0 | Robert Relyea | } |
261 | 111a38b0 | Robert Relyea | |
262 | 111a38b0 | Robert Relyea | /*
|
263 | 111a38b0 | Robert Relyea | * utilities for creating and destroying the private applet data
|
264 | 111a38b0 | Robert Relyea | */
|
265 | 111a38b0 | Robert Relyea | static void |
266 | 111a38b0 | Robert Relyea | cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) |
267 | 111a38b0 | Robert Relyea | { |
268 | 111a38b0 | Robert Relyea | CACPKIAppletData *pki_applet_data = NULL;
|
269 | 111a38b0 | Robert Relyea | if (pki_applet_data == NULL) { |
270 | 111a38b0 | Robert Relyea | return;
|
271 | 111a38b0 | Robert Relyea | } |
272 | 111a38b0 | Robert Relyea | pki_applet_data = &(applet_private->u.pki_data); |
273 | 111a38b0 | Robert Relyea | if (pki_applet_data->cert != NULL) { |
274 | 111a38b0 | Robert Relyea | qemu_free(pki_applet_data->cert); |
275 | 111a38b0 | Robert Relyea | } |
276 | 111a38b0 | Robert Relyea | if (pki_applet_data->sign_buffer != NULL) { |
277 | 111a38b0 | Robert Relyea | qemu_free(pki_applet_data->sign_buffer); |
278 | 111a38b0 | Robert Relyea | } |
279 | 111a38b0 | Robert Relyea | if (pki_applet_data->key != NULL) { |
280 | 111a38b0 | Robert Relyea | vcard_emul_delete_key(pki_applet_data->key); |
281 | 111a38b0 | Robert Relyea | } |
282 | 111a38b0 | Robert Relyea | qemu_free(applet_private); |
283 | 111a38b0 | Robert Relyea | } |
284 | 111a38b0 | Robert Relyea | |
285 | 111a38b0 | Robert Relyea | static VCardAppletPrivate *
|
286 | 111a38b0 | Robert Relyea | cac_new_pki_applet_private(const unsigned char *cert, |
287 | 111a38b0 | Robert Relyea | int cert_len, VCardKey *key)
|
288 | 111a38b0 | Robert Relyea | { |
289 | 111a38b0 | Robert Relyea | CACPKIAppletData *pki_applet_data = NULL;
|
290 | 111a38b0 | Robert Relyea | VCardAppletPrivate *applet_private = NULL;
|
291 | 111a38b0 | Robert Relyea | applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate));
|
292 | 111a38b0 | Robert Relyea | |
293 | 111a38b0 | Robert Relyea | pki_applet_data = &(applet_private->u.pki_data); |
294 | 111a38b0 | Robert Relyea | pki_applet_data->cert_buffer = NULL;
|
295 | 111a38b0 | Robert Relyea | pki_applet_data->cert_buffer_len = 0;
|
296 | 111a38b0 | Robert Relyea | pki_applet_data->sign_buffer = NULL;
|
297 | 111a38b0 | Robert Relyea | pki_applet_data->sign_buffer_len = 0;
|
298 | 111a38b0 | Robert Relyea | pki_applet_data->key = NULL;
|
299 | 111a38b0 | Robert Relyea | pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1); |
300 | 111a38b0 | Robert Relyea | /*
|
301 | 111a38b0 | Robert Relyea | * if we want to support compression, then we simply change the 0 to a 1
|
302 | 111a38b0 | Robert Relyea | * and compress the cert data with libz
|
303 | 111a38b0 | Robert Relyea | */
|
304 | 111a38b0 | Robert Relyea | pki_applet_data->cert[0] = 0; /* not compressed */ |
305 | 111a38b0 | Robert Relyea | memcpy(&pki_applet_data->cert[1], cert, cert_len);
|
306 | 111a38b0 | Robert Relyea | pki_applet_data->cert_len = cert_len+1;
|
307 | 111a38b0 | Robert Relyea | |
308 | 111a38b0 | Robert Relyea | pki_applet_data->key = key; |
309 | 111a38b0 | Robert Relyea | return applet_private;
|
310 | 111a38b0 | Robert Relyea | } |
311 | 111a38b0 | Robert Relyea | |
312 | 111a38b0 | Robert Relyea | |
313 | 111a38b0 | Robert Relyea | /*
|
314 | 111a38b0 | Robert Relyea | * create a new cac applet which links to a given cert
|
315 | 111a38b0 | Robert Relyea | */
|
316 | 111a38b0 | Robert Relyea | static VCardApplet *
|
317 | 111a38b0 | Robert Relyea | cac_new_pki_applet(int i, const unsigned char *cert, |
318 | 111a38b0 | Robert Relyea | int cert_len, VCardKey *key)
|
319 | 111a38b0 | Robert Relyea | { |
320 | 111a38b0 | Robert Relyea | VCardAppletPrivate *applet_private = NULL;
|
321 | 111a38b0 | Robert Relyea | VCardApplet *applet = NULL;
|
322 | 111a38b0 | Robert Relyea | unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; |
323 | 111a38b0 | Robert Relyea | int pki_aid_len = sizeof(pki_aid); |
324 | 111a38b0 | Robert Relyea | |
325 | 111a38b0 | Robert Relyea | pki_aid[pki_aid_len-1] = i;
|
326 | 111a38b0 | Robert Relyea | |
327 | 111a38b0 | Robert Relyea | applet_private = cac_new_pki_applet_private(cert, cert_len, key); |
328 | 111a38b0 | Robert Relyea | if (applet_private == NULL) { |
329 | 111a38b0 | Robert Relyea | goto failure;
|
330 | 111a38b0 | Robert Relyea | } |
331 | 111a38b0 | Robert Relyea | applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, |
332 | 111a38b0 | Robert Relyea | pki_aid, pki_aid_len); |
333 | 111a38b0 | Robert Relyea | if (applet == NULL) { |
334 | 111a38b0 | Robert Relyea | goto failure;
|
335 | 111a38b0 | Robert Relyea | } |
336 | 111a38b0 | Robert Relyea | vcard_set_applet_private(applet, applet_private, |
337 | 111a38b0 | Robert Relyea | cac_delete_pki_applet_private); |
338 | 111a38b0 | Robert Relyea | applet_private = NULL;
|
339 | 111a38b0 | Robert Relyea | |
340 | 111a38b0 | Robert Relyea | return applet;
|
341 | 111a38b0 | Robert Relyea | |
342 | 111a38b0 | Robert Relyea | failure:
|
343 | 111a38b0 | Robert Relyea | if (applet_private != NULL) { |
344 | 111a38b0 | Robert Relyea | cac_delete_pki_applet_private(applet_private); |
345 | 111a38b0 | Robert Relyea | } |
346 | 111a38b0 | Robert Relyea | return NULL; |
347 | 111a38b0 | Robert Relyea | } |
348 | 111a38b0 | Robert Relyea | |
349 | 111a38b0 | Robert Relyea | |
350 | 111a38b0 | Robert Relyea | static unsigned char cac_default_container_aid[] = { |
351 | 111a38b0 | Robert Relyea | 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; |
352 | 111a38b0 | Robert Relyea | static unsigned char cac_id_aid[] = { |
353 | 111a38b0 | Robert Relyea | 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; |
354 | 111a38b0 | Robert Relyea | /*
|
355 | 111a38b0 | Robert Relyea | * Initialize the cac card. This is the only public function in this file. All
|
356 | 111a38b0 | Robert Relyea | * the rest are connected through function pointers.
|
357 | 111a38b0 | Robert Relyea | */
|
358 | 111a38b0 | Robert Relyea | VCardStatus |
359 | 111a38b0 | Robert Relyea | cac_card_init(VReader *reader, VCard *card, |
360 | 111a38b0 | Robert Relyea | const char *params, |
361 | 111a38b0 | Robert Relyea | unsigned char * const *cert, |
362 | 111a38b0 | Robert Relyea | int cert_len[],
|
363 | 111a38b0 | Robert Relyea | VCardKey *key[] /* adopt the keys*/,
|
364 | 111a38b0 | Robert Relyea | int cert_count)
|
365 | 111a38b0 | Robert Relyea | { |
366 | 111a38b0 | Robert Relyea | int i;
|
367 | 111a38b0 | Robert Relyea | VCardApplet *applet; |
368 | 111a38b0 | Robert Relyea | |
369 | 111a38b0 | Robert Relyea | /* CAC Cards are VM Cards */
|
370 | 111a38b0 | Robert Relyea | vcard_set_type(card, VCARD_VM); |
371 | 111a38b0 | Robert Relyea | |
372 | 111a38b0 | Robert Relyea | /* create one PKI applet for each cert */
|
373 | 111a38b0 | Robert Relyea | for (i = 0; i < cert_count; i++) { |
374 | 111a38b0 | Robert Relyea | applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); |
375 | 111a38b0 | Robert Relyea | if (applet == NULL) { |
376 | 111a38b0 | Robert Relyea | goto failure;
|
377 | 111a38b0 | Robert Relyea | } |
378 | 111a38b0 | Robert Relyea | vcard_add_applet(card, applet); |
379 | 111a38b0 | Robert Relyea | } |
380 | 111a38b0 | Robert Relyea | |
381 | 111a38b0 | Robert Relyea | /* create a default blank container applet */
|
382 | 111a38b0 | Robert Relyea | applet = vcard_new_applet(cac_applet_container_process_apdu, |
383 | 111a38b0 | Robert Relyea | NULL, cac_default_container_aid,
|
384 | 111a38b0 | Robert Relyea | sizeof(cac_default_container_aid));
|
385 | 111a38b0 | Robert Relyea | if (applet == NULL) { |
386 | 111a38b0 | Robert Relyea | goto failure;
|
387 | 111a38b0 | Robert Relyea | } |
388 | 111a38b0 | Robert Relyea | vcard_add_applet(card, applet); |
389 | 111a38b0 | Robert Relyea | |
390 | 111a38b0 | Robert Relyea | /* create a default blank container applet */
|
391 | 111a38b0 | Robert Relyea | applet = vcard_new_applet(cac_applet_id_process_apdu, |
392 | 111a38b0 | Robert Relyea | NULL, cac_id_aid,
|
393 | 111a38b0 | Robert Relyea | sizeof(cac_id_aid));
|
394 | 111a38b0 | Robert Relyea | if (applet == NULL) { |
395 | 111a38b0 | Robert Relyea | goto failure;
|
396 | 111a38b0 | Robert Relyea | } |
397 | 111a38b0 | Robert Relyea | vcard_add_applet(card, applet); |
398 | 111a38b0 | Robert Relyea | return VCARD_DONE;
|
399 | 111a38b0 | Robert Relyea | |
400 | 111a38b0 | Robert Relyea | failure:
|
401 | 111a38b0 | Robert Relyea | return VCARD_FAIL;
|
402 | 111a38b0 | Robert Relyea | } |