mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-05 00:00:45 -04:00
Add pkcs12 plugin which adds support for decoding PKCS#12 containers
This commit is contained in:
parent
199fdcadae
commit
feef637368
@ -129,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([pkcs1], [disable PKCS1 key decoding plugin.])
|
||||||
ARG_DISBL_SET([pkcs7], [disable PKCS7 container support plugin.])
|
ARG_DISBL_SET([pkcs7], [disable PKCS7 container support plugin.])
|
||||||
ARG_DISBL_SET([pkcs8], [disable PKCS8 private key decoding 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([pgp], [disable PGP key decoding plugin.])
|
||||||
ARG_DISBL_SET([dnskey], [disable DNS RR key decoding plugin.])
|
ARG_DISBL_SET([dnskey], [disable DNS RR key decoding plugin.])
|
||||||
ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.])
|
ARG_DISBL_SET([sshkey], [disable SSH key decoding plugin.])
|
||||||
@ -966,8 +967,9 @@ ADD_PLUGIN([revocation], [s charon nm cmd])
|
|||||||
ADD_PLUGIN([constraints], [s charon nm cmd])
|
ADD_PLUGIN([constraints], [s charon nm cmd])
|
||||||
ADD_PLUGIN([pubkey], [s charon cmd])
|
ADD_PLUGIN([pubkey], [s charon cmd])
|
||||||
ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm 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 scepclient pki scripts])
|
||||||
ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
|
ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
|
||||||
|
ADD_PLUGIN([pkcs12], [s charon scepclient pki scripts])
|
||||||
ADD_PLUGIN([pgp], [s charon])
|
ADD_PLUGIN([pgp], [s charon])
|
||||||
ADD_PLUGIN([dnskey], [s charon])
|
ADD_PLUGIN([dnskey], [s charon])
|
||||||
ADD_PLUGIN([sshkey], [s charon nm cmd])
|
ADD_PLUGIN([sshkey], [s charon nm cmd])
|
||||||
@ -1100,6 +1102,7 @@ AM_CONDITIONAL(USE_PUBKEY, test x$pubkey = xtrue)
|
|||||||
AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue)
|
AM_CONDITIONAL(USE_PKCS1, test x$pkcs1 = xtrue)
|
||||||
AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue)
|
AM_CONDITIONAL(USE_PKCS7, test x$pkcs7 = xtrue)
|
||||||
AM_CONDITIONAL(USE_PKCS8, test x$pkcs8 = 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_PGP, test x$pgp = xtrue)
|
||||||
AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue)
|
AM_CONDITIONAL(USE_DNSKEY, test x$dnskey = xtrue)
|
||||||
AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue)
|
AM_CONDITIONAL(USE_SSHKEY, test x$sshkey = xtrue)
|
||||||
@ -1296,6 +1299,7 @@ AC_CONFIG_FILES([
|
|||||||
src/libstrongswan/plugins/pkcs1/Makefile
|
src/libstrongswan/plugins/pkcs1/Makefile
|
||||||
src/libstrongswan/plugins/pkcs7/Makefile
|
src/libstrongswan/plugins/pkcs7/Makefile
|
||||||
src/libstrongswan/plugins/pkcs8/Makefile
|
src/libstrongswan/plugins/pkcs8/Makefile
|
||||||
|
src/libstrongswan/plugins/pkcs12/Makefile
|
||||||
src/libstrongswan/plugins/pgp/Makefile
|
src/libstrongswan/plugins/pgp/Makefile
|
||||||
src/libstrongswan/plugins/dnskey/Makefile
|
src/libstrongswan/plugins/dnskey/Makefile
|
||||||
src/libstrongswan/plugins/sshkey/Makefile
|
src/libstrongswan/plugins/sshkey/Makefile
|
||||||
|
@ -309,6 +309,13 @@ if MONOLITHIC
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_PKCS12
|
||||||
|
SUBDIRS += plugins/pkcs12
|
||||||
|
if MONOLITHIC
|
||||||
|
libstrongswan_la_LIBADD += plugins/pkcs12/libstrongswan-pkcs12.la
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
if USE_PGP
|
if USE_PGP
|
||||||
SUBDIRS += plugins/pgp
|
SUBDIRS += plugins/pgp
|
||||||
if MONOLITHIC
|
if MONOLITHIC
|
||||||
|
@ -121,6 +121,9 @@
|
|||||||
0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS
|
0x08 "unstructuredAddress" OID_UNSTRUCTURED_ADDRESS
|
||||||
0x0E "extensionRequest" OID_EXTENSION_REQUEST
|
0x0E "extensionRequest" OID_EXTENSION_REQUEST
|
||||||
0x0F "S/MIME Capabilities"
|
0x0F "S/MIME Capabilities"
|
||||||
|
0x16 "certTypes"
|
||||||
|
0x01 "X.509" OID_X509_CERTIFICATE
|
||||||
|
0x02 "SDSI"
|
||||||
0x0c "PKCS-12"
|
0x0c "PKCS-12"
|
||||||
0x01 "pbeIds"
|
0x01 "pbeIds"
|
||||||
0x01 "pbeWithSHAAnd128BitRC4" OID_PBE_SHA1_RC4_128
|
0x01 "pbeWithSHAAnd128BitRC4" OID_PBE_SHA1_RC4_128
|
||||||
@ -129,6 +132,14 @@
|
|||||||
0x04 "pbeWithSHAAnd2-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_2KEY_CBC
|
0x04 "pbeWithSHAAnd2-KeyTripleDES-CBC" OID_PBE_SHA1_3DES_2KEY_CBC
|
||||||
0x05 "pbeWithSHAAnd128BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_128
|
0x05 "pbeWithSHAAnd128BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_128
|
||||||
0x06 "pbeWithSHAAnd40BitRC2-CBC" OID_PBE_SHA1_RC2_CBC_40
|
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 "digestAlgorithm"
|
||||||
0x02 "md2" OID_MD2
|
0x02 "md2" OID_MD2
|
||||||
0x05 "md5" OID_MD5
|
0x05 "md5" OID_MD5
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
|
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
|
|
||||||
ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS7_ENCRYPTED_DATA,
|
ENUM(container_type_names, CONTAINER_PKCS7, CONTAINER_PKCS12,
|
||||||
"PKCS7",
|
"PKCS7",
|
||||||
"PKCS7_DATA",
|
"PKCS7_DATA",
|
||||||
"PKCS7_SIGNED_DATA",
|
"PKCS7_SIGNED_DATA",
|
||||||
"PKCS7_ENVELOPED_DATA",
|
"PKCS7_ENVELOPED_DATA",
|
||||||
"PKCS7_ENCRYPTED_DATA",
|
"PKCS7_ENCRYPTED_DATA",
|
||||||
|
"PKCS12",
|
||||||
);
|
);
|
||||||
|
@ -44,6 +44,8 @@ enum container_type_t {
|
|||||||
CONTAINER_PKCS7_ENVELOPED_DATA,
|
CONTAINER_PKCS7_ENVELOPED_DATA,
|
||||||
/** PKCS#7/CMS "encrypted-data" */
|
/** PKCS#7/CMS "encrypted-data" */
|
||||||
CONTAINER_PKCS7_ENCRYPTED_DATA,
|
CONTAINER_PKCS7_ENCRYPTED_DATA,
|
||||||
|
/** A PKCS#12 container */
|
||||||
|
CONTAINER_PKCS12,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,9 +21,11 @@
|
|||||||
#ifndef PKCS12_H_
|
#ifndef PKCS12_H_
|
||||||
#define PKCS12_H_
|
#define PKCS12_H_
|
||||||
|
|
||||||
|
#include <credentials/containers/container.h>
|
||||||
#include <crypto/hashers/hasher.h>
|
#include <crypto/hashers/hasher.h>
|
||||||
|
|
||||||
typedef enum pkcs12_key_type_t pkcs12_key_type_t;
|
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.
|
* The types of password based keys used by PKCS#12.
|
||||||
@ -34,6 +36,31 @@ enum pkcs12_key_type_t {
|
|||||||
PKCS12_KEY_MAC = 3,
|
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.
|
* Derive the keys used in PKCS#12 for password integrity/privacy mode.
|
||||||
*
|
*
|
||||||
|
16
src/libstrongswan/plugins/pkcs12/Makefile.am
Normal file
16
src/libstrongswan/plugins/pkcs12/Makefile.am
Normal file
@ -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
|
581
src/libstrongswan/plugins/pkcs12/pkcs12_decode.c
Normal file
581
src/libstrongswan/plugins/pkcs12/pkcs12_decode.c
Normal file
@ -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;
|
||||||
|
}
|
38
src/libstrongswan/plugins/pkcs12/pkcs12_decode.h
Normal file
38
src/libstrongswan/plugins/pkcs12/pkcs12_decode.h
Normal file
@ -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_ @}*/
|
77
src/libstrongswan/plugins/pkcs12/pkcs12_plugin.c
Normal file
77
src/libstrongswan/plugins/pkcs12/pkcs12_plugin.c
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
|
42
src/libstrongswan/plugins/pkcs12/pkcs12_plugin.h
Normal file
42
src/libstrongswan/plugins/pkcs12/pkcs12_plugin.h
Normal file
@ -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_ @}*/
|
Loading…
x
Reference in New Issue
Block a user