Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * 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 program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "pkcs11/pkcs11.h"
24 :
25 : #include "gkm-attributes.h"
26 : #define DEBUG_FLAG GKM_DEBUG_OBJECT
27 : #include "gkm-debug.h"
28 : #include "gkm-factory.h"
29 : #include "gkm-public-xsa-key.h"
30 : #include "gkm-data-der.h"
31 : #include "gkm-session.h"
32 : #include "gkm-sexp.h"
33 : #include "gkm-transaction.h"
34 : #include "gkm-util.h"
35 :
36 75 : G_DEFINE_TYPE (GkmPublicXsaKey, gkm_public_xsa_key, GKM_TYPE_SEXP_KEY);
37 :
38 : /* -----------------------------------------------------------------------------
39 : * INTERNAL
40 : */
41 :
42 : static CK_RV
43 0 : return_modulus_bits (GkmPublicXsaKey *self, CK_ATTRIBUTE_PTR attr)
44 : {
45 : gcry_sexp_t numbers;
46 : gcry_mpi_t mpi;
47 : int algorithm;
48 : CK_RV rv;
49 :
50 0 : if (!gkm_sexp_parse_key (gkm_sexp_get (gkm_sexp_key_get_base (GKM_SEXP_KEY (self))),
51 : &algorithm, NULL, &numbers))
52 0 : g_return_val_if_reached (CKR_GENERAL_ERROR);
53 :
54 0 : if (algorithm != GCRY_PK_RSA) {
55 0 : gcry_sexp_release (numbers);
56 0 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: CKA_MODULUS_BITS not valid for non-RSA keys");
57 0 : return CKR_ATTRIBUTE_TYPE_INVALID;
58 : }
59 :
60 0 : g_assert (numbers);
61 0 : if (!gkm_sexp_extract_mpi (numbers, &mpi, "n", NULL))
62 0 : g_return_val_if_reached (CKR_GENERAL_ERROR);
63 :
64 0 : gcry_sexp_release (numbers);
65 0 : rv = gkm_attribute_set_ulong (attr, gcry_mpi_get_nbits (mpi));
66 0 : gcry_mpi_release (mpi);
67 :
68 0 : return rv;
69 : }
70 :
71 : static CK_RV
72 1 : create_rsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
73 : {
74 : gcry_error_t gcry;
75 1 : gcry_mpi_t n = NULL;
76 1 : gcry_mpi_t e = NULL;
77 : CK_RV ret;
78 :
79 2 : if (!gkm_attributes_find_mpi (attrs, n_attrs, CKA_MODULUS, &n) ||
80 1 : !gkm_attributes_find_mpi (attrs, n_attrs, CKA_PUBLIC_EXPONENT, &e)) {
81 0 : ret = CKR_TEMPLATE_INCOMPLETE;
82 0 : goto done;
83 : }
84 :
85 1 : gcry = gcry_sexp_build (skey, NULL,
86 : "(public-key (rsa (n %m) (e %m)))",
87 : n, e);
88 :
89 1 : if (gcry != 0) {
90 0 : g_message ("couldn't create RSA key from passed attributes: %s", gcry_strerror (gcry));
91 0 : ret = CKR_FUNCTION_FAILED;
92 0 : goto done;
93 : }
94 :
95 1 : gkm_attributes_consume (attrs, n_attrs, CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_MODULUS_BITS, G_MAXULONG);
96 1 : ret = CKR_OK;
97 :
98 1 : done:
99 1 : gcry_mpi_release (n);
100 1 : gcry_mpi_release (e);
101 1 : return ret;
102 : }
103 :
104 : static CK_RV
105 0 : create_dsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
106 : {
107 : gcry_error_t gcry;
108 0 : gcry_mpi_t p = NULL;
109 0 : gcry_mpi_t q = NULL;
110 0 : gcry_mpi_t g = NULL;
111 0 : gcry_mpi_t y = NULL;
112 : CK_RV ret;
113 :
114 0 : if (!gkm_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &p) ||
115 0 : !gkm_attributes_find_mpi (attrs, n_attrs, CKA_SUBPRIME, &q) ||
116 0 : !gkm_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &g) ||
117 0 : !gkm_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &y)) {
118 0 : ret = CKR_TEMPLATE_INCOMPLETE;
119 0 : goto done;
120 : }
121 :
122 0 : gcry = gcry_sexp_build (skey, NULL,
123 : "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))",
124 : p, q, g, y);
125 :
126 0 : if (gcry != 0) {
127 0 : g_message ("couldn't create DSA key from passed attributes: %s", gcry_strerror (gcry));
128 0 : ret = CKR_FUNCTION_FAILED;
129 0 : goto done;
130 : }
131 :
132 0 : gkm_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_SUBPRIME,
133 : CKA_BASE, CKA_VALUE, G_MAXULONG);
134 0 : ret = CKR_OK;
135 :
136 0 : done:
137 0 : gcry_mpi_release (p);
138 0 : gcry_mpi_release (q);
139 0 : gcry_mpi_release (g);
140 0 : gcry_mpi_release (y);
141 0 : return ret;
142 : }
143 :
144 : static CK_RV
145 1 : create_ecdsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
146 : {
147 : gcry_error_t gcry;
148 : const gchar *curve_name, *q_data;
149 1 : GBytes *q = NULL;
150 : gsize q_size;
151 : GQuark oid;
152 : CK_RV ret;
153 :
154 2 : if (!gkm_attributes_find_ecc_oid (attrs, n_attrs, &oid) ||
155 1 : !gkm_attributes_find_ecc_q (attrs, n_attrs, CKA_EC_POINT, &q)) {
156 0 : ret = CKR_TEMPLATE_INCOMPLETE;
157 0 : goto done;
158 : }
159 :
160 1 : curve_name = gkm_data_der_oid_to_curve (oid);
161 1 : if (curve_name == NULL) {
162 0 : ret = CKR_FUNCTION_FAILED;
163 0 : goto done;
164 : }
165 :
166 1 : q_data = g_bytes_get_data (q, &q_size);
167 :
168 1 : gcry = gcry_sexp_build (skey, NULL,
169 : "(public-key (ecdsa (curve %s) (q %b)))",
170 : curve_name, q_size, q_data);
171 :
172 1 : if (gcry != 0) {
173 0 : g_message ("couldn't create ECDSA key from passed attributes: %s", gcry_strerror (gcry));
174 0 : ret = CKR_FUNCTION_FAILED;
175 0 : goto done;
176 : }
177 :
178 1 : gkm_attributes_consume (attrs, n_attrs, CKA_EC_POINT, CKA_EC_PARAMS,
179 : G_MAXULONG);
180 1 : ret = CKR_OK;
181 :
182 1 : done:
183 1 : g_bytes_unref (q);
184 1 : return ret;
185 : }
186 :
187 : static GkmObject*
188 0 : factory_create_public_xsa_key (GkmSession *session, GkmTransaction *transaction,
189 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
190 : {
191 0 : GkmObject *object = NULL;
192 : GkmSexp *sexp;
193 :
194 0 : g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
195 0 : g_return_val_if_fail (attrs || !n_attrs, NULL);
196 :
197 0 : sexp = gkm_public_xsa_key_create_sexp (session, transaction, attrs, n_attrs);
198 0 : if (sexp != NULL) {
199 0 : object = g_object_new (GKM_TYPE_PUBLIC_XSA_KEY, "base-sexp", sexp,
200 : "module", gkm_session_get_module (session),
201 : "manager", gkm_manager_for_template (attrs, n_attrs, session),
202 : NULL);
203 0 : gkm_sexp_unref (sexp);
204 0 : gkm_session_complete_object_creation (session, transaction, object,
205 : TRUE, attrs, n_attrs);
206 : }
207 :
208 0 : return object;
209 : }
210 :
211 : /* -----------------------------------------------------------------------------
212 : * PUBLIC_XSA_KEY
213 : */
214 :
215 : static CK_RV
216 54 : gkm_public_xsa_key_real_get_attribute (GkmObject *base, GkmSession *session, CK_ATTRIBUTE* attr)
217 : {
218 54 : GkmPublicXsaKey *self = GKM_PUBLIC_XSA_KEY (base);
219 : gint algorithm;
220 :
221 54 : switch (attr->type)
222 : {
223 :
224 0 : case CKA_CLASS:
225 0 : return gkm_attribute_set_ulong (attr, CKO_PUBLIC_KEY);
226 :
227 0 : case CKA_ENCRYPT:
228 0 : algorithm = gkm_sexp_key_get_algorithm (GKM_SEXP_KEY (self));
229 0 : return gkm_attribute_set_bool (attr, algorithm == GCRY_PK_RSA);
230 :
231 0 : case CKA_VERIFY:
232 0 : return gkm_attribute_set_bool (attr, TRUE);
233 :
234 0 : case CKA_VERIFY_RECOVER:
235 0 : return gkm_attribute_set_bool (attr, FALSE);
236 :
237 0 : case CKA_WRAP:
238 0 : return gkm_attribute_set_bool (attr, FALSE);
239 :
240 0 : case CKA_TRUSTED:
241 0 : return gkm_attribute_set_bool (attr, FALSE);
242 :
243 0 : case CKA_WRAP_TEMPLATE:
244 0 : gkm_debug ("CKR_ATTRIBUTE_TYPE_INVALID: no CKA_WRAP_TEMPLATE on key");
245 0 : return CKR_ATTRIBUTE_TYPE_INVALID;
246 :
247 0 : case CKA_MODULUS_BITS:
248 0 : return return_modulus_bits (self, attr);
249 :
250 0 : case CKA_MODULUS:
251 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_RSA, "n", attr);
252 :
253 0 : case CKA_PUBLIC_EXPONENT:
254 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_RSA, "e", attr);
255 :
256 0 : case CKA_PRIME:
257 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "p", attr);
258 :
259 0 : case CKA_SUBPRIME:
260 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "q", attr);
261 :
262 0 : case CKA_BASE:
263 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "g", attr);
264 :
265 : /* DSA public value */
266 0 : case CKA_VALUE:
267 0 : return gkm_sexp_key_set_part (GKM_SEXP_KEY (self), GCRY_PK_DSA, "y", attr);
268 :
269 0 : case CKA_EC_POINT:
270 0 : return gkm_sexp_key_set_ec_q (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
271 :
272 0 : case CKA_EC_PARAMS:
273 0 : return gkm_sexp_key_set_ec_params (GKM_SEXP_KEY (self), GCRY_PK_ECC, attr);
274 : };
275 :
276 54 : return GKM_OBJECT_CLASS (gkm_public_xsa_key_parent_class)->get_attribute (base, session, attr);
277 : }
278 :
279 : static GkmSexp*
280 0 : gkm_public_xsa_key_acquire_crypto_sexp (GkmSexpKey *self, GkmSession *session)
281 : {
282 : GkmSexp* sexp;
283 :
284 0 : sexp = gkm_sexp_key_get_base (self);
285 0 : if (sexp != NULL)
286 0 : gkm_sexp_ref (sexp);
287 :
288 0 : return sexp;
289 : }
290 :
291 : static void
292 45 : gkm_public_xsa_key_init (GkmPublicXsaKey *self)
293 : {
294 :
295 45 : }
296 :
297 : static void
298 7 : gkm_public_xsa_key_class_init (GkmPublicXsaKeyClass *klass)
299 : {
300 7 : GkmObjectClass *gkm_class = GKM_OBJECT_CLASS (klass);
301 7 : GkmSexpKeyClass *key_class = GKM_SEXP_KEY_CLASS (klass);
302 :
303 7 : gkm_public_xsa_key_parent_class = g_type_class_peek_parent (klass);
304 :
305 7 : gkm_class->get_attribute = gkm_public_xsa_key_real_get_attribute;
306 :
307 7 : key_class->acquire_crypto_sexp = gkm_public_xsa_key_acquire_crypto_sexp;
308 7 : }
309 :
310 : /* -----------------------------------------------------------------------------
311 : * PUBLIC
312 : */
313 :
314 : GkmSexp*
315 2 : gkm_public_xsa_key_create_sexp (GkmSession *session, GkmTransaction *transaction,
316 : CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
317 : {
318 : CK_KEY_TYPE type;
319 : gcry_sexp_t sexp;
320 : CK_RV ret;
321 :
322 2 : g_return_val_if_fail (GKM_IS_TRANSACTION (transaction), NULL);
323 2 : g_return_val_if_fail (attrs || !n_attrs, NULL);
324 :
325 2 : if (!gkm_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type)) {
326 0 : gkm_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
327 0 : return NULL;
328 : }
329 :
330 2 : gkm_attributes_consume (attrs, n_attrs, CKA_KEY_TYPE, CKA_CLASS, G_MAXULONG);
331 :
332 2 : switch (type) {
333 1 : case CKK_RSA:
334 1 : ret = create_rsa_public (attrs, n_attrs, &sexp);
335 1 : break;
336 0 : case CKK_DSA:
337 0 : ret = create_dsa_public (attrs, n_attrs, &sexp);
338 0 : break;
339 1 : case CKK_EC:
340 1 : ret = create_ecdsa_public (attrs, n_attrs, &sexp);
341 1 : break;
342 0 : default:
343 0 : ret = CKR_ATTRIBUTE_VALUE_INVALID;
344 0 : break;
345 : };
346 :
347 2 : if (ret != CKR_OK) {
348 0 : gkm_transaction_fail (transaction, ret);
349 0 : return NULL;
350 : }
351 :
352 2 : g_return_val_if_fail (sexp, NULL);
353 2 : return gkm_sexp_new (sexp);
354 : }
355 :
356 : GkmFactory*
357 287 : gkm_public_xsa_key_get_factory (void)
358 : {
359 : static CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
360 :
361 : static CK_ATTRIBUTE attributes[] = {
362 : { CKA_CLASS, &klass, sizeof (klass) }
363 : };
364 :
365 : static GkmFactory factory = {
366 : attributes,
367 : G_N_ELEMENTS (attributes),
368 : factory_create_public_xsa_key
369 : };
370 :
371 287 : return &factory;
372 : }
|