Added some security documentation.
Signed-off-by: Martin Bremmer <martin.bremmer@adlinktech.com>
This commit is contained in:
parent
91111af0ea
commit
514bf75276
6 changed files with 1052 additions and 0 deletions
406
docs/dev/dds_security_effort.md
Normal file
406
docs/dev/dds_security_effort.md
Normal file
|
@ -0,0 +1,406 @@
|
|||
# DDS Security effort
|
||||
|
||||
ADLink has decided to donate their Vortex OpenSplice DDS Security
|
||||
implementation to the Cyclone DDS project. However, that will not be a simple
|
||||
code drop.
|
||||
|
||||
This document catches all the work that is foreseen to port Vortex OpenSplice
|
||||
DDS Security to Cyclone DDS.
|
||||
|
||||
This document can be removed when DDS Security has been implemented.
|
||||
|
||||
**Table of contents**
|
||||
- [Definition of done](#done)
|
||||
- [Footprint](#footprint)
|
||||
- [Multi process testing (done)](#testing)
|
||||
- [Runtime library loading (done)](#loading)
|
||||
- [Hopscotch utility (done)](#hopscotch)
|
||||
- [FSM utility (in progress)](#fsm)
|
||||
- [Port DDS Security plugin API (done)](#port-api)
|
||||
- [De-Serializing messages in DDSI (done)](#deserializing)
|
||||
- [De-Serializing security message parameters in DDSI (done)](#deserializing_plist)
|
||||
- [Port DDS Security builtin plugins (in progress)](#port-plugins)
|
||||
- [Port DDSI DDS Security (in progress)](#port-ddsi)
|
||||
- [Move configuration (in progress)](#Move-configuration)
|
||||
- [Failure handling](#failures)
|
||||
- [Multiple configurations](#multiple-configurations)
|
||||
- [Example](#example)
|
||||
- [QosProvider](#qosprovider)
|
||||
- [Data Tags (optional)](#datatags)
|
||||
|
||||
|
||||
## Definition of done<a name="done" />
|
||||
|
||||
When this document tells that a certain aspect is 'done', it means that it
|
||||
has been accepted into the security branch of the cyclonedds repository
|
||||
(https://github.com/eclipse-cyclonedds/cyclonedds/tree/security).
|
||||
|
||||
However, it is possible that various parts need some rework before the security
|
||||
branch can be merged into the cyclonedds master branch.
|
||||
|
||||
|
||||
## Footprint<a name="footprint" />
|
||||
|
||||
A non-functional requirement is that cyclonedds should be buildable without
|
||||
the DDS Security support in it. That will reduce the footprint (and possibly
|
||||
improve performance) for applications that don't need security.
|
||||
|
||||
For that, the ENABLE_SECURITY build option is introduced that translates into
|
||||
the DDSI_INCLUDE_SECURITY compile switch. However, the usage of that switch
|
||||
should not explode. That'll reduce the maintainability.
|
||||
|
||||
For instance, the usage of the switch can be minimized by using functions that
|
||||
will reduce to an inline function that just returns a hardcode value when
|
||||
security is not included (otherwise they'll do some certain task).
|
||||
The compiler can use these inline functions to do clever stuff regarding
|
||||
footprint and performance.
|
||||
|
||||
There can be other solutions to decrease security footprint without impeding
|
||||
on the maintainability of the code by inserting the switch too much.
|
||||
|
||||
|
||||
## Multi process testing (done)<a name="testing" />
|
||||
|
||||
To properly test DDS Security, multi process testing will be necessary.
|
||||
This is not yet available in Cyclone DDS.
|
||||
See the [Multi Process Testing](multi_process_testing.md) document for
|
||||
more information.
|
||||
|
||||
|
||||
## Runtime library loading (done)<a name="loading" />
|
||||
|
||||
The ddsi component needs to be able to load DDS Security plugins at runtime.
|
||||
These plugins are provided as libraries.<br>
|
||||
Loading libraries at runtime is currently not possible in Cyclone DDS.
|
||||
|
||||
|
||||
## Hopscotch utility (done)<a name="hopscotch" />
|
||||
|
||||
This hash table is used by the Security plugins.<br>
|
||||
Both versions on OpenSplice and Cyclone are equivalent.<br>
|
||||
No additional effort is expected.
|
||||
|
||||
|
||||
## FSM utility (in progress)<a name="fsm" />
|
||||
|
||||
The Finite State Machine utility has been introduced in OpenSplice to support
|
||||
the handshake of DDS Security.<br>
|
||||
This has to be ported to Cyclone.
|
||||
|
||||
However, it already has some technical dept, which should be removed before
|
||||
adding it to Cyclone. This means that a refactor should happen as part of the
|
||||
porting.
|
||||
|
||||
The related DBTs should also be ported to Cyclone unit tests.
|
||||
|
||||
It was decided to just port the FSM at the moment. The refactor will take place
|
||||
when trying to get the security branch into master.
|
||||
|
||||
|
||||
## Port DDS Security plugin API (done)<a name="port-api" />
|
||||
|
||||
The DDS Security plugin API are just a few header files. The ddsi component
|
||||
uses that to link against. The implementation of the API is done in the
|
||||
individual plugins. The plugins are [loaded at runtime](#loading) (when
|
||||
configured).
|
||||
|
||||
This means that ddsi can be DDS Security prepared (after building against this
|
||||
API) without there being actual DDS Security plugins.
|
||||
|
||||
It seems to be just a code drop of a number of header files.<br>
|
||||
Maybe add some CMake module for both ddsi and the plugins to easily link
|
||||
against?
|
||||
|
||||
|
||||
## De-Serializing messages in DDSI (done)<a name="deserializing" />
|
||||
|
||||
DDSI needs to be able to (de)serialize a few Security messages. In OpenSplice,
|
||||
some functionality of the database is used. This is unavailable in Cyclone.
|
||||
|
||||
What is available is a serializer that uses marshaling operations (see, for
|
||||
for instance, m_ops in the dds_topic_descriptor struct).
|
||||
|
||||
The (de)serializing of the Security messages should be supported by supplying
|
||||
the m_ops sequences, message structs (if not yet available) and some
|
||||
convenience functions using both.
|
||||
|
||||
|
||||
## De-Serializing security message parameters in DDSI (done)<a name="deserializing_plist" />
|
||||
|
||||
DDSI needs to be able to (de)serialize a few message parameters that have
|
||||
been introduced by the DDS Security spec.
|
||||
|
||||
|
||||
## Port DDS Security builtin plugins (in progress)<a name="port-plugins" />
|
||||
|
||||
No major changes between the DDS Security plugins in OpenSplice and Cyclone
|
||||
are expected.
|
||||
|
||||
The DDS Security plugins require OpenSSL. Cyclone DDS already uses OpenSSL.
|
||||
However, it expects (or at least it's preferred to have) version 1.1 or newer,
|
||||
while the OpenSplice Security plugins are build against 1.0.2. There are some
|
||||
API changes between the two versions. This will take some porting effort.
|
||||
|
||||
The build system should be ported from makefiles to cmake files.
|
||||
|
||||
There are security_plugin DBTs in OpenSplice. These tests are base on cunit,
|
||||
which is also used in Cyclone. However, it is used slightly different. A small
|
||||
porting effort is expected (i.e. let it work with cmake and runner generation).
|
||||
|
||||
This means some additional effort, compared to just a code drop. But it is not
|
||||
expected to be major.
|
||||
|
||||
- Authentication plugin (done).
|
||||
- Access Control plugin (in progress).
|
||||
- Cryptography plugin (done).
|
||||
|
||||
There are a few sub-features that can be implemented separately.
|
||||
- Check/handle expiry dates (in progress).
|
||||
- Trusted directory support.
|
||||
- etc?
|
||||
|
||||
|
||||
## Port DDSI DDS Security (in progress)<a name="port-ddsi" />
|
||||
|
||||
There is already quite a bit of difference between the DDSI codebases in
|
||||
OpenSplice and Cyclone. So, the copy/merge of the DDSI Security code from
|
||||
OpenSplice to Cyclone will not be trivial.
|
||||
|
||||
Most parts of the merging will not be trivial, but should be quite
|
||||
straightforward nonetheless. Things that are noticed to be somewhat different
|
||||
between the DDSI code bases that could impact the merging work:
|
||||
- Entity matching is slightly different.
|
||||
- The q_entity.c has a lot of differences that can obfuscate the differences
|
||||
related to DDS Security.
|
||||
- Unacked messages logic has changed a bit. Does that impact gaps?
|
||||
- (De)serializing, of course
|
||||
(see also [De-Serializing in DDSI](#deserializing)).
|
||||
- Writer history cache is different, which can impact the builtin volatile
|
||||
Security endpoints.
|
||||
- Unknown unknowns.
|
||||
|
||||
The buildsystem has to be upgraded.<br>
|
||||
- A few files are added which are easy to add to cmake.<br>
|
||||
- There's a new dependency on the [DDS Security API](#port-api), which is done.
|
||||
|
||||
Then, of course, there are the tests<br>
|
||||
First of all, [Multi Process Testing](#testing) should be available, which now
|
||||
it is.<br>
|
||||
When that's the case, then the OpenSplice tests business
|
||||
logic have to be ported from scripts and applications to that new framework.
|
||||
That porting shouldn't be that hard. However, it will probably take a while.
|
||||
|
||||
The DDSI Port doesn't have to be a big bang. It can be split up into various
|
||||
different pull requests. Examples are
|
||||
- Extend configuration XML parsing with the security configuration (done).
|
||||
- Extend nn_qos with security related policies. Fill them with values from the
|
||||
configuration when applicable (done).
|
||||
- Add DDS Security endpoints that are non-volatile (done).
|
||||
- Add DDS Security endpoint that is volatile. This change has more impact than
|
||||
all the non-volatile endpoints combined (done).
|
||||
- Handshake (in progress).
|
||||
- Payload (en)(de)coding (DDSI support: done. Wrapper: todo).
|
||||
- Submsg (en)(de)coding (DDSI support: done. Wrapper: todo).
|
||||
- RTPSmsg (en)(de)coding (DDSI support: done. Wrapper: todo).
|
||||
- Etc
|
||||
|
||||
|
||||
|
||||
## Move configuration (in progress)<a name="Move-configuration" />
|
||||
|
||||
After the port, the DDS Security configuration is still (partly) done through
|
||||
the overall configuration XML file (rest is coming from the permissions and
|
||||
governance files).<br>
|
||||
However, according to the specification, the configuration should happen by
|
||||
means of the Participant QoS.
|
||||
|
||||
The ddsc dds_qos_t is mapped on the ddsi xqos. The ddsi xqos already has the
|
||||
necessary policy (after the [port](#port-ddsi)), namely the property_policy.
|
||||
This means that the ddsc qos itself is automatically prepared.<br>
|
||||
However, getting and setting policies are done through getter and setter
|
||||
functions in ddsc.<br>
|
||||
This means we have to add these functions for the security configuration values.
|
||||
|
||||
The ddsc policy getter and setter functions use (arrays of) primitive types as
|
||||
arguments. The configuration of Security is given by means of the property
|
||||
policy, which isn't a primitive. To keep in line with the QoS API, we could add
|
||||
something like:
|
||||
```cpp
|
||||
typedef struct dds_properties_t; /* opaque type in API, but mapped to
|
||||
nn_property_qospolicy_t internally */
|
||||
dds_properties_t *dds_properties_create();
|
||||
void dds_properties_delete(dds_properties_t *);
|
||||
void dds_properties_merge(dds_properties_t *, dds_properties_t *);
|
||||
void dds_properties_add_property(dds_properties_t *, char *name, char *value);
|
||||
void dds_properties_add_binaryproperty(dds_properties_t *, char *name,
|
||||
uchar *value, int valuelength);
|
||||
void dds_qset_properties(dds_qos_t*, dds_properties_t *);
|
||||
void dds_qget_properties(dds_qos_t*, dds_properties_t **);
|
||||
```
|
||||
But this is very preliminary and is still up for debate.
|
||||
|
||||
After moving the Security configuration to the participant QoS, it's possible
|
||||
to have different configurations within a single application if you have
|
||||
multiple participants. However, ddsi only supports one Security configuration
|
||||
for now. That doesn't change by changing where that configuration comes
|
||||
from.<br>
|
||||
To solve this, it is expected that creation of a participant with a different
|
||||
configuration will force a failure for now.
|
||||
Until [Multiple Configurations](#multiple-configurations) is implemented.
|
||||
|
||||
After the ddsc API has been extended, we can decide on what to do with the
|
||||
configuration through XML.
|
||||
- Keep it. It seems usable: no need to change applications when changing (or
|
||||
adding) Security settings. However, conflicts between XML and QoS
|
||||
configuration could cause problems. Simplest seems to be to only allow QoS
|
||||
security configuration when it's not configured in XML already.
|
||||
- Remove it. No conflict resolving needed.
|
||||
|
||||
All the Security tests depend on providing (different) configurations through
|
||||
XML. Depending on if we keep or remove the XML configuration option, a lot of
|
||||
tests have to be updated, or a few added (that test security configuration
|
||||
through QoS).
|
||||
|
||||
For the loading of the plugin libraries, properties with specific names have to
|
||||
be added to the property policy to know the location and names of the plugins.
|
||||
As inspiration, fastrtps can be used:
|
||||
https://github.com/ros2/rmw_fastrtps/blob/master/rmw_fastrtps_shared_cpp/src/rmw_node.cpp#L296
|
||||
|
||||
|
||||
## Failure handling<a name="failures" />
|
||||
|
||||
Currently, when an local action is tried that isn't allowed by DDS Security
|
||||
(like creating a participant when it's not permitted), DDSI is shut down.<br>
|
||||
Mainly because in OpenSplice it's quite hard to get a failure state from DDSI
|
||||
to the application.
|
||||
|
||||
In Cyclone, however, ddsc::dds_create_participant() results in a direct call to
|
||||
ddsi::new_participant(). This means that if creation of an entity (or
|
||||
participant in this example) fails due to security issues in ddsi, we can fail
|
||||
the actual ddsc API call with a proper error result (there's already the
|
||||
DDS_RETCODE_NOT_ALLOWED_BY_SECURITY in the ddsc API (not used)).
|
||||
|
||||
Maybe we have to do some additional cleanup when a failure is encountered.
|
||||
|
||||
Some tests probably have to be adjusted for the new behaviour.
|
||||
|
||||
|
||||
## Multiple configurations<a name="multiple-configurations" />
|
||||
|
||||
Currently (because it's done through the overall XML configuration), only one
|
||||
DDS Security configuration could be supported. Because of this fact, at various
|
||||
locations, shortcuts could be made in both DDSI and plugins.<br>
|
||||
However, because the configuration is coming from participants now (see
|
||||
[Move Configuration](#Move-configuration), we should be able to support
|
||||
multiple different DDS Security configurations.
|
||||
|
||||
Until now, the creation of a second participant with a different configuration
|
||||
would force a failure (again, see [Move Configuration](#Move-configuration)).
|
||||
|
||||
It is expected that the plugin loading still happens through the configuration
|
||||
XML (see [Move Configuration](#Move-configuration)). This means that DDSI doesn't have to support
|
||||
multiple sets of plugins. Just the one set, provided at initialization. This
|
||||
means that DDSI shouldn't have to be changed to support this.
|
||||
|
||||
So, it's the plugins need to be able to support multiple configurations.
|
||||
|
||||
The Cryptography plugin doesn't seem to care about global DDS Security
|
||||
configurations. It has basically configurations per participant/topic/
|
||||
endpoints, which already works. So, this plugin doesn't have to be upgraded.
|
||||
|
||||
The Authentication plugin does have global DDS Security configurations. Main
|
||||
function related to that is validate_local_identity(). This function already
|
||||
creates a new local identity every time it is called. So, this plugin doesn't
|
||||
have to be upgraded either.
|
||||
|
||||
That leaves the Access Control plugin.<br>
|
||||
The main function related to configuration is validate_local_permissions().
|
||||
This function creates access rights depending on Permissions and Governance
|
||||
files. Currently, there's only one local 'rights' structure that is linked
|
||||
directly to the plugin (see also the ACCESS_CONTROL_USE_ONE_PERMISSION compile
|
||||
switch).<br>
|
||||
This has to change.<br>
|
||||
The local rights structure needs to be coupled to a participant. This also
|
||||
means that we have to search for it instead of having direct access when
|
||||
entering the plugin.<br>
|
||||
The remote rights can be used as example. That is basically a list of rights/
|
||||
permissions with the remote identity handle as key.
|
||||
|
||||
Tests have to be added to make sure that a setup with different Security
|
||||
configurations works.
|
||||
|
||||
|
||||
## Example<a name="example" />
|
||||
|
||||
A Security example has to be added.
|
||||
|
||||
|
||||
## QosProvider<a name="qosprovider" />
|
||||
|
||||
The Participant QoS now contains Security related information. This means that
|
||||
the QosProvider has to be upgraded to support that.
|
||||
|
||||
|
||||
## Data Tags (optional)<a name="datatags" />
|
||||
|
||||
The specification is somewhat fuzzy about the data tags.
|
||||
|
||||
The following is a summary (still elaborate) of how it seems to work:
|
||||
|
||||
The permissions document can contain the <data_tags> tag on publish and
|
||||
subscribe level. It's related to the data samples, but don't have to be related
|
||||
to the keys of those samples.<br>
|
||||
The QoS of a writer/reader can also have data tags by means of the
|
||||
DataTagQosPolicy. A writer/reader can only be created when the data_tags in the
|
||||
QoS matches those in the permissions document. This check should happen on both
|
||||
the local and remote level.
|
||||
|
||||
This creation check is the only thing that DDS Security actually does with the
|
||||
data tags. They are only authenticated by DDS Security, but not interpreted
|
||||
further.<br>
|
||||
This is only a minor security addition, because the publisher can still publish
|
||||
data that doesn't match the data tags because DDS doesn't interpret the data
|
||||
nor compares it with the data tags.
|
||||
|
||||
What it can be used for is a kind of custom access control scheme on the
|
||||
application level.<br>
|
||||
An application that consumes data can see if a publisher is allowed to publish
|
||||
that sample by comparing the data within the sample with the data tag(s)
|
||||
associated with that publisher. As said, this comparison is not done on the DDS
|
||||
level, but has to be done within the application itself.
|
||||
|
||||
That leaves the question, how does the application get the tags associated with
|
||||
the related writer?<br>
|
||||
In other words; the application gets a sample. It has to know from which writer
|
||||
it originated and it has to have access to the data tag(s) of that writer.
|
||||
The dds_sample_info_t contains the dds_instance_handle_t publication_handle,
|
||||
which is unique to the writer (locally).<br>
|
||||
That dds_instance_handle_t can be used to get the right
|
||||
DDS_Security_PublicationBuiltinTopicDataSecure sample for the related secure
|
||||
builtin reader [**note1**].<br>
|
||||
DDS_Security_PublicationBuiltinTopicDataSecure contains QoS information
|
||||
regarding that writer, including the DataTagQosPolicy. The remote
|
||||
DDS_Security_PublicationBuiltinTopicDataSecure contents have been authenticated
|
||||
by DDS Security and the data tags can be trusted.<br>
|
||||
The application can check the sample data against the data_tags within that
|
||||
QoS.
|
||||
|
||||
Things to do:
|
||||
- Add DataTagQosPolicy to the ddsc API and the related QoSses.
|
||||
- Add DDS_Security_PublicationBuiltinTopicDataSecure data type to the ddsc API
|
||||
(better yet, all secure builtin types).
|
||||
- Add the related builtin reader to the ddsc99 API (better yet, all secure
|
||||
builtin readers).
|
||||
- Add test regarding the secure builtin readers and data.
|
||||
- Add data tag comparisons between QoS and permission documents during local
|
||||
and remote entity creation.
|
||||
- Add data tag remote/local (mis)match tests.
|
||||
|
||||
Especially because of the lack of access to builtin secure readers, supporting
|
||||
data tags doesn't seem feasible in the near future. Also, it's optional in the
|
||||
specification.
|
||||
|
||||
**note1**
|
||||
That DDS_Security_PublicationBuiltinTopicDataSecure reader is not yet available
|
||||
within the ddsc API, nor is the related data type. Don't know how much work it
|
||||
would be to add them to that API.
|
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
BIN
docs/manual/_static/pictures/dds_security_overview.png
Normal file
BIN
docs/manual/_static/pictures/dds_security_overview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
BIN
docs/manual/_static/pictures/pki_overview.png
Normal file
BIN
docs/manual/_static/pictures/pki_overview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 71 KiB |
BIN
docs/manual/_static/pictures/rtps_message_structure.png
Normal file
BIN
docs/manual/_static/pictures/rtps_message_structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
646
docs/manual/security.rst
Normal file
646
docs/manual/security.rst
Normal file
|
@ -0,0 +1,646 @@
|
|||
.. _`DDS Security`:
|
||||
|
||||
############
|
||||
DDS Security
|
||||
############
|
||||
|
||||
CycloneDDS is (will be) compliant with The Object Management Group (OMG) DDS Security specification.
|
||||
|
||||
This specification defines the Security Model and Service Plugin Interface (SPI) architecture for
|
||||
compliant DDS implementations. The DDS Security Model is enforced by the invocation of these SPIs
|
||||
by the DDS implementation.
|
||||
|
||||
.. image:: ./_static/pictures/dds_security_overview.png
|
||||
:width: 1000
|
||||
|
||||
The three plugins that comprise the DDS Security Model in CycloneDDS are:
|
||||
|
||||
|
||||
**Authentication Service Plugin**
|
||||
|
||||
Provides the means to verify the identity of the application and/or user that invokes operations
|
||||
on DDS. Includes facilities to perform mutual authentication between participants and establish
|
||||
a shared secret.
|
||||
|
||||
**AccessControl Service Plugin**
|
||||
|
||||
Provides the means to enforce policy decisions on what DDS related operations an authenticated
|
||||
user can perform. For example, which domains it can join, which Topics it can publish or
|
||||
subscribe to, etc.
|
||||
|
||||
**Cryptographic Service Plugin**
|
||||
|
||||
Implements (or interfaces with libraries that implement) all cryptographic operations including
|
||||
encryption, decryption, hashing, digital signatures, etc. This includes the means to derive keys
|
||||
from a shared secret.
|
||||
|
||||
----
|
||||
|
||||
CycloneDDS provides built-in implementations of these plugins. Authentication uses PKI
|
||||
(Public Key Infrastructure) with a pre-configured shared Certificate Authority, RSA is used for
|
||||
authentication and Diffie-Hellman is used for key exchange. AccessControl use Permissions document
|
||||
signed by shared Certificate Authority. Cryptography uses AES-GCM (AES using Galois Counter Mode)
|
||||
for encryption and AES-GMAC for message authentication.
|
||||
|
||||
The plugins are accessed by the DDSI2 service when DDS Security is enabled by supplying the
|
||||
security configuration within the XML configuration or Participant QoS.
|
||||
|
||||
Security plugins are dynamically loaded where the locations are defined in CycloneDDS
|
||||
configuration or Participant QoS settings.
|
||||
|
||||
|
||||
*******************************************************
|
||||
Brief information about PKI (public key infrastructure)
|
||||
*******************************************************
|
||||
|
||||
The comprehensive system required to provide public-key encryption and digital signature services
|
||||
is known as a public-key infrastructure (PKI). The purpose of a PKI is to manage keys and
|
||||
certificates. By managing keys and certificates through a PKI, an organization establishes and
|
||||
maintains a trustworthy networking environment.
|
||||
|
||||
Public Key Cryptography: Each user has a key pair, generated during the initial certificate
|
||||
deployment process, that is comprised of a public key, which is shared, and a private key, which
|
||||
is not shared. Data is encrypted with the user’s public key and decrypted with their private key.
|
||||
Digital signatures, used for non-repudiation, authentication and data integrity, are also generated
|
||||
using public key cryptography.
|
||||
|
||||
**Identity Certificate**
|
||||
|
||||
This is an electronic document used to prove the ownership of a public key. The certificate
|
||||
includes information about the key, information about the identity of its owner (called the
|
||||
subject), and the digital signature of an entity that has verified the certificate's contents
|
||||
(called the issuer). If the signature is valid, and the software examining the certificate
|
||||
trusts the issuer, then it can use that key to communicate securely with the certificate's
|
||||
subject.
|
||||
|
||||
**Certificate Authority**
|
||||
|
||||
This issues user certificates and acts as the chief agent of trust. When issuing a certificate
|
||||
to a user, the CA signs the certificate with its private key in order to validate it. During
|
||||
electronic transactions the CA also confirms that certificates are still valid. Certificates
|
||||
may be revoked for various reasons. For example, a user may leave the organization or they may
|
||||
forget their secret passphrase, the certificate may expire or become corrupt. This process is
|
||||
usually accomplished through the use of a Certificate Revocation List (CRL) which is a list of
|
||||
the certificates that have been revoked. Only the certificates that have been revoked appear on
|
||||
this list.
|
||||
|
||||
**Subject of Identity Certificate**
|
||||
|
||||
This is the identity to be secured. It contains information such as common name (CN),
|
||||
organization (OU), state (ST) and country (C).
|
||||
|
||||
**Subject Name**
|
||||
|
||||
This is aka distinguished name and is the string representation of certificate subject.
|
||||
|
||||
ie: emailAddress=alice\@adlink.ist,CN=Alice,OU=IST,O=ADLink,ST=OV,C=NL
|
||||
|
||||
|
||||
*************************
|
||||
PKI Usage in DDS Security
|
||||
*************************
|
||||
|
||||
.. image:: ./_static/pictures/pki_overview.png
|
||||
:width: 1000
|
||||
|
||||
Alice and Bob are the DDS participants who have their private and public keys. Identitity
|
||||
Certificate Authority (ID CA) has its own self-signed certificate (IdentityCA in the diagram).
|
||||
ID CA gets Alice's subject information and public key and generates an IdentityCertificate for her.
|
||||
Alice's certificate includes her public key and certificate of ID CA; so that her certificate can
|
||||
be verified if it is really issued by ID CA.
|
||||
|
||||
Access Control is configured with governance and permissions files.
|
||||
Governance file defines the security behavior of domains and topics.
|
||||
Permissions file contains the permissions of the domain participant, topics, readers and writers,
|
||||
binds them to identity certificate by subject name (distinguished name).
|
||||
|
||||
Governance files and Permissions files are signed by Permission CA. Signed documents also
|
||||
contains Permissions CA certificate; so that they can be verified if they are really issued
|
||||
by Permissions CA.
|
||||
|
||||
Authenticated participants handshakes with each other and generates a shared key by Diffie-Hellman
|
||||
key exchange. This shared key is used for encrypting/decrypting data with AES.
|
||||
|
||||
During the handshake Alice checks Bob's certificate and Bob's Permissions file if they are really
|
||||
issued by the ID CA certificate and Permissions CA Certificate that **she** has. Also Bob checks
|
||||
Alice's certificate and Alice's Permissions file if they are really issued by the ID CA certificate
|
||||
and Permissions CA that **he** has.
|
||||
Permissions file can contain permissions for several identities; so subject name of identity
|
||||
certificate exist in permissions file to establish a binding between identity and its permissions.
|
||||
|
||||
|
||||
*************
|
||||
Configuration
|
||||
*************
|
||||
|
||||
.. image:: ./_static/pictures/dds_security_configuration_overview.png
|
||||
:width: 1000
|
||||
|
||||
|
||||
The configuration of DDS Security is split up into two parts.
|
||||
|
||||
- `Plugins Configuration`_
|
||||
- `Access Control Configuration`_
|
||||
|
||||
This section explains the configuration in details. However, you can see a concrete example on
|
||||
security section of Example Readme file.
|
||||
|
||||
.. _`Plugins Configuration`:
|
||||
|
||||
|
||||
Plugins Configuration
|
||||
*********************
|
||||
|
||||
TODO: Update to reflect the configuration through QoS policies.
|
||||
|
||||
| CyclonDDS gets the plugin configuration from DDS2I configuration elements or the Participant QoS
|
||||
Policies as stated in the DDS Security specification.
|
||||
|
||||
| This behavior allows applications to use DDS Security without update. Only supplying a new
|
||||
configuration with DDS Security enabled is enough to switch from a non-secure to a secure
|
||||
deployment. However, the same DDS Security configuration is forced upon all the participants
|
||||
within the federation.
|
||||
|
||||
| The configuration options are bundled in the ``DDSSecurity`` configuration section in DDS2I.
|
||||
|
||||
| Every DDS Security plugin has its own configuration sub-section.
|
||||
|
||||
|
||||
.. _`Authentication Properties`:
|
||||
|
||||
=========================
|
||||
Authentication Properties
|
||||
=========================
|
||||
|
||||
| To authenticate CycloneDDS, it has to be configured with IdentityCertificate
|
||||
(DDSSecurity/Authentication/IdentityCertificate - see Configuration Guide - DDS Security).
|
||||
This IdentityCertificate is used to authenticate all participants of that particular
|
||||
CycloneDDS domain.
|
||||
|
||||
| Associated with the IdentityCertificate is the corresponding PrivateKey
|
||||
(DDSSecurity/Authentication/PrivateKey).
|
||||
The PrivateKey may either be a 2048-bit RSA or a 256-bit Elliptic Curve Key with
|
||||
a prime256v1 curve.
|
||||
|
||||
| IdentityCA (DDSSecurity/Authentication/IdentityCA) is the certificate of Identity Certificate
|
||||
Authority (CA) which is the issuer of the IdentityCertificate. The public key of the
|
||||
IdentityCA shall either be a 2048-bit RSA key or a 256-bit Elliptic Curve Key for the prime256v1
|
||||
curve. The identity_ca can be a self-signed certificate.
|
||||
|
||||
| Currently the IdentityCertificate, IdentityCA and PrivateKey should be a X509 document in pem
|
||||
format.
|
||||
It may either be specified directly in the configuration file or the configuration file should
|
||||
contain a reference to a corresponding file.
|
||||
|
||||
| Optionally the PrivateKey could be protected by a password (DDSSecurity/Authentication/Password).
|
||||
|
||||
| Furthermore the CycloneDDS configuration allows to configure a directory containing additional
|
||||
IdentityCA's
|
||||
which are used to verify the identity certificates that are received by remote instances
|
||||
(DDSSecurity/Authentication/TrustedCADirectory). This option allows to use more than one identity
|
||||
CA throughout the system. TrustedCADirectory is an extension to DDS Security specification; so it
|
||||
can not be used when communicating with other vendors.
|
||||
|
||||
|
||||
.. _`Access Control Properties`:
|
||||
|
||||
=========================
|
||||
Access Control Properties
|
||||
=========================
|
||||
|
||||
Governance Document (DDSSecurity/AccessControl/Governance),
|
||||
Permissions Document (DDSSecurity/AccessControl/Permissions) and
|
||||
Permissions CA Certificate (DDSSecurity/AccessControl/PermissionsCA) are required for access
|
||||
control plugin. See DDS Security section of Configuration Guide for property descriptions. They
|
||||
can be provided by data itself (with CDATA) or path to file on disk.
|
||||
|
||||
|
||||
.. _`Cryptography Properties`:
|
||||
|
||||
=======================
|
||||
Cryptography Properties
|
||||
=======================
|
||||
|
||||
Cryptography plugin has no property
|
||||
|
||||
|
||||
.. _`Access Control Configuration`:
|
||||
|
||||
Access Control Configuration
|
||||
****************************
|
||||
|
||||
| Access Control configuration consists of Governance document and Permissions document.
|
||||
Both governance and permissions files must be signed by the Permissions CA in S/MIME format.
|
||||
Participants use their own permissions CA to validate remote permissions. So, all permissions CA
|
||||
Certificates must be same for all participants.
|
||||
|
||||
| The signed document should use S/MIME version 3.2 format as defined in IETF RFC 5761 using
|
||||
SignedData Content Type (section 2.4.2 of IETF RFC 5761) formatted as multipart/signed (section
|
||||
3.4.3 of IETF RFC 5761). This corresponds to the mime-type application/pkcs7-signature.
|
||||
Additionally the signer certificate should be be included within the signature.
|
||||
|
||||
|
||||
===================
|
||||
Governance Document
|
||||
===================
|
||||
|
||||
Governance document defines the security behavior of domains and topics. It is an XML document and
|
||||
its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.2.3
|
||||
|
||||
The attributes that specified in Governance document must match with the remote one for
|
||||
establishing communication.
|
||||
|
||||
|
||||
Protection Kinds
|
||||
================
|
||||
|
||||
The domain governance document provides a means for the application to configure the kinds of
|
||||
cryptographic transformation applied to the complete RTPS Message, certain RTPS SubMessages, and
|
||||
the SerializedPayload RTPS submessage element that appears within the Data.
|
||||
|
||||
.. image:: ./_static/pictures/rtps_message_structure.png
|
||||
:width: 300
|
||||
|
||||
The configuration allows specification of five protection levels: NONE, SIGN, ENCRYPT,
|
||||
SIGN_WITH_ORIGIN_AUTHENTICATION and ENCRYPT_WITH_ORIGIN_AUTHENTICATION.
|
||||
|
||||
**NONE**
|
||||
indicates no cryptographic transformation is applied.
|
||||
|
||||
**SIGN**
|
||||
indicates the cryptographic transformation shall be purely a message authentication code (MAC),
|
||||
that is, no encryption is performed.
|
||||
|
||||
**ENCRYPT**
|
||||
indicates the cryptographic transformation shall be an encryption followed by a message
|
||||
authentication code (MAC) computed on the ciphertext, also known as Encrypt-then-MAC.
|
||||
|
||||
**SIGN_WITH_ORIGIN_AUTHENTICATION**
|
||||
indicates the cryptographic transformation shall be purely a set of message authentication codes
|
||||
(MAC), that is, no encryption is performed. This cryptographic transformation shall create a
|
||||
first “common authenticationcode” similar to the case where Protection Kind is SIGN. In addition
|
||||
the cryptographic transformation shall create additional authentication codes, each produced with
|
||||
a different secret key. The additional MACs prove to the receiver that the sender originated the
|
||||
message, preventing other receivers from impersonating the sender.
|
||||
|
||||
**ENCRYPT_WITH_ORIGIN_AUTHENTICATION**
|
||||
indicates the cryptographic transformation shall be an encryption followed by a message
|
||||
authentication code (MAC) computed on the ciphertext, followed by additional authentication
|
||||
codes, Each of the additional authentication codes shall use a different secret key. The
|
||||
encryption and first (common) authentication code is similar to ones produced when the Protection
|
||||
Kind is ENCRYPT. The additional authentication codes are similar to the ones produced when the
|
||||
Protection Kind is SIGN_WITH_ORIGIN_AUTHENTICATION.
|
||||
|
||||
|
||||
Participant attributes
|
||||
======================
|
||||
|
||||
**Allow Unauthenticated Participants**
|
||||
This is used for allowing communication with non-secure participants. If this option is enabled,
|
||||
secure participant can communicate with non-secure participant by only non-protected topics.
|
||||
|
||||
**Enable Join Access Control**
|
||||
If this option is enabled, remote participant permissions are checked if its subject name is
|
||||
allowed to create a topic anyhow.
|
||||
|
||||
**Discovery Protection Kind**
|
||||
Protection attribute for discovery communication when it is enabled for topic. Please see the
|
||||
DDS Security specification document for available options.
|
||||
|
||||
**Liveliness Protection Kind**
|
||||
Protection attribute for liveliness communication when it is enabled for topic. Please see the
|
||||
DDS Security specification document for available options.
|
||||
|
||||
**RTPS Protection Kind**
|
||||
Protection attribute for all messages on the wire. Please see the DDS Security specification
|
||||
document for available options. If encryption is selected for RTPS, there is no need to encrypt
|
||||
submessages (metadata_protection_kind) and payloads (data_protection_kind) which are defined in
|
||||
topic settings.
|
||||
|
||||
|
||||
Topic Attributes
|
||||
================
|
||||
|
||||
**Enable Discovery protection:**
|
||||
If enabled, discovery is protected according to Discovery Protection Kind attribute of
|
||||
corresponding participant.
|
||||
|
||||
**Enable Liveliness protection:**
|
||||
If enabled, liveliness is protected according to Liveliness Protection Kind attribute of
|
||||
corresponding participant.
|
||||
|
||||
**Enable Read Access Control:**
|
||||
If enabled, the permissions document is checked if the participant is allowed to create
|
||||
a datareader for the related topic.
|
||||
|
||||
**Enable Write Access Control:**
|
||||
If enabled, the permissions document is checked if the participant is allowed to create
|
||||
a datawriter for the related topic.
|
||||
|
||||
**Metadata protection Kind:**
|
||||
Protection attribute for submessages.
|
||||
|
||||
**Data protection Kind:**
|
||||
Protection attribute for data payload.
|
||||
|
||||
There are different settings for different domain ranges. The domain rules are evaluated in the
|
||||
same order as they appear in the document. A rule only applies to a particular DomainParticipant
|
||||
if the domain Section matches the DDS domain_id to
|
||||
which the DomainParticipant belongs. If multiple rules match, the first rule that matches is the
|
||||
only one that applies.
|
||||
|
||||
The topic access rules are evaluated in the same order as they appear within the
|
||||
<topic_access_rules> Section. If multiple rules match the first rule that matches is the only one
|
||||
that applies.
|
||||
|
||||
fnmatch pattern matching can be used for topic expressions including the following patterns
|
||||
|
||||
.. _`fnmatch pattern matching`:
|
||||
|
||||
+----------+----------------------------------+
|
||||
|Pattern |Meaning |
|
||||
+==========+==================================+
|
||||
| \* | matches everything |
|
||||
+----------+----------------------------------+
|
||||
| \? | matches any single character |
|
||||
+----------+----------------------------------+
|
||||
| [seq] | matches any character in seq |
|
||||
+----------+----------------------------------+
|
||||
| [!seq] | matches any character not in seq |
|
||||
+----------+----------------------------------+
|
||||
|
||||
|
||||
====================
|
||||
Permissions Document
|
||||
====================
|
||||
|
||||
The permissions document is an XML document containing the permissions of the domain participant
|
||||
and binding them to the subject name of the DomainParticipant as defined in the identity
|
||||
certificate. Its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.3.
|
||||
|
||||
|
||||
Validity period
|
||||
===============
|
||||
|
||||
It is checked before creating participant; expired permissions document results with DDSI shutdown.
|
||||
Validity period is also checked during handshake with remote participant; expired remote
|
||||
permissions document prevents communications to be established.
|
||||
|
||||
|
||||
Subject Name
|
||||
============
|
||||
|
||||
The subject name must match with Identity Certificate subject. It is checked during create
|
||||
participant and during handshake with remote participant. Use the following openssl command to get
|
||||
subject name from identity certificate:
|
||||
|
||||
``openssl x509 -noout -subject -nameopt RFC2253 -in <identity_certificate_file.crt>``
|
||||
|
||||
|
||||
Rules
|
||||
=====
|
||||
|
||||
DomainParticipant permissions are defined by set of rules.
|
||||
|
||||
The rules are applied in the same order that appear in the document. If the criteria for the rule
|
||||
matches the domain_id join and/or publish or subscribe operation that is being attempted, then the
|
||||
allow or deny decision is applied. If the criteria for a rule does not match the operation being
|
||||
attempted, the evaluation shall proceed to the next rule. If all rules have been examined without
|
||||
a match, then the decision specified by the “default” rule is applied. The default rule, if
|
||||
present, must appear after all allow and deny rules. If the default rule is not present, the
|
||||
implied default decision is DENY. The matching criteria for each rule specify the domain_id,
|
||||
topics (published and subscribed), the partitions (published and subscribed), and the data-tags
|
||||
associated with the DataWriter and DataReader.
|
||||
|
||||
For the grant to match there shall be a match of the topics, partitions, and data-tags criteria.
|
||||
This is interpreted as an AND of each of the criteria. For a specific criterion to match
|
||||
(e.g., <topics>) it is enough that one of the topic expressions listed matches (i.e., an OR of
|
||||
the expressions with the <topics> section).
|
||||
|
||||
`fnmatch pattern matching`_ can be used for topic expressions and partition expressions.
|
||||
|
||||
|
||||
Interactions with DDS Security
|
||||
******************************
|
||||
|
||||
DDS Security provides the responses through CycloneDDS error and info log. Users can get
|
||||
messages for:
|
||||
|
||||
- Configuration errors such as plugin library files, certificate files, governance and permissions
|
||||
files that can not be found on filesystem.
|
||||
- Permission errors such as denied permission for creating writer of a topic.
|
||||
- Attribute mismatch errors such as mismatches of security attributes between participants, topics,
|
||||
readers and writers.
|
||||
- Integrity errors such as Permissions file-Permissions CA and Identity Cert-Identity CA integrity.
|
||||
|
||||
Local subscription, publication and topic permission errors are written to error log.
|
||||
Remote participation, subscription and publication permission errors are written to info log as
|
||||
warning message.
|
||||
|
||||
|
||||
Data Communication And Handshake Process
|
||||
*******************************************
|
||||
|
||||
Authentication handshake between participants starts after participant discovery.
|
||||
If a reader and a writer created during that period, their match will be delayed until after the
|
||||
handshake succeeds.
|
||||
This means, during the handshake process, volatile data will be lost, just like there is no reader.
|
||||
|
||||
After publication match, the encryption / decryption keys are exchanged between reader and writer.
|
||||
Best-effort data that are sent during this exchange will be lost, however reliable data will be
|
||||
resent.
|
||||
|
||||
|
||||
DDS Secure Discovery
|
||||
******************************
|
||||
|
||||
Just like normal operation, DDSI will discover local and remote participants, topics, readers and
|
||||
writers.
|
||||
However, when DDS Security is enabled, it is more complex and will take a longer time (especially
|
||||
due to the handshaking that has to happen).
|
||||
|
||||
With every new node in the system, the discovery takes exponentially longer. This can become a
|
||||
problem if the system contains a number of slow platforms or is large.
|
||||
|
||||
The Security discovery performance can be increased quite a bit by using the DDSI
|
||||
Internal/SquashParticipants configuration.
|
||||
|
||||
|
||||
Proprietary builtin endpoints
|
||||
******************************
|
||||
|
||||
| The DDS standard contains some builtin endpoints. A few are added by the DDS Security
|
||||
specification. The behaviour of all these builtin endpoints are specified (and thus are be
|
||||
handled by the plugins that implement the DDS Security specification), meaning that they
|
||||
don't have to be present in the Governance or Permissions documents and the users don't
|
||||
have to be bothered with them.
|
||||
|
|
||||
| A few of these builtin endpoints slave according to the <discovery_protection_kind> within
|
||||
the Governance document. In short, related submessages are protected according to the value
|
||||
of <discovery_protection_kind>. This protects meta information that is send during the
|
||||
discovery phase.
|
||||
|
||||
|
||||
*******************
|
||||
DataTag Permissions
|
||||
*******************
|
||||
|
||||
| Data Tags provide an extra (optional) level of identification. This can mean f.i. that
|
||||
a certain reader is not allowed to read data from writer A but it is allowed to read from
|
||||
writer B (all the same topic).
|
||||
|
|
||||
| This optional feature is not yet supported.
|
||||
|
||||
|
||||
***************************
|
||||
External Plugin Development
|
||||
***************************
|
||||
|
||||
DDS Security consists of three plugins (authentication, cryptography and access control).
|
||||
CycloneDDS comes with built-in security plugins that comply with OMG DDS Security specification.
|
||||
The plugins are loaded in the run-time. However, you can also implement your own custom plugin by
|
||||
implementing the given API according to OMG DDS Security specification.
|
||||
You can implement all of the plugins or just one of them.
|
||||
|
||||
| The followings are the key points for implementing you own plugin:
|
||||
|
||||
|
||||
Interface
|
||||
*********
|
||||
|
||||
Implement all plugin specific functions with exactly same prototype. Plugin specific function
|
||||
interfaces are in dds_security_api_access_control.h, dds_security_api_authentication.h and
|
||||
dds_security_api_cryptography.h header files accordingly.
|
||||
|
||||
|
||||
Init and Finalize
|
||||
*****************
|
||||
|
||||
| A plugin should have an init and a finalize functions. plugin_init and plugin_finalize
|
||||
interfaces are given in dds_security_api.h header file and function should be same as in
|
||||
configuration file.
|
||||
| Init function is called once, just after the plugin is loaded. Finalize function is
|
||||
called once, just before the plugin is unloaded.
|
||||
|
||||
|
||||
Inter Plugin Communication
|
||||
**************************
|
||||
|
||||
| There is a shared object (*DDS_Security_SharedSecretHandle*) within authentication and
|
||||
cryptography plugins. If you want to implement only one of them and use the builtin for the
|
||||
other one, you have to get or provide the shared object properly.
|
||||
| *DDS_Security_SharedSecretHandle* is the integer representation of
|
||||
*DDS_Security_SharedSecretHandleImpl* struct object. Cryptography plugin gets the
|
||||
*DDS_Security_SharedSecretHandle* from authentication plugin and casts to
|
||||
*DDS_Security_SharedSecretHandleImpl* struct. Then all needed information can be retieved
|
||||
through *DDS_Security_SharedSecretHandleImpl* struct:
|
||||
|
||||
::
|
||||
|
||||
typedef struct DDS_Security_SharedSecretHandleImpl {
|
||||
DDS_Security_octet* shared_secret;
|
||||
DDS_Security_long shared_secret_size;
|
||||
DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE];
|
||||
DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE];
|
||||
|
||||
} DDS_Security_SharedSecretHandleImpl;
|
||||
|
||||
|
||||
Error Codes
|
||||
***********
|
||||
|
||||
| Most of the plugin functions have parameter for reporting exception. The following exception
|
||||
codes should be used in the reported exception data according to the situation.
|
||||
dds_security_api_err.h header file contains the code and message constants.
|
||||
|
||||
+-------+----------------------------------------------------------------+
|
||||
| Code | Message |
|
||||
+=======+================================================================+
|
||||
| 0 | (OK) |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 100 | Can not generate random data |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 110 | Identity empty |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 111 | Participant Crypto Handle empty |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 112 | Permission Handle empty |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 113 | Invalid Crypto Handle |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 114 | Invalid argument |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 115 | Invalid Crypto token |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 116 | Invalid parameter |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 117 | File could not be found, opened or is empty, path: %s |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 118 | Unknown or unexpected transformation kind |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 119 | Message cannot be authenticated, incorrect signature |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 120 | Can not open trusted CA directory |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 121 | Identity CA is not trusted |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 122 | Certificate start date is in the future |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 123 | Certificate expired |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 125 | Certificate authentication algorithm unknown |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 126 | Failed to allocate internal structure |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 127 | Failed to parse PKCS7 SMIME document |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 128 | Property is missing: (%s) |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 129 | Permissions document is invalid |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 130 | Governance document is invalid |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 131 | Operation is not permitted in this state |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 132 | Remote permissions document is not available |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 133 | Certificate is invalid |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 134 | Certificate type is not supported |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 135 | Governance property is required |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 136 | Permissions CA property is required |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 137 | Can not parse governance file |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 138 | Can not parse permissions file |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 139 | Could not find permissions for topic |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 140 | Could not find domain %d in permissions |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 141 | Could not find domain %d in governance |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 142 | Could not find %s topic attributes for domain(%d) in governance|
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 143 | PluginClass in remote token is incompatible |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 144 | MajorVersion in remote token is incompatible |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 145 | Access denied by access control |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 146 | Subject name is invalid |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 147 | Permissions validity period expired for %s |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 148 | Permissions validity period has not started yet for %s |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 149 | Could not find valid grant in permissions |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 150 | Permissions of subject (%s) outside validity date: %s - %s |
|
||||
+-------+----------------------------------------------------------------+
|
||||
| 151 | Unsupported URI type: %s |
|
||||
+-------+----------------------------------------------------------------+
|
||||
|
||||
.. EoF
|
Loading…
Add table
Add a link
Reference in a new issue