-
Notifications
You must be signed in to change notification settings - Fork 18
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
Add support for x509 certificates in DSSE #50
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Asra Ali <[email protected]>
Signed-off-by: Asra Ali <[email protected]>
Yes, they must verify it. If they don't know about the root, they should probably reject the signature as they don't know whether to trust it.
Is there anything other than the cert that would/could be added to this envelope? If there are other fields that would be helpful specifically for PKI, I'd suggest we move this there to keep DSSE simple. If it's just the cert I don't think the wrapper is needed. |
Hmm, interesting. Could someone explain the use cases here for distributing these public keys / certs in such a manner? For example, is it for Fulcio? Because I'm not sure whether we ever arrived at a consensus for #42. |
ITE-7 for one would eventually need this. That in turn enables SPIFFE / SPIRE support in in-toto. Also, the proposal here closely mirrors the changes ITE-7 recommends to the old signature wrapper! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a use case for non-X509 certificates? If so, should the name be "x509cert" or similar?
IF the certificate is defined, MUST the clients verify it against a root? I think yes. (But what if clients don't know or care about the root?)
Yes, or more accurately, if and only if it is used. The client MUST authenticate the certificate before using it, but they are free to ignore the field altogether if they are verifying the payload against some other root of trust.
envelope.md
Outdated
@@ -33,6 +34,8 @@ 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. | |||
|
|||
PEM() is a [PEM encoding](), transforming a DER (binary) encoded X.509 certificate to a base64 encoding with a one-line header and footer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to fix the link to PEM encoding.
implementation/signing_spec.py
Outdated
@@ -56,6 +56,9 @@ def keyid(self) -> Optional[str]: | |||
"""Returns the ID of this key, or None if not supported.""" | |||
... | |||
|
|||
def certificate(self) -> Optional[str]: | |||
"""Returns the cert chain of the key, or None if not supported.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in PEM format
implementation/signing_spec.py
Outdated
@@ -66,10 +69,16 @@ def keyid(self) -> Optional[str]: | |||
"""Returns the ID of this key, or None if not supported.""" | |||
... | |||
|
|||
class RootPool(Protocol): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be part of the interface. Instead:
Verifier.verify
ought to take acert: str
(which may be empty) argument- If the implementation of Verifier does not accept certificates, it MUST ignore the
cert
field. - If the implementation of Verifier does accept certificates, it MUST verify
cert
using a known root pool before verifying thatsignature
was signed bycert
.
protocol.md
Outdated
@@ -77,7 +84,7 @@ Functions: | |||
Out of band: | |||
|
|||
- Agree on a PAYLOAD_TYPE and cryptographic details, optionally including | |||
KEYID. | |||
KEYID and trusted root certificates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I worry that this small amount of detail will lead to insecure implementations, in particular just verifying that it came from a trusted root but not verifying the actual chain properties (e.g. common name). Previously, "cryptographic details" implied roots of trust because we said nothing about the public key. Now root certs are called out explicitly, but without sufficient detail.
I feel like we need to either say less (so that it's obvious that there is missing detail) or more (so that it's clear how to implement correctly.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in particular just verifying that it came from a trusted root but not verifying the actual chain properties (e.g. common name).
Hmmm I had to think about this. I would definitely like to call this out explicitly because leaving it out would lead to people potentially not verifying the chain and using the public key inside to verify the sig.
I agree that this does not call out details on path validation: I could link https://www.rfc-editor.org/rfc/rfc5280.html#section-6, and rephrase to say and trusted root certificates and constraints
. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure RFC5280 is sufficient. That RFC is super complex, and it sounds like TLS doesn't even use it directly. It is more strict and requires a SEQUENCE of certificates that leads directly from the root CA to the server's certificate (or the other way around?) and it does something with the subject name to match against the domain name. I feel like we need to call that out explicitly, or else it will get dropped.
Alternatively, is there some implementation we can point to to make things more concrete?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are also caveats around Common Name vs Subject Alternative Name. I think the former used to be the one to verify, but now it's the latter in TLS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure RFC5280 is sufficient. That RFC is super complex, and it sounds like TLS doesn't even use it directly. It is more strict and requires a SEQUENCE of certificates that leads directly from the root CA to the server's certificate (or the other way around?) and it does something with the subject name to match against the domain name. I feel like we need to call that out explicitly, or else it will get dropped.
Alternatively, is there some implementation we can point to to make things more concrete?
I just had to deal with this myself, and ended up using https://github.com/wbond/certvalidator which does complete path validation back to trusted roots
protocol.md
Outdated
- Optionally, filter acceptable public keys by KEYID. | ||
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY). Reject if | ||
the verification fails. | ||
- Optionally, verify the signing key's CERTIFICATE chains back to a trusted root. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds too optional and too insecure. I suggest folding it into the line above, maybe:
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY) using the predefined roots of trust and optionally CERTIFICATE. If CERTIFICATE is used, it MUST be verified against a trusted root certificate. Reject if the verification fails.
Yes -- for any certificate that's shortlived, you would also want to specify a signed timestamp (e.g. an RFC 3161) from a timestamp authority. So we would also need a generic
Yep, it's for short lived certs, and can also be used to identify identity of a public key as normal x509 certificate usage. And yes! Exactly, ITE-7 would support this.
There are some other certificate formats, like SPKI, but that's in draft form, or openpgp's certificate formats, or CVC's. I think we should keep a general name, although 99% of use-cases are probably x.509. |
Signed-off-by: Asra Ali <[email protected]>
@@ -33,6 +34,8 @@ 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. | |||
|
|||
PEM() is a [PEM encoding](https://datatracker.ietf.org/doc/html/rfc1421), transforming a DER (binary) encoded X.509 certificate to a base64 encoding with a one-line header and footer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nits:
- This is a certificate chain, so it is a series of PEM-encoded certificates, concatenated with newlines?
- wrap at 80 columns for consistency with rest of file
@@ -52,6 +53,12 @@ KEYID | string | No | No | |||
decisions; it may only be used to narrow the selection of possible keys to | |||
try. | |||
|
|||
* CERTIFICATE: Optional, unauthenticated PEM encoded X.509 certificate chain for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Should we also allow ASN.1 encoding in the protocol? I can see why we'd want to specify PEM in the JSON envelope because that would need base64 encoding otherwise, but a different envelope format (say CBOR or protobuf) might want a binary format encoding of the certificate.
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY) using | ||
the predefined roots of trust and constraints optionally CERTIFICATE. If | ||
CERTIFICATE is specified, it MUST be verified against a trusted root | ||
certificate. Reject if the verification fails. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"trusted root certificate and path validation" or similar
same on line 134 below
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY). Reject if | ||
the verification fails. | ||
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY) using | ||
the predefined roots of trust and constraints optionally CERTIFICATE. If |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: remove "constraints"
same on line 132 below
- Verify SIGNATURE against PAE(UTF8(PAYLOAD_TYPE), SERIALIZED_BODY) using | ||
the predefined roots of trust and constraints optionally CERTIFICATE. If | ||
CERTIFICATE is specified, it MUST be verified against a trusted root | ||
certificate. Reject if the verification fails. | ||
- Add the accepted public key to the set ACCEPTED_KEYS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: ACCEPTED_KEYS is no longer correct. What should this be instead?
protocol.md
Outdated
@@ -77,7 +84,7 @@ Functions: | |||
Out of band: | |||
|
|||
- Agree on a PAYLOAD_TYPE and cryptographic details, optionally including | |||
KEYID. | |||
KEYID and trusted root certificates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure RFC5280 is sufficient. That RFC is super complex, and it sounds like TLS doesn't even use it directly. It is more strict and requires a SEQUENCE of certificates that leads directly from the root CA to the server's certificate (or the other way around?) and it does something with the subject name to match against the domain name. I feel like we need to call that out explicitly, or else it will get dropped.
Alternatively, is there some implementation we can point to to make things more concrete?
Just a quick ping: will be addressing comments and sending at least one update today. |
I see this PR has been dormant for a while. @asraa are you still working on this change? 😄 |
We would love to see this merged in. We have extended DSSE in our implementation of Witness, and we would like to bring it in spec. https://github.com/testifysec/go-witness/blob/main/dsse/dsse.go#L56 |
Signed-off-by: Asra Ali [email protected]
Adds an optional field for specifying an x509
certificate
to asignature
. This is unathenticated content used to additionally verify that the certificate for the public key used for the signature chains back to a trusted root.Fixes #42
Open questions:
Also, see sigstore/cosign#1743
Related:
https://github.com/in-toto/ITE/tree/master/ITE/7#metadata-signtaures
@laurentsimon @MarkLodato @dlorenc