Skip to content

Commit

Permalink
Use principal in CA abstraction (#570)
Browse files Browse the repository at this point in the history
Modifies the CA abstraction to consume identity.Principal instead of
challenges.ChallengeResult. Also implements the indentity.Principal
methods for ChallengeResult.

Signed-off-by: Nathan Smith <[email protected]>
  • Loading branch information
nsmith5 authored May 12, 2022
1 parent 8d307b5 commit abfea57
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 310 deletions.
4 changes: 2 additions & 2 deletions pkg/api/grpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (g *grpcCAServer) CreateSigningCertificate(ctx context.Context, request *fu
// For CAs that do not support embedded SCTs or if the CT log is not configured
if sctCa, ok := g.ca.(certauth.EmbeddedSCTCA); !ok || g.ct == nil {
// currently configured CA doesn't support pre-certificate flow required to embed SCT in final certificate
csc, err = g.ca.CreateCertificate(ctx, subject)
csc, err = g.ca.CreateCertificate(ctx, subject, publicKey)
if err != nil {
// if the error was due to invalid input in the request, return HTTP 400
if _, ok := err.(certauth.ValidationError); ok {
Expand Down Expand Up @@ -165,7 +165,7 @@ func (g *grpcCAServer) CreateSigningCertificate(ctx context.Context, request *fu
result.GetSignedCertificateDetachedSct().SignedCertificateTimestamp = sctBytes
}
} else {
precert, err := sctCa.CreatePrecertificate(ctx, subject)
precert, err := sctCa.CreatePrecertificate(ctx, subject, publicKey)
if err != nil {
// if the error was due to invalid input in the request, return HTTP 400
if _, ok := err.(certauth.ValidationError); ok {
Expand Down
5 changes: 3 additions & 2 deletions pkg/api/grpc_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package api

import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
Expand All @@ -42,9 +43,9 @@ import (
"github.com/google/certificate-transparency-go/jsonclient"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/ca/ephemeralca"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/config"
"github.com/sigstore/fulcio/pkg/generated/protobuf"
"github.com/sigstore/fulcio/pkg/identity"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -1250,7 +1251,7 @@ func verifyResponse(resp *protobuf.SigningCertificate, eca *ephemeralca.Ephemera
type FailingCertificateAuthority struct {
}

func (fca *FailingCertificateAuthority) CreateCertificate(ctx context.Context, challenge *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
func (fca *FailingCertificateAuthority) CreateCertificate(context.Context, identity.Principal, crypto.PublicKey) (*ca.CodeSigningCertificate, error) {
return nil, errors.New("CreateCertificate always fails for testing")
}
func (fca *FailingCertificateAuthority) Root(ctx context.Context) ([]byte, error) {
Expand Down
5 changes: 3 additions & 2 deletions pkg/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ package ca

import (
"context"
"crypto"

"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/identity"
)

// CertificateAuthority implements certificate creation with a detached SCT and
// fetching the CA trust bundle.
type CertificateAuthority interface {
CreateCertificate(ctx context.Context, challenge *challenges.ChallengeResult) (*CodeSigningCertificate, error)
CreateCertificate(context.Context, identity.Principal, crypto.PublicKey) (*CodeSigningCertificate, error)
Root(ctx context.Context) ([]byte, error)
}
5 changes: 3 additions & 2 deletions pkg/ca/embeddedca.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ package ca

import (
"context"
"crypto"

ct "github.com/google/certificate-transparency-go"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/identity"
)

// EmbeddedSCTCA implements precertificate and certificate issuance. Certificates will contain an embedded SCT.
type EmbeddedSCTCA interface {
CreatePrecertificate(ctx context.Context, challenge *challenges.ChallengeResult) (*CodeSigningPreCertificate, error)
CreatePrecertificate(context.Context, identity.Principal, crypto.PublicKey) (*CodeSigningPreCertificate, error)
IssueFinalCertificate(ctx context.Context, precert *CodeSigningPreCertificate, sct *ct.SignedCertificateTimestamp) (*CodeSigningCertificate, error)
}
9 changes: 5 additions & 4 deletions pkg/ca/googleca/v1/googleca.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package v1

import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
Expand All @@ -30,7 +31,7 @@ import (
privateca "cloud.google.com/go/security/privateca/apiv1"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/ca/x509ca"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/identity"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"google.golang.org/api/iterator"
privatecapb "google.golang.org/genproto/googleapis/cloud/security/privateca/v1"
Expand Down Expand Up @@ -160,13 +161,13 @@ func (c *CertAuthorityService) Root(ctx context.Context) ([]byte, error) {
return c.cachedRoots, nil
}

func (c *CertAuthorityService) CreateCertificate(ctx context.Context, subj *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
cert, err := x509ca.MakeX509(subj)
func (c *CertAuthorityService) CreateCertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningCertificate, error) {
cert, err := x509ca.MakeX509(ctx, principal, publicKey)
if err != nil {
return nil, ca.ValidationError(err)
}

pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(subj.PublicKey)
pubKeyBytes, err := cryptoutils.MarshalPublicKeyToPEM(publicKey)
if err != nil {
return nil, ca.ValidationError(err)
}
Expand Down
14 changes: 7 additions & 7 deletions pkg/ca/intermediateca/intermediateca.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
ctx509 "github.com/google/certificate-transparency-go/x509"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/ca/x509ca"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/identity"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

Expand All @@ -49,8 +49,8 @@ type IntermediateCA struct {
Signer crypto.Signer
}

func (ica *IntermediateCA) CreatePrecertificate(ctx context.Context, challenge *challenges.ChallengeResult) (*ca.CodeSigningPreCertificate, error) {
cert, err := x509ca.MakeX509(challenge)
func (ica *IntermediateCA) CreatePrecertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningPreCertificate, error) {
cert, err := x509ca.MakeX509(ctx, principal, publicKey)
if err != nil {
return nil, err
}
Expand All @@ -64,7 +64,7 @@ func (ica *IntermediateCA) CreatePrecertificate(ctx context.Context, challenge *
Value: asn1.NullBytes,
})

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], challenge.PublicKey, privateKey)
finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -130,15 +130,15 @@ func (ica *IntermediateCA) IssueFinalCertificate(ctx context.Context, precert *c
return ca.CreateCSCFromDER(finalCertBytes, precert.CertChain)
}

func (ica *IntermediateCA) CreateCertificate(ctx context.Context, challenge *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
cert, err := x509ca.MakeX509(challenge)
func (ica *IntermediateCA) CreateCertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningCertificate, error) {
cert, err := x509ca.MakeX509(ctx, principal, publicKey)
if err != nil {
return nil, err
}

certChain, privateKey := ica.getX509KeyPair()

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], challenge.PublicKey, privateKey)
finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certChain[0], publicKey, privateKey)
if err != nil {
return nil, err
}
Expand Down
9 changes: 4 additions & 5 deletions pkg/ca/intermediateca/intermediateca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,10 @@ func TestCreatePrecertificateAndIssueFinalCertificate(t *testing.T) {

ica := IntermediateCA{Certs: certChain, Signer: subKey}
precsc, err := ica.CreatePrecertificate(context.TODO(), &challenges.ChallengeResult{
Issuer: "iss",
TypeVal: challenges.EmailValue,
Value: "[email protected]",
PublicKey: priv.Public(),
})
Issuer: "iss",
TypeVal: challenges.EmailValue,
Value: "[email protected]",
}, priv.Public())

if err != nil {
t.Fatalf("error generating precertificate: %v", err)
Expand Down
76 changes: 8 additions & 68 deletions pkg/ca/x509ca/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ import (
"crypto/rand"
"crypto/x509"
"encoding/pem"
"net/url"
"time"

"github.com/pkg/errors"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/identity"
"github.com/sigstore/sigstore/pkg/cryptoutils"
)

Expand All @@ -35,13 +33,13 @@ type X509CA struct {
PrivKey crypto.Signer
}

func MakeX509(subject *challenges.ChallengeResult) (*x509.Certificate, error) {
func MakeX509(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*x509.Certificate, error) {
serialNumber, err := cryptoutils.GenerateSerialNumber()
if err != nil {
return nil, err
}

skid, err := cryptoutils.SKID(subject.PublicKey)
skid, err := cryptoutils.SKID(publicKey)
if err != nil {
return nil, err
}
Expand All @@ -55,67 +53,9 @@ func MakeX509(subject *challenges.ChallengeResult) (*x509.Certificate, error) {
KeyUsage: x509.KeyUsageDigitalSignature,
}

switch subject.TypeVal {
case challenges.EmailValue:
cert.EmailAddresses = []string{subject.Value}
case challenges.SpiffeValue:
challengeURL, err := url.Parse(subject.Value)
if err != nil {
return nil, ca.ValidationError(err)
}
cert.URIs = []*url.URL{challengeURL}
case challenges.GithubWorkflowValue:
jobWorkflowURI, err := url.Parse(subject.Value)
if err != nil {
return nil, ca.ValidationError(err)
}
cert.URIs = []*url.URL{jobWorkflowURI}
case challenges.KubernetesValue:
k8sURI, err := url.Parse(subject.Value)
if err != nil {
return nil, ca.ValidationError(err)
}
cert.URIs = []*url.URL{k8sURI}
case challenges.URIValue:
subjectURI, err := url.Parse(subject.Value)
if err != nil {
return nil, ca.ValidationError(err)
}
cert.URIs = []*url.URL{subjectURI}
case challenges.UsernameValue:
cert.EmailAddresses = []string{subject.Value}
}

exts := Extensions{
Issuer: subject.Issuer,
}
if subject.TypeVal == challenges.GithubWorkflowValue {
var ok bool
exts.GithubWorkflowTrigger, ok = subject.AdditionalInfo[challenges.GithubWorkflowTrigger]
if !ok {
return nil, errors.New("x509ca: github workflow missing trigger claim")
}
exts.GithubWorkflowSHA, ok = subject.AdditionalInfo[challenges.GithubWorkflowSha]
if !ok {
return nil, errors.New("x509ca: github workflow missing SHA claim")
}
exts.GithubWorkflowName, ok = subject.AdditionalInfo[challenges.GithubWorkflowName]
if !ok {
return nil, errors.New("x509ca: github workflow missing workflow name claim")
}
exts.GithubWorkflowRepository, ok = subject.AdditionalInfo[challenges.GithubWorkflowRepository]
if !ok {
return nil, errors.New("x509ca: github workflow missing repository claim")
}
exts.GithubWorkflowRef, ok = subject.AdditionalInfo[challenges.GithubWorkflowRef]
if !ok {
return nil, errors.New("x509ca: github workflow missing ref claim")
}
}

cert.ExtraExtensions, err = exts.Render()
err = principal.Embed(ctx, cert)
if err != nil {
return nil, err
return nil, ca.ValidationError(err)
}

return cert, nil
Expand All @@ -128,13 +68,13 @@ func (x *X509CA) Root(ctx context.Context) ([]byte, error) {
}), nil
}

func (x *X509CA) CreateCertificate(_ context.Context, subject *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
cert, err := MakeX509(subject)
func (x *X509CA) CreateCertificate(ctx context.Context, principal identity.Principal, publicKey crypto.PublicKey) (*ca.CodeSigningCertificate, error) {
cert, err := MakeX509(ctx, principal, publicKey)
if err != nil {
return nil, err
}

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, x.RootCA, subject.PublicKey, x.PrivKey)
finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, x.RootCA, publicKey, x.PrivKey)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit abfea57

Please sign in to comment.