Skip to content

Commit

Permalink
Add support for X509Certificate2
Browse files Browse the repository at this point in the history
- Rework several functions to accept private key and password.
- Add new function to parse private keys.
- Add and update stubs accordingly.
- Rework SslNative::InitHelper accordingly.
- Update CMakes as required.
- Update declaration or System.Net assembly.

Signed-off-by: José Simões <[email protected]>
  • Loading branch information
josesimoes committed Jul 18, 2019
1 parent f81b05a commit 63d5835
Show file tree
Hide file tree
Showing 18 changed files with 322 additions and 78 deletions.
1 change: 1 addition & 0 deletions CMake/Modules/FindNF_Networking.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(NF_Networking_Security_SRCS
ssl_add_cert_auth_internal.cpp
ssl_closesocket_internal.cpp
ssl_connect_internal.cpp
ssl_decode_private_key_internal.cpp
ssl_exit_context_internal.cpp
ssl_generic.cpp
ssl_generic_init_internal.cpp
Expand Down
1 change: 1 addition & 0 deletions CMake/Modules/FindSystem.Net.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ set(System.Net_SRCS

# System.Security.Cryptography.X509Certificates
sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate.cpp
sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate2.cpp

# System.Net.Security
sys_net_native_System_Net_Security_SslNative.cpp
Expand Down
19 changes: 16 additions & 3 deletions src/DeviceInterfaces/System.Net/sys_net_native.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,25 @@ static const CLR_RT_MethodHandler method_lookup[] =
NULL,
NULL,
Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::ParseCertificate___STATIC__VOID__SZARRAY_U1__STRING__BYREF_STRING__BYREF_STRING__BYREF_mscorlibSystemDateTime__BYREF_mscorlibSystemDateTime,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate2::DecodePrivateKeyNative___STATIC__VOID__SZARRAY_U1__STRING,
};

const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_System_Net =
{
"System.Net",
0x3AD3B5E6,
method_lookup,
{ 100, 1, 1, 0 }
0x7721D4BC,
method_lookup,
{ 100, 1, 2, 0 }
};
20 changes: 20 additions & 0 deletions src/DeviceInterfaces/System.Net/sys_net_native.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,16 @@ struct Library_sys_net_native_System_Net_Sockets_SocketException

};

struct Library_sys_net_native_System_Security_Cryptography_AsymmetricAlgorithm
{
static const int FIELD___keySizeValue = 1;
static const int FIELD___keyPairValue = 2;


//--//

};

struct Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate
{
static const int FIELD___certificate = 1;
Expand All @@ -273,6 +283,16 @@ struct Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509

};

struct Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate2
{
static const int FIELD___privateKey = 9;

NANOCLR_NATIVE_DECLARE(DecodePrivateKeyNative___STATIC__VOID__SZARRAY_U1__STRING);

//--//

};

extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_System_Net;

#endif //_SYS_NET_NATIVE_H_
Original file line number Diff line number Diff line change
Expand Up @@ -457,16 +457,20 @@ HRESULT Library_sys_net_native_System_Net_Security_SslNative::InitHelper( CLR_RT
NATIVE_PROFILE_CLR_NETWORK();
NANOCLR_HEADER();

CLR_RT_TypeDef_Index x509Certificate2TypeDef;

CLR_INT32 sslContext = -1;
CLR_INT32 sslMode = stack.Arg0().NumericByRef().s4;
CLR_INT32 sslVerify = stack.Arg1().NumericByRef().s4;
CLR_RT_HeapBlock *hbCert = stack.Arg2().Dereference();
CLR_RT_HeapBlock* caCert = stack.Arg3().Dereference();
CLR_RT_HeapBlock_Array* arrCert = NULL;
CLR_RT_HeapBlock_Array* privateKey = NULL;
CLR_UINT8* sslCert = NULL;
int result;
bool isFirstCall = false;
const char * szPwd = "";
const char * password = "";
uint8_t* pk = NULL;

if(!g_SSL_SeedData.Initialized)
{
Expand Down Expand Up @@ -511,45 +515,36 @@ HRESULT Library_sys_net_native_System_Net_Security_SslNative::InitHelper( CLR_RT

if(hbCert != NULL)
{
g_CLR_RT_TypeSystem.FindTypeDef( "X509Certificate2", "System.Security.Cryptography.X509Certificates", x509Certificate2TypeDef );

arrCert = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD___certificate ].DereferenceArray(); //FAULT_ON_NULL(arrCert);
arrCert->Pin();

// If arrCert == NULL then the certificate is an X509Certificate2 which uses a certificate handle
if(arrCert == NULL)
// there is a client certificate, find if it's a X509Certificate2
if(hbCert->ObjectCls().Type() == x509Certificate2TypeDef.Type())
{
arrCert = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD___handle ].DereferenceArray(); FAULT_ON_NULL(arrCert);

// pass the certificate handle as the cert data parameter
sslCert = arrCert->GetFirstElement();

arrCert = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD___sessionHandle ].DereferenceArray(); FAULT_ON_NULL(arrCert);

// pass the session handle as the ssl context parameter
sslContext = *(int32_t*)arrCert->GetFirstElement();

// the certificate has already been loaded so just pass an empty string
szPwd = "";
// get private key
privateKey = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate2::FIELD___privateKey ].DereferenceArray();
pk = privateKey->GetFirstElement();
}
else
{
arrCert->Pin();

sslCert = arrCert->GetFirstElement();

CLR_RT_HeapBlock *hbPwd = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD___password ].Dereference();// FAULT_ON_NULL(hbPwd);
// get certificate
sslCert = arrCert->GetFirstElement();

