| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | #include "internal.h" |
|---|
| 22 | #include "cardctl.h" |
|---|
| 23 | #include "muscle.h" |
|---|
| 24 | #include "muscle-filesystem.h" |
|---|
| 25 | #include <opensc/types.h> |
|---|
| 26 | #include <opensc.h> |
|---|
| 27 | |
|---|
| 28 | #include <stdlib.h> |
|---|
| 29 | #include <string.h> |
|---|
| 30 | |
|---|
| 31 | static struct sc_card_operations muscle_ops; |
|---|
| 32 | static struct sc_card_driver muscle_drv = { |
|---|
| 33 | "Muscle Card Driver", |
|---|
| 34 | "muscle", |
|---|
| 35 | &muscle_ops, |
|---|
| 36 | NULL, 0, NULL |
|---|
| 37 | }; |
|---|
| 38 | |
|---|
| 39 | #define MUSCLE_DATA(card) ( (muscle_private_t*)card->drv_data ) |
|---|
| 40 | #define MUSCLE_FS(card) ( ((muscle_private_t*)card->drv_data)->fs ) |
|---|
| 41 | typedef struct muscle_private { |
|---|
| 42 | sc_security_env_t env; |
|---|
| 43 | unsigned short verifiedPins; |
|---|
| 44 | mscfs_t *fs; |
|---|
| 45 | int rsa_key_ref; |
|---|
| 46 | |
|---|
| 47 | } muscle_private_t; |
|---|
| 48 | |
|---|
| 49 | static int muscle_finish(sc_card_t *card) |
|---|
| 50 | { |
|---|
| 51 | muscle_private_t *priv = MUSCLE_DATA(card); |
|---|
| 52 | mscfs_free(priv->fs); |
|---|
| 53 | free(priv); |
|---|
| 54 | return 0; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | |
|---|
| 58 | static u8 muscleAppletId[] = { 0xA0, 0x00,0x00,0x00, 0x01, 0x01 }; |
|---|
| 59 | |
|---|
| 60 | static int muscle_match_card(sc_card_t *card) |
|---|
| 61 | { |
|---|
| 62 | |
|---|
| 63 | int i; |
|---|
| 64 | |
|---|
| 65 | |
|---|
| 66 | card->ops->logout = NULL; |
|---|
| 67 | |
|---|
| 68 | sc_ctx_suppress_errors_on(card->ctx); |
|---|
| 69 | i = msc_select_applet(card, muscleAppletId, 5); |
|---|
| 70 | sc_ctx_suppress_errors_off(card->ctx); |
|---|
| 71 | |
|---|
| 72 | card->drv_data = (void*)0xFFFFFFFF; |
|---|
| 73 | return i; |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | |
|---|
| 81 | static unsigned short muscle_parse_singleAcl(const sc_acl_entry_t* acl) |
|---|
| 82 | { |
|---|
| 83 | unsigned short acl_entry = 0; |
|---|
| 84 | while(acl) { |
|---|
| 85 | int key = acl->key_ref; |
|---|
| 86 | int method = acl->method; |
|---|
| 87 | switch(method) { |
|---|
| 88 | case SC_AC_NEVER: |
|---|
| 89 | return 0xFFFF; |
|---|
| 90 | |
|---|
| 91 | case SC_AC_NONE: |
|---|
| 92 | case SC_AC_UNKNOWN: |
|---|
| 93 | break; |
|---|
| 94 | case SC_AC_CHV: |
|---|
| 95 | acl_entry |= (1 << key); |
|---|
| 96 | break; |
|---|
| 97 | case SC_AC_AUT: |
|---|
| 98 | case SC_AC_TERM: |
|---|
| 99 | case SC_AC_PRO: |
|---|
| 100 | default: |
|---|
| 101 | |
|---|
| 102 | break; |
|---|
| 103 | } |
|---|
| 104 | acl = acl->next; |
|---|
| 105 | } |
|---|
| 106 | return acl_entry; |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | static void muscle_parse_acls(const sc_file_t* file, unsigned short* read_perm, unsigned short* write_perm, unsigned short* delete_perm) |
|---|
| 110 | { |
|---|
| 111 | assert(read_perm && write_perm && delete_perm); |
|---|
| 112 | *read_perm = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_READ)); |
|---|
| 113 | *write_perm = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_UPDATE)); |
|---|
| 114 | *delete_perm = muscle_parse_singleAcl(sc_file_get_acl_entry(file, SC_AC_OP_DELETE)); |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | static int muscle_create_directory(sc_card_t *card, sc_file_t *file) |
|---|
| 118 | { |
|---|
| 119 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 120 | msc_id objectId; |
|---|
| 121 | u8* oid = objectId.id; |
|---|
| 122 | unsigned id = file->id; |
|---|
| 123 | unsigned short read_perm = 0, write_perm = 0, delete_perm = 0; |
|---|
| 124 | int objectSize; |
|---|
| 125 | int r; |
|---|
| 126 | if(id == 0) |
|---|
| 127 | return SC_ERROR_INVALID_ARGUMENTS; |
|---|
| 128 | |
|---|
| 129 | |
|---|
| 130 | if(fs->currentPath[0] != 0x3F || fs->currentPath[1] != 0x00) |
|---|
| 131 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 132 | oid[0] = ((id & 0xFF00) >> 8) & 0xFF; |
|---|
| 133 | oid[1] = id & 0xFF; |
|---|
| 134 | oid[2] = oid[3] = 0; |
|---|
| 135 | |
|---|
| 136 | objectSize = file->size; |
|---|
| 137 | |
|---|
| 138 | muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm); |
|---|
| 139 | r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm); |
|---|
| 140 | mscfs_clear_cache(fs); |
|---|
| 141 | if(r >= 0) return 0; |
|---|
| 142 | return r; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | |
|---|
| 146 | static int muscle_create_file(sc_card_t *card, sc_file_t *file) |
|---|
| 147 | { |
|---|
| 148 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 149 | int objectSize = file->size; |
|---|
| 150 | unsigned short read_perm = 0, write_perm = 0, delete_perm = 0; |
|---|
| 151 | msc_id objectId; |
|---|
| 152 | int r; |
|---|
| 153 | if(file->type == SC_FILE_TYPE_DF) |
|---|
| 154 | return muscle_create_directory(card, file); |
|---|
| 155 | if(file->type != SC_FILE_TYPE_WORKING_EF) |
|---|
| 156 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 157 | if(file->id == 0) |
|---|
| 158 | return SC_ERROR_INVALID_ARGUMENTS; |
|---|
| 159 | |
|---|
| 160 | muscle_parse_acls(file, &read_perm, &write_perm, &delete_perm); |
|---|
| 161 | |
|---|
| 162 | mscfs_lookup_local(fs, file->id, &objectId); |
|---|
| 163 | r = msc_create_object(card, objectId, objectSize, read_perm, write_perm, delete_perm); |
|---|
| 164 | mscfs_clear_cache(fs); |
|---|
| 165 | if(r >= 0) return 0; |
|---|
| 166 | return r; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | static int muscle_read_binary(sc_card_t *card, unsigned int idx, u8* buf, size_t count, unsigned long flags) |
|---|
| 170 | { |
|---|
| 171 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 172 | int r; |
|---|
| 173 | msc_id objectId; |
|---|
| 174 | u8* oid = objectId.id; |
|---|
| 175 | mscfs_file_t *file; |
|---|
| 176 | |
|---|
| 177 | r = mscfs_check_selection(fs, -1); |
|---|
| 178 | if(r < 0) SC_FUNC_RETURN(card->ctx, 0, r); |
|---|
| 179 | file = &fs->cache.array[fs->currentFileIndex]; |
|---|
| 180 | objectId = file->objectId; |
|---|
| 181 | |
|---|
| 182 | if(!file->ef) { |
|---|
| 183 | oid[0] = oid[2]; |
|---|
| 184 | oid[1] = oid[3]; |
|---|
| 185 | oid[2] = oid[3] = 0; |
|---|
| 186 | } |
|---|
| 187 | r = msc_read_object(card, objectId, idx, buf, count); |
|---|
| 188 | SC_FUNC_RETURN(card->ctx, 0, r); |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | static int muscle_update_binary(sc_card_t *card, unsigned int idx, const u8* buf, size_t count, unsigned long flags) |
|---|
| 192 | { |
|---|
| 193 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 194 | int r; |
|---|
| 195 | mscfs_file_t *file; |
|---|
| 196 | msc_id objectId; |
|---|
| 197 | u8* oid = objectId.id; |
|---|
| 198 | |
|---|
| 199 | r = mscfs_check_selection(fs, -1); |
|---|
| 200 | if(r < 0) SC_FUNC_RETURN(card->ctx, 0, r); |
|---|
| 201 | file = &fs->cache.array[fs->currentFileIndex]; |
|---|
| 202 | |
|---|
| 203 | objectId = file->objectId; |
|---|
| 204 | |
|---|
| 205 | if(!file->ef) { |
|---|
| 206 | oid[0] = oid[2]; |
|---|
| 207 | oid[1] = oid[3]; |
|---|
| 208 | oid[2] = oid[3] = 0; |
|---|
| 209 | } |
|---|
| 210 | if(file->size < idx + count) { |
|---|
| 211 | int newFileSize = idx + count; |
|---|
| 212 | u8* buffer = malloc(newFileSize); |
|---|
| 213 | if(buffer == NULL) SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); |
|---|
| 214 | |
|---|
| 215 | r = msc_read_object(card, objectId, 0, buffer, file->size); |
|---|
| 216 | |
|---|
| 217 | if(r < 0) goto update_bin_free_buffer; |
|---|
| 218 | r = msc_delete_object(card, objectId, 0); |
|---|
| 219 | if(r < 0) goto update_bin_free_buffer; |
|---|
| 220 | r = msc_create_object(card, objectId, newFileSize, 0,0,0); |
|---|
| 221 | if(r < 0) goto update_bin_free_buffer; |
|---|
| 222 | memcpy(buffer + idx, buf, count); |
|---|
| 223 | r = msc_update_object(card, objectId, 0, buffer, newFileSize); |
|---|
| 224 | if(r < 0) goto update_bin_free_buffer; |
|---|
| 225 | file->size = newFileSize; |
|---|
| 226 | update_bin_free_buffer: |
|---|
| 227 | free(buffer); |
|---|
| 228 | SC_FUNC_RETURN(card->ctx, 0, r); |
|---|
| 229 | } else { |
|---|
| 230 | r = msc_update_object(card, objectId, idx, buf, count); |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | return r; |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | |
|---|
| 237 | static int muscle_delete_mscfs_file(sc_card_t *card, mscfs_file_t *file_data) |
|---|
| 238 | { |
|---|
| 239 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 240 | msc_id id = file_data->objectId; |
|---|
| 241 | u8* oid = id.id; |
|---|
| 242 | int r; |
|---|
| 243 | |
|---|
| 244 | if(!file_data->ef) { |
|---|
| 245 | int x; |
|---|
| 246 | mscfs_file_t *childFile; |
|---|
| 247 | |
|---|
| 248 | mscfs_check_cache(fs); |
|---|
| 249 | |
|---|
| 250 | if (card->ctx->debug >= 2) { |
|---|
| 251 | sc_debug(card->ctx, "DELETING Children of: %02X%02X%02X%02X\n", |
|---|
| 252 | oid[0],oid[1],oid[2],oid[3]); |
|---|
| 253 | } |
|---|
| 254 | for(x = 0; x < fs->cache.size; x++) { |
|---|
| 255 | msc_id objectId; |
|---|
| 256 | childFile = &fs->cache.array[x]; |
|---|
| 257 | objectId = childFile->objectId; |
|---|
| 258 | |
|---|
| 259 | if(0 == memcmp(oid + 2, objectId.id, 2)) { |
|---|
| 260 | if (card->ctx->debug >= 2) { |
|---|
| 261 | sc_debug(card->ctx, "DELETING: %02X%02X%02X%02X\n", |
|---|
| 262 | objectId.id[0],objectId.id[1],objectId.id[2],objectId.id[3]); |
|---|
| 263 | } |
|---|
| 264 | r = muscle_delete_mscfs_file(card, childFile); |
|---|
| 265 | if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 266 | } |
|---|
| 267 | } |
|---|
| 268 | oid[0] = oid[2]; |
|---|
| 269 | oid[1] = oid[3]; |
|---|
| 270 | oid[2] = oid[3] = 0; |
|---|
| 271 | |
|---|
| 272 | } |
|---|
| 273 | if((0 == memcmp(oid, "\x3F\x00\x00\x00", 4)) |
|---|
| 274 | || (0 == memcmp(oid, "\x3F\x00\x3F\x00", 4))) { |
|---|
| 275 | sc_ctx_suppress_errors_on(card->ctx); |
|---|
| 276 | } |
|---|
| 277 | r = msc_delete_object(card, id, 1); |
|---|
| 278 | |
|---|
| 279 | |
|---|
| 280 | if((0 == memcmp(oid, "\x3F\x00\x00\x00", 4)) |
|---|
| 281 | || (0 == memcmp(oid, "\x3F\x00\x3F\x00", 4))) |
|---|
| 282 | sc_ctx_suppress_errors_off(card->ctx); |
|---|
| 283 | return 0; |
|---|
| 284 | |
|---|
| 285 | if(r < 0) { |
|---|
| 286 | printf("ID: %02X%02X%02X%02X\n", |
|---|
| 287 | oid[0],oid[1],oid[2],oid[3]); |
|---|
| 288 | SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 289 | } |
|---|
| 290 | return 0; |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | static int muscle_delete_file(sc_card_t *card, const sc_path_t *path_in) |
|---|
| 294 | { |
|---|
| 295 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 296 | mscfs_file_t *file_data = NULL; |
|---|
| 297 | int r = 0; |
|---|
| 298 | |
|---|
| 299 | r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, NULL); |
|---|
| 300 | if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 301 | r = muscle_delete_mscfs_file(card, file_data); |
|---|
| 302 | mscfs_clear_cache(fs); |
|---|
| 303 | if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 304 | return 0; |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | static void muscle_load_single_acl(sc_file_t* file, int operation, unsigned short acl) |
|---|
| 308 | { |
|---|
| 309 | int key; |
|---|
| 310 | |
|---|
| 311 | sc_file_add_acl_entry(file, operation, SC_AC_NONE, 0); |
|---|
| 312 | if(acl == 0xFFFF) { |
|---|
| 313 | sc_file_add_acl_entry(file, operation, SC_AC_NEVER, 0); |
|---|
| 314 | return; |
|---|
| 315 | } |
|---|
| 316 | for(key = 0; key < 16; key++) { |
|---|
| 317 | if(acl >> key & 1) { |
|---|
| 318 | sc_file_add_acl_entry(file, operation, SC_AC_CHV, key); |
|---|
| 319 | } |
|---|
| 320 | } |
|---|
| 321 | } |
|---|
| 322 | static void muscle_load_file_acls(sc_file_t* file, mscfs_file_t *file_data) |
|---|
| 323 | { |
|---|
| 324 | muscle_load_single_acl(file, SC_AC_OP_READ, file_data->read); |
|---|
| 325 | muscle_load_single_acl(file, SC_AC_OP_WRITE, file_data->write); |
|---|
| 326 | muscle_load_single_acl(file, SC_AC_OP_UPDATE, file_data->write); |
|---|
| 327 | muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete); |
|---|
| 328 | } |
|---|
| 329 | static void muscle_load_dir_acls(sc_file_t* file, mscfs_file_t *file_data) |
|---|
| 330 | { |
|---|
| 331 | muscle_load_single_acl(file, SC_AC_OP_SELECT, 0); |
|---|
| 332 | muscle_load_single_acl(file, SC_AC_OP_LIST_FILES, 0); |
|---|
| 333 | muscle_load_single_acl(file, SC_AC_OP_LOCK, 0xFFFF); |
|---|
| 334 | muscle_load_single_acl(file, SC_AC_OP_DELETE, file_data->delete); |
|---|
| 335 | muscle_load_single_acl(file, SC_AC_OP_CREATE, file_data->write); |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | static int select_item(sc_card_t *card, const sc_path_t *path_in, sc_file_t ** file_out, int requiredType) |
|---|
| 340 | { |
|---|
| 341 | mscfs_t *fs = MUSCLE_FS(card); |
|---|
| 342 | mscfs_file_t *file_data = NULL; |
|---|
| 343 | const u8 *path = path_in->value; |
|---|
| 344 | int pathlen = path_in->len; |
|---|
| 345 | int r = 0; |
|---|
| 346 | int objectIndex; |
|---|
| 347 | u8* oid; |
|---|
| 348 | |
|---|
| 349 | mscfs_check_cache(fs); |
|---|
| 350 | r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, &objectIndex); |
|---|
| 351 | if(r < 0) SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 352 | |
|---|
| 353 | |
|---|
| 354 | if(requiredType >= 0 && requiredType != file_data->ef) { |
|---|
| 355 | SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_INVALID_ARGUMENTS); |
|---|
| 356 | } |
|---|
| 357 | oid = file_data->objectId.id; |
|---|
| 358 | |
|---|
| 359 | if(file_data->ef) { |
|---|
| 360 | fs->currentPath[0] = oid[0]; |
|---|
| 361 | fs->currentPath[1] = oid[1]; |
|---|
| 362 | fs->currentFile[0] = oid[2]; |
|---|
| 363 | fs->currentFile[1] = oid[3]; |
|---|
| 364 | } else { |
|---|
| 365 | fs->currentPath[0] = oid[pathlen - 2]; |
|---|
| 366 | fs->currentPath[1] = oid[pathlen - 1]; |
|---|
| 367 | fs->currentFile[0] = 0; |
|---|
| 368 | fs->currentFile[1] = 0; |
|---|
| 369 | } |
|---|
| 370 | |
|---|
| 371 | fs->currentFileIndex = objectIndex; |
|---|
| 372 | if(file_out) { |
|---|
| 373 | sc_file_t *file; |
|---|
| 374 | file = sc_file_new(); |
|---|
| 375 | file->path = *path_in; |
|---|
| 376 | file->size = file_data->size; |
|---|
| 377 | file->id = (oid[2] << 8) | oid[3]; |
|---|
| 378 | memcpy(file->name, path, pathlen); |
|---|
| 379 | file->namelen = pathlen; |
|---|
| 380 | if(!file_data->ef) { |
|---|
| 381 | file->type = SC_FILE_TYPE_DF; |
|---|
| 382 | } else { |
|---|
| 383 | file->type = SC_FILE_TYPE_WORKING_EF; |
|---|
| 384 | file->ef_structure = SC_FILE_EF_TRANSPARENT; |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | |
|---|
| 388 | if(file_data->ef) { |
|---|
| 389 | muscle_load_file_acls(file, file_data); |
|---|
| 390 | } else { |
|---|
| 391 | muscle_load_dir_acls(file, file_data); |
|---|
| 392 | |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | file->magic = SC_FILE_MAGIC; |
|---|
| 396 | *file_out = file; |
|---|
| 397 | } |
|---|
| 398 | return 0; |
|---|
| 399 | } |
|---|
| 400 | |
|---|
| 401 | static int muscle_select_file(sc_card_t *card, const sc_path_t *path_in, |
|---|
| 402 | sc_file_t **file_out) |
|---|
| 403 | { |
|---|
| 404 | int r; |
|---|
| 405 | |
|---|
| 406 | assert(card != NULL && path_in != NULL); |
|---|
| 407 | |
|---|
| 408 | switch (path_in->type) { |
|---|
| 409 | case SC_PATH_TYPE_FILE_ID: |
|---|
| 410 | r = select_item(card, path_in, file_out, 1); |
|---|
| 411 | break; |
|---|
| 412 | case SC_PATH_TYPE_DF_NAME: |
|---|
| 413 | r = select_item(card, path_in, file_out, 0); |
|---|
| 414 | break; |
|---|
| 415 | case SC_PATH_TYPE_PATH: |
|---|
| 416 | r = select_item(card, path_in, file_out, -1); |
|---|
| 417 | break; |
|---|
| 418 | default: |
|---|
| 419 | SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS); |
|---|
| 420 | } |
|---|
| 421 | if(r > 0) r = 0; |
|---|
| 422 | SC_FUNC_RETURN(card->ctx, 2,r); |
|---|
| 423 | } |
|---|
| 424 | |
|---|
| 425 | static int _listFile(mscfs_file_t *file, int reset, void *udata) |
|---|
| 426 | { |
|---|
| 427 | int next = reset ? 0x00 : 0x01; |
|---|
| 428 | return msc_list_objects( (sc_card_t*)udata, next, file); |
|---|
| 429 | } |
|---|
| 430 | |
|---|
| 431 | static int muscle_init(sc_card_t *card) |
|---|
| 432 | { |
|---|
| 433 | int r = 0; |
|---|
| 434 | muscle_private_t *priv; |
|---|
| 435 | |
|---|
| 436 | |
|---|
| 437 | |
|---|
| 438 | if(card->drv_data != (void*)0xFFFFFFFF) { |
|---|
| 439 | card->drv_data = NULL; |
|---|
| 440 | if(!muscle_match_card(card)) |
|---|
| 441 | return SC_ERROR_INVALID_CARD; |
|---|
| 442 | } |
|---|
| 443 | |
|---|
| 444 | r = sc_get_default_driver()->ops->init(card); |
|---|
| 445 | if(r) return r; |
|---|
| 446 | |
|---|
| 447 | card->name = "Muscle Card"; |
|---|
| 448 | card->drv_data = malloc(sizeof(muscle_private_t)); |
|---|
| 449 | if(!card->drv_data) { |
|---|
| 450 | SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); |
|---|
| 451 | } |
|---|
| 452 | memset(card->drv_data, 0, sizeof(muscle_private_t)); |
|---|
| 453 | priv = MUSCLE_DATA(card); |
|---|
| 454 | priv->verifiedPins = 0; |
|---|
| 455 | priv->fs = mscfs_new(); |
|---|
| 456 | if(!priv->fs) { |
|---|
| 457 | free(card->drv_data); |
|---|
| 458 | SC_FUNC_RETURN(card->ctx, 0, SC_ERROR_OUT_OF_MEMORY); |
|---|
| 459 | } |
|---|
| 460 | priv->fs->udata = card; |
|---|
| 461 | priv->fs->listFile = _listFile; |
|---|
| 462 | |
|---|
| 463 | card->cla = 0xB0; |
|---|
| 464 | |
|---|
| 465 | card->flags |= SC_CARD_FLAG_ONBOARD_KEY_GEN; |
|---|
| 466 | card->flags |= SC_CARD_FLAG_RNG; |
|---|
| 467 | card->caps |= SC_CARD_CAP_RNG; |
|---|
| 468 | |
|---|
| 469 | if (1) { |
|---|
| 470 | unsigned long flags; |
|---|
| 471 | |
|---|
| 472 | flags = SC_ALGORITHM_RSA_RAW; |
|---|
| 473 | flags |= SC_ALGORITHM_RSA_HASH_NONE; |
|---|
| 474 | flags |= SC_ALGORITHM_ONBOARD_KEY_GEN; |
|---|
| 475 | |
|---|
| 476 | _sc_card_add_rsa_alg(card, 512, flags, 0); |
|---|
| 477 | _sc_card_add_rsa_alg(card, 768, flags, 0); |
|---|
| 478 | _sc_card_add_rsa_alg(card, 1024, flags, 0); |
|---|
| 479 | _sc_card_add_rsa_alg(card, 2048, flags, 0); |
|---|
| 480 | } |
|---|
| 481 | card->max_recv_size = 1024 * 64; |
|---|
| 482 | card->max_send_size = 1024 * 64; |
|---|
| 483 | return 0; |
|---|
| 484 | } |
|---|
| 485 | |
|---|
| 486 | static int muscle_list_files(sc_card_t *card, u8 *buf, size_t bufLen) |
|---|
| 487 | { |
|---|
| 488 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 489 | mscfs_t *fs = priv->fs; |
|---|
| 490 | int x; |
|---|
| 491 | int count = 0; |
|---|
| 492 | |
|---|
| 493 | mscfs_check_cache(priv->fs); |
|---|
| 494 | |
|---|
| 495 | for(x = 0; x < fs->cache.size; x++) { |
|---|
| 496 | u8* oid= fs->cache.array[x].objectId.id; |
|---|
| 497 | if (card->ctx->debug >= 2) { |
|---|
| 498 | sc_debug(card->ctx, "FILE: %02X%02X%02X%02X\n", |
|---|
| 499 | oid[0],oid[1],oid[2],oid[3]); |
|---|
| 500 | } |
|---|
| 501 | if(0 == memcmp(fs->currentPath, oid, 2)) { |
|---|
| 502 | buf[0] = oid[2]; |
|---|
| 503 | buf[1] = oid[3]; |
|---|
| 504 | if(buf[0] == 0x00 && buf[1] == 0x00) continue; |
|---|
| 505 | buf += 2; |
|---|
| 506 | count+=2; |
|---|
| 507 | } |
|---|
| 508 | } |
|---|
| 509 | return count; |
|---|
| 510 | } |
|---|
| 511 | |
|---|
| 512 | static int (*iso_pin_cmd)(struct sc_card *, struct sc_pin_cmd_data *, |
|---|
| 513 | int *tries_left); |
|---|
| 514 | |
|---|
| 515 | static int muscle_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *cmd, |
|---|
| 516 | int *tries_left) |
|---|
| 517 | { |
|---|
| 518 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 519 | const int bufferLength = MSC_MAX_PIN_COMMAND_LENGTH; |
|---|
| 520 | u8 buffer[MSC_MAX_PIN_COMMAND_LENGTH]; |
|---|
| 521 | switch(cmd->cmd) { |
|---|
| 522 | case SC_PIN_CMD_VERIFY: |
|---|
| 523 | switch(cmd->pin_type) { |
|---|
| 524 | case SC_AC_CHV: { |
|---|
| 525 | sc_apdu_t apdu; |
|---|
| 526 | int r; |
|---|
| 527 | msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len); |
|---|
| 528 | cmd->apdu = &apdu; |
|---|
| 529 | cmd->pin1.offset = 5; |
|---|
| 530 | r = iso_pin_cmd(card, cmd, tries_left); |
|---|
| 531 | if(r >= 0) |
|---|
| 532 | priv->verifiedPins |= (1 << cmd->pin_reference); |
|---|
| 533 | return r; |
|---|
| 534 | } |
|---|
| 535 | case SC_AC_TERM: |
|---|
| 536 | case SC_AC_PRO: |
|---|
| 537 | case SC_AC_AUT: |
|---|
| 538 | case SC_AC_NONE: |
|---|
| 539 | default: |
|---|
| 540 | sc_error(card->ctx, "Unsupported authentication method\n"); |
|---|
| 541 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 542 | } |
|---|
| 543 | case SC_PIN_CMD_CHANGE: |
|---|
| 544 | switch(cmd->pin_type) { |
|---|
| 545 | case SC_AC_CHV: { |
|---|
| 546 | sc_apdu_t apdu; |
|---|
| 547 | msc_change_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len, cmd->pin2.data, cmd->pin2.len); |
|---|
| 548 | cmd->apdu = &apdu; |
|---|
| 549 | return iso_pin_cmd(card, cmd, tries_left); |
|---|
| 550 | } |
|---|
| 551 | case SC_AC_TERM: |
|---|
| 552 | case SC_AC_PRO: |
|---|
| 553 | case SC_AC_AUT: |
|---|
| 554 | case SC_AC_NONE: |
|---|
| 555 | default: |
|---|
| 556 | sc_error(card->ctx, "Unsupported authentication method\n"); |
|---|
| 557 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 558 | } |
|---|
| 559 | case SC_PIN_CMD_UNBLOCK: |
|---|
| 560 | switch(cmd->pin_type) { |
|---|
| 561 | case SC_AC_CHV: { |
|---|
| 562 | sc_apdu_t apdu; |
|---|
| 563 | msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len); |
|---|
| 564 | cmd->apdu = &apdu; |
|---|
| 565 | return iso_pin_cmd(card, cmd, tries_left); |
|---|
| 566 | } |
|---|
| 567 | case SC_AC_TERM: |
|---|
| 568 | case SC_AC_PRO: |
|---|
| 569 | case SC_AC_AUT: |
|---|
| 570 | case SC_AC_NONE: |
|---|
| 571 | default: |
|---|
| 572 | sc_error(card->ctx, "Unsupported authentication method\n"); |
|---|
| 573 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 574 | } |
|---|
| 575 | default: |
|---|
| 576 | sc_error(card->ctx, "Unsupported command\n"); |
|---|
| 577 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 578 | |
|---|
| 579 | } |
|---|
| 580 | |
|---|
| 581 | } |
|---|
| 582 | |
|---|
| 583 | static int muscle_card_extract_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info) |
|---|
| 584 | { |
|---|
| 585 | |
|---|
| 586 | switch(info->keyType) { |
|---|
| 587 | case 1: |
|---|
| 588 | return msc_extract_rsa_public_key(card, |
|---|
| 589 | info->keyLocation, |
|---|
| 590 | &info->modLength, |
|---|
| 591 | &info->modValue, |
|---|
| 592 | &info->expLength, |
|---|
| 593 | &info->expValue); |
|---|
| 594 | default: |
|---|
| 595 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 596 | } |
|---|
| 597 | } |
|---|
| 598 | |
|---|
| 599 | static int muscle_card_import_key(sc_card_t *card, sc_cardctl_muscle_key_info_t *info) |
|---|
| 600 | { |
|---|
| 601 | |
|---|
| 602 | switch(info->keyType) { |
|---|
| 603 | case 0x02: |
|---|
| 604 | case 0x03: |
|---|
| 605 | return msc_import_key(card, |
|---|
| 606 | info->keyLocation, |
|---|
| 607 | info); |
|---|
| 608 | default: |
|---|
| 609 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 610 | } |
|---|
| 611 | } |
|---|
| 612 | |
|---|
| 613 | static int muscle_card_generate_key(sc_card_t *card, sc_cardctl_muscle_gen_key_info_t *info) |
|---|
| 614 | { |
|---|
| 615 | return msc_generate_keypair(card, |
|---|
| 616 | info->privateKeyLocation, |
|---|
| 617 | info->publicKeyLocation, |
|---|
| 618 | info->keyType, |
|---|
| 619 | info->keySize, |
|---|
| 620 | 0); |
|---|
| 621 | } |
|---|
| 622 | |
|---|
| 623 | static int muscle_card_verified_pins(sc_card_t *card, sc_cardctl_muscle_verified_pins_info_t *info) |
|---|
| 624 | { |
|---|
| 625 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 626 | info->verifiedPins = priv->verifiedPins; |
|---|
| 627 | return 0; |
|---|
| 628 | } |
|---|
| 629 | static int muscle_card_ctl(sc_card_t *card, unsigned long request, void *data) |
|---|
| 630 | { |
|---|
| 631 | switch(request) { |
|---|
| 632 | case SC_CARDCTL_MUSCLE_GENERATE_KEY: |
|---|
| 633 | return muscle_card_generate_key(card, (sc_cardctl_muscle_gen_key_info_t*) data); |
|---|
| 634 | case SC_CARDCTL_MUSCLE_EXTRACT_KEY: |
|---|
| 635 | return muscle_card_extract_key(card, (sc_cardctl_muscle_key_info_t*) data); |
|---|
| 636 | case SC_CARDCTL_MUSCLE_IMPORT_KEY: |
|---|
| 637 | return muscle_card_import_key(card, (sc_cardctl_muscle_key_info_t*) data); |
|---|
| 638 | case SC_CARDCTL_MUSCLE_VERIFIED_PINS: |
|---|
| 639 | return muscle_card_verified_pins(card, (sc_cardctl_muscle_verified_pins_info_t*) data); |
|---|
| 640 | default: |
|---|
| 641 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 642 | } |
|---|
| 643 | } |
|---|
| 644 | |
|---|
| 645 | static int muscle_set_security_env(sc_card_t *card, |
|---|
| 646 | const sc_security_env_t *env, |
|---|
| 647 | int se_num) |
|---|
| 648 | { |
|---|
| 649 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 650 | |
|---|
| 651 | if (env->operation != SC_SEC_OPERATION_SIGN && |
|---|
| 652 | env->operation != SC_SEC_OPERATION_DECIPHER) { |
|---|
| 653 | sc_error(card->ctx, "Invalid crypto operation supplied.\n"); |
|---|
| 654 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 655 | } |
|---|
| 656 | if (env->algorithm != SC_ALGORITHM_RSA) { |
|---|
| 657 | sc_error(card->ctx, "Invalid crypto algorithm supplied.\n"); |
|---|
| 658 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 659 | } |
|---|
| 660 | |
|---|
| 661 | if ((env->algorithm_flags & SC_ALGORITHM_RSA_PADS) || |
|---|
| 662 | (env->algorithm_flags & SC_ALGORITHM_RSA_HASHES)) { |
|---|
| 663 | sc_error(card->ctx, "Card supports only raw RSA.\n"); |
|---|
| 664 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 665 | } |
|---|
| 666 | if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) { |
|---|
| 667 | if (env->key_ref_len != 1 || |
|---|
| 668 | (env->key_ref[0] > 0x0F)) { |
|---|
| 669 | sc_error(card->ctx, "Invalid key reference supplied.\n"); |
|---|
| 670 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 671 | } |
|---|
| 672 | priv->rsa_key_ref = env->key_ref[0]; |
|---|
| 673 | } |
|---|
| 674 | if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) { |
|---|
| 675 | sc_error(card->ctx, "Algorithm reference not supported.\n"); |
|---|
| 676 | return SC_ERROR_NOT_SUPPORTED; |
|---|
| 677 | } |
|---|
| 678 | |
|---|
| 679 | |
|---|
| 680 | |
|---|
| 681 | |
|---|
| 682 | |
|---|
| 683 | priv->env = *env; |
|---|
| 684 | return 0; |
|---|
| 685 | } |
|---|
| 686 | |
|---|
| 687 | static int muscle_restore_security_env(sc_card_t *card, int se_num) |
|---|
| 688 | { |
|---|
| 689 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 690 | memset(&priv->env, 0, sizeof(priv->env)); |
|---|
| 691 | return 0; |
|---|
| 692 | } |
|---|
| 693 | |
|---|
| 694 | |
|---|
| 695 | static int muscle_decipher(sc_card_t * card, |
|---|
| 696 | const u8 * crgram, size_t crgram_len, u8 * out, |
|---|
| 697 | size_t out_len) |
|---|
| 698 | { |
|---|
| 699 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 700 | |
|---|
| 701 | u8 key_id; |
|---|
| 702 | int r; |
|---|
| 703 | |
|---|
| 704 | |
|---|
| 705 | if (priv->env.operation != SC_SEC_OPERATION_DECIPHER) |
|---|
| 706 | return SC_ERROR_INVALID_ARGUMENTS; |
|---|
| 707 | |
|---|
| 708 | key_id = priv->rsa_key_ref * 2; |
|---|
| 709 | |
|---|
| 710 | if (out_len < crgram_len) { |
|---|
| 711 | sc_error(card->ctx, "Output buffer too small"); |
|---|
| 712 | return SC_ERROR_BUFFER_TOO_SMALL; |
|---|
| 713 | } |
|---|
| 714 | |
|---|
| 715 | r = msc_compute_crypt(card, |
|---|
| 716 | key_id, |
|---|
| 717 | 0x00, |
|---|
| 718 | 0x04, |
|---|
| 719 | crgram, |
|---|
| 720 | out, |
|---|
| 721 | crgram_len, |
|---|
| 722 | out_len); |
|---|
| 723 | SC_TEST_RET(card->ctx, r, "Card signature failed"); |
|---|
| 724 | return r; |
|---|
| 725 | } |
|---|
| 726 | |
|---|
| 727 | static int muscle_compute_signature(sc_card_t *card, const u8 *data, |
|---|
| 728 | size_t data_len, u8 * out, size_t outlen) |
|---|
| 729 | { |
|---|
| 730 | muscle_private_t* priv = MUSCLE_DATA(card); |
|---|
| 731 | u8 key_id; |
|---|
| 732 | int r; |
|---|
| 733 | |
|---|
| 734 | key_id = priv->rsa_key_ref * 2; |
|---|
| 735 | |
|---|
| 736 | if (outlen < data_len) { |
|---|
| 737 | sc_error(card->ctx, "Output buffer too small"); |
|---|
| 738 | return SC_ERROR_BUFFER_TOO_SMALL; |
|---|
| 739 | } |
|---|
| 740 | |
|---|
| 741 | r = msc_compute_crypt(card, |
|---|
| 742 | key_id, |
|---|
| 743 | 0x00, |
|---|
| 744 | 0x04, |
|---|
| 745 | data, |
|---|
| 746 | out, |
|---|
| 747 | data_len, |
|---|
| 748 | outlen); |
|---|
| 749 | SC_TEST_RET(card->ctx, r, "Card signature failed"); |
|---|
| 750 | return r; |
|---|
| 751 | } |
|---|
| 752 | |
|---|
| 753 | static int muscle_get_challenge(sc_card_t *card, u8 *rnd, size_t len) |
|---|
| 754 | { |
|---|
| 755 | return msc_get_challenge(card, len, 0, NULL, rnd); |
|---|
| 756 | } |
|---|
| 757 | |
|---|
| 758 | |
|---|
| 759 | static struct sc_card_driver * sc_get_driver(void) |
|---|
| 760 | { |
|---|
| 761 | struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); |
|---|
| 762 | |
|---|
| 763 | muscle_ops = *iso_drv->ops; |
|---|
| 764 | iso_pin_cmd = iso_drv->ops->pin_cmd; |
|---|
| 765 | muscle_ops.check_sw = iso_drv->ops->check_sw; |
|---|
| 766 | muscle_ops.pin_cmd = muscle_pin_cmd; |
|---|
| 767 | muscle_ops.get_response = iso_drv->ops->get_response; |
|---|
| 768 | muscle_ops.match_card = muscle_match_card; |
|---|
| 769 | muscle_ops.init = muscle_init; |
|---|
| 770 | muscle_ops.finish = muscle_finish; |
|---|
| 771 | |
|---|
| 772 | muscle_ops.get_challenge = muscle_get_challenge; |
|---|
| 773 | |
|---|
| 774 | muscle_ops.set_security_env = muscle_set_security_env; |
|---|
| 775 | muscle_ops.restore_security_env = muscle_restore_security_env; |
|---|
| 776 | muscle_ops.compute_signature = muscle_compute_signature; |
|---|
| 777 | muscle_ops.decipher = muscle_decipher; |
|---|
| 778 | muscle_ops.card_ctl = muscle_card_ctl; |
|---|
| 779 | muscle_ops.read_binary = muscle_read_binary; |
|---|
| 780 | muscle_ops.update_binary = muscle_update_binary; |
|---|
| 781 | muscle_ops.create_file = muscle_create_file; |
|---|
| 782 | muscle_ops.select_file = muscle_select_file; |
|---|
| 783 | muscle_ops.delete_file = muscle_delete_file; |
|---|
| 784 | muscle_ops.list_files = muscle_list_files; |
|---|
| 785 | |
|---|
| 786 | return &muscle_drv; |
|---|
| 787 | } |
|---|
| 788 | |
|---|
| 789 | #if 1 |
|---|
| 790 | struct sc_card_driver * sc_get_muscle_driver(void) |
|---|
| 791 | { |
|---|
| 792 | return sc_get_driver(); |
|---|
| 793 | } |
|---|
| 794 | #endif |
|---|