dd3276d664
If VerifyX509Certificate is set use it also when doing internal certificate management. Added flags to ensure it is possible to find out which type of connection is being made.
754 lines
18 KiB
C
754 lines
18 KiB
C
/**
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
* Certificate Handling
|
|
*
|
|
* Copyright 2011 Jiten Pathy
|
|
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include <winpr/crypto.h>
|
|
#include <winpr/crt.h>
|
|
#include <winpr/file.h>
|
|
#include <winpr/path.h>
|
|
|
|
#include <openssl/pem.h>
|
|
#include <openssl/rsa.h>
|
|
|
|
static const char certificate_store_dir[] = "certs";
|
|
static const char certificate_server_dir[] = "server";
|
|
static const char certificate_known_hosts_file[] = "known_hosts2";
|
|
static const char certificate_legacy_hosts_file[] = "known_hosts";
|
|
|
|
#include <freerdp/log.h>
|
|
#include <freerdp/crypto/certificate.h>
|
|
|
|
#define TAG FREERDP_TAG("crypto")
|
|
|
|
static BOOL certificate_split_line(char* line, char** host, UINT16* port,
|
|
char** subject, char** issuer,
|
|
char** fingerprint);
|
|
static BOOL certificate_line_is_comment(const char* line, size_t length)
|
|
{
|
|
while (length > 0)
|
|
{
|
|
switch (*line)
|
|
{
|
|
case ' ':
|
|
case '\t':
|
|
line++;
|
|
length--;
|
|
break;
|
|
|
|
case '#':
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (length < 1)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL certificate_store_init(rdpCertificateStore* certificate_store)
|
|
{
|
|
char* server_path = NULL;
|
|
rdpSettings* settings;
|
|
settings = certificate_store->settings;
|
|
|
|
if (!PathFileExistsA(settings->ConfigPath))
|
|
{
|
|
if (!PathMakePathA(settings->ConfigPath, 0))
|
|
{
|
|
WLog_ERR(TAG, "error creating directory '%s'", settings->ConfigPath);
|
|
goto fail;
|
|
}
|
|
|
|
WLog_INFO(TAG, "creating directory %s", settings->ConfigPath);
|
|
}
|
|
|
|
if (!(certificate_store->path = GetCombinedPath(settings->ConfigPath,
|
|
(char*) certificate_store_dir)))
|
|
goto fail;
|
|
|
|
if (!PathFileExistsA(certificate_store->path))
|
|
{
|
|
if (!PathMakePathA(certificate_store->path, 0))
|
|
{
|
|
WLog_ERR(TAG, "error creating directory [%s]", certificate_store->path);
|
|
goto fail;
|
|
}
|
|
|
|
WLog_INFO(TAG, "creating directory [%s]", certificate_store->path);
|
|
}
|
|
|
|
if (!(server_path = GetCombinedPath(settings->ConfigPath, (char*) certificate_server_dir)))
|
|
goto fail;
|
|
|
|
if (!PathFileExistsA(server_path))
|
|
{
|
|
if (!PathMakePathA(server_path, 0))
|
|
{
|
|
WLog_ERR(TAG, "error creating directory [%s]", server_path);
|
|
goto fail;
|
|
}
|
|
|
|
WLog_INFO(TAG, "created directory [%s]", server_path);
|
|
}
|
|
|
|
if (!(certificate_store->file = GetCombinedPath(settings->ConfigPath,
|
|
(char*) certificate_known_hosts_file)))
|
|
goto fail;
|
|
|
|
if (!(certificate_store->legacy_file = GetCombinedPath(settings->ConfigPath,
|
|
(char*) certificate_legacy_hosts_file)))
|
|
goto fail;
|
|
|
|
free(server_path);
|
|
return TRUE;
|
|
fail:
|
|
WLog_ERR(TAG, "certificate store initialization failed");
|
|
free(server_path);
|
|
free(certificate_store->path);
|
|
free(certificate_store->file);
|
|
certificate_store->path = NULL;
|
|
certificate_store->file = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
static int certificate_data_match_legacy(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data)
|
|
{
|
|
HANDLE fp;
|
|
int match = 1;
|
|
char* data;
|
|
char* mdata;
|
|
char* pline;
|
|
char* hostname = NULL;
|
|
DWORD lowSize, highSize;
|
|
UINT64 size;
|
|
size_t length;
|
|
DWORD read;
|
|
/* Assure POSIX style paths, CreateFile expects either '/' or '\\' */
|
|
PathCchConvertStyleA(certificate_store->legacy_file, strlen(certificate_store->legacy_file),
|
|
PATH_STYLE_UNIX);
|
|
fp = CreateFileA(certificate_store->legacy_file, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fp == INVALID_HANDLE_VALUE)
|
|
return match;
|
|
|
|
if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE)
|
|
{
|
|
WLog_ERR(TAG, "GetFileSize(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->legacy_file, strerror(errno), GetLastError());
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
size = (UINT64)lowSize | ((UINT64)highSize << 32);
|
|
|
|
if (size < 1)
|
|
{
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
mdata = (char*) malloc(size + 2);
|
|
|
|
if (!mdata)
|
|
{
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
data = mdata;
|
|
|
|
if (!ReadFile(fp, data, size, &read, NULL) || (read != size))
|
|
{
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
CloseHandle(fp);
|
|
data[size] = '\n';
|
|
data[size + 1] = '\0';
|
|
pline = StrSep(&data, "\r\n");
|
|
|
|
while (pline != NULL)
|
|
{
|
|
length = strlen(pline);
|
|
|
|
if (length > 0)
|
|
{
|
|
hostname = StrSep(&pline, " \t");
|
|
|
|
if (!hostname || !pline)
|
|
WLog_WARN(TAG, "Invalid %s entry %s %s!", certificate_legacy_hosts_file,
|
|
hostname, pline);
|
|
else if (strcmp(hostname, certificate_data->hostname) == 0)
|
|
{
|
|
const int diff = strcmp(pline, certificate_data->fingerprint);
|
|
match = (diff == 0) ? 0 : -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pline = StrSep(&data, "\r\n");
|
|
}
|
|
|
|
/* Found a valid fingerprint in legacy file,
|
|
* copy to new file in new format. */
|
|
if (0 == match)
|
|
{
|
|
rdpCertificateData* data = certificate_data_new(
|
|
hostname,
|
|
certificate_data->port,
|
|
NULL, NULL,
|
|
certificate_data->fingerprint);
|
|
|
|
if (data)
|
|
{
|
|
free(data->subject);
|
|
free(data->issuer);
|
|
data->subject = NULL;
|
|
data->issuer = NULL;
|
|
|
|
if (certificate_data->subject)
|
|
{
|
|
data->subject = _strdup(certificate_data->subject);
|
|
|
|
if (!data->subject)
|
|
goto out;
|
|
}
|
|
|
|
if (certificate_data->issuer)
|
|
{
|
|
data->issuer = _strdup(certificate_data->issuer);
|
|
|
|
if (!data->issuer)
|
|
goto out;
|
|
}
|
|
|
|
match = certificate_data_print(certificate_store, data) ? 0 : 1;
|
|
}
|
|
|
|
out:
|
|
certificate_data_free(data);
|
|
}
|
|
|
|
free(mdata);
|
|
return match;
|
|
}
|
|
|
|
static int certificate_data_match_raw(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data,
|
|
char** psubject, char** pissuer,
|
|
char** fprint)
|
|
{
|
|
BOOL found = FALSE;
|
|
HANDLE fp;
|
|
size_t length;
|
|
char* data;
|
|
char* mdata;
|
|
char* pline;
|
|
int match = 1;
|
|
DWORD lowSize, highSize;
|
|
UINT64 size;
|
|
char* hostname = NULL;
|
|
char* subject = NULL;
|
|
char* issuer = NULL;
|
|
char* fingerprint = NULL;
|
|
unsigned short port = 0;
|
|
DWORD read;
|
|
/* Assure POSIX style paths, CreateFile expects either '/' or '\\' */
|
|
PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX);
|
|
fp = CreateFileA(certificate_store->file, GENERIC_READ, FILE_SHARE_READ,
|
|
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fp == INVALID_HANDLE_VALUE)
|
|
return match;
|
|
|
|
if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE)
|
|
{
|
|
WLog_ERR(TAG, "GetFileSize(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->legacy_file, strerror(errno), GetLastError());
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
size = (UINT64)lowSize | ((UINT64)highSize << 32);
|
|
|
|
if (size < 1)
|
|
{
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
mdata = (char*) malloc(size + 2);
|
|
|
|
if (!mdata)
|
|
{
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
data = mdata;
|
|
|
|
if (!ReadFile(fp, data, size, &read, NULL) || (read != size))
|
|
{
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return match;
|
|
}
|
|
|
|
CloseHandle(fp);
|
|
data[size] = '\n';
|
|
data[size + 1] = '\0';
|
|
pline = StrSep(&data, "\r\n");
|
|
|
|
while (pline != NULL)
|
|
{
|
|
length = strlen(pline);
|
|
|
|
if (length > 0)
|
|
{
|
|
if (certificate_line_is_comment(pline, length))
|
|
{
|
|
}
|
|
else if (!certificate_split_line(pline, &hostname, &port,
|
|
&subject, &issuer, &fingerprint))
|
|
WLog_WARN(TAG, "Invalid %s entry %s!",
|
|
certificate_known_hosts_file, pline);
|
|
else if (strcmp(pline, certificate_data->hostname) == 0)
|
|
{
|
|
int outLen;
|
|
|
|
if (port == certificate_data->port)
|
|
{
|
|
found = TRUE;
|
|
|
|
if (fingerprint)
|
|
{
|
|
match = (strcmp(certificate_data->fingerprint, fingerprint) == 0) ? 0 : -1;
|
|
|
|
if (fprint)
|
|
*fprint = _strdup(fingerprint);
|
|
}
|
|
|
|
if (subject && psubject)
|
|
crypto_base64_decode(subject, strlen(subject), (BYTE**)psubject, &outLen);
|
|
|
|
if (issuer && pissuer)
|
|
crypto_base64_decode(issuer, strlen(issuer), (BYTE**)pissuer, &outLen);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pline = StrSep(&data, "\r\n");
|
|
}
|
|
|
|
free(mdata);
|
|
|
|
if ((match != 0) && !found)
|
|
match = certificate_data_match_legacy(certificate_store, certificate_data);
|
|
|
|
return match;
|
|
}
|
|
|
|
BOOL certificate_get_stored_data(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data,
|
|
char** subject, char** issuer,
|
|
char** fingerprint)
|
|
{
|
|
int rc = certificate_data_match_raw(certificate_store, certificate_data,
|
|
subject, issuer, fingerprint);
|
|
|
|
if ((rc == 0) || (rc == -1))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int certificate_data_match(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data)
|
|
{
|
|
return certificate_data_match_raw(certificate_store, certificate_data,
|
|
NULL, NULL, NULL);
|
|
}
|
|
|
|
BOOL certificate_data_replace(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data)
|
|
{
|
|
HANDLE fp;
|
|
BOOL rc = FALSE;
|
|
size_t length;
|
|
char* data;
|
|
char* sdata;
|
|
char* pline;
|
|
UINT64 size;
|
|
DWORD read, written;
|
|
DWORD lowSize, highSize;
|
|
/* Assure POSIX style paths, CreateFile expects either '/' or '\\' */
|
|
PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX);
|
|
fp = CreateFileA(certificate_store->file, GENERIC_READ | GENERIC_WRITE, 0,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fp == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
if ((lowSize = GetFileSize(fp, &highSize)) == INVALID_FILE_SIZE)
|
|
{
|
|
WLog_ERR(TAG, "GetFileSize(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->legacy_file, strerror(errno), GetLastError());
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
size = (UINT64)lowSize | ((UINT64)highSize << 32);
|
|
|
|
if (size < 1)
|
|
{
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
data = (char*) malloc(size + 2);
|
|
|
|
if (!data)
|
|
{
|
|
fclose(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ReadFile(fp, data, size, &read, NULL) || (read != size))
|
|
{
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (SetFilePointer(fp, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
|
|
{
|
|
WLog_ERR(TAG, "SetFilePointer(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->file, strerror(errno), GetLastError());
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SetEndOfFile(fp))
|
|
{
|
|
WLog_ERR(TAG, "SetEndOfFile(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->file, strerror(errno), GetLastError());
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Write the file back out, with appropriate fingerprint substitutions */
|
|
data[size] = '\n';
|
|
data[size + 1] = '\0';
|
|
sdata = data;
|
|
pline = StrSep(&sdata, "\r\n");
|
|
|
|
while (pline != NULL)
|
|
{
|
|
length = strlen(pline);
|
|
|
|
if (length > 0)
|
|
{
|
|
UINT16 port = 0;
|
|
char* hostname = NULL;
|
|
char* fingerprint = NULL;
|
|
char* subject = NULL;
|
|
char* issuer = NULL;
|
|
char* tdata;
|
|
|
|
if (certificate_line_is_comment(pline, length))
|
|
{
|
|
}
|
|
else if (!certificate_split_line(pline, &hostname, &port, &subject, &issuer, &fingerprint))
|
|
WLog_WARN(TAG, "Skipping invalid %s entry %s!",
|
|
certificate_known_hosts_file, pline);
|
|
else
|
|
{
|
|
/* If this is the replaced hostname, use the updated fingerprint. */
|
|
if ((strcmp(hostname, certificate_data->hostname) == 0) &&
|
|
(port == certificate_data->port))
|
|
{
|
|
fingerprint = certificate_data->fingerprint;
|
|
rc = TRUE;
|
|
}
|
|
|
|
size = _snprintf(NULL, 0, "%s %"PRIu16" %s %s %s\n", hostname, port, fingerprint, subject, issuer);
|
|
tdata = malloc(size + 1);
|
|
|
|
if (!tdata)
|
|
{
|
|
WLog_ERR(TAG, "malloc(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (_snprintf(tdata, size + 1, "%s %"PRIu16" %s %s %s\n", hostname, port, fingerprint, subject,
|
|
issuer) != size)
|
|
{
|
|
WLog_ERR(TAG, "_snprintf(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
free(tdata);
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WriteFile(fp, tdata, size, &written, NULL) || (written != size))
|
|
{
|
|
WLog_ERR(TAG, "WriteFile(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
free(tdata);
|
|
free(data);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
free(tdata);
|
|
}
|
|
}
|
|
|
|
pline = StrSep(&sdata, "\r\n");
|
|
}
|
|
|
|
CloseHandle(fp);
|
|
free(data);
|
|
return rc;
|
|
}
|
|
|
|
BOOL certificate_split_line(char* line, char** host, UINT16* port, char** subject,
|
|
char** issuer, char** fingerprint)
|
|
{
|
|
char* cur;
|
|
size_t length = strlen(line);
|
|
|
|
if (length <= 0)
|
|
return FALSE;
|
|
|
|
cur = StrSep(&line, " \t");
|
|
|
|
if (!cur)
|
|
return FALSE;
|
|
|
|
*host = cur;
|
|
cur = StrSep(&line, " \t");
|
|
|
|
if (!cur)
|
|
return FALSE;
|
|
|
|
if (sscanf(cur, "%hu", port) != 1)
|
|
return FALSE;
|
|
|
|
cur = StrSep(&line, " \t");
|
|
|
|
if (!cur)
|
|
return FALSE;
|
|
|
|
*fingerprint = cur;
|
|
cur = StrSep(&line, " \t");
|
|
|
|
if (!cur)
|
|
return FALSE;
|
|
|
|
*subject = cur;
|
|
cur = StrSep(&line, " \t");
|
|
|
|
if (!cur)
|
|
return FALSE;
|
|
|
|
*issuer = cur;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL certificate_data_print(rdpCertificateStore* certificate_store,
|
|
rdpCertificateData* certificate_data)
|
|
{
|
|
HANDLE fp;
|
|
char* tdata;
|
|
UINT64 size;
|
|
DWORD written;
|
|
/* reopen in append mode */
|
|
/* Assure POSIX style paths, CreateFile expects either '/' or '\\' */
|
|
PathCchConvertStyleA(certificate_store->file, strlen(certificate_store->file), PATH_STYLE_UNIX);
|
|
fp = CreateFileA(certificate_store->file, GENERIC_WRITE, 0,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fp == INVALID_HANDLE_VALUE)
|
|
return FALSE;
|
|
|
|
if (SetFilePointer(fp, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
|
|
{
|
|
WLog_ERR(TAG, "SetFilePointer(%s) returned %s [0x%08"PRIX32"]",
|
|
certificate_store->file, strerror(errno), GetLastError());
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
size = _snprintf(NULL, 0, "%s %"PRIu16" %s %s %s\n", certificate_data->hostname,
|
|
certificate_data->port,
|
|
certificate_data->fingerprint, certificate_data->subject,
|
|
certificate_data->issuer);
|
|
tdata = malloc(size + 1);
|
|
|
|
if (!tdata)
|
|
{
|
|
WLog_ERR(TAG, "malloc(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (_snprintf(tdata, size + 1, "%s %"PRIu16" %s %s %s\n", certificate_data->hostname,
|
|
certificate_data->port,
|
|
certificate_data->fingerprint, certificate_data->subject,
|
|
certificate_data->issuer) != size)
|
|
{
|
|
WLog_ERR(TAG, "_snprintf(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
free(tdata);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WriteFile(fp, tdata, size, &written, NULL) || (written != size))
|
|
{
|
|
WLog_ERR(TAG, "WriteFile(%s) returned %s [0x%08X]",
|
|
certificate_store->file, strerror(errno), errno);
|
|
free(tdata);
|
|
CloseHandle(fp);
|
|
return FALSE;
|
|
}
|
|
|
|
free(tdata);
|
|
CloseHandle(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
rdpCertificateData* certificate_data_new(const char* hostname, UINT16 port, const char* subject,
|
|
const char* issuer, const char* fingerprint)
|
|
{
|
|
size_t i;
|
|
rdpCertificateData* certdata;
|
|
|
|
if (!hostname)
|
|
return NULL;
|
|
|
|
if (!fingerprint)
|
|
return NULL;
|
|
|
|
certdata = (rdpCertificateData*)calloc(1, sizeof(rdpCertificateData));
|
|
|
|
if (!certdata)
|
|
return NULL;
|
|
|
|
certdata->port = port;
|
|
certdata->hostname = _strdup(hostname);
|
|
|
|
if (subject)
|
|
certdata->subject = crypto_base64_encode((BYTE*)subject, strlen(subject));
|
|
else
|
|
certdata->subject = crypto_base64_encode((BYTE*)"", 0);
|
|
|
|
if (issuer)
|
|
certdata->issuer = crypto_base64_encode((BYTE*)issuer, strlen(issuer));
|
|
else
|
|
certdata->issuer = crypto_base64_encode((BYTE*)"", 0);
|
|
|
|
certdata->fingerprint = _strdup(fingerprint);
|
|
|
|
if (!certdata->hostname || !certdata->subject ||
|
|
!certdata->issuer || !certdata->fingerprint)
|
|
goto fail;
|
|
|
|
for (i = 0; i < strlen(hostname); i++)
|
|
certdata->hostname[i] = tolower(certdata->hostname[i]);
|
|
|
|
return certdata;
|
|
fail:
|
|
free(certdata->hostname);
|
|
free(certdata->subject);
|
|
free(certdata->issuer);
|
|
free(certdata->fingerprint);
|
|
free(certdata);
|
|
return NULL;
|
|
}
|
|
|
|
void certificate_data_free(rdpCertificateData* certificate_data)
|
|
{
|
|
if (certificate_data != NULL)
|
|
{
|
|
free(certificate_data->hostname);
|
|
free(certificate_data->subject);
|
|
free(certificate_data->issuer);
|
|
free(certificate_data->fingerprint);
|
|
free(certificate_data);
|
|
}
|
|
}
|
|
|
|
rdpCertificateStore* certificate_store_new(rdpSettings* settings)
|
|
{
|
|
rdpCertificateStore* certificate_store;
|
|
certificate_store = (rdpCertificateStore*) calloc(1, sizeof(rdpCertificateStore));
|
|
|
|
if (!certificate_store)
|
|
return NULL;
|
|
|
|
certificate_store->settings = settings;
|
|
|
|
if (!certificate_store_init(certificate_store))
|
|
{
|
|
free(certificate_store);
|
|
return NULL;
|
|
}
|
|
|
|
return certificate_store;
|
|
}
|
|
|
|
void certificate_store_free(rdpCertificateStore* certstore)
|
|
{
|
|
if (certstore != NULL)
|
|
{
|
|
free(certstore->path);
|
|
free(certstore->file);
|
|
free(certstore->legacy_file);
|
|
free(certstore);
|
|
}
|
|
}
|