1/*
2    pps.c
3    Protocol Parameters Selection
4
5    This file is part of the Unix driver for Towitoko smartcard readers
6    Copyright (C) 2000 2001 Carlos Prados <cprados@yahoo.com>
7
8    This library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2 of the License, or (at your option) any later version.
12
13    This library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18	You should have received a copy of the GNU Lesser General Public License
19	along with this library; if not, write to the Free Software Foundation,
20	Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21*/
22
23#include "pps.h"
24#include "atr.h"
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <ifdhandler.h>
29
30#include "commands.h"
31#include "defs.h"
32#include "debug.h"
33
34/*
35 * Not exported funtions declaration
36 */
37
38static bool PPS_Match (BYTE * request, unsigned len_request, BYTE * reply, unsigned len_reply);
39
40static unsigned PPS_GetLength (BYTE * block);
41
42static BYTE PPS_GetPCK (BYTE * block, unsigned length);
43
44int
45PPS_Exchange (int lun, BYTE * params, unsigned *length, unsigned char *pps1)
46{
47  BYTE confirm[PPS_MAX_LENGTH];
48  unsigned len_request, len_confirm;
49  int ret;
50
51  len_request = PPS_GetLength (params);
52  params[len_request - 1] = PPS_GetPCK(params, len_request - 1);
53
54  DEBUG_XXD ("PPS: Sending request: ", params, len_request);
55
56  /* Send PPS request */
57  if (CCID_Transmit (lun, len_request, params, isCharLevel(lun) ? 4 : 0, 0)
58	!= IFD_SUCCESS)
59    return PPS_ICC_ERROR;
60
61  /* Get PPS confirm */
62  len_confirm = sizeof(confirm);
63  if (CCID_Receive (lun, &len_confirm, confirm, NULL) != IFD_SUCCESS)
64    return PPS_ICC_ERROR;
65
66  DEBUG_XXD ("PPS: Receiving confirm: ", confirm, len_confirm);
67
68  if (!PPS_Match (params, len_request, confirm, len_confirm))
69    ret = PPS_HANDSAKE_ERROR;
70  else
71    ret = PPS_OK;
72
73  *pps1 = 0x11;	/* default TA1 */
74
75  /* if PPS1 is echoed */
76  if (PPS_HAS_PPS1 (params) && PPS_HAS_PPS1 (confirm))
77      *pps1 = confirm[2];
78
79  /* Copy PPS handsake */
80  memcpy (params, confirm, len_confirm);
81  (*length) = len_confirm;
82
83  return ret;
84}
85
86static bool
87PPS_Match (BYTE * request, unsigned len_request, BYTE * confirm, unsigned len_confirm)
88{
89  /* See if the reply differs from request */
90  if ((len_request == len_confirm) &&	/* same length */
91      memcmp (request, confirm, len_request))	/* different contents */
92	return FALSE;
93
94  if (len_request < len_confirm)	/* confirm longer than request */
95    return FALSE;
96
97  /* See if the card specifies other than default FI and D */
98  if ((PPS_HAS_PPS1 (confirm)) && (confirm[2] != request[2]))
99    return FALSE;
100
101  return TRUE;
102}
103
104static unsigned
105PPS_GetLength (BYTE * block)
106{
107  unsigned length = 3;
108
109  if (PPS_HAS_PPS1 (block))
110    length++;
111
112  if (PPS_HAS_PPS2 (block))
113    length++;
114
115  if (PPS_HAS_PPS3 (block))
116    length++;
117
118  return length;
119}
120
121static BYTE
122PPS_GetPCK (BYTE * block, unsigned length)
123{
124  BYTE pck;
125  unsigned i;
126
127  pck = block[0];
128  for (i = 1; i < length; i++)
129    pck ^= block[i];
130
131  return pck;
132}
133
134