summaryrefslogtreecommitdiff
path: root/src/pluto/certs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/certs.c')
-rw-r--r--src/pluto/certs.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/src/pluto/certs.c b/src/pluto/certs.c
new file mode 100644
index 000000000..779646a98
--- /dev/null
+++ b/src/pluto/certs.c
@@ -0,0 +1,287 @@
+/* Certificate support for IKE authentication
+ * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: certs.c,v 1.8 2005/11/06 22:55:41 as Exp $
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <freeswan.h>
+#include <ipsec_policy.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "log.h"
+#include "asn1.h"
+#include "id.h"
+#include "x509.h"
+#include "pgp.h"
+#include "pem.h"
+#include "certs.h"
+#include "pkcs1.h"
+
+/*
+ * used for initializatin of certs
+ */
+const cert_t empty_cert = {CERT_NONE, {NULL}};
+
+/*
+ * extracts the certificate to be sent to the peer
+ */
+chunk_t
+get_mycert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ return cert.u.pgp->certificate;
+ case CERT_X509_SIGNATURE:
+ return cert.u.x509->certificate;
+ default:
+ return empty_chunk;
+ }
+}
+
+/* load a coded key or certificate file with autodetection
+ * of binary DER or base64 PEM ASN.1 formats and armored PGP format
+ */
+bool
+load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
+, chunk_t *blob, bool *pgp)
+{
+ err_t ugh = NULL;
+
+ FILE *fd = fopen(filename, "r");
+
+ if (fd)
+ {
+ int bytes;
+ fseek(fd, 0, SEEK_END );
+ blob->len = ftell(fd);
+ rewind(fd);
+ blob->ptr = alloc_bytes(blob->len, type);
+ bytes = fread(blob->ptr, 1, blob->len, fd);
+ fclose(fd);
+ plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes);
+
+ *pgp = FALSE;
+
+ /* try DER format */
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in DER format");
+ )
+ return TRUE;
+ }
+
+ /* try PEM format */
+ ugh = pemtobin(blob, pass, filename, pgp);
+
+ if (ugh == NULL)
+ {
+ if (*pgp)
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in armored PGP format");
+ )
+ return TRUE;
+ }
+ if (is_asn1(*blob))
+ {
+ DBG(DBG_PARSING,
+ DBG_log(" file coded in PEM format");
+ )
+ return TRUE;
+ }
+ ugh = "file coded in unknown format, discarded";
+ }
+
+ /* a conversion error has occured */
+ plog(" %s", ugh);
+ pfree(blob->ptr);
+ *blob = empty_chunk;
+ }
+ else
+ {
+ plog(" could not open %s file '%s'", type, filename);
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a PKCS#1 or PGP private RSA key file
+ */
+err_t
+load_rsa_private_key(const char* filename, prompt_pass_t *pass
+, RSA_private_key_t *key)
+{
+ err_t ugh = NULL;
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
+
+ if (load_coded_file(path, pass, "private key", &blob, &pgp))
+ {
+ if (pgp)
+ {
+ if (!parse_pgp(blob, NULL, key))
+ ugh = "syntax error in PGP private key file";
+ }
+ else
+ {
+ if (!pkcs1_parse_private_key(blob, key))
+ ugh = "syntax error in PKCS#1 private key file";
+ }
+ pfree(blob.ptr);
+ }
+ else
+ ugh = "error loading RSA private key file";
+
+ return ugh;
+}
+/*
+ * Loads a X.509 or OpenPGP certificate
+ */
+bool
+load_cert(const char *filename, const char *label, cert_t *cert)
+{
+ bool pgp = FALSE;
+ chunk_t blob = empty_chunk;
+
+ /* initialize cert struct */
+ cert->type = CERT_NONE;
+ cert->u.x509 = NULL;
+
+ if (load_coded_file(filename, NULL, label, &blob, &pgp))
+ {
+ if (pgp)
+ {
+ pgpcert_t *pgpcert = alloc_thing(pgpcert_t, "pgpcert");
+ *pgpcert = empty_pgpcert;
+ if (parse_pgp(blob, pgpcert, NULL))
+ {
+ cert->type = CERT_PGP;
+ cert->u.pgp = pgpcert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in OpenPGP certificate");
+ free_pgpcert(pgpcert);
+ return FALSE;
+ }
+ }
+ else
+ {
+ x509cert_t *x509cert = alloc_thing(x509cert_t, "x509cert");
+ *x509cert = empty_x509cert;
+ if (parse_x509cert(blob, 0, x509cert))
+ {
+ cert->type = CERT_X509_SIGNATURE;
+ cert->u.x509 = x509cert;
+ return TRUE;
+ }
+ else
+ {
+ plog(" error in X.509 certificate");
+ free_x509cert(x509cert);
+ return FALSE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Loads a host certificate
+ */
+bool
+load_host_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(HOST_CERT_PATH, filename);
+
+ return load_cert(path, "host cert", cert);
+}
+
+/*
+ * Loads a CA certificate
+ */
+bool
+load_ca_cert(const char *filename, cert_t *cert)
+{
+ const char *path = concatenate_paths(CA_CERT_PATH, filename);
+
+ return load_cert(path, "CA cert", cert);
+}
+
+/*
+ * establish equality of two certificates
+ */
+bool
+same_cert(const cert_t *a, const cert_t *b)
+{
+ return a->type == b->type && a->u.x509 == b->u.x509;
+}
+
+/* for each link pointing to the certif icate
+ " increase the count by one
+ */
+void
+share_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ share_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ share_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/* release of a certificate decreases the count by one
+ " the certificate is freed when the counter reaches zero
+ */
+void
+release_cert(cert_t cert)
+{
+ switch (cert.type)
+ {
+ case CERT_PGP:
+ release_pgpcert(cert.u.pgp);
+ break;
+ case CERT_X509_SIGNATURE:
+ release_x509cert(cert.u.x509);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * list all X.509 and OpenPGP end certificates
+ */
+void
+list_certs(bool utc)
+{
+ list_x509_end_certs(utc);
+ list_pgp_end_certs(utc);
+}
+