blob: c37072eeb772bb22840a7c709a0459e95f5c0c40 [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 *
Harald Weltead418632012-09-10 10:49:59 +020020 */
21
22
Harald Welted54c2ee2012-01-17 18:25:50 +010023#include <string.h>
24#include <stdint.h>
25#include <stdio.h>
26#include <errno.h>
27
28#include <osmocom/core/talloc.h>
29#include <osmocom/sim/sim.h>
30
Holger Hans Peter Freytherb0310dd2014-10-27 12:00:37 +010031#include <wintypes.h>
32#include <winscard.h>
Harald Welted54c2ee2012-01-17 18:25:50 +010033
34#include "sim_int.h"
35
36#define PCSC_ERROR(rv, text) \
37if (rv != SCARD_S_SUCCESS) { \
38 fprintf(stderr, text ": %s (0x%lX)\n", pcsc_stringify_error(rv), rv); \
39 goto end; \
Harald Welted54c2ee2012-01-17 18:25:50 +010040}
41
42
Harald Welted54c2ee2012-01-17 18:25:50 +010043struct pcsc_reader_state {
44 SCARDCONTEXT hContext;
45 SCARDHANDLE hCard;
46 DWORD dwActiveProtocol;
47 const SCARD_IO_REQUEST *pioSendPci;
48 SCARD_IO_REQUEST pioRecvPci;
49 char *name;
50};
51
Harald Welte22117a72021-04-25 20:50:13 +020052static int pcsc_get_atr(struct osim_card_hdl *card)
53{
54 struct osim_reader_hdl *rh = card->reader;
55 struct pcsc_reader_state *st = rh->priv;
56 char pbReader[MAX_READERNAME];
57 DWORD dwReaderLen = sizeof(pbReader);
58 DWORD dwAtrLen = sizeof(card->atr);
59 DWORD dwState, dwProt;
60 long rc;
61
62 rc = SCardStatus(st->hCard, pbReader, &dwReaderLen, &dwState, &dwProt,
63 card->atr, &dwAtrLen);
64 PCSC_ERROR(rc, "SCardStatus");
65 card->atr_len = dwAtrLen;
66
67 return 0;
68
69end:
70 return -EIO;
71}
72
Harald Welted54c2ee2012-01-17 18:25:50 +010073static struct osim_reader_hdl *pcsc_reader_open(int num, const char *id, void *ctx)
74{
75 struct osim_reader_hdl *rh;
76 struct pcsc_reader_state *st;
Harald Welte0d246442014-05-04 13:58:54 +020077 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +010078 LPSTR mszReaders = NULL;
79 DWORD dwReaders;
80 unsigned int num_readers;
81 char *ptr;
82
83 /* FIXME: implement matching on id or num */
84
85 rh = talloc_zero(ctx, struct osim_reader_hdl);
86 st = rh->priv = talloc_zero(rh, struct pcsc_reader_state);
87
88 rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
89 &st->hContext);
Harald Welted83d2962013-03-04 17:52:33 +000090 PCSC_ERROR(rc, "SCardEstablishContext");
Harald Welted54c2ee2012-01-17 18:25:50 +010091
92 dwReaders = SCARD_AUTOALLOCATE;
93 rc = SCardListReaders(st->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
94 PCSC_ERROR(rc, "SCardListReaders");
95
Eric Wild94cd4ac2019-10-31 19:18:45 +010096 /* SCARD_S_SUCCESS means there is at least one reader in the group */
Harald Welted54c2ee2012-01-17 18:25:50 +010097 num_readers = 0;
98 ptr = mszReaders;
Eric Wild94cd4ac2019-10-31 19:18:45 +010099 while (*ptr != '\0' && num_readers != num) {
Harald Welted54c2ee2012-01-17 18:25:50 +0100100 ptr += strlen(ptr)+1;
101 num_readers++;
102 }
103
Eric Wild18caa872020-01-29 14:41:18 +0100104 if (num != num_readers) {
105 SCardFreeMemory(st->hContext, mszReaders);
Harald Welted54c2ee2012-01-17 18:25:50 +0100106 goto end;
Eric Wild18caa872020-01-29 14:41:18 +0100107 }
Harald Welted54c2ee2012-01-17 18:25:50 +0100108
Eric Wild94cd4ac2019-10-31 19:18:45 +0100109 st->name = talloc_strdup(rh, ptr);
Harald Welted54c2ee2012-01-17 18:25:50 +0100110 st->dwActiveProtocol = -1;
Eric Wild18caa872020-01-29 14:41:18 +0100111 SCardFreeMemory(st->hContext, mszReaders);
Harald Welted54c2ee2012-01-17 18:25:50 +0100112
113 return rh;
114end:
115 talloc_free(rh);
116 return NULL;
117}
118
Harald Welte55790aa2014-10-26 18:46:50 +0100119static struct osim_card_hdl *pcsc_card_open(struct osim_reader_hdl *rh,
120 enum osim_proto proto)
Harald Welted54c2ee2012-01-17 18:25:50 +0100121{
122 struct pcsc_reader_state *st = rh->priv;
123 struct osim_card_hdl *card;
124 struct osim_chan_hdl *chan;
Harald Welte0d246442014-05-04 13:58:54 +0200125 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100126
Harald Welte55790aa2014-10-26 18:46:50 +0100127 if (proto != OSIM_PROTO_T0)
128 return NULL;
129
Harald Welted54c2ee2012-01-17 18:25:50 +0100130 rc = SCardConnect(st->hContext, st->name, SCARD_SHARE_SHARED,
131 SCARD_PROTOCOL_T0, &st->hCard, &st->dwActiveProtocol);
132 PCSC_ERROR(rc, "SCardConnect");
133
134 st->pioSendPci = SCARD_PCI_T0;
135
136 card = talloc_zero(rh, struct osim_card_hdl);
137 INIT_LLIST_HEAD(&card->channels);
Harald Welte429adec2020-03-20 13:05:40 +0100138 INIT_LLIST_HEAD(&card->apps);
Harald Welted54c2ee2012-01-17 18:25:50 +0100139 card->reader = rh;
140 rh->card = card;
141
142 /* create a default channel */
143 chan = talloc_zero(card, struct osim_chan_hdl);
144 chan->card = card;
145 llist_add(&chan->list, &card->channels);
146
Harald Welte22117a72021-04-25 20:50:13 +0200147 pcsc_get_atr(card);
148
Harald Welted54c2ee2012-01-17 18:25:50 +0100149 return card;
150
151end:
152 return NULL;
153}
154
Harald Welte20199da2021-06-01 20:11:19 +0200155static int pcsc_card_reset(struct osim_card_hdl *card, bool cold_reset)
156{
157 struct pcsc_reader_state *st = card->reader->priv;
158 LONG rc;
159
160 rc = SCardReconnect(st->hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0,
161 cold_reset ? SCARD_UNPOWER_CARD : SCARD_RESET_CARD,
162 &st->dwActiveProtocol);
163 PCSC_ERROR(rc, "SCardReconnect");
164
165 return 0;
166end:
167 return -EIO;
168}
169
170static int pcsc_card_close(struct osim_card_hdl *card)
171{
172 struct pcsc_reader_state *st = card->reader->priv;
173 LONG rc;
174
175 rc = SCardDisconnect(st->hCard, SCARD_UNPOWER_CARD);
176 PCSC_ERROR(rc, "SCardDisconnect");
177
178 return 0;
179end:
180 return -EIO;
181}
182
Harald Welted54c2ee2012-01-17 18:25:50 +0100183
184static int pcsc_transceive(struct osim_reader_hdl *rh, struct msgb *msg)
185{
186 struct pcsc_reader_state *st = rh->priv;
187 DWORD rlen = msgb_tailroom(msg);
Harald Welte0d246442014-05-04 13:58:54 +0200188 LONG rc;
Harald Welted54c2ee2012-01-17 18:25:50 +0100189
Harald Welted54c2ee2012-01-17 18:25:50 +0100190 rc = SCardTransmit(st->hCard, st->pioSendPci, msg->data, msgb_length(msg),
191 &st->pioRecvPci, msg->tail, &rlen);
192 PCSC_ERROR(rc, "SCardEndTransaction");
193
Harald Welted54c2ee2012-01-17 18:25:50 +0100194 msgb_put(msg, rlen);
195 msgb_apdu_le(msg) = rlen;
196
197 return 0;
198end:
199 return -EIO;
200}
201
202const struct osim_reader_ops pcsc_reader_ops = {
203 .name = "PC/SC",
204 .reader_open = pcsc_reader_open,
205 .card_open = pcsc_card_open,
Harald Welte20199da2021-06-01 20:11:19 +0200206 .card_reset = pcsc_card_reset,
207 .card_close = pcsc_card_close,
Harald Welted54c2ee2012-01-17 18:25:50 +0100208 .transceive = pcsc_transceive,
209};
210