Skip to content

Commit

Permalink
Pull in the new Fulcio client code. (#1126)
Browse files Browse the repository at this point in the history
Related to: sigstore/fulcio#262

Signed-off-by: Matt Moore <mattmoor@chainguard.dev>
  • Loading branch information
mattmoor committed Dec 7, 2021
1 parent dd53292 commit 9394f85
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 100 deletions.
77 changes: 17 additions & 60 deletions cmd/cosign/cli/fulcio/fulcio.go
Expand Up @@ -22,25 +22,17 @@ import (
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"net/url"
"os"

"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/go-openapi/strfmt"
"github.com/pkg/errors"
"golang.org/x/term"

"github.com/sigstore/cosign/cmd/cosign/cli/fulcio/fulcioroots"
clioptions "github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/pkg/cosign"
fulcPkgClient "github.com/sigstore/fulcio/pkg/client"
fulcioClient "github.com/sigstore/fulcio/pkg/generated/client"
"github.com/sigstore/fulcio/pkg/generated/client/operations"
"github.com/sigstore/fulcio/pkg/generated/models"
"github.com/sigstore/fulcio/pkg/api"
"github.com/sigstore/sigstore/pkg/oauthflow"
"github.com/sigstore/sigstore/pkg/signature"
)
Expand All @@ -51,12 +43,6 @@ const (
FlowToken = "token"
)

type Resp struct {
CertPEM []byte
ChainPEM []byte
SCT []byte
}

type oidcConnector interface {
OIDConnect(string, string, string) (*oauthflow.OIDCIDToken, error)
}
Expand All @@ -69,66 +55,37 @@ func (rf *realConnector) OIDConnect(url, clientID, secret string) (*oauthflow.OI
return oauthflow.OIDConnect(url, clientID, secret, rf.flow)
}

type signingCertProvider interface {
SigningCert(params *operations.SigningCertParams, authInfo runtime.ClientAuthInfoWriter, opts ...operations.ClientOption) (*operations.SigningCertCreated, error)
}

func getCertForOauthID(priv *ecdsa.PrivateKey, scp signingCertProvider, connector oidcConnector, oidcIssuer string, oidcClientID string) (Resp, error) {
func getCertForOauthID(priv *ecdsa.PrivateKey, fc api.Client, connector oidcConnector, oidcIssuer string, oidcClientID string) (*api.CertificateResponse, error) {
pubBytes, err := x509.MarshalPKIXPublicKey(&priv.PublicKey)
if err != nil {
return Resp{}, err
return nil, err
}

tok, err := connector.OIDConnect(oidcIssuer, oidcClientID, "")
if err != nil {
return Resp{}, err
return nil, err
}

// Sign the email address as part of the request
h := sha256.Sum256([]byte(tok.Subject))
proof, err := ecdsa.SignASN1(rand.Reader, priv, h[:])
if err != nil {
return Resp{}, err
return nil, err
}

bearerAuth := httptransport.BearerToken(tok.RawString)

content := strfmt.Base64(pubBytes)
signedChallenge := strfmt.Base64(proof)
params := operations.NewSigningCertParams()
params.SetCertificateRequest(
&models.CertificateRequest{
PublicKey: &models.CertificateRequestPublicKey{
Algorithm: models.CertificateRequestPublicKeyAlgorithmEcdsa,
Content: &content,
},
SignedEmailAddress: &signedChallenge,
cr := api.CertificateRequest{
PublicKey: api.Key{
Algorithm: "ecdsa",
Content: pubBytes,
},
)

resp, err := scp.SigningCert(params, bearerAuth)
if err != nil {
return Resp{}, err
}
sct, err := base64.StdEncoding.DecodeString(resp.SCT.String())
if err != nil {
return Resp{}, err
}

// split the cert and the chain
certBlock, chainPem := pem.Decode([]byte(resp.Payload))
certPem := pem.EncodeToMemory(certBlock)
fr := Resp{
CertPEM: certPem,
ChainPEM: chainPem,
SCT: sct,
SignedEmailAddress: proof,
}

return fr, nil
return fc.SigningCert(cr, tok.RawString)
}

// GetCert returns the PEM-encoded signature of the OIDC identity returned as part of an interactive oauth2 flow plus the PEM-encoded cert chain.
func GetCert(ctx context.Context, priv *ecdsa.PrivateKey, idToken, flow, oidcIssuer, oidcClientID string, fClient *fulcioClient.Fulcio) (Resp, error) {
func GetCert(ctx context.Context, priv *ecdsa.PrivateKey, idToken, flow, oidcIssuer, oidcClientID string, fClient api.Client) (*api.CertificateResponse, error) {
c := &realConnector{}
switch flow {
case FlowDevice:
Expand All @@ -139,10 +96,10 @@ func GetCert(ctx context.Context, priv *ecdsa.PrivateKey, idToken, flow, oidcIss
case FlowToken:
c.flow = &oauthflow.StaticTokenGetter{RawToken: idToken}
default:
return Resp{}, fmt.Errorf("unsupported oauth flow: %s", flow)
return nil, fmt.Errorf("unsupported oauth flow: %s", flow)
}

return getCertForOauthID(priv, fClient.Operations, c, oidcIssuer, oidcClientID)
return getCertForOauthID(priv, fClient, c, oidcIssuer, oidcClientID)
}

type Signer struct {
Expand All @@ -153,7 +110,7 @@ type Signer struct {
*signature.ECDSASignerVerifier
}

func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fClient *fulcioClient.Fulcio) (*Signer, error) {
func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fClient api.Client) (*Signer, error) {
priv, err := cosign.GeneratePrivateKey()
if err != nil {
return nil, errors.Wrap(err, "generating cert")
Expand Down Expand Up @@ -200,11 +157,11 @@ func GetRoots() *x509.CertPool {
return fulcioroots.Get()
}

func NewClient(fulcioURL string) (*fulcioClient.Fulcio, error) {
func NewClient(fulcioURL string) (api.Client, error) {
fulcioServer, err := url.Parse(fulcioURL)
if err != nil {
return nil, err
}
fClient := fulcPkgClient.New(fulcioServer, fulcPkgClient.WithUserAgent(clioptions.UserAgent()))
fClient := api.NewClient(fulcioServer, api.WithUserAgent(clioptions.UserAgent()))
return fClient, nil
}
65 changes: 31 additions & 34 deletions cmd/cosign/cli/fulcio/fulcio_test.go
Expand Up @@ -25,10 +25,8 @@ import (
"net/http/httptest"
"testing"

"github.com/go-openapi/runtime"

"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/fulcio/pkg/generated/client/operations"
"github.com/sigstore/fulcio/pkg/api"
"github.com/sigstore/sigstore/pkg/oauthflow"
)

Expand All @@ -45,15 +43,15 @@ func (tf *testFlow) OIDConnect(url, clientID, secret string) (*oauthflow.OIDCIDT
return tf.idt, nil
}

type testSigningCertProvider struct {
payload string
type testClient struct {
payload api.CertificateResponse
err error
}

func (p *testSigningCertProvider) SigningCert(params *operations.SigningCertParams, authInfo runtime.ClientAuthInfoWriter, opts ...operations.ClientOption) (*operations.SigningCertCreated, error) {
return &operations.SigningCertCreated{
Payload: p.payload,
}, p.err
var _ api.Client = (*testClient)(nil)

func (p *testClient) SigningCert(cr api.CertificateRequest, token string) (*api.CertificateResponse, error) {
return &p.payload, p.err
}

func TestGetCertForOauthID(t *testing.T) {
Expand All @@ -73,27 +71,23 @@ func TestGetCertForOauthID(t *testing.T) {
signingCertErr error

expectErr bool
}{
{
desc: "happy case",
email: "example@oidc.id",
accessToken: "abc123foobar",
},
{
desc: "getIDToken error",
email: "example@oidc.id",
accessToken: "abc123foobar",
tokenGetterErr: errors.New("getIDToken() failed"),
expectErr: true,
},
{
desc: "SigningCert error",
email: "example@oidc.id",
accessToken: "abc123foobar",
signingCertErr: errors.New("SigningCert() failed"),
expectErr: true,
},
}
}{{
desc: "happy case",
email: "example@oidc.id",
accessToken: "abc123foobar",
}, {
desc: "getIDToken error",
email: "example@oidc.id",
accessToken: "abc123foobar",
tokenGetterErr: errors.New("getIDToken() failed"),
expectErr: true,
}, {
desc: "SigningCert error",
email: "example@oidc.id",
accessToken: "abc123foobar",
signingCertErr: errors.New("SigningCert() failed"),
expectErr: true,
}}

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
Expand All @@ -103,9 +97,12 @@ func TestGetCertForOauthID(t *testing.T) {
}
expectedCertBytes := pem.EncodeToMemory(expectedCertPem)
expectedExtraBytes := []byte("0123456789abcdef")
tscp := &testSigningCertProvider{
payload: string(append(expectedCertBytes, expectedExtraBytes...)),
err: tc.signingCertErr,
tscp := &testClient{
payload: api.CertificateResponse{
CertPEM: expectedCertBytes,
ChainPEM: expectedExtraBytes,
},
err: tc.signingCertErr,
}

tf := testFlow{
Expand Down Expand Up @@ -165,7 +162,7 @@ func TestNewClient(t *testing.T) {
t.Error(err)
}

_, _ = client.Operations.SigningCert(nil, nil)
_, _ = client.SigningCert(api.CertificateRequest{}, "")

if !requestReceived {
t.Fatal("no requests were received")
Expand Down
4 changes: 2 additions & 2 deletions cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go
Expand Up @@ -31,7 +31,7 @@ import (
"github.com/sigstore/cosign/cmd/cosign/cli/fulcio"
"github.com/sigstore/cosign/pkg/cosign"
"github.com/sigstore/cosign/pkg/cosign/tuf"
fulcioClient "github.com/sigstore/fulcio/pkg/generated/client"
"github.com/sigstore/fulcio/pkg/api"
)

// This is the CT log public key target name
Expand Down Expand Up @@ -69,7 +69,7 @@ func verifySCT(certPEM, rawSCT []byte) error {
return ctutil.VerifySCT(pubKey, []*ctx509.Certificate{cert}, &sct, false)
}

func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fClient *fulcioClient.Fulcio) (*fulcio.Signer, error) {
func NewSigner(ctx context.Context, idToken, oidcIssuer, oidcClientID string, fClient api.Client) (*fulcio.Signer, error) {
fs, err := fulcio.NewSigner(ctx, idToken, oidcIssuer, oidcClientID, fClient)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/options/fulcio.go
Expand Up @@ -30,7 +30,7 @@ var _ Interface = (*FulcioOptions)(nil)

// AddFlags implements Interface
func (o *FulcioOptions) AddFlags(cmd *cobra.Command) {
// TODO: change this back to https://fulcio.sigstore.dev after the v1 migration is complete.
// TODO: change this back to api.SigstorePublicServerURL after the v1 migration is complete.
cmd.Flags().StringVar(&o.URL, "fulcio-url", "https://v1.fulcio.sigstore.dev",
"[EXPERIMENTAL] address of sigstore PKI server")

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -23,7 +23,7 @@ require (
github.com/open-policy-agent/opa v0.35.0
github.com/pkg/errors v0.9.1
github.com/secure-systems-lab/go-securesystemslib v0.2.0
github.com/sigstore/fulcio v0.1.2-0.20211204001059-48e1a254cf10
github.com/sigstore/fulcio v0.1.2-0.20211207184413-f4746cc4ff3d
github.com/sigstore/rekor v0.3.1-0.20211203233407-3278f72b78bd
github.com/sigstore/sigstore v1.0.2-0.20211203233310-c8e7f70eab4e
github.com/spf13/cobra v1.2.1
Expand Down
10 changes: 8 additions & 2 deletions go.sum
Expand Up @@ -209,8 +209,12 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/PaesslerAG/gval v1.0.0 h1:GEKnRwkWDdf9dOmKcNrar9EA1bz1z9DqPIO1+iLzhd8=
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I=
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8=
github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk=
github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
Expand Down Expand Up @@ -1645,11 +1649,13 @@ github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX
github.com/shibumi/go-pathspec v1.2.0 h1:KVKEDHYk7bQolRMs7nfzjT3SBOCgcXFJzccnj9bsGbA=
github.com/shibumi/go-pathspec v1.2.0/go.mod h1:bDxCftD0fST3qXIlHoQ/fChsU4mWMVklXp1yPErQaaY=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sigstore/fulcio v0.1.2-0.20211204001059-48e1a254cf10 h1:CbCE3pm2JWMTUgA6V6erGiFKtRsMFM/ZIj+cf5QpT+s=
github.com/sigstore/fulcio v0.1.2-0.20211204001059-48e1a254cf10/go.mod h1:skrBtMLaBrK3Awd0SnDvCSGbBB0l3+nNsBiUC6WOVbM=
github.com/sigstore/fulcio v0.1.2-0.20211207184413-f4746cc4ff3d h1:IPM24VE576hL6vCuZf4h+5WDDg07O9c26dlPi9IBZhI=
github.com/sigstore/fulcio v0.1.2-0.20211207184413-f4746cc4ff3d/go.mod h1:4MU8ZIe1hJz85JUaYi7v1kIxG3z9t1T6I8Ae4KFjPV4=
github.com/sigstore/rekor v0.3.1-0.20211203233407-3278f72b78bd h1:/Brk1DcfZDc69cDmWZPlHkwe5e3CK8j3BrfUKr6EO6c=
github.com/sigstore/rekor v0.3.1-0.20211203233407-3278f72b78bd/go.mod h1:X/YsXRguEJEDfYs2/vSw6zrq0fgFeML99KhZ6arCNaI=
github.com/sigstore/sigstore v0.0.0-20210729211320-56a91f560f44/go.mod h1:rJpRn7XmR/YrfNGDU9jh+vy5WMeSv5YKfNDBwnFg+Qg=
github.com/sigstore/sigstore v0.0.0-20210729211320-56a91f560f44/go.mod h1:rJpRn7XmR/YrfNGDU9jh+vy5WMeSv5YKfNDBwnFg+Qg=
github.com/sigstore/sigstore v1.0.1/go.mod h1:1+krIdtuf81/fLC8mHPt/7uwYiOg7W8k/PAR7lzKW3w=
github.com/sigstore/sigstore v1.0.1/go.mod h1:1+krIdtuf81/fLC8mHPt/7uwYiOg7W8k/PAR7lzKW3w=
github.com/sigstore/sigstore v1.0.2-0.20211203233310-c8e7f70eab4e h1:qxWCfYfujtV4ZlDasR4gkyxmyxmAjbHKhf4q94S/cvs=
github.com/sigstore/sigstore v1.0.2-0.20211203233310-c8e7f70eab4e/go.mod h1:F/4PzB9jSHWZSdBW3JsRmNQRp1MNGHXfSzNfG3Khm1Y=
Expand Down

0 comments on commit 9394f85

Please sign in to comment.