Coverage Report

Created: 2026-01-07 06:05

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
88.4k
{
45
88.4k
  char dir[PATH_MAX];
46
88.4k
  char *last_update = NULL;
47
88.4k
  int  r;
48
88.4k
  unsigned u;
49
88.4k
  size_t change_counter;
50
51
88.4k
  if (p15card->tokeninfo->serial_number == NULL
52
7.90k
      && (p15card->card->uid.len == 0
53
0
        || p15card->card->uid.value[0] == RANDOM_UID_INDICATOR))
54
7.90k
    return SC_ERROR_INVALID_ARGUMENTS;
55
56
88.4k
  assert(path->len <= SC_MAX_PATH_SIZE);
57
80.5k
  r = sc_get_cache_dir(p15card->card->ctx, dir, sizeof(dir));
58
80.5k
  if (r)
59
0
    return r;
60
80.5k
  snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "/");
61
62
80.5k
  last_update = sc_pkcs15_get_lastupdate(p15card);
63
80.5k
  if (!last_update)
64
75.6k
    last_update = "NODATE";
65
66
80.5k
  if (p15card->tokeninfo->serial_number) {
67
80.5k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
68
80.5k
        "%s_%s", p15card->tokeninfo->serial_number,
69
80.5k
        last_update);
70
80.5k
  } else {
71
0
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
72
0
        "uid-%s_%s", sc_dump_hex(
73
0
          p15card->card->uid.value,
74
0
          p15card->card->uid.len), last_update);
75
0
  }
76
77
80.5k
  if (SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_CHANGE_COUNTER, &change_counter))
78
276
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_%" SC_FORMAT_LEN_SIZE_T "u", change_counter);
79
80
80.5k
  if (path->aid.len &&
81
6.44k
    (path->type == SC_PATH_TYPE_FILE_ID || path->type == SC_PATH_TYPE_PATH))   {
82
5.70k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
83
45.8k
    for (u = 0; u < path->aid.len; u++)
84
40.1k
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
85
40.1k
          "%02X",  path->aid.value[u]);
86
5.70k
  }
87
74.8k
  else if (path->type != SC_PATH_TYPE_PATH)  {
88
975
    return SC_ERROR_INVALID_ARGUMENTS;
89
975
  }
90
91
79.5k
  if (path->len)   {
92
79.5k
    size_t offs = 0;
93
94
79.5k
    if (path->len > 2 && memcmp(path->value, "\x3F\x00", 2) == 0)
95
73.1k
      offs = 2;
96
79.5k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
97
328k
    for (u = 0; u < path->len - offs; u++)
98
249k
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
99
249k
          "%02X",  path->value[u + offs]);
100
79.5k
  }
101
102
79.5k
  if (!buf)
103
0
    return SC_ERROR_BUFFER_TOO_SMALL;
104
79.5k
  strlcpy(buf, dir, bufsize);
105
106
79.5k
  return SC_SUCCESS;
107
79.5k
}
108
109
int sc_pkcs15_read_cached_file(struct sc_pkcs15_card *p15card,
110
        const sc_path_t *path,
111
        u8 **buf, size_t *bufsize)
