mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2024-12-02 22:36:16 +08:00
Merge pull request #4829 from informatimago/smartcard-logon-rdp--x509-certificate-info-extraction
Smartcard Logon: restructured x509 certificate info extraction; added extracting the UPN.
This commit is contained in:
commit
9e3b48e0fb
@ -42,12 +42,12 @@
|
||||
|
||||
struct crypto_cert_struct
|
||||
{
|
||||
X509 * px509;
|
||||
STACK_OF(X509) *px509chain;
|
||||
X509* px509;
|
||||
STACK_OF(X509)* px509chain;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct crypto_cert_struct* CryptoCert;
|
||||
@ -56,34 +56,51 @@ FREERDP_API CryptoCert crypto_cert_read(BYTE* data, UINT32 length);
|
||||
FREERDP_API char* crypto_cert_fingerprint(X509* xcert);
|
||||
FREERDP_API char* crypto_cert_subject(X509* xcert);
|
||||
FREERDP_API char* crypto_cert_subject_common_name(X509* xcert, int* length);
|
||||
FREERDP_API char** crypto_cert_subject_alt_name(X509* xcert, int* count,
|
||||
int** lengths);
|
||||
FREERDP_API void crypto_cert_subject_alt_name_free(int count, int *lengths,
|
||||
char** alt_name);
|
||||
FREERDP_API char** crypto_cert_get_dns_names(X509* xcert, int* count, int** lengths);
|
||||
FREERDP_API char* crypto_cert_get_email(X509* x509);
|
||||
FREERDP_API char* crypto_cert_get_upn(X509* x509);
|
||||
FREERDP_API void crypto_cert_dns_names_free(int count, int* lengths, char** dns_names);
|
||||
FREERDP_API char* crypto_cert_issuer(X509* xcert);
|
||||
FREERDP_API void crypto_cert_print_info(X509* xcert);
|
||||
FREERDP_API void crypto_cert_free(CryptoCert cert);
|
||||
|
||||
/*
|
||||
Deprecated function names: crypto_cert_subject_alt_name and crypto_cert_subject_alt_name_free.
|
||||
Use crypto_cert_get_dns_names and crypto_cert_dns_names_free instead.
|
||||
(old names kept for now for compatibility of FREERDP_API).
|
||||
Note: email and upn amongst others are also alt_names,
|
||||
but the old crypto_cert_get_alt_names returned only the dns_names
|
||||
*/
|
||||
FREERDP_API char** crypto_cert_subject_alt_name(X509* xcert, int* count, int** lengths);
|
||||
FREERDP_API void crypto_cert_subject_alt_name_free(int count, int *lengths, char** alt_names);
|
||||
|
||||
FREERDP_API BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path);
|
||||
FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UINT16 port);
|
||||
FREERDP_API BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* PublicKeyLength);
|
||||
FREERDP_API rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname,
|
||||
UINT16 port);
|
||||
FREERDP_API BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey,
|
||||
DWORD* PublicKeyLength);
|
||||
|
||||
#define TSSK_KEY_LENGTH 64
|
||||
extern const BYTE tssk_modulus[];
|
||||
extern const BYTE tssk_privateExponent[];
|
||||
extern const BYTE tssk_exponent[];
|
||||
|
||||
FREERDP_API int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* private_exponent, BYTE* output);
|
||||
FREERDP_API int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* private_exponent, BYTE* output);
|
||||
FREERDP_API void crypto_reverse(BYTE* data, int length);
|
||||
|
||||
FREERDP_API char* crypto_base64_encode(const BYTE* data, int length);
|
||||
FREERDP_API void crypto_base64_decode(const char* enc_data, int length, BYTE** dec_data, int* res_length);
|
||||
FREERDP_API void crypto_base64_decode(const char* enc_data, int length, BYTE** dec_data,
|
||||
int* res_length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_CRYPTO_H */
|
||||
|
@ -32,11 +32,12 @@
|
||||
CryptoCert crypto_cert_read(BYTE* data, UINT32 length)
|
||||
{
|
||||
CryptoCert cert = malloc(sizeof(*cert));
|
||||
|
||||
if (!cert)
|
||||
return NULL;
|
||||
|
||||
/* this will move the data pointer but we don't care, we don't use it again */
|
||||
cert->px509 = d2i_X509(NULL, (D2I_X509_CONST BYTE **) &data, length);
|
||||
cert->px509 = d2i_X509(NULL, (D2I_X509_CONST BYTE**) &data, length);
|
||||
return cert;
|
||||
}
|
||||
|
||||
@ -46,7 +47,6 @@ void crypto_cert_free(CryptoCert cert)
|
||||
return;
|
||||
|
||||
X509_free(cert->px509);
|
||||
|
||||
free(cert);
|
||||
}
|
||||
|
||||
@ -56,8 +56,8 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public
|
||||
int length;
|
||||
BOOL status = TRUE;
|
||||
EVP_PKEY* pkey = NULL;
|
||||
|
||||
pkey = X509_get_pubkey(cert->px509);
|
||||
|
||||
if (!pkey)
|
||||
{
|
||||
WLog_ERR(TAG, "X509_get_pubkey() failed");
|
||||
@ -66,6 +66,7 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public
|
||||
}
|
||||
|
||||
length = i2d_PublicKey(pkey, NULL);
|
||||
|
||||
if (length < 1)
|
||||
{
|
||||
WLog_ERR(TAG, "i2d_PublicKey() failed");
|
||||
@ -75,7 +76,8 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public
|
||||
|
||||
*PublicKeyLength = (DWORD) length;
|
||||
*PublicKey = (BYTE*) malloc(length);
|
||||
ptr = (BYTE*) (*PublicKey);
|
||||
ptr = (BYTE*)(*PublicKey);
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
status = FALSE;
|
||||
@ -83,30 +85,30 @@ BOOL crypto_cert_get_public_key(CryptoCert cert, BYTE** PublicKey, DWORD* Public
|
||||
}
|
||||
|
||||
i2d_PublicKey(pkey, &ptr);
|
||||
|
||||
exit:
|
||||
|
||||
if (pkey)
|
||||
EVP_PKEY_free(pkey);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, int exponent_size, BYTE* output)
|
||||
static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* exponent, int exponent_size, BYTE* output)
|
||||
{
|
||||
BN_CTX* ctx;
|
||||
int output_length = -1;
|
||||
BYTE* input_reverse;
|
||||
BYTE* modulus_reverse;
|
||||
BYTE* exponent_reverse;
|
||||
BIGNUM *mod, *exp, *x, *y;
|
||||
|
||||
BIGNUM* mod, *exp, *x, *y;
|
||||
input_reverse = (BYTE*) malloc(2 * key_length + exponent_size);
|
||||
|
||||
if (!input_reverse)
|
||||
return -1;
|
||||
|
||||
modulus_reverse = input_reverse + key_length;
|
||||
exponent_reverse = modulus_reverse + key_length;
|
||||
|
||||
memcpy(modulus_reverse, modulus, key_length);
|
||||
crypto_reverse(modulus_reverse, key_length);
|
||||
memcpy(exponent_reverse, exponent, exponent_size);
|
||||
@ -133,7 +135,6 @@ static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, c
|
||||
BN_bin2bn(exponent_reverse, exponent_size, exp);
|
||||
BN_bin2bn(input_reverse, length, x);
|
||||
BN_mod_exp(y, x, exp, mod, ctx);
|
||||
|
||||
output_length = BN_bn2bin(y, output);
|
||||
crypto_reverse(output, output_length);
|
||||
|
||||
@ -151,41 +152,47 @@ fail_bn_mod:
|
||||
BN_CTX_free(ctx);
|
||||
fail_bn_ctx:
|
||||
free(input_reverse);
|
||||
|
||||
return output_length;
|
||||
}
|
||||
|
||||
static int crypto_rsa_public(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, BYTE* output)
|
||||
static int crypto_rsa_public(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_common(input, length, key_length, modulus, exponent, EXPONENT_MAX_SIZE, output);
|
||||
}
|
||||
|
||||
static int crypto_rsa_private(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
static int crypto_rsa_private(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* private_exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_common(input, length, key_length, modulus, private_exponent, key_length, output);
|
||||
}
|
||||
|
||||
int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, BYTE* output)
|
||||
int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_public(input, length, key_length, modulus, exponent, output);
|
||||
}
|
||||
|
||||
int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, BYTE* output)
|
||||
int crypto_rsa_public_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_public(input, length, key_length, modulus, exponent, output);
|
||||
}
|
||||
|
||||
int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
int crypto_rsa_private_encrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_private(input, length, key_length, modulus, private_exponent, output);
|
||||
}
|
||||
|
||||
int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
int crypto_rsa_private_decrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_private(input, length, key_length, modulus, private_exponent, output);
|
||||
}
|
||||
|
||||
int crypto_rsa_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* private_exponent, BYTE* output)
|
||||
int crypto_rsa_decrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus,
|
||||
const BYTE* private_exponent, BYTE* output)
|
||||
{
|
||||
return crypto_rsa_common(input, length, key_length, modulus, private_exponent, key_length, output);
|
||||
}
|
||||
@ -210,21 +217,21 @@ char* crypto_cert_fingerprint(X509* xcert)
|
||||
char* fp_buffer;
|
||||
UINT32 fp_len;
|
||||
BYTE fp[EVP_MAX_MD_SIZE];
|
||||
|
||||
X509_digest(xcert, EVP_sha1(), fp, &fp_len);
|
||||
|
||||
fp_buffer = (char*) calloc(fp_len, 3);
|
||||
|
||||
if (!fp_buffer)
|
||||
return NULL;
|
||||
|
||||
p = fp_buffer;
|
||||
for (i = 0; i < (int) (fp_len - 1); i++)
|
||||
|
||||
for (i = 0; i < (int)(fp_len - 1); i++)
|
||||
{
|
||||
sprintf(p, "%02"PRIx8":", fp[i]);
|
||||
p = &fp_buffer[(i + 1) * 3];
|
||||
}
|
||||
sprintf(p, "%02"PRIx8"", fp[i]);
|
||||
|
||||
sprintf(p, "%02"PRIx8"", fp[i]);
|
||||
return fp_buffer;
|
||||
}
|
||||
|
||||
@ -237,13 +244,14 @@ char* crypto_print_name(X509_NAME* name)
|
||||
{
|
||||
unsigned long size = BIO_number_written(outBIO);
|
||||
buffer = calloc(1, size + 1);
|
||||
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
BIO_read(outBIO, buffer, size);
|
||||
}
|
||||
|
||||
BIO_free(outBIO);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@ -260,7 +268,6 @@ char* crypto_cert_subject_common_name(X509* xcert, int* length)
|
||||
X509_NAME* subject_name;
|
||||
X509_NAME_ENTRY* entry;
|
||||
ASN1_STRING* entry_data;
|
||||
|
||||
subject_name = X509_get_subject_name(xcert);
|
||||
|
||||
if (subject_name == NULL)
|
||||
@ -288,88 +295,459 @@ char* crypto_cert_subject_common_name(X509* xcert, int* length)
|
||||
|
||||
common_name = _strdup((char*)common_name_raw);
|
||||
OPENSSL_free(common_name_raw);
|
||||
|
||||
return (char*) common_name;
|
||||
}
|
||||
|
||||
void crypto_cert_subject_alt_name_free(int count, int *lengths,
|
||||
char** alt_name)
|
||||
|
||||
/* GENERAL_NAME type labels */
|
||||
|
||||
static const char* general_name_type_labels[] = { "OTHERNAME",
|
||||
"EMAIL ",
|
||||
"DNS ",
|
||||
"X400 ",
|
||||
"DIRNAME ",
|
||||
"EDIPARTY ",
|
||||
"URI ",
|
||||
"IPADD ",
|
||||
"RID "
|
||||
};
|
||||
|
||||
static const char* general_name_type_label(int general_name_type)
|
||||
{
|
||||
if ((0 <= general_name_type)
|
||||
&& (general_name_type < ARRAYSIZE(general_name_type_labels)))
|
||||
{
|
||||
return general_name_type_labels[general_name_type];
|
||||
}
|
||||
else
|
||||
{
|
||||
static char buffer[80];
|
||||
sprintf(buffer, "Unknown general name type (%d)", general_name_type);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
map_subject_alt_name(x509, general_name_type, mapper, data)
|
||||
|
||||
Call the function mapper with subjectAltNames found in the x509
|
||||
certificate and data. if generate_name_type is GEN_ALL, the the
|
||||
mapper is called for all the names, else it's called only for names
|
||||
of the given type.
|
||||
|
||||
|
||||
We implement two extractors:
|
||||
|
||||
- a string extractor that can be used to get the subjectAltNames of
|
||||
the following types: GEN_URI, GEN_DNS, GEN_EMAIL
|
||||
|
||||
- a ASN1_OBJECT filter/extractor that can be used to get the
|
||||
subjectAltNames of OTHERNAME type.
|
||||
|
||||
Note: usually, it's a string, but some type of otherNames can be
|
||||
associated with different classes of objects. eg. a KPN may be a
|
||||
sequence of realm and principal name, instead of a single string
|
||||
object.
|
||||
|
||||
Not implemented yet: extractors for the types: GEN_X400, GEN_DIRNAME,
|
||||
GEN_EDIPARTY, GEN_RID, GEN_IPADD (the later can contain nul-bytes).
|
||||
|
||||
|
||||
mapper(name, data, index, count)
|
||||
|
||||
The mapper is passed:
|
||||
- the GENERAL_NAME selected,
|
||||
- the data,
|
||||
- the index of the general name in the subjectAltNames,
|
||||
- the total number of names in the subjectAltNames.
|
||||
|
||||
The last parameter let's the mapper allocate arrays to collect objects.
|
||||
Note: if names are filtered, not all the indices from 0 to count-1 are
|
||||
passed to mapper, only the indices selected.
|
||||
|
||||
When the mapper returns 0, map_subject_alt_name stops the iteration immediately.
|
||||
|
||||
*/
|
||||
|
||||
#define GEN_ALL (-1)
|
||||
|
||||
typedef int (*general_name_mapper_pr)(GENERAL_NAME* name, void* data, int index, int count);
|
||||
|
||||
static void map_subject_alt_name(X509* x509, int general_name_type, general_name_mapper_pr mapper,
|
||||
void* data)
|
||||
{
|
||||
int i;
|
||||
int num;
|
||||
STACK_OF(GENERAL_NAME) *gens;
|
||||
gens = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
|
||||
|
||||
if (!gens)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
num = sk_GENERAL_NAME_num(gens);
|
||||
|
||||
for (i = 0; (i < num); i++)
|
||||
{
|
||||
GENERAL_NAME* name = sk_GENERAL_NAME_value(gens, i);
|
||||
|
||||
if (name)
|
||||
{
|
||||
if ((general_name_type == GEN_ALL) || (general_name_type == name->type))
|
||||
{
|
||||
if (!mapper(name, data, i, num))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
extract_string -- string extractor
|
||||
|
||||
- the strings array is allocated lazily, when we first have to store a
|
||||
string.
|
||||
|
||||
- allocated contains the size of the strings array, or -1 if
|
||||
allocation failed.
|
||||
|
||||
- count contains the actual count of strings in the strings array.
|
||||
|
||||
- maximum limits the number of strings we can store in the strings
|
||||
array: beyond, the extractor returns 0 to short-cut the search.
|
||||
|
||||
extract_string stores in the string list OPENSSL strings,
|
||||
that must be freed with OPENSSL_free.
|
||||
|
||||
*/
|
||||
|
||||
typedef struct string_list
|
||||
{
|
||||
char** strings;
|
||||
int allocated;
|
||||
int count;
|
||||
int maximum;
|
||||
} string_list;
|
||||
|
||||
static void string_list_initialize(string_list* list)
|
||||
{
|
||||
list->strings = 0;
|
||||
list->allocated = 0;
|
||||
list->count = 0;
|
||||
list->maximum = INT_MAX;
|
||||
}
|
||||
|
||||
static void string_list_allocate(string_list* list, int allocate_count)
|
||||
{
|
||||
if (!list->strings && list->allocated == 0)
|
||||
{
|
||||
list->strings = calloc(allocate_count, sizeof(list->strings[0]));
|
||||
list->allocated = list->strings ? allocate_count : -1;
|
||||
list->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void string_list_free(string_list* list)
|
||||
{
|
||||
/* Note: we don't free the contents of the strings array: this */
|
||||
/* is handled by the caller, either by returning this */
|
||||
/* content, or freeing it itself. */
|
||||
free(list->strings);
|
||||
}
|
||||
|
||||
static int extract_string(GENERAL_NAME* name, void* data, int index, int count)
|
||||
{
|
||||
string_list* list = data;
|
||||
unsigned char* cstring = 0;
|
||||
ASN1_STRING* str;
|
||||
|
||||
switch (name->type)
|
||||
{
|
||||
case GEN_URI:
|
||||
str = name->d.uniformResourceIdentifier;
|
||||
break;
|
||||
|
||||
case GEN_DNS:
|
||||
str = name->d.dNSName;
|
||||
break;
|
||||
|
||||
case GEN_EMAIL:
|
||||
str = name->d.rfc822Name;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((ASN1_STRING_to_UTF8(&cstring, str)) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "ASN1_STRING_to_UTF8() failed for %s: %s",
|
||||
general_name_type_label(name->type),
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return 1;
|
||||
}
|
||||
|
||||
string_list_allocate(list, count);
|
||||
|
||||
if (list->allocated <= 0)
|
||||
{
|
||||
OPENSSL_free(cstring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list->strings[list->count] = (char*)cstring;
|
||||
list->count ++ ;
|
||||
|
||||
if (list->count >= list->maximum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
extract_othername_object -- object extractor.
|
||||
|
||||
- the objects array is allocated lazily, when we first have to store a
|
||||
string.
|
||||
|
||||
- allocated contains the size of the objects array, or -1 if
|
||||
allocation failed.
|
||||
|
||||
- count contains the actual count of objects in the objects array.
|
||||
|
||||
- maximum limits the number of objects we can store in the objects
|
||||
array: beyond, the extractor returns 0 to short-cut the search.
|
||||
|
||||
extract_othername_objects stores in the objects array ASN1_TYPE *
|
||||
pointers directly obtained from the GENERAL_NAME.
|
||||
*/
|
||||
|
||||
typedef struct object_list
|
||||
{
|
||||
ASN1_OBJECT* type_id;
|
||||
char** strings;
|
||||
int allocated;
|
||||
int count;
|
||||
int maximum;
|
||||
} object_list;
|
||||
|
||||
static void object_list_initialize(object_list* list)
|
||||
{
|
||||
list->type_id = 0;
|
||||
list->strings = 0;
|
||||
list->allocated = 0;
|
||||
list->count = 0;
|
||||
list->maximum = INT_MAX;
|
||||
}
|
||||
|
||||
static void object_list_allocate(object_list* list, int allocate_count)
|
||||
{
|
||||
if (!list->strings && list->allocated == 0)
|
||||
{
|
||||
list->strings = calloc(allocate_count, sizeof(list->strings[0]));
|
||||
list->allocated = list->strings ? allocate_count : -1;
|
||||
list->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* object_string(ASN1_TYPE* object)
|
||||
{
|
||||
char* result;
|
||||
unsigned char* utf8String;
|
||||
int length;
|
||||
/* TODO: check that object.type is a string type. */
|
||||
length = ASN1_STRING_to_UTF8(& utf8String, object->value.asn1_string);
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = (char*)strdup((char*)utf8String);
|
||||
OPENSSL_free(utf8String);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void object_list_free(object_list* list)
|
||||
{
|
||||
free(list->strings);
|
||||
}
|
||||
|
||||
static int extract_othername_object_as_string(GENERAL_NAME* name, void* data, int index, int count)
|
||||
{
|
||||
object_list* list = data;
|
||||
|
||||
if (name->type != GEN_OTHERNAME)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 != OBJ_cmp(name->d.otherName->type_id, list->type_id))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
object_list_allocate(list, count);
|
||||
|
||||
if (list->allocated <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
list->strings[list->count] = object_string(name->d.otherName->value);
|
||||
|
||||
if (list->strings[list->count])
|
||||
{
|
||||
list->count ++ ;
|
||||
}
|
||||
|
||||
if (list->count >= list->maximum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
crypto_cert_get_email returns a dynamically allocated copy of the
|
||||
first email found in the subjectAltNames (use free to free it).
|
||||
*/
|
||||
|
||||
char* crypto_cert_get_email(X509* x509)
|
||||
{
|
||||
char* result = 0;
|
||||
string_list list;
|
||||
string_list_initialize(&list);
|
||||
list.maximum = 1;
|
||||
map_subject_alt_name(x509, GEN_EMAIL, extract_string, &list);
|
||||
|
||||
if (list.count == 0)
|
||||
{
|
||||
string_list_free(&list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strdup(list.strings[0]);
|
||||
OPENSSL_free(list.strings[0]);
|
||||
string_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
crypto_cert_get_upn returns a dynamically allocated copy of the
|
||||
first UPN otherNames in the subjectAltNames (use free to free it).
|
||||
Note: if this first UPN otherName is not a string, then 0 is returned,
|
||||
instead of searching for another UPN that would be a string.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
char* crypto_cert_get_upn(X509* x509)
|
||||
{
|
||||
char* result = 0;
|
||||
object_list list;
|
||||
object_list_initialize(&list);
|
||||
list.type_id = OBJ_nid2obj(NID_ms_upn);
|
||||
list.maximum = 1;
|
||||
map_subject_alt_name(x509, GEN_OTHERNAME, extract_othername_object_as_string, &list);
|
||||
|
||||
if (list.count == 0)
|
||||
{
|
||||
object_list_free(&list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = list.strings[0];
|
||||
object_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Deprecated name.*/
|
||||
void crypto_cert_subject_alt_name_free(int count, int *lengths, char** alt_names)
|
||||
{
|
||||
crypto_cert_dns_names_free(count, lengths, alt_names);
|
||||
}
|
||||
|
||||
void crypto_cert_dns_names_free(int count, int* lengths,
|
||||
char** dns_names)
|
||||
{
|
||||
free(lengths);
|
||||
|
||||
if (alt_name)
|
||||
if (dns_names)
|
||||
{
|
||||
for (i=0; i<count; i++)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (alt_name[i])
|
||||
OPENSSL_free(alt_name[i]);
|
||||
if (dns_names[i])
|
||||
{
|
||||
OPENSSL_free(dns_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(alt_name);
|
||||
free(dns_names);
|
||||
}
|
||||
}
|
||||
|
||||
/* Deprecated name.*/
|
||||
char** crypto_cert_subject_alt_name(X509* xcert, int* count, int** lengths)
|
||||
{
|
||||
int index;
|
||||
int length = 0;
|
||||
char** strings = NULL;
|
||||
BYTE* string;
|
||||
int num_subject_alt_names;
|
||||
GENERAL_NAMES* subject_alt_names;
|
||||
GENERAL_NAME* subject_alt_name;
|
||||
|
||||
*count = 0;
|
||||
subject_alt_names = X509_get_ext_d2i(xcert, NID_subject_alt_name, 0, 0);
|
||||
|
||||
if (!subject_alt_names)
|
||||
return NULL;
|
||||
|
||||
num_subject_alt_names = sk_GENERAL_NAME_num(subject_alt_names);
|
||||
if (num_subject_alt_names)
|
||||
{
|
||||
strings = (char**) calloc(num_subject_alt_names, sizeof(char*));
|
||||
if (!strings)
|
||||
goto out;
|
||||
|
||||
*lengths = (int*) calloc(num_subject_alt_names, sizeof(int));
|
||||
if (!*lengths)
|
||||
{
|
||||
free(strings);
|
||||
strings = NULL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < num_subject_alt_names; ++index)
|
||||
{
|
||||
subject_alt_name = sk_GENERAL_NAME_value(subject_alt_names, index);
|
||||
|
||||
if (subject_alt_name->type == GEN_DNS)
|
||||
{
|
||||
length = ASN1_STRING_to_UTF8(&string, subject_alt_name->d.dNSName);
|
||||
strings[*count] = (char*) string;
|
||||
(*lengths)[*count] = length;
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
|
||||
if (*count < 1)
|
||||
{
|
||||
free(strings) ;
|
||||
free(*lengths) ;
|
||||
*lengths = NULL ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
GENERAL_NAMES_free(subject_alt_names);
|
||||
|
||||
return strings;
|
||||
return crypto_cert_get_dns_names(xcert, count, lengths);
|
||||
}
|
||||
|
||||
char** crypto_cert_get_dns_names(X509* x509, int* count, int** lengths)
|
||||
{
|
||||
int i;
|
||||
char** result = 0;
|
||||
string_list list;
|
||||
string_list_initialize(&list);
|
||||
map_subject_alt_name(x509, GEN_DNS, extract_string, &list);
|
||||
(*count) = list.count;
|
||||
|
||||
if (list.count == 0)
|
||||
{
|
||||
string_list_free(&list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* lengths are not useful, since we converted the
|
||||
strings to utf-8, there cannot be nul-bytes in them. */
|
||||
result = calloc(list.count, sizeof(*result));
|
||||
(*lengths) = calloc(list.count, sizeof(**lengths));
|
||||
|
||||
if (!result || !(*lengths))
|
||||
{
|
||||
free(result);
|
||||
free(*lengths);
|
||||
(*lengths) = 0;
|
||||
(*count) = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
for (i = 0; i < list.count; i ++)
|
||||
{
|
||||
result[i] = list.strings[i];
|
||||
(*lengths)[i] = strlen(result[i]);
|
||||
}
|
||||
|
||||
string_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char* crypto_cert_issuer(X509* xcert)
|
||||
{
|
||||
return crypto_print_name(X509_get_issuer_name(xcert));
|
||||
@ -382,7 +760,6 @@ BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path)
|
||||
X509_STORE* cert_ctx = NULL;
|
||||
X509_LOOKUP* lookup = NULL;
|
||||
X509* xcert = cert->px509;
|
||||
|
||||
cert_ctx = X509_STORE_new();
|
||||
|
||||
if (cert_ctx == NULL)
|
||||
@ -392,10 +769,9 @@ BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path)
|
||||
OpenSSL_add_all_algorithms();
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS \
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS \
|
||||
| OPENSSL_INIT_LOAD_CONFIG, NULL);
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS \
|
||||
| OPENSSL_INIT_LOAD_CONFIG, NULL);
|
||||
#endif
|
||||
|
||||
lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
|
||||
|
||||
if (lookup == NULL)
|
||||
@ -428,7 +804,6 @@ BOOL x509_verify_certificate(CryptoCert cert, char* certificate_store_path)
|
||||
|
||||
X509_STORE_CTX_free(csc);
|
||||
X509_STORE_free(cert_ctx);
|
||||
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
@ -439,20 +814,17 @@ rdpCertificateData* crypto_get_certificate_data(X509* xcert, char* hostname, UIN
|
||||
char* subject;
|
||||
char* fp;
|
||||
rdpCertificateData* certdata;
|
||||
|
||||
fp = crypto_cert_fingerprint(xcert);
|
||||
|
||||
if (!fp)
|
||||
return NULL;
|
||||
|
||||
issuer = crypto_cert_issuer(xcert);
|
||||
subject = crypto_cert_subject(xcert);
|
||||
|
||||
certdata = certificate_data_new(hostname, port, issuer, subject, fp);
|
||||
|
||||
free(subject);
|
||||
free(issuer);
|
||||
free(fp);
|
||||
|
||||
return certdata;
|
||||
}
|
||||
|
||||
@ -461,10 +833,10 @@ void crypto_cert_print_info(X509* xcert)
|
||||
char* fp;
|
||||
char* issuer;
|
||||
char* subject;
|
||||
|
||||
subject = crypto_cert_subject(xcert);
|
||||
issuer = crypto_cert_issuer(xcert);
|
||||
fp = crypto_cert_fingerprint(xcert);
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
WLog_ERR(TAG, "error computing fingerprint");
|
||||
@ -475,9 +847,10 @@ void crypto_cert_print_info(X509* xcert)
|
||||
WLog_INFO(TAG, "\tSubject: %s", subject);
|
||||
WLog_INFO(TAG, "\tIssuer: %s", issuer);
|
||||
WLog_INFO(TAG, "\tThumbprint: %s", fp);
|
||||
WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"the CA certificate in your certificate store, or the certificate has expired. "
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.");
|
||||
WLog_INFO(TAG,
|
||||
"The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"the CA certificate in your certificate store, or the certificate has expired. "
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.");
|
||||
free(fp);
|
||||
out_free_issuer:
|
||||
free(issuer);
|
||||
|
@ -6,7 +6,8 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestKnownHosts.c
|
||||
TestBase64.c)
|
||||
TestBase64.c
|
||||
Test_x509_cert_info.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
@ -16,7 +17,7 @@ include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} freerdp winpr)
|
||||
target_link_libraries(${MODULE_NAME} freerdp winpr ${OPENSSL_LIBRARIES})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
|
169
libfreerdp/crypto/test/Test_x509_cert_info.c
Normal file
169
libfreerdp/crypto/test/Test_x509_cert_info.c
Normal file
@ -0,0 +1,169 @@
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
|
||||
typedef char* (*get_field_pr)(X509*);
|
||||
typedef struct
|
||||
{
|
||||
enum
|
||||
{
|
||||
DISABLED, ENABLED,
|
||||
} status;
|
||||
const char* field_description;
|
||||
get_field_pr get_field;
|
||||
const char* expected_result;
|
||||
} certificate_test_t;
|
||||
|
||||
char* crypto_cert_subject_common_name_wo_length(X509* xcert)
|
||||
{
|
||||
int length;
|
||||
return crypto_cert_subject_common_name(xcert, & length);
|
||||
}
|
||||
|
||||
const char* certificate_path()
|
||||
{
|
||||
/*
|
||||
Assume the .pem file is in the same directory as this source file.
|
||||
Assume that __FILE__ will be a valid path to this file, even from the current working directory where the tests are run.
|
||||
(ie. no chdir occurs between compilation and test running, or __FILE__ is an absolute path).
|
||||
*/
|
||||
|
||||
#if defined(_WIN32)
|
||||
static const char dirsep = '\\';
|
||||
#else
|
||||
static const char dirsep = '/';
|
||||
#endif
|
||||
static const char * filename = "Test_x509_cert_info.pem";
|
||||
const char * file = __FILE__;
|
||||
const char * last_dirsep = strrchr(file, dirsep);
|
||||
if (last_dirsep)
|
||||
{
|
||||
char * result = malloc(last_dirsep - file + 1 + strlen(filename) + 1);
|
||||
strncpy(result, file, (last_dirsep - file + 1));
|
||||
strcpy(result + (last_dirsep - file + 1), filename);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No dirsep => relative path in same directory */
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
const certificate_test_t certificate_tests[] =
|
||||
{
|
||||
|
||||
{
|
||||
ENABLED,
|
||||
"Certificate Common Name",
|
||||
crypto_cert_subject_common_name_wo_length,
|
||||
"TESTJEAN TESTMARTIN 9999999"
|
||||
},
|
||||
|
||||
{
|
||||
ENABLED,
|
||||
"Certificate subject",
|
||||
crypto_cert_subject,
|
||||
"CN = TESTJEAN TESTMARTIN 9999999, C = FR, O = MINISTERE DES TESTS, OU = 0002 110014016, OU = PERSONNES, UID = 9999999, GN = TESTJEAN, SN = TESTMARTIN"
|
||||
},
|
||||
|
||||
{
|
||||
DISABLED,
|
||||
"Kerberos principal name",
|
||||
0,
|
||||
"testjean.testmartin@kpn.test.example.com"
|
||||
},
|
||||
|
||||
{
|
||||
ENABLED,
|
||||
"Certificate e-mail",
|
||||
crypto_cert_get_email,
|
||||
"testjean.testmartin@test.example.com"
|
||||
},
|
||||
|
||||
{
|
||||
ENABLED,
|
||||
"Microsoft's Universal Principal Name",
|
||||
crypto_cert_get_upn,
|
||||
"testjean.testmartin.9999999@upn.test.example.com"
|
||||
},
|
||||
|
||||
{
|
||||
ENABLED,
|
||||
"Certificate issuer",
|
||||
crypto_cert_issuer,
|
||||
"CN = ADMINISTRATION CENTRALE DES TESTS, C = FR, O = MINISTERE DES TESTS, OU = 0002 110014016"
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
int TestCertificateFile(const char* certificate_path, const certificate_test_t* certificate_tests,
|
||||
int count)
|
||||
{
|
||||
X509* certificate;
|
||||
FILE* certificate_file = fopen(certificate_path, "r");
|
||||
int success = 0;
|
||||
int i;
|
||||
|
||||
if (!certificate_file)
|
||||
{
|
||||
printf("%s: failure: cannot open certificate file '%s'\n", __FUNCTION__, certificate_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
certificate = PEM_read_X509(certificate_file, 0, 0, 0);
|
||||
|
||||
if (!certificate)
|
||||
{
|
||||
printf("%s: failure: cannot read certificate file '%s'\n", __FUNCTION__, certificate_path);
|
||||
success = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i ++)
|
||||
{
|
||||
char* result;
|
||||
|
||||
if (certificate_tests[i].status == DISABLED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = (certificate_tests[i].get_field
|
||||
? certificate_tests[i].get_field(certificate)
|
||||
: 0);
|
||||
|
||||
if (result)
|
||||
{
|
||||
printf("%s: crypto got %-40s -> \"%s\"\n", __FUNCTION__,
|
||||
certificate_tests[i].field_description,
|
||||
result);
|
||||
|
||||
if (0 != strcmp(result, certificate_tests[i].expected_result))
|
||||
{
|
||||
printf("%s: failure: for %s, actual: \"%s\", expected \"%s\"\n",
|
||||
__FUNCTION__,
|
||||
certificate_tests[i].field_description,
|
||||
result,
|
||||
certificate_tests[i].expected_result);
|
||||
success = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: failure: cannot get %s\n", __FUNCTION__,
|
||||
certificate_tests[i].field_description);
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
fclose(certificate_file);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
int Test_x509_cert_info(int argc, char* argv[])
|
||||
{
|
||||
return TestCertificateFile(certificate_path(), certificate_tests, ARRAYSIZE(certificate_tests));
|
||||
}
|
||||
|
41
libfreerdp/crypto/test/Test_x509_cert_info.pem
Normal file
41
libfreerdp/crypto/test/Test_x509_cert_info.pem
Normal file
@ -0,0 +1,41 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHNzCCBR+gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwcDEqMCgGA1UEAwwhQURN
|
||||
SU5JU1RSQVRJT04gQ0VOVFJBTEUgREVTIFRFU1RTMQswCQYDVQQGEwJGUjEcMBoG
|
||||
A1UECgwTTUlOSVNURVJFIERFUyBURVNUUzEXMBUGA1UECwwOMDAwMiAxMTAwMTQw
|
||||
MTYwHhcNMTgwNTE4MDkyNTU1WhcNMTkwNTEzMDkyNTU1WjCBvzEkMCIGA1UEAwwb
|
||||
VEVTVEpFQU4gVEVTVE1BUlRJTiA5OTk5OTk5MQswCQYDVQQGEwJGUjEcMBoGA1UE
|
||||
CgwTTUlOSVNURVJFIERFUyBURVNUUzEXMBUGA1UECwwOMDAwMiAxMTAwMTQwMTYx
|
||||
EjAQBgNVBAsMCVBFUlNPTk5FUzEXMBUGCgmSJomT8ixkAQEMBzk5OTk5OTkxETAP
|
||||
BgNVBCoMCFRFU1RKRUFOMRMwEQYDVQQEDApURVNUTUFSVElOMIICIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAg8AMIICCgKCAgEA3yc22RDYc+Vc6F26/LONvaYkdTVDiCgbh9Ik
|
||||
6pLF5izNpfdQ/YZU25h/UPECdchYX31UEErVOYudOBOHtU4fNjTO0oK5Va/DoFln
|
||||
LnfwNpAlBZfogG+yy8fK4yLxG+raoSKDR/5P3hmTqKJqw1WpkwcVE2EDqkP1clMZ
|
||||
L5cvJj6gLJa2q0JCdoKe7NntZkgpIk5ZHUZm2JYC30xL7XHfvvb/i0OZLpPOIekT
|
||||
DCzxr9HTjbqe+BRZix2UiGpXzjIlDm6EEQNebZqf5kKgcbkxIDWcVraE0kO3TqJI
|
||||
P4FBUeuxLqGwQ0AMKrZ+j8U7KAoM9WUoIFcmm8nYGo4hT6ugNIQ9nwQSgyH3yGH1
|
||||
PU2k12Ovv2Ft8C/IFuusXxTOJprcFxtjE7qYZ44tmvlozlDOBOJYjLiURAh3r5LL
|
||||
TadgArZ3XVMyWlwlTEy9qX59izY9Zz27kd5H11DOz5ezopHAWwP6sgCvWeNDyx8Q
|
||||
I3jY8TYzJHahN2bknP2fqwwdGqFCrHItJx2DhDe2ruTk6vvbnwGgYqGzv+RtdNbW
|
||||
CL4IMEQQKG9AM40WCz9pu32/vOaQ+hrYyCQMCtli0DSauB+K2IFPsAcz5OAaITJv
|
||||
LenMt8mUP9NWHWfr5WYm0tuUCCU4dUT38MqkkdQv7oly1LHkvUdMU+Nk/Ki0Q83U
|
||||
9gMvaPcCAwEAAaOCAYkwggGFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXg
|
||||
MDIGA1UdJQQrMCkGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQCAgYHKwYB
|
||||
BQIDBDAdBgNVHQ4EFgQUXs4RKN+vUVsZjEW/J6qo6EZTLZUwHwYDVR0jBBgwFoAU
|
||||
fUXj4k7OA3d8KylcprhMptiOL10wgbIGA1UdEQSBqjCBp6A9BgYrBgEFAgKgMzAx
|
||||
oBYbFGtwbi50ZXN0LmV4YW1wbGUuY29toRcwFRsTdGVzdGplYW4udGVzdG1hcnRp
|
||||
bqBABgorBgEEAYI3FAIDoDIMMHRlc3RqZWFuLnRlc3RtYXJ0aW4uOTk5OTk5OUB1
|
||||
cG4udGVzdC5leGFtcGxlLmNvbYEkdGVzdGplYW4udGVzdG1hcnRpbkB0ZXN0LmV4
|
||||
YW1wbGUuY29tMDEGA1UdEgQqMCiCEnJvb3RjYS5leGFtcGxlLmNvbYISaW50ZWNh
|
||||
LmV4YW1wbGUuY29tMAkGA1UdIAQCMAAwDQYJKoZIhvcNAQEFBQADggIBAKRDovf+
|
||||
CCnV2mtXnzH5JlduOjPWJmGB5a8HLPvakfAm4wQ0YyAViE1tar0V9lhG6nCogWWa
|
||||
28D+eM5vLPjVE8ebq5UjIv76x6gWoJkQ3HtfVJvn9UfXwax6IqT7hb1fAHBqu0rj
|
||||
uSnSxf1wIzPMp9Lb5x3jBu9ryNMiLUzeY1slBvosOXKlmprPhGWfPYYNCZo2bGJI
|
||||
1w5alGDgTBcWKl7icJjAIuCpyRTnKCsaN3kyDU7C5aUhsm9AriPiNErzRI+l5+eu
|
||||
Ywg3MZ7Yfjd3rXb6JleT0ZnCh/nFtVLIccWaI4phCrYTGz6odNIqrZ6X23Pt6Rx3
|
||||
ZbQjtj4ipMdvbvJbS90aFMrTyfqhVLOxHy+setDcmPOixUgXlx8ZjFI9vgFUeJbo
|
||||
OKrkLw4ITUduO+9MplBX7Kt/iCS/CbTfPlHMv03Xb6rbjqHxTJZCCu5QMNHiBeHV
|
||||
l8FK5R6gv+9FuCl8uPHwGh/jelQp51cVORlQWeKpqWdwTi0Q3VeVeQAG5RR34xgT
|
||||
cQa8h9AqkxYajhxKUmbUlaoYGd8TwUQLrS2jZxp/9geyApVQLAQ27CyAK5HyHSCA
|
||||
uqCKsM0gFQyCL4IbXQyFMWgjXZYaorHFjVuMhYEkgWui/9sv+7sMAV5JzROeAw3l
|
||||
4+D7yhywwuRzH2SzoavzGpWGMUveVsdLMRk9
|
||||
-----END CERTIFICATE-----
|
@ -1295,9 +1295,9 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
|
||||
int index;
|
||||
char* common_name = NULL;
|
||||
int common_name_length = 0;
|
||||
char** alt_names = NULL;
|
||||
int alt_names_count = 0;
|
||||
int* alt_names_lengths = NULL;
|
||||
char** dns_names = 0;
|
||||
int dns_names_count = 0;
|
||||
int* dns_names_lengths = NULL;
|
||||
BOOL certificate_status;
|
||||
BOOL hostname_match = FALSE;
|
||||
BOOL verification_status = FALSE;
|
||||
@ -1367,8 +1367,8 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
|
||||
certificate_data = crypto_get_certificate_data(cert->px509, hostname, port);
|
||||
/* extra common name and alternative names */
|
||||
common_name = crypto_cert_subject_common_name(cert->px509, &common_name_length);
|
||||
alt_names = crypto_cert_subject_alt_name(cert->px509, &alt_names_count,
|
||||
&alt_names_lengths);
|
||||
dns_names = crypto_cert_get_dns_names(cert->px509, &dns_names_count,
|
||||
&dns_names_lengths);
|
||||
|
||||
/* compare against common name */
|
||||
|
||||
@ -1380,11 +1380,11 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
|
||||
|
||||
/* compare against alternative names */
|
||||
|
||||
if (alt_names)
|
||||
if (dns_names)
|
||||
{
|
||||
for (index = 0; index < alt_names_count; index++)
|
||||
for (index = 0; index < dns_names_count; index++)
|
||||
{
|
||||
if (tls_match_hostname(alt_names[index], alt_names_lengths[index], hostname))
|
||||
if (tls_match_hostname(dns_names[index], dns_names_lengths[index], hostname))
|
||||
{
|
||||
hostname_match = TRUE;
|
||||
break;
|
||||
@ -1415,8 +1415,8 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
|
||||
if (!hostname_match)
|
||||
tls_print_certificate_name_mismatch_error(
|
||||
hostname, port,
|
||||
common_name, alt_names,
|
||||
alt_names_count);
|
||||
common_name, dns_names,
|
||||
dns_names_count);
|
||||
|
||||
/* Automatically accept certificate on first use */
|
||||
if (tls->settings->AutoAcceptCertificate)
|
||||
@ -1508,9 +1508,9 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
|
||||
certificate_data_free(certificate_data);
|
||||
free(common_name);
|
||||
|
||||
if (alt_names)
|
||||
crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths,
|
||||
alt_names);
|
||||
if (dns_names)
|
||||
crypto_cert_dns_names_free(dns_names_count, dns_names_lengths,
|
||||
dns_names);
|
||||
|
||||
if (verification_status > 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user