blob: 7d424b853e1adfe5064615667d5a6b14cc87e6bb [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file reader_pcsc.c
2 * PC/SC Card reader backend for libosmosim. */
Harald Weltead418632012-09-10 10:49:59 +02003/*
4 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
Harald Weltee08da972017-11-13 01:00:26 +09008 * SPDX-License-Identifier: GPL-2.0+
9 *
Harald Weltead418632012-09-10 10:49:59 +020010 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
Harald Welted54c2ee2012-01-17 18:25:50 +010027#include <string.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <errno.h>
31
32#include <osmocom/core/talloc.h>
33#include <osmocom/sim/sim.h>
34
Holger Hans Peter Freytherb0310dd2014-10-27 12:00:37 +010035#include <wintypes.h>
36#include <winscard.h>
Harald Welted54c2ee2012-01-17 18:25:50 +010037
38#include "sim_int.h"
39
40#define PCSC_ERROR(rv, text) \
41if (rv != SCARD_S_SUCCESS) { \
42 fprintf(stderr, text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
43 goto end; \
44} else { \
45 printf(text ": OK\n\n"); \
46}
47
48
49
50struct pcsc_reader_state {
51 SCARDCONTEXT hContext;
52 SCARDHANDLE hCard;
53 DWORD dwActiveProtocol;
54 const SCARD_IO_REQUEST *pioSendPci;
55 SCARD_IO_REQUEST pioRecvPci;
56 char *name;
57};
58
Harald Welte22117a72021-04-25 20:50:13 +020059static int pcsc_get_atr(struct osim_card_hdl *card)
60{
61 struct osim_reader_hdl *rh = card->reader;
62 struct pcsc_reader_state *st = rh->priv;
63 char pbReader[MAX_READERNAME];
64 DWORD dwReaderLen = sizeof(pbReader);
65 DWORD dwAtrLen = sizeof(card->atr);
66 DWORD dwState, dwProt;
67 long rc;
68
69 rc = SCardStatus(st->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
70 card->atr, &dwAtrLen);
71 PCSC_ERROR(rc, "SCardStatus");
72 card->atr_len = dwAtrLen;
73
74 return 0;
75
76end:
77 return -EIO;
78}
79
Harald Welted54c2ee2012-01-17 18:25:50 +010080static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *ctx)
81{
82 struct osim_reader_hdl *rh;
83 struct pcsc_reader_state *st;
Harald Welte0d246442014-05-04 13:58:54 +020084 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +010085 LPSTR mszReaders = NULL;
86 DWORD dwReaders;
87 unsigned int num_readers;
88 char *ptr;
89
90 /* FIXME: implement matching on id or num */
91
92 rh = talloc_zero(ctx, struct osim_reader_hdl);
93 st = rh->priv = talloc_zero(rh, struct pcsc_reader_state);
94
95 rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
96 &st->hContext);
Harald Welted83d2962013-03-04 17:52:33 +000097 PCSC_ERROR(rc, "SCardEstablishContext");
Harald Welted54c2ee2012-01-17 18:25:50 +010098
99 dwReaders = SCARD_AUTOALLOCATE;
100 rc = SCardListReaders(st->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
101 PCSC_ERROR(rc, "SCardListReaders");
102
Eric Wild94cd4ac2019-10-31 19:18:45 +0100103 /* SCARD_S_SUCCESS means there is at least one reader in the group */
Harald Welted54c2ee2012-01-17 18:25:50 +0100104 num_readers = 0;
105 ptr = mszReaders;
Eric Wild94cd4ac2019-10-31 19:18:45 +0100106 while (*ptr != '\0' && num_readers != num) {
Harald Welted54c2ee2012-01-17 18:25:50 +0100107 ptr += strlen(ptr)+1;
108 num_readers++;
109 }
110
Eric Wild18caa872020-01-29 14:41:18 +0100111 if (num != num_readers) {
112 SCardFreeMemory(st->hContext, mszReaders);
Harald Welted54c2ee2012-01-17 18:25:50 +0100113 goto end;
Eric Wild18caa872020-01-29 14:41:18 +0100114 }
Harald Welted54c2ee2012-01-17 18:25:50 +0100115
Eric Wild94cd4ac2019-10-31 19:18:45 +0100116 st->name = talloc_strdup(rh, ptr);
Harald Welted54c2ee2012-01-17 18:25:50 +0100117 st->dwActiveProtocol = -1;
Eric Wild18caa872020-01-29 14:41:18 +0100118 SCardFreeMemory(st->hContext, mszReaders);
Harald Welted54c2ee2012-01-17 18:25:50 +0100119
120 return rh;
121end:
122 talloc_free(rh);
123 return NULL;
124}
125
Harald Welte55790aa2014-10-26 18:46:50 +0100126static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh,
127 enum osim_proto proto)
Harald Welted54c2ee2012-01-17 18:25:50 +0100128{
129 struct pcsc_reader_state *st = rh->priv;
130 struct osim_card_hdl *card;
131 struct osim_chan_hdl *chan;
Harald Welte0d246442014-05-04 13:58:54 +0200132 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100133
Harald Welte55790aa2014-10-26 18:46:50 +0100134 if (proto != OSIM_PROTO_T0)
135 return NULL;
136
Harald Welted54c2ee2012-01-17 18:25:50 +0100137 rc = SCardConnect(st->hContext, st->name, SCARD_SHARE_SHARED,
138 SCARD_PROTOCOL_T0, &st->hCard, &st->dwActiveProtocol);
139 PCSC_ERROR(rc, "SCardConnect");
140
141 st->pioSendPci = SCARD_PCI_T0;
142
143 card = talloc_zero(rh, struct osim_card_hdl);
144 INIT_LLIST_HEAD(&card->channels);
Harald Welte429adec2020-03-20 13:05:40 +0100145 INIT_LLIST_HEAD(&card->apps);
Harald Welted54c2ee2012-01-17 18:25:50 +0100146 card->reader = rh;
147 rh->card = card;
148
149 /* create a default channel */
150 chan = talloc_zero(card, struct osim_chan_hdl);
151 chan->card = card;
152 llist_add(&chan->list, &card->channels);
153
Harald Welte22117a72021-04-25 20:50:13 +0200154 pcsc_get_atr(card);
155
Harald Welted54c2ee2012-01-17 18:25:50 +0100156 return card;
157
158end:
159 return NULL;
160}
161
162
163static int pcsc_transceive(struct osim_reader_hdl *rh, struct msgb *msg)
164{
165 struct pcsc_reader_state *st = rh->priv;
166 DWORD rlen = msgb_tailroom(msg);
Harald Welte0d246442014-05-04 13:58:54 +0200167 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100168
169 printf("TX: %s\n", osmo_hexdump(msg->data, msg->len));
170
171 rc = SCardTransmit(st->hCard, st->pioSendPci, msg->data, msgb_length(msg),
172 &st->pioRecvPci, msg->tail, &rlen);
173 PCSC_ERROR(rc, "SCardEndTransaction");
174
175 printf("RX: %s\n", osmo_hexdump(msg->tail, rlen));
176 msgb_put(msg, rlen);
177 msgb_apdu_le(msg) = rlen;
178
179 return 0;
180end:
181 return -EIO;
182}
183
184const struct osim_reader_ops pcsc_reader_ops = {
185 .name = "PC/SC",
186 .reader_open = pcsc_reader_open,
187 .card_open = pcsc_card_open,
188 .transceive = pcsc_transceive,
189};
190