Blame libfreerdp/core/certificate.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Certificate Handling
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011 Jiten Pathy
Packit 1fb8d4
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.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 <errno.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/wtypes.h>
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/crypto.h>
Packit 1fb8d4
Packit 1fb8d4
#include <openssl/pem.h>
Packit 1fb8d4
#include <openssl/rsa.h>
Packit 1fb8d4
Packit 1fb8d4
#include "certificate.h"
Packit 1fb8d4
#include "../crypto/opensslcompat.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG "com.freerdp.core"
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 *
Packit 1fb8d4
 * X.509 Certificate Structure
Packit 1fb8d4
 *
Packit 1fb8d4
 * Certificate ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	tbsCertificate			TBSCertificate,
Packit 1fb8d4
 * 	signatureAlgorithm		AlgorithmIdentifier,
Packit 1fb8d4
 * 	signatureValue			BIT_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * TBSCertificate ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	version			[0]	EXPLICIT Version DEFAULT v1,
Packit 1fb8d4
 * 	serialNumber			CertificateSerialNumber,
Packit 1fb8d4
 * 	signature			AlgorithmIdentifier,
Packit 1fb8d4
 * 	issuer				Name,
Packit 1fb8d4
 * 	validity			Validity,
Packit 1fb8d4
 * 	subject				Name,
Packit 1fb8d4
 * 	subjectPublicKeyInfo		SubjectPublicKeyInfo,
Packit 1fb8d4
 * 	issuerUniqueID		[1]	IMPLICIT UniqueIdentifier OPTIONAL,
Packit 1fb8d4
 * 	subjectUniqueId		[2]	IMPLICIT UniqueIdentifier OPTIONAL,
Packit 1fb8d4
 * 	extensions		[3]	EXPLICIT Extensions OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
Packit 1fb8d4
 *
Packit 1fb8d4
 * CertificateSerialNumber ::= INTEGER
Packit 1fb8d4
 *
Packit 1fb8d4
 * AlgorithmIdentifier ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	algorithm			OBJECT_IDENTIFIER,
Packit 1fb8d4
 * 	parameters			ANY DEFINED BY algorithm OPTIONAL
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Name ::= CHOICE { RDNSequence }
Packit 1fb8d4
 *
Packit 1fb8d4
 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
Packit 1fb8d4
 *
Packit 1fb8d4
 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
Packit 1fb8d4
 *
Packit 1fb8d4
 * AttributeTypeAndValue ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	type				AttributeType,
Packit 1fb8d4
 * 	value				AttributeValue
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * AttributeType ::= OBJECT_IDENTIFIER
Packit 1fb8d4
 *
Packit 1fb8d4
 * AttributeValue ::= ANY DEFINED BY AttributeType
Packit 1fb8d4
 *
Packit 1fb8d4
 * Validity ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	notBefore			Time,
Packit 1fb8d4
 * 	notAfter			Time
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Time ::= CHOICE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	utcTime				UTCTime,
Packit 1fb8d4
 * 	generalTime			GeneralizedTime
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * UniqueIdentifier ::= BIT_STRING
Packit 1fb8d4
 *
Packit 1fb8d4
 * SubjectPublicKeyInfo ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	algorithm			AlgorithmIdentifier,
Packit 1fb8d4
 * 	subjectPublicKey		BIT_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * RSAPublicKey ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	modulus				INTEGER
Packit 1fb8d4
 * 	publicExponent			INTEGER
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
Packit 1fb8d4
 *
Packit 1fb8d4
 * Extension ::= SEQUENCE
Packit 1fb8d4
 * {
Packit 1fb8d4
 * 	extnID				OBJECT_IDENTIFIER
Packit 1fb8d4
 * 	critical			BOOLEAN DEFAULT FALSE,
Packit 1fb8d4
 * 	extnValue			OCTET_STRING
Packit 1fb8d4
 * }
