Coverage Report

Created: 2025-10-10 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/sm.c
Line
Count
Source
1
/*
2
 * sm.c: Secure Messaging helper functions
3
 *
4
 * Copyright (C) 2013 Viktor Tarasov <viktor.tarasov@gmail.com>
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 <stdlib.h>
27
#include <assert.h>
28
#include <string.h>
29
30
#include "internal.h"
31
#include "asn1.h"
32
#include "sm.h"
33
34
#ifdef ENABLE_SM
35
static const struct sc_asn1_entry c_asn1_sm_response[4] = {
36
  { "encryptedData",  SC_ASN1_OCTET_STRING,   SC_ASN1_CTX | 7,        SC_ASN1_OPTIONAL,       NULL, NULL },
37
  { "statusWord",   SC_ASN1_OCTET_STRING,   SC_ASN1_CTX | 0x19,     0,                      NULL, NULL },
38
  { "mac",    SC_ASN1_OCTET_STRING,   SC_ASN1_CTX | 0x0E,     0,                      NULL, NULL },
39
  { NULL, 0, 0, 0, NULL, NULL }
40
};
41
42
int
43
sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
44
    struct sm_card_response *out)
45
2.16k
{
46
2.16k
  struct sc_asn1_entry asn1_sm_response[4];
47
2.16k
  unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
48
2.16k
  size_t data_len = sizeof(data);
49
2.16k
  unsigned char status[2] = {0, 0};
50
2.16k
  size_t status_len = sizeof(status);
51
2.16k
  unsigned char mac[8];
52
2.16k
  size_t mac_len = sizeof(mac);
53
2.16k
  int rv;
54
55
2.16k
  if (!resp_data || !resp_len || !out)
56
0
    return SC_ERROR_INVALID_ARGUMENTS;
57
58
2.16k
  sc_copy_asn1_entry(c_asn1_sm_response, asn1_sm_response);
59
60
2.16k
  sc_format_asn1_entry(asn1_sm_response + 0, data, &data_len, 0);
61
2.16k
  sc_format_asn1_entry(asn1_sm_response + 1, status, &status_len, 0);
62
2.16k
  sc_format_asn1_entry(asn1_sm_response + 2, mac, &mac_len, 0);
63
64
2.16k
  rv = sc_asn1_decode(card->ctx, asn1_sm_response, resp_data, resp_len, NULL, NULL);
65
2.16k
  if (rv)
66
1.87k
    return rv;
67
68
293
  if (asn1_sm_response[0].flags & SC_ASN1_PRESENT)   {
69
184
    if (data_len > sizeof(out->data))
70
0
      return SC_ERROR_BUFFER_TOO_SMALL;
71
184
    memcpy(out->data, data, data_len);
72
184
    out->data_len = data_len;
73
184
  }
74
293
  if (asn1_sm_response[1].flags & SC_ASN1_PRESENT)   {
75
293
    if (!status[0])
76
54
      return SC_ERROR_INVALID_DATA;
77
239
    out->sw1 = status[0];
78
239
    out->sw2 = status[1];
79
239
  }
80
239
  if (asn1_sm_response[2].flags & SC_ASN1_PRESENT)   {
81
239
    memcpy(out->mac, mac, mac_len);
82
239
    out->mac_len = mac_len;
83
239
  }
84
85
239
  return SC_SUCCESS;
86
293
}
87
88
/**  parse answer of SM protected APDU returned by APDU or by 'GET RESPONSE'
89
 *  @param  card 'sc_card' smartcard object
90
 *  @param  resp_data 'raw data returned by SM protected APDU
91
 *  @param  resp_len 'length of raw data returned by SM protected APDU
92
 *  @param  ref_rv 'status word returned by APDU or 'GET RESPONSE' (can be different from status word encoded into SM response date)
93
 *  @param  apdu 'sc_apdu' object to update
94
 *  @return SC_SUCCESS on success and an error code otherwise
95
 */
96
int
97
sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
98
    int ref_rv, struct sc_apdu *apdu)
