/src/opensc/src/libopensc/pkcs15-eoi.c
Line | Count | Source |
1 | | /* |
2 | | * Support for the eOI card. |
3 | | * |
4 | | * Copyright (C) 2022 Luka Logar <luka.logar@iname.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 <string.h> |
22 | | |
23 | | #ifdef HAVE_CONFIG_H |
24 | | #include "config.h" |
25 | | #endif |
26 | | #include "log.h" |
27 | | #include "pkcs15.h" |
28 | | |
29 | | #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE) |
30 | | |
31 | | #include "cards.h" |
32 | | #include "card-eoi.h" |
33 | | |
34 | | int sc_pkcs15emu_eoi_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid) |
35 | 7.29k | { |
36 | 7.29k | struct sc_card *card = p15card->card; |
37 | 7.29k | struct eoi_privdata *privdata = (struct eoi_privdata *)card->drv_data; |
38 | 7.29k | struct sc_pkcs15_search_key sk; |
39 | 7.29k | struct sc_pkcs15_object *objs[MAX_OBJECTS]; |
40 | 7.29k | int i, j, len; |
41 | | |
42 | 7.29k | LOG_FUNC_CALLED(card->ctx); |
43 | | |
44 | 7.29k | if (card->type != SC_CARD_TYPE_EOI && card->type != SC_CARD_TYPE_EOI_CONTACTLESS) |
45 | 7.29k | LOG_FUNC_RETURN(card->ctx, SC_ERROR_WRONG_CARD); |
46 | | |
47 | 0 | if (!privdata) |
48 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); |
49 | | |
50 | | /* |
51 | | * Some of the data is not accessible over the unencrypted channel |
52 | | * when contactless reader is used. So start SM now (if not yet establisahed). |
53 | | */ |
54 | 0 | if (card->type == SC_CARD_TYPE_EOI_CONTACTLESS && card->sm_ctx.sm_mode == SM_MODE_NONE) { |
55 | 0 | int r = card->sm_ctx.ops.open(card); |
56 | 0 | if (r != SC_SUCCESS) |
57 | 0 | LOG_FUNC_RETURN(card->ctx, r); |
58 | 0 | } |
59 | | |
60 | | /* |
61 | | * Get the card objects, so we can manipulate them. See below |
62 | | */ |
63 | 0 | LOG_TEST_RET(card->ctx, sc_pkcs15_bind_internal(p15card, aid), |
64 | 0 | "sc_pkcs15_bind_internal failed"); |
65 | | |
66 | | /* |
67 | | * PIN objects: |
68 | | * 1) Find the "Card CAN" PIN and store it's path, so we'll be able to fetch the CAN and do the PACE auth |
69 | | * 2) Add PIN's auth_info->path to the list of paths that can fail on select. sc_pin_cmd would break otherwise |
70 | | */ |
71 | 0 | memset(&sk, 0, sizeof(sk)); |
72 | 0 | sk.class_mask = SC_PKCS15_SEARCH_CLASS_AUTH; |
73 | 0 | len = sc_pkcs15_search_objects(p15card, &sk, (struct sc_pkcs15_object **)&objs, MAX_OBJECTS); |
74 | 0 | for (i = 0, j = 0; i < len; i++) { |
75 | 0 | struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)objs[i]->data; |
76 | 0 | if (auth_info && auth_info->auth_id.len == 8 && !strcmp((char*)auth_info->auth_id.value, "Card CAN")) { |
77 | 0 | auth_info->path.type = SC_PATH_TYPE_PATH; |
78 | | /* Read the file that contains serial and encrypted CAN */ |
79 | 0 | if (sc_pkcs15_read_file(p15card, &auth_info->path, &privdata->enc_can.value, &privdata->enc_can.len, 0) == SC_SUCCESS) { |
80 | | /* File should be 24 bytes long */ |
81 | 0 | if (privdata->enc_can.len != 24) |
82 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA); |
83 | 0 | if (strlen(p15card->tokeninfo->serial_number) != 20) |
84 | 0 | LOG_FUNC_RETURN(card->ctx, SC_ERROR_CORRUPTED_DATA); |
85 | | /* First 8 bytes are used as serial number */ |
86 | 0 | sc_bin_to_hex(privdata->enc_can.value, 8, &p15card->tokeninfo->serial_number[4], 17, 0); |
87 | 0 | } |
88 | | /* Do not add "Card CAN" to the list of PIN paths to ignore, otherwise the 2nd PKCS#15 app can not access it */ |
89 | 0 | auth_info = NULL; |
90 | | /* Mark "Card CAN" as NOT a PIN object, so that it doesn't get it's own PKCS#11 slot */ |
91 | 0 | objs[i]->type &= ~SC_PKCS15_TYPE_AUTH_PIN; |
92 | 0 | } |
93 | | /* |
94 | | * For some reason QES app has "Norm PUK" not flagged as unblocking PIN and thus "Norm PUK" appears as a slot in |
95 | | * PKCS#11. Flag it as unblockingPin, so it doesn't appear as a separate slot. |
96 | | */ |
97 | 0 | if (auth_info && auth_info->auth_id.len == 8 && !strcmp((char*)auth_info->auth_id.value, "Norm PUK")) { |
98 | 0 | auth_info->attrs.pin.flags |= SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN; |
99 | 0 | } |
100 | 0 | if (auth_info) { |
101 | 0 | privdata->pin_paths[j++] = &auth_info->path; |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | | /* |
106 | | * Private key objects: |
107 | | * 1) Rename "Card PIN" to "Norm PIN" as it's the later name that is used throughout the PKCS#15 objects |
108 | | * 2) Add the key references to the prkey_mappings array, as it seems that eOI expects them counted from 0xA0 up (starting from 1 within each app) |
109 | | * Currently there are 3 private keys on the card |
110 | | * key_ref |
111 | | * 2 - for pinless entry (Prijava brez PIN-a), maps to 0xA1 |
112 | | * 1 - for authentication in QES app (Podpis in prijava), maps to 0xA1 |
113 | | * 3 - for signing in QES app (Podpis in prijava), maps to 0xA2 |
114 | | */ |
115 | 0 | memset(&sk, 0, sizeof(sk)); |
116 | 0 | sk.class_mask = SC_PKCS15_SEARCH_CLASS_PRKEY; |
117 | 0 | len = sc_pkcs15_search_objects(p15card, &sk, (struct sc_pkcs15_object **)&objs, MAX_OBJECTS); |
118 | | /* |
119 | | * If both PKCS#15 apps are enabled, prkey_mappings can already be partially filled up from the first PKCS#15 app |
120 | | * as the privdata is shared between both apps which use the same driver |
121 | | */ |
122 | 0 | for (j = 0; privdata->prkey_mappings[j][1] != 0; j++) { |
123 | | /* NOP */ |
124 | 0 | } |
125 | 0 | for (i = 0; i < len; i++) { |
126 | 0 | struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *)objs[i]->data; |
127 | 0 | if ((objs[i]->auth_id.len == 8) && !strncmp((char*)objs[i]->auth_id.value, "Card PIN", 8)) { |
128 | 0 | memcpy(objs[i]->auth_id.value, "Norm PIN", 8); |
129 | 0 | } |
130 | 0 | if (prkey_info) { |
131 | 0 | privdata->prkey_mappings[j][0] = prkey_info->key_reference; |
132 | 0 | privdata->prkey_mappings[j++][1] = 0xA0 + (i + 1); |
133 | 0 | } |
134 | 0 | } |
135 | |
|
136 | 0 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
137 | 0 | } |
138 | | |
139 | | #else |
140 | | |
141 | | int sc_pkcs15emu_eoi_init_ex(struct sc_pkcs15_card *p15card, struct sc_aid *aid) |
142 | | { |
143 | | LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_WRONG_CARD); |
144 | | } |
145 | | |
146 | | #endif |