Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2011 Collabora Ltd.
3 : : *
4 : : * This program is free software; you can redistribute it and/or modify
5 : : * it under the terms of the GNU Lesser General Public License as
6 : : * published by the Free Software Foundation; either version 2.1 of
7 : : * the License, or (at your option) any later version.
8 : : *
9 : : * This program is distributed in the hope that it will be useful, but
10 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16 : : *
17 : : * Author: Stef Walter <stefw@collabora.co.uk>
18 : : */
19 : :
20 : : #include "config.h"
21 : :
22 : : #include "gcr-certificate-request.h"
23 : : #include "gcr-key-mechanisms.h"
24 : : #include "gcr-subject-public-key.h"
25 : :
26 : : #include "gcr/gcr-enum-types.h"
27 : : #include "gcr/gcr-oids.h"
28 : :
29 : : #include <egg/egg-armor.h>
30 : : #include <egg/egg-asn1x.h>
31 : : #include <egg/egg-asn1-defs.h>
32 : : #include <egg/egg-dn.h>
33 : :
34 : : #include <glib/gi18n-lib.h>
35 : :
36 : : /**
37 : : * GcrCertificateRequest:
38 : : *
39 : : * An object that allows creation of certificate requests. A certificate
40 : : * request is sent to a certificate authority to request an X.509 certificate.
41 : : *
42 : : * Use [func@CertificateRequest.prepare] to create a blank certificate
43 : : * request for a given private key. Set the common name on the certificate
44 : : * request with [method@CertificateRequest.set_cn], and then sign the request
45 : : * with [method@CertificateRequest.complete_async].
46 : : */
47 : :
48 : : /**
49 : : * GcrCertificateRequestFormat:
50 : : * @GCR_CERTIFICATE_REQUEST_PKCS10: certificate request is in PKCS#10 format
51 : : *
52 : : * The format of a certificate request. Currently only PKCS#10 is supported.
53 : : */
54 : :
55 : : struct _GcrCertificateRequest {
56 : : GObject parent;
57 : :
58 : : GckObject *private_key;
59 : : GNode *asn;
60 : : gulong *mechanisms;
61 : : gulong n_mechanisms;
62 : : };
63 : :
64 : : enum {
65 : : PROP_0,
66 : : PROP_FORMAT,
67 : : PROP_PRIVATE_KEY
68 : : };
69 : :
70 : : /* Forward declarations */
71 [ # # # # : 0 : G_DEFINE_TYPE (GcrCertificateRequest, gcr_certificate_request, G_TYPE_OBJECT);
# # ]
72 : :
73 : : /* When updating here, update prepare_to_be_signed() */
74 : : static const gulong RSA_MECHANISMS[] = {
75 : : CKM_SHA1_RSA_PKCS,
76 : : CKM_RSA_PKCS,
77 : : };
78 : :
79 : : /* When updating here, update prepare_to_be_signed() */
80 : : static const gulong DSA_MECHANISMS[] = {
81 : : CKM_DSA_SHA1,
82 : : CKM_DSA,
83 : : };
84 : :
85 : : static const gulong ALL_MECHANISMS[] = {
86 : : CKM_SHA1_RSA_PKCS,
87 : : CKM_DSA_SHA1,
88 : : CKM_RSA_PKCS,
89 : : CKM_DSA,
90 : : };
91 : :
92 : : G_STATIC_ASSERT (sizeof (ALL_MECHANISMS) == sizeof (RSA_MECHANISMS) + sizeof (DSA_MECHANISMS));
93 : :
94 : : static void
95 : 0 : gcr_certificate_request_init (GcrCertificateRequest *self)
96 : : {
97 : :
98 : 0 : }
99 : :
100 : : static void
101 : 0 : gcr_certificate_request_constructed (GObject *obj)
102 : : {
103 : 0 : GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
104 : : GNode *version;
105 : :
106 : 0 : G_OBJECT_CLASS (gcr_certificate_request_parent_class)->constructed (obj);
107 : :
108 : 0 : self->asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-10-CertificationRequest");
109 [ # # ]: 0 : g_return_if_fail (self->asn != NULL);
110 : :
111 : : /* Setup the version */
112 : 0 : version = egg_asn1x_node (self->asn, "certificationRequestInfo", "version", NULL);
113 : 0 : egg_asn1x_set_integer_as_ulong (version, 0);
114 : : }
115 : :
116 : : static void
117 : 0 : gcr_certificate_request_finalize (GObject *obj)
118 : : {
119 : 0 : GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
120 : :
121 : 0 : egg_asn1x_destroy (self->asn);
122 : 0 : g_free (self->mechanisms);
123 : :
124 : 0 : G_OBJECT_CLASS (gcr_certificate_request_parent_class)->finalize (obj);
125 : 0 : }
126 : :
127 : : static void
128 : 0 : gcr_certificate_request_set_property (GObject *obj,
129 : : guint prop_id,
130 : : const GValue *value,
131 : : GParamSpec *pspec)
132 : : {
133 : 0 : GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
134 : : GcrCertificateRequestFormat format;
135 : :
136 [ # # # ]: 0 : switch (prop_id) {
137 : 0 : case PROP_PRIVATE_KEY:
138 [ # # ]: 0 : g_return_if_fail (self->private_key == NULL);
139 : 0 : self->private_key = g_value_dup_object (value);
140 [ # # ]: 0 : g_return_if_fail (GCK_IS_OBJECT (self->private_key));
141 : 0 : break;
142 : 0 : case PROP_FORMAT:
143 : 0 : format = g_value_get_enum (value);
144 [ # # ]: 0 : g_return_if_fail (format == GCR_CERTIFICATE_REQUEST_PKCS10);
145 : 0 : break;
146 : 0 : default:
147 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
148 : 0 : break;
149 : : }
150 : : }
151 : :
152 : : static void
153 : 0 : gcr_certificate_request_get_property (GObject *obj,
154 : : guint prop_id,
155 : : GValue *value,
156 : : GParamSpec *pspec)
157 : : {
158 : 0 : GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
159 : :
160 [ # # # ]: 0 : switch (prop_id) {
161 : 0 : case PROP_PRIVATE_KEY:
162 : 0 : g_value_set_object (value, gcr_certificate_request_get_private_key (self));
163 : 0 : break;
164 : 0 : case PROP_FORMAT:
165 : 0 : g_value_set_enum (value, gcr_certificate_request_get_format (self));
166 : 0 : break;
167 : 0 : default:
168 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
169 : 0 : break;
170 : : }
171 : 0 : }
172 : :
173 : : static void
174 : 0 : gcr_certificate_request_class_init (GcrCertificateRequestClass *klass)
175 : : {
176 : 0 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
177 : :
178 : 0 : gobject_class->constructed = gcr_certificate_request_constructed;
179 : 0 : gobject_class->finalize = gcr_certificate_request_finalize;
180 : 0 : gobject_class->set_property = gcr_certificate_request_set_property;
181 : 0 : gobject_class->get_property = gcr_certificate_request_get_property;
182 : :
183 : : /**
184 : : * GcrCertificateRequest:private-key:
185 : : *
186 : : * The private key that this certificate request is for.
187 : : */
188 : 0 : g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY,
189 : : g_param_spec_object ("private-key", "Private key", "Private key for request",
190 : : GCK_TYPE_OBJECT,
191 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
192 : :
193 : : /**
194 : : * GcrCertificateRequest:format:
195 : : *
196 : : * The format of the certificate request.
197 : : */
198 : 0 : g_object_class_install_property (gobject_class, PROP_FORMAT,
199 : : g_param_spec_enum ("format", "Format", "Format of certificate request",
200 : : GCR_TYPE_CERTIFICATE_REQUEST_FORMAT, GCR_CERTIFICATE_REQUEST_PKCS10,
201 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
202 : 0 : }
203 : :
204 : : /**
205 : : * gcr_certificate_request_prepare:
206 : : * @format: the format for the certificate request
207 : : * @private_key: the private key the the certificate is being requested for
208 : : *
209 : : * Create a new certificate request, in the given format for the private key.
210 : : *
211 : : * Returns: (transfer full): a new #GcrCertificate request
212 : : */
213 : : GcrCertificateRequest *
214 : 0 : gcr_certificate_request_prepare (GcrCertificateRequestFormat format,
215 : : GckObject *private_key)
216 : : {
217 [ # # ]: 0 : g_return_val_if_fail (format == GCR_CERTIFICATE_REQUEST_PKCS10, NULL);
218 [ # # ]: 0 : g_return_val_if_fail (GCK_IS_OBJECT (private_key), NULL);
219 : :
220 : 0 : return g_object_new (GCR_TYPE_CERTIFICATE_REQUEST,
221 : : "format", format,
222 : : "private-key", private_key,
223 : : NULL);
224 : : }
225 : :
226 : : /**
227 : : * gcr_certificate_request_get_private_key:
228 : : * @self: the certificate request
229 : : *
230 : : * Get the private key this certificate request is for.
231 : : *
232 : : * Returns: (transfer none): the private key,
233 : : */
234 : : GckObject *
235 : 0 : gcr_certificate_request_get_private_key (GcrCertificateRequest *self)
236 : : {
237 [ # # ]: 0 : g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), NULL);
238 : 0 : return self->private_key;
239 : : }
240 : :
241 : : /**
242 : : * gcr_certificate_request_get_format:
243 : : * @self: the certificate request
244 : : *
245 : : * Get the format of this certificate request.
246 : : *
247 : : * Returns: the format
248 : : */
249 : : GcrCertificateRequestFormat
250 : 0 : gcr_certificate_request_get_format (GcrCertificateRequest *self)
251 : : {
252 [ # # ]: 0 : g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), 0);
253 : 0 : return GCR_CERTIFICATE_REQUEST_PKCS10;
254 : : }
255 : :
256 : : /**
257 : : * gcr_certificate_request_set_cn:
258 : : * @self: the certificate request
259 : : * @cn: common name to set on the request
260 : : *
261 : : * Set the common name encoded in the certificate request.
262 : : */
263 : : void
264 : 0 : gcr_certificate_request_set_cn (GcrCertificateRequest *self,
265 : : const gchar *cn)
266 : : {
267 : : GNode *subject;
268 : : GNode *dn;
269 : :
270 [ # # ]: 0 : g_return_if_fail (GCR_IS_CERTIFICATE_REQUEST (self));
271 [ # # ]: 0 : g_return_if_fail (cn != NULL);
272 : :
273 : 0 : subject = egg_asn1x_node (self->asn, "certificationRequestInfo", "subject", NULL);
274 : 0 : dn = egg_asn1x_node (subject, "rdnSequence", NULL);
275 : :
276 : : /* TODO: we shouldn't really be clearing this, but replacing CN */
277 : 0 : egg_asn1x_set_choice (subject, dn);
278 : 0 : egg_asn1x_clear (dn);
279 : 0 : egg_dn_add_string_part (dn, GCR_OID_NAME_CN, cn);
280 : : }
281 : :
282 : : static GBytes *
283 : 0 : hash_sha1_pkcs1 (GBytes *data)
284 : : {
285 : 0 : const guchar SHA1_ASN[15] = /* Object ID is 1.3.14.3.2.26 */
286 : : { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
287 : : 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
288 : :
289 : : GChecksum *checksum;
290 : : guchar *hash;
291 : : gsize n_hash;
292 : : gsize n_digest;
293 : :
294 : 0 : n_digest = g_checksum_type_get_length (G_CHECKSUM_SHA1);
295 : 0 : n_hash = n_digest + sizeof (SHA1_ASN);
296 : 0 : hash = g_malloc (n_hash);
297 : 0 : memcpy (hash, SHA1_ASN, sizeof (SHA1_ASN));
298 : :
299 : 0 : checksum = g_checksum_new (G_CHECKSUM_SHA1);
300 : 0 : g_checksum_update (checksum, g_bytes_get_data (data, NULL), g_bytes_get_size (data));
301 : 0 : g_checksum_get_digest (checksum, hash + sizeof (SHA1_ASN), &n_digest);
302 : 0 : g_checksum_free (checksum);
303 : :
304 : 0 : return g_bytes_new_take (hash, n_hash);
305 : : }
306 : :
307 : : static GBytes *
308 : 0 : hash_sha1 (GBytes *data)
309 : : {
310 : : GChecksum *checksum;
311 : : guchar *hash;
312 : : gsize n_hash;
313 : :
314 : 0 : n_hash = g_checksum_type_get_length (G_CHECKSUM_SHA1);
315 : 0 : hash = g_malloc (n_hash);
316 : :
317 : 0 : checksum = g_checksum_new (G_CHECKSUM_SHA1);
318 : 0 : g_checksum_update (checksum, g_bytes_get_data (data, NULL), g_bytes_get_size (data));
319 : 0 : g_checksum_get_digest (checksum, hash, &n_hash);
320 : 0 : g_checksum_free (checksum);
321 : :
322 : 0 : return g_bytes_new_take (hash, n_hash);
323 : : }
324 : :
325 : : static GBytes *
326 : 0 : prepare_to_be_signed (GcrCertificateRequest *self,
327 : : GckMechanism *mechanism)
328 : : {
329 : : GNode *node;
330 : : GBytes *data;
331 : : GBytes *hash;
332 : :
333 [ # # ]: 0 : g_assert (mechanism != NULL);
334 : :
335 : 0 : node = egg_asn1x_node (self->asn, "certificationRequestInfo", NULL);
336 : 0 : data = egg_asn1x_encode (node, NULL);
337 : :
338 : 0 : mechanism->parameter = NULL;
339 : 0 : mechanism->n_parameter = 0;
340 : :
341 [ # # # # ]: 0 : switch (mechanism->type) {
342 : 0 : case CKM_SHA1_RSA_PKCS:
343 : : case CKM_DSA_SHA1:
344 : 0 : return data;
345 : :
346 : 0 : case CKM_RSA_PKCS:
347 : 0 : hash = hash_sha1_pkcs1 (data);
348 : 0 : g_bytes_unref (data);
349 : 0 : return hash;
350 : :
351 : 0 : case CKM_DSA:
352 : 0 : hash = hash_sha1 (data);
353 : 0 : g_bytes_unref (data);
354 : 0 : return hash;
355 : :
356 : 0 : default:
357 : 0 : g_assert_not_reached ();
358 : : return NULL;
359 : : }
360 : : }
361 : :
362 : : static gboolean
363 : 0 : prepare_subject_public_key_and_mechanisms (GcrCertificateRequest *self,
364 : : GNode *subject_public_key,
365 : : GQuark *algorithm,
366 : : const gulong **mechanisms,
367 : : gsize *n_mechanisms,
368 : : GError **error)
369 : : {
370 : : GBytes *encoded;
371 : : GNode *node;
372 : : GQuark oid;
373 : :
374 [ # # ]: 0 : g_assert (algorithm != NULL);
375 [ # # ]: 0 : g_assert (mechanisms != NULL);
376 [ # # ]: 0 : g_assert (n_mechanisms != NULL);
377 : :
378 : 0 : encoded = egg_asn1x_encode (subject_public_key, NULL);
379 [ # # ]: 0 : g_return_val_if_fail (encoded != NULL, FALSE);
380 : :
381 : 0 : node = egg_asn1x_node (subject_public_key, "algorithm", "algorithm", NULL);
382 : 0 : oid = egg_asn1x_get_oid_as_quark (node);
383 : :
384 [ # # ]: 0 : if (oid == GCR_OID_PKIX1_RSA) {
385 : 0 : *mechanisms = RSA_MECHANISMS;
386 : 0 : *n_mechanisms = G_N_ELEMENTS (RSA_MECHANISMS);
387 : 0 : *algorithm = GCR_OID_PKIX1_SHA1_WITH_RSA;
388 : :
389 [ # # ]: 0 : } else if (oid == GCR_OID_PKIX1_DSA) {
390 : 0 : *mechanisms = DSA_MECHANISMS;
391 : 0 : *n_mechanisms = G_N_ELEMENTS (DSA_MECHANISMS);
392 : 0 : *algorithm = GCR_OID_PKIX1_SHA1_WITH_DSA;
393 : :
394 : : } else {
395 : 0 : g_bytes_unref (encoded);
396 : 0 : g_set_error (error, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED,
397 : : _("Unsupported key type for certificate request"));
398 : 0 : return FALSE;
399 : : }
400 : :
401 : 0 : node = egg_asn1x_node (self->asn, "certificationRequestInfo", "subjectPKInfo", NULL);
402 [ # # ]: 0 : if (!egg_asn1x_decode (node, encoded))
403 : 0 : g_return_val_if_reached (FALSE);
404 : :
405 : 0 : g_bytes_unref (encoded);
406 : 0 : return TRUE;
407 : : }
408 : :
409 : : static void
410 : 0 : encode_take_signature_into_request (GcrCertificateRequest *self,
411 : : GQuark algorithm,
412 : : GNode *subject_public_key,
413 : : guchar *result,
414 : : gsize n_result)
415 : : {
416 : : GNode *params;
417 : : GNode *node;
418 : :
419 : 0 : node = egg_asn1x_node (self->asn, "signature", NULL);
420 : 0 : egg_asn1x_take_bits_as_raw (node, g_bytes_new_take (result, n_result), n_result * 8);
421 : :
422 : 0 : node = egg_asn1x_node (self->asn, "signatureAlgorithm", "algorithm", NULL);
423 : 0 : egg_asn1x_set_oid_as_quark (node, algorithm);
424 : :
425 : 0 : node = egg_asn1x_node (self->asn, "signatureAlgorithm", "parameters", NULL);
426 : 0 : params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
427 : 0 : egg_asn1x_set_any_from (node, params);
428 : 0 : }
429 : :
430 : : /**
431 : : * gcr_certificate_request_complete:
432 : : * @self: a certificate request
433 : : * @cancellable: a cancellation object
434 : : * @error: location to place an error on failure
435 : : *
436 : : * Complete and sign a certificate request, so that it can be encoded
437 : : * and sent to a certificate authority.
438 : : *
439 : : * This call may block as it signs the request using the private key.
440 : : *
441 : : * Returns: whether certificate request was successfully completed or not
442 : : */
443 : : gboolean
444 : 0 : gcr_certificate_request_complete (GcrCertificateRequest *self,
445 : : GCancellable *cancellable,
446 : : GError **error)
447 : : {
448 : : GNode *subject_public_key;
449 : : const gulong *mechanisms;
450 : : gsize n_mechanisms;
451 : 0 : GckMechanism mechanism = { 0, };
452 : 0 : GQuark algorithm = 0;
453 : : GBytes *tbs;
454 : : GckSession *session;
455 : : guchar *signature;
456 : : gsize n_signature;
457 : : gboolean ret;
458 : :
459 [ # # ]: 0 : g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), FALSE);
460 [ # # # # ]: 0 : g_return_val_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable), FALSE);
461 [ # # # # ]: 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
462 : :
463 : 0 : subject_public_key = _gcr_subject_public_key_load (self->private_key,
464 : : cancellable, error);
465 [ # # ]: 0 : if (subject_public_key == NULL)
466 : 0 : return FALSE;
467 : :
468 : 0 : ret = prepare_subject_public_key_and_mechanisms (self, subject_public_key,
469 : : &algorithm, &mechanisms,
470 : : &n_mechanisms, error);
471 : :
472 [ # # ]: 0 : if (!ret) {
473 : 0 : egg_asn1x_destroy (subject_public_key);
474 : 0 : return FALSE;
475 : : }
476 : :
477 : : /* Figure out which mechanism to use */
478 : 0 : mechanism.type = _gcr_key_mechanisms_check (self->private_key, mechanisms,
479 : : n_mechanisms, CKA_SIGN,
480 : : cancellable, NULL);
481 [ # # ]: 0 : if (mechanism.type == GCK_INVALID) {
482 : 0 : egg_asn1x_destroy (subject_public_key);
483 : 0 : g_set_error (error, GCK_ERROR, CKR_KEY_TYPE_INCONSISTENT,
484 : : _("The key cannot be used to sign the request"));
485 : 0 : return FALSE;
486 : : }
487 : :
488 : 0 : tbs = prepare_to_be_signed (self, &mechanism);
489 : 0 : session = gck_object_get_session (self->private_key);
490 : 0 : signature = gck_session_sign_full (session, self->private_key, &mechanism,
491 : 0 : g_bytes_get_data (tbs, NULL),
492 : : g_bytes_get_size (tbs),
493 : : &n_signature, cancellable, error);
494 : 0 : g_object_unref (session);
495 : 0 : g_bytes_unref (tbs);
496 : :
497 [ # # ]: 0 : if (!signature) {
498 : 0 : egg_asn1x_destroy (subject_public_key);
499 : 0 : return FALSE;
500 : : }
501 : :
502 : 0 : encode_take_signature_into_request (self, algorithm, subject_public_key,
503 : : signature, n_signature);
504 : 0 : egg_asn1x_destroy (subject_public_key);
505 : 0 : return TRUE;
506 : : }
507 : :
508 : : typedef struct {
509 : : GcrCertificateRequest *request;
510 : : GQuark algorithm;
511 : : GNode *subject_public_key;
512 : : GckMechanism mechanism;
513 : : GckSession *session;
514 : : GBytes *tbs;
515 : : } CompleteClosure;
516 : :
517 : : static void
518 : 0 : complete_closure_free (gpointer data)
519 : : {
520 : 0 : CompleteClosure *closure = data;
521 : 0 : egg_asn1x_destroy (closure->subject_public_key);
522 [ # # ]: 0 : g_clear_object (&closure->request);
523 [ # # ]: 0 : g_clear_object (&closure->session);
524 [ # # ]: 0 : if (closure->tbs)
525 : 0 : g_bytes_unref (closure->tbs);
526 : 0 : g_free (closure);
527 : 0 : }
528 : :
529 : : static void
530 : 0 : on_certificate_request_signed (GObject *source,
531 : : GAsyncResult *result,
532 : : gpointer user_data)
533 : : {
534 : 0 : GTask *task = G_TASK (user_data);
535 : 0 : CompleteClosure *closure = g_task_get_task_data (task);
536 : 0 : GError *error = NULL;
537 : : guchar *signature;
538 : : gsize n_signature;
539 : :
540 : 0 : signature = gck_session_sign_finish (closure->session, result, &n_signature, &error);
541 [ # # ]: 0 : if (error == NULL) {
542 : 0 : encode_take_signature_into_request (closure->request,
543 : : closure->algorithm,
544 : : closure->subject_public_key,
545 : : signature, n_signature);
546 : :
547 : 0 : g_task_return_boolean (task, TRUE);
548 : : } else {
549 : 0 : g_task_return_error (task, g_steal_pointer (&error));
550 : : }
551 : :
552 [ # # ]: 0 : g_clear_object (&task);
553 : 0 : }
554 : :
555 : : static void
556 : 0 : on_mechanism_check (GObject *source,
557 : : GAsyncResult *result,
558 : : gpointer user_data)
559 : : {
560 : 0 : GTask *task = G_TASK (user_data);
561 : 0 : CompleteClosure *closure = g_task_get_task_data (task);
562 : 0 : GCancellable *cancellable = g_task_get_cancellable (task);
563 : :
564 : 0 : closure->mechanism.type = _gcr_key_mechanisms_check_finish (closure->request->private_key,
565 : : result, NULL);
566 [ # # ]: 0 : if (closure->mechanism.type == GCK_INVALID) {
567 : 0 : g_task_return_new_error (task, GCK_ERROR, CKR_KEY_TYPE_INCONSISTENT,
568 : 0 : _("The key cannot be used to sign the request"));
569 : :
570 : : } else {
571 : 0 : closure->tbs = prepare_to_be_signed (closure->request, &closure->mechanism);
572 : 0 : gck_session_sign_async (closure->session,
573 : 0 : closure->request->private_key,
574 : : &closure->mechanism,
575 : 0 : g_bytes_get_data (closure->tbs, NULL),
576 : : g_bytes_get_size (closure->tbs),
577 : : cancellable,
578 : : on_certificate_request_signed,
579 : : g_steal_pointer (&task));
580 : : }
581 : :
582 [ # # ]: 0 : g_clear_object (&task);
583 : 0 : }
584 : :
585 : : static void
586 : 0 : on_subject_public_key_loaded (GObject *source,
587 : : GAsyncResult *result,
588 : : gpointer user_data)
589 : : {
590 : 0 : GTask *task = G_TASK (user_data);
591 : 0 : CompleteClosure *closure = g_task_get_task_data (task);
592 : 0 : GCancellable *cancellable = g_task_get_cancellable (task);
593 : : const gulong *mechanisms;
594 : : gsize n_mechanisms;
595 : 0 : GError *error = NULL;
596 : :
597 : 0 : closure->subject_public_key = _gcr_subject_public_key_load_finish (result, &error);
598 [ # # ]: 0 : if (error == NULL) {
599 : 0 : prepare_subject_public_key_and_mechanisms (closure->request,
600 : : closure->subject_public_key,
601 : : &closure->algorithm,
602 : : &mechanisms,
603 : : &n_mechanisms,
604 : : &error);
605 : : }
606 : :
607 [ # # ]: 0 : if (error != NULL) {
608 : 0 : g_task_return_error (task, g_steal_pointer (&error));
609 [ # # ]: 0 : g_clear_object (&task);
610 : 0 : return;
611 : : }
612 : :
613 : 0 : _gcr_key_mechanisms_check_async (closure->request->private_key,
614 : : mechanisms, n_mechanisms, CKA_SIGN,
615 : : cancellable, on_mechanism_check,
616 : : g_steal_pointer (&task));
617 : : }
618 : :
619 : : /**
620 : : * gcr_certificate_request_complete_async:
621 : : * @self: a certificate request
622 : : * @cancellable: (nullable): a cancellation object
623 : : * @callback: called when the operation completes
624 : : * @user_data: data to pass to the callback
625 : : *
626 : : * Asynchronously complete and sign a certificate request, so that it can
627 : : * be encoded and sent to a certificate authority.
628 : : *
629 : : * This call will return immediately and complete later.
630 : : */
631 : : void
632 : 0 : gcr_certificate_request_complete_async (GcrCertificateRequest *self,
633 : : GCancellable *cancellable,
634 : : GAsyncReadyCallback callback,
635 : : gpointer user_data)
636 : : {
637 : : GTask *task;
638 : : CompleteClosure *closure;
639 : :
640 [ # # ]: 0 : g_return_if_fail (GCR_IS_CERTIFICATE_REQUEST (self));
641 [ # # # # ]: 0 : g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
642 : :
643 : 0 : task = g_task_new (self, cancellable, callback, user_data);
644 [ # # ]: 0 : g_task_set_source_tag (task, gcr_certificate_request_complete_async);
645 : 0 : closure = g_new0 (CompleteClosure, 1);
646 : 0 : closure->session = gck_object_get_session (self->private_key);
647 : 0 : closure->request = g_object_ref (self);
648 : 0 : g_task_set_task_data (task, closure, complete_closure_free);
649 : :
650 : 0 : _gcr_subject_public_key_load_async (self->private_key, cancellable,
651 : : on_subject_public_key_loaded,
652 : : g_steal_pointer (&task));
653 : :
654 [ # # ]: 0 : g_clear_object (&task);
655 : : }
656 : :
657 : : /**
658 : : * gcr_certificate_request_complete_finish:
659 : : * @self: a certificate request
660 : : * @result: result of the asynchronous operation
661 : : * @error: location to place an error on failure
662 : : *
663 : : * Finish an asynchronous operation to complete and sign a certificate
664 : : * request.
665 : : *
666 : : * Returns: whether certificate request was successfully completed or not
667 : : */
668 : : gboolean
669 : 0 : gcr_certificate_request_complete_finish (GcrCertificateRequest *self,
670 : : GAsyncResult *result,
671 : : GError **error)
672 : : {
673 [ # # ]: 0 : g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), FALSE);
674 [ # # # # ]: 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
675 [ # # ]: 0 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
676 : :
677 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
678 : : }
679 : :
680 : : /**
681 : : * gcr_certificate_request_encode:
682 : : * @self: a certificate request
683 : : * @textual: whether to encode output as text
684 : : * @length: (out): location to place length of returned data
685 : : *
686 : : * Encode the certificate request. It must have been completed with
687 : : * [method@CertificateRequest.complete] or
688 : : * [method@CertificateRequest.complete_async].
689 : : *
690 : : * If @textual is %FALSE, the output is a DER encoded certificate request.
691 : : *
692 : : * If @textual is %TRUE, the output is encoded as text. For PKCS#10 requests
693 : : * this is done using the OpenSSL style PEM encoding.
694 : : *
695 : : * Returns: (transfer full) (array length=length): the encoded certificate request
696 : : */
697 : : guchar *
698 : 0 : gcr_certificate_request_encode (GcrCertificateRequest *self,
699 : : gboolean textual,
700 : : gsize *length)
701 : : {
702 : : GBytes *bytes;
703 : : gpointer encoded;
704 : : gpointer data;
705 : : gsize size;
706 : :
707 [ # # ]: 0 : g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), NULL);
708 [ # # ]: 0 : g_return_val_if_fail (length != NULL, NULL);
709 : :
710 : 0 : bytes = egg_asn1x_encode (self->asn, NULL);
711 [ # # ]: 0 : if (bytes == NULL) {
712 : 0 : g_warning ("couldn't encode certificate request: %s",
713 : : egg_asn1x_message (self->asn));
714 : 0 : return NULL;
715 : : }
716 : :
717 : 0 : encoded = g_bytes_unref_to_data (bytes, &size);
718 [ # # ]: 0 : if (textual) {
719 : 0 : data = egg_armor_write (encoded, size,
720 : : g_quark_from_static_string ("CERTIFICATE REQUEST"),
721 : : NULL, length);
722 : 0 : g_free (encoded);
723 : 0 : encoded = data;
724 : :
725 : : } else {
726 : 0 : *length = size;
727 : : }
728 : :
729 : 0 : return encoded;
730 : : }
731 : :
732 : : /**
733 : : * gcr_certificate_request_capable:
734 : : * @private_key: a private key
735 : : * @cancellable: (nullable): cancellation object
736 : : * @error: location to place an error
737 : : *
738 : : * Check whether [class@CertificateRequest] is capable of creating a request
739 : : * for the given @private_key.
740 : : *
741 : : * Returns: whether a request can be created
742 : : */
743 : : gboolean
744 : 0 : gcr_certificate_request_capable (GckObject *private_key,
745 : : GCancellable *cancellable,
746 : : GError **error)
747 : : {
748 [ # # ]: 0 : g_return_val_if_fail (GCK_IS_OBJECT (private_key), FALSE);
749 [ # # # # : 0 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
# # # # #
# ]
750 [ # # # # ]: 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
751 : :
752 : 0 : return _gcr_key_mechanisms_check (private_key, ALL_MECHANISMS,
753 : : G_N_ELEMENTS (ALL_MECHANISMS),
754 : : CKA_SIGN, cancellable, error);
755 : : }
756 : :
757 : : /**
758 : : * gcr_certificate_request_capable_async:
759 : : * @private_key: a private key
760 : : * @cancellable: (nullable): cancellation object
761 : : * @callback: will be called when the operation completes
762 : : * @user_data: data to be passed to callback
763 : : *
764 : : * Asynchronously check whether [class@CertificateRequest] is capable of
765 : : * creating a request for the given @private_key.
766 : : */
767 : : void
768 : 0 : gcr_certificate_request_capable_async (GckObject *private_key,
769 : : GCancellable *cancellable,
770 : : GAsyncReadyCallback callback,
771 : : gpointer user_data)
772 : : {
773 [ # # ]: 0 : g_return_if_fail (GCK_IS_OBJECT (private_key));
774 [ # # # # : 0 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
# # # # #
# ]
775 : :
776 : 0 : _gcr_key_mechanisms_check_async (private_key, ALL_MECHANISMS,
777 : : G_N_ELEMENTS (ALL_MECHANISMS),
778 : : CKA_SIGN, cancellable,
779 : : callback, user_data);
780 : : }
781 : :
782 : : /**
783 : : * gcr_certificate_request_capable_finish:
784 : : * @result: asynchronous result
785 : : * @error: location to place an error
786 : : *
787 : : * Get the result for asynchronously check whether [class@CertificateRequest] is
788 : : * capable of creating a request for the given @private_key.
789 : : *
790 : : * Returns: whether a request can be created
791 : : */
792 : : gboolean
793 : 0 : gcr_certificate_request_capable_finish (GAsyncResult *result,
794 : : GError **error)
795 : : {
796 : : GObject *source;
797 : : gulong mech;
798 : :
799 [ # # # # : 0 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
# # # # ]
800 : :
801 : 0 : source = g_async_result_get_source_object (result);
802 : 0 : mech = _gcr_key_mechanisms_check_finish (GCK_OBJECT (source), result, error);
803 : 0 : g_object_unref (source);
804 : :
805 : 0 : return mech != GCK_INVALID;
806 : : }
|