streamlined file loading labels
[strongswan.git] / src / pluto / certs.c
index 92b4060..129b58c 100644 (file)
@@ -1,5 +1,7 @@
 /* Certificate support for IKE authentication
- * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
+ * Copyright (C) 2002-2009 Andreas Steffen
+ *
+ * HSR - Hochschule fuer Technik Rapperswil
  *
  * 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
  * 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 <unistd.h>
 
 #include <freeswan.h>
-#include <freeswan/ipsec_policy.h>
+
+#include "library.h"
+#include "asn1/asn1.h"
+#include "credentials/certificates/certificate.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"
+#include "whack.h"
+#include "builder.h"
 
-/*
+/**
  * used for initializatin of certs
  */
-const cert_t empty_cert = {CERT_NONE, {NULL}};
+const cert_t cert_empty = {CERT_NONE, {NULL}};
 
-/*
+/**
  * extracts the certificate to be sent to the peer
  */
-chunk_t
-get_mycert(cert_t cert)
+chunk_t cert_get_encoding(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;
-    }
+       switch (cert.type)
+       {
+       case CERT_PGP:
+               return cert.u.pgp->certificate;
+       case CERT_X509_SIGNATURE:
+               return cert.u.x509->certificate;
+       default:
+               return chunk_empty;
+       }
 }
 
-/* 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)
+public_key_t* cert_get_public_key(const cert_t cert)
 {
-    err_t ugh = NULL;
+       switch (cert.type)
+       {
+               case CERT_PGP:
+                       return cert.u.pgp->public_key;
+                       break;
+               case CERT_X509_SIGNATURE:
+                       return cert.u.x509->public_key;
+                       break;
+               default:
+                       return NULL;
+       }
+}
 
-    FILE *fd = fopen(filename, "r");
+/**
+ * Passphrase callback to read from whack fd
+ */
+chunk_t whack_pass_cb(prompt_pass_t *pass, int try)
+{
+       int n;
 
-    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);
+       if (try > MAX_PROMPT_PASS_TRIALS)
+       {
+               whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials");
+               return chunk_empty;
+       }
+       if (try == 1)
+       {
+               whack_log(RC_ENTERSECRET, "need passphrase for 'private key'");
+       }
+       else
+       {
+               whack_log(RC_ENTERSECRET, "invalid passphrase, please try again");
+       }
 
-       *pgp = FALSE;
+       n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
 
-       /* try DER format */
-       if (is_asn1(*blob))
+       if (n == -1)
        {
-           DBG(DBG_PARSING,
-               DBG_log("  file coded in DER format");
-           )
-           return TRUE;
+               whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
+               return chunk_empty;
        }
 
-       /* try PEM format */
-       ugh = pemtobin(blob, pass, filename, pgp);
+       pass->secret[n-1] = '\0';
 
-       if (ugh == NULL)
+       if (strlen(pass->secret) == 0)
        {
-           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";
+               whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted");
+               return chunk_empty;
        }
-
-       /* 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;
+       return chunk_create(pass->secret, strlen(pass->secret));
 }
 
-/*
- *  Loads a PKCS#1 or PGP private RSA key file
+/**
+ *  Loads a PKCS#1 or PGP privatekey file
  */