Packit 1fb8d4
 *
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static const char* certificate_read_errors[] =
Packit 1fb8d4
{
Packit 1fb8d4
	"Certificate tag",
Packit 1fb8d4
	"TBSCertificate",
Packit 1fb8d4
	"Explicit Contextual Tag [0]",
Packit 1fb8d4
	"version",
Packit 1fb8d4
	"CertificateSerialNumber",
Packit 1fb8d4
	"AlgorithmIdentifier",
Packit 1fb8d4
	"Issuer Name",
Packit 1fb8d4
	"Validity",
Packit 1fb8d4
	"Subject Name",
Packit 1fb8d4
	"SubjectPublicKeyInfo Tag",
Packit 1fb8d4
	"subjectPublicKeyInfo::AlgorithmIdentifier",
Packit 1fb8d4
	"subjectPublicKeyInfo::subjectPublicKey",
Packit 1fb8d4
	"RSAPublicKey Tag",
Packit 1fb8d4
	"modulusLength",
Packit 1fb8d4
	"zero padding",
Packit 1fb8d4
	"modulusLength",
Packit 1fb8d4
	"modulus",
Packit 1fb8d4
	"publicExponent length",
Packit 1fb8d4
	"publicExponent"
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read X.509 Certificate
Packit 1fb8d4
 * @param certificate certificate module
Packit 1fb8d4
 * @param cert X.509 certificate
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL certificate_read_x509_certificate(rdpCertBlob* cert, rdpCertInfo* info)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	BYTE padding;
Packit 1fb8d4
	UINT32 version;
Packit 1fb8d4
	size_t modulus_length;
Packit 1fb8d4
	size_t exponent_length;
Packit 1fb8d4
	int error = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!cert || !info)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	memset(info, 0, sizeof(rdpCertInfo));
Packit 1fb8d4
	s = Stream_New(cert->data, cert->length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	info->Modulus = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_contextual_tag(s, 0, &length, TRUE))	/* Explicit Contextual Tag [0] */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_integer(s, &version)) /* version (INTEGER) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
	version++;
Packit 1fb8d4
Packit 1fb8d4
	/* serialNumber */
Packit 1fb8d4
	if (!ber_read_integer(s, NULL)) /* CertificateSerialNumber (INTEGER) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* signature */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) ||
Packit 1fb8d4
	    !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* issuer */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* validity */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Validity (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* subject */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* subjectPublicKeyInfo */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* subjectPublicKeyInfo::AlgorithmIdentifier */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length) ||
Packit 1fb8d4
	    !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* subjectPublicKeyInfo::subjectPublicKey */
Packit 1fb8d4
	if (!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* RSAPublicKey (SEQUENCE) */
Packit 1fb8d4
	if (!ber_read_sequence_tag(s, &length)) /* SEQUENCE */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	/* skip zero padding, if any */
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (Stream_GetRemainingLength(s) < 1)
Packit 1fb8d4
			goto error1;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Peek_UINT8(s, padding);
Packit 1fb8d4
Packit 1fb8d4
		if (padding == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!Stream_SafeSeek(s, 1))
Packit 1fb8d4
				goto error1;
Packit 1fb8d4
Packit 1fb8d4
			modulus_length--;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	while (padding == 0);
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (((int) Stream_GetRemainingLength(s)) < modulus_length)
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	info->ModulusLength = modulus_length;
Packit 1fb8d4
	info->Modulus = (BYTE*) malloc(info->ModulusLength);
Packit 1fb8d4
Packit 1fb8d4
	if (!info->Modulus)
Packit 1fb8d4
		goto error1;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, info->Modulus, info->ModulusLength);
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if (!ber_read_integer_length(s, &exponent_length)) /* publicExponent (INTEGER) */
Packit 1fb8d4
		goto error2;
Packit 1fb8d4
Packit 1fb8d4
	error++;
Packit 1fb8d4
Packit 1fb8d4
	if ((((int) Stream_GetRemainingLength(s)) < exponent_length) || (exponent_length > 4))
Packit 1fb8d4
		goto error2;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, &info->exponent[4 - exponent_length], exponent_length);
Packit 1fb8d4
	crypto_reverse(info->Modulus, info->ModulusLength);
Packit 1fb8d4
	crypto_reverse(info->exponent, 4);
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
error2:
Packit 1fb8d4
	free(info->Modulus);
Packit 1fb8d4
	info->Modulus = 0;
Packit 1fb8d4
error1:
Packit 1fb8d4
	WLog_ERR(TAG, "error reading when reading certificate: part=%s error=%d",
Packit 1fb8d4
	         certificate_read_errors[error], error);
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Instantiate new X.509 Certificate Chain.
Packit 1fb8d4
 * @param count certificate chain count
