/src/opensc/src/libopensc/sec.c
Line | Count | Source |
1 | | /* |
2 | | * sec.c: Cryptography and security (ISO7816-8) functions |
3 | | * |
4 | | * Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrjola@iki.fi> |
5 | | * |
6 | | * This library is free software; you can redistribute it and/or |
7 | | * modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | */ |
20 | | |
21 | | #ifdef HAVE_CONFIG_H |
22 | | #include "config.h" |
23 | | #endif |
24 | | |
25 | | #include <stdio.h> |
26 | | #include <string.h> |
27 | | #include <assert.h> |
28 | | #include <ctype.h> |
29 | | #ifdef HAVE_UNISTD_H |
30 | | #include <unistd.h> |
31 | | #endif |
32 | | |
33 | | #include "internal.h" |
34 | | |
35 | | int sc_decipher(sc_card_t *card, |
36 | | const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) |
37 | 0 | { |
38 | 0 | int r; |
39 | |
|
40 | 0 | if (card == NULL) { |
41 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
42 | 0 | } |
43 | 0 | if (crgram == NULL || out == NULL) { |
44 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); |
45 | 0 | } |
46 | 0 | LOG_FUNC_CALLED(card->ctx); |
47 | 0 | if (card->ops->decipher == NULL) |
48 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
49 | 0 | r = card->ops->decipher(card, crgram, crgram_len, out, outlen); |
50 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
51 | 0 | } |
52 | | |
53 | | int sc_compute_signature(sc_card_t *card, |
54 | | const u8 * data, size_t datalen, |
55 | | u8 * out, size_t outlen) |
56 | 0 | { |
57 | 0 | int r; |
58 | |
|
59 | 0 | if (card == NULL) { |
60 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
61 | 0 | } |
62 | 0 | LOG_FUNC_CALLED(card->ctx); |
63 | 0 | if (card->ops->compute_signature == NULL) |
64 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
65 | 0 | r = card->ops->compute_signature(card, data, datalen, out, outlen); |
66 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
67 | 0 | } |
68 | | |
69 | | int sc_unwrap(sc_card_t *card, |
70 | | const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) |
71 | 0 | { |
72 | 0 | int r; |
73 | |
|
74 | 0 | if (card == NULL || crgram == NULL) { |
75 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
76 | 0 | } |
77 | 0 | LOG_FUNC_CALLED(card->ctx); |
78 | 0 | if (card->ops->unwrap == NULL) |
79 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
80 | 0 | r = card->ops->unwrap(card, crgram, crgram_len); |
81 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
82 | 0 | } |
83 | | |
84 | | int sc_wrap(sc_card_t *card, |
85 | | const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen) |
86 | 0 | { |
87 | 0 | int r; |
88 | |
|
89 | 0 | if (card == NULL) { |
90 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
91 | 0 | } |
92 | 0 | LOG_FUNC_CALLED(card->ctx); |
93 | 0 | if (card->ops->wrap == NULL) |
94 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
95 | 0 | r = card->ops->wrap(card, out, outlen); |
96 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
97 | 0 | } |
98 | | |
99 | | int sc_set_security_env(sc_card_t *card, |
100 | | const sc_security_env_t *env, |
101 | | int se_num) |
102 | 0 | { |
103 | 0 | int r; |
104 | |
|
105 | 0 | if (card == NULL) { |
106 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
107 | 0 | } |
108 | 0 | LOG_FUNC_CALLED(card->ctx); |
109 | 0 | if (card->ops->set_security_env == NULL) |
110 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
111 | 0 | r = card->ops->set_security_env(card, env, se_num); |
112 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
113 | 0 | } |
114 | | |
115 | | int sc_restore_security_env(sc_card_t *card, int se_num) |
116 | 0 | { |
117 | 0 | int r; |
118 | |
|
119 | 0 | if (card == NULL) { |
120 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
121 | 0 | } |
122 | 0 | LOG_FUNC_CALLED(card->ctx); |
123 | 0 | if (card->ops->restore_security_env == NULL) |
124 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
125 | 0 | r = card->ops->restore_security_env(card, se_num); |
126 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
127 | 0 | } |
128 | | |
129 | | int sc_verify(sc_card_t *card, unsigned int type, int ref, |
130 | | const u8 *pin, size_t pinlen, int *tries_left) |
131 | 722 | { |
132 | 722 | struct sc_pin_cmd_data data; |
133 | | |
134 | 722 | memset(&data, 0, sizeof(data)); |
135 | 722 | data.cmd = SC_PIN_CMD_VERIFY; |
136 | 722 | data.pin_type = type; |
137 | 722 | data.pin_reference = ref; |
138 | 722 | data.pin1.data = pin; |
139 | 722 | data.pin1.len = pinlen; |
140 | | |
141 | 722 | int r = sc_pin_cmd(card, &data); |
142 | 722 | if (tries_left) |
143 | 722 | *tries_left = data.pin1.tries_left; |
144 | | |
145 | 722 | return r; |
146 | 722 | } |
147 | | |
148 | | int sc_logout(sc_card_t *card) |
149 | 0 | { |
150 | 0 | if (card->ops->logout == NULL) |
151 | 0 | return SC_ERROR_NOT_SUPPORTED; |
152 | 0 | return card->ops->logout(card); |
153 | 0 | } |
154 | | |
155 | | int sc_change_reference_data(sc_card_t *card, unsigned int type, |
156 | | int ref, const u8 *old, size_t oldlen, |
157 | | const u8 *newref, size_t newlen, |
158 | | int *tries_left) |
159 | 0 | { |
160 | 0 | struct sc_pin_cmd_data data; |
161 | |
|
162 | 0 | memset(&data, 0, sizeof(data)); |
163 | 0 | data.cmd = SC_PIN_CMD_CHANGE; |
164 | 0 | data.pin_type = type; |
165 | 0 | data.pin_reference = ref; |
166 | 0 | data.pin1.data = old; |
167 | 0 | data.pin1.len = oldlen; |
168 | 0 | data.pin2.data = newref; |
169 | 0 | data.pin2.len = newlen; |
170 | |
|
171 | 0 | int r = sc_pin_cmd(card, &data); |
172 | 0 | if (tries_left) |
173 | 0 | *tries_left = data.pin1.tries_left; |
174 | |
|
175 | 0 | return r; |
176 | 0 | } |
177 | | |
178 | | int sc_reset_retry_counter(sc_card_t *card, unsigned int type, int ref, |
179 | | const u8 *puk, size_t puklen, const u8 *newref, |
180 | | size_t newlen) |
181 | 0 | { |
182 | 0 | struct sc_pin_cmd_data data; |
183 | |
|
184 | 0 | memset(&data, 0, sizeof(data)); |
185 | 0 | data.cmd = SC_PIN_CMD_UNBLOCK; |
186 | 0 | data.pin_type = type; |
187 | 0 | data.pin_reference = ref; |
188 | 0 | data.pin1.data = puk; |
189 | 0 | data.pin1.len = puklen; |
190 | 0 | data.pin2.data = newref; |
191 | 0 | data.pin2.len = newlen; |
192 | |
|
193 | 0 | return sc_pin_cmd(card, &data); |
194 | 0 | } |
195 | | |
196 | | /* |
197 | | * This is the new style pin command, which takes care of all PIN |
198 | | * operations. |
199 | | * If a PIN was given by the application, the card driver should |
200 | | * send this PIN to the card. If no PIN was given, the driver should |
201 | | * ask the reader to obtain the pin(s) via the pin pad |
202 | | */ |
203 | | int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data) |
204 | 1.34k | { |
205 | 1.34k | int r, debug; |
206 | | |
207 | 1.34k | if (card == NULL) { |
208 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
209 | 0 | } |
210 | 1.34k | LOG_FUNC_CALLED(card->ctx); |
211 | | |
212 | 1.34k | debug = card->ctx->debug; |
213 | 1.34k | if (data->cmd != SC_PIN_CMD_GET_INFO |
214 | 722 | && card->ctx->debug < SC_LOG_DEBUG_PIN) { |
215 | 722 | card->ctx->debug = 0; |
216 | 722 | } |
217 | | |
218 | 1.34k | if (card->ops->pin_cmd) { |
219 | 1.34k | r = card->ops->pin_cmd(card, data); |
220 | 1.34k | } else if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) { |
221 | | /* Card driver doesn't support new style pin_cmd, fall |
222 | | * back to old interface */ |
223 | |
|
224 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
225 | 0 | switch (data->cmd) { |
226 | 0 | case SC_PIN_CMD_VERIFY: |
227 | 0 | if (card->ops->verify != NULL) |
228 | 0 | r = card->ops->verify(card, |
229 | 0 | data->pin_type, |
230 | 0 | data->pin_reference, |
231 | 0 | data->pin1.data, |
232 | 0 | (size_t) data->pin1.len, |
233 | 0 | &data->pin1.tries_left); |
234 | 0 | break; |
235 | 0 | case SC_PIN_CMD_CHANGE: |
236 | 0 | if (card->ops->change_reference_data != NULL) |
237 | 0 | r = card->ops->change_reference_data(card, |
238 | 0 | data->pin_type, |
239 | 0 | data->pin_reference, |
240 | 0 | data->pin1.data, |
241 | 0 | (size_t) data->pin1.len, |
242 | 0 | data->pin2.data, |
243 | 0 | (size_t) data->pin2.len, |
244 | 0 | &data->pin1.tries_left); |
245 | 0 | break; |
246 | 0 | case SC_PIN_CMD_UNBLOCK: |
247 | 0 | if (card->ops->reset_retry_counter != NULL) |
248 | 0 | r = card->ops->reset_retry_counter(card, |
249 | 0 | data->pin_type, |
250 | 0 | data->pin_reference, |
251 | 0 | data->pin1.data, |
252 | 0 | (size_t) data->pin1.len, |
253 | 0 | data->pin2.data, |
254 | 0 | (size_t) data->pin2.len); |
255 | 0 | break; |
256 | 0 | } |
257 | 0 | if (r == SC_ERROR_NOT_SUPPORTED) |
258 | 0 | sc_log(card->ctx, "unsupported PIN operation (%d)", |
259 | 0 | data->cmd); |
260 | 0 | } else { |
261 | 0 | sc_log(card->ctx, "Use of pin pad not supported by card driver"); |
262 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
263 | 0 | } |
264 | 1.34k | card->ctx->debug = debug; |
265 | | |
266 | 1.34k | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
267 | 1.34k | } |
268 | | |
269 | | /* |
270 | | * This function will copy a PIN, convert and pad it as required |
271 | | * |
272 | | * Note about the SC_PIN_ENCODING_GLP encoding: |
273 | | * PIN buffers are always 16 nibbles (8 bytes) and look like this: |
274 | | * 0x2 + len + pin_in_BCD + paddingnibbles |
275 | | * in which the paddingnibble = 0xF |
276 | | * E.g. if PIN = 12345, then sbuf = {0x25, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF} |
277 | | * E.g. if PIN = 123456789012, then sbuf = {0x2C, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0xFF} |
278 | | * Reference: Global Platform - Card Specification - version 2.0.1' - April 7, 2000 |
279 | | */ |
280 | | int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad) |
281 | 0 | { |
282 | 0 | size_t i = 0, j, pin_len = pin->len; |
283 | |
|
284 | 0 | if (pin->max_length && pin_len > pin->max_length) |
285 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
286 | | |
287 | 0 | if (pin->encoding == SC_PIN_ENCODING_GLP) { |
288 | 0 | while (pin_len > 0 && pin->data[pin_len - 1] == 0xFF) |
289 | 0 | pin_len--; |
290 | 0 | if (pin_len > 12) |
291 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
292 | 0 | for (i = 0; i < pin_len; i++) { |
293 | 0 | if (pin->data[i] < '0' || pin->data[i] > '9') |
294 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
295 | 0 | } |
296 | 0 | buf[0] = 0x20 | (u8) pin_len; |
297 | 0 | buf++; |
298 | 0 | buflen--; |
299 | 0 | } |
300 | | |
301 | | /* PIN given by application, encode if required */ |
302 | 0 | if (pin->encoding == SC_PIN_ENCODING_ASCII) { |
303 | 0 | if (pin_len > buflen) |
304 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
305 | 0 | memcpy(buf, pin->data, pin_len); |
306 | 0 | i = pin_len; |
307 | 0 | } else if (pin->encoding == SC_PIN_ENCODING_BCD || pin->encoding == SC_PIN_ENCODING_GLP) { |
308 | 0 | if (pin_len > 2 * buflen) |
309 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
310 | 0 | for (i = j = 0; j < pin_len; j++) { |
311 | 0 | if (!isdigit(pin->data[j])) { |
312 | 0 | return SC_ERROR_INVALID_DATA; |
313 | 0 | } |
314 | 0 | buf[i] <<= 4; |
315 | 0 | buf[i] |= pin->data[j] & 0xf; |
316 | 0 | if (j & 1) |
317 | 0 | i++; |
318 | 0 | } |
319 | 0 | if (j & 1) { |
320 | 0 | buf[i] <<= 4; |
321 | 0 | buf[i] |= pin->pad_char & 0xf; |
322 | 0 | i++; |
323 | 0 | } |
324 | 0 | } |
325 | | |
326 | | /* Pad to maximum PIN length if requested */ |
327 | 0 | if (pad || pin->encoding == SC_PIN_ENCODING_GLP) { |
328 | 0 | size_t pad_length = pin->pad_length; |
329 | 0 | u8 pad_char = pin->encoding == SC_PIN_ENCODING_GLP ? 0xFF : pin->pad_char; |
330 | |
|
331 | 0 | if (pin->encoding == SC_PIN_ENCODING_BCD) |
332 | 0 | pad_length >>= 1; |
333 | 0 | if (pin->encoding == SC_PIN_ENCODING_GLP) |
334 | 0 | pad_length = 8; |
335 | |
|
336 | 0 | if (pad_length > buflen) |
337 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
338 | | |
339 | 0 | if (pad_length && i < pad_length) { |
340 | 0 | memset(buf + i, pad_char, pad_length - i); |
341 | 0 | i = pad_length; |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 0 | return (int)i; |
346 | 0 | } |
347 | | |
348 | | int |
349 | | sc_encrypt_sym(struct sc_card *card, const u8 *plaintext, size_t plaintext_len, |
350 | | u8 *out, size_t *outlen) |
351 | 0 | { |
352 | 0 | int r; |
353 | |
|
354 | 0 | if (card == NULL) |
355 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
356 | | |
357 | 0 | LOG_FUNC_CALLED(card->ctx); |
358 | 0 | if (card->ops->encrypt_sym == NULL) |
359 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
360 | 0 | r = card->ops->encrypt_sym(card, plaintext, plaintext_len, out, outlen); |
361 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
362 | 0 | } |
363 | | |
364 | | int |
365 | | sc_decrypt_sym(struct sc_card *card, const u8 *data, size_t data_len, |
366 | | u8 *out, size_t *outlen) |
367 | 0 | { |
368 | 0 | int r; |
369 | |
|
370 | 0 | if (card == NULL) |
371 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
372 | | |
373 | 0 | LOG_FUNC_CALLED(card->ctx); |
374 | 0 | if (card->ops->decrypt_sym == NULL) |
375 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
376 | 0 | r = card->ops->decrypt_sym(card, data, data_len, out, outlen); |
377 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
378 | 0 | } |