2006-04-28 07:14:48 +00:00
|
|
|
/* Certificate support for IKE authentication
|
2009-06-05 19:14:31 +00:00
|
|
|
* Copyright (C) 2002-2009 Andreas Steffen
|
|
|
|
*
|
|
|
|
* HSR - Hochschule fuer Technik Rapperswil
|
2006-04-28 07:14:48 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2009-08-12 14:13:18 +00:00
|
|
|
#include <unistd.h>
|
2006-04-28 07:14:48 +00:00
|
|
|
|
|
|
|
#include <freeswan.h>
|
|
|
|
|
2009-06-05 19:14:31 +00:00
|
|
|
#include "library.h"
|
2009-04-20 20:53:38 +00:00
|
|
|
#include "asn1/asn1.h"
|
2009-08-13 13:05:14 +00:00
|
|
|
#include "credentials/certificates/certificate.h"
|
2009-04-20 20:53:38 +00:00
|
|
|
|
2006-04-28 07:14:48 +00:00
|
|
|
#include "constants.h"
|
|
|
|
#include "defs.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "id.h"
|
|
|
|
#include "certs.h"
|
2009-08-12 14:13:18 +00:00
|
|
|
#include "whack.h"
|
2009-08-13 08:48:22 +00:00
|
|
|
#include "builder.h"
|
2006-04-28 07:14:48 +00:00
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2006-04-28 07:14:48 +00:00
|
|
|
* used for initializatin of certs
|
|
|
|
*/
|
2009-06-06 11:13:11 +00:00
|
|
|
const cert_t cert_empty = {CERT_NONE, {NULL}};
|
2006-04-28 07:14:48 +00:00
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2006-04-28 07:14:48 +00:00
|
|
|
* extracts the certificate to be sent to the peer
|
|
|
|
*/
|
2009-06-06 11:13:11 +00:00
|
|
|
chunk_t cert_get_encoding(cert_t cert)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-04-19 19:16:09 +00:00
|
|
|
switch (cert.type)
|
|
|
|
{
|
|
|
|
case CERT_PGP:
|
2009-09-27 21:09:30 +00:00
|
|
|
return chunk_clone(cert.u.pgp->certificate);
|
2009-04-19 19:16:09 +00:00
|
|
|
case CERT_X509_SIGNATURE:
|
2009-09-27 21:09:30 +00:00
|
|
|
return cert.u.x509->cert->get_encoding(cert.u.x509->cert);
|
2009-04-19 19:16:09 +00:00
|
|
|
default:
|
|
|
|
return chunk_empty;
|
|
|
|
}
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-06-06 11:13:11 +00:00
|
|
|
public_key_t* cert_get_public_key(const cert_t cert)
|
|
|
|
{
|
|
|
|
switch (cert.type)
|
|
|
|
{
|
|
|
|
case CERT_PGP:
|
2009-09-27 21:09:30 +00:00
|
|
|
{
|
|
|
|
public_key_t *public_key = cert.u.pgp->public_key;
|
|
|
|
|
|
|
|
return public_key->get_ref(public_key);
|
|
|
|
}
|
2009-06-06 11:13:11 +00:00
|
|
|
case CERT_X509_SIGNATURE:
|
2009-09-27 21:09:30 +00:00
|
|
|
{
|
|
|
|
certificate_t *certificate = cert.u.x509->cert;
|
|
|
|
|
|
|
|
return certificate->get_public_key(certificate);
|
|
|
|
}
|
2009-06-06 11:13:11 +00:00
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-12 14:13:18 +00:00
|
|
|
/**
|
|
|
|
* Passphrase callback to read from whack fd
|
|
|
|
*/
|
|
|
|
chunk_t whack_pass_cb(prompt_pass_t *pass, int try)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
n = read(pass->fd, pass->secret, PROMPT_PASS_LEN);
|
|
|
|
|
|
|
|
if (n == -1)
|
|
|
|
{
|
|
|
|
whack_log(RC_LOG_SERIOUS, "read(whackfd) failed");
|
|
|
|
return chunk_empty;
|
|
|
|
}
|
|
|
|
|
|
|
|
pass->secret[n-1] = '\0';
|
|
|
|
|
|
|
|
if (strlen(pass->secret) == 0)
|
|
|
|
{
|
|
|
|
whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted");
|
|
|
|
return chunk_empty;
|
|
|
|
}
|
|
|
|
return chunk_create(pass->secret, strlen(pass->secret));
|
|
|
|
}
|
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2009-08-26 20:25:24 +00:00
|
|
|
* Loads a PKCS#1 or PGP private key file
|
2006-04-28 07:14:48 +00:00
|
|
|
*/
|
2009-06-05 19:14:31 +00:00
|
|
|
private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
|
|
|
|
key_type_t type)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-06-05 19:14:31 +00:00
|
|
|
private_key_t *key = NULL;
|
2009-08-12 14:13:18 +00:00
|
|
|
char *path;
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-12 14:13:18 +00:00
|
|
|
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)
|
2009-04-19 19:16:09 +00:00
|
|
|
{
|
2009-08-12 14:13:18 +00:00
|
|
|
whack_log(RC_SUCCESS, "valid passphrase");
|
2009-04-19 19:16:09 +00:00
|
|
|
}
|
2009-08-12 14:13:18 +00:00
|
|
|
}
|
|
|
|
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);
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
else
|
2009-08-12 14:13:18 +00:00
|
|
|
{ /* no passphrase */
|
|
|
|
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
|
|
|
|
BUILD_FROM_FILE, path, BUILD_END);
|
2009-09-04 11:46:09 +00:00
|
|
|
|
2009-08-12 14:13:18 +00:00
|
|
|
}
|
2009-08-13 15:14:41 +00:00
|
|
|
if (key)
|
|
|
|
{
|
2009-08-26 20:02:00 +00:00
|
|
|
plog(" loaded private key from '%s'", filename);
|
2009-08-13 15:14:41 +00:00
|
|
|
}
|
|
|
|
else
|
2009-06-05 19:14:31 +00:00
|
|
|
{
|
2009-08-12 14:13:18 +00:00
|
|
|
plog(" syntax error in private key file");
|
2009-06-05 19:14:31 +00:00
|
|
|
}
|
|
|
|
return key;
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
2009-04-20 20:53:38 +00:00
|
|
|
|
2009-08-12 15:27:15 +00:00
|
|
|
/**
|
|
|
|
* Loads a X.509 or OpenPGP certificate
|
|
|
|
*/
|
2009-08-13 08:48:22 +00:00
|
|
|
bool load_cert(char *filename, const char *label, cert_t *out)
|
2009-08-12 15:27:15 +00:00
|
|
|
{
|
2009-08-13 08:48:22 +00:00
|
|
|
cert_t *cert;
|
2009-08-12 15:27:15 +00:00
|
|
|
|
2009-08-13 13:05:14 +00:00
|
|
|
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT,
|
2009-08-12 15:27:15 +00:00
|
|
|
BUILD_FROM_FILE, filename, BUILD_END);
|
|
|
|
if (cert)
|
|
|
|
{
|
2009-08-13 12:18:58 +00:00
|
|
|
/* the API passes an empty cert_t, we move over and free the built one */
|
2009-08-26 20:02:00 +00:00
|
|
|
plog(" loaded %s certificate from '%s'", label, filename);
|
2009-08-13 08:48:22 +00:00
|
|
|
*out = *cert;
|
2009-08-13 12:18:58 +00:00
|
|
|
free(cert);
|
2009-08-12 15:27:15 +00:00
|
|
|
return TRUE;
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
2009-04-19 19:16:09 +00:00
|
|
|
return FALSE;
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2006-04-28 07:14:48 +00:00
|
|
|
* Loads a host certificate
|
|
|
|
*/
|
2009-04-20 20:53:38 +00:00
|
|
|
bool load_host_cert(char *filename, cert_t *cert)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-04-20 20:53:38 +00:00
|
|
|
char *path = concatenate_paths(HOST_CERT_PATH, filename);
|
2006-04-28 07:14:48 +00:00
|
|
|
|
2009-08-26 20:02:00 +00:00
|
|
|
return load_cert(path, "host", cert);
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2006-04-28 07:14:48 +00:00
|
|
|
* Loads a CA certificate
|
|
|
|
*/
|
2009-04-20 20:53:38 +00:00
|
|
|
bool load_ca_cert(char *filename, cert_t *cert)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-04-20 20:53:38 +00:00
|
|
|
char *path = concatenate_paths(CA_CERT_PATH, filename);
|
2006-04-28 07:14:48 +00:00
|
|
|
|
2009-08-26 20:02:00 +00:00
|
|
|
return load_cert(path, "CA", cert);
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
2006-04-28 07:14:48 +00:00
|
|
|
* establish equality of two certificates
|
|
|
|
*/
|
2009-04-20 20:53:38 +00:00
|
|
|
bool same_cert(const cert_t *a, const cert_t *b)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-04-19 19:16:09 +00:00
|
|
|
return a->type == b->type && a->u.x509 == b->u.x509;
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-20 20:53:38 +00:00
|
|
|
/**
|
|
|
|
* for each link pointing to the certificate increase the count by one
|
2006-04-28 07:14:48 +00:00
|
|
|
*/
|
2009-04-20 20:53:38 +00:00
|
|
|
void share_cert(cert_t cert)
|
2006-04-28 07:14:48 +00:00
|
|
|
{
|
2009-04-19 19:16:09 +00:00
|
|
|
switch (cert.type)
|
|
|
|
{
|
|
|
|
case CERT_PGP:
|
|
|
|
share_pgpcert(cert.u.pgp);
|
|
|
|
break;
|
|
|
|
case CERT_X509_SIGNATURE:
|
|
|
|
share_x509cert(cert.u.x509);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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)
|
2009-04-19 19:16:09 +00:00
|
|
|
{
|
|
|
|
case CERT_PGP:
|
|
|
|
release_pgpcert(cert.u.pgp);
|
|
|
|
break;
|
|
|
|
case CERT_X509_SIGNATURE:
|
|
|
|
release_x509cert(cert.u.x509);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* list all X.509 and OpenPGP end certificates
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
list_certs(bool utc)
|
|
|
|
{
|
2009-04-19 19:16:09 +00:00
|
|
|
list_x509_end_certs(utc);
|
|
|
|
list_pgp_end_certs(utc);
|
2006-04-28 07:14:48 +00:00
|
|
|
}
|
|
|
|
|