Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ITE-5: Replace signature wrapper with SSL signing spec #13

Merged
merged 24 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dd228c5
Add initial draft of ITE-5.
MarkLodato Sep 28, 2020
8d77a45
ITE-5: Fix typo, PAYLOAD -> SERIALIZED_BODY.
MarkLodato Oct 5, 2020
54592d9
ENH: refer to signing-spec, reframe motivation
SantiagoTorres Nov 24, 2020
df231f0
Merge branch 'master' of github.com:/in-toto/ITE into ite-5
SantiagoTorres Nov 24, 2020
c804293
grammar: fix usage from backwards compatible
SantiagoTorres Nov 24, 2020
86b7e5d
FIX: grammar nits
SantiagoTorres Nov 24, 2020
6ffd23d
FIX: use new title one header
SantiagoTorres Nov 24, 2020
0c22027
Misc. writing fixes
SantiagoTorres Nov 30, 2020
d73f327
Fix link to ITE-5
MarkLodato Apr 13, 2021
6da5622
Rename "wrapper" to "envelope".
MarkLodato Apr 13, 2021
049136c
Typo fix: addition
MarkLodato Apr 13, 2021
e891a60
Remove reference to backwards compatible mode.
MarkLodato Apr 13, 2021
44fbebf
Remove test vectors from ITE-5.
MarkLodato Apr 13, 2021
7b22a40
Specify payloadType and payload
MarkLodato Apr 13, 2021
524c384
Fix asciidoc syntax
MarkLodato Apr 13, 2021
351b22b
Add Backwards Compatibility section.
MarkLodato Apr 13, 2021
18a9e24
Prototype implementation is just of the envelope
MarkLodato Apr 13, 2021
c77da2b
Talk about pointing payloadType URLs to docs
MarkLodato Apr 13, 2021
a4aaea1
Remove obsolete python notebooks.
MarkLodato Apr 14, 2021
6a4b34b
Refer to specific signing spec revision.
MarkLodato Apr 14, 2021
ab77440
Use single payloadType of LegacyJsonMessage.
MarkLodato Apr 14, 2021
2a12c6b
Add pseudocode to spec
MarkLodato Apr 14, 2021
bcc3e9b
Remove discussion of supporting arbitrary envelopes.
MarkLodato Apr 14, 2021
a12eb60
fix typo: spec
MarkLodato Apr 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions ITE/5/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
= ITE-5: Replace signature envelope with SSL signing spec
:source-highlighter: pygments
:toc: preamble
:toclevels: 2
ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

.Metadata
[cols="2"]
|===
| ITE
| 5

| Title
| Replace signature envelope with SSL signing spec

| Sponsor
| link:https://github.com/santiagotorres[Santiago Torres]

| Status
| Draft 💬


| Type
| Standards

| Created
| 2020-09-28

|===

[[abstract]]
== Abstract

This link:https://github.com/in-toto/ITE[in-toto enhancement (ITE)] proposes
removing the in-toto signature scheme requirements, and allow users to adopt the
signature envelope that better fits their ecosystem. This has the following
MarkLodato marked this conversation as resolved.
Show resolved Hide resolved
general benefits:

1. avoid mandating an ad-hoc signing specification for in-toto; and
2. allow for implementers to propose different signing specifications.

In addition, this ITE makes a recommendation to use the
link:http://github.com/secure-systems-lab/signing-spec[SSL Signing Spec]. This
has the following benefits over the current state:

1. Avoids canonicalization for security reasons (i.e., to not parse untrusted input)
2. Reduces the possibility of misinterpretation of the payload. The serialized payload is encoded as a string and verified by the recipient before de-serializing.

[[specification]]
== Specification
MarkLodato marked this conversation as resolved.
Show resolved Hide resolved

The specification adopted will be the SSL signing spec, as linked above. As
such, we defer to that document to describe the specifics of signature
MarkLodato marked this conversation as resolved.
Show resolved Hide resolved
generation and verification.

The envelope's `payloadType` is either:

* `https://in-toto.io/Link/v1+json` (for links)
SantiagoTorres marked this conversation as resolved.
Show resolved Hide resolved
* `https://in-toto.io/Layout/v1+json` (for layouts)

The `payload` is the JSON serialization of the message, equivalent to the
`signed` object in the current format.

