Coverage Report

Created: 2025-11-23 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/pkcs15init/pkcs15-muscle.c
Line
Count
Source
1
/*
2
 * pkcs15-muscle.c: Support for MuscleCard Applet from musclecard.com
3
 *
4
 * Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.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
#include "config.h"
22
23
#include <sys/types.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <assert.h>
27
#include <stdarg.h>
28
#ifdef HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
32
#include "libopensc/pkcs15.h"
33
#include "libopensc/opensc.h"
34
#include "libopensc/cardctl.h"
35
#include "libopensc/cards.h"
36
#include "libopensc/log.h"
37
#include "pkcs15-init.h"
38
#include "profile.h"
39
40
0
#define MUSCLE_KEY_ID_MIN 0x00
41
0
#define MUSCLE_KEY_ID_MAX 0x0F
42
43
static int muscle_erase_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
44
0
{
45
0
  int r;
46
0
  struct sc_file *file;
47
0
  struct sc_path path;
48
0
  memset(&file, 0, sizeof(file));
49
0
  sc_format_path("3F00", &path);
50
0
  if ((r = sc_select_file(p15card->card, &path, &file)) < 0)
51
0
    return r;
52
0
  if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE)) < 0) {
53
0
    sc_file_free(file);
54
0
    return r;
55
0
  }
56
0
  sc_file_free(file);
57
0
  if ((r = sc_delete_file(p15card->card, &path)) < 0)
58
0
    return r;
59
0
  return 0;
60
0
}
61
62
63
static int muscle_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
64
0
{
65
0
  return 0;
66
0
}
67
68
static int
69
muscle_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df)
70
0
{
71
0
  int r;
72
0
  struct sc_file *file;
73
0
  struct sc_path path;
74
0
  memset(&file, 0, sizeof(file));
75
0
  sc_format_path("3F00", &path);
76
0
  if ((r = sc_select_file(p15card->card, &path, &file)) < 0)
77
0
    return r;
78
0
  if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE)) < 0) {
79
0
    sc_file_free(file);
80
0
    return r;
81
0
  }
82
0
  sc_file_free(file);
83
84
  /* Create the application DF */
85
0
  if ((r = sc_pkcs15init_create_file(profile, p15card, df)) < 0)
86
0
    return r;
87
88
0
  if ((r = sc_select_file(p15card->card, &df->path, NULL)) < 0)
89
0
    return r;
90
91
92
0
  return 0;
93
0
}
94
95
static int
96
muscle_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
97
  sc_file_t *df, sc_pkcs15_object_t *pin_obj,
98
  const unsigned char *pin, size_t pin_len,
99
  const unsigned char *puk, size_t puk_len)
100
0
{
101
0
  sc_file_t *file;
102
0
  sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
103
0
  int r;
104
105
0
  if ((r = sc_select_file(p15card->card, &df->path, &file)) < 0)
106
0
    return r;
107
0
  if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_WRITE)) < 0) {
108
0
    sc_file_free(file);
109
0
    return r;
110
0
  }
111
112
0
  auth_info->attrs.pin.flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
113
0
  sc_file_free(file);
114
0
  return 0;
115
0
}
116
117
static int
118
muscle_select_pin_reference(sc_profile_t *profike, sc_pkcs15_card_t *p15card,
119
    sc_pkcs15_auth_info_t *auth_info)
120
0
{
121
0
  int preferred;
122
123
0
  if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
124
0
    return SC_ERROR_OBJECT_NOT_VALID;
125
126
0
  if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
127
0
    preferred = 0;
128
0
  } else {
129
0
    preferred = 1;
130
0
  }
131
0
  if (auth_info->attrs.pin.reference <= preferred) {
132
0
    auth_info->attrs.pin.reference = preferred;
133
0
    return 0;
134
0
  }
135
136
0
  if (auth_info->attrs.pin.reference > 2)
137
0
    return SC_ERROR_INVALID_ARGUMENTS;
138
139
  /* Caller, please select a different PIN reference */
140
0
  return SC_ERROR_INVALID_PIN_REFERENCE;
141
0
}
142
143
/*
144
 * Select a key reference
145
 */
146
static int
147
muscle_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
148
      sc_pkcs15_prkey_info_t *key_info)
149
0
{
150
0
  if (key_info->key_reference < MUSCLE_KEY_ID_MIN)
151
0
    key_info->key_reference = MUSCLE_KEY_ID_MIN;
152
0
  if (key_info->key_reference > MUSCLE_KEY_ID_MAX)
153
0
    return SC_ERROR_TOO_MANY_OBJECTS;
154
0
  return 0;
155
0
}
156
157
/*
158
 * Create a private key object.
159
 * This is a no-op.
160
 */
161
static int
162
muscle_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
163
      sc_pkcs15_object_t *obj)
164
0
{
165
0
  return 0;
166
0
}
167
168
/*
169
 * Store a private key object.
170
 */
171
static int
172
muscle_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
173
      sc_pkcs15_object_t *obj,
174
      sc_pkcs15_prkey_t *key)
175
0
{
176
0
  struct sc_context *ctx = p15card->card->ctx;
177
0
  sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
178
0
  sc_file_t* prkf;
179
0
  struct sc_pkcs15_prkey_rsa *rsa;
180
0
  sc_cardctl_muscle_key_info_t info;
181
0
  int   r;
182
183
0
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
184
0
    sc_log(ctx,  "Muscle supports RSA keys only.");
185
0
    return SC_ERROR_NOT_SUPPORTED;
186
0
  }
187
  /* Verification stuff */
