1 /* $Id: cyberflex.c,v 1.3 2001/08/02 16:41:32 rees Exp $ */
2
3 /*
4 copyright 2000
5 the regents of the university of michigan
6 all rights reserved
7
8 permission is granted to use, copy, create derivative works
9 and redistribute this software and such derivative works
10 for any purpose, so long as the name of the university of
11 michigan is not used in any advertising or publicity
12 pertaining to the use or distribution of this software
13 without specific, written prior authorization. if the
14 above copyright notice or any other identification of the
15 university of michigan is included in any copy of any
16 portion of this software, then the disclaimer below must
17 also be included.
18
19 this software is provided as is, without representation
20 from the university of michigan as to its fitness for any
21 purpose, and without warranty by the university of
22 michigan of any kind, either express or implied, including
23 without limitation the implied warranties of
24 merchantability and fitness for a particular purpose. the
25 regents of the university of michigan shall not be liable
26 for any damages, including special, indirect, incidental, or
27 consequential damages, with respect to any claim arising
28 out of or in connection with the use of the software, even
29 if it has been or is hereafter advised of the possibility of
30 such damages.
31 */
32
33 /*
34 * Cyberflex routines
35 *
36 * University of Michigan CITI, July 2001
37 */
38
39 #ifdef __palmos__
40 #include <Common.h>
41 #include <System/SysAll.h>
42 #include <System/Unix/unix_stdlib.h>
43 #include <System/Unix/unix_string.h>
44 #include <UI/UIAll.h>
45 #include "field.h"
46 #else
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <stdio.h>
50 #include <string.h>
51 #endif
52
53 #include "sectok.h"
54
55 #define MAX_APDU_SIZE 0xfa
56 #define MAX_KEY_FILE_SIZE 1024
57 #define PRV_KEY_SIZE 64*6
58 #define key_number 0x10
59 #define key_type 0xc8 /* key type 0xc8 (1024 bit RSA private) */
60 #define KEY_FILE_HEADER_SIZE 8
61 #define BLOCK_SIZE 8
62
63 int
cyberflex_create_file_acl(int fd,int cla,unsigned char * fid,int size,int ftype,unsigned char * acl,int * swp)64 cyberflex_create_file_acl(int fd, int cla, unsigned char *fid, int size, int ftype, unsigned char *acl, int *swp)
65 {
66 unsigned char data[16];
67
68 size += 16;
69
70 data[0] = (size >> 8);
71 data[1] = (size & 0xff);
72 data[2] = fid[0];
73 data[3] = fid[1];
74 data[4] = ftype;
75 data[5] = 0x01; /* status = 1 */
76 data[6] = data[7] = 0x00; /* record related */
77 memcpy(&data[8], acl, 8);
78
79 sectok_apdu(fd, cla, 0xe0, 0, 0, 0x10, data, 0, NULL, swp);
80 if (!sectok_swOK(*swp))
81 return -1;
82
83 return sectok_selectfile(fd, cla, fid, swp);
84 }
85
86 /* Create a file with default acl "world: r w x/a inval rehab dec inc" */
87
88 int
cyberflex_create_file(int fd,int cla,unsigned char * fid,int size,int ftype,int * swp)89 cyberflex_create_file(int fd, int cla, unsigned char *fid, int size, int ftype, int *swp)
90 {
91 static unsigned char acl[] = {0xff, 0, 0, 0, 0, 0, 0, 0};
92
93 return cyberflex_create_file_acl(fd, cla, fid, size, ftype, acl, swp);
94 }
95
96 int
cyberflex_delete_file(int fd,int cla,unsigned char * fid,int * swp)97 cyberflex_delete_file(int fd, int cla, unsigned char *fid, int *swp)
98 {
99 sectok_apdu(fd, cla, 0xe4, 0, 0, 0x02, fid, 0, NULL, swp);
100 if (!sectok_swOK(*swp))
101 return -1;
102
103 return 0;
104 }
105
106 int
cyberflex_load_rsa_pub(int fd,int cla,unsigned char * key_fid,int key_len,unsigned char * key_data,int * swp)107 cyberflex_load_rsa_pub(int fd, int cla, unsigned char *key_fid,
108 int key_len, unsigned char *key_data, int *swp)
109 {
110 static unsigned char acl[] = {0x1, 0, 0, 0xb, 0, 0, 0, 0};
111
112 if (sectok_selectfile(fd, cla, root_fid, swp) < 0)
113 return -1;
114
115 if (sectok_selectfile(fd, cla, key_fid, swp) < 0 && *swp == STENOFILE) {
116 if (cyberflex_create_file_acl(fd, cla, key_fid, key_len, 3, acl, swp) < 0)
117 return -1;
118 }
119
120 /* Write the key data */
121 sectok_apdu(fd, cla, 0xd6, 0, 0, key_len, key_data, 0, NULL, swp);
122 if (!sectok_swOK(*swp))
123 return -1;
124
125 return 0;
126 }
127
128 /* download RSA private key into 3f.00/00.12 */
129 int
cyberflex_load_rsa_priv(int fd,int cla,unsigned char * key_fid,int nkey_elems,int key_len,unsigned char * key_elems[],int * swp)130 cyberflex_load_rsa_priv(int fd, int cla, unsigned char *key_fid,
131 int nkey_elems, int key_len, unsigned char *key_elems[],
132 int *swp)
133 {
134 int i, j, offset = 0, size;
135 unsigned char data[MAX_KEY_FILE_SIZE];
136 static unsigned char acl[] = {0, 0, 0, 0xa, 0, 0, 0, 0}; /* AUT0: w inval */
137 static unsigned char key_file_header[KEY_FILE_HEADER_SIZE] =
138 {0xC2, 0x06, 0xC1, 0x08, 0x13, 0x00, 0x00, 0x05};
139 static unsigned char key_header[3] = {0xC2, 0x41, 0x00};
140
141 /* select 3f.00 */
142 if (sectok_selectfile(fd, cla, root_fid, swp) < 0)
143 return -1;
144
145 /* select 00.12 */
146 if (sectok_selectfile(fd, cla, key_fid, swp) < 0 && *swp == STENOFILE) {
147 /* rv != 0, 00.12 does not exist. create it. */
148 if (cyberflex_create_file_acl(fd, cla, key_fid, PRV_KEY_SIZE, 3, acl, swp) < 0)
149 return -1;
150 }
151
152 /* burn the key */
153 data[0] = 0x01; /* key size, I guess */
154 data[1] = 0x5b; /* key size, I guess */
155 data[2] = key_number; /* key number */
156 data[3] = key_type;
157 offset = 4;
158 for (j = 0 ; j < KEY_FILE_HEADER_SIZE ; j ++)
159 data[offset++] = key_file_header[j];
160 for (i = 0 ; i < nkey_elems; i ++) {
161 /* put the key header */
162 for (j = 0 ; j < 3 ; j ++) {
163 data[offset++] = key_header[j];
164 }
165 for (j = 0 ; j < key_len/2/8 ; j ++) {
166 data[offset++] = key_elems [i][j];
167 }
168 }
169 for (j = 0 ; j < 2 ; j ++) data[offset++] = 0;
170
171 #ifdef DEBUG
172 printf ("data:\n");
173 for (i = 0 ; i < 0x015d; i ++) {
174 printf ("%02x ", data[i]);
175 }
176 printf ("\n");
177 #endif
178
179 /* now send this to the card */
180 /* select private key file */
181 if (sectok_selectfile(fd, cla, key_fid, swp) < 0)
182 return -1;
183
184 /* update binary */
185 size = offset;
186
187 for (i = 0; i < size; i += MAX_APDU_SIZE) {
188 int send_size;
189
190 /* compute the size to be sent */
191 if (size - i > MAX_APDU_SIZE) send_size = MAX_APDU_SIZE;
192 else send_size = size - i;
193
194 sectok_apdu(fd, cla, 0xd6, i >> 8, i & 0xff, send_size, data + i, 0, NULL, swp);
195
196 if (!sectok_swOK(*swp))
197 return -1;
198 }
199
200 return 0;
201 }
202
203 int
cyberflex_verify_AUT0(int fd,int cla,unsigned char * aut0,int aut0len)204 cyberflex_verify_AUT0(int fd, int cla, unsigned char *aut0, int aut0len)
205 {
206 int sw;
207
208 sectok_apdu(fd, cla, 0x2a, 0, 0, aut0len, aut0, 0, NULL, &sw);
209 if (!sectok_swOK(sw))
210 return -1;
211
212 return 0;
213 }
214
215 /* fill the key block.
216
217 Input
218 dst : destination buffer
219 key_num : key number (0: AUT, 5: signed applet, etc.)
220 alg_num : algorithm number
221 key : incoming 8 byte DES key
222
223 The resulting format:
224 00 0e key_num alg_num key(8 byte) 0a 0a
225
226 total 14 byte
227 */
228 void
cyberflex_fill_key_block(unsigned char * dst,int key_num,int alg_num,unsigned char * key)229 cyberflex_fill_key_block (unsigned char *dst, int key_num,
230 int alg_num, unsigned char *key)
231 {
232 int i;
233
234 *(dst+0) = 0x00; /* const */
235 *(dst+1) = 0x0e; /* const */
236 *(dst+2) = key_num; /* key number */
237 *(dst+3) = alg_num; /* algorithm number */
238 for (i = 0; i < BLOCK_SIZE; i++)
239 *(dst+i+4) = *(key+i);
240 *(dst+12) = 0x0a; /* const */
241 *(dst+13) = 0x0a; /* const */
242
243 return;
244 }
245
246 int
cyberflex_inq_class(int fd)247 cyberflex_inq_class(int fd)
248 {
249 unsigned char buf[32];
250 int n, sw;
251
252 n = sectok_apdu(fd, 0x00, 0xca, 0, 1, 0, NULL, 0x16, buf, &sw);
253 if (sectok_swOK(sw))
254 return 0x00;
255
256 if (n >= 0 && sectok_r1(sw) == 0x6d) {
257 /* F0 card? */
258 sectok_apdu(fd, 0xf0, 0xca, 0, 1, 0, NULL, 0x16, buf, &sw);
259 if (sectok_swOK(sw))
260 return 0xf0;
261 }
262
263 return -1;
264 }
265