Packit 1fb8d4
 * @return new X.509 certificate chain
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static rdpX509CertChain* certificate_new_x509_certificate_chain(UINT32 count)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpX509CertChain* x509_cert_chain;
Packit 1fb8d4
	x509_cert_chain = (rdpX509CertChain*) malloc(sizeof(rdpX509CertChain));
Packit 1fb8d4
Packit 1fb8d4
	if (!x509_cert_chain)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	x509_cert_chain->count = count;
Packit 1fb8d4
	x509_cert_chain->array = (rdpCertBlob*) calloc(count, sizeof(rdpCertBlob));
Packit 1fb8d4
Packit 1fb8d4
	if (!x509_cert_chain->array)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(x509_cert_chain);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return x509_cert_chain;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free X.509 Certificate Chain.
Packit 1fb8d4
 * @param x509_cert_chain X.509 certificate chain to be freed
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	if (!x509_cert_chain)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < (int)x509_cert_chain->count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(x509_cert_chain->array[i].data);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(x509_cert_chain->array);
Packit 1fb8d4
	free(x509_cert_chain);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL certificate_process_server_public_key(rdpCertificate* certificate, wStream* s,
Packit 1fb8d4
        UINT32 length)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE magic[4];
Packit 1fb8d4
	UINT32 keylen;
Packit 1fb8d4
	UINT32 bitlen;
Packit 1fb8d4
	UINT32 datalen;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 20)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, magic, 4);
Packit 1fb8d4
Packit 1fb8d4
	if (memcmp(magic, "RSA1", 4) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "magic error");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, keylen);
Packit 1fb8d4
	Stream_Read_UINT32(s, bitlen);
Packit 1fb8d4
	Stream_Read_UINT32(s, datalen);
Packit 1fb8d4
	Stream_Read(s, certificate->cert_info.exponent, 4);
Packit 1fb8d4
Packit 1fb8d4
	if ((keylen <= 8) || (Stream_GetRemainingLength(s) < keylen))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	certificate->cert_info.ModulusLength = keylen - 8;
Packit 1fb8d4
	certificate->cert_info.Modulus = malloc(certificate->cert_info.ModulusLength);
Packit 1fb8d4
Packit 1fb8d4
	if (!certificate->cert_info.Modulus)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read(s, certificate->cert_info.Modulus, certificate->cert_info.ModulusLength);
Packit 1fb8d4
	Stream_Seek(s, 8); /* 8 bytes of zero padding */
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL certificate_process_server_public_signature(rdpCertificate* certificate,
Packit 1fb8d4
        const BYTE* sigdata, size_t sigdatalen, wStream* s, UINT32 siglen)
Packit 1fb8d4
{
Packit 1fb8d4
#if defined(CERT_VALIDATE_PADDING) || defined(CERT_VALIDATE_RSA)
Packit 1fb8d4
	size_t i, sum;
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(CERT_VALIDATE_RSA)
Packit 1fb8d4
	BYTE sig[TSSK_KEY_LENGTH];
Packit 1fb8d4
#endif
Packit 1fb8d4
	BYTE encsig[TSSK_KEY_LENGTH + 8];
Packit 1fb8d4
#if defined(CERT_VALIDATE_MD5) && defined(CERT_VALIDATE_RSA)
Packit 1fb8d4
	BYTE md5hash[WINPR_MD5_DIGEST_LENGTH];
Packit 1fb8d4
#endif
Packit 1fb8d4
#if !defined(CERT_VALIDATE_MD5) || !defined(CERT_VALIDATE_RSA)
Packit 1fb8d4
	(void)sigdata;
Packit 1fb8d4
	(void)sigdatalen;
Packit 1fb8d4
#endif
Packit 1fb8d4
	(void)certificate;
Packit 1fb8d4
	/* Do not bother with validation of server proprietary certificate. The use of MD5 here is not allowed under FIPS.
Packit 1fb8d4
	 * Since the validation is not protecting against anything since the private/public keys are well known and documented in
Packit 1fb8d4
	 * MS-RDPBCGR section 5.3.3.1, we are not gaining any security by using MD5 for signature comparison. Rather then use MD5
Packit 1fb8d4
	 * here we just dont do the validation to avoid its use. Historically, freerdp has been ignoring a failed validation anyways. */
Packit 1fb8d4
#if defined(CERT_VALIDATE_MD5)
Packit 1fb8d4
Packit 1fb8d4
	if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	Stream_Read(s, encsig, siglen);
Packit 1fb8d4
Packit 1fb8d4
	if (siglen < 8)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* Last 8 bytes shall be all zero. */
Packit 1fb8d4
#if defined(CERT_VALIDATE_PADDING)
Packit 1fb8d4
Packit 1fb8d4
	for (sum = 0, i = sizeof(encsig) - 8; i < sizeof(encsig); i++)
Packit 1fb8d4
		sum += encsig[i];
Packit 1fb8d4
Packit 1fb8d4
	if (sum != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "invalid signature");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#if defined(CERT_VALIDATE_RSA)
Packit 1fb8d4
Packit 1fb8d4
	if (crypto_rsa_public_decrypt(encsig, siglen - 8, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent,
Packit 1fb8d4
	                              sig) <= 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "invalid RSA decrypt");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Verify signature. */
Packit 1fb8d4
	/* Do not bother with validation of server proprietary certificate as described above. */
Packit 1fb8d4
#if defined(CERT_VALIDATE_MD5)
Packit 1fb8d4
Packit 1fb8d4
	if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "invalid signature");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Verify rest of decrypted data:
