From 74f4ae92cc2db5756ec700893988af33b87bda86 Mon Sep 17 00:00:00 2001
From: Luke Hinds <7058938+lukehinds@users.noreply.github.com>
Date: Thu, 29 Jul 2021 13:29:19 +0100
Subject: [PATCH] Provide instructions on verifying releases (#399)

Provide instructions on verifying signatures

Note this is quite lengthy / hand wavy, but I believe
its better we show how our trust model works.

I also point out how much of this will be streamlined and improved
via the TUF integration

Signed-off-by: Luke Hinds <lhinds@redhat.com>
---
 README.md         |   8 ++
 release-verify.md | 217 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 225 insertions(+)
 create mode 100644 release-verify.md

diff --git a/README.md b/README.md
index fd2d0c1..25ba666 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,14 @@ Please reach out via the [mailing list](https://groups.google.com/g/sigstore-dev
 If you have production use-cases in mind, again - please reach out over email via the [mailing list](https://groups.google.com/g/sigstore-dev).
 We are interested in helping on board you!
 
+### Installation
+
+Rekor releases are available on the [release page](https://github.com/sigstore/rekor/releases)
+
+The components are available, the server; `rekor-server` and the CLI tool `rekor-cli`
+
+See [release-verify](release-verify.md) for details of to verify rekor release binaries.
+
 ### Usage
 
 For examples of uploading signatures for all the supported types to rekor, see [the types documentation](types.md).
diff --git a/release-verify.md b/release-verify.md
new file mode 100644
index 0000000..1075e40
--- /dev/null
+++ b/release-verify.md
@@ -0,0 +1,217 @@
+# Verify Rekor Binaries
+
+> :notebook: We will refine this process over time to be more streamlined with a higher consensus threshold
+   as well as an implementation of a [TUF](https://theupdateframework.io/) style policy. For now this is quite a
+   multi step process. We will also deep dive a fair amount here, as its a good opporuntity to pull the covers aside
+   and see how this all works.
+
+Rekor releases are currently signed and verified using Fulcio OpenID connect based short lived signing certificates.
+
+Rekor release signing artifacts are also stored within the public rekor instance.
+
+Here we will show you how to verify a release, but also take the opportunity to dig down into sigstores
+signing implementation and process.
+
+## How to verify a release
+
+Head over to the [release page](https://github.com/sigstore/rekor/releases) and select the correct release
+for your systems architecture. Alongside downloading the main binary, also download the signature and signing
+certificate from the same release.
+
+For example, with binary `rekor-cli-linux-amd64`, also retrieve `rekor-cli-linux-amd64_cert.pem`
+and `rekor-cli-linux-amd64_signature.sig`.
+
+* `rekor-cli-linux-amd64`: The binary itself
+* `rekor-cli-linux-amd64_cert.pem`: The signing cerificate. This is an X509 certificate generated by sigstore
+   root CA, with the email of a project maintainer embedded as a X509v3 Subject Alternative Name. This
+   provides a guarantees that the binary was signed by the individual with access to that account (the email comes
+   from an OpenID provider). In turn this information is recorded into the transparency log, so that the account can
+   be monitored for misuse or compromise.
+* `rekor-cli-linux-amd64_signature.sig`: This is the signature generated as a result of the signing event.
+
+#### Basic verify
+
+With the above three files, we can now perform a rudimentary verification.
+
+We grab the public key from the signing cert:
+
+```
+openssl x509 -pubkey -noout -in rekor-cli-linux-amd64_cert.pem > rekor-cli-linux-amd64_cert_public.pem
+```
+
+And then we verify
+
+
+```
+openssl dgst -sha256 -verify rekor-cli-linux-amd64_cert_public.pem -signature rekor-cli-linux-amd64_signature.sig rekor-cli-linux-amd64
+Verified OK
+```
+
+#### Verify the certificate chain
+
+We should check the trust chain to sigstores Root CA
+
+The root CA for fulcio is currently:
+
+```
+-----BEGIN CERTIFICATE-----
+MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq
+MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
+MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu
+ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy
+A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas
+taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm
+MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
+FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u
+Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx
+Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup
+Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
+-----END CERTIFICATE-----
+```
+
+Save this locally to your machine as `fulcio-root.pem`
+
+> :notebook: We are looking at leveraging other trust stores for our Root CA
+   , so consider getting the root CA from here, a temporary approach.
+
+Let's now validate the cert chain:
+
+```
+openssl verify -verbose -no_check_time -CAfile fulcio-root.pem rekor-cli-linux-amd64_cert.pem
+
+rekor-cli-linux-amd64_cert.pem: OK
+```
+
+> :notebook: We use `-no_check_time` as fulcio certificates are  (so always will be expired by design!)
+
+#### Verify the signing identity
+
+However, how do we know we can trust that public key is from a maintainer at sigstore?
+
+Let's look at mapping this to an identity..
+
+```
+openssl x509 -in rekor-cli-linux-amd64_cert.pem -noout -text |grep email
+email:ctadeu@gmail.com
+```
+
+OK, so we can see that a fulcio generated certificate, with a chain to the root certificate
+has the email identity of a sigstore maintainer, in this instance our own release manager the awesome Carlos.
+
+If you really wanted to and are super paranoid, you could email Carlos and ask him to give you assurance
+he is Carlos and he signed the release.
+
+#### Verify the entry is in the transparency log
+
+On the  [release page](https://github.com/sigstore/rekor/releases) you will see some URLs, these are the
+rekor entries of the signing events.
+
+This is the link for the binary and signing materials we have been working with in this guide
+
+https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33
+
+Let's dig into this;
+
+```
+curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq
+
+{
+  "b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33": {
+    "attestation": {},
+    "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJzcGVjIjp7ImRhdGEiOnsiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImNlOWE3YzgyZjMyMTk0OTk1ODg4NzU4Y2YxMDdlZjBjYzUyZTBiOGNkY2U3M2I0MjQwNjU4ZWU5ZTczNzgzY2IifX0sInNpZ25hdHVyZSI6eyJjb250ZW50IjoiTUdVQ01EM29LemdzR25QQWtKRVhlZ0RJc2RsaDRCRkNRYk02am5nNFN5M2F4WS8rMnRsSzk3b2UvQ2t4YWJUMVpYVXFDQUl4QUpEcSt6TGZSWlpFSkQ1RHZhS2hGRXUrSm0rakQ0VVhjM0NhWnAyTVNhamlyYWxtdGFsQTZmU0dDWGp3R2ZVek93PT0iLCJmb3JtYXQiOiJ4NTA5IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VOcmFrTkRRV2hwWjBGM1NVSkJaMGxWUVUwckswZFlSRk41YlVOUFNXODJZbXhNTUc1RVpuZ3hiMjFuZDBObldVbExiMXBKZW1vd1JVRjNUWGNLUzJwRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5Va1YzUkhkWlJGWlJVVVJGZDJoNllWZGtlbVJIT1hsYVZFRmxSbmN3ZVFwTlZFRXpUV3BuZDA5RVRUTk9SRXBoUm5jd2VVMVVRVE5OYW1kM1QwUlZNMDVFUm1GTlFVRjNaR3BCVVVKblkzRm9hMnBQVUZGSlFrSm5WWEpuVVZGQkNrbG5UbWxCUVZKak1ETXJVVTR2VEhCck9HcHFVRlF3VG1WNWEwMXVjbTltTW5wWlVrSnhObTA1ZWk5VE1YaFJTemR1Wm5aaFUzZ3JSalVyVEV0d04zZ0tSMkV4YkhZMlNXTnZSWGR3VUhBMk1VZHNZbmQ1UzBWUVZXSkxkekpyWW5KeVJWcFBNbmhLVjNreGIwVkVVSEJZTWxKcWNUQllTMFJaY0VGNVppOW1Rd295WnpKalNuVnRhbWRuUlc1TlNVbENTWHBCVDBKblRsWklVVGhDUVdZNFJVSkJUVU5DTkVGM1JYZFpSRlpTTUd4Q1FYZDNRMmRaU1V0M1dVSkNVVlZJQ2tGM1RYZEVRVmxFVmxJd1ZFRlJTQzlDUVVsM1FVUkJaRUpuVGxaSVVUUkZSbWRSVlRSQlVEaHRUa0k0ZWpoU1pGSnlUVlZMWjFBMk1tMHhVRkVyZDNjS1NIZFpSRlpTTUdwQ1FtZDNSbTlCVlhsTlZXUkJSVWRoU2tOcmVWVlRWSEpFWVRWTE4xVnZSekFyZDNkbldUQkhRME56UjBGUlZVWkNkMFZDUWtsSFFRcE5TRFIzWmtGWlNVdDNXVUpDVVZWSVRVRkxSMk5IYURCa1NFRTJUSGs1ZDJOdGJESlpXRkpzV1RKRmRGa3lPWFZrUjFaMVpFTXdNazFFVG0xYVZHUnNDazU1TUhkTlJFRjNURlJKZVUxcVkzUlpiVmt6VGxNeGJVNUhXVEZhVkdkM1drUkpOVTVVVVhWak0xSjJZMjFHYmxwVE5XNWlNamx1WWtkV2FHTkhiSG9LVEcxT2RtSlRPV3BaVkUweVdWUkdiRTlVV1hsT1JFcHBUMWRhYWxscVJUQk9hVGxxV1ZNMWFtTnVVWGRJWjFsRVZsSXdVa0ZSU0M5Q1FsRjNSVzlGVVFwWk0xSm9Xa2RXTVZGSFpIUlpWMnh6VEcxT2RtSlVRVXRDWjJkeGFHdHFUMUJSVVVSQmQwNXZRVVJDYkVGcVJVRTNUVEp3U3poUlVGUnJTR3MxYnpaMENtZG5hbXBaZGpCTFYxQlVhalJLVVRBd1UzUmpSMHhxYTFnM1NVMWlOQzlIZFhwWVJrUTRjelpET0VkM05tcHdNRUZxUVcxWGEySlJPVFZzTXpsblVHUUtSMnBqVWpCU1FVUmFUMGRZYjBOUFFVUndPRTVsU3poQkwyZEtkV2RuUjBaSU5IWllaMmwxT0RKc1FtNU1PRVpTYzA5alBRb3RMUzB0TFVWT1JDQkRSVkpVU1VaSlEwRlVSUzB0TFMwdENnPT0ifX19LCJraW5kIjoicmVrb3JkIn0=",
+    "integratedTime": 1627461494,
+    "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
+    "logIndex": 25579,
+    "verification": {
+      "inclusionProof": {
+        "hashes": [
+          "779627efafc2601b0b5c4755d1aa27eb3cf8c1f034960ccc1038b9556b1d78bb",
+          "892fffd41824856e3279fb815cdedd28fc76722985e508f6ffdf5af5684f0d84",
+          "24259982c90f0e2e8a051c06f4cda83fb7f06c3e47b1307d5bc3e50a625b3dcb",
+          "a5d5a5841e65786e0718db2f43d909ff92fbfa19bc90bc3187fc143e7af2eb29",
+          "2cba9779511cd8c964ac59e4763ecd5257aa67695b20bfbc957341e326848b60",
+          "b269aa60e284ce1f866f5c7abd9da16d8e29bf9ab069c66ce91cfe8d6a852458",
+          "8af1c7cd9d0a691984963b643c572c560cee08fe38083e2013763df5131e63b3",
+          "e86d56509d6b149df6bf2389e066a4b21516f5a13540b8ef52c790b8ed70efe2",
+          "04cfd843e6ee05e78eee3229a1b547a4776a81e651888c09bdbfde866ac38d97",
+          "339bd5b9f48f7ecf1116f0b0ec9f9eeb95b84f3d53f27b8081e56facbcd71548",
+          "74c9aba66c2704b143e33c3ebc5f12a17be5bda8a8eba055bd471ed57a6fd0b4",
+          "43a291f5a7301f1b18bbf76829435251a9189c477aa52633fef3f589e3d47446",
+          "73b38c2b7d6eac887dc9f028500b67ede8655f136bc75354f8bfe94515327513",
+          "4a33ede5d1c6be306c0362fbee2e9f692522327b4cae78165f810f7dcfaa8dd0"
+        ],
+        "logIndex": 25579,
+        "rootHash": "9ecebec82edb290e54f8b45702b05b94efe1e2a7848d5b5aa2c4bbe188995ca2",
+        "treeSize": 27024
+      },
+      "signedEntryTimestamp": "MEUCIHPlKC5Hh34bdjBrqk++9yuznsFOyolHsoulTTxjM+hGAiEA3MEf6d2zsxFJaiZsGCHIhN8Yvc+NZMmUolIBqUGCps0="
+    }
+  }
+}
+```
+
+Woah, thats a lot of stuff, lets focus on the the body and decode it from base64
+
+```
+curl -X GET "https://rekor.sigstore.dev/api/v1/log/entries/b6fdc91e6af5bdd8df133802b7966aa53c1e59365741ee56e287f11263e02c33"  | jq -r '.[].body'| base64 -d | jq -r '.[]'
+
+{
+  "data": {
+    "hash": {
+      "algorithm": "sha256",
+      "value": "ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb"
+    }
+  },
+  "signature": {
+    "content": "MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw==",
+    "format": "x509",
+    "publicKey": {
+      "content": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
+    }
+  }
+}
+```
+
+Ok now you can see the digest of the artifact that was signed:
+
+```
+sha256sum rekor-cli-linux-amd64
+ce9a7c82f32194995888758cf107ef0cc52e0b8cdce73b4240658ee9e73783cb  rekor-cli-linux-amd64
+```
+
+We can then also grab the signing certicate
+
+```
+echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNrakNDQWhpZ0F3SUJBZ0lVQU0rK0dYRFN5bUNPSW82YmxMMG5EZngxb21nd0NnWUlLb1pJemowRUF3TXcKS2pFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUkV3RHdZRFZRUURFd2h6YVdkemRHOXlaVEFlRncweQpNVEEzTWpnd09ETTNOREphRncweU1UQTNNamd3T0RVM05ERmFNQUF3ZGpBUUJnY3Foa2pPUFFJQkJnVXJnUVFBCklnTmlBQVJjMDMrUU4vTHBrOGpqUFQwTmV5a01ucm9mMnpZUkJxNm05ei9TMXhRSzduZnZhU3grRjUrTEtwN3gKR2ExbHY2SWNvRXdwUHA2MUdsYnd5S0VQVWJLdzJrYnJyRVpPMnhKV3kxb0VEUHBYMlJqcTBYS0RZcEF5Zi9mQwoyZzJjSnVtamdnRW5NSUlCSXpBT0JnTlZIUThCQWY4RUJBTUNCNEF3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVICkF3TXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVTRBUDhtTkI4ejhSZFJyTVVLZ1A2Mm0xUFErd3cKSHdZRFZSMGpCQmd3Rm9BVXlNVWRBRUdhSkNreVVTVHJEYTVLN1VvRzArd3dnWTBHQ0NzR0FRVUZCd0VCQklHQQpNSDR3ZkFZSUt3WUJCUVVITUFLR2NHaDBkSEE2THk5d2NtbDJZWFJsWTJFdFkyOXVkR1Z1ZEMwMk1ETm1aVGRsCk55MHdNREF3TFRJeU1qY3RZbVkzTlMxbU5HWTFaVGd3WkRJNU5UUXVjM1J2Y21GblpTNW5iMjluYkdWaGNHbHoKTG1OdmJTOWpZVE0yWVRGbE9UWXlOREppT1daallqRTBOaTlqWVM1amNuUXdIZ1lEVlIwUkFRSC9CQlF3RW9FUQpZM1JoWkdWMVFHZHRZV2xzTG1OdmJUQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqRUE3TTJwSzhRUFRrSGs1bzZ0CmdnampZdjBLV1BUajRKUTAwU3RjR0xqa1g3SU1iNC9HdXpYRkQ4czZDOEd3NmpwMEFqQW1Xa2JROTVsMzlnUGQKR2pjUjBSQURaT0dYb0NPQURwOE5lSzhBL2dKdWdnR0ZINHZYZ2l1ODJsQm5MOEZSc09jPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==| base64 -d > tlog_signing_cert.pem```
+```
+
+Which is of course the same as our signing cert:
+
+```
+diff tlog_signing_cert.pem rekor-cli-linux-amd64_cert.pem 
+```
+
+And the signature can also be retrieved:
+
+```
+echo MGUCMD3oKzgsGnPAkJEXegDIsdlh4BFCQbM6jng4Sy3axY/+2tlK97oe/CkxabT1ZXUqCAIxAJDq+zLfRZZEJD5DvaKhFEu+Jm+jD4UXc3CaZp2MSajiralmtalA6fSGCXjwGfUzOw== | base64 -d > tlog_signing_sig.sig
+
+diff tlog_signing_sig.sig rekor-cli-linux-amd64_signature.sig 
+```
+
+So we can then do the same verification using just the tlog!
+
+```
+openssl x509 -pubkey -noout -in tlog_signing_cert.pem > tlog_signing_cert_public.pem
+openssl dgst -sha256 -verify tlog_signing_cert_public.pem -signature tlog_signing_sig.sig rekor-cli-linux-amd64
+Verified OK
+```
+
+### Summarise
+
+So we now know that the binary you downloaded, was signed by the individual in control of the OpenID based account.
+
+In turn this account has 2FA enabled and is monitored for misuse as records are tranparent within the public rekor transparency log.
+
+There is a lot more we could do well. Using the sha256 digest you could retrieve the signing materials for a release binary, *even* if
+you sourced the binary from elsewhere!
\ No newline at end of file
-- 
GitLab