Blame libfreerdp/crypto/crypto.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Cryptographic Abstraction Layer
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *	 http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/crypto.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <freerdp/crypto/crypto.h>
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("crypto")
Packit Service fa4841
Packit Service fa4841
CryptoCert crypto_cert_read(BYTE* data, UINT32 length)
Packit Service fa4841
{
Packit Service fa4841
	CryptoCert cert = malloc(sizeof(*cert));
Packit Service fa4841
Packit Service fa4841
	if (!cert)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	/* this will move the data pointer but we don't care, we don't use it again */
Packit Service bb5c11
	cert->px509 = d2i_X509(NULL, (D2I_X509_CONST BYTE**) &data, length);
Packit Service fa4841
	return cert;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void crypto_cert_free(CryptoCert cert)
Packit Service fa4841
{
Packit Service fa4841
	if (cert == NULL)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	X509_free(cert->px509);
Packit Service fa4841
	free(cert);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* PublicKeyLength)
Packit Service fa4841
{
Packit Service fa4841
	BYTE* ptr;
Packit Service fa4841
	int length;
Packit Service fa4841
	BOOL status = TRUE;
Packit Service fa4841
	EVP_PKEY* pkey = NULL;
Packit Service fa4841
	pkey = X509_get_pubkey(cert->px509);
Packit Service fa4841
Packit Service fa4841
	if (!pkey)
Packit Service fa4841
	{
Packit Service bb5c11
		WLog_ERR(TAG,  "X509_get_pubkey() failed");
Packit Service fa4841
		status = FALSE;
Packit Service fa4841
		goto exit;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	length = i2d_PublicKey(pkey, NULL);
Packit Service fa4841
Packit Service fa4841
	if (length < 1)
Packit Service fa4841
	{
Packit Service bb5c11
		WLog_ERR(TAG,  "i2d_PublicKey() failed");
Packit Service fa4841
		status = FALSE;
Packit Service fa4841
		goto exit;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	*PublicKeyLength = (DWORD) length;
Packit Service bb5c11
	*PublicKey = (BYTE*) malloc(length);
Packit Service fa4841
	ptr = (BYTE*)(*PublicKey);
Packit Service fa4841
Packit Service fa4841
	if (!ptr)
Packit Service fa4841
	{
Packit Service fa4841
		status = FALSE;
Packit Service fa4841
		goto exit;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	i2d_PublicKey(pkey, &ptr);
Packit Service fa4841
exit:
Packit Service fa4841
Packit Service fa4841
	if (pkey)
Packit Service fa4841
		EVP_PKEY_free(pkey);
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service fa4841
                             const BYTE* exponent, int exponent_size, BYTE* output)
Packit Service fa4841
{
Packit Service bb5c11
	BN_CTX* ctx;
Packit Service fa4841
	int output_length = -1;
Packit Service bb5c11
	BYTE* input_reverse;
Packit Service bb5c11
	BYTE* modulus_reverse;
Packit Service bb5c11
	BYTE* exponent_reverse;
Packit Service bb5c11
	BIGNUM* mod, *exp, *x, *y;
Packit Service bb5c11
	input_reverse = (BYTE*) malloc(2 * key_length + exponent_size);
Packit Service fa4841
Packit Service fa4841
	if (!input_reverse)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	modulus_reverse = input_reverse + key_length;
Packit Service fa4841
	exponent_reverse = modulus_reverse + key_length;
Packit Service fa4841
	memcpy(modulus_reverse, modulus, key_length);
Packit Service fa4841
	crypto_reverse(modulus_reverse, key_length);
Packit Service fa4841
	memcpy(exponent_reverse, exponent, exponent_size);
Packit Service fa4841
	crypto_reverse(exponent_reverse, exponent_size);
Packit Service fa4841
	memcpy(input_reverse, input, length);
Packit Service fa4841
	crypto_reverse(input_reverse, length);
Packit Service fa4841
Packit Service fa4841
	if (!(ctx = BN_CTX_new()))
Packit Service fa4841
		goto fail_bn_ctx;
Packit Service fa4841
Packit Service fa4841
	if (!(mod = BN_new()))
Packit Service fa4841
		goto fail_bn_mod;
Packit Service fa4841
Packit Service fa4841
	if (!(exp = BN_new()))
Packit Service fa4841
		goto fail_bn_exp;
Packit Service fa4841
Packit Service fa4841
	if (!(x = BN_new()))
Packit Service fa4841
		goto fail_bn_x;
Packit Service fa4841
Packit Service fa4841
	if (!(y = BN_new()))
Packit Service fa4841
		goto fail_bn_y;
Packit Service fa4841
Packit Service bb5c11
	BN_bin2bn(modulus_reverse, key_length, mod);
Packit Service bb5c11
	BN_bin2bn(exponent_reverse, exponent_size, exp);
Packit Service bb5c11
	BN_bin2bn(input_reverse, length, x);
Packit Service bb5c11
	BN_mod_exp(y, x, exp, mod, ctx);
Packit Service fa4841
	output_length = BN_bn2bin(y, output);
Packit Service fa4841
	crypto_reverse(output, output_length);
Packit Service fa4841
Packit Service bb5c11
	if (output_length < (int) key_length)
Packit Service fa4841
		memset(output + output_length, 0, key_length - output_length);
Packit Service fa4841
Packit Service fa4841
	BN_free(y);
Packit Service fa4841
fail_bn_y:
Packit Service fa4841
	BN_clear_free(x);
Packit Service fa4841
fail_bn_x:
Packit Service fa4841
	BN_free(exp);
Packit Service fa4841
fail_bn_exp:
Packit Service fa4841
	BN_free(mod);
Packit Service fa4841
fail_bn_mod:
Packit Service fa4841
	BN_CTX_free(ctx);
Packit Service fa4841
fail_bn_ctx:
Packit Service fa4841
	free(input_reverse);
Packit Service fa4841
	return output_length;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int crypto_rsa_public(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service fa4841
                             const BYTE* exponent, BYTE* output)
Packit Service fa4841
{
Packit Service bb5c11
	return crypto_rsa_common(input, length, key_length, modulus, exponent, EXPONENT_MAX_SIZE, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int crypto_rsa_private(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service fa4841
                              const BYTE* private_exponent, BYTE* output)
Packit Service fa4841
{
Packit Service bb5c11
	return crypto_rsa_common(input, length, key_length, modulus, private_exponent, key_length, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service fa4841
                              const BYTE* exponent, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_rsa_public(input, length, key_length, modulus, exponent, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service fa4841
                              const BYTE* exponent, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_rsa_public(input, length, key_length, modulus, exponent, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length,
Packit Service fa4841
                               const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_rsa_private(input, length, key_length, modulus, private_exponent, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length,
Packit Service fa4841
                               const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_rsa_private(input, length, key_length, modulus, private_exponent, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
int crypto_rsa_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
Packit Service bb5c11
                       const BYTE* private_exponent, BYTE* output)
Packit Service fa4841
{
Packit Service bb5c11
	return crypto_rsa_common(input, length, key_length, modulus, private_exponent, key_length, output);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void crypto_reverse(BYTE* data, int length)
Packit Service fa4841
{
Packit Service fa4841
	int i, j;
Packit Service fa4841
	BYTE temp;
Packit Service fa4841
Packit Service fa4841
	for (i = 0, j = length - 1; i < j; i++, j--)
Packit Service fa4841
	{
Packit Service fa4841
		temp = data[i];
Packit Service fa4841
		data[i] = data[j];
Packit Service fa4841
		data[j] = temp;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* crypto_cert_fingerprint(X509* xcert)
Packit Service fa4841
{
Packit Service bb5c11
	size_t i = 0;
Packit Service fa4841
	char* p;
Packit Service fa4841
	char* fp_buffer;
Packit Service bb5c11
	UINT32 fp_len;
Packit Service bb5c11
	BYTE fp[EVP_MAX_MD_SIZE];
Packit Service bb5c11
	X509_digest(xcert, EVP_sha1(), fp, &fp_len);
Packit Service bb5c11
	fp_buffer = (char*) calloc(fp_len + 1, 3);
Packit Service fa4841
Packit Service fa4841
	if (!fp_buffer)
Packit Service bb5c11
		return NULL;
Packit Service fa4841
Packit Service fa4841
	p = fp_buffer;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < (fp_len - 1); i++)
Packit Service fa4841
	{
Packit Service bb5c11
		sprintf_s(p, (fp_len - i) * 3, "%02"PRIx8":", fp[i]);
Packit Service fa4841
		p = &fp_buffer[(i + 1) * 3];
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	sprintf_s(p, (fp_len - i) * 3,  "%02"PRIx8"", fp[i]);
Packit Service fa4841
	return fp_buffer;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
char* crypto_print_name(X509_NAME* name)
Packit Service fa4841
{
Packit Service fa4841
	char* buffer = NULL;
Packit Service fa4841
	BIO* outBIO = BIO_new(BIO_s_mem());
Packit Service fa4841
Packit Service fa4841
	if (X509_NAME_print_ex(outBIO, name, 0, XN_FLAG_ONELINE) > 0)
Packit Service fa4841
	{
Packit Service fa4841
		unsigned long size = BIO_number_written(outBIO);
Packit Service fa4841
		buffer = calloc(1, size + 1);
Packit Service fa4841
Packit Service fa4841
		if (!buffer)
Packit Service fa4841
			return NULL;
Packit Service fa4841
Packit Service fa4841
		BIO_read(outBIO, buffer, size);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	BIO_free_all(outBIO);
Packit Service fa4841
	return buffer;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* crypto_cert_subject(X509* xcert)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_print_name(X509_get_subject_name(xcert));
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char* crypto_cert_subject_common_name(X509* xcert, int* length)
Packit Service fa4841
{
Packit Service fa4841
	int index;
Packit Service fa4841
	BYTE* common_name_raw;
Packit Service fa4841
	char* common_name;
Packit Service fa4841
	X509_NAME* subject_name;
Packit Service fa4841
	X509_NAME_ENTRY* entry;
Packit Service fa4841
	ASN1_STRING* entry_data;
Packit Service fa4841
	subject_name = X509_get_subject_name(xcert);
Packit Service fa4841
Packit Service fa4841
	if (subject_name == NULL)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	index = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
Packit Service fa4841
Packit Service fa4841
	if (index < 0)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	entry = X509_NAME_get_entry(subject_name, index);
Packit Service fa4841
Packit Service fa4841
	if (entry == NULL)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	entry_data = X509_NAME_ENTRY_get_data(entry);
Packit Service fa4841
Packit Service fa4841
	if (entry_data == NULL)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	*length = ASN1_STRING_to_UTF8(&common_name_raw, entry_data);
Packit Service fa4841
Packit Service fa4841
	if (*length < 0)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	common_name = _strdup((char*)common_name_raw);
Packit Service fa4841
	OPENSSL_free(common_name_raw);
Packit Service bb5c11
	return (char*) common_name;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
/* GENERAL_NAME type labels */
Packit Service fa4841
Packit Service bb5c11
static const char*   general_name_type_labels[] = { "OTHERNAME",
Packit Service bb5c11
                                                    "EMAIL    ",
Packit Service bb5c11
                                                    "DNS      ",
Packit Service bb5c11
                                                    "X400     ",
Packit Service bb5c11
                                                    "DIRNAME  ",
Packit Service bb5c11
                                                    "EDIPARTY ",
Packit Service bb5c11
                                                    "URI      ",
Packit Service bb5c11
                                                    "IPADD    ",
Packit Service bb5c11
                                                    "RID      "
Packit Service bb5c11
                                                  };
Packit Service fa4841
Packit Service fa4841
static const char* general_name_type_label(int general_name_type)
Packit Service fa4841
{
Packit Service bb5c11
	if ((0 <= general_name_type)
Packit Service bb5c11
	    && (general_name_type < ARRAYSIZE(general_name_type_labels)))
Packit Service fa4841
	{
Packit Service fa4841
		return general_name_type_labels[general_name_type];
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		static char buffer[80];
Packit Service fa4841
		sprintf(buffer, "Unknown general name type (%d)", general_name_type);
Packit Service fa4841
		return buffer;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
/*
Packit Service fa4841
Packit Service fa4841
map_subject_alt_name(x509,  general_name_type, mapper, data)
Packit Service fa4841
Packit Service fa4841
Call the function mapper with subjectAltNames found in the x509
Packit Service fa4841
certificate and data.  if generate_name_type is GEN_ALL,  the the
Packit Service fa4841
mapper is called for all the names,  else it's called only for names
Packit Service fa4841
of the given type.
Packit Service fa4841
Packit Service fa4841
Packit Service fa4841
We implement two extractors:
Packit Service fa4841
Packit Service fa4841
 -  a string extractor that can be used to get the subjectAltNames of
Packit Service fa4841
    the following types: GEN_URI,  GEN_DNS,  GEN_EMAIL
Packit Service fa4841
Packit Service fa4841
 - a ASN1_OBJECT filter/extractor that can be used to get the
Packit Service fa4841
   subjectAltNames of OTHERNAME type.
Packit Service fa4841
Packit Service fa4841
   Note: usually, it's a string, but some type of otherNames can be
Packit Service fa4841
   associated with different classes of objects. eg. a KPN may be a
Packit Service fa4841
   sequence of realm and principal name, instead of a single string
Packit Service fa4841
   object.
Packit Service fa4841
Packit Service fa4841
Not implemented yet: extractors for the types: GEN_X400, GEN_DIRNAME,
Packit Service fa4841
GEN_EDIPARTY, GEN_RID, GEN_IPADD (the later can contain nul-bytes).
Packit Service fa4841
Packit Service fa4841
Packit Service fa4841
mapper(name, data, index, count)
Packit Service fa4841
Packit Service fa4841
The mapper is passed:
Packit Service fa4841
 - the GENERAL_NAME selected,
Packit Service fa4841
 - the data,
Packit Service fa4841
 - the index of the general name in the subjectAltNames,
Packit Service fa4841
 - the total number of names in the subjectAltNames.
Packit Service fa4841
Packit Service fa4841
The last parameter let's the mapper allocate arrays to collect objects.
Packit Service fa4841
Note: if names are filtered,  not all the indices from 0 to count-1 are
Packit Service fa4841
passed to mapper,  only the indices selected.
Packit Service fa4841
Packit Service fa4841
When the mapper returns 0, map_subject_alt_name stops the iteration immediately.
Packit Service fa4841
Packit Service fa4841
*/
Packit Service fa4841
Packit Service fa4841
#define GEN_ALL (-1)
Packit Service fa4841
Packit Service fa4841
typedef int (*general_name_mapper_pr)(GENERAL_NAME* name, void* data, int index, int count);
Packit Service fa4841
Packit Service fa4841
static void map_subject_alt_name(X509* x509, int general_name_type, general_name_mapper_pr mapper,
Packit Service fa4841
                                 void* data)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	int num;
Packit Service bb5c11
	STACK_OF(GENERAL_NAME) *gens;
Packit Service fa4841
	gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
Packit Service fa4841
Packit Service fa4841
	if (!gens)
Packit Service fa4841
	{
Packit Service fa4841
		return;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	num = sk_GENERAL_NAME_num(gens);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; (i < num); i++)
Packit Service fa4841
	{
Packit Service fa4841
		GENERAL_NAME* name = sk_GENERAL_NAME_value(gens, i);
Packit Service fa4841
Packit Service fa4841
		if (name)
Packit Service fa4841
		{
Packit Service fa4841
			if ((general_name_type == GEN_ALL) || (general_name_type == name->type))
Packit Service fa4841
			{
Packit Service fa4841
				if (!mapper(name, data, i, num))
Packit Service fa4841
				{
Packit Service fa4841
					break;
Packit Service fa4841
				}
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
/*
Packit Service fa4841
extract_string  --  string extractor
Packit Service fa4841
Packit Service fa4841
- the strings array is allocated lazily, when we first have to store a
Packit Service fa4841
  string.
Packit Service fa4841
Packit Service fa4841
- allocated contains the size of the strings array, or -1 if
Packit Service fa4841
  allocation failed.
Packit Service fa4841
Packit Service fa4841
- count contains the actual count of strings in the strings array.
Packit Service fa4841
Packit Service fa4841
- maximum limits the number of strings we can store in the strings
Packit Service fa4841
  array: beyond, the extractor returns 0 to short-cut the search.
Packit Service fa4841
Packit Service fa4841
extract_string stores in the string list OPENSSL strings,
Packit Service fa4841
that must be freed with OPENSSL_free.
Packit Service fa4841
Packit Service fa4841
*/
Packit Service fa4841
Packit Service fa4841
typedef struct string_list
Packit Service fa4841
{
Packit Service bb5c11
	char**   strings;
Packit Service bb5c11
	int      allocated;
Packit Service bb5c11
	int      count;
Packit Service bb5c11
	int      maximum;
Packit Service fa4841
} string_list;
Packit Service fa4841
Packit Service fa4841
static void string_list_initialize(string_list* list)
Packit Service fa4841
{
Packit Service fa4841
	list->strings = 0;
Packit Service fa4841
	list->allocated = 0;
Packit Service fa4841
	list->count = 0;
Packit Service fa4841
	list->maximum = INT_MAX;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void string_list_allocate(string_list* list, int allocate_count)
Packit Service fa4841
{
Packit Service fa4841
	if (!list->strings && list->allocated == 0)
Packit Service fa4841
	{
Packit Service bb5c11
		list->strings = calloc(allocate_count, sizeof(list->strings[0]));
Packit Service fa4841
		list->allocated = list->strings ? allocate_count : -1;
Packit Service fa4841
		list->count = 0;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void string_list_free(string_list* list)
Packit Service fa4841
{
Packit Service fa4841
	/* Note: we don't free the contents of the strings array: this */
Packit Service fa4841
	/* is handled by the caller,  either by returning this */
Packit Service fa4841
	/* content,  or freeing it itself. */
Packit Service fa4841
	free(list->strings);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int extract_string(GENERAL_NAME* name, void* data, int index, int count)
Packit Service fa4841
{
Packit Service bb5c11
	string_list*   list = data;
Packit Service fa4841
	unsigned char* cstring = 0;
Packit Service bb5c11
	ASN1_STRING*   str;
Packit Service fa4841
Packit Service fa4841
	switch (name->type)
Packit Service fa4841
	{
Packit Service fa4841
		case GEN_URI:
Packit Service fa4841
			str = name->d.uniformResourceIdentifier;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case GEN_DNS:
Packit Service fa4841
			str = name->d.dNSName;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		case GEN_EMAIL:
Packit Service fa4841
			str = name->d.rfc822Name;
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		default:
Packit Service fa4841
			return 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((ASN1_STRING_to_UTF8(&cstring, str)) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "ASN1_STRING_to_UTF8() failed for %s: %s",
Packit Service bb5c11
		         general_name_type_label(name->type),
Packit Service bb5c11
		         ERR_error_string(ERR_get_error(), NULL));
Packit Service fa4841
		return 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	string_list_allocate(list, count);
Packit Service fa4841
Packit Service fa4841
	if (list->allocated <= 0)
Packit Service fa4841
	{
Packit Service fa4841
		OPENSSL_free(cstring);
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	list->strings[list->count] = (char*)cstring;
Packit Service bb5c11
	list->count ++ ;
Packit Service fa4841
Packit Service fa4841
	if (list->count >= list->maximum)
Packit Service fa4841
	{
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
extract_othername_object --  object extractor.
Packit Service fa4841
Packit Service fa4841
- the objects array is allocated lazily, when we first have to store a
Packit Service fa4841
  string.
Packit Service fa4841
Packit Service fa4841
- allocated contains the size of the objects array, or -1 if
Packit Service fa4841
  allocation failed.
Packit Service fa4841
Packit Service fa4841
- count contains the actual count of objects in the objects array.
Packit Service fa4841
Packit Service fa4841
- maximum limits the number of objects we can store in the objects
Packit Service fa4841
  array: beyond, the extractor returns 0 to short-cut the search.
Packit Service fa4841
Packit Service fa4841
extract_othername_objects stores in the objects array ASN1_TYPE *
Packit Service fa4841
pointers directly obtained from the GENERAL_NAME.
Packit Service fa4841
*/
Packit Service fa4841
Packit Service fa4841
typedef struct object_list
Packit Service fa4841
{
Packit Service fa4841
	ASN1_OBJECT* type_id;
Packit Service bb5c11
	char**      strings;
Packit Service bb5c11
	int          allocated;
Packit Service bb5c11
	int          count;
Packit Service bb5c11
	int          maximum;
Packit Service fa4841
} object_list;
Packit Service fa4841
Packit Service fa4841
static void object_list_initialize(object_list* list)
Packit Service fa4841
{
Packit Service fa4841
	list->type_id = 0;
Packit Service fa4841
	list->strings = 0;
Packit Service fa4841
	list->allocated = 0;
Packit Service fa4841
	list->count = 0;
Packit Service fa4841
	list->maximum = INT_MAX;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void object_list_allocate(object_list* list, int allocate_count)
Packit Service fa4841
{
Packit Service fa4841
	if (!list->strings && list->allocated == 0)
Packit Service fa4841
	{
Packit Service fa4841
		list->strings = calloc(allocate_count, sizeof(list->strings[0]));
Packit Service fa4841
		list->allocated = list->strings ? allocate_count : -1;
Packit Service fa4841
		list->count = 0;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static char* object_string(ASN1_TYPE* object)
Packit Service fa4841
{
Packit Service fa4841
	char* result;
Packit Service fa4841
	unsigned char* utf8String;
Packit Service fa4841
	int length;
Packit Service fa4841
	/* TODO: check that object.type is a string type. */
Packit Service bb5c11
	length = ASN1_STRING_to_UTF8(& utf8String, object->value.asn1_string);
Packit Service fa4841
Packit Service fa4841
	if (length < 0)
Packit Service fa4841
	{
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	result = (char*)strdup((char*)utf8String);
Packit Service fa4841
	OPENSSL_free(utf8String);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void object_list_free(object_list* list)
Packit Service fa4841
{
Packit Service fa4841
	free(list->strings);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int extract_othername_object_as_string(GENERAL_NAME* name, void* data, int index, int count)
Packit Service fa4841
{
Packit Service bb5c11
	object_list*   list = data;
Packit Service fa4841
Packit Service fa4841
	if (name->type != GEN_OTHERNAME)
Packit Service fa4841
	{
Packit Service fa4841
		return 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (0 != OBJ_cmp(name->d.otherName->type_id, list->type_id))
Packit Service fa4841
	{
Packit Service fa4841
		return 1;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	object_list_allocate(list, count);
Packit Service fa4841
Packit Service fa4841
	if (list->allocated <= 0)
Packit Service fa4841
	{
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	list->strings[list->count] = object_string(name->d.otherName->value);
Packit Service fa4841
Packit Service fa4841
	if (list->strings[list->count])
Packit Service fa4841
	{
Packit Service bb5c11
		list->count ++ ;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (list->count >= list->maximum)
Packit Service fa4841
	{
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
crypto_cert_get_email returns a dynamically allocated copy of the
Packit Service fa4841
first email found in the subjectAltNames (use free to free it).
Packit Service fa4841
*/
Packit Service fa4841
Packit Service fa4841
char* crypto_cert_get_email(X509* x509)
Packit Service fa4841
{
Packit Service fa4841
	char* result = 0;
Packit Service fa4841
	string_list list;
Packit Service fa4841
	string_list_initialize(&list);
Packit Service fa4841
	list.maximum = 1;
Packit Service fa4841
	map_subject_alt_name(x509, GEN_EMAIL, extract_string, &list);
Packit Service fa4841
Packit Service fa4841
	if (list.count == 0)
Packit Service fa4841
	{
Packit Service fa4841
		string_list_free(&list);
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	result = strdup(list.strings[0]);
Packit Service fa4841
	OPENSSL_free(list.strings[0]);
Packit Service fa4841
	string_list_free(&list);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
/*
Packit Service fa4841
crypto_cert_get_upn returns a dynamically allocated copy of the
Packit Service fa4841
first UPN otherNames in the subjectAltNames (use free to free it).
Packit Service fa4841
Note: if this first UPN otherName is not a string, then 0 is returned,
Packit Service fa4841
instead of searching for another UPN that would be a string.
Packit Service fa4841
*/
Packit Service fa4841
Packit Service bb5c11
Packit Service bb5c11
Packit Service fa4841
char* crypto_cert_get_upn(X509* x509)
Packit Service fa4841
{
Packit Service fa4841
	char* result = 0;
Packit Service fa4841
	object_list list;
Packit Service fa4841
	object_list_initialize(&list);
Packit Service fa4841
	list.type_id = OBJ_nid2obj(NID_ms_upn);
Packit Service fa4841
	list.maximum = 1;
Packit Service fa4841
	map_subject_alt_name(x509, GEN_OTHERNAME, extract_othername_object_as_string, &list);
Packit Service fa4841
Packit Service fa4841
	if (list.count == 0)
Packit Service fa4841
	{
Packit Service fa4841
		object_list_free(&list);
Packit Service fa4841
		return 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	result = list.strings[0];
Packit Service fa4841
	object_list_free(&list);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
/* Deprecated name.*/
Packit Service fa4841
void crypto_cert_subject_alt_name_free(int count, int* lengths, char** alt_names)
Packit Service fa4841
{
Packit Service fa4841
	crypto_cert_dns_names_free(count, lengths, alt_names);
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
void crypto_cert_dns_names_free(int count, int* lengths,
Packit Service bb5c11
                                char** dns_names)
Packit Service fa4841
{
Packit Service fa4841
	free(lengths);
Packit Service fa4841
Packit Service fa4841
	if (dns_names)
Packit Service fa4841
	{
Packit Service fa4841
		int i;
Packit Service fa4841
Packit Service fa4841
		for (i = 0; i < count; i++)
Packit Service fa4841
		{
Packit Service fa4841
			if (dns_names[i])
Packit Service fa4841
			{
Packit Service fa4841
				OPENSSL_free(dns_names[i]);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(dns_names);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/* Deprecated name.*/
Packit Service fa4841
char** crypto_cert_subject_alt_name(X509* xcert, int* count, int** lengths)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_cert_get_dns_names(xcert, count, lengths);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
char** crypto_cert_get_dns_names(X509* x509, int* count, int** lengths)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	char** result = 0;
Packit Service fa4841
	string_list list;
Packit Service fa4841
	string_list_initialize(&list);
Packit Service fa4841
	map_subject_alt_name(x509, GEN_DNS, extract_string, &list);
Packit Service fa4841
	(*count) = list.count;
Packit Service fa4841
Packit Service fa4841
	if (list.count == 0)
Packit Service fa4841
	{
Packit Service fa4841
		string_list_free(&list);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* lengths are not useful,  since we converted the
Packit Service fa4841
	   strings to utf-8,  there cannot be nul-bytes in them. */
Packit Service fa4841
	result = calloc(list.count, sizeof(*result));
Packit Service fa4841
	(*lengths) = calloc(list.count, sizeof(**lengths));
Packit Service fa4841
Packit Service fa4841
	if (!result || !(*lengths))
Packit Service fa4841
	{
Packit Service fa4841
		string_list_free(&list);
Packit Service fa4841
		free(result);
Packit Service fa4841
		free(*lengths);
Packit Service fa4841
		(*lengths) = 0;
Packit Service fa4841
		(*count) = 0;
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	for (i = 0; i < list.count; i ++)
Packit Service fa4841
	{
Packit Service fa4841
		result[i] = list.strings[i];
Packit Service fa4841
		(*lengths)[i] = strlen(result[i]);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	string_list_free(&list);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
Packit Service fa4841
char* crypto_cert_issuer(X509* xcert)
Packit Service fa4841
{
Packit Service fa4841
	return crypto_print_name(X509_get_issuer_name(xcert));
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path)
Packit Service fa4841
{
Packit Service fa4841
	X509_STORE_CTX* csc;
Packit Service fa4841
	BOOL status = FALSE;
Packit Service fa4841
	X509_STORE* cert_ctx = NULL;
Packit Service fa4841
	X509_LOOKUP* lookup = NULL;
Packit Service bb5c11
	X509* xcert = cert->px509;
Packit Service fa4841
	cert_ctx = X509_STORE_new();
Packit Service fa4841
Packit Service fa4841
	if (cert_ctx == NULL)
Packit Service fa4841
		goto end;
Packit Service fa4841
Packit Service fa4841
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
Packit Service fa4841
	OpenSSL_add_all_algorithms();
Packit Service fa4841
#else
Packit Service bb5c11
	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
Packit Service bb5c11
	                    | OPENSSL_INIT_ADD_ALL_DIGESTS \
Packit Service bb5c11
	                    | OPENSSL_INIT_LOAD_CONFIG, NULL);
Packit Service fa4841
#endif
Packit Service fa4841
	lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
Packit Service fa4841
Packit Service fa4841
	if (lookup == NULL)
Packit Service fa4841
		goto end;
Packit Service fa4841
Packit Service fa4841
	lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
Packit Service fa4841
Packit Service fa4841
	if (lookup == NULL)
Packit Service fa4841
		goto end;
Packit Service fa4841
Packit Service fa4841
	X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
Packit Service fa4841
Packit Service fa4841
	if (certificate_store_path != NULL)
Packit Service fa4841
	{
Packit Service fa4841
		X509_LOOKUP_add_dir(lookup, certificate_store_path, X509_FILETYPE_PEM);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	csc = X509_STORE_CTX_new();
Packit Service bb5c11
Packit Service bb5c11
	if (csc == NULL)
Packit Service bb5c11
		goto end;
Packit Service bb5c11
Packit Service fa4841
	X509_STORE_set_flags(cert_ctx, 0);
Packit Service fa4841
Packit Service bb5c11
	if (!X509_STORE_CTX_init(csc, cert_ctx, xcert, cert->px509chain))
Packit Service bb5c11
		goto end;
Packit Service bb5c11
Packit Service bb5c11
	if (X509_verify_cert(csc) == 1)
Packit Service bb5c11
		status = TRUE;
Packit Service fa4841
Packit Service bb5c11
	X509_STORE_CTX_free(csc);
Packit Service fa4841
	X509_STORE_free(cert_ctx);
Packit Service fa4841
end:
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UINT16 port)
Packit Service fa4841
{
Packit Service fa4841
	char* issuer;
Packit Service fa4841
	char* subject;
Packit Service fa4841
	char* fp;
Packit Service fa4841
	rdpCertificateData* certdata;
Packit Service fa4841
	fp = crypto_cert_fingerprint(xcert);
Packit Service fa4841
Packit Service fa4841
	if (!fp)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	issuer = crypto_cert_issuer(xcert);
Packit Service fa4841
	subject = crypto_cert_subject(xcert);
Packit Service fa4841
	certdata = certificate_data_new(hostname, port, issuer, subject, fp);
Packit Service fa4841
	free(subject);
Packit Service fa4841
	free(issuer);
Packit Service fa4841
	free(fp);
Packit Service fa4841
	return certdata;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void crypto_cert_print_info(X509* xcert)
Packit Service fa4841
{
Packit Service fa4841
	char* fp;
Packit Service fa4841
	char* issuer;
Packit Service fa4841
	char* subject;
Packit Service fa4841
	subject = crypto_cert_subject(xcert);
Packit Service fa4841
	issuer = crypto_cert_issuer(xcert);
Packit Service fa4841
	fp = crypto_cert_fingerprint(xcert);
Packit Service fa4841
Packit Service fa4841
	if (!fp)
Packit Service fa4841
	{
Packit Service bb5c11
		WLog_ERR(TAG,  "error computing fingerprint");
Packit Service fa4841
		goto out_free_issuer;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service bb5c11
	WLog_INFO(TAG,  "Certificate details:");
Packit Service bb5c11
	WLog_INFO(TAG,  "\tSubject: %s", subject);
Packit Service bb5c11
	WLog_INFO(TAG,  "\tIssuer: %s", issuer);
Packit Service bb5c11
	WLog_INFO(TAG,  "\tThumbprint: %s", fp);
Packit Service fa4841
	WLog_INFO(TAG,
Packit Service fa4841
	          "The above X.509 certificate could not be verified, possibly because you do not have "
Packit Service fa4841
	          "the CA certificate in your certificate store, or the certificate has expired. "
Packit Service fa4841
	          "Please look at the OpenSSL documentation on how to add a private CA to the store.");
Packit Service fa4841
	free(fp);
Packit Service fa4841
out_free_issuer:
Packit Service fa4841
	free(issuer);
Packit Service fa4841
	free(subject);
Packit Service fa4841
}