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 = %d\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