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

Rename to DSSE, update PAE, mark as v1 #37

Merged
merged 8 commits into from
Jun 21, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# signing-spec
# DSSE: Dead Simple Signing Envelope

Simple, foolproof standard for signing arbitrary data.

Expand Down
20 changes: 13 additions & 7 deletions envelope.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# signing-spec Envelope
# DSSE Envelope

March 03, 2021

Version 0.1.0
Version 1.0.0

This document describes the recommended data structure for storing signing-spec
This document describes the recommended data structure for storing DSSE
signatures, which we call the "JSON Envelope". For the protocol/algorithm, see
[Protocol](protocol.md).

Expand All @@ -29,16 +29,13 @@ the following form, called the "JSON envelope":

See [Protocol](protocol.md) for a definition of parameters and functions.

Empty fields may be omitted. [Multiple signatures](#multiple-signatures) are
allowed.

Base64() is [Base64 encoding](https://tools.ietf.org/html/rfc4648), transforming
a byte sequence to a unicode string. Either standard or URL-safe encoding is
allowed.

### Multiple signatures

An envelope may have more than one signature, which is equivalent to separate
An envelope MAY have more than one signature, which is equivalent to separate
envelopes with individual signatures.

```json
Expand All @@ -55,6 +52,15 @@ envelopes with individual signatures.
}
```

### Parsing rules

* The following fields are REQUIRED and MUST be set, even if empty: `payload`,
`payloadType`, `signature`, `signature.sig`.
* The following fields are OPTIONAL and MAY be unset: `signature.keyid`.
An unset field MUST be treated the same as set-but-empty.
* Producers, or future versions of the spec, MAY add additional fields.
Consumers MUST ignore unrecognized fields.

## Other data structures

The standard envelope is JSON message with an explicit `payloadType`.
Expand Down
23 changes: 7 additions & 16 deletions implementation/signing_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The following example requires `pip3 install pycryptodome` and uses ecdsa.py in
the same directory as this file.

>>> import binascii, os, sys, textwrap
>>> import os, sys
>>> from pprint import pprint
>>> sys.path.insert(0, os.path.dirname(__file__))
>>> import ecdsa
Expand All @@ -26,7 +26,7 @@
>>> pprint(json.loads(signature_json))
{'payload': 'aGVsbG8gd29ybGQ=',
'payloadType': 'http://example.com/HelloWorld',
'signatures': [{'sig': 'Cc3RkvYsLhlaFVd+d6FPx4ZClhqW4ZT0rnCYAfv6/ckoGdwT7g/blWNpOBuL/tZhRiVFaglOGTU8GEjm4aEaNA=='}]}
'signatures': [{'sig': 'A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=='}]}

Verification example:

Expand All @@ -36,14 +36,8 @@

PAE:

>>> def print_hex(b: bytes):
... octets = ' '.join(textwrap.wrap(binascii.hexlify(b).decode('utf-8'), 2))
... print(*textwrap.wrap(octets, 48), sep='\n')
>>> print_hex(PAE(payloadType, payload))
02 00 00 00 00 00 00 00 1d 00 00 00 00 00 00 00
68 74 74 70 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63
6f 6d 2f 48 65 6c 6c 6f 57 6f 72 6c 64 0b 00 00
00 00 00 00 00 68 65 6c 6c 6f 20 77 6f 72 6c 64
>>> PAE(payloadType, payload)
b'DSSEv1 29 http://example.com/HelloWorld 11 hello world'
"""

import base64, binascii, dataclasses, json, struct
Expand Down Expand Up @@ -88,12 +82,9 @@ def b64dec(m: str) -> bytes:


def PAE(payloadType: str, payload: bytes) -> bytes:
return b''.join([
struct.pack('<Q', 2),
struct.pack('<Q', len(payloadType)),
payloadType.encode('utf-8'),
struct.pack('<Q', len(payload)), payload
])
return b'DSSEv1 %d %b %d %b' % (
len(payloadType), payloadType.encode('utf-8'),
len(payload), payload)


def Sign(payloadType: str, payload: bytes, signer: Signer) -> str:
Expand Down
42 changes: 21 additions & 21 deletions protocol.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# signing-spec Protocol
# DSSE Protocol

March 03, 2021

Version 0.1.0
Version 1.0.0

This document describes the protocol/algorithm for creating and verifying
signing-spec signatures, independent of how they are transmitted or stored. For
the recommended data structure, see [Envelope](envelope.md).
This document describes the protocol/algorithm for creating and verifying DSSE
signatures, independent of how they are transmitted or stored. For the
recommended data structure, see [Envelope](envelope.md).

## Signature Definition

Expand All @@ -24,7 +24,7 @@ SERIALIZED_BODY | bytes | Yes | Yes
PAYLOAD_TYPE | string | Yes | Yes
KEYID | string | No | No

* SERIALIZED_BODY: Byte sequence to be signed.
* SERIALIZED_BODY: Arbitrary byte sequence to be signed.

* PAYLOAD_TYPE: Opaque, case-sensitive string that uniquely and unambiguously
identifies how to interpret `payload`. This includes both the encoding
Expand All @@ -34,10 +34,11 @@ KEYID | string | No | No
* [Media Type](https://www.iana.org/assignments/media-types/), a.k.a. MIME
type or Content Type
* Example: `application/vnd.in-toto+json`.
* IMPORTANT: SHOULD NOT be a generic type that only represents
encoding but not schema. For example, `application/json` is almost
always WRONG. Instead, invent a media type specific for your
application in the `application/vnd` namespace.
* IMPORTANT: This SHOULD be an application-specific type describing
both encoding and schema, NOT a generic type like
`application/json`. The problem with generic types is that two
different applications could use the same encoding (e.g. JSON) but
interpret the payload differently.
* SHOULD be lowercase.
* [URI](https://tools.ietf.org/html/rfc3986)
* Example: `https://example.com/MyMessage/v1-json`.
Expand All @@ -53,13 +54,15 @@ KEYID | string | No | No

Functions:

* PAE() is the
[PASETO Pre-Authentication Encoding](https://github.com/paragonie/paseto/blob/master/docs/01-Protocol-Versions/Common.md#authentication-padding),
where parameters `type` and `body` are byte sequences:
* PAE() is the "Pre-Authentication Encoding", where parameters `type` and
`body` are byte sequences:

```none
PAE(type, body) := le64(2) || le64(len(type)) || type || le64(len(body)) || body
le64(n) := 64-bit little-endian encoding of `n`, where 0 <= n < 2^63
PAE(type, body) = "DSSEv1" + SP + LEN(type) + SP + type + SP + LEN(body) + SP + body
+ = concatenation
SP = ASCII space [0x20]
"DSSEv1" = ASCII [0x44, 0x53, 0x53, 0x45, 0x76, 0x31]
LEN(s) = ASCII decimal encoding of the byte length of s, with no leading zeros
```

* Sign() is an arbitrary digital signature format. Details are agreed upon
Expand Down Expand Up @@ -102,7 +105,7 @@ either, and verifiers **MUST** accept either.

## Test Vectors

See [reference implementation](reference_implementation.ipynb). Here is an
See [reference implementation](implementation/signing_spec.py). Here is an
example.

SERIALIZED_BODY:
Expand All @@ -120,10 +123,7 @@ http://example.com/HelloWorld
PAE:

```none
02 00 00 00 00 00 00 00 1d 00 00 00 00 00 00 00
68 74 74 70 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63
6f 6d 2f 48 65 6c 6c 6f 57 6f 72 6c 64 0b 00 00
00 00 00 00 00 68 65 6c 6c 6f 20 77 6f 72 6c 64
DSSEv1 29 http://example.com/HelloWorld 11 hello world
```

Cryptographic keys:
Expand All @@ -141,7 +141,7 @@ Result (using the recommended [JSON envelope](envelope.md)):
```json
{"payload": "aGVsbG8gd29ybGQ=",
"payloadType": "http://example.com/HelloWorld",
"signatures": [{"sig": "y7BK8Mm8Mr4gxk4+G9X3BD1iBc/vVVuJuV4ubmsEK4m/8MhQOOS26ejx+weIjyAx8VjYoZRPpoXSNjHEzdE7nQ=="}]}
"signatures": [{"sig": "A3JqsQGtVsJ2O2xqrI5IcnXip5GToJ3F+FnZ+O88SjtR6rDAajabZKciJTfUiHqJPcIAriEGAHTVeCUjW2JIZA=="}]}
```

[Canonical JSON]: http://wiki.laptop.org/go/Canonical_JSON
Expand Down