Skip to content

Commit 3cd2b7b

Browse files
authored
Merge pull request #11 from alopez-suse/NVSHAS-7882
NVSHAS-7882: Proxy support for sigstore-interface
2 parents 1889d7c + eb15bfc commit 3cd2b7b

File tree

5 files changed

+300
-35
lines changed

5 files changed

+300
-35
lines changed

caller/main.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"io"
8+
"log"
9+
"os/exec"
10+
)
11+
12+
var proxyURL = flag.String("proxy-url", "", "")
13+
var proxyHasCredentials = flag.Bool("proxy-has-credentials", false, "")
14+
var configFilePath = flag.String("config-file", "", "")
15+
var proxyLogin = flag.String("proxy-login", "", "")
16+
17+
// for testing stdin pipe operations
18+
func main() {
19+
flag.Parse()
20+
cmd := exec.Command(
21+
"../sigstore-interface",
22+
fmt.Sprintf("--config-file=%s", *configFilePath),
23+
fmt.Sprintf("--proxy-url=%s", *proxyURL),
24+
fmt.Sprintf("--proxy-has-credentials=%t", *proxyHasCredentials),
25+
)
26+
27+
stderr, _ := cmd.StderrPipe()
28+
stdout, _ := cmd.StdoutPipe()
29+
stdin, _ := cmd.StdinPipe()
30+
31+
var closeErr error
32+
33+
go func() {
34+
fmt.Println("writing to stdin")
35+
io.WriteString(stdin, *proxyLogin)
36+
closeErr = stdin.Close()
37+
}()
38+
39+
fmt.Println("starting cmd")
40+
if err := cmd.Start(); err != nil {
41+
log.Fatal(err)
42+
}
43+
44+
scanner := bufio.NewScanner(stderr)
45+
for scanner.Scan() {
46+
fmt.Println(scanner.Text())
47+
}
48+
49+
scanner = bufio.NewScanner(stdout)
50+
for scanner.Scan() {
51+
fmt.Println(scanner.Text())
52+
}
53+
54+
cmd.Wait()
55+
56+
if closeErr != nil {
57+
fmt.Printf("error when closing stdin pipe: %s\n", closeErr)
58+
}
59+
}

http-client.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"crypto/tls"
5+
"encoding/base64"
6+
"fmt"
7+
"net/http"
8+
"net/url"
9+
)
10+
11+
type Proxy struct {
12+
URL string
13+
Username string
14+
Password string
15+
}
16+
17+
func (p Proxy) HasAuthorizationCredentials() bool {
18+
return p.Username != ""
19+
}
20+
21+
func (p Proxy) BasicAuthorizationHeader() string {
22+
auth := fmt.Sprintf("%s:%s", p.Username, p.Password)
23+
encodedAuth := base64.StdEncoding.EncodeToString([]byte(auth))
24+
return "Basic " + encodedAuth
25+
}
26+
27+
func (p Proxy) HttpTransport() http.Transport {
28+
proxyURLFunc := func(r *http.Request) (*url.URL, error) {
29+
return url.Parse(p.URL)
30+
}
31+
transport := http.Transport{
32+
Proxy: proxyURLFunc,
33+
TLSClientConfig: &tls.Config{
34+
InsecureSkipVerify: true,
35+
},
36+
}
37+
if p.HasAuthorizationCredentials() {
38+
transport.ProxyConnectHeader = http.Header{}
39+
transport.ProxyConnectHeader.Add("Proxy-Authorization", p.BasicAuthorizationHeader())
40+
}
41+
return transport
42+
}

main.go

Lines changed: 97 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ import (
1515

1616
v1 "github.com/google/go-containerregistry/pkg/v1"
1717
"github.com/google/go-containerregistry/pkg/v1/static"
18-
"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
1918
"github.com/sigstore/cosign/v2/pkg/cosign"
2019
"github.com/sigstore/cosign/v2/pkg/oci"
2120
"github.com/sigstore/cosign/v2/pkg/oci/signature"
2221
sig "github.com/sigstore/cosign/v2/pkg/signature"
2322
"github.com/sigstore/sigstore/pkg/cryptoutils"
24-
"github.com/sigstore/sigstore/pkg/tuf"
23+
sigtuf "github.com/sigstore/sigstore/pkg/tuf"
2524
)
2625

