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 <stdio.h>
25 #include <stdlib.h>
26 #include <stddef.h>
27 #include <stdarg.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <stdint.h>
33 #include <fcntl.h>
34 #include <log/log.h>
35 
36 #include "se-gto/libse-gto.h"
37 #include "libse-gto-private.h"
38 #include "spi.h"
39 
40 #define SE_GTO_GTODEV "/dev/gto"
41 
42 SE_GTO_EXPORT void *
se_gto_get_userdata(struct se_gto_ctx * ctx)43 se_gto_get_userdata(struct se_gto_ctx *ctx)
44 {
45     if (ctx == NULL)
46         return NULL;
47 
48     return ctx->userdata;
49 }
50 
51 SE_GTO_EXPORT void
se_gto_set_userdata(struct se_gto_ctx * ctx,void * userdata)52 se_gto_set_userdata(struct se_gto_ctx *ctx, void *userdata)
53 {
54     if (ctx == NULL)
55         return;
56 
57     ctx->userdata = userdata;
58 }
59 
60 static int
log_level(const char * priority)61 log_level(const char *priority)
62 {
63     char *endptr;
64     int   prio;
65 
66     prio = strtol(priority, &endptr, 10);
67     if ((endptr[0] == '\0') || isspace(endptr[0]))
68         return prio;
69 
70     if (strncmp(priority, "err", 3) == 0)
71         return 0;
72 
73     if (strncmp(priority, "info", 4) == 0)
74         return 3;
75 
76     if (strncmp(priority, "debug", 5) == 0)
77         return 4;
78 
79     return 0;
80 }
81 
82 static void
log_stderr(struct se_gto_ctx * ctx,const char * s)83 log_stderr(struct se_gto_ctx *ctx, const char *s)
84 {
85     //fputs(s, stderr);
86     ALOGD("%s",s);
87 }
88 
89 SE_GTO_EXPORT int
se_gto_new(struct se_gto_ctx ** c)90 se_gto_new(struct se_gto_ctx **c)
91 {
92     const char        *env;
93     struct se_gto_ctx *ctx;
94 
95     ctx = calloc(1, sizeof(struct se_gto_ctx));
96     if (!ctx) {
97         errno = ENOMEM;
98         return -1;
99     }
100 
101     isot1_init(&ctx->t1);
102 
103     ctx->log_fn = log_stderr;
104 
105     ctx->gtodev = SE_GTO_GTODEV;
106 
107     ctx->log_level = 2;
108     /* environment overwrites config */
109     env = getenv("SE_GTO_LOG");
110     if (env != NULL)
111         se_gto_set_log_level(ctx, log_level(env));
112 
113     dbg("ctx %p created\n", ctx);
114     dbg("log_level=%d\n", ctx->log_level);
115     *c = ctx;
116     return 0;
117 }
118 
119 SE_GTO_EXPORT int
se_gto_get_log_level(struct se_gto_ctx * ctx)120 se_gto_get_log_level(struct se_gto_ctx *ctx)
121 {
122     return ctx->log_level;
123 }
124 
125 SE_GTO_EXPORT void
se_gto_set_log_level(struct se_gto_ctx * ctx,int level)126 se_gto_set_log_level(struct se_gto_ctx *ctx, int level)
127 {
128     if (level < 0)
129         level = 0;
130     else if (level > 4)
131         level = 4;
132     ctx->log_level = level;
133 }
134 
135 SE_GTO_EXPORT se_gto_log_fn *
se_gto_get_log_fn(struct se_gto_ctx * ctx)136 se_gto_get_log_fn(struct se_gto_ctx *ctx)
137 {
138     return ctx->log_fn;
139 }
140 
141 SE_GTO_EXPORT void
se_gto_set_log_fn(struct se_gto_ctx * ctx,se_gto_log_fn * fn)142 se_gto_set_log_fn(struct se_gto_ctx *ctx, se_gto_log_fn *fn)
143 {
144     ctx->log_fn = fn;
145 }
146 
147 SE_GTO_EXPORT const char *
se_gto_get_gtodev(struct se_gto_ctx * ctx)148 se_gto_get_gtodev(struct se_gto_ctx *ctx)
149 {
150     return ctx->gtodev;
151 }
152 
153 SE_GTO_EXPORT void
se_gto_set_gtodev(struct se_gto_ctx * ctx,const char * gtodev)154 se_gto_set_gtodev(struct se_gto_ctx *ctx, const char *gtodev)
155 {
156     ctx->gtodev = strdup(gtodev);
157 }
158 
159 SE_GTO_EXPORT int
se_gto_reset(struct se_gto_ctx * ctx,void * atr,size_t r)160 se_gto_reset(struct se_gto_ctx *ctx, void *atr, size_t r)
161 {
162     int err;
163 
164     err = isot1_reset(&ctx->t1);
165     if (err < 0) {
166         errno = -err;
167         ctx->check_alive = 1;
168     }
169     else {
170         err = isot1_get_atr(&ctx->t1, atr, r);
171         if (err < 0)
172             errno = -err;
173     }
174     return err;
175 }
176 
177 SE_GTO_EXPORT int
se_gto_apdu_transmit(struct se_gto_ctx * ctx,const void * apdu,int n,void * resp,int r)178 se_gto_apdu_transmit(struct se_gto_ctx *ctx, const void *apdu, int n, void *resp, int r)
179 {
180     if (!apdu || (n < 4) || !resp || (r < 2)) {
181         errno = EINVAL;
182         return -1;
183     }
184     r = isot1_transceive(&ctx->t1, apdu, n, resp, r);
185     dbg("isot1_transceive: r=%d\n", r);
186     dbg("isot1_transceive: ctx->t1.recv.end - ctx->t1.recv.start = %d\n", ctx->t1.recv.end - ctx->t1.recv.start);
187     dbg("isot1_transceive: ctx->t1.recv.size = %zu\n", ctx->t1.recv.size);
188     dbg("isot1_transceive: ctx->t1.buf[2] = %02X\n", ctx->t1.buf[2]);
189     if (r < 0) {
190         errno = -r;
191         err("failed to read APDU response, %s\n", strerror(-r));
192     } else if (r < 2) {
193         err("APDU response too short, only %d bytes, needs 2 at least\n", r);
194     }
195     if (r < 2){
196         ctx->check_alive = 1;
197         return -1;
198     } else
199         return r;
200 }
201 
202 SE_GTO_EXPORT int
se_gto_open(struct se_gto_ctx * ctx)203 se_gto_open(struct se_gto_ctx *ctx)
204 {
205     info("eSE GTO: using %s\n", ctx->gtodev);
206 
207     if (spi_setup(ctx) < 0) {
208         err("failed to set up se-gto.\n");
209         return -1;
210     }
211 
212     ctx->check_alive = 0;
213 
214     isot1_bind(&ctx->t1, 0x2, 0x1);
215 
216     dbg("fd: spi=%d\n", ctx->t1.spi_fd);
217     return 0;
218 }
219 
220 int gtoSPI_checkAlive(struct se_gto_ctx *ctx);
gtoSPI_checkAlive(struct se_gto_ctx * ctx)221 int gtoSPI_checkAlive(struct se_gto_ctx *ctx)
222 {
223   int ret = 0;
224   unsigned char apdu[5]= {0x80,0xCA,0x9F,0x7F,0x2D};
225   unsigned char resp[258] = {0,};
226 
227   /*Check Alive implem*/
228   ret = se_gto_apdu_transmit(ctx, apdu, 5, resp, sizeof(resp));
229   if(ret < 0){
230     return -1;
231   }
232 
233   return 0;
234 }
235 
236 SE_GTO_EXPORT int
se_gto_close(struct se_gto_ctx * ctx)237 se_gto_close(struct se_gto_ctx *ctx)
238 {
239     int status = 0;
240 
241     if(ctx) dbg("se_gto_close check_alive = %d\n", ctx->check_alive);
242     if (ctx->check_alive == 1)
243         if (gtoSPI_checkAlive(ctx) != 0) status = 0xDEAD;
244 
245     (void)isot1_release(&ctx->t1);
246     (void)spi_teardown(ctx);
247     log_teardown(ctx);
248     if(ctx) free(ctx);
249     return status;
250 }
251