/src/opensc/src/libopensc/pkcs15-nqApplet.c
Line | Count | Source |
1 | | /* |
2 | | * PKCS15 emulation for JCOP4 Cards with NQ-Applet |
3 | | * |
4 | | * Copyright (C) 2021 jozsefd <jozsef.dojcsak@gmail.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 <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "internal.h" |
25 | | #include "opensc.h" |
26 | | #include "cards.h" |
27 | | #include "common/compat_strlcpy.h" |
28 | | #include "log.h" |
29 | | #include "pkcs15.h" |
30 | | |
31 | | static const char name_Card[] = "NQ-Applet"; |
32 | | static const char name_Vendor[] = "NXP"; |
33 | | |
34 | | static int get_nqapplet_certificate(sc_card_t *card, u8 data_id, struct sc_pkcs15_der *cert_info) |
35 | 79 | { |
36 | 79 | int rv; |
37 | 79 | u8 buffer[3072]; |
38 | 79 | size_t cb_buffer = sizeof(buffer); |
39 | 79 | LOG_FUNC_CALLED(card->ctx); |
40 | | |
41 | 79 | rv = sc_get_data(card, data_id, buffer, cb_buffer); |
42 | 79 | LOG_TEST_RET(card->ctx, rv, "GET DATA failed"); |
43 | 61 | if (rv == 0) { |
44 | 30 | LOG_TEST_RET(card->ctx, SC_ERROR_FILE_NOT_FOUND, "No certificate data returned"); |
45 | 30 | } |
46 | | |
47 | 31 | if (cert_info != NULL) { |
48 | 31 | free(cert_info->value); |
49 | 31 | cert_info->value = malloc(rv); |
50 | 31 | if (cert_info->value != NULL) { |
51 | 31 | cert_info->len = rv; |
52 | 31 | memcpy(cert_info->value, buffer, rv); |
53 | 31 | } |
54 | 31 | } |
55 | 31 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
56 | 31 | } |
57 | | |
58 | | static int add_nqapplet_pin(sc_pkcs15_card_t *p15card, const char *id, u8 reference) |
59 | 53 | { |
60 | 53 | int rv; |
61 | 53 | struct sc_pkcs15_auth_info pin_info; |
62 | 53 | struct sc_pkcs15_object pin_obj; |
63 | 53 | sc_card_t *card = p15card->card; |
64 | | |
65 | 53 | LOG_FUNC_CALLED(card->ctx); |
66 | | |
67 | 53 | memset(&pin_info, 0, sizeof(pin_info)); |
68 | 53 | memset(&pin_obj, 0, sizeof(pin_obj)); |
69 | | |
70 | 53 | sc_pkcs15_format_id(id, &pin_info.auth_id); |
71 | 53 | pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; |
72 | 53 | pin_info.attrs.pin.reference = reference; |
73 | 53 | pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | |
74 | 53 | SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL | SC_PKCS15_PIN_AUTH_TYPE_PIN; |
75 | 53 | pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_UTF8; |
76 | 53 | pin_info.attrs.pin.min_length = 6; |
77 | 53 | pin_info.attrs.pin.stored_length = 6; |
78 | 53 | pin_info.attrs.pin.max_length = 6; |
79 | 53 | pin_info.attrs.pin.pad_char = '\0'; |
80 | 53 | pin_info.tries_left = -1; // TODO |
81 | 53 | pin_info.max_tries = 3; |
82 | | |
83 | 53 | strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label)); |
84 | 53 | pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE; |
85 | | |
86 | 53 | rv = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); |
87 | 53 | LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_pin_obj failed"); |
88 | | |
89 | 53 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
90 | 53 | } |
91 | | |
92 | | static int add_nqapplet_certificate(sc_pkcs15_card_t *p15card, const char *id, const char *name, u8 data_id) |
93 | 79 | { |
94 | 79 | int rv; |
95 | 79 | struct sc_pkcs15_cert_info cert_info; |
96 | 79 | struct sc_pkcs15_object cert_obj; |
97 | 79 | sc_card_t *card = p15card->card; |
98 | | |
99 | 79 | LOG_FUNC_CALLED(card->ctx); |
100 | | |
101 | 79 | memset(&cert_info, 0, sizeof(cert_info)); |
102 | 79 | memset(&cert_obj, 0, sizeof(cert_obj)); |
103 | | |
104 | 79 | sc_pkcs15_format_id(id, &cert_info.id); |
105 | 79 | rv = get_nqapplet_certificate(card, data_id, &cert_info.value); |
106 | 79 | LOG_TEST_RET(card->ctx, rv, "Failed to get certificate"); |
107 | | |
108 | 31 | strlcpy(cert_obj.label, name, sizeof(cert_obj.label)); |
109 | | |
110 | 31 | rv = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info); |
111 | 31 | LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_x509_cert failed"); |
112 | | |
113 | 31 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
114 | 31 | } |
115 | | |
116 | | static int add_nqapplet_private_key(sc_pkcs15_card_t *p15card, const char *id, int reference, |
117 | | const char *name, const char *pin_id, unsigned int usage) |
118 | 31 | { |
119 | 31 | int rv; |
120 | 31 | struct sc_pkcs15_prkey_info prkey_info; |
121 | 31 | struct sc_pkcs15_object prkey_obj; |
122 | 31 | sc_card_t *card = p15card->card; |
123 | | |
124 | 31 | LOG_FUNC_CALLED(card->ctx); |
125 | | |
126 | 31 | memset(&prkey_info, 0, sizeof(prkey_info)); |
127 | 31 | memset(&prkey_obj, 0, sizeof(prkey_obj)); |
128 | | |
129 | 31 | sc_pkcs15_format_id(id, &prkey_info.id); |
130 | 31 | prkey_info.usage = usage; |
131 | 31 | prkey_info.native = 1; |
132 | 31 | prkey_info.key_reference = reference; |
133 | 31 | prkey_info.modulus_length = 3072; |
134 | | |
135 | 31 | strlcpy(prkey_obj.label, name, sizeof(prkey_obj.label)); |
136 | 31 | prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; |
137 | 31 | sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id); |
138 | | |
139 | 31 | rv = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); |
140 | 31 | LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_rsa_prkey failed"); |
141 | | |
142 | 31 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
143 | 31 | } |
144 | | |
145 | | static int add_nqapplet_objects(sc_pkcs15_card_t *p15card) |
146 | 53 | { |
147 | 53 | int rv; |
148 | 53 | sc_card_t *card = p15card->card; |
149 | | |
150 | 53 | LOG_FUNC_CALLED(card->ctx); |
151 | | |
152 | | // 1) User PIN |
153 | 53 | rv = add_nqapplet_pin(p15card, "1", 0x01); |
154 | 53 | LOG_TEST_RET(card->ctx, rv, "Failed to add PIN 1"); |
155 | | |
156 | | // 2.1) C.CH.Auth |
157 | 53 | rv = add_nqapplet_certificate(p15card, "1", "C.CH.Auth", 0x00); |
158 | 53 | LOG_TEST_RET(card->ctx, rv, "Failed to add Auth. certificate"); |
159 | | |
160 | | // 2.2) PrK.CH.Auth |
161 | 26 | rv = add_nqapplet_private_key(p15card, "1", 0x01, "PrK.CH.Auth", "1", |
162 | 26 | SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT); |
163 | 26 | LOG_TEST_RET(card->ctx, rv, "Failed to add Auth. private key"); |
164 | | |
165 | | // 3.1) C.CH.Encr |
166 | 26 | rv = add_nqapplet_certificate(p15card, "2", "C.CH.Encr", 0x01); |
167 | 26 | if (rv == SC_SUCCESS) { |
168 | | // 3.2) PrK.CH.Encr |
169 | 5 | rv = add_nqapplet_private_key(p15card, "2", 0x02, "PrK.CH.Encr", "1", SC_PKCS15_PRKEY_USAGE_DECRYPT); |
170 | 5 | LOG_TEST_RET(card->ctx, rv, "Failed to add Encr. private key"); |
171 | 21 | } else { |
172 | 21 | sc_log(p15card->card->ctx, "The card has no C.CH.Encr, ignoring CH.Encr container"); |
173 | 21 | } |
174 | | |
175 | 26 | LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); |
176 | 26 | } |
177 | | |
178 | | int sc_pkcs15emu_nqapplet_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid) |
179 | 7.07k | { |
180 | 7.07k | int rv = SC_ERROR_WRONG_CARD; |
181 | 7.07k | sc_context_t *ctx; |
182 | 7.07k | sc_card_t *card; |
183 | | |
184 | 7.07k | if (!p15card || !p15card->card || !p15card->card->ctx) { |
185 | 0 | return SC_ERROR_INVALID_ARGUMENTS; |
186 | 0 | } |
187 | | |
188 | 7.07k | card = p15card->card; |
189 | 7.07k | ctx = card->ctx; |
190 | | |
191 | 7.07k | SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); |
192 | | |
193 | 7.07k | if (card->type < SC_CARD_TYPE_NQ_APPLET || card->type > SC_CARD_TYPE_NQ_APPLET_RFID) { |
194 | 7.01k | sc_log(p15card->card->ctx, "Unsupported card type: %d", card->type); |
195 | 7.01k | return SC_ERROR_WRONG_CARD; |
196 | 7.01k | } |
197 | | |
198 | 53 | rv = add_nqapplet_objects(p15card); |
199 | 53 | LOG_TEST_GOTO_ERR(ctx, rv, "Failed to add PKCS15"); |
200 | | |
201 | 26 | if (aid != NULL) { |
202 | 0 | struct sc_file *file = sc_file_new(); |
203 | 0 | if (file != NULL) { |
204 | | /* PKCS11 depends on the file_app object, provide MF */ |
205 | 0 | sc_format_path("3f00", &file->path); |
206 | 0 | sc_file_free(p15card->file_app); |
207 | 0 | p15card->file_app = file; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | 26 | sc_pkcs15_free_tokeninfo(p15card->tokeninfo); |
212 | | |
213 | 26 | p15card->tokeninfo = sc_pkcs15_tokeninfo_new(); |
214 | 26 | if (p15card->tokeninfo == NULL) { |
215 | 0 | rv = SC_ERROR_OUT_OF_MEMORY; |
216 | 0 | LOG_TEST_GOTO_ERR(ctx, rv, "unable to create tokeninfo struct"); |
217 | 26 | } else { |
218 | 26 | char serial_hex[SC_MAX_SERIALNR * 2 + 2]; |
219 | | |
220 | 26 | sc_bin_to_hex(card->serialnr.value, card->serialnr.len, serial_hex, sizeof(serial_hex), 0); |
221 | 26 | set_string(&p15card->tokeninfo->serial_number, serial_hex); |
222 | 26 | set_string(&p15card->tokeninfo->label, name_Card); |
223 | 26 | set_string(&p15card->tokeninfo->manufacturer_id, name_Vendor); |
224 | 26 | p15card->tokeninfo->flags = SC_PKCS15_TOKEN_READONLY; |
225 | 26 | } |
226 | | |
227 | 26 | LOG_FUNC_RETURN(ctx, SC_SUCCESS); |
228 | 27 | err: |
229 | 27 | sc_pkcs15_card_clear(p15card); |
230 | 27 | LOG_FUNC_RETURN(ctx, rv); |
231 | 27 | } |