Packit 1fb8d4
	 * The 17th byte is 0x00.
Packit 1fb8d4
	 * The 18th through 62nd bytes are each 0xFF.
Packit 1fb8d4
	 * The 63rd byte is 0x01.
Packit 1fb8d4
	 */
Packit 1fb8d4
Packit 1fb8d4
	for (sum = 0, i = 17; i < 62; i++)
Packit 1fb8d4
		sum += sig[i];
Packit 1fb8d4
Packit 1fb8d4
	if (sig[16] != 0x00 || sum != 0xFF * (62 - 17) || sig[62] != 0x01)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "invalid signature");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a Server Proprietary Certificate.\n
Packit 1fb8d4
 * @param certificate certificate module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 dwSigAlgId;
Packit 1fb8d4
	UINT32 dwKeyAlgId;
Packit 1fb8d4
	UINT16 wPublicKeyBlobType;
Packit 1fb8d4
	UINT16 wPublicKeyBlobLen;
Packit 1fb8d4
	UINT16 wSignatureBlobType;
Packit 1fb8d4
	UINT16 wSignatureBlobLen;
Packit 1fb8d4
	BYTE* sigdata;
Packit 1fb8d4
	size_t sigdatalen;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 12)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	/* -4, because we need to include dwVersion */
Packit 1fb8d4
	sigdata = Stream_Pointer(s) - 4;
Packit 1fb8d4
	Stream_Read_UINT32(s, dwSigAlgId);
Packit 1fb8d4
	Stream_Read_UINT32(s, dwKeyAlgId);
Packit 1fb8d4
Packit 1fb8d4
	if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unsupported signature or key algorithm, dwSigAlgId=%"PRIu32" dwKeyAlgId=%"PRIu32"",
Packit 1fb8d4
		         dwSigAlgId, dwKeyAlgId);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wPublicKeyBlobType);
Packit 1fb8d4
Packit 1fb8d4
	if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unsupported public key blob type %"PRIu16"", wPublicKeyBlobType);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wPublicKeyBlobLen);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < wPublicKeyBlobLen)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough bytes for public key(len=%"PRIu16")", wPublicKeyBlobLen);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "error in server public key");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	sigdatalen = Stream_Pointer(s) - sigdata;
Packit 1fb8d4
	Stream_Read_UINT16(s, wSignatureBlobType);
Packit 1fb8d4
Packit 1fb8d4
	if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unsupported blob signature %"PRIu16"", wSignatureBlobType);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT16(s, wSignatureBlobLen);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < wSignatureBlobLen)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "not enough bytes for signature(len=%"PRIu16")", wSignatureBlobLen);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (wSignatureBlobLen != 72)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "invalid signature length (got %"PRIu16", expected 72)", wSignatureBlobLen);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s,
Packit 1fb8d4
	        wSignatureBlobLen))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unable to parse server public signature");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read an X.509 Certificate Chain.\n
Packit 1fb8d4
 * @param certificate certificate module
Packit 1fb8d4
 * @param s stream
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	BOOL ret;
Packit 1fb8d4
	UINT32 certLength;
