extern "C" {
#endif
+/* Flags used by certificate callbacks */
+#define VERIFY_CERT_FLAG_NONE 0x00
+#define VERIFY_CERT_FLAG_LEGACY 0x02
+#define VERIFY_CERT_FLAG_REDIRECT 0x10
+#define VERIFY_CERT_FLAG_GATEWAY 0x20
+#define VERIFY_CERT_FLAG_CHANGED 0x40
+#define VERIFY_CERT_FLAG_MISMATCH 0x80
+
typedef BOOL (*pContextNew)(freerdp* instance, rdpContext* context);
typedef void (*pContextFree)(freerdp* instance, rdpContext* context);
/** @brief Callback used if user interaction is required to accept
* an unknown certificate.
*
+ * @deprecated Use pVerifyCertificateEx
* @param common_name The certificate registered hostname.
* @param subject The common name of the certificate.
* @param issuer The issuer of the certificate.
BOOL host_mismatch);
/** @brief Callback used if user interaction is required to accept
+ * an unknown certificate.
+ *
+ * @param host The hostname connecting to.
+ * @param port The port connecting to.
+ * @param common_name The certificate registered hostname.
+ * @param subject The common name of the certificate.
+ * @param issuer The issuer of the certificate.
+ * @param fingerprint The fingerprint of the certificate.
+ * @param flags Flags of type VERIFY_CERT_FLAG*
+ *
+ * @return 1 to accept and store a certificate, 2 to accept
+ * a certificate only for this session, 0 otherwise.
+ */
+typedef DWORD (*pVerifyCertificateEx)(freerdp* instance,
+ const char* host,
+ UINT16 port,
+ const char* common_name,
+ const char* subject,
+ const char* issuer,
+ const char* fingerprint,
+ DWORD flags);
+
+/** @brief Callback used if user interaction is required to accept
* a changed certificate.
*
+ * @deprecated Use pVerifyChangedCertificateEx
* @param common_name The certificate registered hostname.
* @param subject The common name of the new certificate.
* @param issuer The issuer of the new certificate.
const char* old_issuer,
const char* old_fingerprint);
+/** @brief Callback used if user interaction is required to accept
+ * a changed certificate.
+ *
+ * @param host The hostname connecting to.
+ * @param port The port connecting to.
+ * @param common_name The certificate registered hostname.
+ * @param subject The common name of the new certificate.
+ * @param issuer The issuer of the new certificate.
+ * @param fingerprint The fingerprint of the new certificate.
+ * @param old_subject The common name of the old certificate.
+ * @param old_issuer The issuer of the new certificate.
+ * @param old_fingerprint The fingerprint of the old certificate.
+ * @param flags Flags of type VERIFY_CERT_FLAG*
+ *
+ * @return 1 to accept and store a certificate, 2 to accept
+ * a certificate only for this session, 0 otherwise.
+ */
-#define VERIFY_X509_CERT_FLAG_NONE 0x00
-#define VERIFY_X509_CERT_FLAG_LEGACY 0x02
-#define VERIFY_X509_CERT_FLAG_REDIRECT 0x10
-#define VERIFY_X509_CERT_FLAG_GATEWAY 0x20
-#define VERIFY_X509_CERT_FLAG_CHANGED 0x40
-#define VERIFY_X509_CERT_FLAG_MISMATCH 0x80
+typedef DWORD (*pVerifyChangedCertificateEx)(freerdp* instance,
+ const char* host,
+ UINT16 port,
+ const char* common_name,
+ const char* subject,
+ const char* issuer,
+ const char* new_fingerprint,
+ const char* old_subject,
+ const char* old_issuer,
+ const char* old_fingerprint,
+ DWORD flags);
/** @brief Callback used if user interaction is required to accept
* a certificate.
* @param length The length of the certificate data.
* @param hostname The hostname connecting to.
* @param port The port connecting to.
- * @param flags The issuer of the new certificate.
+ * @param flags Flags of type VERIFY_CERT_FLAG*
*
* @return 1 to accept and store a certificate, 2 to accept
* a certificate only for this session, 0 otherwise.
It is used to get the username/password when it was not provided at connection time. */
ALIGN64 pVerifyCertificate VerifyCertificate; /**< (offset 51)
Callback for certificate validation.
- Used to verify that an unknown certificate is trusted. */
+ Used to verify that an unknown certificate is trusted.
+ DEPRECATED: Use VerifyChangedCertificateEx*/
ALIGN64 pVerifyChangedCertificate VerifyChangedCertificate; /**< (offset 52)
Callback for changed certificate validation.
Used when a certificate differs from stored fingerprint.
- If returns TRUE, the new fingerprint will be trusted and old thrown out. */
+ DEPRECATED: Use VerifyChangedCertificateEx */
ALIGN64 pVerifyX509Certificate
VerifyX509Certificate; /**< (offset 53) Callback for X509 certificate verification (PEM format) */
This is called by freerdp_channel_process() (if not NULL).
Clients will typically use a function that calls freerdp_channels_data() to perform the needed tasks. */
- UINT64 paddingE[80 - 66]; /* 66 */
+ ALIGN64 pVerifyCertificateEx VerifyCertificateEx; /**< (offset 66)
+ Callback for certificate validation.
+ Used to verify that an unknown certificate is trusted. */
+ ALIGN64 pVerifyChangedCertificateEx VerifyChangedCertificateEx; /**< (offset 67)
+ Callback for changed certificate validation.
+ Used when a certificate differs from stored fingerprint. */
+ UINT64 paddingE[80 - 68]; /* 68 */
};
struct rdp_channel_handles
BOOL certificate_status;
BOOL hostname_match = FALSE;
BOOL verification_status = FALSE;
- rdpCertificateData* certificate_data;
+ rdpCertificateData* certificate_data = NULL;
freerdp* instance = (freerdp*) tls->settings->instance;
DWORD length;
- BYTE* pemCert;
- DWORD flags = VERIFY_X509_CERT_FLAG_NONE;
+ BYTE* pemCert = NULL;
+ DWORD flags = VERIFY_CERT_FLAG_NONE;
if (!tls_extract_pem(cert, &pemCert, &length))
- return -1;
+ goto end;
/* Check, if we already accepted this key. */
if (is_accepted(tls, pemCert, length))
- {
- free(pemCert);
- return 1;
- }
+ goto end;
if (tls->isGatewayTransport || is_redirected(tls))
- flags |= VERIFY_X509_CERT_FLAG_LEGACY;
+ flags |= VERIFY_CERT_FLAG_LEGACY;
if (tls->isGatewayTransport)
- flags |= VERIFY_X509_CERT_FLAG_GATEWAY;
+ flags |= VERIFY_CERT_FLAG_GATEWAY;
if (is_redirected(tls))
- flags |= VERIFY_X509_CERT_FLAG_REDIRECT;
+ flags |= VERIFY_CERT_FLAG_REDIRECT;
if (tls->settings->ExternalCertificateManagement)
{
WLog_ERR(TAG, "No VerifyX509Certificate callback registered!");
if (status > 0)
- {
accept_cert(tls, pemCert, length);
- }
else if (status < 0)
{
WLog_ERR(TAG, "VerifyX509Certificate failed: (length = %d) status: [%d] %s",
length, status, pemCert);
- free(pemCert);
- return -1;
+ goto end;
}
- else
- free(pemCert);
- return (status == 0) ? 0 : 1;
+ verification_status = (status == 0) ? FALSE : TRUE;
+ goto end;
}
/* ignore certificate verification if user explicitly required it (discouraged) */
if (tls->settings->IgnoreCertificate)
{
- free(pemCert);
- return 1; /* success! */
+ verification_status = TRUE;
+ goto end; /* success! */
}
if (!tls->isGatewayTransport && tls->settings->AuthenticationLevel == 0)
{
- free(pemCert);
- return 1; /* success! */
+ verification_status = TRUE;
+ goto end; /* success! */
}
/* if user explicitly specified a certificate name, use it instead of the hostname */
verification_status = TRUE; /* success! */
if (!hostname_match)
- flags |= VERIFY_X509_CERT_FLAG_MISMATCH;
+ flags |= VERIFY_CERT_FLAG_MISMATCH;
/* verification could not succeed with OpenSSL, use known_hosts file and prompt user for manual verification */
if (!certificate_status || !hostname_match)
else
accept_certificate = 0;
}
+ else if (instance->VerifyCertificateEx)
+ {
+ accept_certificate = instance->VerifyCertificateEx(
+ instance, hostname, port, common_name,
+ subject, issuer,
+ fingerprint, flags);
+ }
else if (instance->VerifyCertificate)
{
accept_certificate = instance->VerifyCertificate(
if (instance->VerifyX509Certificate)
{
const int rc = instance->VerifyX509Certificate(instance, pemCert, length, hostname,
- port, flags | VERIFY_X509_CERT_FLAG_CHANGED);
+ port, flags | VERIFY_CERT_FLAG_CHANGED);
if (rc == 1)
accept_certificate = 1;
else
accept_certificate = 0;
}
+ else if (instance->VerifyChangedCertificateEx)
+ {
+ accept_certificate = instance->VerifyChangedCertificateEx(
+ instance, hostname, port, common_name, subject, issuer,
+ fingerprint, old_subject, old_issuer,
+ old_fingerprint, flags | VERIFY_CERT_FLAG_CHANGED);
+ }
else if (instance->VerifyChangedCertificate)
{
accept_certificate = instance->VerifyChangedCertificate(
free(fingerprint);
}
+ if (verification_status > 0)
+ accept_cert(tls, pemCert, length);
+
+end:
certificate_data_free(certificate_data);
free(common_name);
crypto_cert_dns_names_free(dns_names_count, dns_names_lengths,
dns_names);
- if (verification_status > 0)
- {
- accept_cert(tls, pemCert, length);
- }
- else
- {
- free(pemCert);
- }
-
+ free(pemCert);
return (verification_status == 0) ? 0 : 1;
}