[vpn-help] Unable to verify remote peer certificate

Tai-hwa Liang avatar at mmlab.cse.yzu.edu.tw
Tue Apr 20 06:38:00 CDT 2010


On Mon, 19 Apr 2010, Matthew Grooms wrote:
> On 3/31/2010 7:44 AM, Michael wrote:
>>
>> Hello list,
>>
>> I'm using the shrew ike daemon (packaged with the Qt client) version
>> 2.1.4 on Ubuntu Linux 9.10. The goal is a roadwarrior installation
>> with X.509 certificate authentication.
>>
>> When using preshared keys this same configuration works. Mobile
>> clients using other software (IPSecuritas) with the same
>> certificates I'm loading in Shrew work as well so...
>>
>> The problem is that I see 'Gateway authentication error' in the
>> GUI window after trying to connect. The log /var/log/iked.log:
>>
>>    ii : unable to get local issuer certificate(20) at depth:0
>>    ii : subject :/CN=name.host.tld
>>    !! : unable to verify remote peer certificate
>>
>> The host 'name.host.tld' is in the SubjectAltName of the X.509
>> certificate loaded on the ike v1 server m0n0wall 1.31. I have
>> concatanated the root and intermediate CA certificates of CaCert.org
>> to the file 'cacert-combi.pem':
>>
>> s:ident-server-type:asn1dn
>> s:auth-server-cert:/home/username/.ike/certs/cacert-combi.pem
>> s:auth-client-cert:/home/username/.ike/certs/myclienthost-cacert-rsa-4096-crt.pem
>> s:auth-client-key:/home/username/.ike/keys/myclienthost-cacert-rsa-4096-key.pem
>>
>> What can be the problem?
>>
>
> I don't believe concatenating the certificate files together will have
> any effect. A lot of work was done between 2.1.4 and 2.1.6 to handle a
> multi-certificate chain to be interpreted correctly when received from
> the peer during phase1 negotiations. And on the windows platform, we
> have a special directory where a user can drop additional certificates
> that are used as intermediates during certificate verification. But on
> Linux/BSD, there is no analog to this.

   Did you try the attached patch I've sent you a few years ago?  I believe
it supports chained/concatnated certificate inside a single .pem file.
Even better, it also supports .p12 file that includes user's key pair and
complete CA certificate chain.

   Given that this patch only utilises standard OpenSSL APIs, it should be
portable amongst WIN32 and UN*X Shrew VPN implementations.

> I think we need to allow a certificate directory to be passed instead of
> a single certificate file. This will allow a client to configure a group
> of certificate files that can be used for chained authentication.
> Unfortunately, I don't have time to do this at the moment. This should
> be completed before 2.2.0 release. Sorry I can't be more help at this time.

   IMHO, the problem in directory based certificate storage is that there're
multiple directories which can be confusing to users.  I've run into this in 
2.1.0(not sure if it is fixed in recent release) since I put the chained 
.pem into 'My Document/Shrew .../certificate' rather than 'Program Files/Shrew 
VPN/certificate.'  The former path didn't seem to be in ShrewVPN's default 
ceritificate search path and thus caused failure in subsequent server 
certificate verification process.
-------------- next part --------------
diff -rup ike.orig/source/iked/iked.h ike/source/iked/iked.h
--- ike.orig/source/iked/iked.h	2008-06-10 10:13:52.000000000 +0800
+++ ike/source/iked/iked.h	2008-08-06 17:59:08.000000000 +0800
@@ -547,12 +551,17 @@ typedef class _IKED

 	// x.509 certificate helper functions

 

 	bool	cert_2_bdata( BDATA & cert, X509 * x509 );

+	bool	certs_2_bdata( BDATA & certs, STACK_OF(X509) * x509_chain );

 	bool	bdata_2_cert( X509 ** x509, BDATA & cert );