-err_t
-load_rsa_private_key(const char* filename, prompt_pass_t *pass
-, RSA_private_key_t *key)
+private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
+                                                               key_type_t type)
 {
-    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)
+       private_key_t *key = NULL;
+       char *path;
+       
+       path = concatenate_paths(PRIVATE_KEY_PATH, filename);
+       if (pass && pass->prompt && pass->fd != NULL_FD)
+       {       /* use passphrase callback */
+               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+                                                                BUILD_FROM_FILE, path,
+                                                                BUILD_PASSPHRASE_CALLBACK, whack_pass_cb, pass,
+                                                                BUILD_END);
+               if (key)
+               {
+                       whack_log(RC_SUCCESS, "valid passphrase");
+               }
+       }
+       else if (pass)
+       {       /* use a given passphrase */
+               chunk_t password = chunk_create(pass->secret, strlen(pass->secret));
+               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+                                                                BUILD_FROM_FILE, path,
+                                                                BUILD_PASSPHRASE, password, BUILD_END);
+       }
+       else
+       {       /* no passphrase */
+               key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
+                                                                BUILD_FROM_FILE, path, BUILD_END);
+               
+       }
+       if (key)
        {
-           if (!parse_pgp(blob, NULL, key))
-               ugh = "syntax error in PGP private key file";
+               plog("  loaded private key from '%s'", filename);
        }
        else
        {
-           if (!pkcs1_parse_private_key(blob, key))
-               ugh = "syntax error in PKCS#1 private key file";
+               plog("  syntax error in private key file");
        }
-       pfree(blob.ptr);
-    }
-    else
-       ugh = "error loading RSA private key file";
-
-    return ugh;
+       return key;
 }
-/*
+
+/**
  *  Loads a X.509 or OpenPGP certificate
  */
-bool
-load_cert(const char *filename, const char *label, cert_t *cert)
+bool load_cert(char *filename, const char *label, cert_t *out)
 {
-    bool pgp = FALSE;
-    chunk_t blob = empty_chunk;
+       cert_t *cert;
 
-    /* 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
+       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT,
+                                                         BUILD_FROM_FILE, filename, BUILD_END);
+       if (cert)
        {
-           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;
+               /* the API passes an empty cert_t, we move over and free the built one */
+               plog("  loaded %s certificate from '%s'", label, filename);
+               *out = *cert;
+               free(cert);
                return TRUE;
-           }
-           else
-           {
-               plog("  error in X.509 certificate");
-               free_x509cert(x509cert);
-               return FALSE;
-           }
        }
-    }
-    return FALSE;
+       return FALSE;
 }
 
-/*
+/**
  *  Loads a host certificate
  */
-bool
-load_host_cert(const char *filename, cert_t *cert)
+bool load_host_cert(char *filename, cert_t *cert)
 {
-    const char *path = concatenate_paths(HOST_CERT_PATH, filename);
+       char *path = concatenate_paths(HOST_CERT_PATH, filename);
 
-    return load_cert(path, "host cert", cert);
+       return load_cert(path, "host", cert);
 }
 
-/*
+/**
  *  Loads a CA certificate
  */
-bool
-load_ca_cert(const char *filename, cert_t *cert)
+bool load_ca_cert(char *filename, cert_t *cert)
 {
-    const char *path = concatenate_paths(CA_CERT_PATH, filename);
+       char *path = concatenate_paths(CA_CERT_PATH, filename);
 
-    return load_cert(path, "CA cert", cert);
+       return load_cert(path, "CA", cert);
 }
 
-/*
+/**
  * establish equality of two certificates
  */
-bool
-same_cert(const cert_t *a, const cert_t *b)
+bool same_cert(const cert_t *a, const cert_t *b)
 {
-    return a->type == b->type && a->u.x509 == b->u.x509;
+       return a->type == b->type && a->u.x509 == b->u.x509;
 }
 
-/*  for each link pointing to the certif icate
 increase the count by one
+/**
* for each link pointing to the certificate increase the count by one
  */
-void
-share_cert(cert_t cert)
+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;
-    }
+       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
@@ -263,16 +226,16 @@ 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;
-    }
+       {
+       case CERT_PGP:
+               release_pgpcert(cert.u.pgp);
+               break;
+       case CERT_X509_SIGNATURE:
+               release_x509cert(cert.u.x509);
+               break;
+       default:
+               break;
+       }
 }
 
 /*
@@ -281,7 +244,7 @@ release_cert(cert_t cert)
 void
 list_certs(bool utc)
 {
-    list_x509_end_certs(utc);
-    list_pgp_end_certs(utc);
+       list_x509_end_certs(utc);
+       list_pgp_end_certs(utc);
 }