Once this ITE is accepted, we will change the website to redirect those URLs to
point to documentation.

[[motivation]]
== Motivation

The early motivations for in-toto to use the current envelope were to allow for
our sister project, TUF, to transparently use the same crypto provider. The
reasoning back then is that we would maximize code reuse, and allow for users
of both solutions to easily integrate them.

However, as time has shown, keeping these two separately-specified signature
envelopes (i.e., one for TUF and one for in-toto) synchronized is rather difficult. As time
passes, and due to the interactions in each community, the signature envelopes
evolve to better fit their user-bases. Adopting a common source of truth (i.e.,
a separate signature specification) should help increase cohesion between
projects while maintaining the original goal of code-reuse and transparent
integration.

In addition, keeping the signature envelope specification *outside* of the
current in-toto specification will also simplify the specification, which can
now only focus on describing in-toto specifics, rather than cryptographic
building blocks.

[[reasoning]]
== Reasoning

Our goal was to adopt a signature envelope that is as simple and foolproof as
possible. Alternatives such as link:https://tools.ietf.org/html/rfc7515[JWS] are
extremely complex and error-prone, while others such as
link:https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version2.md#sig[PASETO]
are overly specific. (Both are also JSON-specific.) We believe the SSL signing
spec strikes the right balance of simplicity, usefulness, and security.

Further, the SSL signing spec is a "natural evolution" of the current signature
envelope, which was defined in both the TUF and in-toto specifications. As such,
it allows for a transparent upgrade via their cryptographic provider,
link:https://github.com/secure-systems-lab/securesystemslib[securesystemslib].

Further information on the reasoning behind the envelope's specifics is provided in the link:https://github.com/secure-systems-lab/signing-spec[signing specification] repository

[[backwards-compatibility]]
== Backwards Compatibility

Implementations should continue to support old-style envelope as well as
new-style SSL Signing Spec envelopes.

[[security]]
== Security

At first sight this proposal is central to security, yet the actual
contribution is to allow for a signature provider to be disaggregated from the
specification. As such, no supply-chain security properties are removed from
the system through this ITE.

The adoption of SSL signing spec slightly improves the security stance of
implementations because they are no longer parsing untrusted input.

[[infrastructure-requirements]]
== Infrastructure Requirements

Since this is a change in the metadata format, no infrastructure requirements
exist.


[[prototype-implementation]]
== Prototype Implementation

See
link:https://github.com/secure-systems-lab/signing-spec/blob/master/reference_implementation.ipynb[reference_implementation.ipynb]
for an implementation of the envelope itself.

[[testing]]
== Testing

The test-suite should include loading/generating both new-style SSL signing spec
metadata as well old-style metadata.

[[references]]
== References

