Coverage Report

Created: 2026-09-03 06:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/pkcs15-cache.c
Line
Count
Source
1
/*
2
 * pkcs15-cache.c: PKCS #15 file caching 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., 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 <string.h>
28
#ifdef HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
#include <sys/stat.h>
32
#include <limits.h>
33
#include <errno.h>
34
#include <assert.h>
35
36
#include "internal.h"
37
#include "pkcs15.h"
38
#include "common/compat_strlcpy.h"
39
40
0
#define RANDOM_UID_INDICATOR 0x08
41
static int generate_cache_filename(struct sc_pkcs15_card *p15card,
42
           const sc_path_t *path,
43
           char *buf, size_t bufsize)
44
1.03k
{
45
1.03k
  char dir[PATH_MAX];
46
1.03k
  char *last_update = NULL;
47
1.03k
  int  r;
48
1.03k
  unsigned u;
49
1.03k
  size_t change_counter;
50
51
1.03k
  if (p15card->tokeninfo->serial_number == NULL
52
1.02k
      && (p15card->card->uid.len == 0
53
0
        || p15card->card->uid.value[0] == RANDOM_UID_INDICATOR))
54
1.02k
    return SC_ERROR_INVALID_ARGUMENTS;
55
56
15
  if (path->len > SC_MAX_PATH_SIZE)
57
0
    return SC_ERROR_INTERNAL;
58
15
  r = sc_get_cache_dir(p15card->card->ctx, dir, sizeof(dir));
59
15
  if (r)
60
0
    return r;
61
15
  snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "/");
62
63
15
  last_update = sc_pkcs15_get_lastupdate(p15card);
64
15
  if (!last_update)
65
15
    last_update = "NODATE";
66
67
15
  if (p15card->tokeninfo->serial_number) {
68
15
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
69
15
        "%s_%s", p15card->tokeninfo->serial_number,
70
15
        last_update);
71
15
  } else {
72
0
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
73
0
        "uid-%s_%s", sc_dump_hex(
74
0
          p15card->card->uid.value,
75
0
          p15card->card->uid.len), last_update);
76
0
  }
77
78
15
  if (SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_CHANGE_COUNTER, &change_counter))
79
3
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_%zu", change_counter);
80
81
15
  if (path->aid.len &&
82
0
    (path->type == SC_PATH_TYPE_FILE_ID || path->type == SC_PATH_TYPE_PATH))   {
83
0
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
84
0
    for (u = 0; u < path->aid.len; u++)
85
0
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
86
0
          "%02X",  path->aid.value[u]);
87
0
  }
88
15
  else if (path->type != SC_PATH_TYPE_PATH)  {
89
0
    return SC_ERROR_INVALID_ARGUMENTS;
90
0
  }
91
92
15
  if (path->len)   {
93
15
    size_t offs = 0;
94
95
15
    if (path->len > 2 && memcmp(path->value, "\x3F\x00", 2) == 0)
96
15
      offs = 2;
97
15
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
98
49
    for (u = 0; u < path->len - offs; u++)
99
34
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
100
34
          "%02X",  path->value[u + offs]);
101
15
  }
102
103
15
  if (!buf)
104
0
    return SC_ERROR_BUFFER_TOO_SMALL;
105
15
  strlcpy(buf, dir, bufsize);
106
107
15
  return SC_SUCCESS;
108
15
}
109
110
int sc_pkcs15_read_cached_file(struct sc_pkcs15_card *p15card,
111
        const sc_path_t *path,
112
        u8 **buf, size_t *bufsize)
113
2.51k
{
114
2.51k
  char fname[PATH_MAX];
115
2.51k
  int rv;
116
2.51k
  FILE *f;
117
2.51k
  size_t count;
118
2.51k
  struct stat stbuf;
119
2.51k
  u8 *data = NULL;
120
121
2.51k
  if (path->len < 2)
122
194
    return SC_ERROR_INVALID_ARGUMENTS;
123
124
  /* Accept full path or FILE-ID path with AID */
125
2.32k
  if ((path->type != SC_PATH_TYPE_PATH) && (path->type != SC_PATH_TYPE_FILE_ID || path->aid.len == 0))