99
2.16k
{
100
2.16k
  struct sm_card_response sm_resp;
101
2.16k
  int r;
102
103
2.16k
  if (!apdu)
104
0
    return SC_ERROR_INVALID_ARGUMENTS;
105
2.16k
  else if (!resp_data || !resp_len)
106
0
    return SC_SUCCESS;
107
108
2.16k
  memset(&sm_resp, 0, sizeof(sm_resp));
109
2.16k
  r = sc_sm_parse_answer(card, resp_data, resp_len, &sm_resp);
110
2.16k
  if (r)
111
1.92k
    return r;
112
113
239
  if (sm_resp.mac_len)   {
114
170
    if (sm_resp.mac_len > sizeof(apdu->mac))
115
0
      return SC_ERROR_INVALID_DATA;
116
170
    memcpy(apdu->mac, sm_resp.mac, sm_resp.mac_len);
117
170
    apdu->mac_len = sm_resp.mac_len;
118
170
  }
119
120
239
  apdu->sw1 = sm_resp.sw1;
121
239
  apdu->sw2 = sm_resp.sw2;
122
123
239
  return SC_SUCCESS;
124
239
}
125
126
int
127
sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
128
4.02k
{
129
4.02k
  struct sc_context *ctx  = card->ctx;
130
4.02k
  struct sc_apdu *sm_apdu = NULL;
131
4.02k
  int rv;
132
133
4.02k
  LOG_FUNC_CALLED(ctx);
134
4.02k
  sc_log(ctx, "SM_MODE:%X", card->sm_ctx.sm_mode);
135
4.02k
  if (!card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu)
136
4.02k
    LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
137
138
  /* get SM encoded APDU */
139
4.02k
  rv = card->sm_ctx.ops.get_sm_apdu(card, apdu, &sm_apdu);
140
4.02k
  if (rv == SC_ERROR_SM_NOT_APPLIED)   {
141
    /* SM wrap of this APDU is ignored by card driver.
142
     * Send plain APDU to the reader driver */
143
0
    rv = card->reader->ops->transmit(card->reader, apdu);
144
0
    LOG_FUNC_RETURN(ctx, rv);
145
4.02k
  } else {
146
4.02k
    if (rv < 0)
147
0
      sc_sm_stop(card);
148
4.02k
  }
149
4.02k
  LOG_TEST_RET(ctx, rv, "get SM APDU error");
150
151
  /* check if SM APDU is still valid */
152
4.02k
  rv = sc_check_apdu(card, sm_apdu);
153
4.02k
  if (rv < 0)   {
154
0
    card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
155
0
    sc_sm_stop(card);
156
0
    LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU");
157
0
  }
158
159
  /* send APDU flagged as NO_SM */
160
4.02k
  sm_apdu->flags |= SC_APDU_FLAGS_NO_SM | SC_APDU_FLAGS_NO_RETRY_WL;
161
4.02k
  rv = sc_transmit_apdu(card, sm_apdu);
162
4.02k
  if (rv < 0) {
163
30
    card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
164
30
    sc_sm_stop(card);
165
30
    LOG_TEST_RET(ctx, rv, "unable to transmit APDU");
166
30
  }
167
168
  /* decode SM answer and free temporary SM related data */
169
3.99k
  rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu);
170
3.99k
  if (rv < 0)
171
637
    sc_sm_stop(card);
172
173
3.99k
  LOG_FUNC_RETURN(ctx, rv);
174
3.99k
}
175
176
int
177
sc_sm_stop(struct sc_card *card)
178
898
{
179
898
    int r = SC_SUCCESS;
180
181
898
    if (card) {
182
898
        if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT
183
667
                && card->sm_ctx.ops.close)
184
0
            r = card->sm_ctx.ops.close(card);
185
898
        card->sm_ctx.sm_mode = SM_MODE_NONE;
186
898
    }
187
188
898
    return r;
189
898
}
190
191
#else
192
193
int
194
sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
195
    struct sm_card_response *out)
196
{
197
  return SC_ERROR_NOT_SUPPORTED;
198
}
199
200
int
201
sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len,
202
    int ref_rv, struct sc_apdu *apdu)
203
{
204
  return SC_ERROR_NOT_SUPPORTED;
205
}
206
207
int
208
sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu)
209
{
210
  return SC_ERROR_NOT_SUPPORTED;
211
}
212
213
int
214
sc_sm_stop(struct sc_card *card)
215
{
216
    return SC_ERROR_NOT_SUPPORTED;
217
}
218
#endif