FreeRDP/libfreerdp-crypto/certificate.c

260 lines
5.5 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.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <freerdp/utils/file.h>
static const char certificate_store_dir[] = "certs";
static const char certificate_known_hosts_file[] = "known_hosts";
#include <freerdp/crypto/certificate.h>
void certificate_store_init(rdpCertificateStore* certificate_store)
{
char* config_path;
rdpSettings* settings;
settings = certificate_store->settings;
config_path = freerdp_get_config_path(settings);
certificate_store->path = freerdp_construct_path(config_path, (char*) certificate_store_dir);
if (freerdp_check_file_exists(certificate_store->path) == false)
{
freerdp_mkdir(certificate_store->path);
printf("creating directory %s\n", certificate_store->path);
}
certificate_store->file = freerdp_construct_path(config_path, (char*) certificate_known_hosts_file);
if (freerdp_check_file_exists(certificate_store->file) == false)
{
certificate_store->fp = fopen((char*) certificate_store->file, "w+");
if (certificate_store->fp == NULL)
{
printf("certificate_store_open: error opening [%s] for writing\n", certificate_store->file);
return;
}
fflush(certificate_store->fp);
}
else
{
certificate_store->fp = fopen((char*) certificate_store->file, "r+");
}
}
int certificate_data_match(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
{
FILE* fp;
int length;
char* data;
char* pline;
int match = 1;
long int size;
fp = certificate_store->fp;
if (!fp)
return match;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (size < 1)
return match;
data = (char*) xmalloc(size + 2);
if (fread(data, size, 1, fp) != 1)
{
xfree(data);
return match;
}
data[size] = '\n';
data[size + 1] = '\0';
pline = strtok(data, "\n");
while (pline != NULL)
{
length = strlen(pline);
if (length > 0)
{
length = strcspn(pline, " \t");
pline[length] = '\0';
if (strcmp(pline, certificate_data->hostname) == 0)
{
pline = &pline[length + 1];
if (strcmp(pline, certificate_data->fingerprint) == 0)
match = 0;
else
match = -1;
break;
}
}
pline = strtok(NULL, "\n");
}
xfree(data);
return match;
}
void certificate_data_replace(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
{
FILE* fp;
int length;
char* data;
char* pline;
long int size;
fp = certificate_store->fp;
if (!fp)
return;
// Read the current contents of the file.
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (size < 1)
return;
data = (char*) xmalloc(size + 2);
if (fread(data, size, 1, fp) != 1)
{
xfree(data);
return;
}
// Write the file back out, with appropriate fingerprint substitutions
fp = fopen(certificate_store->file, "w+");
data[size] = '\n';
data[size + 1] = '\0';
pline = strtok(data, "\n"); // xxx: use strsep
while (pline != NULL)
{
length = strlen(pline);
if (length > 0)
{
char* hostname = pline, *fingerprint;
length = strcspn(pline, " \t");
hostname[length] = '\0';
/* If this is the replaced hostname, use the updated fingerprint. */
if (strcmp(hostname, certificate_data->hostname) == 0)
fingerprint = certificate_data->fingerprint;
else
fingerprint = &hostname[length + 1];
fprintf(fp, "%s %s\n", hostname, fingerprint);
}
pline = strtok(NULL, "\n");
}
fclose(fp);
xfree(data);
}
void certificate_data_print(rdpCertificateStore* certificate_store, rdpCertificateData* certificate_data)
{
FILE* fp;
/* reopen in append mode */
fp = fopen(certificate_store->file, "a");
if (!fp)
return;
fprintf(fp, "%s %s\n", certificate_data->hostname, certificate_data->fingerprint);
fclose(fp);
}
rdpCertificateData* certificate_data_new(char* hostname, char* fingerprint)
{
rdpCertificateData* certdata;
certdata = (rdpCertificateData*) xzalloc(sizeof(rdpCertificateData));
if (certdata != NULL)
{
certdata->hostname = xstrdup(hostname);
certdata->fingerprint = xstrdup(fingerprint);
}
return certdata;
}
void certificate_data_free(rdpCertificateData* certificate_data)
{
if (certificate_data != NULL)
{
xfree(certificate_data->hostname);
xfree(certificate_data->fingerprint);
xfree(certificate_data);
}
}
rdpCertificateStore* certificate_store_new(rdpSettings* settings)
{
rdpCertificateStore* certificate_store;
certificate_store = (rdpCertificateStore*) xzalloc(sizeof(rdpCertificateStore));
if (certificate_store != NULL)
{
certificate_store->settings = settings;
certificate_store_init(certificate_store);
}
return certificate_store;
}
void certificate_store_free(rdpCertificateStore* certstore)
{
if (certstore != NULL)
{
if (certstore->fp != NULL)
fclose(certstore->fp);
xfree(certstore->path);
xfree(certstore->file);
xfree(certstore);
}
}