libfreerdp-core: add external certificate management, pass X509 PEM certificate through client callback

This commit is contained in:
Marc-André Moreau 2013-11-18 13:54:33 -05:00
parent fa64ca758d
commit b0369cf284
5 changed files with 70 additions and 4 deletions

View File

@ -61,6 +61,7 @@ typedef void (*pPostDisconnect)(freerdp* instance);
typedef BOOL (*pAuthenticate)(freerdp* instance, char** username, char** password, char** domain);
typedef BOOL (*pVerifyCertificate)(freerdp* instance, char* subject, char* issuer, char* fingerprint);
typedef BOOL (*pVerifyChangedCertificate)(freerdp* instance, char* subject, char* issuer, char* new_fingerprint, char* old_fingerprint);
typedef int (*pVerifyX509Certificate)(freerdp* instance, BYTE* data, int length, DWORD flags);
typedef int (*pLogonErrorInfo)(freerdp* instance, UINT32 data, UINT32 type);
@ -195,13 +196,15 @@ struct rdp_freerdp
Used when a certificate differs from stored fingerprint.
If returns TRUE, the new fingerprint will be trusted and old thrown out. */
ALIGN64 pLogonErrorInfo LogonErrorInfo; /**< (offset 53) Callback for logon error info, important for logon system messages with RemoteApp */
ALIGN64 pVerifyX509Certificate VerifyX509Certificate; /**< (offset 53) Callback for X509 certificate verification (PEM format) */
ALIGN64 pPostDisconnect PostDisconnect; /**< (offset 54)
ALIGN64 pLogonErrorInfo LogonErrorInfo; /**< (offset 54) Callback for logon error info, important for logon system messages with RemoteApp */
ALIGN64 pPostDisconnect PostDisconnect; /**< (offset 55)
Callback for cleaning up resources allocated
by connect callbacks. */
UINT64 paddingD[64 - 55]; /* 55 */
UINT64 paddingD[64 - 56]; /* 56 */
ALIGN64 pSendChannelData SendChannelData; /* (offset 64)
Callback for sending data to a channel.

View File

@ -594,6 +594,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_RdpKeyFile 1412
#define FreeRDP_RdpServerRsaKey 1413
#define FreeRDP_RdpServerCertificate 1414
#define FreeRDP_ExternalCertificateManagement 1415
#define FreeRDP_Workarea 1536
#define FreeRDP_Fullscreen 1537
#define FreeRDP_PercentScreen 1538
@ -960,7 +961,8 @@ struct rdp_settings
ALIGN64 char* RdpKeyFile; /* 1412 */
ALIGN64 rdpRsaKey* RdpServerRsaKey; /* 1413 */
ALIGN64 rdpCertificate* RdpServerCertificate; /* 1414 */
UINT64 padding1472[1472 - 1350]; /* 1415 */
ALIGN64 BOOL ExternalCertificateManagement; /* 1415 */
UINT64 padding1472[1472 - 1416]; /* 1416 */
UINT64 padding1536[1536 - 1472]; /* 1472 */
/**

View File

@ -665,6 +665,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
return settings->IgnoreCertificate;
break;
case FreeRDP_ExternalCertificateManagement:
return settings->ExternalCertificateManagement;
break;
case FreeRDP_Workarea:
return settings->Workarea;
break;
@ -1129,6 +1133,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->IgnoreCertificate = param;
break;
case FreeRDP_ExternalCertificateManagement:
settings->ExternalCertificateManagement = param;
break;
case FreeRDP_Workarea:
settings->Workarea = param;
break;

View File

@ -620,6 +620,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->MstscCookieMode = settings->MstscCookieMode; /* 1152 */
_settings->SendPreconnectionPdu = settings->SendPreconnectionPdu; /* 1156 */
_settings->IgnoreCertificate = settings->IgnoreCertificate; /* 1408 */
_settings->ExternalCertificateManagement = settings->ExternalCertificateManagement; /* 1415 */
_settings->Workarea = settings->Workarea; /* 1536 */
_settings->Fullscreen = settings->Fullscreen; /* 1537 */
_settings->GrabKeyboard = settings->GrabKeyboard; /* 1539 */

View File

@ -582,6 +582,58 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname)
BOOL verification_status = FALSE;
rdpCertificateData* certificate_data;
if (tls->settings->ExternalCertificateManagement)
{
BIO* bio;
int status;
int length;
int offset;
BYTE* pemCert;
freerdp* instance = (freerdp*) tls->settings->instance;
/**
* Don't manage certificates internally, leave it up entirely to the external client implementation
*/
bio = BIO_new(BIO_s_mem());
status = PEM_write_bio_X509(bio, cert->px509);
offset = 0;
length = 2048;
pemCert = (BYTE*) malloc(length + 1);
status = BIO_read(bio, pemCert, length);
offset += status;
while (offset >= length)
{
length *= 2;
pemCert = (BYTE*) realloc(pemCert, length + 1);
status = BIO_read(bio, &pemCert[offset], length);
if (status < 0)
break;
offset += status;
}
length = offset;
pemCert[length] = '\0';
status = -1;
if (instance->VerifyX509Certificate)
{
status = instance->VerifyX509Certificate(instance, pemCert, length, 0);
}
free(pemCert);
return (status < 0) ? FALSE : TRUE;
}
/* ignore certificate verification if user explicitly required it (discouraged) */
if (tls->settings->IgnoreCertificate)
return TRUE; /* success! */