summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/openssl')
-rw-r--r--src/libstrongswan/plugins/openssl/Makefile.in2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_crl.c111
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c5
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_diffie_hellman.h5
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_private_key.c15
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_private_key.h3
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_ec_public_key.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_hasher.c22
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_hasher.h14
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_pkcs7.c2
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_plugin.c158
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c512
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h3
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c146
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_sha1_prf.c1
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_x509.c93
16 files changed, 828 insertions, 266 deletions
diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in
index dcf4c2c8a..856055c6a 100644
--- a/src/libstrongswan/plugins/openssl/Makefile.in
+++ b/src/libstrongswan/plugins/openssl/Makefile.in
@@ -254,9 +254,11 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
+FUZZING_LDFLAGS = @FUZZING_LDFLAGS@
GEM = @GEM@
GENHTML = @GENHTML@
GPERF = @GPERF@
+GPERF_LEN_TYPE = @GPERF_LEN_TYPE@
GPRBUILD = @GPRBUILD@
GREP = @GREP@
INSTALL = @INSTALL@
diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c
index 61cf3e884..88f7a67c2 100644
--- a/src/libstrongswan/plugins/openssl/openssl_crl.c
+++ b/src/libstrongswan/plugins/openssl/openssl_crl.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
*
@@ -47,14 +50,13 @@
#include <credentials/certificates/x509.h>
#if OPENSSL_VERSION_NUMBER < 0x10100000L
-static inline void X509_CRL_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, const X509_CRL *crl) {
+static inline void X509_CRL_get0_signature(const X509_CRL *crl, ASN1_BIT_STRING **psig, X509_ALGOR **palg) {
if (psig) { *psig = crl->signature; }
if (palg) { *palg = crl->sig_alg; }
}
#define X509_REVOKED_get0_serialNumber(r) ({ (r)->serialNumber; })
#define X509_REVOKED_get0_revocationDate(r) ({ (r)->revocationDate; })
#define X509_CRL_get0_extensions(c) ({ (c)->crl->extensions; })
-#define X509_ALGOR_get0(oid, ppt, ppv, alg) ({ *(oid) = (alg)->algorithm; })
#endif
typedef struct private_openssl_crl_t private_openssl_crl_t;
@@ -85,6 +87,16 @@ struct private_openssl_crl_t {
chunk_t serial;
/**
+ * Number of base CRL (deltaCrlIndicator), if a delta CRL
+ */
+ chunk_t base;
+
+ /**
+ * List of Freshest CRL distribution points
+ */
+ linked_list_t *crl_uris;
+
+ /**
* AuthorityKeyIdentifier of the issuing CA
*/
chunk_t authKeyIdentifier;
@@ -107,7 +119,7 @@ struct private_openssl_crl_t {
/**
* Signature scheme used in this CRL
*/
- signature_scheme_t scheme;
+ signature_params_t *scheme;
/**
* References to this CRL
@@ -140,6 +152,11 @@ typedef struct {
int i;
} crl_enumerator_t;
+/**
+ * from openssl_x509
+ */
+bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext,
+ linked_list_t *list);
METHOD(enumerator_t, crl_enumerate, bool,
crl_enumerator_t *this, va_list args)
@@ -215,6 +232,26 @@ METHOD(crl_t, get_serial, chunk_t,
return this->serial;
}
+METHOD(crl_t, is_delta_crl, bool,
+ private_openssl_crl_t *this, chunk_t *base_crl)
+{
+ if (this->base.len)
+ {
+ if (base_crl)
+ {
+ *base_crl = this->base;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(crl_t, create_delta_crl_uri_enumerator, enumerator_t*,
+ private_openssl_crl_t *this)
+{
+ return this->crl_uris->create_enumerator(this->crl_uris);
+}
+
METHOD(crl_t, get_authKeyIdentifier, chunk_t,
private_openssl_crl_t *this)
{
@@ -246,7 +283,7 @@ METHOD(certificate_t, has_subject_or_issuer, id_match_t,
METHOD(certificate_t, issued_by, bool,
private_openssl_crl_t *this, certificate_t *issuer,
- signature_scheme_t *scheme)
+ signature_params_t **scheme)
{
chunk_t fingerprint, tbs;
public_key_t *key;
@@ -283,23 +320,20 @@ METHOD(certificate_t, issued_by, bool,
return FALSE;
}
}
- if (this->scheme == SIGN_UNKNOWN)
- {
- return FALSE;
- }
/* i2d_re_X509_CRL_tbs() was added with 1.1.0 when X509_CRL became opaque */
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
tbs = openssl_i2chunk(re_X509_CRL_tbs, this->crl);
#else
tbs = openssl_i2chunk(X509_CRL_INFO, this->crl->crl);
#endif
- X509_CRL_get0_signature(&sig, NULL, this->crl);
- valid = key->verify(key, this->scheme, tbs, openssl_asn1_str2chunk(sig));
+ X509_CRL_get0_signature(this->crl, &sig, NULL);
+ valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs,
+ openssl_asn1_str2chunk(sig));
free(tbs.ptr);
key->destroy(key);
if (valid && scheme)
{
- *scheme = this->scheme;
+ *scheme = signature_params_clone(this->scheme);
}
return valid;
}
@@ -379,8 +413,12 @@ METHOD(certificate_t, destroy, void,
{
X509_CRL_free(this->crl);
}
+ signature_params_destroy(this->scheme);
+ this->crl_uris->destroy_function(this->crl_uris,
+ (void*)x509_cdp_destroy);
DESTROY_IF(this->issuer);
free(this->authKeyIdentifier.ptr);
+ free(this->base.ptr);
free(this->serial.ptr);
free(this->encoding.ptr);
free(this);
@@ -413,11 +451,12 @@ static private_openssl_crl_t *create_empty()
},
.get_serial = _get_serial,
.get_authKeyIdentifier = _get_authKeyIdentifier,
- .is_delta_crl = (void*)return_false,
- .create_delta_crl_uri_enumerator = (void*)enumerator_create_empty,
+ .is_delta_crl = _is_delta_crl,
+ .create_delta_crl_uri_enumerator = _create_delta_crl_uri_enumerator,
.create_enumerator = _create_enumerator,
},
},
+ .crl_uris = linked_list_create(),
.ref = 1,
);
return this;
@@ -444,21 +483,19 @@ static bool parse_authKeyIdentifier_ext(private_openssl_crl_t *this,
}
/**
- * Parse the crlNumber extension
+ * Quick and dirty INTEGER unwrap for crlNumber/deltaCrlIndicator extensions
*/
-static bool parse_crlNumber_ext(private_openssl_crl_t *this,
- X509_EXTENSION *ext)
+static bool parse_integer_ext(X509_EXTENSION *ext, chunk_t *out)
{
chunk_t chunk;
chunk = openssl_asn1_str2chunk(X509_EXTENSION_get_data(ext));
- /* quick and dirty INTEGER unwrap */
if (chunk.len > 1 && chunk.ptr[0] == V_ASN1_INTEGER &&
chunk.ptr[1] == chunk.len - 2)
{
chunk = chunk_skip(chunk, 2);
- free(this->serial.ptr);
- this->serial = chunk_clone(chunk);
+ free(out->ptr);
+ *out = chunk_clone(chunk);
return TRUE;
}
return FALSE;
@@ -488,7 +525,13 @@ static bool parse_extensions(private_openssl_crl_t *this)
ok = parse_authKeyIdentifier_ext(this, ext);
break;
case NID_crl_number:
- ok = parse_crlNumber_ext(this, ext);
+ ok = parse_integer_ext(ext, &this->serial);
+ break;
+ case NID_delta_crl:
+ ok = parse_integer_ext(ext, &this->base);
+ break;
+ case NID_freshest_crl:
+ ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris);
break;
case NID_issuing_distribution_point:
/* TODO support of IssuingDistributionPoints */
@@ -520,7 +563,7 @@ static bool parse_extensions(private_openssl_crl_t *this)
static bool parse_crl(private_openssl_crl_t *this)
{
const unsigned char *ptr = this->encoding.ptr;
- ASN1_OBJECT *oid;
+ chunk_t sig_scheme;
X509_ALGOR *alg;
this->crl = d2i_X509_CRL(NULL, &ptr, this->encoding.len);
@@ -529,28 +572,16 @@ static bool parse_crl(private_openssl_crl_t *this)
return FALSE;
}
- X509_CRL_get0_signature(NULL, &alg, this->crl);
- X509_ALGOR_get0(&oid, NULL, NULL, alg);
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- if (!chunk_equals(
- openssl_asn1_obj2chunk(this->crl->crl->sig_alg->algorithm),
- openssl_asn1_obj2chunk(this->crl->sig_alg->algorithm)))
+ X509_CRL_get0_signature(this->crl, NULL, &alg);
+ sig_scheme = openssl_i2chunk(X509_ALGOR, alg);
+ INIT(this->scheme);
+ if (!signature_params_parse(sig_scheme, 0, this->scheme))
{
+ DBG1(DBG_ASN, "unable to parse signature algorithm");
+ free(sig_scheme.ptr);
return FALSE;
}
-#elif 0
- /* FIXME: we currently can't do this if X509_CRL is opaque (>= 1.1.0) as
- * X509_CRL_get0_tbs_sigalg() does not exist and there does not seem to be
- * another easy way to get the algorithm from the tbsCertList of the CRL */
- alg = X509_CRL_get0_tbs_sigalg(this->crl);
- X509_ALGOR_get0(&oid_tbs, NULL, NULL, alg);
- if (!chunk_equals(openssl_asn1_obj2chunk(oid),
- openssl_asn1_obj2chunk(oid_tbs)))
- {
- return FALSE;
- }
-#endif
- this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid(oid));
+ free(sig_scheme.ptr);
this->issuer = openssl_x509_name2id(X509_CRL_get_issuer(this->crl));
if (!this->issuer)
diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
index f08dfff7e..8e9c1183f 100644
--- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
+++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.c
@@ -193,7 +193,7 @@ METHOD(diffie_hellman_t, destroy, void,
* Described in header.
*/
openssl_diffie_hellman_t *openssl_diffie_hellman_create(
- diffie_hellman_group_t group, chunk_t g, chunk_t p)
+ diffie_hellman_group_t group, ...)
{
private_openssl_diffie_hellman_t *this;
const BIGNUM *privkey;
@@ -225,6 +225,9 @@ openssl_diffie_hellman_t *openssl_diffie_hellman_create(
if (group == MODP_CUSTOM)
{
+ chunk_t g, p;
+
+ VA_ARGS_GET(group, g, p);
if (!DH_set0_pqg(this->dh, BN_bin2bn(p.ptr, p.len, NULL), NULL,
BN_bin2bn(g.ptr, g.len, NULL)))
{
diff --git a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.h b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.h
index 53dc59c78..5de5520b5 100644
--- a/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.h
+++ b/src/libstrongswan/plugins/openssl/openssl_diffie_hellman.h
@@ -40,12 +40,11 @@ struct openssl_diffie_hellman_t {
* Creates a new openssl_diffie_hellman_t object.
*
* @param group Diffie Hellman group number to use
- * @param g custom generator, if MODP_CUSTOM
- * @param p custom prime, if MODP_CUSTOM
+ * @param ... expects generator and prime as chunk_t if MODP_CUSTOM
* @return openssl_diffie_hellman_t object, NULL if not supported
*/
openssl_diffie_hellman_t *openssl_diffie_hellman_create(
- diffie_hellman_group_t group, chunk_t g, chunk_t p);
+ diffie_hellman_group_t group, ...);
#endif /** OPENSSL_DIFFIE_HELLMAN_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
index 22bbf6dc7..364190758 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
@@ -49,6 +49,11 @@ struct private_openssl_ec_private_key_t {
EC_KEY *ec;
/**
+ * TRUE if the key is from an OpenSSL ENGINE and might not be readable
+ */
+ bool engine;
+
+ /**
* reference count
*/
refcount_t ref;
@@ -146,7 +151,7 @@ static bool build_der_signature(private_openssl_ec_private_key_t *this,
METHOD(private_key_t, sign, bool,
private_openssl_ec_private_key_t *this, signature_scheme_t scheme,
- chunk_t data, chunk_t *signature)
+ void *params, chunk_t data, chunk_t *signature)
{
switch (scheme)
{
@@ -226,6 +231,11 @@ METHOD(private_key_t, get_encoding, bool,
{
u_char *p;
+ if (this->engine)
+ {
+ return FALSE;
+ }
+
switch (type)
{
case PRIVKEY_ASN1_DER:
@@ -307,7 +317,7 @@ static private_openssl_ec_private_key_t *create_empty(void)
/*
* See header.
*/
-private_key_t *openssl_ec_private_key_create(EVP_PKEY *key)
+private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine)
{
private_openssl_ec_private_key_t *this;
EC_KEY *ec;
@@ -320,6 +330,7 @@ private_key_t *openssl_ec_private_key_create(EVP_PKEY *key)
}
this = create_empty();
this->ec = ec;
+ this->engine = engine;
return &this->public.key;
}
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.h b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.h
index 84314f671..56c59cfc8 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_private_key.h
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_private_key.h
@@ -67,8 +67,9 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
* Wrap an EVP_PKEY object of type EVP_PKEY_EC
*
* @param key EVP_PKEY_EC key object (adopted)
+ * @param engine whether the key was loaded via an engine
* @return loaded key, NULL on failure
*/
-private_key_t *openssl_ec_private_key_create(EVP_PKEY *key);
+private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine);
#endif /** OPENSSL_EC_PRIVATE_KEY_H_ @}*/
diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
index a1e56fc5e..faa940839 100644
--- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
@@ -151,7 +151,7 @@ METHOD(public_key_t, get_type, key_type_t,
METHOD(public_key_t, verify, bool,
private_openssl_ec_public_key_t *this, signature_scheme_t scheme,
- chunk_t data, chunk_t signature)
+ void *params, chunk_t data, chunk_t signature)
{
switch (scheme)
{
diff --git a/src/libstrongswan/plugins/openssl/openssl_hasher.c b/src/libstrongswan/plugins/openssl/openssl_hasher.c
index 96ee230c9..eb6c50508 100644
--- a/src/libstrongswan/plugins/openssl/openssl_hasher.c
+++ b/src/libstrongswan/plugins/openssl/openssl_hasher.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2008-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -91,16 +91,24 @@ METHOD(hasher_t, destroy, void,
/*
* Described in header
*/
-openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo)
+const EVP_MD *openssl_get_md(hash_algorithm_t hash)
{
- private_openssl_hasher_t *this;
- char* name;
+ char *name;
- name = enum_to_name(hash_algorithm_short_names, algo);
+ name = enum_to_name(hash_algorithm_short_names, hash);
if (!name)
{
return NULL;
}
+ return EVP_get_digestbyname(name);
+}
+
+/*
+ * Described in header
+ */
+openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo)
+{
+ private_openssl_hasher_t *this;
INIT(this,
.public = {
@@ -114,7 +122,7 @@ openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo)
},
);
- this->hasher = EVP_get_digestbyname(name);
+ this->hasher = openssl_get_md(algo);
if (!this->hasher)
{
/* OpenSSL does not support the requested algo */
diff --git a/src/libstrongswan/plugins/openssl/openssl_hasher.h b/src/libstrongswan/plugins/openssl/openssl_hasher.h
index b03f6891b..66b9b505e 100644
--- a/src/libstrongswan/plugins/openssl/openssl_hasher.h
+++ b/src/libstrongswan/plugins/openssl/openssl_hasher.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2008-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -25,6 +25,8 @@ typedef struct openssl_hasher_t openssl_hasher_t;
#include <crypto/hashers/hasher.h>
+#include <openssl/evp.h>
+
/**
* Implementation of hashers using OpenSSL.
*/
@@ -37,6 +39,14 @@ struct openssl_hasher_t {
};
/**
+ * Determine EVP_MD for the given hash algorithm
+ *
+ * @param hash hash algorithm
+ * @return EVP_MD or NULL if not found/supported
+ */
+const EVP_MD *openssl_get_md(hash_algorithm_t hash);
+
+/**
* Constructor to create openssl_hasher_t.
*
* @param algo algorithm
diff --git a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
index 83ac8df5b..f94767cf5 100644
--- a/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
+++ b/src/libstrongswan/plugins/openssl/openssl_pkcs7.c
@@ -256,7 +256,7 @@ static auth_cfg_t *verify_signature(CMS_SignerInfo *si, int hash_oid)
key = cert->get_public_key(cert);
if (key)
{
- if (key->verify(key, signature_scheme_from_oid(hash_oid),
+ if (key->verify(key, signature_scheme_from_oid(hash_oid), NULL,
attrs, sig))
{
found = auth->clone(auth);
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index ab73d718f..8b0a7c5c7 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -301,11 +301,11 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
{
#ifndef OPENSSL_NO_RSA
case EVP_PKEY_RSA:
- return openssl_rsa_private_key_create(key);
+ return openssl_rsa_private_key_create(key, FALSE);
#endif
#ifndef OPENSSL_NO_ECDSA
case EVP_PKEY_EC:
- return openssl_ec_private_key_create(key);
+ return openssl_ec_private_key_create(key, FALSE);
#endif
default:
EVP_PKEY_free(key);
@@ -316,6 +316,152 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
return NULL;
}
+#ifndef OPENSSL_NO_ENGINE
+/**
+ * Login to engine with a PIN specified for a keyid
+ */
+static bool login(ENGINE *engine, chunk_t keyid)
+{
+ enumerator_t *enumerator;
+ shared_key_t *shared;
+ identification_t *id;
+ chunk_t key;
+ char pin[64];
+ bool found = FALSE, success = FALSE;
+
+ id = identification_create_from_encoding(ID_KEY_ID, keyid);
+ enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
+ SHARED_PIN, id, NULL);
+ while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
+ {
+ found = TRUE;
+ key = shared->get_key(shared);
+ if (snprintf(pin, sizeof(pin),
+ "%.*s", (int)key.len, key.ptr) >= sizeof(pin))
+ {
+ continue;
+ }
+ if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
+ {
+ success = TRUE;
+ break;
+ }
+ else
+ {
+ DBG1(DBG_CFG, "setting PIN on engine failed");
+ }
+ }
+ enumerator->destroy(enumerator);
+ id->destroy(id);
+ if (!found)
+ {
+ DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
+ }
+ return success;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+/**
+ * Load private key via engine
+ */
+static private_key_t *openssl_private_key_connect(key_type_t type,
+ va_list args)
+{
+#ifndef OPENSSL_NO_ENGINE
+ char *engine_id = NULL;
+ char keyname[BUF_LEN];
+ chunk_t keyid = chunk_empty;;
+ EVP_PKEY *key;
+ ENGINE *engine;
+ int slot = -1;
+
+ while (TRUE)
+ {
+ switch (va_arg(args, builder_part_t))
+ {
+ case BUILD_PKCS11_KEYID:
+ keyid = va_arg(args, chunk_t);
+ continue;
+ case BUILD_PKCS11_SLOT:
+ slot = va_arg(args, int);
+ continue;
+ case BUILD_PKCS11_MODULE:
+ engine_id = va_arg(args, char*);
+ continue;
+ case BUILD_END:
+ break;
+ default:
+ return NULL;
+ }
+ break;
+ }
+ if (!keyid.len || keyid.len > 40)
+ {
+ return NULL;
+ }
+
+ memset(keyname, 0, sizeof(keyname));
+ if (slot != -1)
+ {
+ snprintf(keyname, sizeof(keyname), "%d:", slot);
+ }
+ if (sizeof(keyname) - strlen(keyname) <= keyid.len * 4 / 3 + 1)
+ {
+ return NULL;
+ }
+ chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
+
+ if (!engine_id)
+ {
+ engine_id = lib->settings->get_str(lib->settings,
+ "%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
+ }
+ engine = ENGINE_by_id(engine_id);
+ if (!engine)
+ {
+ DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
+ return NULL;
+ }
+ if (!ENGINE_init(engine))
+ {
+ DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
+ ENGINE_free(engine);
+ return NULL;
+ }
+ if (!login(engine, keyid))
+ {
+ DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
+ ENGINE_free(engine);
+ return NULL;
+ }
+ key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
+ if (!key)
+ {
+ DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
+ "engine '%s'", keyname, engine_id);
+ ENGINE_free(engine);
+ return NULL;
+ }
+ ENGINE_free(engine);
+
+ switch (EVP_PKEY_base_id(key))
+ {
+#ifndef OPENSSL_NO_RSA
+ case EVP_PKEY_RSA:
+ return openssl_rsa_private_key_create(key, TRUE);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case EVP_PKEY_EC:
+ return openssl_ec_private_key_create(key, TRUE);
+#endif
+ default:
+ EVP_PKEY_free(key);
+ break;
+ }
+#endif /* OPENSSL_NO_ENGINE */
+ return NULL;
+}
+
METHOD(plugin_t, get_name, char*,
private_openssl_plugin_t *this)
{
@@ -469,8 +615,6 @@ METHOD(plugin_t, get_features, int,
/* RSA private/public key loading */
PLUGIN_REGISTER(PRIVKEY, openssl_rsa_private_key_load, TRUE),
PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
- PLUGIN_REGISTER(PRIVKEY, openssl_rsa_private_key_connect, FALSE),
- PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
PLUGIN_REGISTER(PRIVKEY_GEN, openssl_rsa_private_key_gen, FALSE),
PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
PLUGIN_REGISTER(PUBKEY, openssl_rsa_public_key_load, TRUE),
@@ -480,6 +624,10 @@ METHOD(plugin_t, get_features, int,
/* signature/encryption schemes */
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL),
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS),
+ PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS),
+#endif
#ifndef OPENSSL_NO_SHA1
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1),
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA1),
@@ -554,6 +702,8 @@ METHOD(plugin_t, get_features, int,
/* generic key loader */
PLUGIN_REGISTER(PRIVKEY, openssl_private_key_load, TRUE),
PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
+ PLUGIN_REGISTER(PRIVKEY, openssl_private_key_connect, FALSE),
+ PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
PLUGIN_REGISTER(RNG, openssl_rng_create),
PLUGIN_PROVIDE(RNG, RNG_STRONG),
PLUGIN_PROVIDE(RNG, RNG_WEAK),
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
index 54ecf2542..401a51a0b 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2016 Tobias Brunner
+ * Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -20,16 +20,15 @@
#include "openssl_rsa_private_key.h"
#include "openssl_rsa_public_key.h"
+#include "openssl_hasher.h"
#include "openssl_util.h"
#include <utils/debug.h>
+#include <credentials/keys/signature_params.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif /* OPENSSL_NO_ENGINE */
/**
* Public exponent to use for key generation.
@@ -40,6 +39,7 @@
OPENSSL_KEY_FALLBACK(RSA, key, n, e, d)
OPENSSL_KEY_FALLBACK(RSA, factors, p, q)
OPENSSL_KEY_FALLBACK(RSA, crt_params, dmp1, dmq1, iqmp)
+#define BN_secure_new() BN_new()
#endif
typedef struct private_openssl_rsa_private_key_t private_openssl_rsa_private_key_t;
@@ -72,8 +72,126 @@ struct private_openssl_rsa_private_key_t {
/* implemented in rsa public key */
bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+
/**
- * Build an EMPSA PKCS1 signature described in PKCS#1
+ * Build RSA signature
+ */
+static bool build_signature(private_openssl_rsa_private_key_t *this,
+ const EVP_MD *md, rsa_pss_params_t *pss,
+ chunk_t data, chunk_t *sig)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY *key;
+ bool success = FALSE;
+
+ mctx = EVP_MD_CTX_create();
+ key = EVP_PKEY_new();
+ if (!mctx || !key)
+ {
+ goto error;
+ }
+ if (!EVP_PKEY_set1_RSA(key, this->rsa))
+ {
+ goto error;
+ }
+ if (EVP_DigestSignInit(mctx, &pctx, md, NULL, key) <= 0)
+ {
+ goto error;
+ }
+ if (pss)
+ {
+ const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
+ int slen = EVP_MD_size(md);
+ if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
+ {
+ slen = pss->salt_len;
+ }
+ if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
+ {
+ goto error;
+ }
+ }
+ if (EVP_DigestSignUpdate(mctx, data.ptr, data.len) <= 0)
+ {
+ goto error;
+ }
+ success = (EVP_DigestSignFinal(mctx, sig->ptr, &sig->len) == 1);
+
+error:
+ if (key)
+ {
+ EVP_PKEY_free(key);
+ }
+ if (mctx)
+ {
+ EVP_MD_CTX_destroy(mctx);
+ }
+ return success;
+}
+
+/**
+ * Build an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this,
+ int type, chunk_t data, chunk_t *sig)
+{
+ const EVP_MD *md;
+
+ *sig = chunk_alloc(RSA_size(this->rsa));
+
+ if (type == NID_undef)
+ {
+ if (RSA_private_encrypt(data.len, data.ptr, sig->ptr, this->rsa,
+ RSA_PKCS1_PADDING) == sig->len)
+ {
+ return TRUE;
+ }
+ }
+ else
+ {
+ md = EVP_get_digestbynid(type);
+ if (md && build_signature(this, md, NULL, data, sig))
+ {
+ return TRUE;
+ }
+ }
+ chunk_free(sig);
+ return FALSE;
+}
+
+/**
+ * Build an EMSA PSS signature described in PKCS#1
+ */
+static bool build_emsa_pss_signature(private_openssl_rsa_private_key_t *this,
+ rsa_pss_params_t *params, chunk_t data,
+ chunk_t *sig)
+{
+ const EVP_MD *md;
+
+ if (!params)
+ {
+ return FALSE;
+ }
+
+ *sig = chunk_alloc(RSA_size(this->rsa));
+
+ md = openssl_get_md(params->hash);
+ if (md && build_signature(this, md, params, data, sig))
+ {
+ return TRUE;
+ }
+ chunk_free(sig);
+ return FALSE;
+}
+
+#else /* OPENSSL_VERSION_NUMBER < 1.0 */
+
+/**
+ * Build an EMSA PKCS1 signature described in PKCS#1
*/
static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this,
int type, chunk_t data, chunk_t *sig)
@@ -92,15 +210,15 @@ static bool build_emsa_pkcs1_signature(private_openssl_rsa_private_key_t *this,
}
else
{
- EVP_MD_CTX *ctx;
- EVP_PKEY *key;
+ EVP_MD_CTX *ctx = NULL;
+ EVP_PKEY *key = NULL;
const EVP_MD *hasher;
u_int len;
hasher = EVP_get_digestbynid(type);
if (!hasher)
{
- return FALSE;
+ goto error;
}
ctx = EVP_MD_CTX_create();
@@ -142,7 +260,7 @@ error:
}
return success;
}
-
+#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
METHOD(private_key_t, get_type, key_type_t,
private_openssl_rsa_private_key_t *this)
@@ -152,7 +270,7 @@ METHOD(private_key_t, get_type, key_type_t,
METHOD(private_key_t, sign, bool,
private_openssl_rsa_private_key_t *this, signature_scheme_t scheme,
- chunk_t data, chunk_t *signature)
+ void *params, chunk_t data, chunk_t *signature)
{
switch (scheme)
{
@@ -170,6 +288,10 @@ METHOD(private_key_t, sign, bool,
return build_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5:
return build_emsa_pkcs1_signature(this, NID_md5, data, signature);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ case SIGN_RSA_EMSA_PSS:
+ return build_emsa_pss_signature(this, params, data, signature);
+#endif
default:
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
signature_scheme_names, scheme);
@@ -386,7 +508,7 @@ error:
/*
* See header
*/
-private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key)
+private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine)
{
private_openssl_rsa_private_key_t *this;
RSA *rsa;
@@ -399,9 +521,199 @@ private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key)
}
this = create_empty();
this->rsa = rsa;
+ this->engine = engine;
return &this->public.key;
}
+/**
+ * Recover the primes from n, e and d using the algorithm described in
+ * Appendix C of NIST SP 800-56B.
+ */
+static bool calculate_pq(BIGNUM *n, BIGNUM *e, BIGNUM *d,
+ BIGNUM **p, BIGNUM **q)
+{
+ BN_CTX *ctx;
+ BIGNUM *k, *r, *g, *y, *n1, *x;
+ int i, t, j;
+ bool success = FALSE;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ {
+ return FALSE;
+ }
+ BN_CTX_start(ctx);
+ k = BN_CTX_get(ctx);
+ r = BN_CTX_get(ctx);
+ g = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ n1 = BN_CTX_get(ctx);
+ x = BN_CTX_get(ctx);
+ if (!x)
+ {
+ goto error;
+ }
+ /* k = (d * e) - 1 */
+ if (!BN_mul(k, d, e, ctx) || !BN_sub(k, k, BN_value_one()))
+ {
+ goto error;
+ }
+ /* k must be even */
+ if (BN_is_odd(k))
+ {
+ goto error;
+ }
+ /* k = 2^t * r, where r is the largest odd integer dividing k, and t >= 1 */
+ if (!BN_copy(r, k))
+ {
+ goto error;
+ }
+ for (t = 0; !BN_is_odd(r); t++)
+ { /* r = r/2 */
+ if (!BN_rshift(r, r, 1))
+ {
+ goto error;
+ }
+ }
+ /* we need n-1 below */
+ if (!BN_sub(n1, n, BN_value_one()))
+ {
+ goto error;
+ }
+ for (i = 0; i < 100; i++)
+ { /* generate random integer g in [0, n-1] */
+ if (!BN_pseudo_rand_range(g, n))
+ {
+ goto error;
+ }
+ /* y = g^r mod n */
+ if (!BN_mod_exp(y, g, r, n, ctx))
+ {
+ goto error;
+ }
+ /* try again if y == 1 or y == n-1 */
+ if (BN_is_one(y) || BN_cmp(y, n1) == 0)
+ {
+ continue;
+ }
+ for (j = 0; j < t; j++)
+ { /* x = y^2 mod n */
+ if (!BN_mod_sqr(x, y, n, ctx))
+ {
+ goto error;
+ }
+ /* stop if x == 1 */
+ if (BN_is_one(x))
+ {
+ goto done;
+ }
+ /* retry with new g if x = n-1 */
+ if (BN_cmp(x, n1) == 0)
+ {
+ break;
+ }
+ /* y = x */
+ if (!BN_copy(y, x))
+ {
+ goto error;
+ }
+ }
+ }
+ goto error;
+
+done:
+ /* p = gcd(y-1, n) */
+ if (!BN_sub(y, y, BN_value_one()))
+ {
+ goto error;
+ }
+ *p = BN_secure_new();
+ if (!BN_gcd(*p, y, n, ctx))
+ {
+ BN_clear_free(*p);
+ goto error;
+ }
+ /* q = n/p */
+ *q = BN_secure_new();
+ if (!BN_div(*q, NULL, n, *p, ctx))
+ {
+ BN_clear_free(*p);
+ BN_clear_free(*q);
+ goto error;
+ }
+ success = TRUE;
+
+error:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return success;
+}
+
+/**
+ * Calculates dp = d (mod p-1) or dq = d (mod q-1) for the Chinese remainder
+ * algorithm.
+ */
+static BIGNUM *dmodpq1(BIGNUM *d, BIGNUM *pq)
+{
+ BN_CTX *ctx;
+ BIGNUM *res = NULL, *pq1;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ {
+ return NULL;
+ }
+ BN_CTX_start(ctx);
+ pq1 = BN_CTX_get(ctx);
+ /* p|q - 1 */
+ if (!BN_sub(pq1, pq, BN_value_one()))
+ {
+ goto error;
+ }
+ /* d (mod p|q -1) */
+ res = BN_secure_new();
+ if (!BN_mod(res, d, pq1, ctx))
+ {
+ BN_clear_free(res);
+ res = NULL;
+ goto error;
+ }
+
+error:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return res;
+}
+
+/**
+ * Calculates qinv = q^-1 (mod p) for the Chinese remainder algorithm.
+ */
+static BIGNUM *qinv(BIGNUM *q, BIGNUM *p)
+{
+ BN_CTX *ctx;
+ BIGNUM *res = NULL;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ {
+ return NULL;
+ }
+ BN_CTX_start(ctx);
+ /* q^-1 (mod p) */
+ res = BN_secure_new();
+ if (!BN_mod_inverse(res, q, p, ctx))
+ {
+ BN_clear_free(res);
+ res = NULL;
+ goto error;
+ }
+
+error:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return res;
+}
+
/*
* See header
*/
@@ -460,7 +772,7 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
return &this->public;
}
}
- else if (n.ptr && e.ptr && d.ptr && p.ptr && q.ptr && coeff.ptr)
+ else if (n.ptr && e.ptr && d.ptr)
{
BIGNUM *bn_n, *bn_e, *bn_d, *bn_p, *bn_q;
BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
@@ -472,178 +784,58 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
bn_d = BN_bin2bn((const u_char*)d.ptr, d.len, NULL);
if (!RSA_set0_key(this->rsa, bn_n, bn_e, bn_d))
{
- destroy(this);
- return NULL;
+ goto error;
}
- bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, NULL);
- bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, NULL);
+ if (p.ptr && q.ptr)
+ {
+ bn_p = BN_bin2bn((const u_char*)p.ptr, p.len, NULL);
+ bn_q = BN_bin2bn((const u_char*)q.ptr, q.len, NULL);
+ }
+ else
+ {
+ if (!calculate_pq(bn_n, bn_e, bn_d, &bn_p, &bn_q))
+ {
+ goto error;
+ }
+ }
if (!RSA_set0_factors(this->rsa, bn_p, bn_q))
{
- destroy(this);
- return NULL;
+ goto error;
}
if (exp1.ptr)
{
dmp1 = BN_bin2bn((const u_char*)exp1.ptr, exp1.len, NULL);
}
- if (exp2.ptr)
+ else
{
- dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, NULL);
+ dmp1 = dmodpq1(bn_d, bn_p);
}
- iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, NULL);
- if (RSA_set0_crt_params(this->rsa, dmp1, dmq1, iqmp) &&
- RSA_check_key(this->rsa) == 1)
+ if (exp2.ptr)
{
- return &this->public;
+ dmq1 = BN_bin2bn((const u_char*)exp2.ptr, exp2.len, NULL);
}
- }
- destroy(this);
- return NULL;
-}
-
-#ifndef OPENSSL_NO_ENGINE
-/**
- * Login to engine with a PIN specified for a keyid
- */
-static bool login(ENGINE *engine, chunk_t keyid)
-{
- enumerator_t *enumerator;
- shared_key_t *shared;
- identification_t *id;
- chunk_t key;
- char pin[64];
- bool found = FALSE, success = FALSE;
-
- id = identification_create_from_encoding(ID_KEY_ID, keyid);
- enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
- SHARED_PIN, id, NULL);
- while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
- {
- found = TRUE;
- key = shared->get_key(shared);
- if (snprintf(pin, sizeof(pin),
- "%.*s", (int)key.len, key.ptr) >= sizeof(pin))
+ else
{
- continue;
+ dmq1 = dmodpq1(bn_d, bn_q);
}
- if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
+ if (coeff.ptr)
{
- success = TRUE;
- break;
+ iqmp = BN_bin2bn((const u_char*)coeff.ptr, coeff.len, NULL);
}
else
{
- DBG1(DBG_CFG, "setting PIN on engine failed");
+ iqmp = qinv(bn_q, bn_p);
}
- }
- enumerator->destroy(enumerator);
- id->destroy(id);
- if (!found)
- {
- DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
- }
- return success;
-}
-#endif /* OPENSSL_NO_ENGINE */
-
-/*
- * See header.
- */
-openssl_rsa_private_key_t *openssl_rsa_private_key_connect(key_type_t type,
- va_list args)
-{
-#ifndef OPENSSL_NO_ENGINE
- private_openssl_rsa_private_key_t *this;
- char *engine_id = NULL;
- char keyname[64];
- chunk_t keyid = chunk_empty;;
- EVP_PKEY *key;
- ENGINE *engine;
- int slot = -1;
-
- while (TRUE)
- {
- switch (va_arg(args, builder_part_t))
+ if (RSA_set0_crt_params(this->rsa, dmp1, dmq1, iqmp) &&
+ RSA_check_key(this->rsa) == 1)
{
- case BUILD_PKCS11_KEYID:
- keyid = va_arg(args, chunk_t);
- continue;
- case BUILD_PKCS11_SLOT:
- slot = va_arg(args, int);
- continue;
- case BUILD_PKCS11_MODULE:
- engine_id = va_arg(args, char*);
- continue;
- case BUILD_END:
- break;
- default:
- return NULL;
+ return &this->public;
}
- break;
- }
- if (!keyid.len || keyid.len > 40)
- {
- return NULL;
- }
-
- memset(keyname, 0, sizeof(keyname));
- if (slot != -1)
- {
- snprintf(keyname, sizeof(keyname), "%d:", slot);
- }
- if (sizeof(keyname) - strlen(keyname) <= keyid.len * 4 / 3 + 1)
- {
- return NULL;
- }
- chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
-
- if (!engine_id)
- {
- engine_id = lib->settings->get_str(lib->settings,
- "%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
- }
- engine = ENGINE_by_id(engine_id);
- if (!engine)
- {
- DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
- return NULL;
- }
- if (!ENGINE_init(engine))
- {
- DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
- ENGINE_free(engine);
- return NULL;
- }
- if (!login(engine, keyid))
- {
- DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
- ENGINE_free(engine);
- return NULL;
- }
- key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
- if (!key)
- {
- DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
- "engine '%s'", keyname, engine_id);
- ENGINE_free(engine);
- return NULL;
- }
- ENGINE_free(engine);
-
- this = create_empty();
- this->rsa = EVP_PKEY_get1_RSA(key);
- this->engine = TRUE;
- if (!this->rsa)
- {
- destroy(this);
- return NULL;
}
-
- return &this->public;
-#else /* OPENSSL_NO_ENGINE */
+error:
+ destroy(this);
return NULL;
-#endif /* OPENSSL_NO_ENGINE */
}
#endif /* OPENSSL_NO_RSA */
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h
index 34ce4c776..783181c1d 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h
@@ -67,9 +67,10 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
* Wrap an EVP_PKEY object of type EVP_PKEY_RSA
*
* @param key EVP_PKEY_RSA key object (adopted)
+ * @param engine whether the key was loaded via an engine
* @return loaded key, NULL on failure
*/
-private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key);
+private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine);
/**
* Connect to a RSA private key on a smartcard.
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
index d3a644f72..20bf30ae9 100644
--- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
+++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
@@ -1,7 +1,7 @@
/*
+ * Copyright (C) 2008-2017 Tobias Brunner
* Copyright (C) 2009 Martin Willi
- * Copyright (C) 2008 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -19,9 +19,11 @@
#ifndef OPENSSL_NO_RSA
#include "openssl_rsa_public_key.h"
+#include "openssl_hasher.h"
#include "openssl_util.h"
#include <utils/debug.h>
+#include <credentials/keys/signature_params.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
@@ -54,8 +56,138 @@ struct private_openssl_rsa_public_key_t {
refcount_t ref;
};
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+
+/**
+ * Verify RSA signature
+ */
+static bool verify_signature(private_openssl_rsa_public_key_t *this,
+ const EVP_MD *md, rsa_pss_params_t *pss,
+ chunk_t data, chunk_t signature)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY *key;
+ int rsa_size = RSA_size(this->rsa);
+ bool valid = FALSE;
+
+ /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */
+ if (signature.len > rsa_size)
+ {
+ signature = chunk_skip(signature, signature.len - rsa_size);
+ }
+
+ mctx = EVP_MD_CTX_create();
+ key = EVP_PKEY_new();
+ if (!mctx || !key)
+ {
+ goto error;
+ }
+ if (!EVP_PKEY_set1_RSA(key, this->rsa))
+ {
+ goto error;
+ }
+ if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, key) <= 0)
+ {
+ goto error;
+ }
+ if (pss)
+ {
+ const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash);
+ int slen = EVP_MD_size(md);
+ if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT)
+ {
+ slen = pss->salt_len;
+ }
+ if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 ||
+ EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0)
+ {
+ goto error;
+ }
+ }
+ if (EVP_DigestVerifyUpdate(mctx, data.ptr, data.len) <= 0)
+ {
+ goto error;
+ }
+ valid = (EVP_DigestVerifyFinal(mctx, signature.ptr, signature.len) == 1);
+
+error:
+ if (key)
+ {
+ EVP_PKEY_free(key);
+ }
+ if (mctx)
+ {
+ EVP_MD_CTX_destroy(mctx);
+ }
+ return valid;
+}
+
/**
- * Verification of an EMPSA PKCS1 signature described in PKCS#1
+ * Verification of a signature without hashing
+ */
+static bool verify_plain_signature(private_openssl_rsa_public_key_t *this,
+ chunk_t data, chunk_t signature)
+{
+ char *buf;
+ int len, rsa_size = RSA_size(this->rsa);
+ bool valid = FALSE;
+
+ /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */
+ if (signature.len > rsa_size)
+ {
+ signature = chunk_skip(signature, signature.len - rsa_size);
+ }
+ buf = malloc(rsa_size);
+ len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa,
+ RSA_PKCS1_PADDING);
+ if (len != -1)
+ {
+ valid = chunk_equals_const(data, chunk_create(buf, len));
+ }
+ free(buf);
+ return valid;
+}
+
+/**
+ * Verification of an EMSA PKCS1 signature described in PKCS#1
+ */
+static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this,
+ int type, chunk_t data, chunk_t signature)
+{
+ const EVP_MD *md;
+
+ if (type == NID_undef)
+ {
+ return verify_plain_signature(this, data, signature);
+ }
+ md = EVP_get_digestbynid(type);
+ return md && verify_signature(this, md, NULL, data, signature);
+}
+
+/**
+ * Verification of an EMSA PSS signature described in PKCS#1
+ */
+static bool verify_emsa_pss_signature(private_openssl_rsa_public_key_t *this,
+ rsa_pss_params_t *params, chunk_t data,
+ chunk_t signature)
+{
+ const EVP_MD *md;
+
+ if (!params)
+ {
+ return FALSE;
+ }
+ md = openssl_get_md(params->hash);
+ return md && verify_signature(this, md, params, data, signature);
+}
+
+#else /* OPENSSL_VERSION_NUMBER < 1.0 */
+
+/**
+ * Verification of an EMSA PKCS1 signature described in PKCS#1
*/
static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this,
int type, chunk_t data, chunk_t signature)
@@ -129,6 +261,8 @@ error:
return valid;
}
+#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
+
METHOD(public_key_t, get_type, key_type_t,
private_openssl_rsa_public_key_t *this)
{
@@ -137,7 +271,7 @@ METHOD(public_key_t, get_type, key_type_t,
METHOD(public_key_t, verify, bool,
private_openssl_rsa_public_key_t *this, signature_scheme_t scheme,
- chunk_t data, chunk_t signature)
+ void *params, chunk_t data, chunk_t signature)
{
switch (scheme)
{
@@ -155,6 +289,10 @@ METHOD(public_key_t, verify, bool,
return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature);
case SIGN_RSA_EMSA_PKCS1_MD5:
return verify_emsa_pkcs1_signature(this, NID_md5, data, signature);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ case SIGN_RSA_EMSA_PSS:
+ return verify_emsa_pss_signature(this, params, data, signature);
+#endif
default:
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
signature_scheme_names, scheme);
diff --git a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c
index f6df03f12..3a6d2f193 100644
--- a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c
+++ b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c
@@ -20,6 +20,7 @@
#include "openssl_sha1_prf.h"
#include <openssl/sha.h>
+#include <crypto/hashers/hasher.h>
typedef struct private_openssl_sha1_prf_t private_openssl_sha1_prf_t;
diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c
index e03a4255d..60c08770b 100644
--- a/src/libstrongswan/plugins/openssl/openssl_x509.c
+++ b/src/libstrongswan/plugins/openssl/openssl_x509.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2011-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2010 revosec AG
@@ -154,7 +154,7 @@ struct private_openssl_x509_t {
/**
* Signature scheme of the certificate
*/
- signature_scheme_t scheme;
+ signature_params_t *scheme;
/**
* subjectAltNames
@@ -189,16 +189,6 @@ struct private_openssl_x509_t {
};
/**
- * Destroy a CRL URI struct
- */
-static void crl_uri_destroy(x509_cdp_t *this)
-{
- free(this->uri);
- DESTROY_IF(this->issuer);
- free(this);
-}
-
-/**
* Convert a GeneralName to an identification_t.
*/
static identification_t *general_name2id(GENERAL_NAME *name)
@@ -394,7 +384,7 @@ METHOD(certificate_t, has_issuer, id_match_t,
METHOD(certificate_t, issued_by, bool,
private_openssl_x509_t *this, certificate_t *issuer,
- signature_scheme_t *scheme)
+ signature_params_t **scheme)
{
public_key_t *key;
bool valid;
@@ -406,7 +396,8 @@ METHOD(certificate_t, issued_by, bool,
{
if (this->flags & X509_SELF_SIGNED)
{
- return TRUE;
+ valid = TRUE;
+ goto out;
}
}
else
@@ -424,10 +415,6 @@ METHOD(certificate_t, issued_by, bool,
return FALSE;
}
}
- if (this->scheme == SIGN_UNKNOWN)
- {
- return FALSE;
- }
key = issuer->get_public_key(issuer);
if (!key)
{
@@ -440,12 +427,15 @@ METHOD(certificate_t, issued_by, bool,
tbs = openssl_i2chunk(X509_CINF, this->x509->cert_info);
#endif
X509_get0_signature(&sig, NULL, this->x509);
- valid = key->verify(key, this->scheme, tbs, openssl_asn1_str2chunk(sig));
+ valid = key->verify(key, this->scheme->scheme, this->scheme->params, tbs,
+ openssl_asn1_str2chunk(sig));
free(tbs.ptr);
key->destroy(key);
+
+out:
if (valid && scheme)
{
- *scheme = this->scheme;
+ *scheme = signature_params_clone(this->scheme);
}
return valid;
}
@@ -538,6 +528,7 @@ METHOD(certificate_t, destroy, void,
{
X509_free(this->x509);
}
+ signature_params_destroy(this->scheme);
DESTROY_IF(this->subject);
DESTROY_IF(this->issuer);
DESTROY_IF(this->pubkey);
@@ -549,7 +540,8 @@ METHOD(certificate_t, destroy, void,
offsetof(identification_t, destroy));
this->issuerAltNames->destroy_offset(this->issuerAltNames,
offsetof(identification_t, destroy));
- this->crl_uris->destroy_function(this->crl_uris, (void*)crl_uri_destroy);
+ this->crl_uris->destroy_function(this->crl_uris,
+ (void*)x509_cdp_destroy);
this->ocsp_uris->destroy_function(this->ocsp_uris, free);
this->ipAddrBlocks->destroy_offset(this->ipAddrBlocks,
offsetof(traffic_selector_t, destroy));
@@ -739,15 +731,15 @@ static bool parse_extKeyUsage_ext(private_openssl_x509_t *this,
/**
* Parse CRL distribution points
*/
-static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
- X509_EXTENSION *ext)
+bool openssl_parse_crlDistributionPoints(X509_EXTENSION *ext,
+ linked_list_t *list)
{
CRL_DIST_POINTS *cdps;
DIST_POINT *cdp;
identification_t *id, *issuer;
x509_cdp_t *entry;
char *uri;
- int i, j, k, point_num, name_num, issuer_num;
+ int i, j, k, point_num, name_num, issuer_num, len;
cdps = X509V3_EXT_d2i(ext);
if (!cdps)
@@ -770,7 +762,12 @@ static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
cdp->distpoint->name.fullname, j));
if (id)
{
- if (asprintf(&uri, "%Y", id) > 0)
+ len = asprintf(&uri, "%Y", id);
+ if (!len)
+ {
+ free(uri);
+ }
+ else if (len > 0)
{
if (cdp->CRLissuer)
{
@@ -785,8 +782,7 @@ static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
.uri = strdup(uri),
.issuer = issuer,
);
- this->crl_uris->insert_last(
- this->crl_uris, entry);
+ list->insert_last(list, entry);
}
}
free(uri);
@@ -796,7 +792,7 @@ static bool parse_crlDistributionPoints_ext(private_openssl_x509_t *this,
INIT(entry,
.uri = uri,
);
- this->crl_uris->insert_last(this->crl_uris, entry);
+ list->insert_last(list, entry);
}
}
id->destroy(id);
@@ -820,7 +816,7 @@ static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
AUTHORITY_INFO_ACCESS *infos;
ACCESS_DESCRIPTION *desc;
identification_t *id;
- int i, num;
+ int i, num, len;
char *uri;
infos = X509V3_EXT_d2i(ext);
@@ -839,7 +835,12 @@ static bool parse_authorityInfoAccess_ext(private_openssl_x509_t *this,
id = general_name2id(desc->location);
if (id)
{
- if (asprintf(&uri, "%Y", id) > 0)
+ len = asprintf(&uri, "%Y", id);
+ if (!len)
+ {
+ free(uri);
+ }
+ else if (len > 0)
{
this->ocsp_uris->insert_last(this->ocsp_uris, uri);
}
@@ -1025,7 +1026,7 @@ static bool parse_extensions(private_openssl_x509_t *this)
ok = parse_extKeyUsage_ext(this, ext);
break;
case NID_crl_distribution_points:
- ok = parse_crlDistributionPoints_ext(this, ext);
+ ok = openssl_parse_crlDistributionPoints(ext, this->crl_uris);
break;
#ifndef OPENSSL_NO_RFC3779
case NID_sbgp_ipAddrBlock:
@@ -1063,8 +1064,8 @@ static bool parse_certificate(private_openssl_x509_t *this)
{
const unsigned char *ptr = this->encoding.ptr;
hasher_t *hasher;
- chunk_t chunk;
- ASN1_OBJECT *oid, *oid_tbs;
+ chunk_t chunk, sig_scheme, sig_scheme_tbs;
+ ASN1_OBJECT *oid;
X509_ALGOR *alg;
this->x509 = d2i_X509(NULL, &ptr, this->encoding.len);
@@ -1089,6 +1090,10 @@ static bool parse_certificate(private_openssl_x509_t *this)
}
switch (openssl_asn1_known_oid(oid))
{
+ case OID_RSASSA_PSS:
+ /* TODO: we should treat such keys special and use the params as
+ * restrictions regarding the use of this key (or rather the
+ * associated private key) */
case OID_RSA_ENCRYPTION:
this->pubkey = lib->creds->create(lib->creds,
CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_ASN1_DER,
@@ -1119,15 +1124,25 @@ static bool parse_certificate(private_openssl_x509_t *this)
/* while X509_ALGOR_cmp() is declared in the headers of older OpenSSL
* versions, at least on Ubuntu 14.04 it is not actually defined */
X509_get0_signature(NULL, &alg, this->x509);
- X509_ALGOR_get0(&oid, NULL, NULL, alg);
+ sig_scheme = openssl_i2chunk(X509_ALGOR, alg);
alg = X509_get0_tbs_sigalg(this->x509);
- X509_ALGOR_get0(&oid_tbs, NULL, NULL, alg);
- if (!chunk_equals(openssl_asn1_obj2chunk(oid),
- openssl_asn1_obj2chunk(oid_tbs)))
+ sig_scheme_tbs = openssl_i2chunk(X509_ALGOR, alg);
+ if (!chunk_equals(sig_scheme, sig_scheme_tbs))
+ {
+ free(sig_scheme_tbs.ptr);
+ free(sig_scheme.ptr);
+ return FALSE;
+ }
+ free(sig_scheme_tbs.ptr);
+
+ INIT(this->scheme);
+ if (!signature_params_parse(sig_scheme, 0, this->scheme))
{
+ DBG1(DBG_ASN, "unable to parse signature algorithm");
+ free(sig_scheme.ptr);
return FALSE;
}
- this->scheme = signature_scheme_from_oid(openssl_asn1_known_oid(oid));
+ free(sig_scheme.ptr);
if (!parse_extensions(this))
{