aboutsummaryrefslogtreecommitdiff
path: root/archive
diff options
context:
space:
mode:
Diffstat (limited to 'archive')
-rw-r--r--archive/2022-03-14-notes-on-sigsum-and-rekor.md533
1 files changed, 533 insertions, 0 deletions
diff --git a/archive/2022-03-14-notes-on-sigsum-and-rekor.md b/archive/2022-03-14-notes-on-sigsum-and-rekor.md
new file mode 100644
index 0000000..d19e696
--- /dev/null
+++ b/archive/2022-03-14-notes-on-sigsum-and-rekor.md
@@ -0,0 +1,533 @@
+# A frequently asked question
+We are frequently asked how Sigsum compares to Sigstore. This document
+highlights some technical similarities and differences as of March, 2022.
+
+Sigstore's sub-project Rekor and Sigsum are both transparency log designs that
+aim to make a signer's key-usage transparent. By enabling end-users to verify
+that signatures they trust are public, they are protected from accepting
+malicious signatures that were created in secret (e.g., due to key compromise).
+
+The following transparency log concepts are explored side-by-side:
+
+ - Purpose of logging
+ - What is logged
+ - Auditing
+ - Gossip
+ - Anti-poison
+ - Anti-spam
+ - Privacy
+ - API
+ - Promises of future logging (SCTs)
+ - Sharding
+
+There is also an Appendix at the end with relevant code snippets.
+
+## Purpose of logging
+
+**Sigsum**
+
+No signature that an end-user accepts as valid should go unnoticed by anyone who
+inspects the log.
+
+Sigsum is designed to be secure even if an attacker controls:
+
+ - The signer's infrastructure and signing key
+ - The log's infrastructure and signing key
+ - A threshold of independent witnesses that cosign the log
+
+The log operator is not trusted beyond being available at the time of logging.
+
+**Sigstore/Rekor**
+
+[Rekor's README][] says that the goal is to "[e]nable software maintainers and
+build systems to record signed metadata to an immutable record", and that it
+"fulfils the signature transparency role of sigstore's software signing
+infrastructure". [No threat model][] is available at the time of writing.
+
+[Rekor's README]: https://github.com/sigstore/rekor/tree/6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5#readme
+[No threat model]: https://web.archive.org/web/20220312143825/https://docs.sigstore.dev/security/
+
+## What is logged
+
+**Sigsum**
+
+A shard hint, a SHA256 checksum, an Ed25519 signature, and a SHA256-hashed
+public key. The signed blob is based on the [SSH format][]. The logged
+signatures are verifiable by anyone who knows the corresponding public keys.
+
+[SSH format]: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.sshsig
+
+**Sigstore/Rekor**
+
+Signed manifests called [pluggable types][]. The rekord type allows signatures
+based on Signify, Minisign, SSH, and PGP, as well as PKIX/X.509. For example,
+you could log a signature for a PGP email that was received in 2002. There are
+several other pluggable types with more to come. Rekor is overall permissive.
+
+Some pluggable type signatures are not verifiable in isolation for a monitor
+that observes the log because to verify a signature data is needed that is not
+included in the log and might be known only to the creator of the signature, see
+"Example 1: unverifiable signatures" in the Appendix at the end. This means
+that it is impossible to distinguish between unverifiable log entries fabricated
+by the log and log entries maliciously created with a signer's private key.
+
+[pluggable types]: https://github.com/sigstore/rekor/blob/6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5/pkg/types/README.md
+
+## Auditing
+How will end-users verify that public logging took place?
+
+**Sigsum**
+
+End-users receive inclusion proofs and cosigned tree heads that can be verified
+offline in the same way that data and signatures are currently delivered (a
+website, a git repository, etc). No other network communication is required.
+
+This means that a sigsum log does not have to be available to the end-user after
+logging succeeded to verify that public logging took place.
+
+**Sigstore/Rekor**
+
+End-users [query the log][] to check that a signature is included. This means
+the log needs to stay available to end-users at all times, also see "Privacy".
+
+Alternatively, an end-user may trust a signed promise (SCT) from Rekor to
+include a signature in the future, see "Promises of future log inclusion".
+
+[query the log]: https://web.archive.org/web/20220312144545/https://www.sigstore.dev/how-it-works
+
+## Gossip
+A mechanism that ensures everyone observes the same append-only log. A
+transparency log without gossip requires trusting the log operator and the
+integrity of the log's signing key.
+
+**Sigsum**
+
+Gossip is handled proactively using a simplified version of witness cosigning
+([S&P 2016][]). It can be thought of as a policy-based consensus mechanism:
+m-of-n witnesses audit the log's consistency from their respective vantage
+points. The log distributes the witnesses' signatures, which end-users and
+monitors make use of. This ensures that a malicious sigsum log operator is
+unable to fool even an offline verifier.
+
+[S&P 2016]: https://arxiv.org/pdf/1503.08768.pdf
+
+**Sigstore/Rekor**
+
+Does not have gossip. Sigstore proposes to instead use multiple independent
+[full-fledged logs][]. Logs have more freedom to fool a verifier than cosigning
+witnesses and are harder and more expensive to run.
+
+Signers would have to take great care to submit the same entries to all the logs
+and would have to monitor all of them. End-users would have to contact and/or
+trust multiple logs when verifying.
+
+[full-fledged logs]: https://web.archive.org/web/20220312144801/http://web.archive.org/screenshot/https://docs.sigstore.dev/faq
+
+## Anti-poison
+A transparency log design must take caution to not include large amounts of
+arbitrary data, as someone could submit information that is illegal to possess
+or distribute. Because the log operator cannot selectively erase information
+from the log without invalidating it, the operator may be compelled to shut down
+the log, or simply choose to not operate a log in the first place.
+
+**Sigsum**
+
+Include as little arbitrary information as possible. A log entry contains a
+time value (a shard hint, in the interval `[shard_start, now()]`) of which the
+least significant few bytes are arbitrary. The remaining content can only be
+specified by brute forcing signatures or hashes so that parts of them contain
+certain patterns. This quickly becomes expensive.
+
+**Sigstore/Rekor**
+
+The pluggable type system allows logging of a wide variety of information. The
+rekord type for instance allows encoding an image, see "Example 2: logging JPG
+images" in the Appendix at the end. Other current and future pluggable types
+might permit similar things but we have not looked into that further.
+
+## Anti-spam
+An approach to limit abusive logging requests that consume the log's capacity.
+
+**Sigsum**
+
+A logging request is only accepted if the involved public key is hashed into a
+DNS TXT record. So, rate limits can be based on DNS names. This is similar to
+the anti-spam mechanisms that CT relies on, where a certificate is not accepted
+unless it chains up to a trusted CA. Let's Encrypt [rate-limits via DNS][].
+
+[rate-limits via DNS]: https://web.archive.org/web/20220312145502/https://letsencrypt.org/docs/rate-limits/
+
+**Sigstore/Rekor**
+
+Recently opened an issue about [needing rate-limits][]. It has since been added
+to Sigstore's infrastructure setup based on IP addresses via Nginx.
+
+[needing rate-limits]: https://github.com/sigstore/rekor/issues/637
+
+## Privacy
+
+**Sigsum**
+
+For end-users, nothing changes with regard to privacy compared to signature
+verification that does not make use of a transparency log.
+
+A signer has to expose to the log operator a public key and a 32-byte preimage
+([which should be a hash][]).
+
+The signer's hashed public key is exposed in DNS, see "Anti spam". Logs can be
+be instructed to fetch such TXT resource records if they match `_sigsum_v0.*`.
+
+Log entries consisting of a shard hint, hashes and signatures become public, see
+"What is logged".
+
+[which should be a hash]: https://git.sigsum.org/sigsum/tree/doc/design.md?id=741a65ab1894b35c9cc132d9b8401776c04fe1ce#n351
+
+**Sigstore/Rekor**
+
+End-users that query the log for entries they are interested in expose this
+information to the log.
+
+A signer's public key and data is exposed to the log operator. The data may be
+a hash if [using X.509/PKIX][] signatures and the "hashed rekord type".
+
+Logs can be instructed to download arbitrary data from [specified URLs][].
+
+The content of pluggable types become public, notably including public keys and
+other data that may be encoded (which depends on the exact pluggable type).
+
+[using X.509/PKIX]: https://github.com/sigstore/rekor/blob/6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5/types.md#hashed-rekord
+[specified URLs]: https://github.com/sigstore/rekor/blob/6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5/openapi.yaml#L143
+
+## API
+
+**Sigsum**
+
+Simple ASCII parsers are used to add input and get output from the log. Binary
+data is hex-encoded. Data that is signed and/or logged can be (de)serialized
+using Tor's easy wire-format, [Trunnel][]. The overall take of the API is to
+keep it as simple as possible, and to nudge towards correct usage by design.
+
+[Trunnel]: https://gitweb.torproject.org/trunnel.git/tree/doc/trunnel.md
+
+**Sigstore/Rekor**
+
+REST API with JSON, both for input and output as well as canonicalization of
+data. Some parts of the API are easily misused due to returning redundant
+and/or unauthenticated data. This happened [once][] and [twice][] already.
+
+Other types of mis-usage are likely to be expected. For example, the
+availability of public keys makes it tempting to inappropriately use Rekor for
+key discovery even though it is not designed to be a trustworthy source of keys.
+
+The implementation complexity of Rekor's API is also relatively large. Imports
+contain much hidden complexity, in part due to pluggable types that involve PGP,
+ASN.1, and such. This has already lead to issues like Rekor starting to return
+[YAML instead of JSON][]; JSON marshalling of tree leaves [not being canonical
+enough][]; the [need of another PGP library][]; etc. It will likely be hard to
+understand, implement, and maintain Rekor compliant software in the long run.
+
+[once]: https://github.com/sigstore/rekor/issues/200
+[twice]: https://github.com/sigstore/rekor/pull/469
+[YAML instead of JSON]: https://github.com/sigstore/rekor/issues/593
+[not being canonical enough]: https://github.com/sigstore/rekor/pull/445
+[need of another PGP library]: https://github.com/sigstore/rekor/issues/286
+
+## Promises of future log inclusion (SCTs)
+A construct that enables low-latency logging. Certificate Transparency
+introduced this to work with the existing TLS PKI during a gradual roll-out
+scenario. Nine years later such roll-outs are still in the earlier stages.
+
+**Sigsum**
+
+Does not support SCTs. Unlike the TLS case there is no existing system to be
+compatible with and use-cases that cannot tolerate a few minutes of logging
+latency are out-of-scope. This is a trade-off that keeps the design simple.
+
+**Sigstore/Rekor**
+
+[Supports SCTs][]. If an entry (promised to be logged by an SCT) is not included
+in the log in time the operator should not be trusted in the future. This
+places high requirements on uptime and availability, and on not losing the log
+request between the time of issuing an SCT and inclusion in the log. Rekor
+avoids this by simply including the signature in the log [before issuing][] the
+SCT. That however provides no latency reduction, making SCTs pointless.
+
+The mere existence of SCTs also encourages their use, making users who rely on
+them not receive the full benefits of using a transparency log. We are not
+aware of any clear plans specifying how Sigstore will solve SCT verification.
+Without such plans, the log may deceive end-users by changing its history.
+
+[Supports SCTs]: https://twitter.com/lorenc_dan/status/1388109774579982340
+[before issuing]: https://github.com/sigstore/rekor/blob/a61d5f63843cbae4e5bf1f97d06628fa914a4435/openapi.yaml#L493
+
+## Sharding
+The practise of dividing a log into smaller independent partitions. One of
+Certificate Transparency's successes is [temporal sharding][] based on expiry
+date to allow log rotation (helpful to make log life cycles more manageable).
+
+[temporal sharding]: https://web.archive.org/web/20220312150931/https://googlechrome.github.io/CertificateTransparency/log_policy.html
+
+**Sigsum**
+
+Establishes shards based on shard hints in the interval `[shard_start, now()]`.
+Shard hints are part of the signer's signing context and cannot be forged,
+preventing past entries from being re-logged in a newer shard. A log can also
+cease its operations safely due to Sigsum's take on offline auditing. This
+gives a complete story for log life cycles without any expiration dates.
+
+**Sigstore/Rekor**
+
+Creates [virtual shards][], see also related [GitHub issues][]. The latest
+virtual shard is active. All other virtual shards are kept around but in
+read-only mode. If a virtual shard was to be deleted those entries can be
+logged again. As old virtual shards have to be saved, this gives a complicated
+log configuration but does not provide any of the benefits of sharding.
+
+[virtual shards]: https://docs.google.com/document/d/1QBTyK-wquplNdeUB5_aqztQHigJOepCvd-4FL4H-zl8/edit?resourcekey=0-grdVbSltkTvpNvhj03laCQ#
+[GitHub issues]: https://github.com/sigstore/rekor/issues/353
+
+# Appendix
+## Example 1: Unverifiable signatures
+The input to a signature verification is a public key, a message, and a
+signature. Rekor incorrectly assumes that the signed message ("artifact")
+is always a hash.
+
+First we demonstrate the issue using `signify`.
+
+**Step 1 - Generate a key-pair**
+
+ $ signify-openbsd -G -c "demo" -p example.pub -s example.sec
+ passphrase:
+ confirm passphrase:
+ $ ls
+ example.pub example.sec
+
+**Step 2 - Create something to sign**
+
+ $ echo 'print("hello")' > hello.py
+ $ sha256sum hello.py
+ b80792336156c7b0f7fe02eeef24610d2d52a10d1810397744471d1dc5738180 hello.py
+ $ ls
+ example.pub example.sec hello.py
+
+**Step 3 - Sign**
+
+ $ signify-openbsd -Ss example.sec -m hello.py
+ passphrase:
+ $ ls
+ example.pub example.sec hello.py hello.py.sig
+
+**Step 4 - Log**
+
+The below uses Rekor on commit 6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5.
+
+ $ rekor-cli upload \
+ --artifact hello.py\
+ --signature hello.py.sig\
+ --pki-format=minisign\
+ --public-key=example.pub\
+ --rekor_server http://localhost:3000
+ Created entry at index 99, available at: http://localhost:3000/api/v1/log/entries/bf5f87c83bfffc3b0d3d0151a6cfef836594dcd90ac286541b25856b7d6fd6b1
+ $ rekor-cli get --log-index 99 --rekor_server http://localhost:3000
+ LogID: e0f8a8ff472431bda298489c292f33f5d30363949df58d2e35c5195f915c7069
+ Index: 99
+ IntegratedTime: 2022-03-12T11:59:28Z
+ UUID: bf5f87c83bfffc3b0d3d0151a6cfef836594dcd90ac286541b25856b7d6fd6b1
+ Body: {
+ "RekordObj": {
+ "data": {
+ "hash": {
+ "algorithm": "sha256",
+ "value": "b80792336156c7b0f7fe02eeef24610d2d52a10d1810397744471d1dc5738180"
+ }
+ },
+ "signature": {
+ "content": "dW50cnVzdGVkIGNvbW1lbnQ6ClJXVE9PWDNrMjE0L3VDR0VuQWtHaC9wOGxCK2o4ZlU0bzN2aFpzc3dud2RFeDE2M2REUHpReE1BVXdUcUFjK1ovaGdycGdISU5VNHlFbnhPOXNwSnkydmZmcHdWSUJIV3lnWT0=",
+ "format": "minisign",
+ "publicKey": {
+ "content": "UldUT09YM2syMTQvdUg1RVhHbUFwdDZWSnhxVUlJZzIrWnMrajlFRDNTM1ZGOXBHSzZoWDRLSmM="
+ }
+ }
+ }
+ }
+
+Let's understand the above in more detail. Our public key and signature is in
+the above output, but without the untrusted comment which is irrelevant.
+
+ cat example.pub
+ untrusted comment: demo public key
+ RWTOOX3k214/uH5EXGmApt6VJxqUIIg2+Zs+j9ED3S3VF9pGK6hX4KJc
+ $ echo UldUT09YM2syMTQvdUg1RVhHbUFwdDZWSnhxVUlJZzIrWnMrajlFRDNTM1ZGOXBHSzZoWDRLSmM= | base64 -d
+ RWTOOX3k214/uH5EXGmApt6VJxqUIIg2+Zs+j9ED3S3VF9pGK6hX4KJc
+ $
+ $ cat hello.py.sig
+ untrusted comment: verify with example.pub
+ RWTOOX3k214/uCGEnAkGh/p8lB+j8fU4o3vhZsswnwdEx163dDPzQxMAUwTqAc+Z/hgrpgHINU4yEnxO9spJy2vffpwVIBHWygY=
+ $ echo "dW50cnVzdGVkIGNvbW1lbnQ6ClJXVE9PWDNrMjE0L3VDR0VuQWtHaC9wOGxCK2o4ZlU0bzN2aFpzc3dud2RFeDE2M2REUHpReE1BVXdUcUFjK1ovaGdycGdISU5VNHlFbnhPOXNwSnkydmZmcHdWSUJIV3lnWT0=" | base64 -d
+ untrusted comment:
+ RWTOOX3k214/uCGEnAkGh/p8lB+j8fU4o3vhZsswnwdEx163dDPzQxMAUwTqAc+Z/hgrpgHINU4yEnxO9spJy2vffpwVIBHWygY=
+
+Rekor also stored a SHA256 hash:
+
+ "RekordObj": {
+ "data": {
+ "hash": {
+ "algorithm": "sha256",
+ "value": "b80792336156c7b0f7fe02eeef24610d2d52a10d1810397744471d1dc5738180"
+ }
+ },
+
+You might recognize it from step 2. It is the output of `sha256sum hello.py`.
+What is needed to do verification with the logged signature and public key is
+the output of `cat hello.py`. This is because signify signs those exact bytes
+without doing any hashing (unlike other schemes that actually do sign a hash).
+
+The impact is that you cannot know by observing the log if a real signature
+operation happened (there is nothing to verify), or if the Rekor operator
+fabricated an entry. The signature would be verifiable if the data can be
+located. In the case of a malicious signature this might not be the case.
+
+**The same issue in other places**
+
+Minisign has the same issue, even with its pre-hashed mode because Minisign
+[does not use SHA256][] which is what Rekor still stores. The exact same issue
+is also there for SSH signatures. We did not dig into any other types.
+
+[does not use SHA256]: https://github.com/sigstore/rekor/blob/6ace9fe63b072a3a7e8b544fcbf393d2aafe9ae5/pkg/pki/minisign/minisign.go#L109
+
+## Example 2: Logging JPG images
+As shown above Rekor scrubs some information that was submitted for logging.
+Most likely to not accept arbitrary bytes, such as signify's untrusted comments.
+To protect Rekor against logging of illegal content, each pluggable type needs
+to be considered in more detail. Below is an example that encodes a JPG image.
+
+**Step 1 - Create an image**
+
+ $ convert -size 16x16 xc:red red.jpg
+ $ ls
+ red.jpg
+
+This also works with larger images, e.g., `-size 4096x4096`.
+
+**Step 2 - Encode image in an X.509 configuration**
+
+ $ echo "[ req ]" > crt.cnf
+ $ echo "distinguished_name = dn" >> crt.cnf
+ $ echo "x509_extensions = extensions" >> crt.cnf
+ $ echo "prompt = no" >> crt.cnf
+ $ echo "" >> crt.cnf
+ $ echo "[ extensions ]" >> crt.cnf
+ $ echo "1.2.3.4 = ASN1:UTF8String:$(base64 -w0 red.jpg)" >> crt.cnf
+ $ echo "" >> crt.cnf
+ $ echo "[ dn ]" >> crt.cnf
+ $ echo "0.DC = com" >> crt.cnf
+ $ echo "1.DC = example" >> crt.cnf
+ $ echo "commonName = example.com" >> crt.cnf
+ $ ls
+ crt.cnf red.jpg
+
+Credit: [this post][] outlines how an X.509v3 extension can be prepared.
+
+[this post]: https://serverfault.com/questions/1005029/error-when-trying-to-add-custom-extensions-to-x509-certificates-using-openssl
+
+**Step 3 - Create X.509 certificate**
+
+ $ openssl req -x509 -nodes\
+ -newkey ec:<(openssl ecparam -name prime256v1)\
+ -config crt.cnf\
+ -keyout priv.pem\
+ -out cert.pem
+ Generating an EC private key
+ writing new private key to 'priv.pem'
+ -----
+ $ ls
+ cert.pem crt.cnf priv.pem red.jpg
+
+Note that we now have an X.509 certificate that encodes our image:
+
+ $ openssl x509 -in cert.pem -text -noout
+ Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 27:a5:0e:37:9c:3e:e1:0d:d7:a4:8f:10:ce:2d:09:35:40:9c:a8:1e
+ Signature Algorithm: ecdsa-with-SHA256
+ Issuer: DC = com, DC = example, CN = example.com
+ Validity
+ Not Before: Mar 12 13:46:06 2022 GMT
+ Not After : Apr 11 13:46:06 2022 GMT
+ Subject: DC = com, DC = example, CN = example.com
+ Subject Public Key Info:
+ Public Key Algorithm: id-ecPublicKey
+ Public-Key: (256 bit)
+ pub:
+ 04:9d:2a:5d:4c:df:d4:fa:9a:76:32:59:96:3b:44:
+ 12:00:03:3c:c0:d9:42:58:c1:fb:2a:ed:fb:0d:95:
+ d0:ce:7d:62:e6:f8:ae:be:76:6b:3b:0c:44:aa:ca:
+ 43:57:cf:19:a3:c9:b1:cd:05:21:a2:b8:0c:50:13:
+ 0c:d9:9f:8f:ea
+ ASN1 OID: prime256v1
+ NIST CURVE: P-256
+ X509v3 extensions:
+ 1.2.3.4:
+ ..../9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAQABADAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAcJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AnRDGqYAAD//Z
+ Signature Algorithm: ecdsa-with-SHA256
+ 30:46:02:21:00:ee:ee:81:d6:1c:e8:a7:ca:dd:54:b5:82:fe:
+ 22:1d:94:1d:b1:31:91:d6:3e:68:99:f5:d5:da:c9:f4:bc:53:
+ 53:02:21:00:cd:08:98:c5:73:e8:a1:8f:8c:95:06:cc:5c:70:
+ 65:aa:dd:94:f0:38:59:ec:f7:c7:35:98:eb:75:5f:23:eb:c5
+
+Compare the X.509v3 extensions to this:
+
+ $ base64 red.jpg
+ /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAQABADAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAcJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AnRDGqYAAD//Z
+
+Now we need to get this X.509 certificate into Rekor.
+
+**Step 4 - Sign something**
+
+ $ openssl dgst -sha256 -sign priv.pem -out red.jpg.sig red.jpg
+ $ ls
+ cert.pem crt.cnf priv.pem red.jpg red.jpg.sig
+
+**Step 5 - Log**
+
+ $ rekor-cli upload \
+ --artifact red.jpg\
+ --signature red.jpg.sig\
+ --pki-format=x509\
+ --public-key=cert.pem\
+ --rekor_server http://localhost:3000
+ Created entry at index 102, available at: http://localhost:3000/api/v1/log/entries/688f817bb1e7cb1b28eadf173b0095724cce86ab0116b0df5a0c8e06c00e880c
+ $
+ $ rekor-cli get --log-index 102 --rekor_server http://localhost:3000
+ LogID: e0f8a8ff472431bda298489c292f33f5d30363949df58d2e35c5195f915c7069
+ Index: 102
+ IntegratedTime: 2022-03-12T13:51:30Z
+ UUID: 688f817bb1e7cb1b28eadf173b0095724cce86ab0116b0df5a0c8e06c00e880c
+ Body: {
+ "RekordObj": {
+ "data": {
+ "hash": {
+ "algorithm": "sha256",
+ "value": "4a837db6d6a21a9bdfccff6ca21f72d1d4a671b59a5df76158629ff5f6b22ddf"
+ }
+ },
+ "signature": {
+ "content": "MEYCIQD4HWtXfSDGpWUUmk1tWUP/V5MRUPgwrUMiiJB7miKZcQIhAJDYUO+lyGYKShCtt3AZZilZkoLEm9WAaXhlzGVwZMu6",
+ "format": "x509",
+ "publicKey": {
+ "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKakNDQXN1Z0F3SUJBZ0lVSjZVT041dys0UTNYcEk4UXppMEpOVUNjcUI0d0NnWUlLb1pJemowRUF3SXcKUkRFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTJOdmJURVhNQlVHQ2dtU0pvbVQ4aXhrQVJrV0IyVjRZVzF3YkdVeApGREFTQmdOVkJBTU1DMlY0WVcxd2JHVXVZMjl0TUI0WERUSXlNRE14TWpFek5EWXdObG9YRFRJeU1EUXhNVEV6Ck5EWXdObG93UkRFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTJOdmJURVhNQlVHQ2dtU0pvbVQ4aXhrQVJrV0IyVjQKWVcxd2JHVXhGREFTQmdOVkJBTU1DMlY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowRApBUWNEUWdBRW5TcGRUTi9VK3BwMk1sbVdPMFFTQUFNOHdObENXTUg3S3UzN0RaWFF6bjFpNXZpdXZuWnJPd3hFCnFzcERWODhabzhteHpRVWhvcmdNVUJNTTJaK1A2cU9DQVprd2dnR1ZNSUlCa1FZREtnTUVCSUlCaUF5Q0FZUXYKT1dvdk5FRkJVVk5yV2twU1owRkNRVkZCUVVGUlFVSkJRVVF2TW5kQ1JFRkJUVU5CWjBsRFFXZE5RMEZuU1VSQgpkMDFFUWtGWlJVSkJVVVZDUVdkSFFtZFZSME5SWjB0RFoydEpRMUZyUzBSQk9FMURaM05QUTNkclNrUlNSVTVFClp6aFJSVUpGVVVObmQxTkZlRWxSUlhjNFVVVkNSQzh5ZDBKRVFWRk5SRUYzVVVSQ1FXZEZRa0ZuVVVOM2EweEYKUWtGUlJVSkJVVVZDUVZGRlFrRlJSVUpCVVVWQ1FWRkZRa0ZSUlVKQlVVVkNRVkZGUWtGUlJVSkJVVVZDUVZGRgpRa0ZSUlVKQlVVVkNRVkZGUWtGUlJVSkVMM2RCUVZKRFFVRlJRVUpCUkVGU1JVRkJhRVZDUVhoRlFpODRVVUZHClVVRkNRVkZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVdvdmVFRkJWVVZCUlVGQlFVRkJRVUZCUVVGQlFVRkIKUVVGQlFVRkJRUzg0VVVGR1owVkNRVkZGUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVdOS0x6aFJRVVpDUlVKQgpRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZRTDJGQlFYZEVRVkZCUTBWUlRWSkJSRGhCYmxKRVIzRlpRVUZFCkx5OWFNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUUR1N29IV0hPaW55dDFVdFlMK0loMlVIYkV4a2RZK2FKbjEKMWRySjlMeFRVd0loQU0wSW1NVno2S0dQakpVR3pGeHdaYXJkbFBBNFdlejN4eldZNjNWZkkrdkYKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
+ }
+ }
+ }
+ }
+
+Of interest here is the public key:
+
+ $ echo "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKakNDQXN1Z0F3SUJBZ0lVSjZVT041dys0UTNYcEk4UXppMEpOVUNjcUI0d0NnWUlLb1pJemowRUF3SXcKUkRFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTJOdmJURVhNQlVHQ2dtU0pvbVQ4aXhrQVJrV0IyVjRZVzF3YkdVeApGREFTQmdOVkJBTU1DMlY0WVcxd2JHVXVZMjl0TUI0WERUSXlNRE14TWpFek5EWXdObG9YRFRJeU1EUXhNVEV6Ck5EWXdObG93UkRFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTJOdmJURVhNQlVHQ2dtU0pvbVQ4aXhrQVJrV0IyVjQKWVcxd2JHVXhGREFTQmdOVkJBTU1DMlY0WVcxd2JHVXVZMjl0TUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowRApBUWNEUWdBRW5TcGRUTi9VK3BwMk1sbVdPMFFTQUFNOHdObENXTUg3S3UzN0RaWFF6bjFpNXZpdXZuWnJPd3hFCnFzcERWODhabzhteHpRVWhvcmdNVUJNTTJaK1A2cU9DQVprd2dnR1ZNSUlCa1FZREtnTUVCSUlCaUF5Q0FZUXYKT1dvdk5FRkJVVk5yV2twU1owRkNRVkZCUVVGUlFVSkJRVVF2TW5kQ1JFRkJUVU5CWjBsRFFXZE5RMEZuU1VSQgpkMDFFUWtGWlJVSkJVVVZDUVdkSFFtZFZSME5SWjB0RFoydEpRMUZyUzBSQk9FMURaM05QUTNkclNrUlNSVTVFClp6aFJSVUpGVVVObmQxTkZlRWxSUlhjNFVVVkNSQzh5ZDBKRVFWRk5SRUYzVVVSQ1FXZEZRa0ZuVVVOM2EweEYKUWtGUlJVSkJVVVZDUVZGRlFrRlJSVUpCVVVWQ1FWRkZRa0ZSUlVKQlVVVkNRVkZGUWtGUlJVSkJVVVZDUVZGRgpRa0ZSUlVKQlVVVkNRVkZGUWtGUlJVSkVMM2RCUVZKRFFVRlJRVUpCUkVGU1JVRkJhRVZDUVhoRlFpODRVVUZHClVVRkNRVkZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVdvdmVFRkJWVVZCUlVGQlFVRkJRVUZCUVVGQlFVRkIKUVVGQlFVRkJRUzg0VVVGR1owVkNRVkZGUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZCUVdOS0x6aFJRVVpDUlVKQgpRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZRTDJGQlFYZEVRVkZCUTBWUlRWSkJSRGhCYmxKRVIzRlpRVUZFCkx5OWFNQW9HQ0NxR1NNNDlCQU1DQTBrQU1FWUNJUUR1N29IV0hPaW55dDFVdFlMK0loMlVIYkV4a2RZK2FKbjEKMWRySjlMeFRVd0loQU0wSW1NVno2S0dQakpVR3pGeHdaYXJkbFBBNFdlejN4eldZNjNWZkkrdkYKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" | base64 -d > logged-cert.pem
+ $ diff cert.pem logged-cert.pem
+ $
+
+As you can see, it is the same certificate that contains our JPG image. Any
+other data could be encoded as well using the above trick.