diff --git a/README.md b/README.md index 3aa299a1..f07accac 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ __IMPORTANT NOTICE:__ The contents of this repository currectly reflect a __DRAF 1. [The Links Object](./eiffel-syntax-and-usage/the-links-object.md) 1. [Versioning](./eiffel-syntax-and-usage/versioning.md) 1. [Compositions and Validity Checking](./eiffel-syntax-and-usage/compositions-and-validity-checking.md) + 1. [Security](./eiffel-syntax-and-usage/security.md) 1. The Eiffel Vocabulary 1. [EiffelActivityTriggeredEvent (ActT)](./eiffel-vocabulary/EiffelActivityTriggeredEvent.md) 1. [EiffelActivityCanceledEvent (ActC)](./eiffel-vocabulary/EiffelActivityCanceledEvent.md) diff --git a/eiffel-syntax-and-usage/security.md b/eiffel-syntax-and-usage/security.md new file mode 100644 index 00000000..488b976c --- /dev/null +++ b/eiffel-syntax-and-usage/security.md @@ -0,0 +1,17 @@ +# Security +Let us begin by establishing that the Eiffel protocol by itself can be considered neither _secure_ nor _insecure_, any more than English is secure or French is insecure. Security is not a property of the language or the protocol as such, but of how it is communicated and managed. That being said, security is a highly relevant concern, and where feasible Eiffel supports it. It is important to understand that security is a broad concept, however, and that feasibility varies depending on the type of security in question. In literature, the three key concepts of security (sometimes referred to as the CIA triad) are confidentiality, integrity and availability. We will discuss each of these in turn. + +## Confidentiality +In the words of ISO27000, confidentiality means that "information is not made available or disclosed to unauthorized individuals, entities, or processes". This can be achieved through multiple (and often complementary) means, such as encryption and access control. The Eiffel protocol itself cannot support confidentiality; instead it is a property of the systems used to transport, process and store the Eiffel events. In other words, if the confidentiality of information communicated as Eiffel events is a concern for you, then you are recommended to take appropriate action to ensure the confidentiality of your data, both at rest and in transit, e.g. through encryption. + +## Integrity +In information security, integrity refers to the accuracy and completeness of data. In other words, safeguarding integrity requires protection against both malicious and unintentional tampering with or corruption of data in an unauthorized or undetected manner. This cannot be _solved_ by a communication protocol, as it relies on adequate infrastructure and processes for managing the data, but it can be _supported_. Eiffel supports data integrity through digital signing, according to the [Strong Distribution Model](http://www.cryptnet.net/fdp/crypto/strong_distro.html). + +A digital signature is a combination of hashing technology and encryption. Hash functions are commonly used to ensure data integrity and are familiar to most software professionals. By using checksums or hash values (particularly hash values, or _digests_, produced by cryptographic hash functions such as the SHA series), any piece of data of arbitrary length is computed into a fixed length digest, with any alteration of the input data resulting in a different digest. Consequently, as long as the digest of the received data matches the digest of the data sent, its integrity can be verified. Unfortunately, the digest must be securely communicated: any malicious attacker able to not only manipulate the data but also the digest can make a corrupted message appear authentic. This is why digital signing also employs encryption. + +In the Strong Distribution Model, the author of the data encrypts the digest using a _private key_. A private key is one half of an asymmetric _key pair_, with a matching _public key_ making up the other half. As the names suggest, the private key is kept secret, while the public key is distributed. The two keys in a pair are matches in the sense that one key can decrypt data encrypted by the other, and vice versa. In other words, if the recipient of a message can identify the correct public key and use it to decrypt the digest, and that digest turns out to be correct, both the identity of the author and the integrity of the data can be verified. + +In support of this model, Eiffel events optionally include properties for communicating author identity and the encrypted digest as part of the __meta.security__ object. In combination, these two properties enable enforcement of the Strong Distribution Model. They are kept optional, however, as the Eiffel protocol itself leaves the decision to the user whether to make use of this security feature. Note that this optionality does not in any way lessen the strength of the security model: it is always up to the recipient of an unprotected Eiffel event to decide whether to trust it or not. In this sense, Eiffel support of data integrity is very similar to that employed by other document formats, such as the [Portable Document Format](http://www.adobe.com/devnet/pdf/pdf_reference.html). + +## Availability +Availability of information communicated over the Eiffel protocol is a property of the communication channels and storage solutions used. In other words, similarly to confidentiality, it is an infrastructural concern and external to the protocol itself. \ No newline at end of file diff --git a/eiffel-syntax-and-usage/the-meta-object.md b/eiffel-syntax-and-usage/the-meta-object.md index a83d0915..d406295b 100644 --- a/eiffel-syntax-and-usage/the-meta-object.md +++ b/eiffel-syntax-and-usage/the-meta-object.md @@ -86,6 +86,29 @@ __Format:__ URI __Required:__ No __Description:__ The URI of, related to or describing the event sender. +### meta.security +__Type:__ Object +__Format:__ +__Required:__ No +__Description:__ An optional object for enclosing security related information, particularly supporting data integrity. See [Security](../eiffel-syntax-and-usage/security.md) for further information. + +#### meta.security.sdm +__Type:__ Object +__Format:__ +__Required:__ No +__Description:__ An optional object for properties supporting the [Strong Distribution Model](http://www.cryptnet.net/fdp/crypto/strong_distro.html). Note that this only addressed the _integrity_ of the Eiffel event, not its _confidentiality_ or _availability_. + +##### meta.security.sdm.authorIdentity +__Type:__ String +__Format:__ +__Required:__ Yes +__Description:__ The identity of the author of the event. This property is intended to enable the recipient to look up the appropriate public key for decrypting the digest and thereby verifying author identity and data integrity. The format of the author identity varies depending on the key infrastructure solution used. Note that this requires the presence of a Trusted Authority (TA) which the recipient can query for the correct public key. The identity and location of the TA must never be included in the event itself, as this would compromise the security of the solution. + +##### meta.security.sdm.encryptedDigest +__Type:__ String +__Format:__ +__Required:__ Yes +__Description:__ The encrypted digest. The cryptographic hash function and the decryption algorithm to use, similarly to the Trusted Authority (TA), must be known to the recipient. Note that the digest of the entire event is affected by the value of this property. For this reason the input to the hash function SHALL be the entire event unaltered in all parts except for this property, which SHALL be replaced by an empty string.     @@ -93,4 +116,4 @@ __Description:__ The URI of, related to or describing the event sender. ------------------   -1: Event types are versioned independently from one another. There are three important consequences of this. First, any change to __meta__ requires all events to be updated. Second, any schema of a specific version of an event must also include the __meta__ object – specifically as it is defined for that version of the event. Third, consumers should be prepared to receive events of varying __meta__ contents. The exception to this are the __meta.type__ and __meta.version__ fields, which are always assumed to be present change. +1: Event types are versioned independently from one another. There are three important consequences of this. First, any change to __meta__ requires all events to be updated. Second, any schema of a specific version of an event must also include the __meta__ object – specifically as it is defined for that version of the event. Third, consumers should be prepared to receive events of varying __meta__ contents. The exception to this are the __meta.type__ and __meta.version__ fields, which are always assumed to be present change. \ No newline at end of file diff --git a/examples/events/EiffelArtifactPublishedEvent/simple.json b/examples/events/EiffelArtifactPublishedEvent/simple.json index f7abe67a..527c2fa1 100644 --- a/examples/events/EiffelArtifactPublishedEvent/simple.json +++ b/examples/events/EiffelArtifactPublishedEvent/simple.json @@ -3,7 +3,13 @@ "type": "EiffelArtifactPublishedEvent", "version": "1.0.0", "time": 1234567890, - "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee0" + "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee0", + "security": { + "sdm": { + "authorIdentity": "MyCompany/JohnDoe", + "encryptedDigest": "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a" + } + } }, "data": { "locations": [ diff --git a/schemas/EiffelActivityCanceledEvent/1.0.0.json b/schemas/EiffelActivityCanceledEvent/1.0.0.json index 66a5c7cb..82e220a4 100644 --- a/schemas/EiffelActivityCanceledEvent/1.0.0.json +++ b/schemas/EiffelActivityCanceledEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelActivityFinishedEvent/1.0.0.json b/schemas/EiffelActivityFinishedEvent/1.0.0.json index 1585bb38..ef18cae5 100644 --- a/schemas/EiffelActivityFinishedEvent/1.0.0.json +++ b/schemas/EiffelActivityFinishedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelActivityStartedEvent/1.0.0.json b/schemas/EiffelActivityStartedEvent/1.0.0.json index a6ab73a2..8407427c 100644 --- a/schemas/EiffelActivityStartedEvent/1.0.0.json +++ b/schemas/EiffelActivityStartedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelActivityTriggeredEvent/1.0.0.json b/schemas/EiffelActivityTriggeredEvent/1.0.0.json index d14902bf..2fb70d1a 100644 --- a/schemas/EiffelActivityTriggeredEvent/1.0.0.json +++ b/schemas/EiffelActivityTriggeredEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelAnnouncementPublishedEvent/1.0.0.json b/schemas/EiffelAnnouncementPublishedEvent/1.0.0.json index 66423a9d..19d4eb7b 100644 --- a/schemas/EiffelAnnouncementPublishedEvent/1.0.0.json +++ b/schemas/EiffelAnnouncementPublishedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelArtifactCreatedEvent/1.0.0.json b/schemas/EiffelArtifactCreatedEvent/1.0.0.json index 0ee11e3c..38ea49b9 100644 --- a/schemas/EiffelArtifactCreatedEvent/1.0.0.json +++ b/schemas/EiffelArtifactCreatedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelArtifactPublishedEvent/1.0.0.json b/schemas/EiffelArtifactPublishedEvent/1.0.0.json index 54f31e76..dab43962 100644 --- a/schemas/EiffelArtifactPublishedEvent/1.0.0.json +++ b/schemas/EiffelArtifactPublishedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelArtifactReusedEvent/1.0.0.json b/schemas/EiffelArtifactReusedEvent/1.0.0.json index a1481213..94dcc574 100644 --- a/schemas/EiffelArtifactReusedEvent/1.0.0.json +++ b/schemas/EiffelArtifactReusedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelCompositionDefinedEvent/1.0.0.json b/schemas/EiffelCompositionDefinedEvent/1.0.0.json index 1a12fd41..cc8bf497 100644 --- a/schemas/EiffelCompositionDefinedEvent/1.0.0.json +++ b/schemas/EiffelCompositionDefinedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelConfidenceLevelModifiedEvent/1.0.0.json b/schemas/EiffelConfidenceLevelModifiedEvent/1.0.0.json index 3eba188f..0e2d9610 100644 --- a/schemas/EiffelConfidenceLevelModifiedEvent/1.0.0.json +++ b/schemas/EiffelConfidenceLevelModifiedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelEnvironmentDefinedEvent/1.0.0.json b/schemas/EiffelEnvironmentDefinedEvent/1.0.0.json index a42a0d9d..576fbccb 100644 --- a/schemas/EiffelEnvironmentDefinedEvent/1.0.0.json +++ b/schemas/EiffelEnvironmentDefinedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelFlowContextDefinedEvent/1.0.0.json b/schemas/EiffelFlowContextDefinedEvent/1.0.0.json index 249bef96..7edac9e2 100644 --- a/schemas/EiffelFlowContextDefinedEvent/1.0.0.json +++ b/schemas/EiffelFlowContextDefinedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelIssueVerifiedEvent/1.0.0.json b/schemas/EiffelIssueVerifiedEvent/1.0.0.json index 154e0238..62f9c85e 100644 --- a/schemas/EiffelIssueVerifiedEvent/1.0.0.json +++ b/schemas/EiffelIssueVerifiedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelSourceChangeCreatedEvent/1.0.0.json b/schemas/EiffelSourceChangeCreatedEvent/1.0.0.json index 27402849..f496bbc0 100644 --- a/schemas/EiffelSourceChangeCreatedEvent/1.0.0.json +++ b/schemas/EiffelSourceChangeCreatedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelSourceChangeSubmittedEvent/1.0.0.json b/schemas/EiffelSourceChangeSubmittedEvent/1.0.0.json index f4fd2563..d515472c 100644 --- a/schemas/EiffelSourceChangeSubmittedEvent/1.0.0.json +++ b/schemas/EiffelSourceChangeSubmittedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelTestCaseFinishedEvent/1.0.0.json b/schemas/EiffelTestCaseFinishedEvent/1.0.0.json index f1b54c5d..8ad36180 100644 --- a/schemas/EiffelTestCaseFinishedEvent/1.0.0.json +++ b/schemas/EiffelTestCaseFinishedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelTestCaseStartedEvent/1.0.0.json b/schemas/EiffelTestCaseStartedEvent/1.0.0.json index f98b0377..6987a46e 100644 --- a/schemas/EiffelTestCaseStartedEvent/1.0.0.json +++ b/schemas/EiffelTestCaseStartedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelTestExecutionRecipeCollectionCreatedEvent/1.0.0.json b/schemas/EiffelTestExecutionRecipeCollectionCreatedEvent/1.0.0.json index 55527d64..5156bb67 100644 --- a/schemas/EiffelTestExecutionRecipeCollectionCreatedEvent/1.0.0.json +++ b/schemas/EiffelTestExecutionRecipeCollectionCreatedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelTestSuiteFinishedEvent/1.0.0.json b/schemas/EiffelTestSuiteFinishedEvent/1.0.0.json index 3e4fae62..ec2306d9 100644 --- a/schemas/EiffelTestSuiteFinishedEvent/1.0.0.json +++ b/schemas/EiffelTestSuiteFinishedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [ diff --git a/schemas/EiffelTestSuiteStartedEvent/1.0.0.json b/schemas/EiffelTestSuiteStartedEvent/1.0.0.json index 1e8093a0..6210b732 100644 --- a/schemas/EiffelTestSuiteStartedEvent/1.0.0.json +++ b/schemas/EiffelTestSuiteStartedEvent/1.0.0.json @@ -63,6 +63,28 @@ } }, "additionalProperties": false + }, + "security": { + "type": "object", + "properties": { + "sdm": { + "type": "object", + "properties": { + "authorIdentity": { + "type": "string" + }, + "encryptedDigest": { + "type": "string" + } + }, + "required": [ + "authorIdentity", + "encryptedDigest" + ], + "additionalProperties": false + } + }, + "additionalProperties": false } }, "required": [