Coverage Report

Created: 2025-11-23 06:57

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
3.48k
{
45
3.48k
  char dir[PATH_MAX];
46
3.48k
  char *last_update = NULL;
47
3.48k
  int  r;
48
3.48k
  unsigned u;
49
3.48k
  size_t change_counter;
50
51
3.48k
  if (p15card->tokeninfo->serial_number == NULL
52
1.51k
      && (p15card->card->uid.len == 0
53
0
        || p15card->card->uid.value[0] == RANDOM_UID_INDICATOR))
54
1.51k
    return SC_ERROR_INVALID_ARGUMENTS;
55
56
3.48k
  assert(path->len <= SC_MAX_PATH_SIZE);
57
1.97k
  r = sc_get_cache_dir(p15card->card->ctx, dir, sizeof(dir));
58
1.97k
  if (r)
59
0
    return r;
60
1.97k
  snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "/");
61
62
1.97k
  last_update = sc_pkcs15_get_lastupdate(p15card);
63
1.97k
  if (!last_update)
64
1.95k
    last_update = "NODATE";
65
66
1.97k
  if (p15card->tokeninfo->serial_number) {
67
1.97k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
68
1.97k
        "%s_%s", p15card->tokeninfo->serial_number,
69
1.97k
        last_update);
70
1.97k
  } 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
1.97k
  if (SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_CHANGE_COUNTER, &change_counter))
78
11
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_%" SC_FORMAT_LEN_SIZE_T "u", change_counter);
79
80
1.97k
  if (path->aid.len &&
81
1.39k
    (path->type == SC_PATH_TYPE_FILE_ID || path->type == SC_PATH_TYPE_PATH))   {
82
1.25k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
83
10.0k
    for (u = 0; u < path->aid.len; u++)
84
8.78k
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
85
8.78k
          "%02X",  path->aid.value[u]);
86
1.25k
  }
87
713
  else if (path->type != SC_PATH_TYPE_PATH)  {
88
156
    return SC_ERROR_INVALID_ARGUMENTS;
89
156
  }
90
91
1.81k
  if (path->len)   {
92
1.81k
    size_t offs = 0;
93
94
1.81k
    if (path->len > 2 && memcmp(path->value, "\x3F\x00", 2) == 0)
95
557
      offs = 2;
96
1.81k
    snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir), "_");
97
7.02k
    for (u = 0; u < path->len - offs; u++)
98
5.21k
      snprintf(dir + strlen(dir), sizeof(dir) - strlen(dir),
99
5.21k
          "%02X",  path->value[u + offs]);
100
1.81k
  }
101
102
1.81k
  if (!buf)
103
0
    return SC_ERROR_BUFFER_TOO_SMALL;
104
1.81k
  strlcpy(buf, dir, bufsize);
105
106
1.81k
  return SC_SUCCESS;
107
1.81k
}
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
5.68k
{
113
5.68k
  char fname[PATH_MAX];
114
5.68k
  int rv;
115
5.68k
  FILE *f;
116
5.68k
  size_t count;
117
5.68k
  struct stat stbuf;
118
5.68k
  u8 *data = NULL;
119
120
5.68k
  if (path->len < 2)
121
1.58k
    return SC_ERROR_INVALID_ARGUMENTS;
122
123
  /* Accept full path or FILE-ID path with AID */
124
4.10k
  if ((path->type != SC_PATH_TYPE_PATH) && (path->type != SC_PATH_TYPE_FILE_ID || path->aid.len == 0))
125
1.37k
    return SC_ERROR_INVALID_ARGUMENTS;
126
127
2.72k
  sc_log(p15card->card->ctx, "try to read cache for %s", sc_print_path(path));
128
2.72k
  rv = generate_cache_filename(p15card, path, fname, sizeof(fname));
129
2.72k
  if (rv != SC_SUCCESS)
130
1.06k
    return rv;
131
1.66k
  sc_log(p15card->card->ctx, "read cached file %s", fname);
132
133
1.66k
  f = fopen(fname, "rb");
134
1.66k
  if (!f)
135
1.54k
    return SC_ERROR_FILE_NOT_FOUND;
136
117
  if (fstat(fileno(f), &stbuf))   {
137
0
    fclose(f);
138
0
    return  SC_ERROR_FILE_NOT_FOUND;
139
0
  }
140
141
117
  if (path->count < 0) {
142
75
    count = stbuf.st_size;
143
75
  }
144
42
  else {
145
42
    count = path->count;
146
42
    if (path->index + count > (size_t)stbuf.st_size)   {
147
40
      rv = SC_ERROR_FILE_NOT_FOUND; /* cache file bad? */
148
40
      goto err;
149
40
    }
150
151
2
    if (0 != fseek(f, (long)path->index, SEEK_SET)) {
152
0
      rv = SC_ERROR_FILE_NOT_FOUND;
153
0
      goto err;
154
0
    }
155
2
  }
156
157
77
  if (*buf == NULL) {
158
69
    data = malloc((size_t)stbuf.st_size);
159
69
    if (data == NULL)   {
160
0
      rv = SC_ERROR_OUT_OF_MEMORY;
161
0
      goto err;
162
0
    }
163
69
  }
164
8
  else {
165
8
    if (count > *bufsize) {
166
5
      rv =  SC_ERROR_BUFFER_TOO_SMALL;
167
5
      goto err;
168
5
    }
169
3
    data = *buf;
170
3
  }
171
172
72
  if (count != fread(data, 1, count, f)) {
173
0
    rv = SC_ERROR_BUFFER_TOO_SMALL;
174
0
    goto err;
175
0
  }
176
72
  *buf = data;
177
72
  *bufsize = count;
178
179
72
  rv = SC_SUCCESS;
180
181
117
err:
182
117
  if (rv != SC_SUCCESS) {
183
45
    if (data != *buf) {
184
5
      free(data);
185
5
    }
186
45
  }
187
188
117
  fclose(f);
189
117
  return rv;
190
72
}
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
760
{
196
760
  char fname[PATH_MAX];
197
760
  int r;
198
760
  long len;
199
760
  FILE *f;
200
760
  size_t c;
201
202
760
  r = generate_cache_filename(p15card, path, fname, sizeof(fname));
203
760
  if (r != 0)
204
605
    return r;
205
206
155
  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
155
  if (f == NULL && errno == ENOENT) {
211
70
    if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0)
212
70
      return r;
213
0
    f = fopen(fname, "ab");
214
0
  }
215
85
  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
85
  len = ftell(f);
221
85
  if (len > path->index) {
222
    /* override previous cache records on this location */
223
18
    r = fseek(f, path->index, SEEK_SET);
224
18
    if (r != 0) {
225
0
      fclose(f);
226
0
      return 0;
227
0
    }
228
67
  } else if (path->index > len) {
229
    /* We miss some bytes so we will not cache this chunk */
230
1
    fclose(f);
231
1
    return 0;
232
1
  }
233
234
84
  c = fwrite(buf, 1, bufsize, f);
235
84
  fclose(f);
236
84
  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
84
  return 0;
244
84
}