1 // gnoMint: a graphical interface for managing a certification authority
2 // Copyright (C) 2006-2009 David Marín Carreño <davefx@gmail.com>
3 //
4 // This file is part of gnoMint.
5 //
6 // gnoMint is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program 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
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 #ifndef GNOMINTCLI
21
22 #include <gtk/gtk.h>
23 #endif
24
25 #include <glib-object.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "import.h"
30 #include "tls.h"
31 #include "dialog.h"
32 #include "ca_file.h"
33
34
35 gchar * __import_ask_password (const gchar *crypted_part_description);
36 gint __import_csr (gnutls_x509_crq_t *crq, gchar ** csr_dn, guint64 *id);
37 gint __import_cert (gnutls_x509_crt_t *cert, gchar ** cert_dn, guint64 *id);
38
__import_ask_password(const gchar * crypted_part_description)39 gchar * __import_ask_password (const gchar *crypted_part_description)
40 {
41 #ifndef GNOMINTCLI
42 gchar *password;
43 GObject * widget = NULL, * password_widget = NULL, *description_widget = NULL;
44 GtkBuilder * dialog_gtkb = NULL;
45 gchar * label = NULL;
46 gint response = 0;
47
48 dialog_gtkb = gtk_builder_new();
49 gtk_builder_add_from_file (dialog_gtkb,
50 g_build_filename (PACKAGE_DATA_DIR, "gnomint", "import_password_dialog.ui", NULL),
51 NULL);
52 gtk_builder_connect_signals (dialog_gtkb, NULL);
53
54 password_widget = gtk_builder_get_object (dialog_gtkb, "import_password_entry");
55 description_widget = gtk_builder_get_object (dialog_gtkb, "import_crypted_part_description");
56
57 label = g_strdup_printf ("<small><i>%s</i></small>", crypted_part_description);
58 gtk_label_set_markup (GTK_LABEL(description_widget), (const gchar *) label);
59 g_free (label);
60
61 gtk_widget_grab_focus (GTK_WIDGET(password_widget));
62 widget = gtk_builder_get_object (dialog_gtkb, "import_password_dialog");
63 response = gtk_dialog_run(GTK_DIALOG(widget));
64
65 if (!response) {
66 gtk_widget_destroy (GTK_WIDGET(widget));
67 g_object_unref (G_OBJECT(dialog_gtkb));
68 return NULL;
69 } else {
70 password = g_strdup ((gchar *) gtk_entry_get_text (GTK_ENTRY(password_widget)));
71 }
72
73 widget = gtk_builder_get_object (dialog_gtkb, "import_password_dialog");
74 gtk_widget_destroy (GTK_WIDGET(widget));
75 g_object_unref (G_OBJECT(dialog_gtkb));
76
77 return password;
78 #else
79 gchar *password = NULL;
80 gchar *prompt = NULL;
81
82 printf (_("The whole selected file, or some of its elements, seems to\n"
83 "be cyphered using a password or passphrase. For importing\n"
84 "the file into gnoMint database, you must provide an \n"
85 "appropiate password.\n"));
86
87 prompt = g_strdup_printf (_("Please introduce password for `%s'"), crypted_part_description);
88 password = dialog_ask_for_password (prompt);
89 g_free (prompt);
90
91 return password;
92 #endif
93 }
94
95
__import_csr(gnutls_x509_crq_t * crq,gchar ** csr_dn,guint64 * id)96 gint __import_csr (gnutls_x509_crq_t *crq, gchar ** csr_dn, guint64 *id)
97 {
98 gchar * pem_csr=NULL;
99 size_t size;
100 gchar * error_msg;
101 gint result = -1;
102 gchar *aux = NULL;
103
104
105 if (csr_dn) {
106 size = 0;
107 gnutls_x509_crq_get_dn (*crq, aux, &size);
108 if (size) {
109 aux = g_new0(gchar, size);
110 gnutls_x509_crq_get_dn (*crq, aux, &size);
111 *csr_dn = g_strdup (aux);
112 g_free (aux);
113 aux = NULL;
114 }
115 }
116
117 size = 0;
118 gnutls_x509_crq_export (*crq, GNUTLS_X509_FMT_PEM, pem_csr, &size) ;
119 if (size) {
120 pem_csr = g_new0(gchar, size);
121 gnutls_x509_crq_export (*crq, GNUTLS_X509_FMT_PEM, pem_csr, &size);
122
123 }
124
125 error_msg = ca_file_insert_csr (NULL, pem_csr, NULL, id);
126
127
128 if (error_msg) {
129 gchar *message = g_strdup_printf (_("Couldn't import the certificate request. \n"
130 "The database returned this error: \n\n'%s'"),
131 error_msg);
132 dialog_error (message);
133 g_free (message);
134 } else {
135 result = 1;
136 }
137 return result;
138 }
139
__import_cert(gnutls_x509_crt_t * cert,gchar ** cert_dn,guint64 * id)140 gint __import_cert (gnutls_x509_crt_t *cert, gchar **cert_dn, guint64 *id)
141 {
142 guchar *serial_str = NULL;
143 UInt160 serial;
144 gchar * pem_cert=NULL;
145 size_t size;
146 gchar * error_msg;
147 gboolean is_ca;
148 guint is_critical;
149 gchar *aux = NULL;
150 gint result = -1;
151
152 // For inserting the cert into the database we must get:
153 // - if the certificate is a CA certificate
154 // - serial
155 // - activation time
156 // - expiration time
157
158 // Is_CA?
159 is_ca = gnutls_x509_crt_get_ca_status (*cert, &is_critical);
160 if (is_ca == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
161 is_ca = FALSE;
162
163 // Serial
164 size = 0;
165 gnutls_x509_crt_get_serial (*cert, aux, &size);
166 aux = NULL;
167 if (size) {
168 serial_str = g_new0(guchar, size);
169 gnutls_x509_crt_get_serial (*cert, serial_str, &size);
170 uint160_read (&serial, serial_str, size);
171 g_free (serial_str);
172 aux = NULL;
173 }
174
175 if (cert_dn) {
176 size = 0;
177 gnutls_x509_crt_get_dn (*cert, aux, &size);
178 if (size) {
179 aux = g_new0(gchar, size);
180 gnutls_x509_crt_get_dn (*cert, aux, &size);
181 *cert_dn = g_strdup (aux);
182 g_free (aux);
183 aux = NULL;
184 }
185 }
186
187
188 // Now we re-export the PEM (as the original PEM can be a list of certs)
189 size = 0;
190 gnutls_x509_crt_export (*cert, GNUTLS_X509_FMT_PEM, aux, &size);
191 if (size) {
192 aux = g_new0(gchar, size);
193 gnutls_x509_crt_export (*cert, GNUTLS_X509_FMT_PEM, aux, &size);
194 pem_cert = g_strdup (aux);
195 g_free (aux);
196 aux = NULL;
197 }
198
199 error_msg = ca_file_insert_imported_cert (is_ca, serial, pem_cert, id);
200
201 if (pem_cert)
202 g_free (pem_cert);
203
204
205 if (error_msg) {
206 gchar *message = g_strdup_printf (_("Couldn't import the certificate. \n"
207 "The database returned this error: \n\n'%s'"),
208 error_msg);
209 dialog_error (message);
210 g_free (message);
211 } else {
212 result = 1;
213 }
214
215 return result;
216 }
217
__import_crl(gnutls_x509_crl_t * crl)218 gint __import_crl (gnutls_x509_crl_t *crl)
219 {
220 gint result = -1;
221 gnutls_x509_crt_t issuer_crt;
222 gsize size = 0;
223 gchar *issuer_dn = NULL;
224 gchar *cert_pem = NULL;
225 guint64 issuer_id;
226 gnutls_datum_t file_datum;
227
228
229 size = 0;
230 gnutls_x509_crl_get_issuer_dn (*crl, issuer_dn, &size) ;
231 if (size) {
232 issuer_dn = g_new0(gchar, size);
233 gnutls_x509_crl_get_issuer_dn (*crl, issuer_dn, &size);
234 }
235
236 // First, we search the issuer in the database, using DN
237 if (ca_file_get_id_from_dn (CA_FILE_ELEMENT_TYPE_CERT, issuer_dn, &issuer_id)) {
238
239 // We check if the supposed issuer is the actual issuer
240 cert_pem = ca_file_get_public_pem_from_id (CA_FILE_ELEMENT_TYPE_CERT, issuer_id);
241
242 if (gnutls_x509_crt_init (&issuer_crt) < 0) {
243 g_free (issuer_dn);
244 g_free (cert_pem);
245 return result;
246 }
247
248 file_datum.data = (guchar *) cert_pem;
249 file_datum.size = strlen(cert_pem);
250
251 if (gnutls_x509_crt_import (issuer_crt, &file_datum, GNUTLS_X509_FMT_PEM) == GNUTLS_E_SUCCESS) {
252
253 if (gnutls_x509_crl_check_issuer (*crl, issuer_crt)) {
254 int number_of_certs;
255 int i;
256
257 // If it is, we recover all the certificates
258 number_of_certs = gnutls_x509_crl_get_crt_count(*crl);
259
260 for (i=0; i<number_of_certs; i++) {
261 guchar *serialcrt = NULL;
262 UInt160 serial;
263 time_t revocation = 0;
264
265 // We look up each of the certificates in the crl
266
267 size = 0;
268 gnutls_x509_crl_get_crt_serial (*crl, i, serialcrt, &size, &revocation);
269 if (size) {
270 guint64 cert_id;
271
272 serialcrt = g_new0 (guchar, size);
273 gnutls_x509_crl_get_crt_serial (*crl, i, serialcrt, &size, &revocation);
274 uint160_read (&serial, serialcrt, size);
275 g_free (serialcrt);
276 serialcrt = NULL;
277
278 if (ca_file_get_id_from_serial_issuer_id (&serial, issuer_id, &cert_id)) {
279 // If found, we revoke it with the correct date
280 ca_file_revoke_crt_with_date (cert_id, revocation);
281 result = 1;
282 }
283 }
284 }
285
286 }
287 }
288
289 gnutls_x509_crt_deinit (issuer_crt);
290 }
291 return result;
292 }
293
import_csr(guchar * file_contents,gsize file_contents_size,gchar ** csr_dn,guint64 * id)294 gint import_csr (guchar *file_contents, gsize file_contents_size, gchar **csr_dn, guint64 *id)
295 {
296 gnutls_x509_crq_t crq;
297 gnutls_datum_t file_datum;
298 gint result = 0;
299
300 file_datum.data = file_contents;
301 file_datum.size = file_contents_size;
302
303 // Trying to import a Certificate Signing Request
304
305 if (gnutls_x509_crq_init (&crq) < 0)
306 return result;
307
308 if (gnutls_x509_crq_import (crq, &file_datum, GNUTLS_X509_FMT_PEM) == 0 ||
309 gnutls_x509_crq_import (crq, &file_datum, GNUTLS_X509_FMT_DER) == 0) {
310
311 result = __import_csr (&crq, csr_dn, id);
312 }
313
314 gnutls_x509_crq_deinit (crq);
315
316 return result;
317
318 }
319
320
import_certlist(guchar * file_contents,gsize file_contents_size,gchar ** cert_dn,guint64 * id)321 gint import_certlist (guchar *file_contents, gsize file_contents_size, gchar **cert_dn, guint64 *id)
322 {
323 gnutls_x509_crt_t cert;
324 gnutls_x509_crt_t *certs = NULL;
325 gnutls_datum_t file_datum;
326 guint num_certs = 0;
327 gint result = 0;
328
329 file_datum.size = file_contents_size;
330 file_datum.data = file_contents;
331
332
333 // Trying to import a list of certificates in PEM format
334 gnutls_x509_crt_list_import (NULL, &num_certs, &file_datum, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
335
336 certs = g_new0 (gnutls_x509_crt_t, num_certs);
337
338 if (gnutls_x509_crt_list_import (certs, &num_certs, &file_datum, GNUTLS_X509_FMT_PEM, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED) > 0) {
339
340 int i;
341
342 // We go through all the certificates in inverse
343 // order, as it's usual having a list of certificates conforming a
344 // certification path, with the root CA certificate as the last
345 // certificate
346 result = -1;
347 for (i = num_certs - 1; i>=0; i--) {
348 if (cert_dn && *cert_dn) {
349 g_free (*cert_dn);
350 *cert_dn = NULL;
351 }
352 if (__import_cert (&certs[i], cert_dn, id) > 0)
353 result = 1;
354 }
355
356 g_free (certs);
357
358 return result;
359 }
360
361 // Trying to import a single certificate in DER format
362
363 if (gnutls_x509_crt_init (&cert) < 0)
364 return 0;
365
366 if (gnutls_x509_crt_import (cert, &file_datum, GNUTLS_X509_FMT_DER) == 0) {
367 result = __import_cert (&cert, cert_dn, id);
368 }
369
370 gnutls_x509_crt_deinit (cert);
371
372 return result;
373 }
374
import_pkey_wo_passwd(guchar * file_contents,gsize file_contents_size)375 gint import_pkey_wo_passwd (guchar *file_contents, gsize file_contents_size)
376 {
377 gint result = 0;
378 gnutls_x509_privkey_t privkey;
379 gnutls_datum_t file_datum;
380 gchar *result_import;
381
382 file_datum.data = file_contents;
383 file_datum.size = file_contents_size;
384
385 // Trying to import a Private Key in PEM format
386
387 if (gnutls_x509_privkey_init (&privkey) < 0)
388 return 0;
389
390 // Trying to import a Private Key in DER format
391
392 if (gnutls_x509_privkey_import (privkey, &file_datum, GNUTLS_X509_FMT_PEM) == 0 ||
393 gnutls_x509_privkey_import (privkey, &file_datum, GNUTLS_X509_FMT_DER) == 0) {
394 gchar * pem_privkey=NULL;
395 size_t size;
396 result = -1;
397
398 size = 0;
399 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size) ;
400 if (size) {
401 pem_privkey = g_new0(gchar, size);
402 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size);
403
404 }
405
406 result_import = ca_file_insert_imported_privkey (pem_privkey);
407 if (result_import) {
408 dialog_error (result_import);
409 } else {
410 result = 1;
411 }
412 g_free (pem_privkey);
413
414 }
415
416 gnutls_x509_privkey_deinit (privkey);
417
418 return result;
419 }
420
import_crl(guchar * file_contents,gsize file_contents_size)421 gint import_crl (guchar *file_contents, gsize file_contents_size)
422 {
423 gint result = 0;
424 gnutls_x509_crl_t crl;
425 gnutls_datum_t file_datum;
426
427 file_datum.data = file_contents;
428 file_datum.size = file_contents_size;
429
430 // Trying to import a Certificate Revocation List in PEM format
431
432 if (gnutls_x509_crl_init (&crl) < 0)
433 return 0;
434
435 if (gnutls_x509_crl_import (crl, &file_datum, GNUTLS_X509_FMT_PEM) != 0 &&
436 gnutls_x509_crl_import (crl, &file_datum, GNUTLS_X509_FMT_DER) != 0) {
437 // The given file is not a DER-coded CRL, neither a PEM-coded CRL
438
439 gnutls_x509_crl_deinit (crl);
440 return 0;
441 }
442
443 result = __import_crl (&crl);
444
445 gnutls_x509_crl_deinit (crl);
446
447 return result;
448 }
449
450 /* PKCS#7 importing was removed in libgnutls 2.6.0 */
451
452 /* gint import_pkcs7 (guchar *file_contents, gsize file_contents_size) */
453 /* { */
454 /* gboolean successful_import = FALSE; */
455 /* gnutls_pkcs7_t pkcs7; */
456 /* gnutls_datum_t file_datum; */
457
458 /* file_datum.data = file_contents; */
459 /* file_datum.size = file_contents_size; */
460
461 /* // Trying to import a Private Key in PEM format */
462
463 /* if (gnutls_pkcs7_init (&pkcs7) < 0) */
464 /* return FALSE; */
465
466 /* // Trying to import a Private Key in DER format */
467
468 /* if (gnutls_pkcs7_import (pkcs7, &file_datum, GNUTLS_X509_FMT_PEM) == 0 || */
469 /* gnutls_pkcs7_import (pkcs7, &file_datum, GNUTLS_X509_FMT_DER) == 0) { */
470 /* int i; */
471 /* int certs_no = gnutls_pkcs7_get_crt_count (pkcs7); */
472 /* int crl_no = gnutls_pkcs7_get_crl_count (pkcs7); */
473
474 /* for (i=0; i < certs_no; i++) { */
475 /* guchar *raw_cert = NULL; */
476 /* gsize raw_cert_size = 0; */
477
478 /* gnutls_pkcs7_get_crt_raw (pkcs7, i, raw_cert, &raw_cert_size); */
479
480 /* raw_cert = g_new0(guchar, raw_cert_size); */
481 /* gnutls_pkcs7_get_crt_raw (pkcs7, i, raw_cert, &raw_cert_size); */
482
483 /* import_certlist (raw_cert, raw_cert_size); */
484
485 /* g_free (raw_cert); */
486 /* } */
487
488 /* for (i=0; i < crl_no; i++) { */
489 /* guchar *raw_crl = NULL; */
490 /* gsize raw_crl_size = 0; */
491
492 /* gnutls_pkcs7_get_crl_raw (pkcs7, i, raw_crl, &raw_crl_size); */
493
494 /* raw_crl = g_new0(guchar, raw_crl_size); */
495 /* gnutls_pkcs7_get_crl_raw (pkcs7, i, raw_crl, &raw_crl_size); */
496
497 /* import_crl (raw_crl, raw_crl_size); */
498
499 /* g_free (raw_crl); */
500 /* } */
501
502 /* successful_import = TRUE; */
503 /* } */
504
505 /* gnutls_pkcs7_deinit (pkcs7); */
506
507 /* return successful_import; */
508 /* } */
509
import_pkcs8(guchar * file_contents,gsize file_contents_size)510 gint import_pkcs8 (guchar *file_contents, gsize file_contents_size)
511 {
512 gint result = 0;
513 gnutls_x509_privkey_t privkey;
514 gnutls_datum_t file_datum;
515
516 file_datum.data = file_contents;
517 file_datum.size = file_contents_size;
518
519 // Trying to import a Private Key in PEM format
520
521 if (gnutls_x509_privkey_init (&privkey) < 0)
522 return 0;
523
524 // Trying to import a Private Key in DER format
525
526 if (gnutls_x509_privkey_import_pkcs8 (privkey, &file_datum, GNUTLS_X509_FMT_PEM, NULL, GNUTLS_PKCS_PLAIN) == 0 ||
527 gnutls_x509_privkey_import_pkcs8 (privkey, &file_datum, GNUTLS_X509_FMT_DER, NULL, GNUTLS_PKCS_PLAIN) == 0) {
528 result = -1;
529 gchar * pem_privkey=NULL;
530 gchar * error_msg = NULL;
531 size_t size;
532
533 size = 0;
534 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size) ;
535 if (size) {
536 pem_privkey = g_new0(gchar, size);
537 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size);
538
539 }
540
541 error_msg = ca_file_insert_imported_privkey (pem_privkey);
542 if (error_msg) {
543 dialog_error (error_msg);
544 } else {
545 result = 1;
546 }
547
548 g_free (pem_privkey);
549
550 } else {
551 // Now we check if the given file is a PEM codified encrypted private key: while trying to import,
552 // the password won't be correct.
553
554 gint result_decryption = gnutls_x509_privkey_import_pkcs8 (privkey, &file_datum, GNUTLS_X509_FMT_PEM, NULL, 0);
555
556 while (result_decryption==GNUTLS_E_DECRYPTION_FAILED) {
557
558 // We mark a successful import, as it is a PKCS#8 cyphered file: it must not be probed with other formats.
559 result = -1;
560
561 // We launch a window for asking the password.
562 gchar * password = __import_ask_password (_("PKCS#8 crypted private key"));
563
564 if (! password) {
565 gnutls_x509_privkey_deinit (privkey);
566 return result;
567 }
568
569 result_decryption = gnutls_x509_privkey_import_pkcs8 (privkey, &file_datum, GNUTLS_X509_FMT_PEM, password, 0);
570 g_free (password);
571
572 if (result_decryption == GNUTLS_E_DECRYPTION_FAILED) {
573 dialog_error (_("The given password doesn't match the one used for crypting this part"));
574 }
575 }
576
577 if (result_decryption == GNUTLS_E_SUCCESS) {
578 gchar * pem_privkey=NULL;
579 size_t size;
580 gchar * error_msg = NULL;
581
582 result = -1;
583
584 size = 0;
585 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size) ;
586 if (size) {
587 pem_privkey = g_new0(gchar, size);
588 gnutls_x509_privkey_export (privkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size);
589
590 }
591
592 error_msg = ca_file_insert_imported_privkey (pem_privkey);
593 if (error_msg) {
594 dialog_error (error_msg);
595 } else {
596 result = 1;
597 }
598 g_free (pem_privkey);
599 }
600
601 // Importing DER-codified encrypted private keys is not supported, as they cannot be probed without
602 // a password.
603 }
604
605 gnutls_x509_privkey_deinit (privkey);
606
607 return result;
608 }
609
import_pkcs12(guchar * file_contents,gsize file_contents_size)610 gint import_pkcs12 (guchar *file_contents, gsize file_contents_size)
611 {
612 gint result = 0;
613 gnutls_pkcs12_t pkcs12;
614 gnutls_datum_t file_datum;
615
616 file_datum.data = file_contents;
617 file_datum.size = file_contents_size;
618
619 // Trying to import a Private Key in PEM format
620
621 if (gnutls_pkcs12_init (&pkcs12) < 0)
622 return result;
623
624 // Trying to import a PKCS#12 in PEM or DER format
625 if (gnutls_pkcs12_import (pkcs12, &file_datum, GNUTLS_X509_FMT_PEM, 0) == 0 ||
626 gnutls_pkcs12_import (pkcs12, &file_datum, GNUTLS_X509_FMT_DER, 0) == 0) {
627 guint n_bags = 0;
628 gnutls_pkcs12_bag_t *pkcs12_aux_bag = NULL;
629 GArray *pkcs_bag_array = g_array_new (FALSE, TRUE, sizeof(gnutls_pkcs12_bag_t));
630 gint get_bag_status;
631 gchar *password = NULL;
632 guint i;
633
634 result = -1;
635
636 // Now, we walk through all the bags in the PKCS12 structure
637 // inserting them into an array for walking through them afterwards
638 do {
639 pkcs12_aux_bag = g_new0 (gnutls_pkcs12_bag_t, 1);
640 gnutls_pkcs12_bag_init (pkcs12_aux_bag);
641
642 get_bag_status = gnutls_pkcs12_get_bag (pkcs12, n_bags, *pkcs12_aux_bag);
643
644 if (get_bag_status == GNUTLS_E_SUCCESS) {
645 g_array_append_val (pkcs_bag_array, pkcs12_aux_bag);
646 n_bags ++;
647 } else {
648 gnutls_pkcs12_bag_deinit (*pkcs12_aux_bag);
649 g_free (pkcs12_aux_bag);
650 }
651
652 } while (get_bag_status == GNUTLS_E_SUCCESS);
653
654 if (n_bags == 0) {
655 // Couldn't get any bag.
656 // Exiting with error
657 gnutls_pkcs12_deinit (pkcs12);
658 return result;
659 }
660
661
662 // Now, we first uncrypt all crypted bags
663 for (i=0; i<n_bags; i++) {
664 if (gnutls_pkcs12_bag_get_type (* g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i), 0) == GNUTLS_BAG_ENCRYPTED) {
665 gboolean pkcs12_bag_decrypted = FALSE;
666 if (! password)
667 password = __import_ask_password (_("Encrypted PKCS#12 bag"));
668
669 if (! password) {
670 // The user cancelled the operation
671 for (i=0; i<n_bags; i++) {
672 gnutls_pkcs12_bag_deinit (* g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i));
673 g_free (g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i));
674 gnutls_pkcs12_deinit (pkcs12);
675 g_array_free (pkcs_bag_array, TRUE);
676 return result;
677 }
678 }
679
680 pkcs12_bag_decrypted = ! (gnutls_pkcs12_bag_decrypt (* g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i),
681 password));
682 if (!pkcs12_bag_decrypted) {
683 gint j;
684 dialog_error (_("The given password doesn't match with the password used for encrypting this part."));
685 for (j=0; j<n_bags; j++) {
686 gnutls_pkcs12_bag_deinit (* g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, j));
687 g_free (g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, j));
688 }
689 gnutls_pkcs12_deinit (pkcs12);
690 g_array_free (pkcs_bag_array, TRUE);
691 return result;
692 }
693 }
694 }
695
696 // After having all the parts unencrypted, we import all certificates first.
697 for (i=0; i<n_bags; i++) {
698 gnutls_pkcs12_bag_t * pkcs12_bag = g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i);
699 guint num_elements_in_bag = gnutls_pkcs12_bag_get_count (*pkcs12_bag);
700
701 for (i=0; i < num_elements_in_bag; i++) {
702 gnutls_datum data;
703 if (gnutls_pkcs12_bag_get_type (*pkcs12_bag, i) == GNUTLS_BAG_CERTIFICATE) {
704 gnutls_x509_crt cert;
705
706 gnutls_x509_crt_init (&cert);
707 if (gnutls_pkcs12_bag_get_data(*pkcs12_bag, i, &data) < 0) {
708 gnutls_x509_crt_deinit (cert);
709 continue;
710 }
711 if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_DER) < 0) {
712 gnutls_x509_crt_deinit (cert);
713 continue;
714 }
715 __import_cert (& cert, NULL, NULL);
716
717 gnutls_x509_crt_deinit (cert);
718 }
719 }
720 }
721
722
723 // Then, we import all PKCS8 private keys.
724 for (i=0; i<n_bags; i++) {
725 gnutls_pkcs12_bag_t * pkcs12_bag = g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i);
726 guint num_elements_in_bag = gnutls_pkcs12_bag_get_count (*pkcs12_bag);
727
728 for (i=0; i < num_elements_in_bag; i++) {
729 gnutls_datum data;
730 if (gnutls_pkcs12_bag_get_type (*pkcs12_bag, i) == GNUTLS_BAG_PKCS8_KEY ||
731 gnutls_pkcs12_bag_get_type (*pkcs12_bag, i) == GNUTLS_BAG_PKCS8_ENCRYPTED_KEY) {
732 gnutls_x509_privkey pkey;
733 gint result_decryption;
734
735 gnutls_x509_privkey_init (&pkey);
736 if (gnutls_pkcs12_bag_get_data(*pkcs12_bag, i, &data) < 0) {
737 gnutls_x509_privkey_deinit (pkey);
738 continue;
739 }
740
741 result_decryption = gnutls_x509_privkey_import_pkcs8(pkey, &data, GNUTLS_X509_FMT_DER, password, 0);
742 if (result_decryption < 0) {
743 while (result_decryption==GNUTLS_E_DECRYPTION_FAILED) {
744 if (password)
745 g_free (password);
746
747 // We launch a window for asking the password.
748 password = __import_ask_password (_("PKCS#8 crypted private key"));
749
750 if (! password) {
751 break;
752 }
753
754 result_decryption = gnutls_x509_privkey_import_pkcs8 (pkey, &data, GNUTLS_X509_FMT_DER,
755 password, 0);
756
757 if (result_decryption == GNUTLS_E_DECRYPTION_FAILED) {
758 dialog_error (_("The given password doesn't match the one used "
759 "for crypting this part"));
760 }
761 }
762 if (result_decryption < 0) {
763 // The user pressed "Cancel" button, or
764 // the decryption has failed
765 gnutls_x509_privkey_deinit (pkey);
766 continue;
767 }
768 }
769 if (result_decryption == GNUTLS_E_SUCCESS) {
770 gchar * pem_privkey=NULL;
771 size_t size;
772 gchar * error_msg = NULL;
773
774 result = -1;
775
776 size = 0;
777 gnutls_x509_privkey_export (pkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size) ;
778 if (size) {
779 pem_privkey = g_new0(gchar, size);
780 gnutls_x509_privkey_export (pkey, GNUTLS_X509_FMT_PEM, pem_privkey, &size);
781
782 }
783
784 error_msg = ca_file_insert_imported_privkey (pem_privkey);
785 if (error_msg) {
786 dialog_error (error_msg);
787 } else {
788 result = 1;
789 }
790 g_free (pem_privkey);
791 gnutls_x509_privkey_deinit (pkey);
792 }
793 }
794 }
795 }
796 // Then we import the CRLs
797
798 for (i=0; i<n_bags; i++) {
799 gnutls_pkcs12_bag_t * pkcs12_bag = g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i);
800 guint num_elements_in_bag = gnutls_pkcs12_bag_get_count (*pkcs12_bag);
801
802 for (i=0; i < num_elements_in_bag; i++) {
803 gnutls_datum data;
804 if (gnutls_pkcs12_bag_get_type (*pkcs12_bag, i) == GNUTLS_BAG_CRL) {
805 gnutls_x509_crl crl;
806
807 gnutls_x509_crl_init (&crl);
808 if (gnutls_pkcs12_bag_get_data(*pkcs12_bag, i, &data) < 0) {
809 gnutls_x509_crl_deinit (crl);
810 continue;
811 }
812 if (gnutls_x509_crl_import(crl, &data, GNUTLS_X509_FMT_DER) < 0) {
813 gnutls_x509_crl_deinit (crl);
814 continue;
815 }
816 __import_crl (& crl);
817
818 gnutls_x509_crl_deinit (crl);
819 }
820 }
821 }
822
823 // Ok. Now we free all the bags
824 for (i=0; i<n_bags; i++) {
825 gnutls_pkcs12_bag_deinit (* g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i));
826 g_free (g_array_index (pkcs_bag_array, gnutls_pkcs12_bag_t *, i));
827 }
828 g_array_free (pkcs_bag_array, TRUE);
829
830 }
831
832 gnutls_pkcs12_deinit (pkcs12);
833
834 return result;
835 }
836
import_single_file(gchar * filename,gchar ** dn,guint64 * id)837 gboolean import_single_file (gchar *filename, gchar **dn, guint64 *id)
838 {
839 gboolean successful_import = FALSE;
840 GError *error = NULL;
841 guchar *file_contents = NULL;
842 gsize file_contents_size = 0;
843
844 GMappedFile * mapped_file = g_mapped_file_new (filename, FALSE, &error);
845
846 if (error) {
847 dialog_error (_(error->message));
848 return FALSE;
849 }
850
851 file_contents_size = g_mapped_file_get_length (mapped_file);
852 file_contents = g_new0 (guchar, file_contents_size);
853 memcpy (file_contents, g_mapped_file_get_contents (mapped_file), file_contents_size);
854
855 g_mapped_file_free (mapped_file);
856
857
858 // We start to check each type of file, in PEM and DER
859 // formats, for see if some of them matches with the actual file
860
861
862 // Certificate request
863 successful_import = import_csr (file_contents, file_contents_size, dn, id);
864
865 // Certificate list (or single certificate)
866 if (! successful_import)
867 successful_import = import_certlist (file_contents, file_contents_size, dn, id);
868
869 // Private key without password
870 if (! successful_import)
871 successful_import = import_pkey_wo_passwd (file_contents, file_contents_size);
872
873 // Certificate revocation list
874 if (! successful_import)
875 successful_import = import_crl (file_contents, file_contents_size);
876
877 /* PKCS7 importing was removed in libgnutls 2.6.0 */
878 /* // PKCS7 structure */
879 /* if (! successful_import) */
880 /* successful_import = import_pkcs7 (file_contents, file_contents_size); */
881
882 // PKCS12 structure
883 if (! successful_import)
884 successful_import = import_pkcs12 (file_contents, file_contents_size);
885
886 // PKCS8 privkey structure
887 if (! successful_import)
888 successful_import = import_pkcs8 (file_contents, file_contents_size);
889
890 g_free (file_contents);
891
892 if (successful_import) {
893 dialog_refresh_list();
894 } else {
895 dialog_error (_("Couldn't find any supported format in the given file"));
896 }
897
898 return TRUE;
899
900 }
901
import_openssl_private_key(const gchar * filename,gchar ** last_password,gchar * file_description)902 gint import_openssl_private_key (const gchar *filename, gchar **last_password, gchar *file_description)
903 {
904 guint result = 0;
905 gchar *filecontents = NULL;
906
907 if (! g_file_get_contents (filename, &filecontents, NULL, NULL)) {
908 gchar *message = g_strdup_printf(_("Couldn't open %s file. Check permissions."), filename);
909 dialog_error (message);
910 g_free (message);
911 return result;
912 }
913 if (g_strrstr (filecontents, "Proc-Type") &&
914 g_strrstr (filecontents, "DEK-Info")) {
915 // The file is codified with a proprietary OpenSSL format
916 // so we call openssl for decoding it
917 gchar *keytype = NULL;
918 gchar *uncyphered_cakey = NULL;
919 gchar *error_message = NULL;
920 gchar *temp_pwd = NULL;
921 gint exit_status = 0;
922 GError *gerror = NULL;
923 gchar *opensslargv[7];
924 gboolean first_time = TRUE;
925
926 if (g_strrstr (filecontents, "BEGIN RSA")) {
927 keytype = "rsa";
928 }
929
930 if (g_strrstr (filecontents, "BEGIN DSA")) {
931 keytype = "dsa";
932 }
933
934 if (!keytype) {
935 gchar * message = g_strdup_printf(_("Couldn't recognize the file %s as a RSA or DSA private key."), filename);
936 dialog_error (message);
937 g_free (message);
938 g_free (filecontents);
939 return result;
940 }
941
942 do {
943 gchar *description;
944 gchar *dirname = NULL;
945
946 if (! first_time || ! *last_password) {
947 // We ask for a password only if there is no current password
948 // or if the current password has already failed.
949
950 if (file_description)
951 description = g_strdup_printf (_("Private key for %s"),file_description);
952 else
953 description = g_strdup_printf (_("Private key %s"), filename);
954 *last_password = __import_ask_password (description);
955 g_free (description);
956
957 if (*last_password == NULL) {
958 g_free (filecontents);
959 break;
960 }
961 }
962
963 temp_pwd = g_strdup_printf ("pass:%s", *last_password);
964 opensslargv[0] = "openssl";
965 opensslargv[1] = keytype;
966 opensslargv[2] = "-in";
967 opensslargv[3] = (gchar *) filename;
968 opensslargv[4] = "-passin";
969 opensslargv[5] = temp_pwd;
970 opensslargv[6] = NULL;
971
972 dirname = g_path_get_dirname (filename);
973
974 if (! g_spawn_sync (dirname,
975 opensslargv,
976 NULL,
977 G_SPAWN_SEARCH_PATH,
978 NULL,
979 NULL,
980 &uncyphered_cakey,
981 &error_message,
982 &exit_status,
983 &gerror)) {
984 // Problem while launching openssl...
985 g_free (filecontents);
986 g_free (temp_pwd);
987 g_free (dirname);
988 dialog_error (_("Problem while calling to openssl for decyphering private key."));
989 break;
990 }
991
992 g_free (dirname);
993 g_free (temp_pwd);
994
995 if (exit_status != 0) {
996 gchar *error_to_show = g_strdup_printf (_("OpenSSL has returned the following error "
997 "while trying to decypher the private key:\n\n%s"),
998 error_message);
999 dialog_error (error_to_show);
1000 g_free (error_to_show);
1001 first_time = FALSE;
1002 }
1003 } while (exit_status != 0);
1004
1005 if (* last_password == NULL || gerror) {
1006 return result;
1007 }
1008
1009 g_free (filecontents);
1010 if (error_message)
1011 g_free (error_message);
1012
1013 filecontents = uncyphered_cakey;
1014 }
1015 // Now, we import the uncyphered private key:
1016
1017 result = import_pkey_wo_passwd ((guchar *) filecontents, strlen(filecontents));
1018
1019 if (result == 1)
1020 dialog_refresh_list();
1021
1022 g_free (filecontents);
1023
1024 return result;
1025 }
1026
import_whole_dir(gchar * dirname)1027 gchar * import_whole_dir (gchar *dirname)
1028 {
1029 gchar *result = NULL;
1030 gchar *filename = NULL;
1031 const gchar *int_filename = NULL;
1032
1033 guint CA_directory_type = 0;
1034 gboolean error = FALSE;
1035 gchar *ca_password = NULL;
1036
1037 GError *gerror = NULL;
1038
1039 GDir * dir = NULL;
1040 GList * problematic_files = NULL, *cursor = NULL;
1041
1042 GHashTable *descriptions = NULL;
1043 guint64 ca_root_id;
1044
1045 gchar *filecontents = NULL;
1046
1047 UInt160 next_serial;
1048
1049 // First, we try to probe if this is really a CA-containing directory
1050
1051 // * Try to detect OpenSSL CA.pl or TinyCA
1052 {
1053 filename = g_build_filename (dirname, "cacert.pem", NULL);
1054 if (! g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
1055 error = TRUE;
1056 }
1057 g_free (filename);
1058 filename = g_build_filename (dirname, "serial", NULL);
1059 if (! g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
1060 error = TRUE;
1061 }
1062 g_free (filename);
1063 filename = g_build_filename (dirname, "certs", NULL);
1064 if (! g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1065 error = TRUE;
1066 }
1067 g_free (filename);
1068 filename = g_build_filename (dirname, "crl", NULL);
1069 if (! g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1070 error = TRUE;
1071 }
1072 g_free (filename);
1073 filename = g_build_filename (dirname, "cacert.key", NULL);
1074 if (! g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
1075 g_free (filename);
1076 filename = g_build_filename (dirname, "private", "cakey.pem", NULL);
1077 if (! g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
1078 error = TRUE;
1079 } else {
1080 if (! error)
1081 CA_directory_type = 2; // OpenSSL CA.pl
1082 }
1083 }
1084 g_free (filename);
1085
1086 if (! error && ! CA_directory_type) {
1087 CA_directory_type = 1; //TinyCA
1088 }
1089
1090 if (error) {
1091 CA_directory_type = 0;
1092 }
1093 }
1094
1095 // * Other formats... (?)
1096
1097 switch (CA_directory_type) {
1098 case 1:
1099 case 2:
1100
1101 descriptions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1102
1103 // First we import the public CA root certificate
1104 filename = g_build_filename (dirname, "cacert.pem", NULL);
1105 if (import_single_file (filename, NULL, &ca_root_id) == FALSE) {
1106 g_free (filename);
1107 result = _("There was a problem while importing the public CA root certificate");
1108 break;
1109 }
1110 g_free (filename);
1111
1112 // Now we import the private CA root-certificate private key
1113 // Usually, it is crypted in a OpenSSL proprietary format.
1114 // Let's check it:
1115 if (CA_directory_type == 1 /* TinyCA */) {
1116 filename = g_build_filename (dirname, "cacert.key", NULL);
1117 } else {
1118 /* CA_directory_type == 2 (OpenSSL's CA.pl) */
1119 filename = g_build_filename (dirname, "private", "cakey.pem", NULL);
1120 }
1121 if (import_openssl_private_key (filename, &ca_password, _("CA Root certificate")) == 0) {
1122 g_free (filename);
1123 result = _("There was a problem while importing the private key corresponding to CA root certificate");
1124 break;
1125 }
1126 g_free (filename);
1127
1128 // Now we import all the certificates emitted by the CA
1129 filename = g_build_filename (dirname, "certs", NULL);
1130 dir = g_dir_open (filename, 0, &gerror);
1131 if (! dir) {
1132 g_free (filename);
1133 result = _("There was a problem while opening the directory certs/.");
1134 } else {
1135 g_free (filename);
1136 while ((int_filename = g_dir_read_name (dir))) {
1137
1138 if (g_strrstr (int_filename, ".pem")) {
1139 gchar *description = NULL;
1140 filename = g_build_filename (dirname, "certs", int_filename, NULL);
1141 if (import_single_file ((gchar *) filename, &description, NULL) == 0) {
1142 problematic_files = g_list_append (problematic_files, g_strdup(filename));
1143 } else {
1144 if (description && ! g_hash_table_lookup (descriptions, int_filename))
1145 g_hash_table_insert (descriptions, g_strdup(int_filename), description);
1146 }
1147 g_free (filename);
1148 }
1149 }
1150 g_dir_close (dir);
1151 }
1152 filename = g_build_filename (dirname, "newcerts", NULL);
1153 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1154 dir = g_dir_open (filename, 0, &gerror);
1155 if (! dir) {
1156 g_free (filename);
1157 result = _("There was a problem while opening the directory newcerts/.");
1158 } else {
1159 g_free (filename);
1160 while ((int_filename = g_dir_read_name (dir))) {
1161
1162 if (g_strrstr (int_filename, ".pem")) {
1163 gchar *description = NULL;
1164 filename = g_build_filename (dirname, "newcerts", int_filename, NULL);
1165 if (import_single_file ((gchar *) filename, &description, NULL) == 0) {
1166 problematic_files = g_list_append (problematic_files, g_strdup(filename));
1167 } else {
1168 if (description && ! g_hash_table_lookup (descriptions, int_filename))
1169 g_hash_table_insert (descriptions, g_strdup(int_filename), description);
1170 }
1171 g_free (filename);
1172 }
1173 }
1174 g_dir_close (dir);
1175 }
1176 }
1177
1178 // Now we import all the CSRs of the CA
1179 filename = g_build_filename (dirname, "req", NULL);
1180 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1181 dir = g_dir_open (filename, 0, &gerror);
1182 if (! dir) {
1183 g_free (filename);
1184 result = _("There was a problem while opening the directory req.");
1185 break;
1186 }
1187 g_free (filename);
1188 while ((int_filename = g_dir_read_name (dir))) {
1189
1190 if (g_strrstr (int_filename, ".pem")) {
1191 gchar *description = NULL;
1192 filename = g_build_filename (dirname, "req", int_filename, NULL);
1193 if (import_single_file ((gchar *) filename, &description, NULL) == 0) {
1194 problematic_files = g_list_append (problematic_files, g_strdup(filename));
1195 } else {
1196 if (description && ! g_hash_table_lookup (descriptions, int_filename))
1197 g_hash_table_insert (descriptions, g_strdup(int_filename), description);
1198 }
1199 g_free (filename);
1200 }
1201 }
1202 g_dir_close (dir);
1203 }
1204
1205 // Now we import all the CRLs of the CA
1206 filename = g_build_filename (dirname, "crl", NULL);
1207 dir = g_dir_open (filename, 0, &gerror);
1208 if (! dir) {
1209 g_free (filename);
1210 result = _("There was a problem while opening the directory crl/.");
1211 break;
1212 }
1213 g_free (filename);
1214 while ((int_filename = g_dir_read_name (dir))) {
1215
1216 if (g_strrstr (int_filename, ".pem")) {
1217 filename = g_build_filename (dirname, "crl", int_filename, NULL);
1218 if (import_single_file ((gchar *) filename, NULL, NULL) == 0) {
1219 problematic_files = g_list_append (problematic_files, g_strdup(filename));
1220 }
1221 g_free (filename);
1222 }
1223 }
1224 g_dir_close (dir);
1225
1226 // Now we import all the private keys of the CA
1227 filename = g_build_filename (dirname, "keys", NULL);
1228 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) {
1229 dir = g_dir_open (filename, 0, &gerror);
1230 if (! dir) {
1231 g_free (filename);
1232 result = _("There was a problem while opening the directory keys/.");
1233 break;
1234 }
1235 g_free (filename);
1236 while ((int_filename = g_dir_read_name (dir))) {
1237
1238 if (g_strrstr (int_filename, ".pem")) {
1239 gchar *description = NULL;
1240
1241 filename = g_build_filename (dirname, "keys", int_filename, NULL);
1242
1243 description = g_hash_table_lookup (descriptions, int_filename);
1244 if (! description)
1245 description = filename;
1246
1247 if (import_openssl_private_key (filename, &ca_password, description) == 0) {
1248 problematic_files = g_list_append (problematic_files, g_strdup(filename));
1249 }
1250 g_free (filename);
1251 }
1252 }
1253 g_dir_close (dir);
1254 }
1255
1256 // Now we import the last serial number
1257 filename = g_build_filename (dirname, "serial", NULL);
1258 if (! g_file_get_contents (filename, &filecontents, NULL, NULL)) {
1259 gchar *message = g_strdup_printf(_("Couldn't open %s file. Check permissions."), filename);
1260 dialog_error (message);
1261 g_free (message);
1262 return result;
1263 }
1264 g_free (filename);
1265
1266 if (! uint160_assign_hexstr (&next_serial, filecontents))
1267 uint160_assign (&next_serial, 1);
1268
1269 g_free (filecontents);
1270
1271 ca_file_set_next_serial (&next_serial, ca_root_id);
1272
1273
1274 // We must show the problematic files.
1275 // TO DO
1276
1277 cursor = g_list_first (problematic_files);
1278 while (cursor) {
1279 g_free (cursor->data);
1280 cursor->data = NULL;
1281 cursor = cursor->next;
1282 }
1283 g_list_free (problematic_files);
1284
1285 g_hash_table_destroy (descriptions);
1286
1287 break;
1288 case 0:
1289 default:
1290 result = _("Files in the directory don't belong to any supported CA format.");
1291 break;
1292 }
1293
1294
1295 return result;
1296 }
1297