moved PEM parsing functionality to its own plugin
This commit is contained in:
@@ -287,6 +287,17 @@ AC_ARG_ENABLE(
|
|||||||
pubkey=true
|
pubkey=true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(
|
||||||
|
[pem],
|
||||||
|
AS_HELP_STRING([--disable-pem],[disable PEM decoding plugin. (default is NO).]),
|
||||||
|
[if test x$enableval = xyes; then
|
||||||
|
pem=true
|
||||||
|
else
|
||||||
|
pem=false
|
||||||
|
fi],
|
||||||
|
pem=true
|
||||||
|
)
|
||||||
|
|
||||||
AC_ARG_ENABLE(
|
AC_ARG_ENABLE(
|
||||||
[hmac],
|
[hmac],
|
||||||
AS_HELP_STRING([--disable-hmac],[disable HMAC crypto implementation plugin. (default is NO).]),
|
AS_HELP_STRING([--disable-hmac],[disable HMAC crypto implementation plugin. (default is NO).]),
|
||||||
@@ -1181,6 +1192,10 @@ if test x$pubkey = xtrue; then
|
|||||||
libstrongswan_plugins=${libstrongswan_plugins}" pubkey"
|
libstrongswan_plugins=${libstrongswan_plugins}" pubkey"
|
||||||
pluto_plugins=${pluto_plugins}" pubkey"
|
pluto_plugins=${pluto_plugins}" pubkey"
|
||||||
fi
|
fi
|
||||||
|
if test x$pem = xtrue; then
|
||||||
|
libstrongswan_plugins=${libstrongswan_plugins}" pem"
|
||||||
|
pluto_plugins=${pluto_plugins}" pem"
|
||||||
|
fi
|
||||||
if test x$mysql = xtrue; then
|
if test x$mysql = xtrue; then
|
||||||
libstrongswan_plugins=${libstrongswan_plugins}" mysql"
|
libstrongswan_plugins=${libstrongswan_plugins}" mysql"
|
||||||
fi
|
fi
|
||||||
@@ -1237,6 +1252,7 @@ AM_CONDITIONAL(USE_GMP, test x$gmp = xtrue)
|
|||||||
AM_CONDITIONAL(USE_RANDOM, test x$random = xtrue)
|
AM_CONDITIONAL(USE_RANDOM, test x$random = xtrue)
|
||||||
AM_CONDITIONAL(USE_X509, test x$x509 = xtrue)
|
AM_CONDITIONAL(USE_X509, test x$x509 = xtrue)
|
||||||
AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue)
|
AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue)
|
||||||
|
AM_CONDITIONAL(USE_PEM, test x$pem = xtrue)
|
||||||
AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue)
|
AM_CONDITIONAL(USE_HMAC, test x$hmac = xtrue)
|
||||||
AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue)
|
AM_CONDITIONAL(USE_XCBC, test x$xcbc = xtrue)
|
||||||
AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
|
AM_CONDITIONAL(USE_MYSQL, test x$mysql = xtrue)
|
||||||
@@ -1331,6 +1347,7 @@ AC_OUTPUT(
|
|||||||
src/libstrongswan/plugins/xcbc/Makefile
|
src/libstrongswan/plugins/xcbc/Makefile
|
||||||
src/libstrongswan/plugins/x509/Makefile
|
src/libstrongswan/plugins/x509/Makefile
|
||||||
src/libstrongswan/plugins/pubkey/Makefile
|
src/libstrongswan/plugins/pubkey/Makefile
|
||||||
|
src/libstrongswan/plugins/pem/Makefile
|
||||||
src/libstrongswan/plugins/curl/Makefile
|
src/libstrongswan/plugins/curl/Makefile
|
||||||
src/libstrongswan/plugins/ldap/Makefile
|
src/libstrongswan/plugins/ldap/Makefile
|
||||||
src/libstrongswan/plugins/mysql/Makefile
|
src/libstrongswan/plugins/mysql/Makefile
|
||||||
|
|||||||
@@ -162,6 +162,10 @@ if USE_PUBKEY
|
|||||||
SUBDIRS += plugins/pubkey
|
SUBDIRS += plugins/pubkey
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_PEM
|
||||||
|
SUBDIRS += plugins/pem
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_CURL
|
if USE_CURL
|
||||||
SUBDIRS += plugins/curl
|
SUBDIRS += plugins/curl
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
|
|||||||
"BUILD_FROM_FILE",
|
"BUILD_FROM_FILE",
|
||||||
"BUILD_AGENT_SOCKET",
|
"BUILD_AGENT_SOCKET",
|
||||||
"BUILD_BLOB_ASN1_DER",
|
"BUILD_BLOB_ASN1_DER",
|
||||||
"BUILD_BLOB_ASN1_PEM",
|
"BUILD_BLOB_PEM",
|
||||||
"BUILD_BLOB_PGP",
|
"BUILD_BLOB_PGP",
|
||||||
"BUILD_BLOB_RFC_3110",
|
"BUILD_BLOB_RFC_3110",
|
||||||
|
"BUILD_PASSPHRASE",
|
||||||
|
"BUILD_PASSPHRASE_CALLBACK",
|
||||||
"BUILD_KEY_SIZE",
|
"BUILD_KEY_SIZE",
|
||||||
"BUILD_SIGNING_KEY",
|
"BUILD_SIGNING_KEY",
|
||||||
"BUILD_SIGNING_CERT",
|
"BUILD_SIGNING_CERT",
|
||||||
|
|||||||
@@ -44,12 +44,18 @@ enum builder_part_t {
|
|||||||
BUILD_AGENT_SOCKET,
|
BUILD_AGENT_SOCKET,
|
||||||
/** DER encoded ASN.1 blob, chunk_t */
|
/** DER encoded ASN.1 blob, chunk_t */
|
||||||
BUILD_BLOB_ASN1_DER,
|
BUILD_BLOB_ASN1_DER,
|
||||||
/** PEM encoded ASN.1 blob, null terminated char* */
|
/** PEM encoded ASN.1/PGP blob, chunk_t */
|
||||||
BUILD_BLOB_ASN1_PEM,
|
BUILD_BLOB_PEM,
|
||||||
/** OpenPGP key blob, chunk_t */
|
/** OpenPGP key blob, chunk_t */
|
||||||
BUILD_BLOB_PGP,
|
BUILD_BLOB_PGP,
|
||||||
/** RFC 3110 DNS public key blob, chunk_t */
|
/** RFC 3110 DNS public key blob, chunk_t */
|
||||||
BUILD_BLOB_RFC_3110,
|
BUILD_BLOB_RFC_3110,
|
||||||
|
/** passphrase for e.g. PEM decryption, chunk_t */
|
||||||
|
BUILD_PASSPHRASE,
|
||||||
|
/** passphrase callback, chunk_t(*fn)(void *user, int try), void *user.
|
||||||
|
* The callback is invoked until the returned passphrase is accepted, or
|
||||||
|
* a zero-length passphrase is returned. Try starts at 1. */
|
||||||
|
BUILD_PASSPHRASE_CALLBACK,
|
||||||
/** key size in bits, as used for key generation, u_int */
|
/** key size in bits, as used for key generation, u_int */
|
||||||
BUILD_KEY_SIZE,
|
BUILD_KEY_SIZE,
|
||||||
/** private key to use for signing, private_key_t* */
|
/** private key to use for signing, private_key_t* */
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
|
|||||||
builder_t *builder;
|
builder_t *builder;
|
||||||
builder_part_t part;
|
builder_part_t part;
|
||||||
va_list args;
|
va_list args;
|
||||||
void* construct = NULL;
|
void* construct = NULL, *fn, *data;
|
||||||
|
|
||||||
enumerator = create_builder_enumerator(this, type, subtype);
|
enumerator = create_builder_enumerator(this, type, subtype);
|
||||||
while (enumerator->enumerate(enumerator, &builder))
|
while (enumerator->enumerate(enumerator, &builder))
|
||||||
@@ -155,9 +155,11 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
|
|||||||
{
|
{
|
||||||
case BUILD_END:
|
case BUILD_END:
|
||||||
break;
|
break;
|
||||||
|
case BUILD_BLOB_PEM:
|
||||||
case BUILD_BLOB_ASN1_DER:
|
case BUILD_BLOB_ASN1_DER:
|
||||||
case BUILD_BLOB_PGP:
|
case BUILD_BLOB_PGP:
|
||||||
case BUILD_BLOB_RFC_3110:
|
case BUILD_BLOB_RFC_3110:
|
||||||
|
case BUILD_PASSPHRASE:
|
||||||
case BUILD_SERIAL:
|
case BUILD_SERIAL:
|
||||||
builder->add(builder, part, va_arg(args, chunk_t));
|
builder->add(builder, part, va_arg(args, chunk_t));
|
||||||
continue;
|
continue;
|
||||||
@@ -171,7 +173,6 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
|
|||||||
case BUILD_NOT_AFTER_TIME:
|
case BUILD_NOT_AFTER_TIME:
|
||||||
builder->add(builder, part, va_arg(args, time_t));
|
builder->add(builder, part, va_arg(args, time_t));
|
||||||
continue;
|
continue;
|
||||||
case BUILD_BLOB_ASN1_PEM:
|
|
||||||
case BUILD_FROM_FILE:
|
case BUILD_FROM_FILE:
|
||||||
case BUILD_AGENT_SOCKET:
|
case BUILD_AGENT_SOCKET:
|
||||||
case BUILD_SIGNING_KEY:
|
case BUILD_SIGNING_KEY:
|
||||||
@@ -188,6 +189,11 @@ static void* create(private_credential_factory_t *this, credential_type_t type,
|
|||||||
case BUILD_SMARTCARD_PIN:
|
case BUILD_SMARTCARD_PIN:
|
||||||
builder->add(builder, part, va_arg(args, void*));
|
builder->add(builder, part, va_arg(args, void*));
|
||||||
continue;
|
continue;
|
||||||
|
case BUILD_PASSPHRASE_CALLBACK:
|
||||||
|
fn = va_arg(args, void*);
|
||||||
|
data = va_arg(args, void*);
|
||||||
|
builder->add(builder, part, fn, data);
|
||||||
|
continue;
|
||||||
/* no default to get a compiler warning */
|
/* no default to get a compiler warning */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||||
|
|
||||||
|
AM_CFLAGS = -rdynamic
|
||||||
|
|
||||||
|
plugin_LTLIBRARIES = libstrongswan-pem.la
|
||||||
|
|
||||||
|
libstrongswan_pem_la_SOURCES = pem_plugin.h pem_plugin.c \
|
||||||
|
pem_builder.c pem_builder.h
|
||||||
|
|
||||||
|
libstrongswan_pem_la_LDFLAGS = -module -avoid-version
|
||||||
|
|
||||||
@@ -0,0 +1,490 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Martin Willi
|
||||||
|
* Copyright (C) 2001-2008 Andreas Steffen
|
||||||
|
* 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
|
||||||
|
* 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 "pem_builder.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
#include <library.h>
|
||||||
|
#include <utils/lexparser.h>
|
||||||
|
#include <crypto/hashers/hasher.h>
|
||||||
|
#include <crypto/crypters/crypter.h>
|
||||||
|
|
||||||
|
#define PKCS5_SALT_LEN 8 /* bytes */
|
||||||
|
|
||||||
|
typedef struct private_builder_t private_builder_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder implementation for PEM decoding
|
||||||
|
*/
|
||||||
|
struct private_builder_t {
|
||||||
|
/** implements the builder interface */
|
||||||
|
builder_t public;
|
||||||
|
/** credential type we are building */
|
||||||
|
credential_type_t type;
|
||||||
|
/** subtype (keytype, certtype) of the credential we build */
|
||||||
|
int subtype;
|
||||||
|
/** PEM encoding of the credential */
|
||||||
|
chunk_t pem;
|
||||||
|
/** PEM decryption passphrase, if given */
|
||||||
|
chunk_t passphrase;
|
||||||
|
/** supplied callback to read passphrase */
|
||||||
|
chunk_t (*cb)(void *data, int try);
|
||||||
|
/** user data to callback */
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check the presence of a pattern in a character string, skip if found
|
||||||
|
*/
|
||||||
|
static bool present(char* pattern, chunk_t* ch)
|
||||||
|
{
|
||||||
|
u_int len = strlen(pattern);
|
||||||
|
|
||||||
|
if (ch->len >= len && strneq(ch->ptr, pattern, len))
|
||||||
|
{
|
||||||
|
*ch = chunk_skip(*ch, len);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find a boundary of the form -----tag name-----
|
||||||
|
*/
|
||||||
|
static bool find_boundary(char* tag, chunk_t *line)
|
||||||
|
{
|
||||||
|
chunk_t name = chunk_empty;
|
||||||
|
|
||||||
|
if (!present("-----", line) ||
|
||||||
|
!present(tag, line) ||
|
||||||
|
*line->ptr != ' ')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*line = chunk_skip(*line, 1);
|
||||||
|
|
||||||
|
/* extract name */
|
||||||
|
name.ptr = line->ptr;
|
||||||
|
while (line->len > 0)
|
||||||
|
{
|
||||||
|
if (present("-----", line))
|
||||||
|
{
|
||||||
|
DBG2(" -----%s %.*s-----", tag, (int)name.len, name.ptr);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
line->ptr++; line->len--; name.len++;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* decrypts a passphrase protected encrypted data block
|
||||||
|
*/
|
||||||
|
static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg,
|
||||||
|
size_t key_size, chunk_t iv, chunk_t passphrase)
|
||||||
|
{
|
||||||
|
hasher_t *hasher;
|
||||||
|
crypter_t *crypter;
|
||||||
|
chunk_t salt = { iv.ptr, PKCS5_SALT_LEN };
|
||||||
|
chunk_t hash;
|
||||||
|
chunk_t decrypted;
|
||||||
|
chunk_t key = {alloca(key_size), key_size};
|
||||||
|
u_int8_t padding, *last_padding_pos, *first_padding_pos;
|
||||||
|
|
||||||
|
/* build key from passphrase and IV */
|
||||||
|
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
|
||||||
|
if (hasher == NULL)
|
||||||
|
{
|
||||||
|
DBG1(" MD5 hash algorithm not available");
|
||||||
|
return NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
hash.len = hasher->get_hash_size(hasher);
|
||||||
|
hash.ptr = alloca(hash.len);
|
||||||
|
hasher->get_hash(hasher, passphrase, NULL);
|
||||||
|
hasher->get_hash(hasher, salt, hash.ptr);
|
||||||
|
memcpy(key.ptr, hash.ptr, hash.len);
|
||||||
|
|
||||||
|
if (key.len > hash.len)
|
||||||
|
{
|
||||||
|
hasher->get_hash(hasher, hash, NULL);
|
||||||
|
hasher->get_hash(hasher, passphrase, NULL);
|
||||||
|
hasher->get_hash(hasher, salt, hash.ptr);
|
||||||
|
memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
|
||||||
|
}
|
||||||
|
hasher->destroy(hasher);
|
||||||
|
|
||||||
|
/* decrypt blob */
|
||||||
|
crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size);
|
||||||
|
if (crypter == NULL)
|
||||||
|
{
|
||||||
|
DBG1(" %N encryption algorithm not available",
|
||||||
|
encryption_algorithm_names, alg);
|
||||||
|
return NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
crypter->set_key(crypter, key);
|
||||||
|
|
||||||
|
if (iv.len != crypter->get_block_size(crypter) ||
|
||||||
|
blob->len % iv.len)
|
||||||
|
{
|
||||||
|
crypter->destroy(crypter);
|
||||||
|
DBG1(" data size is not multiple of block size");
|
||||||
|
return PARSE_ERROR;
|
||||||
|
}
|
||||||
|
crypter->decrypt(crypter, *blob, iv, &decrypted);
|
||||||
|
crypter->destroy(crypter);
|
||||||
|
memcpy(blob->ptr, decrypted.ptr, blob->len);
|
||||||
|
chunk_free(&decrypted);
|
||||||
|
|
||||||
|
/* determine amount of padding */
|
||||||
|
last_padding_pos = blob->ptr + blob->len - 1;
|
||||||
|
padding = *last_padding_pos;
|
||||||
|
if (padding > blob->len)
|
||||||
|
{
|
||||||
|
first_padding_pos = blob->ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first_padding_pos = last_padding_pos - padding;
|
||||||
|
}
|
||||||
|
/* check the padding pattern */
|
||||||
|
while (--last_padding_pos > first_padding_pos)
|
||||||
|
{
|
||||||
|
if (*last_padding_pos != padding)
|
||||||
|
{
|
||||||
|
DBG1(" invalid passphrase");
|
||||||
|
return INVALID_ARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* remove padding */
|
||||||
|
blob->len -= padding;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a PEM encoded file into its binary form (RFC 1421, RFC 934)
|
||||||
|
*/
|
||||||
|
status_t pem_to_bin(chunk_t *blob, private_builder_t *this, bool *pgp)
|
||||||
|
{
|
||||||
|
typedef enum {
|
||||||
|
PEM_PRE = 0,
|
||||||
|
PEM_MSG = 1,
|
||||||
|
PEM_HEADER = 2,
|
||||||
|
PEM_BODY = 3,
|
||||||
|
PEM_POST = 4,
|
||||||
|
PEM_ABORT = 5
|
||||||
|
} state_t;
|
||||||
|
|
||||||
|
encryption_algorithm_t alg = ENCR_UNDEFINED;
|
||||||
|
size_t key_size = 0;
|
||||||
|
bool encrypted = FALSE;
|
||||||
|
state_t state = PEM_PRE;
|
||||||
|
chunk_t src = *blob;
|
||||||
|
chunk_t dst = *blob;
|
||||||
|
chunk_t line = chunk_empty;
|
||||||
|
chunk_t iv = chunk_empty;
|
||||||
|
chunk_t passphrase;
|
||||||
|
int try = 0;
|
||||||
|
u_char iv_buf[HASH_SIZE_MD5];
|
||||||
|
|
||||||
|
dst.len = 0;
|
||||||
|
iv.ptr = iv_buf;
|
||||||
|
iv.len = 0;
|
||||||
|
|
||||||
|
while (fetchline(&src, &line))
|
||||||
|
{
|
||||||
|
if (state == PEM_PRE)
|
||||||
|
{
|
||||||
|
if (find_boundary("BEGIN", &line))
|
||||||
|
{
|
||||||
|
state = PEM_MSG;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (find_boundary("END", &line))
|
||||||
|
{
|
||||||
|
state = PEM_POST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (state == PEM_MSG)
|
||||||
|
{
|
||||||
|
state = PEM_HEADER;
|
||||||
|
if (memchr(line.ptr, ':', line.len) == NULL)
|
||||||
|
{
|
||||||
|
state = PEM_BODY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state == PEM_HEADER)
|
||||||
|
{
|
||||||
|
err_t ugh = NULL;
|
||||||
|
chunk_t name = chunk_empty;
|
||||||
|
chunk_t value = chunk_empty;
|
||||||
|
|
||||||
|
/* an empty line separates HEADER and BODY */
|
||||||
|
if (line.len == 0)
|
||||||
|
{
|
||||||
|
state = PEM_BODY;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we are looking for a parameter: value pair */
|
||||||
|
DBG2(" %.*s", (int)line.len, line.ptr);
|
||||||
|
ugh = extract_parameter_value(&name, &value, &line);
|
||||||
|
if (ugh != NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (match("Proc-Type", &name) && *value.ptr == '4')
|
||||||
|
{
|
||||||
|
encrypted = TRUE;
|
||||||
|
}
|
||||||
|
else if (match("DEK-Info", &name))
|
||||||
|
{
|
||||||
|
chunk_t dek;
|
||||||
|
|
||||||
|
if (!extract_token(&dek, ',', &value))
|
||||||
|
{
|
||||||
|
dek = value;
|
||||||
|
}
|
||||||
|
if (match("DES-EDE3-CBC", &dek))
|
||||||
|
{
|
||||||
|
alg = ENCR_3DES;
|
||||||
|
key_size = 24;
|
||||||
|
}
|
||||||
|
else if (match("AES-128-CBC", &dek))
|
||||||
|
{
|
||||||
|
alg = ENCR_AES_CBC;
|
||||||
|
key_size = 16;
|
||||||
|
}
|
||||||
|
else if (match("AES-192-CBC", &dek))
|
||||||
|
{
|
||||||
|
alg = ENCR_AES_CBC;
|
||||||
|
key_size = 24;
|
||||||
|
}
|
||||||
|
else if (match("AES-256-CBC", &dek))
|
||||||
|
{
|
||||||
|
alg = ENCR_AES_CBC;
|
||||||
|
key_size = 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(" encryption algorithm '%.s' not supported",
|
||||||
|
dek.len, dek.ptr);
|
||||||
|
return NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
eat_whitespace(&value);
|
||||||
|
iv = chunk_from_hex(value, iv.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* state is PEM_BODY */
|
||||||
|
{
|
||||||
|
chunk_t data;
|
||||||
|
|
||||||
|
/* remove any trailing whitespace */
|
||||||
|
if (!extract_token(&data ,' ', &line))
|
||||||
|
{
|
||||||
|
data = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for PGP armor checksum */
|
||||||
|
if (*data.ptr == '=')
|
||||||
|
{
|
||||||
|
*pgp = TRUE;
|
||||||
|
data.ptr++;
|
||||||
|
data.len--;
|
||||||
|
DBG2(" armor checksum: %.*s", (int)data.len, data.ptr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blob->len - dst.len < data.len / 4 * 3)
|
||||||
|
{
|
||||||
|
state = PEM_ABORT;
|
||||||
|
}
|
||||||
|
data = chunk_from_base64(data, dst.ptr);
|
||||||
|
|
||||||
|
dst.ptr += data.len;
|
||||||
|
dst.len += data.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* set length to size of binary blob */
|
||||||
|
blob->len = dst.len;
|
||||||
|
|
||||||
|
if (state != PEM_POST)
|
||||||
|
{
|
||||||
|
DBG1(" file coded in unknown format, discarded");
|
||||||
|
return PARSE_ERROR;
|
||||||
|
}
|
||||||
|
if (!encrypted)
|
||||||
|
{
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
if (!this->cb)
|
||||||
|
{
|
||||||
|
DBG1(" missing passphrase");
|
||||||
|
return INVALID_ARG;
|
||||||
|
}
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
passphrase = this->cb(this->data, ++try);
|
||||||
|
if (!passphrase.len || !passphrase.ptr)
|
||||||
|
{
|
||||||
|
return INVALID_ARG;
|
||||||
|
}
|
||||||
|
switch (pem_decrypt(blob, alg, key_size, iv, passphrase))
|
||||||
|
{
|
||||||
|
case INVALID_ARG:
|
||||||
|
/* bad passphrase, retry */
|
||||||
|
continue;
|
||||||
|
case SUCCESS:
|
||||||
|
return SUCCESS;
|
||||||
|
default:
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of builder_t.build
|
||||||
|
*/
|
||||||
|
static void *build(private_builder_t *this)
|
||||||
|
{
|
||||||
|
bool pgp = FALSE;
|
||||||
|
void *cred = NULL;
|
||||||
|
chunk_t blob;
|
||||||
|
builder_part_t part = BUILD_BLOB_ASN1_DER;
|
||||||
|
|
||||||
|
if (!this->pem.ptr)
|
||||||
|
{
|
||||||
|
free(this);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
blob = chunk_clone(this->pem);
|
||||||
|
if (pem_to_bin(&blob, this, &pgp) == SUCCESS)
|
||||||
|
{
|
||||||
|
if (pgp)
|
||||||
|
{
|
||||||
|
part = BUILD_BLOB_PGP;
|
||||||
|
}
|
||||||
|
cred = lib->creds->create(lib->creds, this->type, this->subtype,
|
||||||
|
part, blob, BUILD_END);
|
||||||
|
}
|
||||||
|
chunk_clear(&blob);
|
||||||
|
free(this);
|
||||||
|
return cred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* passphrase callback to use if passphrase given
|
||||||
|
*/
|
||||||
|
static chunk_t given_passphrase_cb(chunk_t *passphrase, int try)
|
||||||
|
{
|
||||||
|
if (try > 1)
|
||||||
|
{ /* try only once for given passphrases */
|
||||||
|
return chunk_empty;
|
||||||
|
}
|
||||||
|
return *passphrase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of builder_t.add
|
||||||
|
*/
|
||||||
|
static void add(private_builder_t *this, builder_part_t part, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
switch (part)
|
||||||
|
{
|
||||||
|
case BUILD_BLOB_PEM:
|
||||||
|
va_start(args, part);
|
||||||
|
this->pem = va_arg(args, chunk_t);
|
||||||
|
va_end(args);
|
||||||
|
break;
|
||||||
|
case BUILD_PASSPHRASE:
|
||||||
|
va_start(args, part);
|
||||||
|
this->passphrase = va_arg(args, chunk_t);
|
||||||
|
va_end(args);
|
||||||
|
if (this->passphrase.len && this->passphrase.ptr)
|
||||||
|
{
|
||||||
|
this->cb = (void*)given_passphrase_cb;
|
||||||
|
this->data = &this->passphrase;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILD_PASSPHRASE_CALLBACK:
|
||||||
|
va_start(args, part);
|
||||||
|
this->cb = va_arg(args, chunk_t(*)(void*,int));
|
||||||
|
this->data = va_arg(args, void*);
|
||||||
|
va_end(args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
builder_cancel(&this->public);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic PEM builder.
|
||||||
|
*/
|
||||||
|
static builder_t *pem_builder(credential_type_t type, int subtype)
|
||||||
|
{
|
||||||
|
private_builder_t *this = malloc_thing(private_builder_t);
|
||||||
|
|
||||||
|
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||||
|
this->public.build = (void*(*)(builder_t *this))build;
|
||||||
|
|
||||||
|
this->type = type;
|
||||||
|
this->subtype = subtype;
|
||||||
|
this->pem = chunk_empty;
|
||||||
|
this->passphrase = chunk_empty;
|
||||||
|
this->cb = NULL;
|
||||||
|
this->data = NULL;
|
||||||
|
|
||||||
|
return &this->public;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key PEM builder.
|
||||||
|
*/
|
||||||
|
builder_t *private_key_pem_builder(key_type_t type)
|
||||||
|
{
|
||||||
|
return pem_builder(CRED_PRIVATE_KEY, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key PEM builder.
|
||||||
|
*/
|
||||||
|
builder_t *public_key_pem_builder(key_type_t type)
|
||||||
|
{
|
||||||
|
return pem_builder(CRED_PUBLIC_KEY, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Certificate PEM builder.
|
||||||
|
*/
|
||||||
|
builder_t *certificate_pem_builder(certificate_type_t type)
|
||||||
|
{
|
||||||
|
return pem_builder(CRED_CERTIFICATE, type);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Martin Willi
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup pem_builder pem_builder
|
||||||
|
* @{ @ingroup pem_p
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PEM_PRIVATE_KEY_H_
|
||||||
|
#define PEM_PRIVATE_KEY_H_
|
||||||
|
|
||||||
|
#include <credentials/certificates/certificate.h>
|
||||||
|
#include <credentials/credential_factory.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for PEM encoded private keys of all kind.
|
||||||
|
*
|
||||||
|
* @param type type of the key
|
||||||
|
* @return builder instance
|
||||||
|
*/
|
||||||
|
builder_t *private_key_pem_builder(key_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for PEM encoded public keys of all kind.
|
||||||
|
*
|
||||||
|
* @param type type of the key
|
||||||
|
* @return builder instance
|
||||||
|
*/
|
||||||
|
builder_t *public_key_pem_builder(key_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for PEM encoded certificates of all kind.
|
||||||
|
*
|
||||||
|
* @param type type of the key
|
||||||
|
* @return builder instance
|
||||||
|
*/
|
||||||
|
builder_t *certificate_pem_builder(certificate_type_t type);
|
||||||
|
|
||||||
|
#endif /** PEM_PRIVATE_KEY_H_ @}*/
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Martin Willi
|
||||||
|
* 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
|
||||||
|
* 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 "pem_plugin.h"
|
||||||
|
|
||||||
|
#include <library.h>
|
||||||
|
#include "pem_builder.h"
|
||||||
|
|
||||||
|
typedef struct private_pem_plugin_t private_pem_plugin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private data of pem_plugin
|
||||||
|
*/
|
||||||
|
struct private_pem_plugin_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* public functions
|
||||||
|
*/
|
||||||
|
pem_plugin_t public;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of pem_plugin_t.pemtroy
|
||||||
|
*/
|
||||||
|
static void destroy(private_pem_plugin_t *this)
|
||||||
|
{
|
||||||
|
lib->creds->remove_builder(lib->creds,
|
||||||
|
(builder_constructor_t)private_key_pem_builder);
|
||||||
|
lib->creds->remove_builder(lib->creds,
|
||||||
|
(builder_constructor_t)public_key_pem_builder);
|
||||||
|
lib->creds->remove_builder(lib->creds,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* see header file
|
||||||
|
*/
|
||||||
|
plugin_t *plugin_create()
|
||||||
|
{
|
||||||
|
private_pem_plugin_t *this = malloc_thing(private_pem_plugin_t);
|
||||||
|
|
||||||
|
this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
|
||||||
|
|
||||||
|
/* register private key PEM decoding builders */
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
|
||||||
|
(builder_constructor_t)private_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
|
||||||
|
(builder_constructor_t)private_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_ECDSA,
|
||||||
|
(builder_constructor_t)private_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, KEY_DSA,
|
||||||
|
(builder_constructor_t)private_key_pem_builder);
|
||||||
|
|
||||||
|
/* register public key PEM decoding builders */
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
|
||||||
|
(builder_constructor_t)public_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
||||||
|
(builder_constructor_t)public_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA,
|
||||||
|
(builder_constructor_t)public_key_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_PUBLIC_KEY, KEY_DSA,
|
||||||
|
(builder_constructor_t)public_key_pem_builder);
|
||||||
|
|
||||||
|
/* register certificate PEM decoding builders */
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_ANY,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PGP,
|
||||||
|
(builder_constructor_t)certificate_pem_builder);
|
||||||
|
|
||||||
|
return &this->public.plugin;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Martin Willi
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup pem_p pem
|
||||||
|
* @ingroup plugins
|
||||||
|
*
|
||||||
|
* @defgroup pem_plugin pem_plugin
|
||||||
|
* @{ @ingroup pem_p
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PEM_PLUGIN_H_
|
||||||
|
#define PEM_PLUGIN_H_
|
||||||
|
|
||||||
|
#include <plugins/plugin.h>
|
||||||
|
|
||||||
|
typedef struct pem_plugin_t pem_plugin_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plugin providing support to load credentials in PEM format
|
||||||
|
*/
|
||||||
|
struct pem_plugin_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* implements plugin interface
|
||||||
|
*/
|
||||||
|
plugin_t plugin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a pem_plugin instance.
|
||||||
|
*/
|
||||||
|
plugin_t *plugin_create();
|
||||||
|
|
||||||
|
#endif /** PEM_PLUGIN_H_ @}*/
|
||||||
@@ -137,14 +137,13 @@ static void add(private_builder_t *this, builder_part_t part, ...)
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case BUILD_BLOB_ASN1_PEM:
|
case BUILD_BLOB_PEM:
|
||||||
{
|
{
|
||||||
bool pgp;
|
bool pgp;
|
||||||
char *pem;
|
|
||||||
|
|
||||||
va_start(args, part);
|
va_start(args, part);
|
||||||
pem = va_arg(args, char *);
|
blob = va_arg(args, chunk_t);
|
||||||
blob = chunk_clone(chunk_create(pem, strlen(pem)));
|
blob = chunk_clone(blob);
|
||||||
if (pem_to_bin(&blob, chunk_empty, &pgp) == SUCCESS)
|
if (pem_to_bin(&blob, chunk_empty, &pgp) == SUCCESS)
|
||||||
{
|
{
|
||||||
this->key = pubkey_public_key_load(chunk_clone(blob));
|
this->key = pubkey_public_key_load(chunk_clone(blob));
|
||||||
|
|||||||
@@ -122,15 +122,18 @@ static bool parse_public_key(private_peer_controller_t *this,
|
|||||||
{
|
{
|
||||||
public_key_t *public;
|
public_key_t *public;
|
||||||
identification_t *id;
|
identification_t *id;
|
||||||
|
chunk_t blob;
|
||||||
|
|
||||||
if (!public_key || *public_key == '\0')
|
if (!public_key || *public_key == '\0')
|
||||||
{
|
{
|
||||||
request->setf(request, "error=Public key is missing.");
|
request->setf(request, "error=Public key is missing.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
blob = chunk_clone(chunk_create(public_key, strlen(public_key)));
|
||||||
public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
|
public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
|
||||||
BUILD_BLOB_ASN1_PEM, public_key,
|
BUILD_BLOB_PEM, blob,
|
||||||
BUILD_END);
|
BUILD_END);
|
||||||
|
chunk_free(&blob);
|
||||||
if (!public)
|
if (!public)
|
||||||
{
|
{
|
||||||
request->setf(request, "error=Parsing public key failed.");
|
request->setf(request, "error=Parsing public key failed.");
|
||||||
|
|||||||
Reference in New Issue
Block a user