1 /*****************************************************************************
2 * Copyright ©2017-2019 Gemalto – a Thales Company. All rights Reserved.
3 *
4 * This copy is licensed under the Apache License, Version 2.0 (the "License");
5 * You may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0 or https://www.apache.org/licenses/LICENSE-2.0.html
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and limitations under the License.
11
12 ****************************************************************************/
13
14 /**
15 * @file
16 * $Author$
17 * $Revision$
18 * $Date$
19 *
20 * libse-gto main functions.
21 *
22 */
23
24 #include <ctype.h>
25 #include <cutils/properties.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <log/log.h>
29 #include <stdarg.h>
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/ioctl.h>
36 #include <unistd.h>
37
38 #include "libse-gto-private.h"
39 #include "se-gto/libse-gto.h"
40 #include "spi.h"
41
42 #define SE_GTO_GTODEV "/dev/gto"
43
44 SE_GTO_EXPORT void *
se_gto_get_userdata(struct se_gto_ctx * ctx)45 se_gto_get_userdata(struct se_gto_ctx *ctx)
46 {
47 if (ctx == NULL)
48 return NULL;
49
50 return ctx->userdata;
51 }
52
53 SE_GTO_EXPORT void
se_gto_set_userdata(struct se_gto_ctx * ctx,void * userdata)54 se_gto_set_userdata(struct se_gto_ctx *ctx, void *userdata)
55 {
56 if (ctx == NULL)
57 return;
58
59 ctx->userdata = userdata;
60 }
61
62 static int
log_level(const char * priority)63 log_level(const char *priority)
64 {
65 char *endptr;
66 int prio;
67
68 prio = strtol(priority, &endptr, 10);
69 if ((endptr[0] == '\0') || isspace(endptr[0]))
70 return prio;
71
72 if (strncmp(priority, "err", 3) == 0)
73 return 0;
74
75 if (strncmp(priority, "info", 4) == 0)
76 return 3;
77
78 if (strncmp(priority, "debug", 5) == 0)
79 return 4;
80
81 return 0;
82 }
83
84 static void
log_stderr(struct se_gto_ctx * ctx,const char * s)85 log_stderr(struct se_gto_ctx *ctx, const char *s)
86 {
87 //fputs(s, stderr);
88 ALOGD("%s",s);
89 }
90
91 SE_GTO_EXPORT int
se_gto_new(struct se_gto_ctx ** c)92 se_gto_new(struct se_gto_ctx **c)
93 {
94 const char *env;
95 struct se_gto_ctx *ctx;
96
97 ctx = calloc(1, sizeof(struct se_gto_ctx));
98 if (!ctx) {
99 errno = ENOMEM;
100 return -1;
101 }
102
103 isot1_init(&ctx->t1);
104
105 ctx->log_fn = log_stderr;
106
107 ctx->gtodev = SE_GTO_GTODEV;
108
109 ctx->log_level = 2;
110 /* environment overwrites config */
111 env = getenv("SE_GTO_LOG");
112 if (env != NULL)
113 se_gto_set_log_level(ctx, log_level(env));
114
115 dbg("ctx %p created\n", ctx);
116 dbg("log_level=%d\n", ctx->log_level);
117 *c = ctx;
118 return 0;
119 }
120
121 SE_GTO_EXPORT int
se_gto_get_log_level(struct se_gto_ctx * ctx)122 se_gto_get_log_level(struct se_gto_ctx *ctx)
123 {
124 return ctx->log_level;
125 }
126
127 SE_GTO_EXPORT void
se_gto_set_log_level(struct se_gto_ctx * ctx,int level)128 se_gto_set_log_level(struct se_gto_ctx *ctx, int level)
129 {
130 if (level < 0)
131 level = 0;
132 else if (level > 4)
133 level = 4;
134 ctx->log_level = level;
135 }
136
137 SE_GTO_EXPORT se_gto_log_fn *
se_gto_get_log_fn(struct se_gto_ctx * ctx)138 se_gto_get_log_fn(struct se_gto_ctx *ctx)
139 {
140 return ctx->log_fn;
141 }
142
143 SE_GTO_EXPORT void
se_gto_set_log_fn(struct se_gto_ctx * ctx,se_gto_log_fn * fn)144 se_gto_set_log_fn(struct se_gto_ctx *ctx, se_gto_log_fn *fn)
145 {
146 ctx->log_fn = fn;
147 }
148
149 SE_GTO_EXPORT const char *
se_gto_get_gtodev(struct se_gto_ctx * ctx)150 se_gto_get_gtodev(struct se_gto_ctx *ctx)
151 {
152 return ctx->gtodev;
153 }
154
155 SE_GTO_EXPORT void
se_gto_set_gtodev(struct se_gto_ctx * ctx,const char * gtodev)156 se_gto_set_gtodev(struct se_gto_ctx *ctx, const char *gtodev)
157 {
158 ctx->gtodev = strdup(gtodev);
159 }
160
161 SE_GTO_EXPORT int
se_gto_reset(struct se_gto_ctx * ctx,void * atr,size_t r)162 se_gto_reset(struct se_gto_ctx *ctx, void *atr, size_t r)
163 {
164 int err;
165
166 err = isot1_reset(&ctx->t1);
167 if (err < 0) {
168 errno = -err;
169 ctx->check_alive = 1;
170 }
171 else {
172 err = isot1_get_atr(&ctx->t1, atr, r);
173 if (err < 0)
174 errno = -err;
175 }
176 return err;
177 }
178
179 SE_GTO_EXPORT int
se_gto_apdu_transmit(struct se_gto_ctx * ctx,const void * apdu,int n,void * resp,int r)180 se_gto_apdu_transmit(struct se_gto_ctx *ctx, const void *apdu, int n, void *resp, int r)
181 {
182 if (!apdu || (n < 4) || !resp || (r < 2)) {
183 errno = EINVAL;
184 return -1;
185 }
186 r = isot1_transceive(&ctx->t1, apdu, n, resp, r);
187 dbg("isot1_transceive: r=%d\n", r);
188 dbg("isot1_transceive: ctx->t1.recv.end - ctx->t1.recv.start = %ld\n", ctx->t1.recv.end - ctx->t1.recv.start);
189 dbg("isot1_transceive: ctx->t1.recv.size = %zu\n", ctx->t1.recv.size);
190 dbg("isot1_transceive: ctx->t1.buf[2] = %02X\n", ctx->t1.buf[2]);
191 if (r < 0) {
192 errno = -r;
193 err("failed to read APDU response, %s\n", strerror(-r));
194 } else if (r < 2) {
195 err("APDU response too short, only %d bytes, needs 2 at least\n", r);
196 }
197 if (r < 2){
198 ctx->check_alive = 1;
199 return -1;
200 } else
201 return r;
202 }
203
204 SE_GTO_EXPORT int
se_gto_open(struct se_gto_ctx * ctx)205 se_gto_open(struct se_gto_ctx *ctx)
206 {
207 info("eSE GTO: using %s\n", ctx->gtodev);
208
209 if (spi_setup(ctx) < 0) {
210 err("failed to set up se-gto.\n");
211 return -1;
212 }
213
214 ctx->check_alive = 0;
215
216 isot1_bind(&ctx->t1, 0x2, 0x1);
217
218 dbg("fd: spi=%d\n", ctx->t1.spi_fd);
219 return 0;
220 }
221
222 #define SPI_IOC_MAGIC 'k'
223 #define ST54SPI_IOC_WR_POWER _IOW(SPI_IOC_MAGIC, 99, __u32)
224
se_gto_Spi_Reset(struct se_gto_ctx * ctx)225 int se_gto_Spi_Reset(struct se_gto_ctx *ctx)
226 {
227 uint32_t io_code;
228 uint32_t power = 0;
229
230 printf("Send software reset via ioctl\n");
231 io_code = ST54SPI_IOC_WR_POWER;
232 power = 1;
233 if (-1 == ioctl (ctx->t1.spi_fd, io_code, &power)) {
234 perror("unable to soft reset via ioctl\n");
235 return -1;
236 }
237
238 isot1_resync(&ctx->t1);
239 return 0;
240 }
241
242 int gtoSPI_checkAlive(struct se_gto_ctx *ctx);
gtoSPI_checkAlive(struct se_gto_ctx * ctx)243 int gtoSPI_checkAlive(struct se_gto_ctx *ctx)
244 {
245 int ret = 0;
246 unsigned char apdu[5]= {0x80,0xCA,0x9F,0x7F,0x2D};
247 unsigned char resp[258] = {0,};
248
249 /*Check Alive implem*/
250 for(int count = 0; count < 3; count++) {
251 ret = se_gto_apdu_transmit(ctx, apdu, 5, resp, sizeof(resp));
252 if(ret < 0){
253 if (count == 2) return -1;
254 /*Run SPI reset*/
255 se_gto_Spi_Reset(ctx);
256 }
257 }
258
259 return 0;
260 }
261
262 SE_GTO_EXPORT int
se_gto_close(struct se_gto_ctx * ctx)263 se_gto_close(struct se_gto_ctx *ctx)
264 {
265 int status = 0;
266 const char ese_reset_property[] = "persist.vendor.se.reset";
267
268 if (ctx){
269 dbg("se_gto_close check_alive = %d\n", ctx->check_alive);
270 }
271 if (ctx->check_alive == 1) {
272 if (gtoSPI_checkAlive(ctx) != 0) {
273 status = -(0xDEAD);
274 // eSE needs cold reset.
275 if (strncmp(ctx->gtodev, "/dev/st54spi", 12) == 0 ) {
276 property_set(ese_reset_property, "needed");
277 }
278 } else {
279 // Set noneed if SPI worked normally.
280 if (strncmp(ctx->gtodev, "/dev/st54spi", 12) == 0 ) {
281 property_set(ese_reset_property, "noneed");
282 }
283 }
284 } else {
285 // Set noneed if SPI worked normally.
286 if (strncmp(ctx->gtodev, "/dev/st54spi", 12) == 0 ) {
287 property_set(ese_reset_property, "noneed");
288 }
289 }
290
291 (void)isot1_release(&ctx->t1);
292 (void)spi_teardown(ctx);
293 log_teardown(ctx);
294 if(ctx) free(ctx);
295 return status;
296 }
297