+	bool	bdata_2_certs( STACK_OF(X509) ** x509_chain, BDATA & cert );

 

 	long	cert_save( BDATA & cert, char * fpath );

 	long	cert_load( BDATA & cert, char * fpath, bool ca, BDATA & pass );

 	bool	cert_load_pem( BDATA & cert, FILE * fp, bool ca, BDATA & pass );

 	bool	cert_load_p12( BDATA & cert, FILE * fp, bool ca, BDATA & pass );

+	long	certs_load( BDATA & certs, char * fpath, bool ca, BDATA & pass );

+	bool	certs_load_pem( BDATA & certs, FILE * fp, bool ca, BDATA & pass );

+	bool	certs_load_p12( BDATA & certs, FILE * fp, bool ca, BDATA & pass );

 	bool	cert_desc( BDATA & cert, BDATA & text );

 	bool	cert_subj( BDATA & cert, BDATA & subj );

 	bool	asn1_text( BDATA & asn1, BDATA & text );

diff -rup ike.orig/source/iked/ike.io.admin.cpp ike/source/iked/ike.io.admin.cpp
--- ike.orig/source/iked/ike.io.admin.cpp	2008-05-19 05:35:53.000000000 +0800
+++ ike/source/iked/ike.io.admin.cpp	2008-08-06 18:20:58.000000000 +0800
@@ -406,7 +406,7 @@ long _IKED::loop_ipc_client( IKEI * ikei
 

 							log.txt( LLOG_INFO, "<A : remote cert \'%s\' message\n", text.text() );

 

-							long loaded = cert_load( tunnel->peer->cert_r, text.text(), true, tunnel->peer->fpass );

+							long loaded = certs_load( tunnel->peer->cert_r, text.text(), true, tunnel->peer->fpass );

 

 							switch( loaded )

 							{

diff -rup ike.orig/source/iked/ike.keyfile.cpp ike/source/iked/ike.keyfile.cpp
--- ike.orig/source/iked/ike.keyfile.cpp	2008-02-20 15:10:05.000000000 +0800
+++ ike/source/iked/ike.keyfile.cpp	2008-08-06 18:44:32.000000000 +0800
@@ -79,6 +79,21 @@ bool _IKED::cert_2_bdata( BDATA & cert, 
 	return true;

 }

 

+bool _IKED::certs_2_bdata( BDATA & certs, STACK_OF(X509) * x509_chain )

+{

+	int size = i2d_ASN1_SET_OF_X509(x509_chain, NULL, i2d_X509,

+	    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, IS_SEQUENCE);

+

+	certs.size( size );

+

+	unsigned char * cert_buff = certs.buff();

+	if( i2d_ASN1_SET_OF_X509(x509_chain, &cert_buff, i2d_X509,

+	    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, IS_SEQUENCE) < size )

+		return false;

+

+	return true;

+}

+

 bool _IKED::bdata_2_cert( X509 ** x509, BDATA & cert )

 {

 	X509CONST unsigned char * cert_buff = cert.buff();

@@ -90,6 +105,123 @@ bool _IKED::bdata_2_cert( X509 ** x509, 
 	return true;

 }

 

+bool _IKED::bdata_2_certs( STACK_OF(X509) ** x509_chain, BDATA & certs )

+{

+	X509CONST unsigned char * cert_buff = certs.buff();

+

+	*x509_chain = d2i_ASN1_SET_OF_X509( NULL, &cert_buff,

+	    ( long ) certs.size(), d2i_X509, X509_free,

+	    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);

+

+	if( *x509_chain == NULL )

+		return false;

+

+	return true;

+}

+

+long _IKED::certs_load( BDATA & certs, char * fpath, bool ca, BDATA & pass )

+{

+#ifdef WIN32

+

+	FILE * fp;

+	if( fopen_s( &fp, fpath, "rb" ) )

+		return FILE_PATH;

+

+#else

+

+	FILE * fp = fopen( fpath, "rb" );

+	if( !fp )

+		return FILE_PATH;

+

+#endif

+

+	bool loaded = certs_load_pem( certs, fp, ca, pass );

+	if( !loaded )

+		loaded = certs_load_p12( certs, fp, ca, pass );

+

+	fclose( fp );

+

+	if( !loaded )

+		return FILE_FAIL;

+

+	return FILE_OK;

+}

+

+bool _IKED::certs_load_pem( BDATA & certs, FILE * fp, bool ca, BDATA & pass )

+{

+	fseek( fp, 0, SEEK_SET );

+

+	STACK_OF(X509) *cert_chain = sk_X509_new_null();

+	STACK_OF(X509_INFO) *allcerts = NULL;

+

+	allcerts = PEM_X509_INFO_read(fp, NULL, keyfile_cb, &pass);

+	if (allcerts == NULL || sk_X509_INFO_num(allcerts) == 0)

+	{

+		sk_X509_free(cert_chain);

+		return (false);

+	}

+	for (int i = 0; i < sk_X509_INFO_num(allcerts); i++)

+	{

+		X509_INFO *xi = sk_X509_INFO_value (allcerts, i);

+		if (xi->x509)

+		{

+			sk_X509_push(cert_chain, xi->x509);

+			xi->x509 = NULL;

+		}

+	}

+

+	certs_2_bdata( certs, cert_chain );

+

+	sk_X509_INFO_pop_free(allcerts, X509_INFO_free);
+

+	return (true);

+}

+

+bool _IKED::certs_load_p12( BDATA & certs, FILE * fp, bool ca, BDATA & pass )

+{

+	fseek( fp, 0, SEEK_SET );

+

+	PKCS12 * p12 = d2i_PKCS12_fp( fp, NULL );

+	if( p12 == NULL )

+		return false;

+

+	X509 * x509 = NULL;

+

+	BDATA passnull;

+	passnull.set( pass );

+	passnull.add( 0, 1 );

+

+	if( ca )

+	{

+		STACK_OF( X509 ) * stack = NULL;

+

+		if( PKCS12_parse( p12, ( const char * ) passnull.buff(), NULL, NULL, &stack ) )

+		{

+			if ( stack == NULL )

+			{

+				PKCS12_free( p12 );

+				return false;

+			}

+			certs_2_bdata( certs, stack );

+			sk_X509_free( stack );

+			PKCS12_free( p12 );

+			return true;

+		}

+	}

+	else

+		PKCS12_parse( p12, ( const char * ) passnull.buff(), NULL, &x509, NULL );

+

+	PKCS12_free( p12 );

+

+	if( x509 == NULL )

+		return false;

+

+	cert_2_bdata( certs, x509 );

+	X509_free( x509 );

+

+	return true;

+}

+

 long _IKED::cert_load( BDATA & cert, char * fpath, bool ca, BDATA & pass )

 {

 #ifdef WIN32

@@ -566,14 +698,17 @@ bool _IKED::cert_verify( IDB_LIST_CERT &
 	// load ca and add to store

 	//

 

-	X509 * x509_ca;

-	if( !bdata_2_cert( &x509_ca, ca ) )

+	STACK_OF(X509) * x509_ca;

+	if( !bdata_2_certs( &x509_ca, ca ) )

 	{

 		X509_STORE_free( store );

 		return false;

 	}

 

-	X509_STORE_add_cert( store, x509_ca );

+	for (int i = 0; i < sk_X509_num(x509_ca); i++)

+	{

+		X509_STORE_add_cert( store, sk_X509_value(x509_ca, i) );

+	}

 

 #ifdef WIN32

 

@@ -678,7 +837,7 @@ bool _IKED::cert_verify( IDB_LIST_CERT &
 	// cleanup

 	//

 

-	X509_free( x509_ca );

+	sk_X509_free( x509_ca );

 	X509_STORE_free( store );

 

 	return ( result > 0 );



More information about the vpn-help mailing list