2726
type Configuration struct {
@@ -63,12 +62,47 @@ type SignatureData struct {
6362
Payloads map[string]string `json:"Payloads"`
6463
}
6564

65+
var configFilePath = flag.String("config-file", "", "path to the config file with target image digest, root of trust, signature, and verifier data")
66+
67+
var proxyURL = flag.String("proxy-url", "", "")
68+
var proxyHasCredentials = flag.Bool("proxy-has-credentials", false, "")
69+
70+
func getProxyDetails() (Proxy, error) {
71+
if *proxyURL == "" {
72+
return Proxy{}, nil
73+
}
74+
proxy := Proxy{URL: *proxyURL}
75+
if *proxyHasCredentials {
76+
stdinCredentials, err := os.ReadFile(os.Stdin.Name())
77+
if err != nil {
78+
return Proxy{}, fmt.Errorf("error when reading credentials, could not read stdin: %s", err.Error())
79+
}
80+
if len(stdinCredentials) == 0 {
81+
return Proxy{}, fmt.Errorf("expecting credentials but received empty string")
82+
}
83+
separatorIndex := strings.Index(string(stdinCredentials), ":")
84+
if separatorIndex == 0 {
85+
return Proxy{}, fmt.Errorf("proxy credentials argument cannot start with colon, expecting USERNAME:PASSWORD")
86+
}
87+
splitCredentials := strings.Split(string(stdinCredentials), ":")
88+
proxy.Username = splitCredentials[0]
89+
proxy.Password = strings.Join(splitCredentials[1:], ":")
90+
}
91+
return proxy, nil
92+
}
93+
6694
func main() {
95+
flag.Parse()
6796
config, err := loadConfiguration()
6897
if err != nil {
6998
log.Fatalf("ERROR: error loading config: %s", err.Error())
7099
}
71100

101+
proxy, err := getProxyDetails()
102+
if err != nil {
103+
log.Fatalf("ERROR: error when getting proxy details: %s", err.Error())
104+
}
105+
72106
imageDigestHash, err := v1.NewHash(config.ImageDigest)
73107
if err != nil {
74108
log.Fatalf("ERROR: error hashing image digest: %s", err.Error())
@@ -82,7 +116,7 @@ func main() {
82116
allSatisfiedVerifiers := []string{}
83117
for _, rootOfTrust := range config.RootsOfTrust {
84118
fmt.Printf("\n>>>> checking root of trust: %s\n", rootOfTrust.Name)
85-
satisfiedVerifiers, err := verify(imageDigestHash, rootOfTrust, signatures)
119+
satisfiedVerifiers, err := verify(imageDigestHash, rootOfTrust, signatures, proxy)
86120
if err != nil {
87121
// line with prefix "ERROR: " is recognized by scanner for error encounted when verifying against a verifier
88122
fmt.Printf("ERROR: %s\n", err.Error())
@@ -96,8 +130,6 @@ func main() {
96130
}
97131

98132
func loadConfiguration() (config Configuration, err error) {
99-
configFilePath := flag.String("config-file", "", "path to the config file with target image digest, root of trust, signature, and verifier data")
100-
flag.Parse()
101133
if *configFilePath == "" {
102134
return config, errors.New("must provide --config-file flag")
103135
}
@@ -126,10 +158,10 @@ func generateCosignSignatureObjects(sigData SignatureData) ([]oci.Signature, err
126158
return signatures, nil
127159
}
128160

129-
func verify(imgDigest v1.Hash, rootOfTrust RootOfTrust, sigs []oci.Signature) (satisfiedVerifiers []string, err error) {
161+
func verify(imgDigest v1.Hash, rootOfTrust RootOfTrust, sigs []oci.Signature, proxy Proxy) (satisfiedVerifiers []string, err error) {
130162
ctx := context.Background()
131163
cosignOptions := cosign.CheckOpts{ClaimVerifier: cosign.SimpleClaimVerifier}
132-
err = setRootOfTrustCosignOptions(&cosignOptions, rootOfTrust, ctx)
164+
err = setRootOfTrustCosignOptions(&cosignOptions, rootOfTrust, proxy, ctx)
133165
if err != nil {
134166
return satisfiedVerifiers, fmt.Errorf("could not set root of trust %s cosign check options: %s", rootOfTrust.Name, err.Error())
135167
}
@@ -158,25 +190,31 @@ func verify(imgDigest v1.Hash, rootOfTrust RootOfTrust, sigs []oci.Signature) (s
158190
return satisfiedVerifiers, nil
159191
}
160192

161-
func setRootOfTrustCosignOptions(cosignOptions *cosign.CheckOpts, rootOfTrust RootOfTrust, ctx context.Context) (err error) {
162-
// rekor pub keys
163-
if rootOfTrust.RekorPublicKey != "" {
164-
publicKeyCollection := cosign.NewTrustedTransparencyLogPubKeys()
165-
if err := publicKeyCollection.AddTransparencyLogPubKey([]byte(rootOfTrust.RekorPublicKey), tuf.Active); err != nil {
166-
return fmt.Errorf("could not add custom rekor public key to collection: %w", err)
193+
func setRootOfTrustCosignOptions(cosignOptions *cosign.CheckOpts, rootOfTrust RootOfTrust, proxy Proxy, ctx context.Context) (err error) {
194+
// rekor public keys
195+
rekorKeyCollection := cosign.NewTrustedTransparencyLogPubKeys()
196+
if rootOfTrust.RekorPublicKey == "" {
197+
rekorKeyTargets, err := GetTargets(sigtuf.Rekor, proxy)
198+
if err != nil {
199+
return fmt.Errorf("could not retrieve rekor tuf targets: %s", err.Error())
200+
}
201+
for _, rekorKeyTarget := range rekorKeyTargets {
202+
if err := rekorKeyCollection.AddTransparencyLogPubKey(rekorKeyTarget.Target, rekorKeyTarget.Status); err != nil {
203+
return fmt.Errorf("could not add public root of trust rekor public key to collection: %w", err)
204+
}
167205
}
168-
cosignOptions.RekorPubKeys = &publicKeyCollection
169206
} else {
170-
cosignOptions.RekorPubKeys, err = cosign.GetRekorPubs(ctx)
171-
if err != nil {
172-
return fmt.Errorf("could not get default rekor public key: %w", err)
207+
if err := rekorKeyCollection.AddTransparencyLogPubKey([]byte(rootOfTrust.RekorPublicKey), sigtuf.Active); err != nil {
208+
return fmt.Errorf("could not add custom root of trust rekor public key to collection: %w", err)
173209
}
174210
}
175-
// root certificate(s)
211+
cosignOptions.RekorPubKeys = &rekorKeyCollection
212+
213+
// root & intermediate certificates
214+
selfSigned := func(cert *x509.Certificate) bool {
215+
return bytes.Equal(cert.RawSubject, cert.RawIssuer)
216+
}
176217
if rootOfTrust.RootCert != "" {
177-
selfSigned := func(cert *x509.Certificate) bool {
178-
return bytes.Equal(cert.RawSubject, cert.RawIssuer)
179-
}
180218
rootPool := x509.NewCertPool()
181219
var intermediatePool *x509.CertPool // should be nil if no intermediate certs are found
182220
certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(rootOfTrust.RootCert))
@@ -196,28 +234,52 @@ func setRootOfTrustCosignOptions(cosignOptions *cosign.CheckOpts, rootOfTrust Ro
196234
cosignOptions.RootCerts = rootPool
197235
cosignOptions.IntermediateCerts = intermediatePool
198236
} else {
199-
cosignOptions.RootCerts, err = fulcio.GetRoots()
237+
targetCertificates, err := GetTargets(sigtuf.Fulcio, proxy)
238+
// certificates, err := GetPublicRootOfTrustFulcioCertificates(proxy)
200239
if err != nil {
201-
return fmt.Errorf("could not fetch default fulcio root certificate(s): %s", err.Error())
240+
return fmt.Errorf("could not retrieve public root of trust fulcio certificates: %s", err.Error())
202241
}
203-
cosignOptions.IntermediateCerts, err = fulcio.GetIntermediates()
204-
if err != nil {
205-
return fmt.Errorf("could not fetch default fulcio intermediate certificate(s): %s", err.Error())
242+
rootPool := x509.NewCertPool()
243+
var intermediatePool *x509.CertPool // should be nil if no intermediate certs are found
244+
for _, targetCertificate := range targetCertificates {
245+
certs, err := cryptoutils.UnmarshalCertificatesFromPEM(targetCertificate.Target)
246+
if err != nil {
247+
continue
248+
}
249+
for _, cert := range certs {
250+
if selfSigned(cert) {
251+
rootPool.AddCert(cert)
252+
} else {
253+
if intermediatePool == nil {
254+
intermediatePool = x509.NewCertPool()
255+
}
256+
intermediatePool.AddCert(cert)
257+
}
258+
}
206259
}
260+
cosignOptions.RootCerts = rootPool
261+
cosignOptions.IntermediateCerts = intermediatePool
207262
}
208-
// sct pub keys
209-
if rootOfTrust.SCTPublicKey != "" {
210-
sctPubKeyCollection := cosign.NewTrustedTransparencyLogPubKeys()
211-
if err := sctPubKeyCollection.AddTransparencyLogPubKey([]byte(rootOfTrust.SCTPublicKey), tuf.Active); err != nil {
212-
return fmt.Errorf("could not add custom sct public key to collection: %w", err)
263+
264+
// sct public keys
265+
sctKeyCollection := cosign.NewTrustedTransparencyLogPubKeys()
266+
if rootOfTrust.SCTPublicKey == "" {
267+
sctKeyTargets, err := GetTargets(sigtuf.CTFE, proxy)
268+
if err != nil {
269+
return fmt.Errorf("could not retrieve ctfe tuf targets: %s", err.Error())
270+
}
271+
for _, sctKeyTarget := range sctKeyTargets {
272+
if err := sctKeyCollection.AddTransparencyLogPubKey(sctKeyTarget.Target, sctKeyTarget.Status); err != nil {
273+
return fmt.Errorf("could not add public root of trust sct public key to collection: %w", err)
274+
}
213275
}
214-
cosignOptions.CTLogPubKeys = &sctPubKeyCollection
215276
} else {
216-
cosignOptions.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx)
217-
if err != nil {
218-
return fmt.Errorf("error retrieving default CT log public keys: %s", err.Error())
277+
if err := sctKeyCollection.AddTransparencyLogPubKey([]byte(rootOfTrust.SCTPublicKey), sigtuf.Active); err != nil {
278+
return fmt.Errorf("could not add custom root of trust sct public key to collection: %w", err)
219279
}
220280
}
281+
cosignOptions.CTLogPubKeys = &sctKeyCollection
282+
221283
return nil
222284
}
223285

0 commit comments

Comments
 (0)