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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #if 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 
sc_decipher(sc_card_t * card,const u8 * crgram,size_t crgram_len,u8 * out,size_t outlen)35 int sc_decipher(sc_card_t *card,
36 		const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
37 {
38 	int r;
39 
40 	if (card == NULL || crgram == NULL || out == NULL) {
41 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
42 	}
43 	LOG_FUNC_CALLED(card->ctx);
44 	if (card->ops->decipher == NULL)
45 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
46 	r = card->ops->decipher(card, crgram, crgram_len, out, outlen);
47         SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
48 }
49 
sc_compute_signature(sc_card_t * card,const u8 * data,size_t datalen,u8 * out,size_t outlen)50 int sc_compute_signature(sc_card_t *card,
51 			 const u8 * data, size_t datalen,
52 			 u8 * out, size_t outlen)
53 {
54 	int r;
55 
56 	if (card == NULL) {
57 		return SC_ERROR_INVALID_ARGUMENTS;
58 	}
59 	LOG_FUNC_CALLED(card->ctx);
60 	if (card->ops->compute_signature == NULL)
61 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
62 	r = card->ops->compute_signature(card, data, datalen, out, outlen);
63         SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
64 }
65 
sc_unwrap(sc_card_t * card,const u8 * crgram,size_t crgram_len,u8 * out,size_t outlen)66 int sc_unwrap(sc_card_t *card,
67 		const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
68 {
69 	int r;
70 
71 	if (card == NULL || crgram == NULL) {
72 		return SC_ERROR_INVALID_ARGUMENTS;
73 	}
74 	LOG_FUNC_CALLED(card->ctx);
75 	if (card->ops->unwrap == NULL)
76 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
77 	r = card->ops->unwrap(card, crgram, crgram_len);
78 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
79 }
80 
sc_wrap(sc_card_t * card,const u8 * crgram,size_t crgram_len,u8 * out,size_t outlen)81 int sc_wrap(sc_card_t *card,
82 		const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
83 {
84 	int r;
85 
86 	if (card == NULL) {
87 		return SC_ERROR_INVALID_ARGUMENTS;
88 	}
89 	LOG_FUNC_CALLED(card->ctx);
90 	if (card->ops->wrap == NULL)
91 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
92 	r = card->ops->wrap(card, out, outlen);
93 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
94 }
95 
sc_set_security_env(sc_card_t * card,const sc_security_env_t * env,int se_num)96 int sc_set_security_env(sc_card_t *card,
97 			const sc_security_env_t *env,
98 			int se_num)
99 {
100 	int r;
101 
102 	if (card == NULL) {
103 		return SC_ERROR_INVALID_ARGUMENTS;
104 	}
105 	LOG_FUNC_CALLED(card->ctx);
106 	if (card->ops->set_security_env == NULL)
107 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
108 	r = card->ops->set_security_env(card, env, se_num);
109         SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
110 }
111 
sc_restore_security_env(sc_card_t * card,int se_num)112 int sc_restore_security_env(sc_card_t *card, int se_num)
113 {
114 	int r;
115 
116 	if (card == NULL) {
117 		return SC_ERROR_INVALID_ARGUMENTS;
118 	}
119 	LOG_FUNC_CALLED(card->ctx);
120 	if (card->ops->restore_security_env == NULL)
121 		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
122 	r = card->ops->restore_security_env(card, se_num);
123 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
124 }
125 
sc_verify(sc_card_t * card,unsigned int type,int ref,const u8 * pin,size_t pinlen,int * tries_left)126 int sc_verify(sc_card_t *card, unsigned int type, int ref,
127 	      const u8 *pin, size_t pinlen, int *tries_left)
128 {
129 	struct sc_pin_cmd_data data;
130 
131 	memset(&data, 0, sizeof(data));
132 	data.cmd = SC_PIN_CMD_VERIFY;
133 	data.pin_type = type;
134 	data.pin_reference = ref;
135 	data.pin1.data = pin;
136 	data.pin1.len = pinlen;
137 
138 	return sc_pin_cmd(card, &data, tries_left);
139 }
140 
sc_logout(sc_card_t * card)141 int sc_logout(sc_card_t *card)
142 {
143 	if (card->ops->logout == NULL)
144 		return SC_ERROR_NOT_SUPPORTED;
145 	return card->ops->logout(card);
146 }
147 
sc_change_reference_data(sc_card_t * card,unsigned int type,int ref,const u8 * old,size_t oldlen,const u8 * newref,size_t newlen,int * tries_left)148 int sc_change_reference_data(sc_card_t *card, unsigned int type,
149 			     int ref, const u8 *old, size_t oldlen,
150 			     const u8 *newref, size_t newlen,
151 			     int *tries_left)
152 {
153 	struct sc_pin_cmd_data data;
154 
155 	memset(&data, 0, sizeof(data));
156 	data.cmd = SC_PIN_CMD_CHANGE;
157 	data.pin_type = type;
158 	data.pin_reference = ref;
159 	data.pin1.data = old;
160 	data.pin1.len = oldlen;
161 	data.pin2.data = newref;
162 	data.pin2.len = newlen;
163 
164 	return sc_pin_cmd(card, &data, tries_left);
165 }
166 
sc_reset_retry_counter(sc_card_t * card,unsigned int type,int ref,const u8 * puk,size_t puklen,const u8 * newref,size_t newlen)167 int sc_reset_retry_counter(sc_card_t *card, unsigned int type, int ref,
168 			   const u8 *puk, size_t puklen, const u8 *newref,
169 			   size_t newlen)
170 {
171 	struct sc_pin_cmd_data data;
172 
173 	memset(&data, 0, sizeof(data));
174 	data.cmd = SC_PIN_CMD_UNBLOCK;
175 	data.pin_type = type;
176 	data.pin_reference = ref;
177 	data.pin1.data = puk;
178 	data.pin1.len = puklen;
179 	data.pin2.data = newref;
180 	data.pin2.len = newlen;
181 
182 	return sc_pin_cmd(card, &data, NULL);
183 }
184 
185 /*
186  * This is the new style pin command, which takes care of all PIN
187  * operations.
188  * If a PIN was given by the application, the card driver should
189  * send this PIN to the card. If no PIN was given, the driver should
190  * ask the reader to obtain the pin(s) via the pin pad
191  */
sc_pin_cmd(sc_card_t * card,struct sc_pin_cmd_data * data,int * tries_left)192 int sc_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
193 		int *tries_left)
194 {
195 	int r, debug;
196 
197 	if (card == NULL) {
198 		return SC_ERROR_INVALID_ARGUMENTS;
199 	}
200 	LOG_FUNC_CALLED(card->ctx);
201 
202 	debug = card->ctx->debug;
203 	if (data->cmd != SC_PIN_CMD_GET_INFO
204 			&& card->ctx->debug < SC_LOG_DEBUG_PIN) {
205 		card->ctx->debug = 0;
206 	}
207 
208 	if (card->ops->pin_cmd) {
209 		r = card->ops->pin_cmd(card, data, tries_left);
210 	} else if (!(data->flags & SC_PIN_CMD_USE_PINPAD)) {
211 		/* Card driver doesn't support new style pin_cmd, fall
212 		 * back to old interface */
213 
214 		r = SC_ERROR_NOT_SUPPORTED;
215 		switch (data->cmd) {
216 		case SC_PIN_CMD_VERIFY:
217 			if (card->ops->verify != NULL)
218 				r = card->ops->verify(card,
219 					data->pin_type,
220 					data->pin_reference,
221 					data->pin1.data,
222 					(size_t) data->pin1.len,
223 					tries_left);
224 			break;
225 		case SC_PIN_CMD_CHANGE:
226 			if (card->ops->change_reference_data != NULL)
227 				r = card->ops->change_reference_data(card,
228 					data->pin_type,
229 					data->pin_reference,
230 					data->pin1.data,
231 					(size_t) data->pin1.len,
232 					data->pin2.data,
233 					(size_t) data->pin2.len,
234 					tries_left);
235 			break;
236 		case SC_PIN_CMD_UNBLOCK:
237 			if (card->ops->reset_retry_counter != NULL)
238 				r = card->ops->reset_retry_counter(card,
239 					data->pin_type,
240 					data->pin_reference,
241 					data->pin1.data,
242 					(size_t) data->pin1.len,
243 					data->pin2.data,
244 					(size_t) data->pin2.len);
245 			break;
246 		}
247 		if (r == SC_ERROR_NOT_SUPPORTED)
248 			sc_log(card->ctx,  "unsupported PIN operation (%d)",
249 					data->cmd);
250 	} else {
251 		sc_log(card->ctx,  "Use of pin pad not supported by card driver");
252 		r = SC_ERROR_NOT_SUPPORTED;
253 	}
254 	card->ctx->debug = debug;
255 
256 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
257 }
258 
259 /*
260  * This function will copy a PIN, convert and pad it as required
261  *
262  * Note about the SC_PIN_ENCODING_GLP encoding:
263  * PIN buffers are always 16 nibbles (8 bytes) and look like this:
264  *   0x2 + len + pin_in_BCD + paddingnibbles
265  * in which the paddingnibble = 0xF
266  * E.g. if PIN = 12345, then sbuf = {0x25, 0x12, 0x34, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF}
267  * E.g. if PIN = 123456789012, then sbuf = {0x2C, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0xFF}
268  * Reference: Global Platform - Card Specification - version 2.0.1' - April 7, 2000
269  */
sc_build_pin(u8 * buf,size_t buflen,struct sc_pin_cmd_pin * pin,int pad)270 int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad)
271 {
272 	size_t i = 0, j, pin_len = pin->len;
273 
274 	if (pin->max_length && pin_len > pin->max_length)
275 		return SC_ERROR_INVALID_ARGUMENTS;
276 
277 	if (pin->encoding == SC_PIN_ENCODING_GLP) {
278 		while (pin_len > 0 && pin->data[pin_len - 1] == 0xFF)
279 			pin_len--;
280 		if (pin_len > 12)
281 			return SC_ERROR_INVALID_ARGUMENTS;
282 		for (i = 0; i < pin_len; i++) {
283 			if (pin->data[i] < '0' || pin->data[i] > '9')
284 				return SC_ERROR_INVALID_ARGUMENTS;
285 		}
286 		buf[0] = 0x20 | (u8) pin_len;
287 		buf++;
288 		buflen--;
289 	}
290 
291 	/* PIN given by application, encode if required */
292 	if (pin->encoding == SC_PIN_ENCODING_ASCII) {
293 		if (pin_len > buflen)
294 			return SC_ERROR_BUFFER_TOO_SMALL;
295 		memcpy(buf, pin->data, pin_len);
296 		i = pin_len;
297 	} else if (pin->encoding == SC_PIN_ENCODING_BCD || pin->encoding == SC_PIN_ENCODING_GLP) {
298 		if (pin_len > 2 * buflen)
299 			return SC_ERROR_BUFFER_TOO_SMALL;
300 		for (i = j = 0; j < pin_len; j++) {
301 			if (!isdigit(pin->data[j])) {
302 				return SC_ERROR_INVALID_DATA;
303 			}
304 			buf[i] <<= 4;
305 			buf[i] |= pin->data[j] & 0xf;
306 			if (j & 1)
307 				i++;
308 		}
309 		if (j & 1) {
310 			buf[i] <<= 4;
311 			buf[i] |= pin->pad_char & 0xf;
312 			i++;
313 		}
314 	}
315 
316 	/* Pad to maximum PIN length if requested */
317 	if (pad || pin->encoding == SC_PIN_ENCODING_GLP) {
318 		size_t pad_length = pin->pad_length;
319 		u8     pad_char   = pin->encoding == SC_PIN_ENCODING_GLP ? 0xFF : pin->pad_char;
320 
321 		if (pin->encoding == SC_PIN_ENCODING_BCD)
322 			pad_length >>= 1;
323 		if (pin->encoding == SC_PIN_ENCODING_GLP)
324 			pad_length = 8;
325 
326 		if (pad_length > buflen)
327 			return SC_ERROR_BUFFER_TOO_SMALL;
328 
329 		if (pad_length && i < pad_length) {
330 			memset(buf + i, pad_char, pad_length - i);
331 			i = pad_length;
332 		}
333 	}
334 
335 	return i;
336 }
337