szPwd = hbPwd->StringText();
}
// get password
CLR_RT_HeapBlock *hbPwd = hbCert[ Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate::FIELD___password ].Dereference();// FAULT_ON_NULL(hbPwd);
password = hbPwd->StringText();
}

SSL_RegisterTimeCallback( Time_GetDateTime );

if(isServer)
{
result = (SSL_ServerInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, szPwd, sslContext ) ? 0 : -1);
result = (SSL_ServerInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, pk, pk == NULL ? 0 : privateKey->m_numOfElements, password, hal_strlen_s(password), sslContext ) ? 0 : -1);
}
else
{
result = (SSL_ClientInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, szPwd, sslContext ) ? 0 : -1);
result = (SSL_ClientInit( sslMode, sslVerify, (const char*)sslCert, sslCert == NULL ? 0 : arrCert->m_numOfElements, pk, pk == NULL ? 0 : privateKey->m_numOfElements, password, hal_strlen_s(password), sslContext ) ? 0 : -1);
}

NANOCLR_CHECK_HRESULT(ThrowOnError( stack, result ));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Copyright (c) 2019 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "sys_net_native.h"

typedef Library_sys_net_native_System_Security_Cryptography_AsymmetricAlgorithm asymmetricAlgorithmType;

HRESULT Library_sys_net_native_System_Security_Cryptography_X509Certificates_X509Certificate2::DecodePrivateKeyNative___STATIC__VOID__SZARRAY_U1__STRING( CLR_RT_StackFrame& stack )
{
NATIVE_PROFILE_CLR_NETWORK();
NANOCLR_HEADER();

CLR_RT_HeapBlock_Array* keyData = stack.Arg0().DereferenceArray();
CLR_UINT8* keyBuffer;
CLR_RT_HeapBlock* passwordHb = stack.Arg1().DereferenceString();
const char* password;

// get key buffer
keyBuffer = keyData->GetFirstElement();

// manage password
FAULT_ON_NULL_ARG(passwordHb);
password = passwordHb->StringText();

if(SSL_DecodePrivateKey(
(const unsigned char*)keyBuffer,
keyData->m_numOfElements,
(const unsigned char*)password,
hal_strlen_s(password)) < 0)
{
NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
}

NANOCLR_NOCLEANUP();
}
2 changes: 1 addition & 1 deletion src/PAL/COM/sockets/Sockets_debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ bool Sockets_LWIP_Driver::UpgradeToSsl( int ComPortNum, const int8_t* pCACert, u
if(g_Sockets_LWIP_Driver.m_usingSSL) return TRUE;

// TLS only and Verify=Required --> only verify the server
if(SSL_ClientInit( 0x10, 0x04, (const char*)pDeviceCert, deviceCertLen, NULL, g_DebuggerPort_SslCtx_Handle ))
if(SSL_ClientInit( 0x10, 0x04, (const char*)pDeviceCert, deviceCertLen, NULL, 0 , NULL, 0, g_DebuggerPort_SslCtx_Handle ))
{
int32_t ret;

Expand Down
1 change: 1 addition & 0 deletions src/PAL/COM/sockets/ssl/mbedTLS/mbedtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ typedef struct mbedTLS_NFContext
mbedtls_ssl_context* ssl;
mbedtls_net_context* server_fd;
mbedtls_x509_crt* x509_crt;
mbedtls_pk_context* pk;
}mbedTLS_NFContext;

int net_would_block( const mbedtls_net_context *ctx );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Copyright (c) 2018 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
// See LICENSE file in the project root for full license information.
//

#include "mbedtls.h"

extern void SSL_GetCertDateTime_internal(DATE_TIME_INFO * dt, mbedtls_x509_time * mt );

int ssl_decode_private_key_internal(
const unsigned char *key,
size_t keyLength,
const unsigned char *password,
size_t passwordLength)
{
mbedtls_pk_context pkey;

int retCode;

mbedtls_pk_init( &pkey );

/////////////////////////////////////////////////////////////////////////////////////////////////
// developer notes: //
// this call parses certificates in both string and binary formats //
// when the formart is a string it has to include the terminator otherwise the parse will fail //
/////////////////////////////////////////////////////////////////////////////////////////////////
retCode = mbedtls_pk_parse_key(
&pkey,
key,
keyLength,
password,
passwordLength);


// need to free this here
mbedtls_pk_free( &pkey );

return retCode;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ bool ssl_exit_context_internal(int sslContextHandle )
{
return FALSE;
}


mbedtls_pk_free(context->pk);
mbedtls_net_free(context->server_fd);
mbedtls_ctr_drbg_free( context->ctr_drbg );
mbedtls_entropy_free( context->entropy );
Expand All @@ -33,6 +34,7 @@ bool ssl_exit_context_internal(int sslContextHandle )
memset(context->ssl, 0, sizeof(mbedtls_ssl_context));

// free memory
platform_free(context->pk);
platform_free(context->server_fd);
platform_free(context->entropy);
platform_free(context->ctr_drbg);
Expand Down
91 changes: 62 additions & 29 deletions src/PAL/COM/sockets/ssl/mbedTLS/ssl_generic_init_internal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,26 @@
#include "mbedtls.h"
#include "mbedtls/debug.h"

bool ssl_generic_init_internal( int sslMode, int sslVerify, const char* certificate,
int certLength, const char* certPassword, int& sslContextHandle, bool isServer )
bool ssl_generic_init_internal(
int sslMode,
int sslVerify,
const char* certificate,
int certLength,
const uint8_t* privateKey,
int privateKeyLength,
const char* password,
int passwordLength,
int& sslContextHandle,
bool isServer )
{
(void)sslMode;
(void)certPassword;

int sslContexIndex = -1;
int authMode = MBEDTLS_SSL_VERIFY_NONE;
int endpoint = 0;

mbedtls_x509_crt* ownCertificate = NULL;

// we only have one CA root bundle, so this is fixed to 0
uint32_t configIndex = 0;

Expand Down Expand Up @@ -180,32 +190,53 @@ bool ssl_generic_init_internal( int sslMode, int sslVerify, const char* certific
// parse "own" certificate if passed
if(certificate != NULL && certLength > 0)
{
// TODO
// this isn't required for client authentication

// mbedtls_x509_crt_init( &clicert );

// /////////////////////////////////////////////////////////////////////////////////////////////////
// // developer notes: //
// // this call parses certificates in both string and binary formats //
// // when the formart is a string it has to include the terminator otherwise the parse will fail //
// /////////////////////////////////////////////////////////////////////////////////////////////////
// if(mbedtls_x509_crt_parse( &clicert, (const unsigned char*)certificate, certLength ) != 0)
// {
// // x509_crt_parse_failed
// goto error;
// }

// if( mbedtls_pk_parse_key( &pkey, (const unsigned char *) mbedtls_test_cli_key, mbedtls_test_cli_key_len, NULL, 0 ) != 0)
// {
// // failed parsing the
// }

// if( mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) != 0 )
// {
// // configuring own certificate failed
// goto error;
// }
// create and init private key context
// this needs to be freed in ssl_exit_context_internal
context->pk = (mbedtls_pk_context*)platform_malloc(sizeof(mbedtls_pk_context));
if(context->pk == NULL)
{
goto error;
}

mbedtls_pk_init( context->pk );

// is there a private key?
if(privateKey != NULL && privateKeyLength > 0)
{

if( mbedtls_pk_parse_key(
context->pk,
privateKey,
privateKeyLength,
(const unsigned char *)password,
passwordLength) < 0)
{
// private key parse failed
goto error;
}
}

// parse certificate
ownCertificate = (mbedtls_x509_crt*)platform_malloc(sizeof(mbedtls_x509_crt));
if(ownCertificate == NULL)
{
goto error;
}

mbedtls_x509_crt_init( ownCertificate );

if( mbedtls_x509_crt_parse( ownCertificate, (const unsigned char *) certificate, certLength ) )
{
// failed parsing own certificate failed
goto error;
}

if( mbedtls_ssl_conf_own_cert( context->conf, ownCertificate, context->pk ) )
{
// configuring own certificate failed
goto error;
}

}

mbedtls_ssl_conf_ca_chain( context->conf, context->x509_crt, NULL );
Expand Down Expand Up @@ -249,6 +280,8 @@ bool ssl_generic_init_internal( int sslMode, int sslVerify, const char* certific
if(context->ctr_drbg != NULL) platform_free(context->ctr_drbg);
if(context->server_fd != NULL) platform_free(context->server_fd);
if(context->x509_crt != NULL) platform_free(context->x509_crt);
if(context->pk != NULL) platform_free(context->pk);
if(ownCertificate != NULL) mbedtls_x509_crt_free( ownCertificate );

return FALSE;
}
Loading

0 comments on commit 63d5835

Please sign in to comment.