From 869d278252b519b6b6e7cc6a0f5918f485d50026 Mon Sep 17 00:00:00 2001 From: Billy Lynch Date: Fri, 23 Sep 2022 17:22:46 -0400 Subject: [PATCH] Wire up timestamp authorities option to config. Adds GITSIGN_TIMESTAMP_AUTHORITY config option for specifying a TSA URL in the gitsign config. Also adds an e2e test since this is a pain to test without a real TSA. Note: certain TSA (notably freetsa.org) do not work due to a bug. https://github.com/github/smimesign/pull/118. Trying to fix upstream. Signed-off-by: Billy Lynch --- .github/workflows/e2e.yaml | 20 ++++++++++++++++++- README.md | 40 ++++++++++++++++++++------------------ command_sign.go | 2 +- internal/config/config.go | 4 ++++ internal/signature/sign.go | 4 ++-- main.go | 9 ++------- 6 files changed, 49 insertions(+), 30 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index c234f1d8..9a784633 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -52,7 +52,7 @@ jobs: go-version: 1.19 check-latest: true - - name: Test Sign and Verify commit + - name: Install Gitsign run: | set -e @@ -72,6 +72,9 @@ jobs: # Verify tool is on our path gitsign -h + - name: Test Sign and Verify commit + run: | + set -e # Sign commit git commit --allow-empty -S --message="Signed commit" @@ -79,6 +82,21 @@ jobs: # Verify commit git verify-commit HEAD + # Extra debug info + git cat-file commit HEAD | sed -n '/BEGIN/, /END/p' | sed 's/^ //g' | sed 's/gpgsig //g' | sed 's/SIGNED MESSAGE/PKCS7/g' | openssl pkcs7 -print -print_certs -text + - name: Test Timestamped Commit + env: + # See https://knowledge.digicert.com/generalinformation/INFO4231.html + GITSIGN_TIMESTAMP_AUTHORITY: "http://timestamp.digicert.com" + run: | + set -e + + # Sign commit + git commit --allow-empty -S --message="Signed timestamp commit" + + # Verify commit + git verify-commit HEAD + # Extra debug info git cat-file commit HEAD | sed -n '/BEGIN/, /END/p' | sed 's/^ //g' | sed 's/gpgsig //g' | sed 's/SIGNED MESSAGE/PKCS7/g' | openssl pkcs7 -print -print_certs -text - name: Debug log diff --git a/README.md b/README.md index 01efc0e5..016446ba 100644 --- a/README.md +++ b/README.md @@ -58,28 +58,30 @@ $ git config --local gitsign.fulcio https://fulcio.example.com The following config options are supported: -| Option | Default | Description | -| ----------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| fulcio | https://fulcio.sigstore.dev | Address of Fulcio server | -| logPath | | Path to log status output. Helpful for debugging when no TTY is available in the environment. | -| clientID | sigstore | OIDC client ID for application | -| issuer | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token | -| redirectURL | | OIDC Redirect URL | -| rekor | https://rekor.sigstore.dev | Address of Rekor server | -| connectorID | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` | +| Option | Default | Description | +| ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| fulcio | https://fulcio.sigstore.dev | Address of Fulcio server | +| logPath | | Path to log status output. Helpful for debugging when no TTY is available in the environment. | +| clientID | sigstore | OIDC client ID for application | +| issuer | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token | +| redirectURL | | OIDC Redirect URL | +| rekor | https://rekor.sigstore.dev | Address of Rekor server | +| connectorID | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` | +| timestampAuthority | | Optional address of timestamping authority. If set, a trusted timestamp will be included in the signature. | ### Environment Variables -| Environment Variable | Sigstore
Prefix | Default | Description | -| ------------------------- | ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| GITSIGN_CREDENTIAL_CACHE | ❌ | | Optional path to [gitsign-credential-cache](cmd/gitsign-credential-cache/README.md) socket. | -| GITSIGN_CONNECTOR_ID | ✅ | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` | -| GITSIGN_FULCIO_URL | ✅ | https://fulcio.sigstore.dev | Address of Fulcio server | -| GITSIGN_LOG | ❌ | | Path to log status output. Helpful for debugging when no TTY is available in the environment. | -| GITSIGN_OIDC_CLIENT_ID | ✅ | sigstore | OIDC client ID for application | -| GITSIGN_OIDC_ISSUER | ✅ | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token | -| GITSIGN_OIDC_REDIRECT_URL | ✅ | | OIDC Redirect URL | -| GITSIGN_REKOR_URL | ✅ | https://rekor.sigstore.dev | Address of Rekor server | +| Environment Variable | Sigstore
Prefix | Default | Description | +| --------------------------- | ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| GITSIGN_CREDENTIAL_CACHE | ❌ | | Optional path to [gitsign-credential-cache](cmd/gitsign-credential-cache/README.md) socket. | +| GITSIGN_CONNECTOR_ID | ✅ | | Optional Connector ID to auto-select to pre-select auth flow to use. For the public sigstore instance, valid values are:
- `https://github.com/login/oauth`
- `https://accounts.google.com`
- `https://login.microsoftonline.com` | +| GITSIGN_FULCIO_URL | ✅ | https://fulcio.sigstore.dev | Address of Fulcio server | +| GITSIGN_LOG | ❌ | | Path to log status output. Helpful for debugging when no TTY is available in the environment. | +| GITSIGN_OIDC_CLIENT_ID | ✅ | sigstore | OIDC client ID for application | +| GITSIGN_OIDC_ISSUER | ✅ | https://oauth2.sigstore.dev/auth | OIDC provider to be used to issue ID token | +| GITSIGN_OIDC_REDIRECT_URL | ✅ | | OIDC Redirect URL | +| GITSIGN_REKOR_URL | ✅ | https://rekor.sigstore.dev | Address of Rekor server | +| GITSIGN_TIMESTAMP_AUTHORITY | ✅ | | Optional address of timestamping authority. If set, a trusted timestamp will be included in the signature. | For environment variables that support `Sigstore Prefix`, the values may be provided with either a `GITSIGN_` or `SIGSTORE_` prefix - e.g. diff --git a/command_sign.go b/command_sign.go index 808af45b..5501c419 100644 --- a/command_sign.go +++ b/command_sign.go @@ -63,7 +63,7 @@ func commandSign(cfg *config.Config) error { sig, cert, err := git.Sign(ctx, rekor, userIdent, dataBuf.Bytes(), signature.SignOptions{ Detached: *detachSignFlag, - TimestampAuthority: *tsaOpt, + TimestampAuthority: cfg.TimestampAuthority, Armor: *armorFlag, IncludeCerts: *includeCertsOpt, }) diff --git a/internal/config/config.go b/internal/config/config.go index b4061a39..10e96228 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -48,6 +48,9 @@ type Config struct { // for more details. ConnectorID string + // Timestamp Authority address to use to get a trusted timestamp + TimestampAuthority string + // Path to log status output. Helpful for debugging when no TTY is available in the environment. LogPath string } @@ -83,6 +86,7 @@ func Get() (*Config, error) { out.RedirectURL = envOrValue(fmt.Sprintf("%s_OIDC_REDIRECT_URL", prefix), out.RedirectURL) out.Issuer = envOrValue(fmt.Sprintf("%s_OIDC_ISSUER", prefix), out.Issuer) out.ConnectorID = envOrValue(fmt.Sprintf("%s_CONNECTOR_ID", prefix), out.ConnectorID) + out.TimestampAuthority = envOrValue(fmt.Sprintf("%s_TIMESTAMP_AUTHORITY", prefix), out.TimestampAuthority) } out.LogPath = envOrValue("GITSIGN_LOG", out.LogPath) diff --git a/internal/signature/sign.go b/internal/signature/sign.go index ca5fe4c1..e48486d6 100644 --- a/internal/signature/sign.go +++ b/internal/signature/sign.go @@ -90,13 +90,13 @@ func Sign(ident Identity, body []byte, opts SignOptions) ([]byte, *x509.Certific chain, err := ident.CertificateChain() if err != nil { - return nil, nil, fmt.Errorf("failed to get idenity certificate chain: %w", err) + return nil, nil, fmt.Errorf("failed to get identity certificate chain: %w", err) } // TODO: look into adding back support for opts.IncludeCerts here. // This was removed due to unstable ordering in the cert chain when // intermediates were included. if chain, err = certsForSignature(chain, 1); err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to extract certificates from chain: %w", err) } if err := sd.SetCertificates(chain); err != nil { return nil, nil, fmt.Errorf("failed to set certificates: %w", err) diff --git a/main.go b/main.go index 507a8631..ca93012a 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "os" + "runtime/debug" "github.com/mattn/go-tty" "github.com/pborman/getopt/v2" @@ -29,11 +30,6 @@ import ( "github.com/sigstore/gitsign/internal/config" ) -const ( - // TODO: Use fulcio as timestamp authority. - defaultTSA = "" -) - var ( // Action flags helpFlag = getopt.BoolLong("help", 'h', "print this help message") @@ -46,7 +42,6 @@ var ( detachSignFlag = getopt.BoolLong("detach-sign", 'b', "make a detached signature") armorFlag = getopt.BoolLong("armor", 'a', "create ascii armored output") statusFdOpt = getopt.IntLong("status-fd", 0, -1, "write special status strings to the file descriptor n.", "n") - tsaOpt = getopt.StringLong("timestamp-authority", 't', defaultTSA, "URL of RFC3161 timestamp authority to use for timestamping", "url") includeCertsOpt = getopt.IntLong("include-certs", 0, -2, "-3 is the same as -2, but ommits issuer when cert has Authority Information Access extension. -2 includes all certs except root. -1 includes all certs. 0 includes no certs. 1 includes leaf cert. >1 includes n from the leaf. Default -2.", "n") // Remaining arguments @@ -104,7 +99,7 @@ func wrapIO(cfg *config.Config, fn func(*config.Config) error) error { // Log any panics to ttyout, since otherwise they will be lost to os.Stderr. defer func() { if r := recover(); r != nil { - fmt.Fprintln(ttyout, r) + fmt.Fprintln(ttyout, string(debug.Stack()), r) } }()