126
1.44k
    return SC_ERROR_INVALID_ARGUMENTS;
127
128
880
  sc_log(p15card->card->ctx, "try to read cache for %s", sc_print_path(path));
129
880
  rv = generate_cache_filename(p15card, path, fname, sizeof(fname));
130
880
  if (rv != SC_SUCCESS)
131
871
    return rv;
132
9
  sc_log(p15card->card->ctx, "read cached file %s", fname);
133
134
9
  f = fopen(fname, "rb");
135
9
  if (!f)
136
9
    return SC_ERROR_FILE_NOT_FOUND;
137
0
  if (fstat(fileno(f), &stbuf))   {
138
0
    fclose(f);
139
0
    return  SC_ERROR_FILE_NOT_FOUND;
140
0
  }
141
142
0
  if (path->count < 0) {
143
0
    count = stbuf.st_size;
144
0
  }
145
0
  else {
146
0
    count = path->count;
147
0
    if (path->index + count > (size_t)stbuf.st_size)   {
148
0
      rv = SC_ERROR_FILE_NOT_FOUND; /* cache file bad? */
149
0
      goto err;
150
0
    }
151
152
0
    if (0 != fseek(f, (long)path->index, SEEK_SET)) {
153
0
      rv = SC_ERROR_FILE_NOT_FOUND;
154
0
      goto err;
155
0
    }
156
0
  }
157
158
0
  if (*buf == NULL) {
159
0
    data = malloc((size_t)stbuf.st_size);
160
0
    if (data == NULL)   {
161
0
      rv = SC_ERROR_OUT_OF_MEMORY;
162
0
      goto err;
163
0
    }
164
0
  }
165
0
  else {
166
0
    if (count > *bufsize) {
167
0
      rv =  SC_ERROR_BUFFER_TOO_SMALL;
168
0
      goto err;
169
0
    }
170
0
    data = *buf;
171
0
  }
172
173
0
  if (count != fread(data, 1, count, f)) {
174
0
    rv = SC_ERROR_BUFFER_TOO_SMALL;
175
0
    goto err;
176
0
  }
177
0
  *buf = data;
178
0
  *bufsize = count;
179
180
0
  rv = SC_SUCCESS;
181
182
0
err:
183
0
  if (rv != SC_SUCCESS) {
184
0
    if (data != *buf) {
185
0
      free(data);
186
0
    }
187
0
  }
188
189
0
  fclose(f);
190
0
  return rv;
191
0
}
192
193
int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card,
194
       const sc_path_t *path,
195
       const u8 *buf, size_t bufsize)
196
155
{
197
155
  char fname[PATH_MAX];
198
155
  int r;
199
155
  long len;
200
155
  FILE *f;
201
155
  size_t c;
202
203
155
  r = generate_cache_filename(p15card, path, fname, sizeof(fname));
204
155
  if (r != 0)
205
149
    return r;
206
207
6
  f = fopen(fname, "ab");
208
  /* If the open failed because the cache directory does
209
   * not exist, create it and a re-try the fopen() call.
210
   */
211
6
  if (f == NULL && errno == ENOENT) {
212
0
    if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0)
213
0
      return r;
214
0
    f = fopen(fname, "ab");
215
0
  }
216
6
  if (f == NULL)
217
0
    return 0;
218
219
  /* we opened the file for appending so we should be at the end of file.
220
   * The ftell() will give use the length of the file */
221
6
  len = ftell(f);
222
6
  if (len > path->index) {
223
    /* override previous cache records on this location */
224
2
    r = fseek(f, path->index, SEEK_SET);
225
2
    if (r != 0) {
226
0
      fclose(f);
227
0
      return 0;
228
0
    }
229
4
  } else if (path->index > len) {
230
    /* We miss some bytes so we will not cache this chunk */
231
0
    fclose(f);
232
0
    return 0;
233
0
  }
234
235
6
  c = fwrite(buf, 1, bufsize, f);
236
6
  fclose(f);
237
6
  if (c != bufsize) {
238
0
    sc_log(p15card->card->ctx, "fwrite() wrote only %zu bytes", c);
239
0
    unlink(fname);
240
0
    return SC_ERROR_INTERNAL;
241
0
  }
242
6
  return 0;
243
6
}