Packit 1fb8d4
	UINT32 numCertBlobs;
Packit 1fb8d4
	DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
Packit 1fb8d4
	certificate->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs);
Packit 1fb8d4
Packit 1fb8d4
	if (!certificate->x509_cert_chain)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < numCertBlobs; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (Stream_GetRemainingLength(s) < 4)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read_UINT32(s, certLength);
Packit 1fb8d4
Packit 1fb8d4
		if (Stream_GetRemainingLength(s) < certLength)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		DEBUG_CERTIFICATE("X.509 Certificate #%d, length:%"PRIu32"", i + 1, certLength);
Packit 1fb8d4
		certificate->x509_cert_chain->array[i].data = (BYTE*) malloc(certLength);
Packit 1fb8d4
Packit 1fb8d4
		if (!certificate->x509_cert_chain->array[i].data)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read(s, certificate->x509_cert_chain->array[i].data, certLength);
Packit 1fb8d4
		certificate->x509_cert_chain->array[i].length = certLength;
Packit 1fb8d4
Packit 1fb8d4
		if ((numCertBlobs - i) == 2)
Packit 1fb8d4
		{
Packit 1fb8d4
			rdpCertInfo cert_info = { 0 };
Packit 1fb8d4
			DEBUG_CERTIFICATE("License Server Certificate");
Packit 1fb8d4
			ret = certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i], &cert_info);
Packit 1fb8d4
			DEBUG_LICENSE("modulus length:%"PRIu32"", cert_info.ModulusLength);
Packit 1fb8d4
			free(cert_info.Modulus);
Packit 1fb8d4
Packit 1fb8d4
			if (!ret)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "failed to read License Server, content follows:");
Packit 1fb8d4
				winpr_HexDump(TAG, WLOG_ERROR, certificate->x509_cert_chain->array[i].data,
Packit 1fb8d4
				              certificate->x509_cert_chain->array[i].length);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (numCertBlobs - i == 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			DEBUG_CERTIFICATE("Terminal Server Certificate");
Packit 1fb8d4
Packit 1fb8d4
			if (!certificate_read_x509_certificate(&certificate->x509_cert_chain->array[i],
Packit 1fb8d4
			                                       &certificate->cert_info))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			DEBUG_CERTIFICATE("modulus length:%"PRIu32"", certificate->cert_info.ModulusLength);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Read a Server Certificate.\n
Packit 1fb8d4
 * @param certificate certificate module
Packit 1fb8d4
 * @param server_cert server certificate
Packit 1fb8d4
 * @param length certificate length
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert,
Packit 1fb8d4
        size_t length)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL ret;
Packit 1fb8d4
	wStream* s;
Packit 1fb8d4
	UINT32 dwVersion;
Packit 1fb8d4
Packit 1fb8d4
	if (length < 4)  /* NULL certificate is not an error see #1795 */
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(server_cert, length);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_New failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
	switch (dwVersion & CERT_CHAIN_VERSION_MASK)
Packit 1fb8d4
	{
Packit 1fb8d4
		case CERT_CHAIN_VERSION_1:
Packit 1fb8d4
			ret = certificate_read_server_proprietary_certificate(certificate, s);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case CERT_CHAIN_VERSION_2:
Packit 1fb8d4
			ret = certificate_read_server_x509_certificate_chain(certificate, s);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "invalid certificate chain version:%"PRIu32"", dwVersion & CERT_CHAIN_VERSION_MASK);
