-
Notifications
You must be signed in to change notification settings - Fork 0
/
euicc.c
223 lines (182 loc) · 5.93 KB
/
euicc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#include "euicc.private.h"
#include "hexutil.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define ISD_R_AID "\xA0\x00\x00\x05\x59\x10\x10\xFF\xFF\xFF\xFF\x89\x00\x00\x01\x00"
#define APDU_EUICC_HEADER 0x80, 0xE2
#define APDU_CONTINUE_READ_HEADER 0x80, 0xC0, 0x00, 0x00
static int es10x_transmit(struct euicc_ctx *ctx, struct apdu_response *response, struct apdu_request *req, unsigned req_len)
{
req->cla = (req->cla & 0xF0) | (ctx->apdu._internal.logic_channel & 0x0F);
return euicc_apdu_transmit(ctx, response, req, req_len);
}
static int es10x_transmit_iter(struct euicc_ctx *ctx, struct apdu_request *req, unsigned req_len, int (*callback)(struct apdu_response *response, void *userdata), void *userdata)
{
struct apdu_request *request = NULL;
struct apdu_response response;
if (es10x_transmit(ctx, &response, req, req_len) < 0)
{
return -1;
}
do
{
if (response.length > 0)
{
if (callback(&response, userdata) < 0)
{
return -1;
}
}
euicc_apdu_response_free(&response);
if (response.sw1 == SW1_LAST)
{
int ret;
if ((ret = euicc_apdu_le(ctx, &request, APDU_CONTINUE_READ_HEADER, response.sw2)) < 0)
{
return -1;
}
if (es10x_transmit(ctx, &response, request, ret) < 0)
{
return -1;
}
continue;
}
else if ((response.sw1 & 0xF0) == SW1_OK)
{
return 0;
}
return -1;
} while (1);
}
int es10x_command_buildrequest(struct euicc_ctx *ctx, struct apdu_request **request, uint8_t p1, uint8_t p2, const uint8_t *der_req, unsigned req_len)
{
int ret;
ret = euicc_apdu_lc(ctx, request, APDU_EUICC_HEADER, p1, p2, req_len);
if (ret < 0)
return ret;
memcpy((*request)->data, der_req, req_len);
return ret;
}
static int es10x_command_buildrequest_continue(struct euicc_ctx *ctx, uint8_t reqseq, struct apdu_request **request, const uint8_t *der_req, unsigned req_len)
{
return es10x_command_buildrequest(ctx, request, 0x11, reqseq, der_req, req_len);
}
static int es10x_command_buildrequest_last(struct euicc_ctx *ctx, uint8_t reqseq, struct apdu_request **request, const uint8_t *der_req, unsigned req_len)
{
return es10x_command_buildrequest(ctx, request, 0x91, reqseq, der_req, req_len);
}
int es10x_command_iter(struct euicc_ctx *ctx, const uint8_t *der_req, unsigned req_len, int (*callback)(struct apdu_response *response, void *userdata), void *userdata)
{
int ret, reqseq;
struct apdu_request *req;
const uint8_t *req_ptr;
reqseq = 0;
req_ptr = der_req;
while (req_len)
{
uint8_t rlen;
if (req_len > ctx->es10x_mss)
{
rlen = ctx->es10x_mss;
ret = es10x_command_buildrequest_continue(ctx, reqseq, &req, req_ptr, rlen);
}
else
{
rlen = req_len;
ret = es10x_command_buildrequest_last(ctx, reqseq, &req, req_ptr, rlen);
}
req_len -= rlen;
if (ret < 0)
return -1;
ret = es10x_transmit_iter(ctx, req, ret, callback, userdata);
if (ret < 0)
return -1;
req_ptr += rlen;
reqseq++;
}
return 0;
}
struct userdata_es10x_command
{
uint8_t *resp;
unsigned resp_len;
};
static int iter_es10x_command(struct apdu_response *response, void *userdata)
{
struct userdata_es10x_command *ud = (struct userdata_es10x_command *)userdata;
uint8_t *new_response_data;
new_response_data = realloc(ud->resp, ud->resp_len + response->length);
if (!new_response_data)
{
return -1;
}
ud->resp = new_response_data;
memcpy(ud->resp + ud->resp_len, response->data, response->length);
ud->resp_len += response->length;
return 0;
}
int es10x_command(struct euicc_ctx *ctx, uint8_t **resp, unsigned *resp_len, const uint8_t *der_req, unsigned req_len)
{
int ret = 0;
struct userdata_es10x_command ud;
*resp = NULL;
*resp_len = 0;
memset(&ud, 0, sizeof(ud));
ret = es10x_command_iter(ctx, der_req, req_len, iter_es10x_command, &ud);
if (ret < 0)
{
free(ud.resp);
return -1;
}
*resp = ud.resp;
*resp_len = ud.resp_len;
return 0;
}
int euicc_init(struct euicc_ctx *ctx)
{
int ret;
if (ctx->aid == NULL)
{
ctx->aid = (const uint8_t *)ISD_R_AID;
ctx->aid_len = sizeof(ISD_R_AID) - 1;
}
ctx->es10x_mss = 120;
ret = ctx->apdu.interface->connect(ctx);
if (ret < 0)
{
return -1;
}
ret = ctx->apdu.interface->logic_channel_open(ctx, ctx->aid, ctx->aid_len);
if (ret < 0)
{
ctx->apdu.interface->disconnect(ctx);
return -1;
}
ctx->apdu._internal.logic_channel = ret;
return 0;
}
void euicc_fini(struct euicc_ctx *ctx)
{
ctx->apdu.interface->logic_channel_close(ctx, ctx->apdu._internal.logic_channel);
ctx->apdu.interface->disconnect(ctx);
ctx->apdu._internal.logic_channel = 0;
}
void euicc_http_cleanup(struct euicc_ctx *ctx)
{
free(ctx->http._internal.transaction_id_http);
free(ctx->http._internal.transaction_id_bin);
free(ctx->http._internal.b64_euicc_challenge);
free(ctx->http._internal.b64_euicc_info_1);
es10b_authenticate_server_param_free(ctx->http._internal.authenticate_server_param);
free(ctx->http._internal.authenticate_server_param);
free(ctx->http._internal.b64_authenticate_server_response);
es10b_prepare_download_param_free(ctx->http._internal.prepare_download_param);
free(ctx->http._internal.prepare_download_param);
free(ctx->http._internal.b64_prepare_download_response);
free(ctx->http._internal.b64_bound_profile_package);
free(ctx->http._internal.b64_cancel_session_response);
memset(&ctx->http._internal, 0, sizeof(ctx->http._internal));
}