/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 | 568 | { |
132 | 568 | struct sc_pin_cmd_data data; |
133 | | |
134 | 568 | memset(&data, 0, sizeof(data)); |
135 | 568 | data.cmd = SC_PIN_CMD_VERIFY; |
136 | 568 | data.pin_type = type; |
137 | 568 | data.pin_reference = ref; |
138 | 568 | data.pin1.data = pin; |
139 | 568 | data.pin1.len = pinlen; |
140 | | |
141 | 568 | return sc_pin_cmd(card, &data, tries_left); |
142 | 568 | } |
143 | | |
144 | | int sc_logout(sc_card_t *card) |
145 | 0 | { |
146 | 0 | if (card->ops->logout == NULL) |
147 | 0 | return SC_ERROR_NOT_SUPPORTED; |
148 | 0 | return card->ops->logout(card); |
149 | 0 | } |
150 | | |
151 | | int sc_change_reference_data(sc_card_t *card, unsigned int type, |
152 | | int ref, const u8 *old, size_t oldlen, |
153 | | const u8 *newref, size_t newlen, |
154 | | int *tries_left) |
155 | 250 | { |
156 | 250 | struct sc_pin_cmd_data data; |
157 | | |
158 | 250 | memset(&data, 0, sizeof(data)); |
159 | 250 | data.cmd = SC_PIN_CMD_CHANGE; |
160 | 250 | data.pin_type = type; |
161 | 250 | data.pin_reference = ref; |
162 | 250 | data.pin1.data = old; |
163 | 250 | data.pin1.len = oldlen; |
164 | 250 | data.pin2.data = newref; |
165 | 250 | data.pin2.len = newlen; |
166 | | |
167 | 250 | return sc_pin_cmd(card, &data, tries_left); |
168 | 250 | } |
169 | | |
170 | | int sc_reset_retry_counter(sc_card_t *card, unsigned int type, int ref, |
171 | | const u8 *puk, size_t puklen, const u8 *newref, |
172 | | size_t newlen) |
173 | 0 | { |
174 | 0 | struct sc_pin_cmd_data data; |
175 | |
|
176 | 0 | memset(&data, 0, sizeof(data)); |
177 | 0 | data.cmd = SC_PIN_CMD_UNBLOCK; |
178 | 0 | data.pin_type = type; |
179 | 0 | data.pin_reference = ref; |
180 | 0 | data.pin1.data = puk; |
181 | 0 | data.pin1.len = puklen; |
182 | 0 | data.pin2.data = newref; |
183 | 0 | data.pin2.len = newlen; |
184 | |
|
185 | 0 | return sc_pin_cmd(card, &data, NULL); |
186 | 0 | } |
187 | | |
188 | | /* |
189 | | * This is the new style pin command, which takes care of all PIN |
190 | | * operations. |
191 | | * If a PIN was given by the application, the card driver should |
192 | | * send this PIN to the card. If no PIN was given, the driver should |
193 | | * ask the reader to obtain the pin(s) via the pin pad |
194 | | */ |
195 | | int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, |
196 | | int *tries_left) |
197 | 3.62k | { |
198 | 3.62k | int r, debug; |
199 | | |
200 | 3.62k | if (card == NULL) { |
201 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
202 | 0 | } |
203 | 3.62k | LOG_FUNC_CALLED(card->ctx); |
204 | | |
205 | 3.62k | debug = card->ctx->debug; |
206 | 3.62k | if (data->cmd != SC_PIN_CMD_GET_INFO |
207 | 883 | && card->ctx->debug < SC_LOG_DEBUG_PIN) { |
208 | 883 | card->ctx->debug = 0; |
209 | 883 | } |
210 | | |
211 | 3.62k | if (card->ops->pin_cmd) { |
212 | 3.62k | r = card->ops->pin_cmd(card, data, tries_left); |
213 | 3.62k | } else if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) { |
214 | | /* Card driver doesn't support new style pin_cmd, fall |
215 | | * back to old interface */ |
216 | |
|
217 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
218 | 0 | switch (data->cmd) { |
219 | 0 | case SC_PIN_CMD_VERIFY: |
220 | 0 | if (card->ops->verify != NULL) |
221 | 0 | r = card->ops->verify(card, |
222 | 0 | data->pin_type, |
223 | 0 | data->pin_reference, |
224 | 0 | data->pin1.data, |
225 | 0 | (size_t) data->pin1.len, |
226 | 0 | tries_left); |
227 | 0 | break; |
228 | 0 | case SC_PIN_CMD_CHANGE: |
229 | 0 | if (card->ops->change_reference_data != NULL) |
230 | 0 | r = card->ops->change_reference_data(card, |
231 | 0 | data->pin_type, |
232 | 0 | data->pin_reference, |
233 | 0 | data->pin1.data, |
234 | 0 | (size_t) data->pin1.len, |
235 | 0 | data->pin2.data, |
236 | 0 | (size_t) data->pin2.len, |
237 | 0 | tries_left); |
238 | 0 | break; |
239 | 0 | case SC_PIN_CMD_UNBLOCK: |
240 | 0 | if (card->ops->reset_retry_counter != NULL) |
241 | 0 | r = card->ops->reset_retry_counter(card, |
242 | 0 | data->pin_type, |
243 | 0 | data->pin_reference, |
244 | 0 | data->pin1.data, |
245 | 0 | (size_t) data->pin1.len, |
246 | 0 | data->pin2.data, |
247 | 0 | (size_t) data->pin2.len); |
248 | 0 | break; |
249 | 0 | } |
250 | 0 | if (r == SC_ERROR_NOT_SUPPORTED) |
251 | 0 | sc_log(card->ctx, "unsupported PIN operation (%d)", |
252 | 0 | data->cmd); |
253 | 0 | } else { |
254 | 0 | sc_log(card->ctx, "Use of pin pad not supported by card driver"); |
255 | 0 | r = SC_ERROR_NOT_SUPPORTED; |
256 | 0 | } |
257 | 3.62k | card->ctx->debug = debug; |
258 | | |
259 | 3.62k | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
260 | 3.62k | } |
261 | | |
262 | | /* |
263 | | * This function will copy a PIN, convert and pad it as required |
264 | | * |
265 | | * Note about the SC_PIN_ENCODING_GLP encoding: |
266 | | * PIN buffers are always 16 nibbles (8 bytes) and look like this: |
267 | | * 0x2 + len + pin_in_BCD + paddingnibbles |
268 | | * in which the paddingnibble = 0xF |
269 | | * E.g. if PIN = 12345, then sbuf = {0x25, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF} |
270 | | * E.g. if PIN = 123456789012, then sbuf = {0x2C, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0xFF} |
271 | | * Reference: Global Platform - Card Specification - version 2.0.1' - April 7, 2000 |
272 | | */ |
273 | | int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad) |
274 | 282 | { |
275 | 282 | size_t i = 0, j, pin_len = pin->len; |
276 | | |
277 | 282 | if (pin->max_length && pin_len > pin->max_length) |
278 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
279 | | |
280 | 282 | if (pin->encoding == SC_PIN_ENCODING_GLP) { |
281 | 0 | while (pin_len > 0 && pin->data[pin_len - 1] == 0xFF) |
282 | 0 | pin_len--; |
283 | 0 | if (pin_len > 12) |
284 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
285 | 0 | for (i = 0; i < pin_len; i++) { |
286 | 0 | if (pin->data[i] < '0' || pin->data[i] > '9') |
287 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
288 | 0 | } |
289 | 0 | buf[0] = 0x20 | (u8) pin_len; |
290 | 0 | buf++; |
291 | 0 | buflen--; |
292 | 0 | } |
293 | | |
294 | | /* PIN given by application, encode if required */ |
295 | 282 | if (pin->encoding == SC_PIN_ENCODING_ASCII) { |
296 | 282 | if (pin_len > buflen) |
297 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
298 | 282 | memcpy(buf, pin->data, pin_len); |
299 | 282 | i = pin_len; |
300 | 282 | } else if (pin->encoding == SC_PIN_ENCODING_BCD || pin->encoding == SC_PIN_ENCODING_GLP) { |
301 | 0 | if (pin_len > 2 * buflen) |
302 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
303 | 0 | for (i = j = 0; j < pin_len; j++) { |
304 | 0 | if (!isdigit(pin->data[j])) { |
305 | 0 | return SC_ERROR_INVALID_DATA; |
306 | 0 | } |
307 | 0 | buf[i] <<= 4; |
308 | 0 | buf[i] |= pin->data[j] & 0xf; |
309 | 0 | if (j & 1) |
310 | 0 | i++; |
311 | 0 | } |
312 | 0 | if (j & 1) { |
313 | 0 | buf[i] <<= 4; |
314 | 0 | buf[i] |= pin->pad_char & 0xf; |
315 | 0 | i++; |
316 | 0 | } |
317 | 0 | } |
318 | | |
319 | | /* Pad to maximum PIN length if requested */ |
320 | 282 | if (pad || pin->encoding == SC_PIN_ENCODING_GLP) { |
321 | 32 | size_t pad_length = pin->pad_length; |
322 | 32 | u8 pad_char = pin->encoding == SC_PIN_ENCODING_GLP ? 0xFF : pin->pad_char; |
323 | | |
324 | 32 | if (pin->encoding == SC_PIN_ENCODING_BCD) |
325 | 0 | pad_length >>= 1; |
326 | 32 | if (pin->encoding == SC_PIN_ENCODING_GLP) |
327 | 0 | pad_length = 8; |
328 | | |
329 | 32 | if (pad_length > buflen) |
330 | 0 | return SC_ERROR_BUFFER_TOO_SMALL; |
331 | | |
332 | 32 | if (pad_length && i < pad_length) { |
333 | 20 | memset(buf + i, pad_char, pad_length - i); |
334 | 20 | i = pad_length; |
335 | 20 | } |
336 | 32 | } |
337 | | |
338 | 282 | return (int)i; |
339 | 282 | } |
340 | | |
341 | | int |
342 | | sc_encrypt_sym(struct sc_card *card, const u8 *plaintext, size_t plaintext_len, |
343 | | u8 *out, size_t *outlen) |
344 | 0 | { |
345 | 0 | int r; |
346 | |
|
347 | 0 | if (card == NULL) |
348 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
349 | | |
350 | 0 | LOG_FUNC_CALLED(card->ctx); |
351 | 0 | if (card->ops->encrypt_sym == NULL) |
352 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
353 | 0 | r = card->ops->encrypt_sym(card, plaintext, plaintext_len, out, outlen); |
354 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
355 | 0 | } |
356 | | |
357 | | int |
358 | | sc_decrypt_sym(struct sc_card *card, const u8 *data, size_t data_len, |
359 | | u8 *out, size_t *outlen) |
360 | 0 | { |
361 | 0 | int r; |
362 | |
|
363 | 0 | if (card == NULL) |
364 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
365 | | |
366 | 0 | LOG_FUNC_CALLED(card->ctx); |
367 | 0 | if (card->ops->decrypt_sym == NULL) |
368 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED); |
369 | 0 | r = card->ops->decrypt_sym(card, data, data_len, out, outlen); |
370 | 0 | SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r); |
371 | 0 | } |