Packit 1fb8d4
			ret = FALSE;
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
rdpRsaKey* key_new_from_content(const char* keycontent, const char* keyfile)
Packit 1fb8d4
{
Packit 1fb8d4
	BIO* bio = NULL;
Packit 1fb8d4
	RSA* rsa = NULL;
Packit 1fb8d4
	rdpRsaKey* key = NULL;
Packit 1fb8d4
	const BIGNUM* rsa_e = NULL;
Packit 1fb8d4
	const BIGNUM* rsa_n = NULL;
Packit 1fb8d4
	const BIGNUM* rsa_d = NULL;
Packit 1fb8d4
	key = (rdpRsaKey*) calloc(1, sizeof(rdpRsaKey));
Packit 1fb8d4
Packit 1fb8d4
	if (!key)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	bio = BIO_new_mem_buf((void*)keycontent, strlen(keycontent));
Packit 1fb8d4
Packit 1fb8d4
	if (!bio)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
Packit 1fb8d4
	BIO_free_all(bio);
Packit 1fb8d4
Packit 1fb8d4
	if (!rsa)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unable to load RSA key from %s: %s.", keyfile, strerror(errno));
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	switch (RSA_check_key(rsa))
Packit 1fb8d4
	{
Packit 1fb8d4
		case 0:
Packit 1fb8d4
			WLog_ERR(TAG, "invalid RSA key in %s", keyfile);
Packit 1fb8d4
			goto out_free_rsa;
Packit 1fb8d4
Packit 1fb8d4
		case 1:
Packit 1fb8d4
			/* Valid key. */
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			WLog_ERR(TAG, "unexpected error when checking RSA key from %s: %s.", keyfile, strerror(errno));
Packit 1fb8d4
			goto out_free_rsa;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
Packit 1fb8d4
Packit 1fb8d4
	if (BN_num_bytes(rsa_e) > 4)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "RSA public exponent too large in %s", keyfile);
Packit 1fb8d4
		goto out_free_rsa;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	key->ModulusLength = BN_num_bytes(rsa_n);
Packit 1fb8d4
	key->Modulus = (BYTE*) malloc(key->ModulusLength);
Packit 1fb8d4
Packit 1fb8d4
	if (!key->Modulus)
Packit 1fb8d4
		goto out_free_rsa;
Packit 1fb8d4
Packit 1fb8d4
	BN_bn2bin(rsa_n, key->Modulus);
Packit 1fb8d4
	crypto_reverse(key->Modulus, key->ModulusLength);
Packit 1fb8d4
	key->PrivateExponentLength = BN_num_bytes(rsa_d);
Packit 1fb8d4
	key->PrivateExponent = (BYTE*) malloc(key->PrivateExponentLength);
Packit 1fb8d4
Packit 1fb8d4
	if (!key->PrivateExponent)
Packit 1fb8d4
		goto out_free_modulus;
Packit 1fb8d4
Packit 1fb8d4
	BN_bn2bin(rsa_d, key->PrivateExponent);
Packit 1fb8d4
	crypto_reverse(key->PrivateExponent, key->PrivateExponentLength);
Packit 1fb8d4
	memset(key->exponent, 0, sizeof(key->exponent));
Packit 1fb8d4
	BN_bn2bin(rsa_e, key->exponent + sizeof(key->exponent) - BN_num_bytes(rsa_e));
Packit 1fb8d4
	crypto_reverse(key->exponent, sizeof(key->exponent));
Packit 1fb8d4
	RSA_free(rsa);
Packit 1fb8d4
	return key;
Packit 1fb8d4
out_free_modulus:
Packit 1fb8d4
	free(key->Modulus);
Packit 1fb8d4
out_free_rsa:
Packit 1fb8d4
	RSA_free(rsa);
Packit 1fb8d4
out_free:
Packit 1fb8d4
	free(key);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
rdpRsaKey* key_new(const char* keyfile)
Packit 1fb8d4
{
Packit 1fb8d4
	FILE* fp = NULL;
Packit 1fb8d4
	INT64 length;
Packit 1fb8d4
	char* buffer = NULL;
Packit 1fb8d4
	rdpRsaKey* key = NULL;
Packit 1fb8d4
	fp = fopen(keyfile, "rb");
Packit 1fb8d4
Packit 1fb8d4
	if (!fp)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unable to open RSA key file %s: %s.", keyfile, strerror(errno));
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (_fseeki64(fp, 0, SEEK_END) < 0)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	if ((length = _ftelli64(fp)) < 0)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	if (_fseeki64(fp, 0, SEEK_SET) < 0)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	buffer = (char*)malloc(length + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	if (fread((void*) buffer, length, 1, fp) != 1)
Packit 1fb8d4
		goto out_free;
Packit 1fb8d4
Packit 1fb8d4
	fclose(fp);
Packit 1fb8d4
	buffer[length] = '\0';
Packit 1fb8d4
	key = key_new_from_content(buffer, keyfile);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return key;
Packit 1fb8d4
out_free:
Packit 1fb8d4
Packit 1fb8d4
	if (fp)
Packit 1fb8d4
		fclose(fp);
Packit 1fb8d4
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void key_free(rdpRsaKey* key)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!key)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	free(key->Modulus);
Packit 1fb8d4
	free(key->PrivateExponent);
Packit 1fb8d4
	free(key);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
rdpCertificate* certificate_clone(rdpCertificate* certificate)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	rdpCertificate* _certificate = (rdpCertificate*) calloc(1, sizeof(rdpCertificate));
Packit 1fb8d4
Packit 1fb8d4
	if (!_certificate)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(_certificate, certificate, sizeof(rdpCertificate));
Packit 1fb8d4
Packit 1fb8d4
	if (certificate->cert_info.ModulusLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		_certificate->cert_info.Modulus = (BYTE*) malloc(certificate->cert_info.ModulusLength);
Packit 1fb8d4
Packit 1fb8d4
		if (!_certificate->cert_info.Modulus)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(_certificate->cert_info.Modulus, certificate->cert_info.Modulus,
Packit 1fb8d4
		           certificate->cert_info.ModulusLength);
Packit 1fb8d4
		_certificate->cert_info.ModulusLength = certificate->cert_info.ModulusLength;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (certificate->x509_cert_chain)
Packit 1fb8d4
	{
Packit 1fb8d4
		_certificate->x509_cert_chain = (rdpX509CertChain*) malloc(sizeof(rdpX509CertChain));
Packit 1fb8d4
Packit 1fb8d4
		if (!_certificate->x509_cert_chain)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(_certificate->x509_cert_chain, certificate->x509_cert_chain, sizeof(rdpX509CertChain));
Packit 1fb8d4
Packit 1fb8d4
		if (certificate->x509_cert_chain->count)
Packit 1fb8d4
		{
Packit 1fb8d4
			_certificate->x509_cert_chain->array = (rdpCertBlob*) calloc(certificate->x509_cert_chain->count,
Packit 1fb8d4
			                                       sizeof(rdpCertBlob));
Packit 1fb8d4
Packit 1fb8d4
			if (!_certificate->x509_cert_chain->array)
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			for (index = 0; index < certificate->x509_cert_chain->count; index++)
Packit 1fb8d4
			{
Packit 1fb8d4
				_certificate->x509_cert_chain->array[index].length =
Packit 1fb8d4
				    certificate->x509_cert_chain->array[index].length;
Packit 1fb8d4
Packit 1fb8d4
				if (certificate->x509_cert_chain->array[index].length)
Packit 1fb8d4
				{
Packit 1fb8d4
					_certificate->x509_cert_chain->array[index].data = (BYTE*) malloc(
Packit 1fb8d4
					            certificate->x509_cert_chain->array[index].length);
Packit 1fb8d4
Packit 1fb8d4
					if (!_certificate->x509_cert_chain->array[index].data)
Packit 1fb8d4
					{
Packit 1fb8d4
						for (--index; index >= 0; --index)
Packit 1fb8d4
						{
Packit 1fb8d4
							if (certificate->x509_cert_chain->array[index].length)
Packit 1fb8d4
								free(_certificate->x509_cert_chain->array[index].data);
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						goto out_fail;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					CopyMemory(_certificate->x509_cert_chain->array[index].data,
Packit 1fb8d4
					           certificate->x509_cert_chain->array[index].data,
Packit 1fb8d4
					           _certificate->x509_cert_chain->array[index].length);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return _certificate;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
Packit 1fb8d4
	if (_certificate->x509_cert_chain)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(_certificate->x509_cert_chain->array);
Packit 1fb8d4
		free(_certificate->x509_cert_chain);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(_certificate->cert_info.Modulus);
Packit 1fb8d4
	free(_certificate);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Instantiate new certificate module.\n
Packit 1fb8d4
 * @param rdp RDP module
Packit 1fb8d4
 * @return new certificate module
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
rdpCertificate* certificate_new(void)
Packit 1fb8d4
{
Packit 1fb8d4
	return (rdpCertificate*) calloc(1, sizeof(rdpCertificate));
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Free certificate module.
Packit 1fb8d4
 * @param certificate certificate module to be freed
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void certificate_free(rdpCertificate* certificate)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!certificate)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	certificate_free_x509_certificate_chain(certificate->x509_cert_chain);
Packit 1fb8d4
	free(certificate->cert_info.Modulus);
Packit 1fb8d4
	free(certificate);
Packit 1fb8d4
}