188
  /* Used for verification AND for obtaining private key acls */
189
0
  r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
190
0
  if (r < 0 || !prkf)
191
0
      SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED);
192
0
  r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO);
193
0
  if (r < 0) {
194
0
    sc_file_free(prkf);
195
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED);
196
0
  }
197
0
  sc_file_free(prkf);
198
0
  r = muscle_select_key_reference(profile, p15card, key_info);
199
0
  if (r < 0) {
200
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r);
201
0
  }
202
0
  rsa = &key->u.rsa;
203
204
0
  info.keySize = rsa->modulus.len << 3;
205
0
  info.keyType = 0x03; /* CRT type */
206
0
  info.keyLocation = key_info->key_reference * 2; /* Mult by 2 to preserve even/odd keynumber structure */
207
208
0
  info.pLength = rsa->p.len;
209
0
  info.pValue = rsa->p.data;
210
0
  info.qLength = rsa->q.len;
211
0
  info.qValue = rsa->q.data;
212
213
0
  info.pqLength = rsa->iqmp.len;
214
0
  info.pqValue = rsa->iqmp.data;
215
216
0
  info.dp1Length = rsa->dmp1.len;
217
0
  info.dp1Value = rsa->dmp1.data;
218
0
  info.dq1Length = rsa->dmq1.len;
219
0
  info.dq1Value = rsa->dmq1.data;
220
221
0
  r = sc_card_ctl(p15card->card, SC_CARDCTL_MUSCLE_IMPORT_KEY, &info);
222
0
  if (r < 0) {
223
0
    sc_log(ctx,  "Unable to import key");
224
0
    SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r);
225
0
  }
226
0
  return r;
227
0
}
228
229
static int
230
muscle_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
231
      sc_pkcs15_object_t *obj,
232
      sc_pkcs15_pubkey_t *pubkey)
233
0
{
234
0
  sc_cardctl_muscle_gen_key_info_t args;
235
0
  sc_cardctl_muscle_key_info_t extArgs;
236
0
  sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
237
0
  sc_card_t *card = p15card->card;
238
0
  sc_file_t* prkf;
239
0
  size_t  keybits;
240
0
  int   r;
241
242
0
  if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
243
0
    sc_log(card->ctx,  "Muscle supports only RSA keys (for now).");
244
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED);
245
0
  }
246
0
  keybits = key_info->modulus_length & ~7UL;
247
0
  if (keybits > 2048) {
248
0
    sc_log(card->ctx,  "Unable to generate key, max size is %d",
249
0
        2048);
250
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
251
0
  }
252
  /* Verification stuff */
253
  /* Used for verification AND for obtaining private key acls */
254
0
  r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf);
255
0
  if(r < 0 || !prkf)
256
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED);
257
0
  r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO);
258
0
  if (r < 0) {
259
0
    sc_file_free(prkf);
260
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED);
261
0
  }
262
0
  sc_file_free(prkf);
263
264
  /* END VERIFICATION STUFF */
265
266
  /* Public key acls... get_file_by_path as well? */
267
268
0
  memset(&args, 0, sizeof(args));
269
0
  args.keyType = 0x01; /* RSA forced */
270
0
  args.privateKeyLocation = key_info->key_reference * 2;
271
0
  args.publicKeyLocation = key_info->key_reference * 2 + 1;
272
273
0
  args.keySize = keybits;
274
275
0
  r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_GENERATE_KEY, &args);
276
0
  if (r < 0) {
277
0
    sc_log(card->ctx,  "Unable to generate key");
278
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
279
0
  }
280
281
0
  memset(&extArgs, 0, sizeof(extArgs));
282
0
  memset(pubkey, 0, sizeof(*pubkey));
283
284
0
  extArgs.keyType = 0x01;
285
0
  extArgs.keyLocation = args.publicKeyLocation;
286
0
  r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_EXTRACT_KEY, &extArgs);
287
0
  if (r < 0) {
288
0
    sc_log(card->ctx,  "Unable to extract the public key");
289
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
290
0
  }
291
292
0
  pubkey->algorithm = SC_ALGORITHM_RSA;
293
0
  pubkey->u.rsa.modulus.len   = extArgs.modLength;
294
0
  pubkey->u.rsa.modulus.data  = extArgs.modValue;
295
0
  pubkey->u.rsa.exponent.len  = extArgs.expLength;
296
0
  pubkey->u.rsa.exponent.data = extArgs.expValue;
297
298
0
  return r;
299
0
}
300
301
302
static struct sc_pkcs15init_operations sc_pkcs15init_muscle_operations = {
303
  muscle_erase_card,    /* erase card */
304
  muscle_init_card,   /* init_card  */
305
  muscle_create_dir,    /* create_dir */
306
  NULL,       /* create_domain */
307
  muscle_select_pin_reference,  /* select pin reference */
308
  muscle_create_pin,    /* Create PIN */
309
  muscle_select_key_reference,  /* select_key_reference */
310
  muscle_create_key,    /* create_key */
311
  muscle_store_key,   /* store_key */
312
  muscle_generate_key,    /* generate_key */
313
  NULL, NULL,     /* encode private/public key */
314
  NULL,       /* finalize_card */
315
  NULL,         /* delete_object */
316
  NULL, NULL, NULL, NULL, NULL, /* pkcs15init emulation */
317
  NULL        /* sanity_check */
318
};
319
320
struct sc_pkcs15init_operations *
321
sc_pkcs15init_get_muscle_ops(void)
322
0
{
323
0
  return &sc_pkcs15init_muscle_operations;
324
0
}