Blame libfreerdp/crypto/crypto.c

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