summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.eap-tls3
-rw-r--r--pppd/auth.c15
-rw-r--r--pppd/eap-tls.c165
-rw-r--r--pppd/eap-tls.h4
-rw-r--r--pppd/pppd.h1
5 files changed, 139 insertions, 49 deletions
diff --git a/README.eap-tls b/README.eap-tls
index 7895b2b..ad81ab2 100644
--- a/README.eap-tls
+++ b/README.eap-tls
@@ -134,6 +134,9 @@ EAP-TLS authentication support for PPP
key <key-file>
Use the client private key found in <key-file> in PEM format
or in engine:engine_id format
+ pkcs12 <pkcs12-file>
+ Use a pkcs12 envelope as a substitute for cert and key. A password may be
+ required to use this file.
crl <crl-file>
Use the Certificate Revocation List (CRL) file <crl-file> in PEM format.
crl-dir <dir>
diff --git a/pppd/auth.c b/pppd/auth.c
index 6ccdbf8..0a49f53 100644
--- a/pppd/auth.c
+++ b/pppd/auth.c
@@ -255,6 +255,7 @@ char *cacert_file = NULL; /* CA certificate file (pem format) */
char *ca_path = NULL; /* directory with CA certificates */
char *cert_file = NULL; /* client certificate file (pem format) */
char *privkey_file = NULL; /* client private key file (pem format) */
+char *pkcs12_file = NULL; /* client private key envelope file (pkcs12 format) */
char *crl_dir = NULL; /* directory containing CRL files */
char *crl_file = NULL; /* Certificate Revocation List (CRL) file (pem format) */
char *max_tls_version = NULL; /* Maximum TLS protocol version (default=1.2) */
@@ -445,6 +446,7 @@ option_t auth_options[] = {
{ "key", o_string, &privkey_file, "EAP-TLS client private key in PEM format" },
{ "crl-dir", o_string, &crl_dir, "Use CRLs in directory" },
{ "crl", o_string, &crl_file, "Use specific CRL file" },
+ { "pkcs12", o_string, &pkcs12_file, "EAP-TLS client credentials in PKCS12 format" },
{ "max-tls-version", o_string, &max_tls_version,
"Maximum TLS version (1.0/1.1/1.2 (default)/1.3)" },
{ "tls-verify-key-usage", o_bool, &tls_verify_key_usage,
@@ -2464,6 +2466,8 @@ have_eaptls_secret_client(char *client, char *server)
if ((cacert_file || ca_path) && cert_file && privkey_file)
return 1;
+ if (pkcs12_file)
+ return 1;
filename = _PATH_EAPTLSCLIFILE;
f = fopen(filename, "r");
@@ -2647,7 +2651,7 @@ scan_authfile_eaptls(FILE *f, char *client, char *server,
int
get_eaptls_secret(int unit, char *client, char *server,
char *clicertfile, char *servcertfile, char *cacertfile,
- char *capath, char *pkfile, int am_server)
+ char *capath, char *pkfile, char *pkcs12, int am_server)
{
FILE *fp;
int ret;
@@ -2661,6 +2665,7 @@ get_eaptls_secret(int unit, char *client, char *server,
bzero(cacertfile, MAXWORDLEN);
bzero(capath, MAXWORDLEN);
bzero(pkfile, MAXWORDLEN);
+ bzero(pkcs12, MAXWORDLEN);
/* the ca+cert+privkey can also be specified as options */
if (!am_server && (cacert_file || ca_path) && cert_file && privkey_file )
@@ -2672,6 +2677,14 @@ get_eaptls_secret(int unit, char *client, char *server,
strlcpy( capath, ca_path, MAXWORDLEN );
strlcpy( pkfile, privkey_file, MAXWORDLEN );
}
+ else if (!am_server && pkcs12_file)
+ {
+ strlcpy( pkcs12, pkcs12_file, MAXWORDLEN );
+ if (cacert_file)
+ strlcpy( cacertfile, cacert_file, MAXWORDLEN );
+ if (ca_path)
+ strlcpy( capath, ca_path, MAXWORDLEN );
+ }
else
{
filename = (am_server ? _PATH_EAPTLSSERVFILE : _PATH_EAPTLSCLIFILE);
diff --git a/pppd/eap-tls.c b/pppd/eap-tls.c
index bfcf199..c9730ba 100644
--- a/pppd/eap-tls.c
+++ b/pppd/eap-tls.c
@@ -42,6 +42,7 @@
#include <openssl/err.h>
#include <openssl/ui.h>
#include <openssl/x509v3.h>
+#include <openssl/pkcs12.h>
#include "pppd.h"
#include "eap.h"
@@ -283,7 +284,7 @@ ENGINE *eaptls_ssl_load_engine( char *engine_name )
* for client or server use can be loaded.
*/
SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
- char *certfile, char *peer_certfile, char *privkeyfile)
+ char *certfile, char *peer_certfile, char *privkeyfile, char *pkcs12)
{
#ifndef OPENSSL_NO_ENGINE
char *cert_engine_name = NULL;
@@ -296,7 +297,13 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
X509_STORE *certstore;
X509_LOOKUP *lookup;
X509 *tmp;
+ X509 *cert = NULL;
+ PKCS12 *p12 = NULL;
+ EVP_PKEY *pkey = NULL;
+ STACK_OF(X509) *chain = NULL;
+ BIO *input;
int ret;
+ int reason;
#if defined(TLS1_2_VERSION)
long tls_version = TLS1_2_VERSION;
#elif defined(TLS1_1_VERSION)
@@ -308,22 +315,25 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
/*
* Without these can't continue
*/
- if (!(cacertfile[0] || capath[0]))
+ if (!pkcs12[0])
{
- error("EAP-TLS: CA certificate file or path missing");
- return NULL;
- }
+ if (!(cacertfile[0] || capath[0]))
+ {
+ error("EAP-TLS: CA certificate file or path missing");
+ return NULL;
+ }
- if (!certfile[0])
- {
- error("EAP-TLS: Certificate missing");
- return NULL;
- }
+ if (!certfile[0])
+ {
+ error("EAP-TLS: Certificate missing");
+ return NULL;
+ }
- if (!privkeyfile[0])
- {
- error("EAP-TLS: Private key missing");
- return NULL;
+ if (!privkeyfile[0])
+ {
+ error("EAP-TLS: Private key missing");
+ return NULL;
+ }
}
SSL_library_init();
@@ -458,13 +468,9 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
if (cert_info.cert)
{
- dbglog( "Got the certificate, adding it to SSL context" );
+ dbglog( "Got the certificate" );
dbglog( "subject = %s", X509_NAME_oneline( X509_get_subject_name( cert_info.cert ), NULL, 0 ) );
- if (SSL_CTX_use_certificate(ctx, cert_info.cert) <= 0)
- {
- error("EAP-TLS: Cannot use PKCS11 certificate %s", cert_identifier);
- goto fail;
- }
+ cert = cert_info.cert;
}
else
{
@@ -475,13 +481,63 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
else
#endif
{
- if (!SSL_CTX_use_certificate_chain_file(ctx, certfile))
+ if (pkcs12[0])
{
- error( "EAP-TLS: Cannot use public certificate %s", certfile );
- goto fail;
+ input = BIO_new_file(pkcs12, "r");
+ if (input == NULL)
+ {
+ error("EAP-TLS: Cannot open `%s' PKCS12 for input", pkcs12);
+ goto fail;
+ }
+
+ p12 = d2i_PKCS12_bio(input, NULL);
+ BIO_free(input);
+ if (!p12)
+ {
+ error("EAP-TLS: Cannot load PKCS12 certificate");
+ goto fail;
+ }
+
+ if (PKCS12_parse(p12, passwd, &pkey, &cert, &chain) != 1)
+ {
+ error("EAP-TLS: Cannot parse PKCS12 certificate, invalid password");
+ PKCS12_free(p12);
+ goto fail;
+ }
+
+ PKCS12_free(p12);
+ }
+ else
+ {
+ if (!SSL_CTX_use_certificate_chain_file(ctx, certfile))
+ {
+ error( "EAP-TLS: Cannot load certificate %s", certfile );
+ goto fail;
+ }
}
}
+ if (cert)
+ {
+ if (!SSL_CTX_use_certificate(ctx, cert))
+ {
+ error("EAP-TLS: Cannot use load certificate");
+ goto fail;
+ }
+
+ if (chain)
+ {
+ int i;
+ for (i = 0; i < sk_X509_num(chain); i++)
+ {
+ if (!SSL_CTX_add_extra_chain_cert(ctx, sk_X509_value(chain, i)))
+ {
+ error("EAP-TLS: Cannot add extra chain certificate");
+ goto fail;
+ }
+ }
+ }
+ }
/*
* Check the Before and After dates of the certificate
@@ -513,7 +569,6 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
#ifndef OPENSSL_NO_ENGINE
if (pkey_engine)
{
- EVP_PKEY *pkey = NULL;
PW_CB_DATA cb_data;
cb_data.password = passwd;
@@ -547,33 +602,38 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
dbglog( "Loading private key '%s' from engine", pkey_identifier );
pkey = ENGINE_load_private_key(pkey_engine, pkey_identifier, NULL, NULL);
}
- if (pkey)
+ }
+ else
+#endif
+ {
+ if (!pkey)
{
- dbglog( "Got the private key, adding it to SSL context" );
- if (SSL_CTX_use_PrivateKey(ctx, pkey) <= 0)
+ input = BIO_new_file(privkeyfile, "r");
+ if (!input)
{
- error("EAP-TLS: Cannot use PKCS11 key %s", pkey_identifier);
+ error("EAP-TLS: Could not open private key, %s", privkeyfile);
+ goto fail;
+ }
+
+ pkey = PEM_read_bio_PrivateKey(input, NULL, password_callback, NULL);
+ BIO_free(input);
+ if (!pkey)
+ {
+ error("EAP-TLS: Cannot load private key, %s", privkeyfile);
goto fail;
}
- }
- else
- {
- warn("EAP-TLS: Cannot load PKCS11 key %s", pkey_identifier);
- log_ssl_errors();
}
}
- else
-#endif
+
+ if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1)
{
- if (!SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, SSL_FILETYPE_PEM))
- {
- error("EAP-TLS: Cannot use private key %s", privkeyfile);
- goto fail;
- }
+ error("EAP-TLS: Cannot use private key");
+ goto fail;
}
- if (SSL_CTX_check_private_key(ctx) != 1) {
- error("EAP-TLS: Private key %s fails security check", privkeyfile);
+ if (SSL_CTX_check_private_key(ctx) != 1)
+ {
+ error("EAP-TLS: Private key fails security check");
goto fail;
}
@@ -696,6 +756,16 @@ SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
return ctx;
fail:
+
+ if (cert)
+ X509_free(cert);
+
+ if (pkey)
+ EVP_PKEY_free(pkey);
+
+ if (chain)
+ sk_X509_pop_free(chain, X509_free);
+
log_ssl_errors();
SSL_CTX_free(ctx);
return NULL;
@@ -734,6 +804,8 @@ int eaptls_init_ssl_server(eap_state * esp)
char cacertfile[MAXWORDLEN];
char capath[MAXWORDLEN];
char pkfile[MAXWORDLEN];
+ char pkcs12[MAXWORDLEN];
+
/*
* Allocate new eaptls session
*/
@@ -753,7 +825,7 @@ int eaptls_init_ssl_server(eap_state * esp)
dbglog( "getting eaptls secret" );
if (!get_eaptls_secret(esp->es_unit, esp->es_server.ea_peer,
esp->es_server.ea_name, clicertfile,
- servcertfile, cacertfile, capath, pkfile, 1)) {
+ servcertfile, cacertfile, capath, pkfile, pkcs12, 1)) {
error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
esp->es_server.ea_peer, esp->es_server.ea_name );
return 0;
@@ -761,7 +833,7 @@ int eaptls_init_ssl_server(eap_state * esp)
ets->mtu = eaptls_get_mtu(esp->es_unit);
- ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile);
+ ets->ctx = eaptls_init_ssl(1, cacertfile, capath, servcertfile, clicertfile, pkfile, pkcs12);
if (!ets->ctx)
goto fail;
@@ -825,6 +897,7 @@ int eaptls_init_ssl_client(eap_state * esp)
char cacertfile[MAXWORDLEN];
char capath[MAXWORDLEN];
char pkfile[MAXWORDLEN];
+ char pkcs12[MAXWORDLEN];
/*
* Allocate new eaptls session
@@ -849,14 +922,14 @@ int eaptls_init_ssl_client(eap_state * esp)
dbglog( "calling get_eaptls_secret" );
if (!get_eaptls_secret(esp->es_unit, esp->es_client.ea_name,
ets->peer, clicertfile,
- servcertfile, cacertfile, capath, pkfile, 0)) {
+ servcertfile, cacertfile, capath, pkfile, pkcs12, 0)) {
error( "EAP-TLS: Cannot get secret/password for client \"%s\", server \"%s\"",
esp->es_client.ea_name, ets->peer );
return 0;
}
dbglog( "calling eaptls_init_ssl" );
- ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, servcertfile, pkfile);
+ ets->ctx = eaptls_init_ssl(0, cacertfile, capath, clicertfile, servcertfile, pkfile, pkcs12);
if (!ets->ctx)
goto fail;
diff --git a/pppd/eap-tls.h b/pppd/eap-tls.h
index b935ec5..b19a905 100644
--- a/pppd/eap-tls.h
+++ b/pppd/eap-tls.h
@@ -70,7 +70,7 @@ struct eaptls_session
SSL_CTX *eaptls_init_ssl(int init_server, char *cacertfile, char *capath,
- char *certfile, char *peer_certfile, char *privkeyfile);
+ char *certfile, char *peer_certfile, char *privkeyfile, char *pkcs12);
int eaptls_init_ssl_server(eap_state * esp);
int eaptls_init_ssl_client(eap_state * esp);
void eaptls_free_session(struct eaptls_session *ets);
@@ -83,7 +83,7 @@ void eaptls_retransmit(struct eaptls_session *ets, u_char ** outp);
int get_eaptls_secret(int unit, char *client, char *server,
char *clicertfile, char *servcertfile, char *cacertfile,
- char *capath, char *pkfile, int am_server);
+ char *capath, char *pkfile, char *pkcs12, int am_server);
#ifdef MPPE
void eaptls_gen_mppe_keys(struct eaptls_session *ets, int client);
diff --git a/pppd/pppd.h b/pppd/pppd.h
index 05e8e37..6a19091 100644
--- a/pppd/pppd.h
+++ b/pppd/pppd.h
@@ -344,6 +344,7 @@ extern int child_wait; /* # seconds to wait for children at end */
extern char *crl_dir;
extern char *crl_file;
+extern char *pkcs12_file;
extern char *max_tls_version;
extern bool tls_verify_key_usage;
extern char *tls_verify_method;