Skip to content
Snippets Groups Projects
Unverified Commit 463e04b2 authored by endorama's avatar endorama Committed by GitHub
Browse files

Remove content migrated to sigstore docs (#476)


* Delete INSTALLATION.md

Signed-off-by: default avatarEdoardo Tenani <edoardo.tenani@pm.me>

* Delete release-verify.md

Signed-off-by: default avatarEdoardo Tenani <edoardo.tenani@pm.me>

* Update README.md

Signed-off-by: default avatarEdoardo Tenani <edoardo.tenani@pm.me>

* Update README.md

Signed-off-by: default avatarEdoardo Tenani <edoardo.tenani@pm.me>

* Apply suggestions from code review

Co-authored-by: default avatarBob Callaway <bobcallaway@users.noreply.github.com>
Signed-off-by: default avatarEdoardo Tenani <edoardo.tenani@pm.me>

Co-authored-by: default avatarBob Callaway <bobcallaway@users.noreply.github.com>
parent 6cd26da7
No related branches found
No related tags found
No related merge requests found
# Rekor installation
There are serveral methods to install rekor which we will cover here for both the rekor-cli and server
## From the release page
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.
## Using go install
If you have go installed, you can use go to retreive the rekor binaries
```
go install -v github.com/sigstore/rekor/cmd/rekor-cli@latest
```
You may also do the same for rekor-server, but **note** that rekor server also
requires trillian and database. See [database]
```
go install -v github.com/sigstore/rekor/cmd/rekor-server@latest
```
## Build from the git repository
Clone rekor
```
git clone https://github.com/sigstore/rekor.git
```
And then use our Makefile to build:
```
make rekor-cli rekor-server
```
> :notebook: You will of course need the 'make' package to run the above
# Rekor Server Set up
## Configure trillians database
To set up trillians database we need to create the database / tables.
Trillian requires a database, we use MariaDB for now (others to be explored later). Once this is installed on your machine,
edit the `scripts/createdb.sh` file with your database root account credentials and run the script.
If you’re just trying out rekor, keep the DB user name and password the same as in the script (test/zaphod). If you change these,
you need to make the changes on Trillian’s side (visit the trillian repo for details).
```
wget https://raw.githubusercontent.com/sigstore/rekor/main/scripts/createdb.sh
```
```
wget https://raw.githubusercontent.com/sigstore/rekor/main/scripts/storage.sql
```
```
chmod +x createdb.sh
```
```
sudo ./createdb.sh
```
## Install trillian
```
go install github.com/google/trillian/cmd/trillian_log_server@v1.3.14-0.20210713114448-df474653733c
```
```
go install github.com/google/trillian/cmd/trillian_log_signer@v1.3.14-0.20210713114448-df474653733c
```
```
go install github.com/google/trillian/cmd/createtree@v1.3.14-0.20210713114448-df474653733c
```
## Run trillian
First run the trillian log server
```
trillian_log_server -http_endpoint=localhost:8091 -rpc_endpoint=localhost:8090 --logtostderr ...
```
Now run the signer:
```
trillian_log_signer --logtostderr --force_master --http_endpoint=localhost:8191 -rpc_endpoint=localhost:8190 --batch_size=1000 --sequencer_guard_window=0 --sequencer_interval=200ms
```
Create tree:
```
createtree --admin_server=localhost:8090
```
## Run Rekor
We are now ready to run rekor.
```
rekor-server serve --rekor_server.address=0.0.0.0 --rekor_server.port=3000 --enable_retrieve_api=false
```
> :notebook: If you want a quick handy search index, then you will need to install redis-server
and remove the argument `--enable_retrieve_api=false`.
Example:
```
2021-07-29T12:06:47.829+0100 INFO app/root.go:107 Using config file: /home/luke/go/src/github.com/lukehinds/rekor/rekor-server.yaml
2021-07-29T12:06:47.830+0100 INFO app/serve.go:66 starting rekor-server
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'jar'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'jar'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'intoto'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'intoto'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'rfc3161'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'rfc3161'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'alpine'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'alpine'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'helm'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'helm'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'rekord'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'rekord'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:91 Loading support for pluggable type 'rpm'
2021-07-29T12:06:47.841+0100 INFO app/serve.go:92 Loading version '0.0.1' for pluggable type 'rpm'
2021-07-29T12:06:47.858+0100 INFO restapi/server.go:230 Serving rekor server at http://127.0.0.1:3000
```
## Use of rekor CLI
For examples of using the rekor-cli, please see the [types](types.md) documentation
......@@ -14,20 +14,15 @@ Rekor fulfils the signature transparency role of sigstore's software signing
infrastructure. However, Rekor can be run on its own and is designed to be
extensible to working with different manifest schemas and PKI tooling.
## Public Instance
[Official Documentation](https://docs.sigstore.dev/rekor/overview).
A public instance of rekor can be found at [rekor.sigstore.dev](https://rekor.sigstore.dev/api/v1/log/)
## Public Instance
**IMPORTANT**: This instance is currently operated on a best-effort basis.
**IMPORTANT**: This instance is currently operated on a best-effort basis.
We **will take the log down** and reset it with zero notice.
We will improve the stability and publish SLOs over time.
This instance is maintained by the Rekor community.
Interested in helping operate and maintain our production CA system and Transparency Logs?
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!
More details on the public instance can be found at [docs.sigstore.dev](https://docs.sigstore.dev/rekor/public-instance).
### Installation
......@@ -38,43 +33,6 @@ the rekor server
For examples of uploading signatures for all the supported types to rekor, see [the types documentation](types.md).
### Auditing the Instance
We run a job to publish the latest Signed Tree Hashes on GCS.
They are served publicly, and can be found with:
```
gsutil ls gs://rekor-sth/
gs://rekor-sth/sth-1173.json
```
The format is currently:
```
$ gsutil cat gs://rekor-sth/sth-1173.json | jq .
{
"SignedLogRoot": {
"key_hint": "Ni+Oy6cvQyY=",
"log_root": "AAEAAAAAAAAElSB3sp4yw0NFEWsTB6RT5mjr6GCKxVQ8Tlym+P3uKTQwuxZquNPzzd3mAAAAAAAACIUAAA==",
"log_root_signature": "MEUCIQCb8QHWym7jBvBMFk8ir1ZTqT83zpjE0c90vi7VrTG70wIgBwQmaQ96Od62ODZkdT6r1eVsl4r14tYR1MwQbkNv8ZM="
},
"VerifiedLogRoot": {
"TreeSize": 1173,
"RootHash": "d7KeMsNDRRFrEwekU+Zo6+hgisVUPE5cpvj97ik0MLs=",
"TimestampNanos": 1615306636833709600,
"Revision": 2181,
"Metadata": ""
}
}
```
We store them in both raw (unverified) and decoded (verified) formats.
You can verify the signatures against Rekor's public key.
These entries contain the tree length, tree root hash as well as the timestamp.
The (signed) timestamp and index of a (signed) tree hash may be used as an attestation that any entries in the log
prior to this index were witnessed by Rekor before this time.
## Extensibility
### Custom schemas / manifests (rekor type)
......
......@@ -21,128 +21,4 @@ Rekor supports pluggable types (aka different schemas) for entries stored in the
- RPM Packages [schema](rpm/rpm_schema.json)
- Versions: 0.0.1
## Base Schema
The base schema for all types is modeled off of the schema used by Kubernetes and can be found in `openapi.yaml` as `#/definitions/ProposedEntry`:
```
definitions:
ProposedEntry:
type: object
discriminator: kind
properties:
kind:
type: string
required:
- kind
```
The `kind` property is a [discriminator](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-13) that is used to differentiate between different pluggable types. Types can have one or more versions of the schema supported concurrently by the same Rekor instance; an example implementation can be seen in `rekord.go`.
## Adding Support for a New Type
To add a new type (called `newType` in this example):
1. Add a new definition in `openapi.yaml` that is a derived type of ProposedEntry (expressed in the `allOf` list seen below); for example:
```yaml
newType:
type: object
description: newType object
allOf:
- $ref: '#/definitions/ProposedEntry'
- properties:
version:
type: string
metadata:
type: object
additionalProperties: true
data:
type: object
$ref: 'pkg/types/newType/newType_schema.json'
required:
- version
- data
additionalProperties: false
```
> Note: the `$ref` feature can be used to refer to an externally defined JSON schema document; however it is also permitted to describe the entirety of the type in valid Swagger (aka OpenAPI) v2 format within `openapi.yaml`.
2. Create a subdirectory under `pkg/types/` with your type name (e.g. `newType`) as a new Go package
3. In this new Go package, define a struct that:
```go
type TypeImpl interface {
CreateProposedEntry(context.Context, string, ArtifactProperties) (models.ProposedEntry, error)
DefaultVersion() string
SupportedVersions() []string
UnmarshalEntry(pe models.ProposedEntry) (EntryImpl, error)
}
```
- implements the `TypeImpl` interface as defined in `types.go`:
- `CreateProposedEntry` will be called with string specifying the requested version and an ArtifactProperties struct that calls the version's `CreateFromArtifactProperties` method
- `DefaultVersion` specifies the default version for the type to be used if one is not explicitly requested
- `SupportedVersions` specifies a list of all version strings that are supported by this Rekor instance
- `UnmarshalEntry` will be called with a pointer to a struct that was automatically generated for the type defined in `openapi.yaml` by the [go-swagger](http://github.com/go-swagger/go-swagger) tool used by Rekor
- This struct will be defined in the generated file at `pkg/generated/models/newType.go` (where `newType` is replaced with the name of the type you are adding)
- This method should return a pointer to an instance of a struct that implements the `EntryImpl` interface as defined in `types.go`, or a `nil` pointer with an error specified
- embeds the `RekorType` type into the struct definition
- The purpose of this is to set the Kind variable to match the type name
- `RekorType` also includes a `VersionMap` field, which provides the lookup for a version string from a proposed entry to find the correct implmentation code
4. Also in this Go package, provide an implementation of the `EntryImpl` interface as defined in `types.go`:
```go
type EntryImpl interface {
APIVersion() string
IndexKeys() []string
Canonicalize(ctx context.Context) ([]byte, error)
Unmarshal(pe models.ProposedEntry) error
Attestation() (string, []byte)
CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error)
}
```
- `APIVersion` should return a version string that identifies the version of the type supported by the Rekor server
- `IndexKeys` should return a `[]string` that extracts the keys from an entry to be stored in the search index
- `Canonicalize` should return a `[]byte` containing the canonicalized contents representing the entry. The canonicalization of contents is important as we should have one record per unique signed object in the transparency log.
- `Unmarshal` will be called with a pointer to a struct that was automatically generated for the type defined in `openapi.yaml` by the [go-swagger](http://github.com/go-swagger/go-swagger) tool used by Rekor
- This method should validate the contents of the struct to ensure any string or cross-field dependencies are met to successfully insert an entry of this type into the transparency log
- This method should also succesfully unmarshal entries that have been canonicalized and inserted into the log; however, it is worth noting that you may not be able to re-canonicalize an entry (since the original content required to verify the signature may not be present in the persisted log entry).
- `Attestation` provides types to return an in-toto attestation that should be persisted.
- `CreateFromArtifactProperties` creates a new entry given the specified artifact properties (typically passed in by `rekor-cli`).
5. In the Go package you have created for the new type, be sure to add an entry in the `TypeMap` in `github.com/sigstore/rekor/pkg/types` for your new type in the `init` method for your package. The key for the map is the unique string used to define your type in `openapi.yaml` (e.g. `newType`), and the value for the map is the name of a factory function for an instance of `TypeImpl`.
```go
func init() {
types.TypeMap.Store("newType", NewEntry)
}
```
6. Add an entry to `pluggableTypeMap` in `cmd/rekor-server/app/serve.go` that provides a reference to your package. This ensures that the `init` function of your type (and optionally, your version implementation) will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.
7. Add an import statement to `cmd/rekor-cli/app/root.go` that provides a reference to your package/new version. This ensures that the `init` function of your type (and optionally, your version implementation) will be called before the CLI runs; this populates the required type maps and allows the CLI to interact with the type implementations in a loosely coupled manner.
8. After adding sufficient unit & integration tests, submit a pull request to `github.com/sigstore/rekor` for review and addition to the codebase.
## Adding a New Version of the `Rekord` type
To add new version of the default `Rekord` type:
1. Create a new subdirectory under `pkg/types/rekord/` for the new version
2. If there are changes to the Rekord schema for this version, create a new JSON schema document and add a reference to it within the `oneOf` clause in `rekord_schema.json`. If there are no changes, skip this step.
3. Provide an implementation of the `EntryImpl` interface as defined in `pkg/types/types.go` for the new version.
4. In your package's `init` method, ensure there is a call to `VersionMap.Store()` which provides the link between the valid *semver* ranges that your package can successfully process and the factory function that creates an instance of a struct for your new version.
5. Add an entry to `pluggableTypeMap` in `cmd/rekor-server/app/serve.go` that provides a reference to the Go package implementing the new version. This ensures that the `init` function will be called before the server starts to process incoming requests and therefore will be added to the map that is used to route request processing for different types.
6. Add an import statement to `cmd/rekor-cli/app/root.go` that provides a reference to your package/new version. This ensures that the `init` function of your type (and optionally, your version implementation) will be called before the CLI runs; this populates the required type maps and allows the CLI to interact with the type implementations in a loosely coupled manner.
7. After adding sufficient unit & integration tests, submit a pull request to `github.com/sigstore/rekor` for review and addition to the codebase.
## Error Handling
The `Canonicalize` method in the `EntryImpl` interface generates the canonicalized content for insertion into the transparency log. While errors returned from the `Unmarshal` method should always be considered as an error with what the client has provided (thus generating a HTTP 400 Bad Request response), errors from the `Canonicalize` method can be either `types.ValidationError` which means the content provided inside of (or referred to by) the incoming request could not be successfully processed or verified, or a generic `error` which should be interpreted as a HTTP 500 Internal Server Error to which the client can not resolve.
\ No newline at end of file
Refer to [Rekor docs](https://docs.sigstore.dev/rekor/pluggable-types) for adding support for new types.
# 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment