Merge branch 'charon-cmd-pkcs12'

Adds support for PKCS#12 files in charon-cmd and ipsec.secrets.

Also fixes the cleanup of the OpenSSL library in the openssl plugin.
This commit is contained in:
Tobias Brunner
2013-05-08 15:19:38 +02:00
55 changed files with 3465 additions and 556 deletions
+9 -1
View File
@@ -112,6 +112,7 @@ ARG_ENABL_SET([ldap], [enable LDAP fetching plugin to fetch files via
ARG_DISBL_SET([aes], [disable AES software implementation plugin.])
ARG_DISBL_SET([des], [disable DES/3DES software implementation plugin.])
ARG_ENABL_SET([blowfish], [enable Blowfish software implementation plugin.])
ARG_DISBL_SET([rc2], [disable RC2 software implementation plugin.])
ARG_ENABL_SET([md4], [enable MD4 software implementation plugin.])
ARG_DISBL_SET([md5], [disable MD5 software implementation plugin.])
ARG_DISBL_SET([sha1], [disable SHA1 software implementation plugin.])
@@ -128,6 +129,7 @@ ARG_DISBL_SET([pubkey], [disable RAW public key support plugin.])
ARG_DISBL_SET([pkcs1], [disable PKCS1 key decoding plugin.])
ARG_DISBL_SET([pkcs7], [disable PKCS7 container support plugin.])
ARG_DISBL_SET([pkcs8], [disable PKCS8 private key decoding plugin.])
ARG_DISBL_SET([pkcs12], [disable PKCS12 container support plugin.])
ARG_DISBL_SET([pgp], [disable PGP key decoding plugin.])
ARG_DISBL_SET([dnskey], [disable DNS RR key decoding plugin.])
ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.])
@@ -952,6 +954,7 @@ ADD_PLUGIN([pkcs11], [s charon pki nm cmd])
ADD_PLUGIN([aes], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([des], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([blowfish], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([rc2], [s charon openac scepclient pki scripts nm cmd])
ADD_PLUGIN([sha1], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([sha2], [s charon openac scepclient pki scripts medsrv attest nm cmd])
ADD_PLUGIN([md4], [s charon openac manager scepclient pki nm cmd])
@@ -964,8 +967,9 @@ ADD_PLUGIN([revocation], [s charon nm cmd])
ADD_PLUGIN([constraints], [s charon nm cmd])
ADD_PLUGIN([pubkey], [s charon cmd])
ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pkcs7], [s scepclient pki])
ADD_PLUGIN([pkcs7], [s charon scepclient pki scripts nm cmd])
ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts cmd])
ADD_PLUGIN([pgp], [s charon])
ADD_PLUGIN([dnskey], [s charon])
ADD_PLUGIN([sshkey], [s charon nm cmd])
@@ -1081,6 +1085,7 @@ AM_CONDITIONAL(USE_LDAP, test x$ldap = xtrue)
AM_CONDITIONAL(USE_AES, test x$aes = xtrue)
AM_CONDITIONAL(USE_DES, test x$des = xtrue)
AM_CONDITIONAL(USE_BLOWFISH, test x$blowfish = xtrue)
AM_CONDITIONAL(USE_RC2, test x$rc2 = xtrue)
AM_CONDITIONAL(USE_MD4, test x$md4 = xtrue)
AM_CONDITIONAL(USE_MD5, test x$md5 = xtrue)
AM_CONDITIONAL(USE_SHA1, test x$sha1 = xtrue)
@@ -1097,6 +1102,7 @@ AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue)
AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue)
AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue)
AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = xtrue)
AM_CONDITIONAL(USE_PKCS12, test x$pkcs12 = xtrue)
AM_CONDITIONAL(USE_PGP, test x$pgp = xtrue)
AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue)
AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue)
@@ -1274,6 +1280,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/cmac/Makefile
src/libstrongswan/plugins/des/Makefile
src/libstrongswan/plugins/blowfish/Makefile
src/libstrongswan/plugins/rc2/Makefile
src/libstrongswan/plugins/md4/Makefile
src/libstrongswan/plugins/md5/Makefile
src/libstrongswan/plugins/sha1/Makefile
@@ -1292,6 +1299,7 @@ AC_CONFIG_FILES([
src/libstrongswan/plugins/pkcs1/Makefile
src/libstrongswan/plugins/pkcs7/Makefile
src/libstrongswan/plugins/pkcs8/Makefile
src/libstrongswan/plugins/pkcs12/Makefile
src/libstrongswan/plugins/pgp/Makefile
src/libstrongswan/plugins/dnskey/Makefile
src/libstrongswan/plugins/sshkey/Makefile
+17 -4
View File
@@ -91,6 +91,9 @@ defines an RSA private key
.B ECDSA
defines an ECDSA private key
.TP
.B P12
defines a PKCS#12 container
.TP
.B EAP
defines EAP credentials
.TP
@@ -133,16 +136,26 @@ Similarly, a character sequence beginning with
.B 0s
is interpreted as Base64 encoded binary data.
.TP
.B [ <selectors> ] : RSA <private key file> [ <passphrase> | %prompt ]
.B : RSA <private key file> [ <passphrase> | %prompt ]
.TQ
.B [ <selectors> ] : ECDSA <private key file> [ <passphrase> | %prompt ]
.B : ECDSA <private key file> [ <passphrase> | %prompt ]
For the private key file both absolute paths or paths relative to
\fI/etc/ipsec.d/private\fP are accepted. If the private key file is
encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase
.B %prompt
can be used which then causes the daemons to ask the user for the password
can be used which then causes the daemon to ask the user for the password
whenever it is required to decrypt the key.
.TP
.B : P12 <PKCS#12 file> [ <passphrase> | %prompt ]
For the PKCS#12 file both absolute paths or paths relative to
\fI/etc/ipsec.d/private\fP are accepted. If the container is
encrypted, the \fIpassphrase\fP must be defined. Instead of a passphrase
.B %prompt
can be used which then causes the daemon to ask the user for the password
whenever it is required to decrypt the container. Private keys, client and CA
certificates are extracted from the container. To use such a client certificate
in a connection set leftid to one of the subjects of the certificate.
.TP
.B <user id> : EAP <secret>
The format of \fIsecret\fP is the same as that of \fBPSK\fP secrets.
.br
@@ -165,7 +178,7 @@ key. The slot number defines the slot on the token, the module name refers to
the module name defined in strongswan.conf(5).
Instead of specifying the pin code statically,
.B %prompt
can be specified, which causes the daemons to ask the user for the pin code.
can be specified, which causes the daemon to ask the user for the pin code.
.LP
.SH FILES
+1
View File
@@ -391,6 +391,7 @@ METHOD(cmd_connection_t, handle, bool,
break;
case CMD_OPT_RSA:
case CMD_OPT_AGENT:
case CMD_OPT_PKCS12:
this->key_seen = TRUE;
break;
case CMD_OPT_LOCAL_TS:
+54 -2
View File
@@ -22,6 +22,7 @@
#include <utils/debug.h>
#include <credentials/sets/mem_cred.h>
#include <credentials/containers/pkcs12.h>
#include <credentials/sets/callback_cred.h>
typedef struct private_cmd_creds_t private_cmd_creds_t;
@@ -70,6 +71,7 @@ static shared_key_t* callback_shared(private_cmd_creds_t *this,
identification_t *me, identification_t *other,
id_match_t *match_me, id_match_t *match_other)
{
shared_key_t *shared;
char *label, *pwd;
if (this->prompted)
@@ -84,6 +86,9 @@ static shared_key_t* callback_shared(private_cmd_creds_t *this,
case SHARED_IKE:
label = "Preshared Key: ";
break;
case SHARED_PRIVATE_KEY_PASS:
label = "Password: ";
break;
default:
return NULL;
}
@@ -93,8 +98,18 @@ static shared_key_t* callback_shared(private_cmd_creds_t *this,
return NULL;
}
this->prompted = TRUE;
*match_me = *match_other = ID_MATCH_PERFECT;
return shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
if (match_me)
{
*match_me = ID_MATCH_PERFECT;
}
if (match_other)
{
*match_other = ID_MATCH_PERFECT;
}
shared = shared_key_create(type, chunk_clone(chunk_from_str(pwd)));
/* cache password in case it is required more than once */
this->creds->add_shared(this->creds, shared, NULL);
return shared->get_ref(shared);
}
/**
@@ -172,6 +187,40 @@ static void load_agent(private_cmd_creds_t *this)
this->creds->add_key(this->creds, privkey);
}
/**
* Load a PKCS#12 file from path
*/
static void load_pkcs12(private_cmd_creds_t *this, char *path)
{
enumerator_t *enumerator;
certificate_t *cert;
private_key_t *key;
container_t *container;
pkcs12_t *pkcs12;
container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS12,
BUILD_FROM_FILE, path, BUILD_END);
if (!container)
{
DBG1(DBG_CFG, "loading PKCS#12 file '%s' failed", path);
exit(1);
}
pkcs12 = (pkcs12_t*)container;
enumerator = pkcs12->create_cert_enumerator(pkcs12);
while (enumerator->enumerate(enumerator, &cert))
{
this->creds->add_cert(this->creds, TRUE, cert->get_ref(cert));
}
enumerator->destroy(enumerator);
enumerator = pkcs12->create_key_enumerator(pkcs12);
while (enumerator->enumerate(enumerator, &key))
{
this->creds->add_key(this->creds, key->get_ref(key));
}
enumerator->destroy(enumerator);
container->destroy(container);
}
METHOD(cmd_creds_t, handle, bool,
private_cmd_creds_t *this, cmd_option_type_t opt, char *arg)
{
@@ -183,6 +232,9 @@ METHOD(cmd_creds_t, handle, bool,
case CMD_OPT_RSA:
load_key(this, KEY_RSA, arg);
break;
case CMD_OPT_PKCS12:
load_pkcs12(this, arg);
break;
case CMD_OPT_IDENTITY:
this->identity = arg;
break;
+4
View File
@@ -38,6 +38,10 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = {
"trusted certificate, for authentication or trust chain validation", {}},
{ CMD_OPT_RSA, "rsa", required_argument, "path",
"RSA private key to use for authentication", {}},
{ CMD_OPT_PKCS12, "p12", required_argument, "path",
"PKCS#12 file with private key and certificates to use for ", {
"authentication and trust chain validation"
}},
{ CMD_OPT_AGENT, "agent", optional_argument, "socket",
"use SSH agent for authentication. If socket is not specified", {
"it is read from the SSH_AUTH_SOCK environment variable",
+4
View File
@@ -1,4 +1,7 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
@@ -35,6 +38,7 @@ enum cmd_option_type_t {
CMD_OPT_REMOTE_IDENTITY,
CMD_OPT_CERT,
CMD_OPT_RSA,
CMD_OPT_PKCS12,
CMD_OPT_AGENT,
CMD_OPT_LOCAL_TS,
CMD_OPT_REMOTE_TS,
+144 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -32,6 +32,7 @@
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
#include <credentials/certificates/ac.h>
#include <credentials/containers/pkcs12.h>
#include <credentials/sets/mem_cred.h>
#include <credentials/sets/callback_cred.h>
#include <collections/linked_list.h>
@@ -72,7 +73,7 @@ struct private_stroke_cred_t {
/**
* ignore missing CA basic constraint (i.e. treat all certificates in
* ipsec.conf ca sections and ipsec.d/cacert as CA certificates)
* ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
*/
bool force_ca_cert;
@@ -225,7 +226,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
cert->destroy(cert);
return NULL;
}
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s",
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
cert->get_subject(cert), filename);
return this->creds->add_cert_ref(this->creds, TRUE, cert);
}
@@ -599,8 +600,12 @@ static err_t extract_secret(chunk_t *secret, chunk_t *line)
* Data for passphrase callback
*/
typedef struct {
/** cached passphrases */
mem_cred_t *cache;
/** socket we use for prompting */
FILE *prompt;
/** type of secret to unlock */
int type;
/** private key file */
char *path;
/** number of tries */
@@ -608,13 +613,15 @@ typedef struct {
} passphrase_cb_data_t;
/**
* Callback function to receive Passphrases
* Callback function to receive passphrases
*/
static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
shared_key_type_t type,
identification_t *me, identification_t *other,
id_match_t *match_me, id_match_t *match_other)
shared_key_type_t type, identification_t *me,
identification_t *other, id_match_t *match_me,
id_match_t *match_other)
{
static const int max_tries = 3;
shared_key_t *shared;
chunk_t secret;
char buf[256];
@@ -623,17 +630,23 @@ static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
return NULL;
}
data->try++;
if (data->try > max_tries + 1)
{ /* another builder might call this after we gave up, fail silently */
return NULL;
}
if (data->try > max_tries)
{
fprintf(data->prompt, "Passphrase invalid, giving up.\n");
return NULL;
}
if (data->try > 1)
{
if (data->try > 5)
{
fprintf(data->prompt, "PIN invalid, giving up.\n");
return NULL;
}
fprintf(data->prompt, "PIN invalid!\n");
fprintf(data->prompt, "Passphrase invalid!\n");
}
data->try++;
fprintf(data->prompt, "Private key '%s' is encrypted.\n", data->path);
fprintf(data->prompt, "%s '%s' is encrypted.\n",
data->type == CRED_PRIVATE_KEY ? "Private key" : "PKCS#12 file",
data->path);
fprintf(data->prompt, "Passphrase:\n");
if (fgets(buf, sizeof(buf), data->prompt))
{
@@ -649,7 +662,10 @@ static shared_key_t* passphrase_cb(passphrase_cb_data_t *data,
{
*match_other = ID_MATCH_NONE;
}
return shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(secret));
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS,
chunk_clone(secret));
data->cache->add_shared(data->cache, shared->get_ref(shared), NULL);
return shared;
}
}
return NULL;
@@ -689,12 +705,12 @@ static shared_key_t* pin_cb(pin_cb_data_t *data, shared_key_type_t type,
return NULL;
}
data->try++;
if (data->try > 1)
{
fprintf(data->prompt, "PIN invalid, aborting.\n");
return NULL;
}
data->try++;
fprintf(data->prompt, "Login to '%s' required\n", data->card);
fprintf(data->prompt, "PIN:\n");
if (fgets(buf, sizeof(buf), data->prompt))
@@ -783,7 +799,7 @@ static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
pin_data.prompt = prompt;
pin_data.card = smartcard;
pin_data.keyid = chunk;
pin_data.try = 1;
pin_data.try = 0;
cb = callback_cred_create_shared((void*)pin_cb, &pin_data);
lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
}
@@ -821,15 +837,14 @@ static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
}
/**
* Load a private key
* Load a private key or PKCS#12 container from a file
*/
static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
FILE *prompt, key_type_t key_type)
static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
char *path, int type, int subtype,
void **result)
{
char path[PATH_MAX];
chunk_t filename;
chunk_t secret = chunk_empty;
private_key_t *key;
err_t ugh = extract_value(&filename, &line);
@@ -846,12 +861,12 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
if (*filename.ptr == '/')
{
/* absolute path name */
snprintf(path, sizeof(path), "%.*s", (int)filename.len, filename.ptr);
snprintf(path, PATH_MAX, "%.*s", (int)filename.len, filename.ptr);
}
else
{
/* relative path name */
snprintf(path, sizeof(path), "%s/%.*s", PRIVATE_KEY_DIR,
snprintf(path, PATH_MAX, "%s/%.*s", PRIVATE_KEY_DIR,
(int)filename.len, filename.ptr);
}
@@ -867,30 +882,35 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
}
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7))
{
callback_cred_t *cb = NULL;
callback_cred_t *cb;
passphrase_cb_data_t pp_data = {
.prompt = prompt,
.type = type,
.path = path,
.try = 1,
.try = 0,
};
free(secret.ptr);
if (!prompt)
{
*result = NULL;
return TRUE;
}
/* add cache first so if valid passphrases are needed multiple times
* the callback is not called anymore */
pp_data.cache = mem_cred_create();
lib->credmgr->add_local_set(lib->credmgr, &pp_data.cache->set, FALSE);
/* use callback credential set to prompt for the passphrase */
pp_data.prompt = prompt;
pp_data.path = path;
pp_data.try = 1;
cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data);
lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
BUILD_FROM_FILE, path, BUILD_END);
*result = lib->creds->create(lib->creds, type, subtype,
BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &cb->set);
cb->destroy(cb);
lib->credmgr->remove_local_set(lib->credmgr, &pp_data.cache->set);
pp_data.cache->destroy(pp_data.cache);
}
else
{
@@ -901,14 +921,44 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
mem = mem_cred_create();
mem->add_shared(mem, shared, NULL);
if (eat_whitespace(&line))
{ /* if there is a second passphrase add that too, could be needed for
* PKCS#12 files using different passwords for MAC and encryption */
ugh = extract_secret(&secret, &line);
if (ugh != NULL)
{
DBG1(DBG_CFG, "line %d: malformed passphrase: %s", line_nr, ugh);
mem->destroy(mem);
return FALSE;
}
shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret);
mem->add_shared(mem, shared, NULL);
}
lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type,
BUILD_FROM_FILE, path, BUILD_END);
*result = lib->creds->create(lib->creds, type, subtype,
BUILD_FROM_FILE, path, BUILD_END);
lib->credmgr->remove_local_set(lib->credmgr, &mem->set);
mem->destroy(mem);
}
return TRUE;
}
/**
* Load a private key
*/
static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
FILE *prompt, key_type_t key_type)
{
char path[PATH_MAX];
private_key_t *key;
if (!load_from_file(line, line_nr, prompt, path, CRED_PRIVATE_KEY,
key_type, (void**)&key))
{
return FALSE;
}
if (key)
{
DBG1(DBG_CFG, " loaded %N private key from '%s'",
@@ -922,6 +972,58 @@ static bool load_private(mem_cred_t *secrets, chunk_t line, int line_nr,
return TRUE;
}
/**
* Load a PKCS#12 container
*/
static bool load_pkcs12(mem_cred_t *secrets, chunk_t line, int line_nr,
FILE *prompt)
{
enumerator_t *enumerator;
char path[PATH_MAX];
certificate_t *cert;
private_key_t *key;
pkcs12_t *pkcs12;
if (!load_from_file(line, line_nr, prompt, path, CRED_CONTAINER,
CONTAINER_PKCS12, (void**)&pkcs12))
{
return FALSE;
}
if (!pkcs12)
{
DBG1(DBG_CFG, " loading credentials from '%s' failed", path);
return TRUE;
}
enumerator = pkcs12->create_cert_enumerator(pkcs12);
while (enumerator->enumerate(enumerator, &cert))
{
x509_t *x509 = (x509_t*)cert;
if (x509->get_flags(x509) & X509_CA)
{
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
cert->get_subject(cert), path);
}
else
{
DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
cert->get_subject(cert), path);
}
secrets->add_cert(secrets, TRUE, cert->get_ref(cert));
}
enumerator->destroy(enumerator);
enumerator = pkcs12->create_key_enumerator(pkcs12);
while (enumerator->enumerate(enumerator, &key))
{
DBG1(DBG_CFG, " loaded %N private key from '%s'",
key_type_names, key->get_type(key), path);
secrets->add_key(secrets, key->get_ref(key));
}
enumerator->destroy(enumerator);
pkcs12->container.destroy(&pkcs12->container);
return TRUE;
}
/**
* Load a shared key
*/
@@ -1140,6 +1242,13 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
break;
}
}
else if (match("P12", &token))
{
if (!load_pkcs12(secrets, line, line_nr, prompt))
{
break;
}
}
else if (match("PIN", &token))
{
if (!load_pin(secrets, line, line_nr, prompt))
@@ -1160,7 +1269,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
else
{
DBG1(DBG_CFG, "line %d: token must be either "
"RSA, ECDSA, PSK, EAP, XAUTH or PIN", line_nr);
"RSA, ECDSA, P12, PIN, PSK, EAP, XAUTH or NTLM", line_nr);
break;
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \
crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \
@@ -17,7 +17,7 @@ credentials/cred_encoding.c credentials/keys/private_key.c \
credentials/keys/public_key.c credentials/keys/shared_key.c \
credentials/certificates/certificate.c credentials/certificates/crl.c \
credentials/certificates/ocsp_response.c \
credentials/containers/container.c \
credentials/containers/container.c credentials/containers/pkcs12.c \
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
+18 -3
View File
@@ -6,7 +6,7 @@ asn1/asn1.c asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \
collections/blocking_queue.c collections/enumerator.c collections/hashtable.c \
collections/linked_list.c crypto/crypters/crypter.c crypto/hashers/hasher.c \
crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c \
crypto/prfs/prf.c crypto/prfs/mac_prf.c crypto/pkcs5.c \
crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \
crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \
crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \
@@ -15,7 +15,7 @@ credentials/cred_encoding.c credentials/keys/private_key.c \
credentials/keys/public_key.c credentials/keys/shared_key.c \
credentials/certificates/certificate.c credentials/certificates/crl.c \
credentials/certificates/ocsp_response.c \
credentials/containers/container.c \
credentials/containers/container.c credentials/containers/pkcs12.c \
credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \
credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \
credentials/sets/cert_cache.c credentials/sets/mem_cred.c \
@@ -45,7 +45,7 @@ crypto/proposal/proposal_keywords.h crypto/proposal/proposal_keywords_static.h \
crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \
crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \
crypto/crypto_factory.h crypto/crypto_tester.h crypto/diffie_hellman.h \
crypto/aead.h crypto/transform.h \
crypto/aead.h crypto/transform.h crypto/pkcs5.h \
credentials/credential_factory.h credentials/builder.h \
credentials/cred_encoding.h credentials/keys/private_key.h \
credentials/keys/public_key.h credentials/keys/shared_key.h \
@@ -55,6 +55,7 @@ credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \
credentials/certificates/ocsp_response.h \
credentials/certificates/pgp_certificate.h \
credentials/containers/container.h credentials/containers/pkcs7.h \
credentials/containers/pkcs12.h \
credentials/ietf_attributes/ietf_attributes.h \
credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \
credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \
@@ -175,6 +176,13 @@ if MONOLITHIC
endif
endif
if USE_RC2
SUBDIRS += plugins/rc2
if MONOLITHIC
libstrongswan_la_LIBADD += plugins/rc2/libstrongswan-rc2.la
endif
endif
if USE_MD4
SUBDIRS += plugins/md4
if MONOLITHIC
@@ -301,6 +309,13 @@ if MONOLITHIC
endif
endif
if USE_PKCS12
SUBDIRS += plugins/pkcs12
if MONOLITHIC
libstrongswan_la_LIBADD += plugins/pkcs12/libstrongswan-pkcs12.la
endif
endif
if USE_PGP
SUBDIRS += plugins/pgp
if MONOLITHIC
+16
View File
@@ -549,6 +549,22 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
return TRUE;
}
/*
* Described in header
*/
u_int64_t asn1_parse_integer_uint64(chunk_t blob)
{
u_int64_t val = 0;
int i;
for (i = 0; i < blob.len; i++)
{ /* if it is longer than 8 bytes, we just use the 8 LSBs */
val <<= 8;
val |= (u_int64_t)blob.ptr[i];
}
return val;
}
/**
* ASN.1 definition of an algorithmIdentifier
*/
+9
View File
@@ -170,6 +170,15 @@ int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *params);
bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level0,
const char* name);
/**
* Converts an ASN.1 INTEGER object to an u_int64_t. If the INTEGER is longer
* than 8 bytes only the 8 LSBs are returned.
*
* @param blob body of an ASN.1 coded integer object
* @return converted integer
*/
u_int64_t asn1_parse_integer_uint64(chunk_t blob);
/**
* Print the value of an ASN.1 simple object
*
+20 -1
View File
@@ -121,6 +121,25 @@
0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS
0x0E "extensionRequest" OID_EXTENSION_REQUEST
0x0F "S/MIME Capabilities"
0x16 "certTypes"
0x01 "X.509" OID_X509_CERTIFICATE
0x02 "SDSI"
0x0c "PKCS-12"
0x01 "pbeIds"
0x01 "pbeWithSHAAnd128BitRC4" OID_PBE_SHA1_RC4_128
0x02 "pbeWithSHAAnd40BitRC4" OID_PBE_SHA1_RC4_40
0x03 "pbeWithSHAAnd3-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_CBC
0x04 "pbeWithSHAAnd2-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_2KEY_CBC
0x05 "pbeWithSHAAnd128BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_128
0x06 "pbeWithSHAAnd40BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_40
0x0a "PKCS-12v1"
0x01 "bagIds"
0x01 "keyBag" OID_P12_KEY_BAG
0x02 "pkcs8ShroudedKeyBag" OID_P12_PKCS8_KEY_BAG
0x03 "certBag" OID_P12_CERT_BAG
0x04 "crlBag" OID_P12_CRL_BAG
0x05 "secretBag"
0x06 "safeContentsBag"
0x02 "digestAlgorithm"
0x02 "md2" OID_MD2
0x05 "md5" OID_MD5
@@ -240,7 +259,7 @@
0x05 "caRepository"
0x08 "ipsec"
0x02 "certificate"
0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE
0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE
0x0E "oiw"
0x03 "secsig"
0x02 "algorithms"
@@ -18,7 +18,7 @@
#include <utils/debug.h>
#include <credentials/certificates/x509.h>
ENUM(certificate_type_names, CERT_ANY, CERT_PLUTO_CRL,
ENUM(certificate_type_names, CERT_ANY, CERT_GPG,
"ANY",
"X509",
"X509_CRL",
@@ -28,9 +28,6 @@ ENUM(certificate_type_names, CERT_ANY, CERT_PLUTO_CRL,
"TRUSTED_PUBKEY",
"PKCS10_REQUEST",
"PGP",
"PLUTO_CERT",
"PLUTO_AC",
"PLUTO_CRL",
);
ENUM(cert_validation_names, VALIDATION_GOOD, VALIDATION_REVOKED,
@@ -52,10 +52,6 @@ enum certificate_type_t {
CERT_PKCS10_REQUEST,
/** PGP certificate */
CERT_GPG,
/** Pluto cert_t (not a certificate_t), either x509 or PGP */
CERT_PLUTO_CERT,
/** Pluto x509crl_t (not a certificate_t), certificate revocation list */
CERT_PLUTO_CRL,
};
/**
@@ -15,9 +15,11 @@
#include "container.h"
ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENVELOPED_DATA,
ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS12,
"PKCS7",
"PKCS7_DATA",
"PKCS7_SIGNED_DATA",
"PKCS7_ENVELOPED_DATA",
"PKCS7_ENCRYPTED_DATA",
"PKCS12",
);
@@ -1,4 +1,7 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG
*
@@ -31,14 +34,18 @@ typedef enum container_type_t container_type_t;
* Type of the container.
*/
enum container_type_t {
/** Any kind of PKCS7/CMS container */
/** Any kind of PKCS#7/CMS container */
CONTAINER_PKCS7,
/** PKCS7/CMS plain "data" */
/** PKCS#7/CMS plain "data" */
CONTAINER_PKCS7_DATA,
/** PKCS7/CMS "signed-data" */
/** PKCS#7/CMS "signed-data" */
CONTAINER_PKCS7_SIGNED_DATA,
/** PKCS7/CMS "enveloped-data" */
/** PKCS#7/CMS "enveloped-data" */
CONTAINER_PKCS7_ENVELOPED_DATA,
/** PKCS#7/CMS "encrypted-data" */
CONTAINER_PKCS7_ENCRYPTED_DATA,
/** A PKCS#12 container */
CONTAINER_PKCS12,
};
/**
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 "pkcs12.h"
#include <utils/debug.h>
/**
* v * ceiling(len/v)
*/
#define PKCS12_LEN(len, v) (((len) + v-1) & ~(v-1))
/**
* Copy src to dst as many times as possible
*/
static inline void copy_chunk(chunk_t dst, chunk_t src)
{
size_t i;
for (i = 0; i < dst.len; i++)
{
dst.ptr[i] = src.ptr[i % src.len];
}
}
/**
* Treat two chunks as integers in network order and add them together.
* The result is stored in the first chunk, if the second chunk is longer or the
* result overflows this is ignored.
*/
static void add_chunks(chunk_t a, chunk_t b)
{
u_int16_t sum;
u_int8_t rem = 0;
ssize_t i, j;
for (i = a.len - 1, j = b.len -1; i >= 0 && j >= 0; i--, j--)
{
sum = a.ptr[i] + b.ptr[j] + rem;
a.ptr[i] = (u_char)sum;
rem = sum >> 8;
}
for (; i >= 0 && rem; i--)
{
sum = a.ptr[i] + rem;
a.ptr[i] = (u_char)sum;
rem = sum >> 8;
}
}
/**
* Do the actual key derivation with the given hasher, password and id.
*/
static bool derive_key(hash_algorithm_t hash, chunk_t unicode, chunk_t salt,
u_int64_t iterations, char id, chunk_t result)
{
chunk_t out = result, D, S, P = chunk_empty, I, Ai, B, Ij;
hasher_t *hasher;
size_t Slen, v, u;
u_int64_t i;
bool success = FALSE;
hasher = lib->crypto->create_hasher(lib->crypto, hash);
if (!hasher)
{
DBG1(DBG_ASN, " %N hash algorithm not available",
hash_algorithm_names, hash);
return FALSE;
}
switch (hash)
{
case HASH_MD2:
case HASH_MD5:
case HASH_SHA1:
case HASH_SHA224:
case HASH_SHA256:
v = 64;
break;
case HASH_SHA384:
case HASH_SHA512:
v = 128;
break;
default:
goto end;
}
u = hasher->get_hash_size(hasher);
D = chunk_alloca(v);
memset(D.ptr, id, D.len);
Slen = PKCS12_LEN(salt.len, v);
I = chunk_alloca(Slen + PKCS12_LEN(unicode.len, v));
S = chunk_create(I.ptr, Slen);
P = chunk_create(I.ptr + Slen, I.len - Slen);
copy_chunk(S, salt);
copy_chunk(P, unicode);
Ai = chunk_alloca(u);
B = chunk_alloca(v);
while (TRUE)
{
if (!hasher->get_hash(hasher, D, NULL) ||
!hasher->get_hash(hasher, I, Ai.ptr))
{
goto end;
}
for (i = 1; i < iterations; i++)
{
if (!hasher->get_hash(hasher, Ai, Ai.ptr))
{
goto end;
}
}
memcpy(out.ptr, Ai.ptr, min(out.len, Ai.len));
out = chunk_skip(out, Ai.len);
if (!out.len)
{
break;
}
copy_chunk(B, Ai);
/* B = B+1 */
add_chunks(B, chunk_from_chars(0x01));
Ij = chunk_create(I.ptr, v);
for (i = 0; i < I.len; i += v, Ij.ptr += v)
{ /* Ij = Ij + B + 1 */
add_chunks(Ij, B);
}
}
success = TRUE;
end:
hasher->destroy(hasher);
return success;
}
/*
* Described in header
*/
bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
u_int64_t iterations, pkcs12_key_type_t type, chunk_t key)
{
chunk_t unicode = chunk_empty;
bool success;
int i;
if (password.len)
{ /* convert the password to UTF-16BE (without BOM) with 0 terminator */
unicode = chunk_alloca(password.len * 2 + 2);
for (i = 0; i < password.len; i++)
{
unicode.ptr[i * 2] = 0;
unicode.ptr[i * 2 + 1] = password.ptr[i];
}
unicode.ptr[i * 2] = 0;
unicode.ptr[i * 2 + 1] = 0;
}
success = derive_key(hash, unicode, salt, iterations, type, key);
memwipe(unicode.ptr, unicode.len);
return success;
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 pkcs12 pkcs12
* @{ @ingroup containers
*/
#ifndef PKCS12_H_
#define PKCS12_H_
#include <credentials/containers/container.h>
#include <crypto/hashers/hasher.h>
typedef enum pkcs12_key_type_t pkcs12_key_type_t;
typedef struct pkcs12_t pkcs12_t;
/**
* The types of password based keys used by PKCS#12.
*/
enum pkcs12_key_type_t {
PKCS12_KEY_ENCRYPTION = 1,
PKCS12_KEY_IV = 2,
PKCS12_KEY_MAC = 3,
};
/**
* PKCS#12/PFX container type.
*/
struct pkcs12_t {
/**
* Implements container_t.
*/
container_t container;
/**
* Create an enumerator over extracted certificates.
*
* @return enumerator over certificate_t
*/
enumerator_t* (*create_cert_enumerator)(pkcs12_t *this);
/**
* Create an enumerator over extracted private keys.
*
* @return enumerator over private_key_t
*/
enumerator_t* (*create_key_enumerator)(pkcs12_t *this);
};
/**
* Derive the keys used in PKCS#12 for password integrity/privacy mode.
*
* @param hash hash algorithm to use for key derivation
* @param password password (ASCII)
* @param salt salt value
* @param iterations number of iterations
* @param type type of key to derive
* @param key the returned key, must be allocated of desired length
* @return TRUE on success
*/
bool pkcs12_derive_key(hash_algorithm_t hash, chunk_t password, chunk_t salt,
u_int64_t iterations, pkcs12_key_type_t type, chunk_t key);
#endif /** PKCS12_H_ @}*/
+4 -3
View File
@@ -46,12 +46,13 @@ ENUM_NEXT(encryption_algorithm_names, ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CCM_ICV16
"CAMELLIA_CCM_8",
"CAMELLIA_CCM_12",
"CAMELLIA_CCM_16");
ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_TWOFISH_CBC, ENCR_CAMELLIA_CCM_ICV16,
ENUM_NEXT(encryption_algorithm_names, ENCR_UNDEFINED, ENCR_RC2_CBC, ENCR_CAMELLIA_CCM_ICV16,
"UNDEFINED",
"DES_ECB",
"SERPENT_CBC",
"TWOFISH_CBC");
ENUM_END(encryption_algorithm_names, ENCR_TWOFISH_CBC);
"TWOFISH_CBC",
"RC2_CBC");
ENUM_END(encryption_algorithm_names, ENCR_RC2_CBC);
/*
* Described in header.
+12 -1
View File
@@ -60,7 +60,9 @@ enum encryption_algorithm_t {
ENCR_UNDEFINED = 1024,
ENCR_DES_ECB = 1025,
ENCR_SERPENT_CBC = 1026,
ENCR_TWOFISH_CBC = 1027
ENCR_TWOFISH_CBC = 1027,
/* see macros below to handle RC2 (effective) key length */
ENCR_RC2_CBC = 1028,
};
#define DES_BLOCK_SIZE 8
@@ -70,6 +72,15 @@ enum encryption_algorithm_t {
#define SERPENT_BLOCK_SIZE 16
#define TWOFISH_BLOCK_SIZE 16
/**
* For RC2, if the effective key size in bits is not key_size * 8, it should
* be encoded with the macro below. It can be decoded with the other two macros.
* After decoding the value should be validated.
*/
#define RC2_KEY_SIZE(kl, eff) ((kl) | ((eff) << 8))
#define RC2_EFFECTIVE_KEY_LEN(ks) ((ks) >> 8)
#define RC2_KEY_LEN(ks) ((ks) & 0xff)
/**
* enum name for encryption_algorithm_t.
*/
+4 -1
View File
@@ -265,7 +265,10 @@ METHOD(crypto_tester_t, test_crypter, bool,
failure:
crypter->destroy(crypter);
chunk_free(&cipher);
chunk_free(&plain);
if (plain.ptr != vector->plain)
{
chunk_free(&plain);
}
if (failed)
{
DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed",
+72
View File
@@ -141,6 +141,9 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg,
case AUTH_HMAC_SHA2_384_384:
*length = 48;
break;
case AUTH_HMAC_SHA2_512_512:
*length = 64;
break;
default:
break;
}
@@ -163,6 +166,7 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg,
case AUTH_HMAC_SHA2_384_384:
return HASH_SHA384;
case AUTH_HMAC_SHA2_512_256:
case AUTH_HMAC_SHA2_512_512:
return HASH_SHA512;
case AUTH_AES_CMAC_96:
case AUTH_AES_128_GMAC:
@@ -177,6 +181,74 @@ hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg,
return HASH_UNKNOWN;
}
/*
* Described in header.
*/
integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg,
size_t length)
{
switch (alg)
{
case HASH_MD5:
switch (length)
{
case 12:
return AUTH_HMAC_MD5_96;
case 16:
return AUTH_HMAC_MD5_128;
}
break;
case HASH_SHA1:
case HASH_PREFERRED:
switch (length)
{
case 12:
return AUTH_HMAC_SHA1_96;
case 16:
return AUTH_HMAC_SHA1_128;
case 20:
return AUTH_HMAC_SHA1_160;
}
break;
case HASH_SHA256:
switch (length)
{
case 12:
return AUTH_HMAC_SHA2_256_96;
case 16:
return AUTH_HMAC_SHA2_256_128;
case 32:
return AUTH_HMAC_SHA2_256_256;
}
break;
case HASH_SHA384:
switch (length)
{
case 24:
return AUTH_HMAC_SHA2_384_192;
case 48:
return AUTH_HMAC_SHA2_384_384;
}
break;
case HASH_SHA512:
switch (length)
{
case 32:
return AUTH_HMAC_SHA2_512_256;
case 64:
return AUTH_HMAC_SHA2_512_512;
}
break;
case HASH_MD2:
case HASH_MD4:
case HASH_SHA224:
case HASH_UNKNOWN:
break;
}
return AUTH_UNDEFINED;
}
/*
* Described in header.
*/
+11
View File
@@ -153,6 +153,17 @@ hash_algorithm_t hasher_algorithm_from_prf(pseudo_random_function_t alg);
hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg,
size_t *length);
/**
* Conversion of hash algorithm to integrity algorithm (if based on a hash).
*
* @param alg hash algorithm
* @param length length of the signature
* @return integrity algorithm, AUTH_UNDEFINED if none is known
* based on the given hash function
*/
integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg,
size_t length);
/**
* Conversion of hash algorithm into ASN.1 OID.
*
+651
View File
@@ -0,0 +1,651 @@
/*
* Copyright (C) 2012-2013 Tobias Brunner
* 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 "pkcs5.h"
#include <utils/debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <credentials/containers/pkcs12.h>
typedef struct private_pkcs5_t private_pkcs5_t;
/**
* Private data of a pkcs5_t object
*/
struct private_pkcs5_t {
/**
* Implements pkcs5_t.
*/
pkcs5_t public;
/**
* Salt used during encryption
*/
chunk_t salt;
/**
* Iterations for key derivation
*/
u_int64_t iterations;
/**
* Encryption algorithm
*/
encryption_algorithm_t encr;
/**
* Encryption key length
*/
size_t keylen;
/**
* Crypter
*/
crypter_t *crypter;
/**
* The encryption scheme
*/
enum {
PKCS5_SCHEME_PBES1,
PKCS5_SCHEME_PBES2,
PKCS5_SCHEME_PKCS12,
} scheme;
/**
* Data used for individual schemes
*/
union {
struct {
/**
* Hash algorithm
*/
hash_algorithm_t hash;
/**
* Hasher
*/
hasher_t *hasher;
} pbes1;
struct {
/**
* PRF algorithm
*/
pseudo_random_function_t prf_alg;
/**
* PRF
*/
prf_t * prf;
/**
* IV
*/
chunk_t iv;
} pbes2;
} data;
};
/**
* Verify padding of decrypted blob.
* Length of blob is adjusted accordingly.
*/
static bool verify_padding(chunk_t *blob)
{
u_int8_t padding, count;
padding = count = blob->ptr[blob->len - 1];
if (padding > 8)
{
return FALSE;
}
for (; blob->len && count; --blob->len, --count)
{
if (blob->ptr[blob->len - 1] != padding)
{
return FALSE;
}
}
return TRUE;
}
/**
* Prototype for key derivation functions.
*/
typedef bool (*kdf_t)(private_pkcs5_t *this, chunk_t password, chunk_t key);
/**
* Try to decrypt the given data with the given password using the given
* key derivation function. keymat is where the kdf function writes the key
* to, key and iv point to the actual keys and initialization vectors resp.
*/
static bool decrypt_generic(private_pkcs5_t *this, chunk_t password,
chunk_t data, chunk_t *decrypted, kdf_t kdf,
chunk_t keymat, chunk_t key, chunk_t iv)
{
if (!kdf(this, password, keymat))
{
return FALSE;
}
if (!this->crypter->set_key(this->crypter, key) ||
!this->crypter->decrypt(this->crypter, data, iv, decrypted))
{
memwipe(keymat.ptr, keymat.len);
return FALSE;
}
memwipe(keymat.ptr, keymat.len);
if (verify_padding(decrypted))
{
return TRUE;
}
chunk_free(decrypted);
return FALSE;
}
/**
* KDF as used by PKCS#12
*/
static bool pkcs12_kdf(private_pkcs5_t *this, chunk_t password, chunk_t keymat)
{
chunk_t key, iv;
key = chunk_create(keymat.ptr, this->keylen);
iv = chunk_create(keymat.ptr + this->keylen, keymat.len - this->keylen);
return pkcs12_derive_key(this->data.pbes1.hash, password, this->salt,
this->iterations, PKCS12_KEY_ENCRYPTION, key) &&
pkcs12_derive_key(this->data.pbes1.hash, password, this->salt,
this->iterations, PKCS12_KEY_IV, iv);
}
/**
* Function F of PBKDF2
*/
static bool pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed,
u_int64_t iterations)
{
chunk_t u;
u_int64_t i;
u = chunk_alloca(prf->get_block_size(prf));
if (!prf->get_bytes(prf, seed, u.ptr))
{
return FALSE;
}
memcpy(block.ptr, u.ptr, block.len);
for (i = 1; i < iterations; i++)
{
if (!prf->get_bytes(prf, u, u.ptr))
{
return FALSE;
}
memxor(block.ptr, u.ptr, block.len);
}
return TRUE;
}
/**
* PBKDF2 key derivation function for PBES2, key must be allocated
*/
static bool pbkdf2(private_pkcs5_t *this, chunk_t password, chunk_t key)
{
prf_t *prf;
chunk_t keymat, block, seed;
size_t blocks;
u_int32_t i = 0;
prf = this->data.pbes2.prf;
if (!prf->set_key(prf, password))
{
return FALSE;
}
block.len = prf->get_block_size(prf);
blocks = (key.len - 1) / block.len + 1;
keymat = chunk_alloca(blocks * block.len);
seed = chunk_cata("cc", this->salt, chunk_from_thing(i));
for (; i < blocks; i++)
{
htoun32(seed.ptr + this->salt.len, i + 1);
block.ptr = keymat.ptr + (i * block.len);
if (!pbkdf2_f(block, prf, seed, this->iterations))
{
return FALSE;
}
}
memcpy(key.ptr, keymat.ptr, key.len);
return TRUE;
}
/**
* PBKDF1 key derivation function for PBES1, key must be allocated
*/
static bool pbkdf1(private_pkcs5_t *this, chunk_t password, chunk_t key)
{
hasher_t *hasher;
chunk_t hash;
u_int64_t i;
hasher = this->data.pbes1.hasher;
hash = chunk_alloca(hasher->get_hash_size(hasher));
if (!hasher->get_hash(hasher, password, NULL) ||
!hasher->get_hash(hasher, this->salt, hash.ptr))
{
return FALSE;
}
for (i = 1; i < this->iterations; i++)
{
if (!hasher->get_hash(hasher, hash, hash.ptr))
{
return FALSE;
}
}
memcpy(key.ptr, hash.ptr, key.len);
return TRUE;
}
static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data)
{
if (!this->crypter)
{
this->crypter = lib->crypto->create_crypter(lib->crypto, this->encr,
this->keylen);
if (!this->crypter)
{
DBG1(DBG_ASN, " %N encryption algorithm not available",
encryption_algorithm_names, this->encr);
return FALSE;
}
}
if (data.len % this->crypter->get_block_size(this->crypter))
{
DBG1(DBG_ASN, " data size is not a multiple of block size");
return FALSE;
}
switch (this->scheme)
{
case PKCS5_SCHEME_PBES1:
{
if (!this->data.pbes1.hasher)
{
hasher_t *hasher;
hasher = lib->crypto->create_hasher(lib->crypto,
this->data.pbes1.hash);
if (!hasher)
{
DBG1(DBG_ASN, " %N hash algorithm not available",
hash_algorithm_names, this->data.pbes1.hash);
return FALSE;
}
if (hasher->get_hash_size(hasher) < this->keylen)
{
hasher->destroy(hasher);
return FALSE;
}
this->data.pbes1.hasher = hasher;
}
}
case PKCS5_SCHEME_PBES2:
{
if (!this->data.pbes2.prf)
{
prf_t *prf;
prf = lib->crypto->create_prf(lib->crypto,
this->data.pbes2.prf_alg);
if (!prf)
{
DBG1(DBG_ASN, " %N prf algorithm not available",
pseudo_random_function_names,
this->data.pbes2.prf_alg);
return FALSE;
}
this->data.pbes2.prf = prf;
}
}
case PKCS5_SCHEME_PKCS12:
break;
}
return TRUE;
}
METHOD(pkcs5_t, decrypt, bool,
private_pkcs5_t *this, chunk_t password, chunk_t data, chunk_t *decrypted)
{
chunk_t keymat, key, iv;
kdf_t kdf;
if (!ensure_crypto_primitives(this, data) || !decrypted)
{
return FALSE;
}
kdf = pbkdf1;
switch (this->scheme)
{
case PKCS5_SCHEME_PKCS12:
kdf = pkcs12_kdf;
/* fall-through */
case PKCS5_SCHEME_PBES1:
keymat = chunk_alloca(this->keylen +
this->crypter->get_iv_size(this->crypter));
key = chunk_create(keymat.ptr, this->keylen);
iv = chunk_create(keymat.ptr + this->keylen,
keymat.len - this->keylen);
break;
case PKCS5_SCHEME_PBES2:
kdf = pbkdf2;
keymat = chunk_alloca(this->keylen);
key = keymat;
iv = this->data.pbes2.iv;
break;
default:
return FALSE;
}
return decrypt_generic(this, password, data, decrypted, kdf,
keymat, key, iv);
}
/**
* ASN.1 definition of a PBEParameter structure
*/
static const asn1Object_t pbeParameterObjects[] = {
{ 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
{ 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBEPARAM_SALT 1
#define PBEPARAM_ITERATION_COUNT 2
/**
* Parse a PBEParameter structure
*/
static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success;
parser = asn1_parser_create(pbeParameterObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBEPARAM_SALT:
{
this->salt = chunk_clone(object);
break;
}
case PBEPARAM_ITERATION_COUNT:
{
this->iterations = asn1_parse_integer_uint64(object);
break;
}
}
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of a PBKDF2-params structure
* The salt is actually a CHOICE and could be an AlgorithmIdentifier from
* PBKDF2-SaltSources (but as per RFC 2898 that's for future versions).
*/
static const asn1Object_t pbkdf2ParamsObjects[] = {
{ 0, "PBKDF2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
{ 1, "iterationCount",ASN1_INTEGER, ASN1_BODY }, /* 2 */
{ 1, "keyLength", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 3 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
{ 1, "prf", ASN1_EOC, ASN1_DEF|ASN1_RAW }, /* 5 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBKDF2_SALT 1
#define PBKDF2_ITERATION_COUNT 2
#define PBKDF2_KEYLENGTH 3
#define PBKDF2_PRF 5
/**
* Parse a PBKDF2-params structure
*/
static bool parse_pbkdf2_params(private_pkcs5_t *this, chunk_t blob, int level0)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success;
parser = asn1_parser_create(pbkdf2ParamsObjects, blob);
parser->set_top_level(parser, level0);
/* keylen is optional */
this->keylen = 0;
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBKDF2_SALT:
{
this->salt = chunk_clone(object);
break;
}
case PBKDF2_ITERATION_COUNT:
{
this->iterations = asn1_parse_integer_uint64(object);
break;
}
case PBKDF2_KEYLENGTH:
{
this->keylen = (size_t)asn1_parse_integer_uint64(object);
break;
}
case PBKDF2_PRF:
{ /* defaults to id-hmacWithSHA1, no other is currently defined */
this->data.pbes2.prf_alg = PRF_HMAC_SHA1;
break;
}
}
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of a PBES2-params structure
*/
static const asn1Object_t pbes2ParamsObjects[] = {
{ 0, "PBES2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "keyDerivationFunc", ASN1_EOC, ASN1_RAW }, /* 1 */
{ 1, "encryptionScheme", ASN1_EOC, ASN1_RAW }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBES2PARAMS_KEY_DERIVATION_FUNC 1
#define PBES2PARAMS_ENCRYPTION_SCHEME 2
/**
* Parse a PBES2-params structure
*/
static bool parse_pbes2_params(private_pkcs5_t *this, chunk_t blob, int level0)
{
asn1_parser_t *parser;
chunk_t object, params;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(pbes2ParamsObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBES2PARAMS_KEY_DERIVATION_FUNC:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser) + 1, &params);
if (oid != OID_PBKDF2)
{ /* unsupported key derivation function */
goto end;
}
if (!parse_pbkdf2_params(this, params,
parser->get_level(parser) + 1))
{
goto end;
}
break;
}
case PBES2PARAMS_ENCRYPTION_SCHEME:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser) + 1, &params);
if (oid != OID_3DES_EDE_CBC)
{ /* unsupported encryption scheme */
goto end;
}
if (this->keylen <= 0)
{ /* default key length for DES-EDE3-CBC-Pad */
this->keylen = 24;
}
if (!asn1_parse_simple_object(&params, ASN1_OCTET_STRING,
parser->get_level(parser) + 1, "IV"))
{
goto end;
}
this->encr = ENCR_3DES;
this->data.pbes2.iv = chunk_clone(params);
break;
}
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
return success;
}
METHOD(pkcs5_t, destroy, void,
private_pkcs5_t *this)
{
DESTROY_IF(this->crypter);
chunk_free(&this->salt);
switch (this->scheme)
{
case PKCS5_SCHEME_PBES1:
DESTROY_IF(this->data.pbes1.hasher);
break;
case PKCS5_SCHEME_PBES2:
DESTROY_IF(this->data.pbes2.prf);
chunk_free(&this->data.pbes2.iv);
break;
case PKCS5_SCHEME_PKCS12:
break;
}
free(this);
}
/*
* Described in header
*/
pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0)
{
private_pkcs5_t *this;
chunk_t params;
int oid;
INIT(this,
.public = {
.decrypt = _decrypt,
.destroy = _destroy,
},
.scheme = PKCS5_SCHEME_PBES1,
.keylen = 8,
);
oid = asn1_parse_algorithmIdentifier(blob, level0, &params);
switch (oid)
{
case OID_PBE_MD5_DES_CBC:
this->encr = ENCR_DES;
this->data.pbes1.hash = HASH_MD5;
break;
case OID_PBE_SHA1_DES_CBC:
this->encr = ENCR_DES;
this->data.pbes1.hash = HASH_SHA1;
break;
case OID_PBE_SHA1_3DES_CBC:
this->scheme = PKCS5_SCHEME_PKCS12;
this->keylen = 24;
this->encr = ENCR_3DES;
this->data.pbes1.hash = HASH_SHA1;
break;
case OID_PBE_SHA1_RC2_CBC_40:
case OID_PBE_SHA1_RC2_CBC_128:
this->scheme = PKCS5_SCHEME_PKCS12;
this->keylen = (oid == OID_PBE_SHA1_RC2_CBC_40) ? 5 : 16;
this->encr = ENCR_RC2_CBC;
this->data.pbes1.hash = HASH_SHA1;
break;
case OID_PBES2:
this->scheme = PKCS5_SCHEME_PBES2;
break;
default:
/* encryption scheme not supported */
goto failure;
}
switch (this->scheme)
{
case PKCS5_SCHEME_PBES1:
case PKCS5_SCHEME_PKCS12:
if (!parse_pbes1_params(this, params, level0))
{
goto failure;
}
break;
case PKCS5_SCHEME_PBES2:
if (!parse_pbes2_params(this, params, level0))
{
goto failure;
}
break;
}
return &this->public;
failure:
destroy(this);
return NULL;
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 pkcs5 pkcs5
* @{ @ingroup crypto
*/
#ifndef PKCS5_H_
#define PKCS5_H_
typedef struct pkcs5_t pkcs5_t;
#include <utils/chunk.h>
/**
* PKCS#5 helper class
*/
struct pkcs5_t {
/**
* Decrypt the given data using the given password and the scheme derived
* from the initial AlgorithmIdentifier object.
*
* @param password password used for decryption
* @param data data to decrypt
* @param decrypted decrypted data gets allocated
* @return TRUE on success, FALSE otherwise
*/
bool (*decrypt)(pkcs5_t *this, chunk_t password, chunk_t data,
chunk_t *decrypted) __attribute__((warn_unused_result));
/**
* Destroy the object and any associated cryptographic primitive.
*/
void (*destroy)(pkcs5_t *this);
};
/**
* Create a PKCS#5 helper object from an ASN.1 encoded AlgorithmIdentifier
* object.
*
* @param blob ASN.1 encoded AlgorithmIdentifier
* @param level0 ASN.1 parser level
* @return pkcs5_t object, NULL on failure
*/
pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0);
#endif /** PKCS5_H_ @}*/
+3 -1
View File
@@ -70,8 +70,10 @@ enum integrity_algorithm_t {
AUTH_HMAC_SHA2_256_256 = 1027,
/** SHA384 full length truncation variant, as used in TLS */
AUTH_HMAC_SHA2_384_384 = 1028,
/** SHA512 full length truncation variant */
AUTH_HMAC_SHA2_512_512 = 1029,
/** draft-kanno-ipsecme-camellia-xcbc, not yet assigned by IANA */
AUTH_CAMELLIA_XCBC_96 = 1029,
AUTH_CAMELLIA_XCBC_96 = 1030,
};
/**
@@ -64,6 +64,7 @@ static struct {
{AUTH_HMAC_SHA2_384_192, "hmac(sha384)", 24, 48, },
{AUTH_HMAC_SHA2_384_384, "hmac(sha384)", 48, 48, },
{AUTH_HMAC_SHA2_512_256, "hmac(sha512)", 32, 64, },
{AUTH_HMAC_SHA2_512_512, "hmac(sha512)", 64, 64, },
{AUTH_AES_XCBC_96, "xcbc(aes)", 12, 16, },
{AUTH_CAMELLIA_XCBC_96, "xcbc(camellia)", 12, 16, },
};
@@ -73,6 +73,8 @@ METHOD(plugin_t, get_features, int,
PLUGIN_DEPENDS(HASHER, HASH_SHA384),
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256),
PLUGIN_DEPENDS(HASHER, HASH_SHA512),
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512),
PLUGIN_DEPENDS(HASHER, HASH_SHA512),
};
*features = f;
return countof(f);
@@ -24,6 +24,7 @@ libstrongswan_openssl_la_SOURCES = \
openssl_x509.c openssl_x509.h \
openssl_crl.c openssl_crl.h \
openssl_pkcs7.c openssl_pkcs7.h \
openssl_pkcs12.c openssl_pkcs12.h \
openssl_rng.c openssl_rng.h \
openssl_hmac.c openssl_hmac.h \
openssl_gcm.c openssl_gcm.h
@@ -0,0 +1,266 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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.
*/
#define _GNU_SOURCE /* for asprintf() */
#include <stdio.h>
#include <openssl/pkcs12.h>
#include "openssl_pkcs12.h"
#include "openssl_util.h"
#include <library.h>
#include <credentials/sets/mem_cred.h>
typedef struct private_pkcs12_t private_pkcs12_t;
/**
* Private data of a pkcs12_t object.
*/
struct private_pkcs12_t {
/**
* Public pkcs12_t interface.
*/
pkcs12_t public;
/**
* OpenSSL PKCS#12 structure
*/
PKCS12 *p12;
/**
* Credentials contained in container
*/
mem_cred_t *creds;
};
/**
* Decode certificate and add it to our credential set
*/
static bool add_cert(private_pkcs12_t *this, X509 *x509)
{
certificate_t *cert = NULL;
chunk_t encoding;
if (!x509)
{ /* no certificate is ok */
return TRUE;
}
encoding = openssl_i2chunk(X509, x509);
if (encoding.ptr)
{
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_ASN1_DER, encoding,
BUILD_END);
if (cert)
{
this->creds->add_cert(this->creds, FALSE, cert);
}
}
chunk_free(&encoding);
X509_free(x509);
return cert != NULL;
}
/**
* Add CA certificates to our credential set
*/
static bool add_cas(private_pkcs12_t *this, STACK_OF(X509) *cas)
{
bool success = TRUE;
int i;
if (!cas)
{ /* no CAs is ok */
return TRUE;
}
for (i = 0; i < sk_X509_num(cas); i++)
{
if (!add_cert(this, sk_X509_value(cas, i)))
{ /* continue to free all X509 objects */
success = FALSE;
}
}
sk_X509_free(cas);
return success;
}
/**
* Decode private key and add it to our credential set
*/
static bool add_key(private_pkcs12_t *this, EVP_PKEY *private)
{
private_key_t *key = NULL;
chunk_t encoding;
key_type_t type;
if (!private)
{ /* no private key is ok */
return TRUE;
}
switch (EVP_PKEY_type(private->type))
{
case EVP_PKEY_RSA:
type = KEY_RSA;
break;
case EVP_PKEY_EC:
type = KEY_ECDSA;
break;
default:
EVP_PKEY_free(private);
return FALSE;
}
encoding = openssl_i2chunk(PrivateKey, private);
if (encoding.ptr)
{
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
BUILD_BLOB_ASN1_DER, encoding,
BUILD_END);
if (key)
{
this->creds->add_key(this->creds, key);
}
}
chunk_clear(&encoding);
EVP_PKEY_free(private);
return key != NULL;
}
/**
* Decrypt PKCS#12 file and unpack credentials
*/
static bool decrypt_and_unpack(private_pkcs12_t *this)
{
enumerator_t *enumerator;
shared_key_t *shared;
STACK_OF(X509) *cas = NULL;
EVP_PKEY *private;
X509 *cert;
chunk_t key;
char *password;
bool success = FALSE;
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
SHARED_PRIVATE_KEY_PASS, NULL, NULL);
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
{
key = shared->get_key(shared);
if (!key.ptr || asprintf(&password, "%.*s", (int)key.len, key.ptr) < 0)
{
password = NULL;
}
if (PKCS12_parse(this->p12, password, &private, &cert, &cas))
{
success = add_key(this, private);
success &= add_cert(this, cert);
success &= add_cas(this, cas);
free(password);
break;
}
free(password);
}
enumerator->destroy(enumerator);
return success;
}
METHOD(container_t, get_type, container_type_t,
private_pkcs12_t *this)
{
return CONTAINER_PKCS12;
}
METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
private_pkcs12_t *this)
{
return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
KEY_ANY, NULL, FALSE);
}
METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
private_pkcs12_t *this)
{
return this->creds->set.create_private_enumerator(&this->creds->set,
KEY_ANY, NULL);
}
METHOD(container_t, destroy, void,
private_pkcs12_t *this)
{
if (this->p12)
{
PKCS12_free(this->p12);
}
this->creds->destroy(this->creds);
free(this);
}
/**
* Parse a PKCS#12 container
*/
static pkcs12_t *parse(chunk_t blob)
{
private_pkcs12_t *this;
BIO *bio;
INIT(this,
.public = {
.container = {
.get_type = _get_type,
.create_signature_enumerator = (void*)enumerator_create_empty,
.get_data = (void*)return_false,
.get_encoding = (void*)return_false,
.destroy = _destroy,
},
.create_cert_enumerator = _create_cert_enumerator,
.create_key_enumerator = _create_key_enumerator,
},
.creds = mem_cred_create(),
);
bio = BIO_new_mem_buf(blob.ptr, blob.len);
this->p12 = d2i_PKCS12_bio(bio, NULL);
BIO_free(bio);
if (!this->p12 || !decrypt_and_unpack(this))
{
destroy(this);
return NULL;
}
return &this->public;
}
/*
* Defined in header
*/
pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args)
{
chunk_t blob = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_BLOB_ASN1_DER:
blob = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
return blob.len ? parse(blob) : NULL;
}
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 openssl_pkcs12 openssl_pkcs12
* @{ @ingroup openssl_p
*/
#ifndef OPENSSL_PKCS12_H_
#define OPENSSL_PKCS12_H_
#include <credentials/containers/pkcs12.h>
/**
* Load a PKCS#12 container.
*
* The argument list must contain a single BUILD_BLOB_ASN1_DER argument.
*
* @param type type of the container, CONTAINER_PKCS12
* @param args builder_part_t argument list
* @return container, NULL on failure
*/
pkcs12_t *openssl_pkcs12_load(container_type_t type, va_list args);
#endif /** OPENSSL_PKCS12_H_ @}*/
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2008-2013 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -14,6 +14,7 @@
* for more details.
*/
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/conf.h>
#include <openssl/rand.h>
@@ -28,6 +29,7 @@
#include <utils/debug.h>
#include <threading/thread.h>
#include <threading/mutex.h>
#include <threading/thread_value.h>
#include "openssl_util.h"
#include "openssl_crypter.h"
#include "openssl_hasher.h"
@@ -41,6 +43,7 @@
#include "openssl_x509.h"
#include "openssl_crl.h"
#include "openssl_pkcs7.h"
#include "openssl_pkcs12.h"
#include "openssl_rng.h"
#include "openssl_hmac.h"
#include "openssl_gcm.h"
@@ -130,16 +133,53 @@ static void destroy_function(struct CRYPTO_dynlock_value *lock,
free(lock);
}
/**
* Thread-local value used to cleanup thread-specific error buffers
*/
static thread_value_t *cleanup;
/**
* Called when a thread is destroyed. Avoid recursion by setting the thread id
* explicitly.
*/
static void cleanup_thread(void *arg)
{
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
CRYPTO_THREADID tid;
CRYPTO_THREADID_set_numeric(&tid, (u_long)(uintptr_t)arg);
ERR_remove_thread_state(&tid);
#else
ERR_remove_state((u_long)(uintptr_t)arg);
#endif
}
/**
* Thread-ID callback function
*/
static unsigned long id_function(void)
static u_long id_function(void)
{
u_long id;
/* ensure the thread ID is never zero, otherwise OpenSSL might try to
* acquire locks recursively */
return 1 + (unsigned long)thread_current_id();
id = 1 + (u_long)thread_current_id();
/* cleanup a thread's state later if OpenSSL interacted with it */
cleanup->set(cleanup, (void*)(uintptr_t)id);
return id;
}
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
/**
* Callback for thread ID
*/
static void threadid_function(CRYPTO_THREADID *threadid)
{
CRYPTO_THREADID_set_numeric(threadid, id_function());
}
#endif /* OPENSSL_VERSION_NUMBER */
/**
* initialize OpenSSL for multi-threaded use
*/
@@ -147,7 +187,14 @@ static void threading_init()
{
int i, num_locks;
cleanup = thread_value_create(cleanup_thread);
#if OPENSSL_VERSION_NUMBER >= 0x1000000fL
CRYPTO_THREADID_set_callback(threadid_function);
#else
CRYPTO_set_id_callback(id_function);
#endif
CRYPTO_set_locking_callback(locking_function);
CRYPTO_set_dynlock_create_callback(create_function);
@@ -162,6 +209,24 @@ static void threading_init()
}
}
/**
* cleanup OpenSSL threading locks
*/
static void threading_cleanup()
{
int i, num_locks;
num_locks = CRYPTO_num_locks();
for (i = 0; i < num_locks; i++)
{
mutex[i]->destroy(mutex[i]);
}
free(mutex);
mutex = NULL;
cleanup->destroy(cleanup);
}
/**
* Seed the OpenSSL RNG, if required
*/
@@ -191,22 +256,6 @@ static bool seed_rng()
return TRUE;
}
/**
* cleanup OpenSSL threading locks
*/
static void threading_cleanup()
{
int i, num_locks;
num_locks = CRYPTO_num_locks();
for (i = 0; i < num_locks; i++)
{
mutex[i]->destroy(mutex[i]);
}
free(mutex);
mutex = NULL;
}
METHOD(plugin_t, get_name, char*,
private_openssl_plugin_t *this)
{
@@ -307,6 +356,7 @@ METHOD(plugin_t, get_features, int,
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_192),
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_384),
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256),
PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512),
#endif
#endif /* OPENSSL_NO_HMAC */
#if OPENSSL_VERSION_NUMBER >= 0x1000100fL
@@ -392,6 +442,8 @@ METHOD(plugin_t, get_features, int,
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS7),
#endif /* OPENSSL_NO_CMS */
#endif /* OPENSSL_VERSION_NUMBER */
PLUGIN_REGISTER(CONTAINER_DECODE, openssl_pkcs12_load, TRUE),
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS12),
#ifndef OPENSSL_NO_ECDH
/* EC DH groups */
PLUGIN_REGISTER(DH, openssl_ec_diffie_hellman_create),
@@ -444,13 +496,15 @@ METHOD(plugin_t, get_features, int,
METHOD(plugin_t, destroy, void,
private_openssl_plugin_t *this)
{
CONF_modules_free();
OBJ_cleanup();
EVP_cleanup();
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif /* OPENSSL_NO_ENGINE */
EVP_cleanup();
CONF_modules_free();
CRYPTO_cleanup_all_ex_data();
threading_cleanup();
ERR_free_strings();
free(this);
}
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Copyright (C) 2001-2008 Andreas Steffen
* Hochschule fuer Technik Rapperswil
@@ -564,3 +565,10 @@ certificate_t *pem_certificate_load(certificate_type_t type, va_list args)
return pem_load(CRED_CERTIFICATE, type, args);
}
/**
* Container PEM loader.
*/
container_t *pem_container_load(container_type_t type, va_list args)
{
return pem_load(CRED_CONTAINER, type, args);
}
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -25,6 +26,7 @@
#include <credentials/credential_factory.h>
#include <credentials/keys/private_key.h>
#include <credentials/certificates/certificate.h>
#include <credentials/containers/container.h>
/**
* Load PEM encoded private keys.
@@ -53,5 +55,14 @@ public_key_t *pem_public_key_load(key_type_t type, va_list args);
*/
certificate_t *pem_certificate_load(certificate_type_t type, va_list args);
/**
* Build PEM encoded containers.
*
* @param type type of the container
* @param args builder_part_t argument list
* @return container, NULL if failed
*/
container_t *pem_container_load(container_type_t type, va_list args);
#endif /** PEM_BUILDER_H_ @}*/
+4 -5
View File
@@ -105,11 +105,10 @@ METHOD(plugin_t, get_features, int,
PLUGIN_PROVIDE(CERT_DECODE, CERT_GPG),
PLUGIN_DEPENDS(CERT_DECODE, CERT_GPG),
/* pluto specific certificate formats */
PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE),
PLUGIN_PROVIDE(CERT_DECODE, CERT_PLUTO_CERT),
PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE),
PLUGIN_PROVIDE(CERT_DECODE, CERT_PLUTO_CRL),
/* container PEM decoding */
PLUGIN_REGISTER(CONTAINER_DECODE, pem_container_load, FALSE),
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS12),
PLUGIN_DEPENDS(CONTAINER_DECODE, CONTAINER_PKCS12),
};
*features = f;
return countof(f);
@@ -0,0 +1,16 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-pkcs12.la
else
plugin_LTLIBRARIES = libstrongswan-pkcs12.la
endif
libstrongswan_pkcs12_la_SOURCES = \
pkcs12_plugin.h pkcs12_plugin.c \
pkcs12_decode.h pkcs12_decode.c
libstrongswan_pkcs12_la_LDFLAGS = -module -avoid-version
@@ -0,0 +1,581 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 "pkcs12_decode.h"
#include <utils/debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <credentials/sets/mem_cred.h>
typedef struct private_pkcs12_t private_pkcs12_t;
/**
* Private data of a pkcs12_t object
*/
struct private_pkcs12_t {
/**
* Public interface
*/
pkcs12_t public;
/**
* Contained credentials
*/
mem_cred_t *creds;
};
METHOD(container_t, get_type, container_type_t,
private_pkcs12_t *this)
{
return CONTAINER_PKCS12;
}
METHOD(container_t, get_data, bool,
private_pkcs12_t *this, chunk_t *data)
{
/* we could return the content of the outer-most PKCS#7 container (authSafe)
* don't really see the point though */
return FALSE;
}
METHOD(container_t, get_encoding, bool,
private_pkcs12_t *this, chunk_t *encoding)
{
/* similar to get_data() we don't have any use for it at the moment */
return FALSE;
}
METHOD(pkcs12_t, create_cert_enumerator, enumerator_t*,
private_pkcs12_t *this)
{
return this->creds->set.create_cert_enumerator(&this->creds->set, CERT_ANY,
KEY_ANY, NULL, FALSE);
}
METHOD(pkcs12_t, create_key_enumerator, enumerator_t*,
private_pkcs12_t *this)
{
return this->creds->set.create_private_enumerator(&this->creds->set,
KEY_ANY, NULL);
}
METHOD(container_t, destroy, void,
private_pkcs12_t *this)
{
this->creds->destroy(this->creds);
free(this);
}
static private_pkcs12_t *pkcs12_create()
{
private_pkcs12_t *this;
INIT(this,
.public = {
.container = {
.get_type = _get_type,
.create_signature_enumerator = (void*)enumerator_create_empty,
.get_data = _get_data,
.get_encoding = _get_encoding,
.destroy = _destroy,
},
.create_cert_enumerator = _create_cert_enumerator,
.create_key_enumerator = _create_key_enumerator,
},
.creds = mem_cred_create(),
);
return this;
}
/**
* ASN.1 definition of an CertBag structure
*/
static const asn1Object_t certBagObjects[] = {
{ 0, "CertBag", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
{ 1, "certId", ASN1_OID, ASN1_BODY }, /* 1 */
{ 1, "certValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define CERT_BAG_ID 1
#define CERT_BAG_VALUE 2
/**
* Parse a CertBag structure and extract certificate
*/
static bool add_certificate(private_pkcs12_t *this, int level0, chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
int oid = OID_UNKNOWN;
bool success = FALSE;
parser = asn1_parser_create(certBagObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case CERT_BAG_ID:
oid = asn1_known_oid(object);
break;
case CERT_BAG_VALUE:
{
if (oid == OID_X509_CERTIFICATE &&
asn1_parse_simple_object(&object, ASN1_OCTET_STRING,
parser->get_level(parser)+1, "x509Certificate"))
{
certificate_t *cert;
DBG2(DBG_ASN, "-- > parsing certificate from PKCS#12");
cert = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509,
BUILD_BLOB_ASN1_DER, object,
BUILD_END);
if (cert)
{
this->creds->add_cert(this->creds, FALSE, cert);
DBG2(DBG_ASN, "-- < --");
}
else
{
DBG2(DBG_ASN, "-- < failed parsing certificate from "
"PKCS#12");
}
}
break;
}
}
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of an AuthenticatedSafe structure
*/
static const asn1Object_t safeContentsObjects[] = {
{ 0, "SafeContents", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
{ 1, "SafeBag", ASN1_SEQUENCE, ASN1_BODY }, /* 1 */
{ 2, "bagId", ASN1_OID, ASN1_BODY }, /* 2 */
{ 2, "bagValue", ASN1_CONTEXT_C_0, ASN1_BODY }, /* 3 */
{ 2, "bagAttr", ASN1_SET, ASN1_OPT|ASN1_RAW }, /* 4 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 5 */
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define SAFE_BAG_ID 2
#define SAFE_BAG_VALUE 3
/**
* Parse a SafeContents structure and extract credentials
*/
static bool parse_safe_contents(private_pkcs12_t *this, int level0,
chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
int oid = OID_UNKNOWN;
bool success = FALSE;
parser = asn1_parser_create(safeContentsObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case SAFE_BAG_ID:
oid = asn1_known_oid(object);
break;
case SAFE_BAG_VALUE:
{
switch (oid)
{
case OID_P12_CERT_BAG:
{
add_certificate(this, parser->get_level(parser)+1,
object);
break;
}
case OID_P12_KEY_BAG:
case OID_P12_PKCS8_KEY_BAG:
{
private_key_t *key;
DBG2(DBG_ASN, "-- > parsing private key from PKCS#12");
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
KEY_ANY, BUILD_BLOB_ASN1_DER, object,
BUILD_END);
if (key)
{
this->creds->add_key(this->creds, key);
DBG2(DBG_ASN, "-- < --");
}
else
{
DBG2(DBG_ASN, "-- < failed parsing private key "
"from PKCS#12");
}
}
default:
break;
}
break;
}
}
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of an AuthenticatedSafe structure
*/
static const asn1Object_t authenticatedSafeObjects[] = {
{ 0, "AuthenticatedSafe", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
{ 1, "ContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define AUTHENTICATED_SAFE_DATA 1
/**
* Parse an AuthenticatedSafe structure
*/
static bool parse_authenticated_safe(private_pkcs12_t *this, chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(authenticatedSafeObjects, blob);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case AUTHENTICATED_SAFE_DATA:
{
container_t *container;
chunk_t data;
container = lib->creds->create(lib->creds, CRED_CONTAINER,
CONTAINER_PKCS7, BUILD_BLOB_ASN1_DER,
object, BUILD_END);
if (!container)
{
goto end;
}
switch (container->get_type(container))
{
case CONTAINER_PKCS7_DATA:
case CONTAINER_PKCS7_ENCRYPTED_DATA:
case CONTAINER_PKCS7_ENVELOPED_DATA:
if (container->get_data(container, &data))
{
break;
}
/* fall-through */
default:
container->destroy(container);
goto end;
}
container->destroy(container);
if (!parse_safe_contents(this, parser->get_level(parser)+1,
data))
{
chunk_free(&data);
goto end;
}
chunk_free(&data);
break;
}
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
return success;
}
/**
* Verify the given MAC with available passwords.
*/
static bool verify_mac(hash_algorithm_t hash, chunk_t salt,
u_int64_t iterations, chunk_t data, chunk_t mac)
{
integrity_algorithm_t integ;
enumerator_t *enumerator;
shared_key_t *shared;
signer_t *signer;
chunk_t key, calculated;
bool success = FALSE;
integ = hasher_algorithm_to_integrity(hash, mac.len);
signer = lib->crypto->create_signer(lib->crypto, integ);
if (!signer)
{
return FALSE;
}
key = chunk_alloca(signer->get_key_size(signer));
calculated = chunk_alloca(signer->get_block_size(signer));
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
SHARED_PRIVATE_KEY_PASS, NULL, NULL);
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
{
if (!pkcs12_derive_key(hash, shared->get_key(shared), salt, iterations,
PKCS12_KEY_MAC, key))
{
break;
}
if (!signer->set_key(signer, key) ||
!signer->get_signature(signer, data, calculated.ptr))
{
break;
}
if (chunk_equals(mac, calculated))
{
success = TRUE;
break;
}
}
enumerator->destroy(enumerator);
signer->destroy(signer);
return success;
}
/**
* ASN.1 definition of digestInfo
*/
static const asn1Object_t digestInfoObjects[] = {
{ 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
{ 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define DIGEST_INFO_ALGORITHM 1
#define DIGEST_INFO_DIGEST 2
/**
* Parse a digestInfo structure
*/
static bool parse_digest_info(chunk_t blob, int level0, hash_algorithm_t *hash,
chunk_t *digest)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success;
parser = asn1_parser_create(digestInfoObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case DIGEST_INFO_ALGORITHM:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser)+1, NULL);
*hash = hasher_algorithm_from_oid(oid);
break;
}
case DIGEST_INFO_DIGEST:
{
*digest = object;
break;
}
default:
break;
}
}
success = parser->success(parser);
parser->destroy(parser);
return success;
}
/**
* ASN.1 definition of a PFX structure
*/
static const asn1Object_t PFXObjects[] = {
{ 0, "PFX", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
{ 1, "authSafe", ASN1_SEQUENCE, ASN1_OBJ }, /* 2 */
{ 1, "macData", ASN1_SEQUENCE, ASN1_OPT|ASN1_BODY }, /* 3 */
{ 2, "mac", ASN1_SEQUENCE, ASN1_RAW }, /* 4 */
{ 2, "macSalt", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
{ 2, "iterations", ASN1_INTEGER, ASN1_DEF|ASN1_BODY }, /* 6 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PFX_AUTH_SAFE 2
#define PFX_MAC 4
#define PFX_SALT 5
#define PFX_ITERATIONS 6
/**
* Parse an ASN.1 encoded PFX structure
*/
static bool parse_PFX(private_pkcs12_t *this, chunk_t blob)
{
asn1_parser_t *parser;
int objectID;
chunk_t object, auth_safe, digest = chunk_empty, salt = chunk_empty,
data = chunk_empty;
hash_algorithm_t hash = HASH_UNKNOWN;
container_t *container = NULL;
u_int64_t iterations = 0;
bool success = FALSE;
parser = asn1_parser_create(PFXObjects, blob);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PFX_AUTH_SAFE:
{
auth_safe = object;
break;
}
case PFX_MAC:
{
if (!parse_digest_info(object, parser->get_level(parser)+1,
&hash, &digest))
{
goto end_parse;
}
break;
}
case PFX_SALT:
{
salt = object;
break;
}
case PFX_ITERATIONS:
{
iterations = object.len ? asn1_parse_integer_uint64(object) : 1;
break;
}
}
}
success = parser->success(parser);
end_parse:
parser->destroy(parser);
if (!success)
{
return FALSE;
}
success = FALSE;
DBG2(DBG_ASN, "-- > --");
container = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
BUILD_BLOB_ASN1_DER, auth_safe, BUILD_END);
if (container && container->get_data(container, &data))
{
if (hash != HASH_UNKNOWN)
{
if (container->get_type(container) != CONTAINER_PKCS7_DATA)
{
goto end;
}
if (!verify_mac(hash, salt, iterations, data, digest))
{
DBG1(DBG_ASN, " MAC verification of PKCS#12 container failed");
goto end;
}
}
else
{
enumerator_t *enumerator;
auth_cfg_t *auth;
if (container->get_type(container) != CONTAINER_PKCS7_SIGNED_DATA)
{
goto end;
}
enumerator = container->create_signature_enumerator(container);
if (!enumerator->enumerate(enumerator, &auth))
{
DBG1(DBG_ASN, " signature verification of PKCS#12 container "
"failed");
enumerator->destroy(enumerator);
goto end;
}
enumerator->destroy(enumerator);
}
success = parse_authenticated_safe(this, data);
}
end:
DBG2(DBG_ASN, "-- < --");
DESTROY_IF(container);
chunk_free(&data);
return success;
}
/**
* See header.
*/
pkcs12_t *pkcs12_decode(container_type_t type, va_list args)
{
private_pkcs12_t *this;
chunk_t blob = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_BLOB_ASN1_DER:
blob = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
if (blob.len)
{
if (blob.len >= 2 &&
blob.ptr[0] == ASN1_SEQUENCE && blob.ptr[1] == 0x80)
{ /* looks like infinite length BER encoding, but we can't handle it.
*/
return NULL;
}
this = pkcs12_create();
if (parse_PFX(this, blob))
{
return &this->public;
}
destroy(this);
}
return NULL;
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 pkcs12_decode pkcs12_decode
* @{ @ingroup pkcs12
*/
#ifndef PKCS12_DECODE_H_
#define PKCS12_DECODE_H_
#include <credentials/builder.h>
#include <credentials/containers/pkcs12.h>
/**
* Load a PKCS#12 container.
*
* The argument list must contain a single BUILD_BLOB_ASN1_DER argument.
*
* @param type type of the container, CONTAINER_PKCS12
* @param args builder_part_t argument list
* @return container, NULL on failure
*/
pkcs12_t *pkcs12_decode(container_type_t type, va_list args);
#endif /** PKCS12_DECODE_H_ @}*/
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2012 Tobias Brunner
* 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 "pkcs12_plugin.h"
#include <library.h>
#include "pkcs12_decode.h"
typedef struct private_pkcs12_plugin_t private_pkcs12_plugin_t;
/**
* private data of pkcs12_plugin
*/
struct private_pkcs12_plugin_t {
/**
* public functions
*/
pkcs12_plugin_t public;
};
METHOD(plugin_t, get_name, char*,
private_pkcs12_plugin_t *this)
{
return "pkcs12";
}
METHOD(plugin_t, get_features, int,
private_pkcs12_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_REGISTER(CONTAINER_DECODE, pkcs12_decode, FALSE),
PLUGIN_PROVIDE(CONTAINER_DECODE, CONTAINER_PKCS12),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_pkcs12_plugin_t *this)
{
free(this);
}
/*
* see header file
*/
plugin_t *pkcs12_plugin_create()
{
private_pkcs12_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 PURPSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup pkcs12 pkcs12
* @ingroup plugins
*
* @defgroup pkcs12_plugin pkcs12_plugin
* @{ @ingroup pkcs12
*/
#ifndef PKCS12_PLUGIN_H_
#define PKCS12_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct pkcs12_plugin_t pkcs12_plugin_t;
/**
* Plugin providing PKCS#12 decoding functions
*/
struct pkcs12_plugin_t {
/**
* Implements plugin interface.
*/
plugin_t plugin;
};
#endif /** PKCS12_PLUGIN_H_ @}*/
@@ -12,6 +12,7 @@ endif
libstrongswan_pkcs7_la_SOURCES = \
pkcs7_generic.h pkcs7_generic.c \
pkcs7_signed_data.h pkcs7_signed_data.c \
pkcs7_encrypted_data.h pkcs7_encrypted_data.c \
pkcs7_enveloped_data.h pkcs7_enveloped_data.c \
pkcs7_data.h pkcs7_data.c \
pkcs7_attributes.h pkcs7_attributes.c \
@@ -0,0 +1,216 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 "pkcs7_encrypted_data.h"
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <asn1/oid.h>
#include <crypto/pkcs5.h>
#include <utils/debug.h>
typedef struct private_pkcs7_encrypted_data_t private_pkcs7_encrypted_data_t;
/**
* Private data of a PKCS#7 signed-data container.
*/
struct private_pkcs7_encrypted_data_t {
/**
* Implements pkcs7_t.
*/
pkcs7_t public;
/**
* Decrypted content
*/
chunk_t content;
/**
* Encrypted and encoded PKCS#7 encrypted-data
*/
chunk_t encoding;
};
/**
* Decrypt encrypted-data with available passwords
*/
static bool decrypt(pkcs5_t *pkcs5, chunk_t data, chunk_t *decrypted)
{
enumerator_t *enumerator;
shared_key_t *shared;
bool success = FALSE;
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
SHARED_PRIVATE_KEY_PASS, NULL, NULL);
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
{
if (pkcs5->decrypt(pkcs5, shared->get_key(shared), data, decrypted))
{
success = TRUE;
break;
}
}
enumerator->destroy(enumerator);
return success;
}
/**
* ASN.1 definition of the PKCS#7 encrypted-data type
*/
static const asn1Object_t encryptedDataObjects[] = {
{ 0, "encryptedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
{ 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 2 */
{ 2, "contentType", ASN1_OID, ASN1_BODY }, /* 3 */
{ 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 4 */
{ 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 5 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PKCS7_VERSION 1
#define PKCS7_CONTENT_TYPE 3
#define PKCS7_CONTENT_ENC_ALGORITHM 4
#define PKCS7_ENCRYPTED_CONTENT 5
/**
* Parse and decrypt encrypted-data
*/
static bool parse(private_pkcs7_encrypted_data_t *this, chunk_t content)
{
asn1_parser_t *parser;
chunk_t object;
int objectID, version;
bool success = FALSE;
chunk_t encrypted = chunk_empty;
pkcs5_t *pkcs5 = NULL;
parser = asn1_parser_create(encryptedDataObjects, content);
while (parser->iterate(parser, &objectID, &object))
{
int level = parser->get_level(parser);
switch (objectID)
{
case PKCS7_VERSION:
version = object.len ? (int)*object.ptr : 0;
DBG2(DBG_LIB, " v%d", version);
if (version != 0)
{
DBG1(DBG_LIB, "encryptedData version is not 0");
goto end;
}
break;
case PKCS7_CONTENT_TYPE:
if (asn1_known_oid(object) != OID_PKCS7_DATA)
{
DBG1(DBG_LIB, "encrypted content not of type pkcs7 data");
goto end;
}
break;
case PKCS7_CONTENT_ENC_ALGORITHM:
pkcs5 = pkcs5_from_algorithmIdentifier(object, level + 1);
if (!pkcs5)
{
DBG1(DBG_LIB, "failed to detect PKCS#5 scheme");
goto end;
}
break;
case PKCS7_ENCRYPTED_CONTENT:
encrypted = object;
break;
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
success = success && decrypt(pkcs5, encrypted, &this->content);
DESTROY_IF(pkcs5);
return success;
}
METHOD(container_t, get_type, container_type_t,
private_pkcs7_encrypted_data_t *this)
{
return CONTAINER_PKCS7_ENCRYPTED_DATA;
}
METHOD(container_t, get_data, bool,
private_pkcs7_encrypted_data_t *this, chunk_t *data)
{
if (this->content.len)
{
*data = chunk_clone(this->content);
return TRUE;
}
return FALSE;
}
METHOD(container_t, get_encoding, bool,
private_pkcs7_encrypted_data_t *this, chunk_t *data)
{
*data = chunk_clone(this->encoding);
return TRUE;
}
METHOD(container_t, destroy, void,
private_pkcs7_encrypted_data_t *this)
{
free(this->content.ptr);
free(this->encoding.ptr);
free(this);
}
/**
* Generic constructor
*/
static private_pkcs7_encrypted_data_t* create_empty()
{
private_pkcs7_encrypted_data_t *this;
INIT(this,
.public = {
.container = {
.get_type = _get_type,
.create_signature_enumerator = (void*)enumerator_create_empty,
.get_data = _get_data,
.get_encoding = _get_encoding,
.destroy = _destroy,
},
.create_cert_enumerator = (void*)enumerator_create_empty,
.get_attribute = (void*)return_false,
},
);
return this;
}
/**
* See header.
*/
pkcs7_t *pkcs7_encrypted_data_load(chunk_t encoding, chunk_t content)
{
private_pkcs7_encrypted_data_t *this = create_empty();
this->encoding = chunk_clone(encoding);
if (!parse(this, content))
{
destroy(this);
return NULL;
}
return &this->public;
}
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 pkcs7_encrypted_data pkcs7_encrypted_data
* @{ @ingroup pkcs7p
*/
#ifndef PKCS7_ENCRYPTED_DATA_H_
#define PKCS7_ENCRYPTED_DATA_H_
#include <credentials/builder.h>
#include <credentials/containers/pkcs7.h>
/**
* Parse a PKCS#7 encrypted-data container.
*
* @param encoding full contentInfo encoding
* @param content DER encoded content from contentInfo
* @return CONTAINER_PKCS7_ENCRYPTED_DATA container, NULL on failure
*/
pkcs7_t *pkcs7_encrypted_data_load(chunk_t encoding, chunk_t content);
#endif /** PKCS7_ENCRYPTED_DATA_H_ @}*/
@@ -20,6 +20,7 @@
#include "pkcs7_generic.h"
#include "pkcs7_data.h"
#include "pkcs7_signed_data.h"
#include "pkcs7_encrypted_data.h"
#include "pkcs7_enveloped_data.h"
#include <utils/debug.h>
@@ -85,6 +86,8 @@ end:
return pkcs7_signed_data_load(blob, content);
case OID_PKCS7_ENVELOPED_DATA:
return pkcs7_enveloped_data_load(blob, content);
case OID_PKCS7_ENCRYPTED_DATA:
return pkcs7_encrypted_data_load(blob, content);
default:
DBG1(DBG_ASN, "pkcs7 content type %d not supported", type);
return NULL;
+16 -455
View File
@@ -19,6 +19,7 @@
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <crypto/pkcs5.h>
#include <credentials/keys/private_key.h>
/**
@@ -100,450 +101,39 @@ end:
return key;
}
/**
* Verify padding of decrypted blob.
* Length of blob is adjusted accordingly.
*/
static bool verify_padding(chunk_t *blob)
{
u_int8_t padding, count;
padding = count = blob->ptr[blob->len - 1];
if (padding > 8)
{
return FALSE;
}
for (; blob->len && count; --blob->len, --count)
{
if (blob->ptr[blob->len - 1] != padding)
{
return FALSE;
}
}
return TRUE;
}
/**
* Prototype for key derivation functions.
*/
typedef bool (*kdf_t)(void *generator, chunk_t password, chunk_t salt,
u_int64_t iterations, chunk_t key);
/**
* Try to decrypt the given blob with multiple passwords using the given
* key derivation function. keymat is where the kdf function writes the key
* to, key and iv point to the actual keys and initialization vectors resp.
* pkcs5 object.
*/
static private_key_t *decrypt_private_key(chunk_t blob,
encryption_algorithm_t encr, size_t key_len, kdf_t kdf,
void *generator, chunk_t salt, u_int64_t iterations,
chunk_t keymat, chunk_t key, chunk_t iv)
static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob)
{
enumerator_t *enumerator;
shared_key_t *shared;
crypter_t *crypter;
private_key_t *private_key = NULL;
crypter = lib->crypto->create_crypter(lib->crypto, encr, key_len);
if (!crypter)
{
DBG1(DBG_ASN, " %N encryption algorithm not available",
encryption_algorithm_names, encr);
return NULL;
}
if (blob.len % crypter->get_block_size(crypter))
{
DBG1(DBG_ASN, " data size is not a multiple of block size");
crypter->destroy(crypter);
return NULL;
}
enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
SHARED_PRIVATE_KEY_PASS, NULL, NULL);
while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
{
chunk_t decrypted;
if (!kdf(generator, shared->get_key(shared), salt, iterations, keymat))
if (!pkcs5->decrypt(pkcs5, shared->get_key(shared), blob, &decrypted))
{
continue;
}
if (!crypter->set_key(crypter, key) ||
!crypter->decrypt(crypter, blob, iv, &decrypted))
private_key = parse_private_key(decrypted);
if (private_key)
{
continue;
}
if (verify_padding(&decrypted))
{
private_key = parse_private_key(decrypted);
if (private_key)
{
chunk_clear(&decrypted);
break;
}
chunk_clear(&decrypted);
break;
}
chunk_free(&decrypted);
}
enumerator->destroy(enumerator);
crypter->destroy(crypter);
return private_key;
}
/**
* Function F of PBKDF2
*/
static bool pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed,
u_int64_t iterations)
{
chunk_t u;
u_int64_t i;
u = chunk_alloca(prf->get_block_size(prf));
if (!prf->get_bytes(prf, seed, u.ptr))
{
return FALSE;
}
memcpy(block.ptr, u.ptr, block.len);
for (i = 1; i < iterations; i++)
{
if (!prf->get_bytes(prf, u, u.ptr))
{
return FALSE;
}
memxor(block.ptr, u.ptr, block.len);
}
return TRUE;
}
/**
* PBKDF2 key derivation function
*/
static bool pbkdf2(prf_t *prf, chunk_t password, chunk_t salt,
u_int64_t iterations, chunk_t key)
{
chunk_t keymat, block, seed;
size_t blocks;
u_int32_t i = 0, *ni;
if (!prf->set_key(prf, password))
{
return FALSE;
}
block.len = prf->get_block_size(prf);
blocks = (key.len - 1) / block.len + 1;
keymat = chunk_alloca(blocks * block.len);
seed = chunk_cata("cc", salt, chunk_from_thing(i));
ni = (u_int32_t*)(seed.ptr + salt.len);
for (; i < blocks; i++)
{
*ni = htonl(i + 1);
block.ptr = keymat.ptr + (i * block.len);
if (!pbkdf2_f(block, prf, seed, iterations))
{
return FALSE;
}
}
memcpy(key.ptr, keymat.ptr, key.len);
return TRUE;
}
/**
* Decrypt an encrypted PKCS#8 encoded private key according to PBES2
*/
static private_key_t *decrypt_private_key_pbes2(chunk_t blob,
encryption_algorithm_t encr, size_t key_len,
chunk_t iv, pseudo_random_function_t prf_func,
chunk_t salt, u_int64_t iterations)
{
private_key_t *private_key;
prf_t *prf;
chunk_t key;
prf = lib->crypto->create_prf(lib->crypto, prf_func);
if (!prf)
{
DBG1(DBG_ASN, " %N prf algorithm not available",
pseudo_random_function_names, prf_func);
return NULL;
}
key = chunk_alloca(key_len);
private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf2, prf,
salt, iterations, key, key, iv);
prf->destroy(prf);
return private_key;
}
/**
* PBKDF1 key derivation function
*/
static bool pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt,
u_int64_t iterations, chunk_t key)
{
chunk_t hash;
u_int64_t i;
hash = chunk_alloca(hasher->get_hash_size(hasher));
if (!hasher->get_hash(hasher, password, NULL) ||
!hasher->get_hash(hasher, salt, hash.ptr))
{
return FALSE;
}
for (i = 1; i < iterations; i++)
{
if (!hasher->get_hash(hasher, hash, hash.ptr))
{
return FALSE;
}
}
memcpy(key.ptr, hash.ptr, key.len);
return TRUE;
}
/**
* Decrypt an encrypted PKCS#8 encoded private key according to PBES1
*/
static private_key_t *decrypt_private_key_pbes1(chunk_t blob,
encryption_algorithm_t encr, size_t key_len,
hash_algorithm_t hash, chunk_t salt,
u_int64_t iterations)
{
private_key_t *private_key = NULL;
hasher_t *hasher = NULL;
chunk_t keymat, key, iv;
hasher = lib->crypto->create_hasher(lib->crypto, hash);
if (!hasher)
{
DBG1(DBG_ASN, " %N hash algorithm not available",
hash_algorithm_names, hash);
goto end;
}
if (hasher->get_hash_size(hasher) < key_len)
{
goto end;
}
keymat = chunk_alloca(key_len * 2);
key.len = key_len;
key.ptr = keymat.ptr;
iv.len = key_len;
iv.ptr = keymat.ptr + key_len;
private_key = decrypt_private_key(blob, encr, key_len, (kdf_t)pbkdf1,
hasher, salt, iterations, keymat,
key, iv);
end:
DESTROY_IF(hasher);
return private_key;
}
/**
* Parse an ASN1_INTEGER to a u_int64_t.
*/
static u_int64_t parse_asn1_integer_uint64(chunk_t blob)
{
u_int64_t val = 0;
int i;
for (i = 0; i < blob.len; i++)
{ /* if it is longer than 8 bytes, we just use the 8 LSBs */
val <<= 8;
val |= (u_int64_t)blob.ptr[i];
}
return val;
}
/**
* ASN.1 definition of a PBKDF2-params structure
* The salt is actually a CHOICE and could be an AlgorithmIdentifier from
* PBKDF2-SaltSources (but as per RFC 2898 that's for future versions).
*/
static const asn1Object_t pbkdf2ParamsObjects[] = {
{ 0, "PBKDF2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
{ 1, "iterationCount",ASN1_INTEGER, ASN1_BODY }, /* 2 */
{ 1, "keyLength", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 3 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */
{ 1, "prf", ASN1_EOC, ASN1_DEF|ASN1_RAW }, /* 5 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBKDF2_SALT 1
#define PBKDF2_ITERATION_COUNT 2
#define PBKDF2_KEY_LENGTH 3
#define PBKDF2_PRF 5
/**
* Parse a PBKDF2-params structure
*/
static void parse_pbkdf2_params(chunk_t blob, chunk_t *salt,
u_int64_t *iterations, size_t *key_len,
pseudo_random_function_t *prf)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
parser = asn1_parser_create(pbkdf2ParamsObjects, blob);
*key_len = 0; /* key_len is optional */
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBKDF2_SALT:
{
*salt = object;
break;
}
case PBKDF2_ITERATION_COUNT:
{
*iterations = parse_asn1_integer_uint64(object);
break;
}
case PBKDF2_KEY_LENGTH:
{
*key_len = (size_t)parse_asn1_integer_uint64(object);
break;
}
case PBKDF2_PRF:
{ /* defaults to id-hmacWithSHA1 */
*prf = PRF_HMAC_SHA1;
break;
}
}
}
parser->destroy(parser);
}
/**
* ASN.1 definition of a PBES2-params structure
*/
static const asn1Object_t pbes2ParamsObjects[] = {
{ 0, "PBES2-params", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "keyDerivationFunc", ASN1_EOC, ASN1_RAW }, /* 1 */
{ 1, "encryptionScheme", ASN1_EOC, ASN1_RAW }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBES2PARAMS_KEY_DERIVATION_FUNC 1
#define PBES2PARAMS_ENCRYPTION_SCHEME 2
/**
* Parse a PBES2-params structure
*/
static void parse_pbes2_params(chunk_t blob, chunk_t *salt,
u_int64_t *iterations, size_t *key_len,
pseudo_random_function_t *prf,
encryption_algorithm_t *encr, chunk_t *iv)
{
asn1_parser_t *parser;
chunk_t object, params;
int objectID;
parser = asn1_parser_create(pbes2ParamsObjects, blob);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBES2PARAMS_KEY_DERIVATION_FUNC:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser) + 1, &params);
if (oid != OID_PBKDF2)
{ /* unsupported key derivation function */
goto end;
}
parse_pbkdf2_params(params, salt, iterations, key_len, prf);
break;
}
case PBES2PARAMS_ENCRYPTION_SCHEME:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser) + 1, &params);
if (oid != OID_3DES_EDE_CBC)
{ /* unsupported encryption scheme */
goto end;
}
if (*key_len <= 0)
{ /* default key len for DES-EDE3-CBC-Pad */
*key_len = 24;
}
if (!asn1_parse_simple_object(&params, ASN1_OCTET_STRING,
parser->get_level(parser) + 1, "IV"))
{
goto end;
}
*encr = ENCR_3DES;
*iv = params;
break;
}
}
}
end:
parser->destroy(parser);
}
/**
* ASN.1 definition of a PBEParameter structure
*/
static const asn1Object_t pbeParameterObjects[] = {
{ 0, "PBEParameter", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "salt", ASN1_OCTET_STRING, ASN1_BODY }, /* 1 */
{ 1, "iterationCount", ASN1_INTEGER, ASN1_BODY }, /* 2 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PBEPARAM_SALT 1
#define PBEPARAM_ITERATION_COUNT 2
/**
* Parse a PBEParameter structure
*/
static void parse_pbe_parameters(chunk_t blob, chunk_t *salt,
u_int64_t *iterations)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
parser = asn1_parser_create(pbeParameterObjects, blob);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
{
case PBEPARAM_SALT:
{
*salt = object;
break;
}
case PBEPARAM_ITERATION_COUNT:
{
*iterations = parse_asn1_integer_uint64(object);
break;
}
}
}
parser->destroy(parser);
}
/**
* ASN.1 definition of an encryptedPrivateKeyInfo structure
*/
@@ -563,14 +153,10 @@ static const asn1Object_t encryptedPKIObjects[] = {
static private_key_t *parse_encrypted_private_key(chunk_t blob)
{
asn1_parser_t *parser;
chunk_t object, params, salt = chunk_empty, iv = chunk_empty;
u_int64_t iterations = 0;
chunk_t object;
int objectID;
encryption_algorithm_t encr = ENCR_UNDEFINED;
hash_algorithm_t hash = HASH_UNKNOWN;
pseudo_random_function_t prf = PRF_UNDEFINED;
private_key_t *key = NULL;
size_t key_len = 8;
pkcs5_t *pkcs5 = NULL;
parser = asn1_parser_create(encryptedPKIObjects, blob);
@@ -580,49 +166,24 @@ static private_key_t *parse_encrypted_private_key(chunk_t blob)
{
case EPKINFO_ENCRYPTION_ALGORITHM:
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser) + 1, &params);
switch (oid)
pkcs5 = pkcs5_from_algorithmIdentifier(object,
parser->get_level(parser) + 1);
if (!pkcs5)
{
case OID_PBE_MD5_DES_CBC:
encr = ENCR_DES;
hash = HASH_MD5;
parse_pbe_parameters(params, &salt, &iterations);
break;
case OID_PBE_SHA1_DES_CBC:
encr = ENCR_DES;
hash = HASH_SHA1;
parse_pbe_parameters(params, &salt, &iterations);
break;
case OID_PBES2:
parse_pbes2_params(params, &salt, &iterations,
&key_len, &prf, &encr, &iv);
break;
default:
/* encryption scheme not supported */
goto end;
goto end;
}
break;
}
case EPKINFO_ENCRYPTED_DATA:
{
if (prf != PRF_UNDEFINED)
{
key = decrypt_private_key_pbes2(object, encr, key_len, iv,
prf, salt, iterations);
}
else
{
key = decrypt_private_key_pbes1(object, encr, key_len, hash,
salt, iterations);
}
key = decrypt_private_key(pkcs5, object);
break;
}
}
}
end:
DESTROY_IF(pkcs5);
parser->destroy(parser);
return key;
}
@@ -43,6 +43,7 @@ METHOD(plugin_t, get_features, int,
{
static plugin_feature_t f[] = {
PLUGIN_REGISTER(PRIVKEY, pkcs8_private_key_load, FALSE),
PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
};
+15
View File
@@ -0,0 +1,15 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan
AM_CFLAGS = -rdynamic
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-rc2.la
else
plugin_LTLIBRARIES = libstrongswan-rc2.la
endif
libstrongswan_rc2_la_SOURCES = \
rc2_plugin.h rc2_plugin.c rc2_crypter.c rc2_crypter.h
libstrongswan_rc2_la_LDFLAGS = -module -avoid-version
+349
View File
@@ -0,0 +1,349 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 "rc2_crypter.h"
typedef struct private_rc2_crypter_t private_rc2_crypter_t;
#define RC2_BLOCK_SIZE 8
#define ROL16(x, k) ({ u_int16_t _x = (x); (_x << (k)) | (_x >> (16 - (k))); })
#define ROR16(x, k) ({ u_int16_t _x = (x); (_x >> (k)) | (_x << (16 - (k))); })
#define GET16(x) ({ u_char *_x = (x); (u_int16_t)_x[0] | ((u_int16_t)_x[1] << 8); })
#define PUT16(x, v) ({ u_char *_x = (x); u_int16_t _v = (v); _x[0] = _v, _x[1] = _v >> 8; })
/**
* Private data of rc2_crypter_t
*/
struct private_rc2_crypter_t {
/**
* Public interface
*/
rc2_crypter_t public;
/**
* The expanded key in 16-bit words
*/
u_int16_t K[64];
/**
* Key size in bytes
*/
size_t T;
/**
* Effective key size in bits
*/
size_t T1;
};
/**
* PITABLE
*/
static const u_char PITABLE[256] =
{
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed,
0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e,
0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13,
0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b,
0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c,
0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1,
0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57,
0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7,
0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7,
0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74,
0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc,
0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a,
0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae,
0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c,
0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0,
0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77,
0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
};
/**
* Encrypt a single block of data
*/
static void encrypt_block(private_rc2_crypter_t *this, u_char R[])
{
register u_int16_t R0, R1, R2, R3, *Kj;
int rounds = 3, mix = 5;
R0 = GET16(R);
R1 = GET16(R + 2);
R2 = GET16(R + 4);
R3 = GET16(R + 6);
Kj = &this->K[0];
/* 5 mix, mash, 6 mix, mash, 5 mix */
while (TRUE)
{
/* mix */
R0 = ROL16(R0 + *(Kj++) + (R3 & R2) + (~R3 & R1), 1);
R1 = ROL16(R1 + *(Kj++) + (R0 & R3) + (~R0 & R2), 2);
R2 = ROL16(R2 + *(Kj++) + (R1 & R0) + (~R1 & R3), 3);
R3 = ROL16(R3 + *(Kj++) + (R2 & R1) + (~R2 & R0), 5);
if (--mix == 0)
{
if (--rounds == 0)
{
break;
}
mix = (rounds == 2) ? 6 : 5;
/* mash */
R0 += this->K[R3 & 63];
R1 += this->K[R0 & 63];
R2 += this->K[R1 & 63];
R3 += this->K[R2 & 63];
}
}
PUT16(R, R0);
PUT16(R + 2, R1);
PUT16(R + 4, R2);
PUT16(R + 6, R3);
}
/**
* Decrypt a single block of data.
*/
static void decrypt_block(private_rc2_crypter_t *this, u_char R[])
{
register u_int16_t R0, R1, R2, R3, *Kj;
int rounds = 3, mix = 5;
R0 = GET16(R);
R1 = GET16(R + 2);
R2 = GET16(R + 4);
R3 = GET16(R + 6);
Kj = &this->K[63];
/* 5 r-mix, r-mash, 6 r-mix, r-mash, 5 r-mix */
while (TRUE)
{
/* r-mix */
R3 = ROR16(R3, 5);
R3 = R3 - *(Kj--) - (R2 & R1) - (~R2 & R0);
R2 = ROR16(R2, 3);
R2 = R2 - *(Kj--) - (R1 & R0) - (~R1 & R3);
R1 = ROR16(R1, 2);
R1 = R1 - *(Kj--) - (R0 & R3) - (~R0 & R2);
R0 = ROR16(R0, 1);
R0 = R0 - *(Kj--) - (R3 & R2) - (~R3 & R1);
if (--mix == 0)
{
if (--rounds == 0)
{
break;
}
mix = (rounds == 2) ? 6 : 5;
/* r-mash */
R3 -= this->K[R2 & 63];
R2 -= this->K[R1 & 63];
R1 -= this->K[R0 & 63];
R0 -= this->K[R3 & 63];
}
}
PUT16(R, R0);
PUT16(R + 2, R1);
PUT16(R + 4, R2);
PUT16(R + 6, R3);
}
METHOD(crypter_t, decrypt, bool,
private_rc2_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted)
{
u_int8_t *in, *out, *prev;
if (data.len % RC2_BLOCK_SIZE || iv.len != RC2_BLOCK_SIZE)
{
return FALSE;
}
in = data.ptr + data.len - RC2_BLOCK_SIZE;
out = data.ptr;
if (decrypted)
{
*decrypted = chunk_alloc(data.len);
out = decrypted->ptr;
}
out += data.len - RC2_BLOCK_SIZE;
prev = in;
for (; in >= data.ptr; in -= RC2_BLOCK_SIZE, out -= RC2_BLOCK_SIZE)
{
if (decrypted)
{
memcpy(out, in, RC2_BLOCK_SIZE);
}
decrypt_block(this, out);
prev -= RC2_BLOCK_SIZE;
if (prev < data.ptr)
{
prev = iv.ptr;
}
memxor(out, prev, RC2_BLOCK_SIZE);
}
return TRUE;
}
METHOD(crypter_t, encrypt, bool,
private_rc2_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted)
{
u_int8_t *in, *out, *end, *prev;
if (data.len % RC2_BLOCK_SIZE || iv.len != RC2_BLOCK_SIZE)
{
return FALSE;
}
in = data.ptr;
end = data.ptr + data.len;
out = data.ptr;
if (encrypted)
{
*encrypted = chunk_alloc(data.len);
out = encrypted->ptr;
}
prev = iv.ptr;
for (; in < end; in += RC2_BLOCK_SIZE, out += RC2_BLOCK_SIZE)
{
if (encrypted)
{
memcpy(out, in, RC2_BLOCK_SIZE);
}
memxor(out, prev, RC2_BLOCK_SIZE);
encrypt_block(this, out);
prev = out;
}
return TRUE;
}
METHOD(crypter_t, get_block_size, size_t,
private_rc2_crypter_t *this)
{
return RC2_BLOCK_SIZE;
}
METHOD(crypter_t, get_iv_size, size_t,
private_rc2_crypter_t *this)
{
return RC2_BLOCK_SIZE;
}
METHOD(crypter_t, get_key_size, size_t,
private_rc2_crypter_t *this)
{
return this->T;
}
METHOD(crypter_t, set_key, bool,
private_rc2_crypter_t *this, chunk_t key)
{
u_int8_t L[128], T8, TM, idx;
int i;
if (key.len != this->T)
{
return FALSE;
}
for (i = 0; i < key.len; i++)
{
L[i] = key.ptr[i];
}
for (; i < 128; i++)
{
idx = L[i-1] + L[i-key.len];
L[i] = PITABLE[idx];
}
T8 = (this->T1 + 7) / 8;
TM = ~(0xff << (8 - (8*T8 - this->T1)));
L[128-T8] = PITABLE[L[128-T8] & TM];
for (i = 127-T8; i >= 0; i--)
{
idx = L[i+1] ^ L[i+T8];
L[i] = PITABLE[idx];
}
for (i = 0; i < 64; i++)
{
this->K[i] = GET16(&L[i << 1]);
}
memwipe(L, sizeof(L));
return TRUE;
}
METHOD(crypter_t, destroy, void,
private_rc2_crypter_t *this)
{
memwipe(this->K, sizeof(this->K));
free(this);
}
/*
* Described in header
*/
rc2_crypter_t *rc2_crypter_create(encryption_algorithm_t algo, size_t key_size)
{
private_rc2_crypter_t *this;
size_t effective;
if (algo != ENCR_RC2_CBC)
{
return NULL;
}
key_size = max(1, key_size);
effective = RC2_EFFECTIVE_KEY_LEN(key_size);
key_size = min(128, RC2_KEY_LEN(key_size));
effective = max(1, min(1024, effective ?: key_size * 8));
INIT(this,
.public = {
.crypter = {
.encrypt = _encrypt,
.decrypt = _decrypt,
.get_block_size = _get_block_size,
.get_iv_size = _get_iv_size,
.get_key_size = _get_key_size,
.set_key = _set_key,
.destroy = _destroy,
},
},
.T = key_size,
.T1 = effective,
);
return &this->public;
}
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 rc2_crypter rc2_crypter
* @{ @ingroup rc2_p
*/
#ifndef RC2_CRYPTER_H_
#define RC2_CRYPTER_H_
typedef struct rc2_crypter_t rc2_crypter_t;
#include <crypto/crypters/crypter.h>
/**
* Class implementing the RC2 block cipher as defined in RFC 2268.
*/
struct rc2_crypter_t {
/**
* Implements crypter_t interface.
*/
crypter_t crypter;
};
/**
* Constructor to create rc2_crypter_t objects.
*
* @param algo algorithm to implement (ENCR_RC2_CBC)
* @param key_size use the RC2_KEY_SIZE macro if the effective key size
* in bits is different than the actual length of the key
* @return rc2_crypter_t object, NULL if not supported
*/
rc2_crypter_t *rc2_crypter_create(encryption_algorithm_t algo,
size_t key_size);
#endif /** RC2_CRYPTER_H_ @}*/
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 "rc2_plugin.h"
#include <library.h>
#include "rc2_crypter.h"
typedef struct private_rc2_plugin_t private_rc2_plugin_t;
/**
* Private data of rc2_plugin
*/
struct private_rc2_plugin_t {
/**
* Public interface
*/
rc2_plugin_t public;
};
METHOD(plugin_t, get_name, char*,
private_rc2_plugin_t *this)
{
return "rc2";
}
METHOD(plugin_t, get_features, int,
private_rc2_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_REGISTER(CRYPTER, rc2_crypter_create),
PLUGIN_PROVIDE(CRYPTER, ENCR_RC2_CBC, 0),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_rc2_plugin_t *this)
{
free(this);
}
/*
* Described in header
*/
plugin_t *rc2_plugin_create()
{
private_rc2_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 rc2_p rc2
* @ingroup plugins
*
* @defgroup rc2_plugin rc2_plugin
* @{ @ingroup rc2_p
*/
#ifndef RC2_PLUGIN_H_
#define RC2_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct rc2_plugin_t rc2_plugin_t;
/**
* Plugin implementing RC2 (RFC 2268).
*/
struct rc2_plugin_t {
/**
* Implements plugin interface
*/
plugin_t plugin;
};
#endif /** RC2_PLUGIN_H_ @}*/
@@ -26,6 +26,7 @@ libstrongswan_test_vectors_la_SOURCES = \
test_vectors/des.c \
test_vectors/idea.c \
test_vectors/null.c \
test_vectors/rc2.c \
test_vectors/rc5.c \
test_vectors/serpent_cbc.c \
test_vectors/twofish_cbc.c \
@@ -55,6 +55,14 @@ TEST_VECTOR_CRYPTER(des3_cbc2)
TEST_VECTOR_CRYPTER(idea1)
TEST_VECTOR_CRYPTER(idea2)
TEST_VECTOR_CRYPTER(null1)
TEST_VECTOR_CRYPTER(rc2_1)
TEST_VECTOR_CRYPTER(rc2_2)
TEST_VECTOR_CRYPTER(rc2_3)
TEST_VECTOR_CRYPTER(rc2_4)
TEST_VECTOR_CRYPTER(rc2_5)
TEST_VECTOR_CRYPTER(rc2_6)
TEST_VECTOR_CRYPTER(rc2_7)
TEST_VECTOR_CRYPTER(rc2_8)
TEST_VECTOR_CRYPTER(rc5_1)
TEST_VECTOR_CRYPTER(rc5_2)
TEST_VECTOR_CRYPTER(serpent_cbc1)
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2013 Tobias Brunner
* 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 Licenseor (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 usefulbut
* 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 <crypto/crypto_tester.h>
/**
* Test vectors from RFC 2268
*/
/**
* RC2 key length 8 bytes, effective key length 63 bits
*/
crypter_test_vector_t rc2_1 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(8, 63), .len = 8,
.key = "\x00\x00\x00\x00\x00\x00\x00\x00",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\xeb\xb7\x73\xf9\x93\x27\x8e\xff",
};
/**
* RC2 key length 8 bytes, effective key length 64 bits
*/
crypter_test_vector_t rc2_2 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(8, 64), .len = 8,
.key = "\xff\xff\xff\xff\xff\xff\xff\xff",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\xff\xff\xff\xff\xff\xff\xff\xff",
.cipher = "\x27\x8b\x27\xe4\x2e\x2f\x0d\x49",
};
/**
* RC2 key length 8 bytes, effective key length 64 bits
*/
crypter_test_vector_t rc2_3 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(8, 64), .len = 8,
.key = "\x30\x00\x00\x00\x00\x00\x00\x00",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x10\x00\x00\x00\x00\x00\x00\x01",
.cipher = "\x30\x64\x9e\xdf\x9b\xe7\xd2\xc2",
};
/**
* RC2 key length 1 byte, effective key length 64 bits
*/
crypter_test_vector_t rc2_4 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(1, 64), .len = 8,
.key = "\x88",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\x61\xa8\xa2\x44\xad\xac\xcc\xf0",
};
/**
* RC2 key length 7 bytes, effective key length 64 bits
*/
crypter_test_vector_t rc2_5 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(7, 64), .len = 8,
.key = "\x88\xbc\xa9\x0e\x90\x87\x5a",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\x6c\xcf\x43\x08\x97\x4c\x26\x7f",
};
/**
* RC2 key length 16 bytes, effective key length 64 bits
*/
crypter_test_vector_t rc2_6 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(16, 64), .len = 8,
.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\x1a\x80\x7d\x27\x2b\xbe\x5d\xb1",
};
/**
* RC2 key length 16 bytes, effective key length 128 bits
*/
crypter_test_vector_t rc2_7 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(16, 128), .len = 8,
.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\x22\x69\x55\x2a\xb0\xf8\x5c\xa6",
};
/**
* RC2 key length 33 bytes, effective key length 129 bits
*/
crypter_test_vector_t rc2_8 = {
.alg = ENCR_RC2_CBC, .key_size = RC2_KEY_SIZE(33, 129), .len = 8,
.key = "\x88\xbc\xa9\x0e\x90\x87\x5a\x7f\x0f\x79\xc3\x84\x62\x7b\xaf\xb2"
"\x16\xf8\x0a\x6f\x85\x92\x05\x84\xc4\x2f\xce\xb0\xbe\x25\x5d\xaf\x1e",
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00",
.plain = "\x00\x00\x00\x00\x00\x00\x00\x00",
.cipher = "\x5b\x78\xd3\xa4\x3d\xff\xf1\xf1",
};
-7
View File
@@ -475,13 +475,6 @@ char *whitelist[] = {
"Curl_client_write",
/* ClearSilver */
"nerr_init",
/* OpenSSL */
"RSA_new_method",
"DH_new_method",
"ENGINE_load_builtin_engines",
"OPENSSL_config",
"ecdsa_check",
"ERR_put_error",
/* libgcrypt */
"gcry_control",
"gcry_check_version",