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