File: sigstore.go

package info (click to toggle)
golang-github-containers-image 5.28.0-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,104 kB
  • sloc: sh: 194; makefile: 73
file content (117 lines) | stat: -rw-r--r-- 4,290 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package sigstore

import (
	"errors"
	"fmt"
	"io"
	"net/url"

	"github.com/containers/image/v5/pkg/cli"
	"github.com/containers/image/v5/pkg/cli/sigstore/params"
	"github.com/containers/image/v5/signature/signer"
	"github.com/containers/image/v5/signature/sigstore"
	"github.com/containers/image/v5/signature/sigstore/fulcio"
	"github.com/containers/image/v5/signature/sigstore/rekor"
)

// Options collects data that the caller should provide to NewSignerFromParameterFile.
// The caller should set all fields unless documented otherwise.
type Options struct {
	PrivateKeyPassphrasePrompt func(keyFile string) (string, error) // A function to call to interactively prompt for a passphrase
	Stdin                      io.Reader
	Stdout                     io.Writer
}

// NewSignerFromParameterFile returns a signature.Signer which creates sigstore signatures based a parameter file at the specified path.
//
// The caller must call Close() on the returned Signer.
func NewSignerFromParameterFile(path string, options *Options) (*signer.Signer, error) {
	params, err := params.ParseFile(path)
	if err != nil {
		return nil, fmt.Errorf("setting up signing using parameter file %q: %w", path, err)
	}
	return newSignerFromParameterData(params, options)
}

// newSignerFromParameterData returns a signature.Signer which creates sigstore signatures based on parameter file contents.
//
// The caller must call Close() on the returned Signer.
func newSignerFromParameterData(params *params.SigningParameterFile, options *Options) (*signer.Signer, error) {
	opts := []sigstore.Option{}
	if params.PrivateKeyFile != "" {
		var getPassphrase func(keyFile string) (string, error)
		switch {
		case params.PrivateKeyPassphraseFile != "":
			getPassphrase = func(_ string) (string, error) {
				return cli.ReadPassphraseFile(params.PrivateKeyPassphraseFile)
			}
		case options.PrivateKeyPassphrasePrompt != nil:
			getPassphrase = options.PrivateKeyPassphrasePrompt
		default: // This shouldn’t happen, the caller is expected to set options.PrivateKeyPassphrasePrompt
			return nil, fmt.Errorf("private key %s specified, but no way to get a passphrase", params.PrivateKeyFile)
		}
		passphrase, err := getPassphrase(params.PrivateKeyFile)
		if err != nil {
			return nil, err
		}
		opts = append(opts, sigstore.WithPrivateKeyFile(params.PrivateKeyFile, []byte(passphrase)))
	}

	if params.Fulcio != nil {
		fulcioOpt, err := fulcioOption(params.Fulcio, options)
		if err != nil {
			return nil, err
		}
		opts = append(opts, fulcioOpt)
	}

	if params.RekorURL != "" {
		rekorURL, err := url.Parse(params.RekorURL)
		if err != nil {
			return nil, fmt.Errorf("parsing rekorURL %q: %w", params.RekorURL, err)
		}
		opts = append(opts, rekor.WithRekor(rekorURL))
	}

	return sigstore.NewSigner(opts...)
}

// fulcioOption returns a sigstore.Option for Fulcio use based on f.
func fulcioOption(f *params.SigningParameterFileFulcio, options *Options) (sigstore.Option, error) {
	if f.FulcioURL == "" {
		return nil, errors.New("missing fulcioURL")
	}
	fulcioURL, err := url.Parse(f.FulcioURL)
	if err != nil {
		return nil, fmt.Errorf("parsing fulcioURL %q: %w", f.FulcioURL, err)
	}

	if f.OIDCMode == params.OIDCModeStaticToken {
		if f.OIDCIDToken == "" {
			return nil, errors.New("missing oidcToken")
		}
		return fulcio.WithFulcioAndPreexistingOIDCIDToken(fulcioURL, f.OIDCIDToken), nil
	}

	if f.OIDCIssuerURL == "" {
		return nil, errors.New("missing oidcIssuerURL")
	}
	oidcIssuerURL, err := url.Parse(f.OIDCIssuerURL)
	if err != nil {
		return nil, fmt.Errorf("parsing oidcIssuerURL %q: %w", f.OIDCIssuerURL, err)
	}
	switch f.OIDCMode {
	case params.OIDCModeDeviceGrant:
		return fulcio.WithFulcioAndDeviceAuthorizationGrantOIDC(fulcioURL, oidcIssuerURL, f.OIDCClientID, f.OIDCClientSecret,
			options.Stdout), nil
	case params.OIDCModeInteractive:
		return fulcio.WithFulcioAndInteractiveOIDC(fulcioURL, oidcIssuerURL, f.OIDCClientID, f.OIDCClientSecret,
			options.Stdin, options.Stdout), nil
	case "":
		return nil, errors.New("missing oidcMode")
	case params.OIDCModeStaticToken:
		return nil, errors.New("internal inconsistency: SigningParameterFileOIDCModeStaticToken was supposed to already be handled")
	default:
		return nil, fmt.Errorf("unknown oidcMode value %q", f.OIDCMode)
	}
}