112
130k
{
113
130k
  char fname[PATH_MAX];
114
130k
  int rv;
115
130k
  FILE *f;
116
130k
  size_t count;
117
130k
  struct stat stbuf;
118
130k
  u8 *data = NULL;
119
120
130k
  if (path->len < 2)
121
28.6k
    return SC_ERROR_INVALID_ARGUMENTS;
122
123
  /* Accept full path or FILE-ID path with AID */
124
101k
  if ((path->type != SC_PATH_TYPE_PATH) && (path->type != SC_PATH_TYPE_FILE_ID || path->aid.len == 0))
125
17.1k
    return SC_ERROR_INVALID_ARGUMENTS;
126
127
84.2k
  sc_log(p15card->card->ctx, "try to read cache for %s", sc_print_path(path));
128
84.2k
  rv = generate_cache_filename(p15card, path, fname, sizeof(fname));
129
84.2k
  if (rv != SC_SUCCESS)
130
5.55k
    return rv;
131
78.6k
  sc_log(p15card->card->ctx, "read cached file %s", fname);
132
133
78.6k
  f = fopen(fname, "rb");
134
78.6k
  if (!f)
135
76.2k
    return SC_ERROR_FILE_NOT_FOUND;
136
2.42k
  if (fstat(fileno(f), &stbuf))   {
137
0
    fclose(f);
138
0
    return  SC_ERROR_FILE_NOT_FOUND;
139
0
  }
140
141
2.42k
  if (path->count < 0) {
142
1.63k
    count = stbuf.st_size;
143
1.63k
  }
144
789
  else {
145
789
    count = path->count;
146
789
    if (path->index + count > (size_t)stbuf.st_size)   {
147
666
      rv = SC_ERROR_FILE_NOT_FOUND; /* cache file bad? */
148
666
      goto err;
149
666
    }
150
151
123
    if (0 != fseek(f, (long)path->index, SEEK_SET)) {
152
0
      rv = SC_ERROR_FILE_NOT_FOUND;
153
0
      goto err;
154
0
    }
155
123
  }
156
157
1.76k
  if (*buf == NULL) {
158
1.74k
    data = malloc((size_t)stbuf.st_size);
159
1.74k
    if (data == NULL)   {
160
0
      rv = SC_ERROR_OUT_OF_MEMORY;
161
0
      goto err;
162
0
    }
163
1.74k
  }
164
20
  else {
165
20
    if (count > *bufsize) {
166
10
      rv =  SC_ERROR_BUFFER_TOO_SMALL;
167
10
      goto err;
168
10
    }
169
10
    data = *buf;
170
10
  }
171
172
1.75k
  if (count != fread(data, 1, count, f)) {
173
0
    rv = SC_ERROR_BUFFER_TOO_SMALL;
174
0
    goto err;
175
0
  }
176
1.75k
  *buf = data;
177
1.75k
  *bufsize = count;
178
179
1.75k
  rv = SC_SUCCESS;
180
181
2.42k
err:
182
2.42k
  if (rv != SC_SUCCESS) {
183
676
    if (data != *buf) {
184
10
      free(data);
185
10
    }
186
676
  }
187
188
2.42k
  fclose(f);
189
2.42k
  return rv;
190
1.75k
}
191
192
int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card,
193
       const sc_path_t *path,
194
       const u8 *buf, size_t bufsize)
195
4.24k
{
196
4.24k
  char fname[PATH_MAX];
197
4.24k
  int r;
198
4.24k
  long len;
199
4.24k
  FILE *f;
200
4.24k
  size_t c;
201
202
4.24k
  r = generate_cache_filename(p15card, path, fname, sizeof(fname));
203
4.24k
  if (r != 0)
204
3.31k
    return r;
205
206
921
  f = fopen(fname, "ab");
207
  /* If the open failed because the cache directory does
208
   * not exist, create it and a re-try the fopen() call.
209
   */
210
921
  if (f == NULL && errno == ENOENT) {
211
261
    if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0)
212
260
      return r;
213
1
    f = fopen(fname, "ab");
214
1
  }
215
661
  if (f == NULL)
216
0
    return 0;
217
218
  /* we opened the file for appending so we should be at the end of file.
219
   * The ftell() will give use the length of the file */
220
661
  len = ftell(f);
221
661
  if (len > path->index) {
222
    /* override previous cache records on this location */
223
119
    r = fseek(f, path->index, SEEK_SET);
224
119
    if (r != 0) {
225
0
      fclose(f);
226
0
      return 0;
227
0
    }
228
542
  } else if (path->index > len) {
229
    /* We miss some bytes so we will not cache this chunk */
230
142
    fclose(f);
231
142
    return 0;
232
142
  }
233
234
519
  c = fwrite(buf, 1, bufsize, f);
235
519
  fclose(f);
236
519
  if (c != bufsize) {
237
0
    sc_log(p15card->card->ctx,
238
0
       "fwrite() wrote only %"SC_FORMAT_LEN_SIZE_T"u bytes",
239
0
       c);
240
0
    unlink(fname);
241
0
    return SC_ERROR_INTERNAL;
242
0
  }
243
519
  return 0;
244
519
}