* link:http://gibson042.github.io/canonicaljson-spec/[Canonical JSON]
* link:https://tools.ietf.org/html/rfc7515[JWS]
* link:https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Version2.md#sig[PASETO]
1 change: 1 addition & 0 deletions ITE/5/hypothetical_signature_attack.ipynb

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions ITE/5/reference_implementation.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Copy of ITE-5: reference implementation.ipynb","provenance":[{"file_id":"https://github.com/MarkLodato/ITE/blob/ite-5/ITE/5/reference_implementation.ipynb","timestamp":1601319975941},{"file_id":"1gfSF3mbwhJcP2Lv_ZdOrodmX3qAOI7u8","timestamp":1601064929341}],"collapsed_sections":["yOiiQrZZSdlg"]},"kernelspec":{"name":"python3","display_name":"Python 3"}},"cells":[{"cell_type":"markdown","metadata":{"id":"ll0X3N1LtM_p"},"source":["##### Copyright 2020 Google LLC\n","\n","Licensed under the Apache License, Version 2.0 (the \"License\");\n","you may not use this file except in compliance with the License.\n","You may obtain a copy of the License at\n","\n","https://www.apache.org/licenses/LICENSE-2.0\n","\n","Unless required by applicable law or agreed to in writing, software\n","distributed under the License is distributed on an \"AS IS\" BASIS,\n","WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n","See the License for the specific language governing permissions and\n","limitations under the License."]},{"cell_type":"markdown","metadata":{"id":"XUErxuD6w0_W"},"source":["## Abstract\n","\n","Reference implementation for [ITE-5: Signature scheme that avoids canonicalization](https://github.com/MarkLodato/ITE/tree/ite-5/ITE/5).\n","\n","_Author: Mark Lodato, Google, <lodato@google.com>_ \n","_Date: September 2020_\n","\n","(To edit, [open this doc in Colab](https://colab.research.google.com/github/MarkLodato/ITE/blob/ite-5/ITE/5/reference_implementation.ipynb).)"]},{"cell_type":"markdown","metadata":{"id":"1TaW-T326i9J"},"source":["## Implementation"]},{"cell_type":"code","metadata":{"id":"wYmIALHq6VZU"},"source":["import base64, binascii, json, struct\n","\n","def b64enc(m: bytes) -> str:\n"," return base64.standard_b64encode(m).decode('utf-8')\n","\n","def b64dec(m: str) -> bytes:\n"," m = m.encode('utf-8')\n"," try:\n"," return base64.b64decode(m, validate=True)\n"," except binascii.Error:\n"," return base64.b64decode(m, altchars='-_', validate=True)\n","\n","def PAE(payloadType: str, payload: bytes) -> bytes:\n"," return b''.join([struct.pack('<Q', 2),\n"," struct.pack('<Q', len(payloadType)),\n"," payloadType.encode('utf-8'),\n"," struct.pack('<Q', len(payload)),\n"," payload])\n","\n","def Sign(payloadType: str, payload: bytes, signer) -> str:\n"," return json.dumps({\n"," 'payload': b64enc(payload),\n"," 'payloadType': payloadType,\n"," 'signatures': [{\"sig\": b64enc(signer.sign(PAE(payloadType, payload)))}],\n"," })\n","\n","def Verify(json_signature: str, verifier) -> (str, bytes):\n"," wrapper = json.loads(json_signature)\n"," payloadType = wrapper['payloadType']\n"," payload = b64dec(wrapper['payload'])\n"," pae = PAE(payloadType, payload)\n"," for signature in wrapper['signatures']:\n"," if verifier.verify(pae, b64dec(signature['sig'])):\n"," break\n"," else:\n"," raise ValueError('No valid signature found')\n"," return payloadType, payload"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"gQLf_dxIIOuV"},"source":["## Dummy crypto implementation"]},{"cell_type":"code","metadata":{"id":"9AIpNrzY7zdN"},"source":["!pip install pycryptodome"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"0QRXrBLF70zN"},"source":["from Crypto.Hash import SHA256\n","from Crypto.PublicKey import ECC\n","from Crypto.Signature import DSS\n","\n","class Signer:\n"," def __init__(self, secret_key):\n"," self.secret_key = secret_key\n"," self.public_key = self.secret_key.public_key()\n","\n"," @classmethod\n"," def generate(cls):\n"," return cls(ECC.generate(curve='P-256'))\n","\n"," def sign(self, message: bytes) -> bytes:\n"," \"\"\"Returns the signature of `message`.\"\"\"\n"," h = SHA256.new(message)\n"," return DSS.new(self.secret_key, 'deterministic-rfc6979').sign(h)\n","\n","\n","class Verifier:\n"," def __init__(self, public_key):\n"," self.public_key = public_key\n","\n"," def verify(self, message: bytes, signature: bytes) -> bool:\n"," \"\"\"Returns true if `message` was signed by `signature`.\"\"\"\n"," h = SHA256.new(message)\n"," try:\n"," DSS.new(self.public_key, 'fips-186-3').verify(h, signature)\n"," return True\n"," except ValueError:\n"," return False"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"OPQu5M9x-rPQ"},"source":["## Example"]},{"cell_type":"code","metadata":{"id":"0VIJU06pBxBT","executionInfo":{"status":"ok","timestamp":1601068987772,"user_tz":240,"elapsed":440,"user":{"displayName":"Mark Lodato","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14Gje3VCiWTKvjKn9WNmOK7z5cDhpwtiSncwf3Flh=s64","userId":"14555828759934874531"}},"outputId":"273f5554-d6fe-4312-a6b1-954f219b52ef","colab":{"base_uri":"https://localhost:8080/"}},"source":["signer = Signer.generate()\n","verifier = Verifier(signer.public_key)\n","print('Algorithm: ECDSA with deterministic-rfc6979 and SHA256')\n","print('Curve:', signer.secret_key.curve)\n","print('Public X:', signer.secret_key.pointQ.x)\n","print('Public Y:', signer.secret_key.pointQ.y)\n","print('Private d:', signer.secret_key.d)"],"execution_count":null,"outputs":[{"output_type":"stream","text":["Algorithm: ECDSA with deterministic-rfc6979 and SHA256\n","Curve: NIST P-256\n","Public X: 46950820868899156662930047687818585632848591499744589407958293238635476079160\n","Public Y: 5640078356564379163099075877009565129882514886557779369047442380624545832820\n","Private d: 97358161215184420915383655311931858321456579547487070936769975997791359926199\n"],"name":"stdout"}]},{"cell_type":"code","metadata":{"id":"BmxVhaE-C2zs","executionInfo":{"status":"ok","timestamp":1601068966016,"user_tz":240,"elapsed":387,"user":{"displayName":"Mark Lodato","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14Gje3VCiWTKvjKn9WNmOK7z5cDhpwtiSncwf3Flh=s64","userId":"14555828759934874531"}},"outputId":"3abd6986-ddfe-40f1-b928-22ad311b2c93","colab":{"base_uri":"https://localhost:8080/"}},"source":["signature_json = Sign('http://example.com/HelloWorld', b'hello world', signer)\n","json.loads(signature_json)"],"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["{'payload': 'aGVsbG8gd29ybGQ=',\n"," 'payloadType': 'http://example.com/HelloWorld',\n"," 'signatures': [{'sig': 'y7BK8Mm8Mr4gxk4+G9X3BD1iBc/vVVuJuV4ubmsEK4m/8MhQOOS26ejx+weIjyAx8VjYoZRPpoXSNjHEzdE7nQ=='}]}"]},"metadata":{"tags":[]},"execution_count":50}]},{"cell_type":"code","metadata":{"id":"VXqcUMh3IHoM","executionInfo":{"status":"ok","timestamp":1601068967258,"user_tz":240,"elapsed":409,"user":{"displayName":"Mark Lodato","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14Gje3VCiWTKvjKn9WNmOK7z5cDhpwtiSncwf3Flh=s64","userId":"14555828759934874531"}},"outputId":"6bb8e289-3b00-4cc8-c6dd-0a308cfc8098","colab":{"base_uri":"https://localhost:8080/"}},"source":["Verify(signature_json, verifier)"],"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["('http://example.com/HelloWorld', b'hello world')"]},"metadata":{"tags":[]},"execution_count":51}]},{"cell_type":"code","metadata":{"id":"BjwUSztTKjNE","executionInfo":{"status":"ok","timestamp":1601069676465,"user_tz":240,"elapsed":387,"user":{"displayName":"Mark Lodato","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14Gje3VCiWTKvjKn9WNmOK7z5cDhpwtiSncwf3Flh=s64","userId":"14555828759934874531"}},"outputId":"a3cddfb6-b8a9-4f19-ec66-09d79ce762bd","colab":{"base_uri":"https://localhost:8080/"}},"source":["import binascii, textwrap\n","def print_hex(b: bytes):\n"," octets = ' '.join(textwrap.wrap(binascii.hexlify(b).decode('utf-8'), 2))\n"," print(*textwrap.wrap(octets, 48), sep='\\n')\n","\n","print_hex(PAE('http://example.com/HelloWorld', b'hello world'))"],"execution_count":null,"outputs":[{"output_type":"stream","text":["02 00 00 00 00 00 00 00 1d 00 00 00 00 00 00 00\n","68 74 74 70 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63\n","6f 6d 2f 48 65 6c 6c 6f 57 6f 72 6c 64 0b 00 00\n","00 00 00 00 00 68 65 6c 6c 6f 20 77 6f 72 6c 64\n"],"name":"stdout"}]}]}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

* [ITE-2: A general overview of combining TUF and in-toto to build compromise-resilient CI/CD](ITE/2/README.adoc)
* [ITE-3: Real-world example of combining TUF and in-toto for packaging Datadog Agent integrations](ITE/3/README.adoc)
* [ITE-5: Replace signature envelope with SSL signing spe](ITE/5/README.adoc)
MarkLodato marked this conversation as resolved.
Show resolved Hide resolved

## License

Expand Down