PermissionsHandle* Permissions::validate_remote_permissions(
        Authentication&,
        const IdentityHandle& local_identity_handle,
        const PermissionsHandle& local_permissions_handle,
        const IdentityHandle& remote_identity_handle,
        const PermissionsToken& remote_permissions_token,
        const PermissionsCredentialToken& remote_credential_token,
        SecurityException& exception)
{
    const PKIIdentityHandle& lih = PKIIdentityHandle::narrow(local_identity_handle);
    const AccessPermissionsHandle& lph = AccessPermissionsHandle::narrow(local_permissions_handle);
    const PKIIdentityHandle& rih = PKIIdentityHandle::narrow(remote_identity_handle);

    if (lih.nil() || lph.nil() || rih.nil())
    {
        exception = _SecurityException_("Bad precondition");
        EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
        return nullptr;
    }

    // Check permissions.
    // Check c.id
    const std::string* sn = DataHolderHelper::find_property_value(remote_permissions_token, "dds.perm_ca.sn");

    if (sn != nullptr)
    {
        if (sn->compare(lph->sn) != 0)
        {
            exception = _SecurityException_("Remote participant PermissionsCA differs from local");
            EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
            return nullptr;
        }
    }

    const std::string* algo = DataHolderHelper::find_property_value(remote_permissions_token, "dds.perm_ca.algo");

    if (algo != nullptr)
    {
        if (algo->compare(lph->algo) != 0)
        {
            exception = _SecurityException_("Remote participant PermissionsCA algorithm differs from local");
            EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
            return nullptr;
        }
    }

    const std::string* permissions_file = DataHolderHelper::find_property_value(remote_credential_token,
                    "dds.perm.cert");

    if (permissions_file == nullptr)
    {
        exception = _SecurityException_("Remote participant doesn't sent the signed permissions file");
        EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
        return nullptr;
    }

    PermissionsData data;
    if (!verify_permissions_file(lph, *permissions_file, data, exception))
    {
        return nullptr;
    }

    Grant remote_grant;
    for (auto grant : data.grants)
    {
        if (is_validation_in_time(grant.validity))
        {
            if (rfc2253_string_compare(grant.subject_name, rih->cert_sn_rfc2253_) ||
                    strcmp(grant.subject_name.c_str(), rih->cert_sn_.c_str()) == 0)
            {
                remote_grant = std::move(grant);
                break;
            }
        }
    }

    if (remote_grant.subject_name.empty())
    {
        exception = _SecurityException_("Remote participant doesn't found in its permissions file");
        EMERGENCY_SECURITY_LOGGING("Permissions", exception.what());
        return nullptr;
    }

    AccessPermissionsHandle* handle =  new AccessPermissionsHandle();
    (*handle)->grant = std::move(remote_grant);
    (*handle)->governance_rule_ = lph->governance_rule_;
    (*handle)->governance_topic_rules_ = lph->governance_topic_rules_;

    return handle;
}