Skip to content

Commit

Permalink
plumb through !cgo golang tags that removes pkcs11 support (#244)
Browse files Browse the repository at this point in the history
Signed-off-by: Ville Aikas <vaikas@chainguard.dev>
  • Loading branch information
vaikas committed Nov 24, 2021
1 parent 5134841 commit 48b5188
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 99 deletions.
4 changes: 4 additions & 0 deletions .ko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ builds:
- main: .
env:
- CGO_ENABLED=1
# If you are deploying from M1, you can use this (uncomment below, and
# comment out above), though it does remove the support for the "createca" command.
# But at least you can deploy it from M1 using this.
# - CGO_ENABLED=0
5 changes: 4 additions & 1 deletion cmd/app/createca.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build cgo
// +build cgo

// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -148,7 +151,7 @@ certificate authority for an instance of sigstore fulcio`,

func init() {
rootCmd.AddCommand(createcaCmd)
createcaCmd.PersistentFlags().String("org", "Fuclio Root CA", "Organization name for root CA")
createcaCmd.PersistentFlags().String("org", "Fulcio Root CA", "Organization name for root CA")
createcaCmd.PersistentFlags().String("country", "", "Country name for root CA")
createcaCmd.PersistentFlags().String("province", "", "Province name for root CA")
createcaCmd.PersistentFlags().String("locality", "", "Locality name for root CA")
Expand Down
5 changes: 4 additions & 1 deletion config/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Developing Fulcio

Fulcio uses Go and can be run with no other dependencies, other than a trust root PKIX / CA capable system. Currently
fulcio supports Google certificate authority service (GCP SA) or a PKCS11 capable HSM (such as SoftHSM).
fulcio supports Google certificate authority service (GCP SA) or a PKCS11 capable HSM (such as SoftHSM). PKCS11 support requires C libraries which can cause some issues in
some cases (like building on Mac M1), and if you do not require it, you can
disable support for it by specifying `CGO_ENABLED=0` when building. **NOTE**
This removes the support for `createca` command from the resulting binary.

## GCP SA configuration

Expand Down
118 changes: 118 additions & 0 deletions pkg/ca/x509ca/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package x509ca

import (
"context"
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"math/big"
"net/url"
"time"

"github.com/google/uuid"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/challenges"
)

type X509CA struct {
RootCA *x509.Certificate
PrivKey crypto.Signer
}

func (x *X509CA) CreateCertificate(_ context.Context, subject *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
return x.CreateCertificateWithCA(x, subject)
}

func (x *X509CA) CreateCertificateWithCA(certauth *X509CA, subject *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
// TODO: Track / increment serial nums instead, although unlikely we will create dupes, it could happen
uuid := uuid.New()
var serialNumber big.Int
serialNumber.SetBytes(uuid[:])

cert := &x509.Certificate{
SerialNumber: &serialNumber,
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Minute * 10),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
KeyUsage: x509.KeyUsageCertSign,
}
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}
}
cert.ExtraExtensions = append(IssuerExtension(subject.Issuer), AdditionalExtensions(subject)...)

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certauth.RootCA, subject.PublicKey, certauth.PrivKey)
if err != nil {
return nil, err
}

return ca.CreateCSCFromDER(subject, finalCertBytes, nil)
}

func AdditionalExtensions(subject *challenges.ChallengeResult) []pkix.Extension {
res := []pkix.Extension{}
if subject.TypeVal == challenges.GithubWorkflowValue {
if trigger, ok := subject.AdditionalInfo[challenges.GithubWorkflowTrigger]; ok {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2},
Value: []byte(trigger),
})
}

if sha, ok := subject.AdditionalInfo[challenges.GithubWorkflowSha]; ok {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3},
Value: []byte(sha),
})
}
}
return res
}

func IssuerExtension(issuer string) []pkix.Extension {
if issuer == "" {
return nil
}

return []pkix.Extension{{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1},
Value: []byte(issuer),
}}
}
100 changes: 3 additions & 97 deletions pkg/ca/x509ca/x509ca.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build cgo
// +build cgo

// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -16,32 +19,16 @@
package x509ca

import (
"context"
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"math/big"
"net/url"
"os"
"path/filepath"
"time"

"github.com/google/uuid"
"github.com/sigstore/fulcio/pkg/ca"
"github.com/sigstore/fulcio/pkg/challenges"
"github.com/sigstore/fulcio/pkg/pkcs11"
"github.com/spf13/viper"
)

type X509CA struct {
RootCA *x509.Certificate
PrivKey crypto.Signer
}

func NewX509CA() (*X509CA, error) {
ca := &X509CA{}
p11Ctx, err := pkcs11.InitHSMCtx()
Expand Down Expand Up @@ -83,84 +70,3 @@ func NewX509CA() (*X509CA, error) {
return ca, nil

}

func (x *X509CA) CreateCertificate(_ context.Context, subject *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
return x.CreateCertificateWithCA(x, subject)
}

func (x *X509CA) CreateCertificateWithCA(certauth *X509CA, subject *challenges.ChallengeResult) (*ca.CodeSigningCertificate, error) {
// TODO: Track / increment serial nums instead, although unlikely we will create dupes, it could happen
uuid := uuid.New()
var serialNumber big.Int
serialNumber.SetBytes(uuid[:])

cert := &x509.Certificate{
SerialNumber: &serialNumber,
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Minute * 10),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning},
KeyUsage: x509.KeyUsageCertSign,
}
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}
}
cert.ExtraExtensions = append(IssuerExtension(subject.Issuer), AdditionalExtensions(subject)...)

finalCertBytes, err := x509.CreateCertificate(rand.Reader, cert, certauth.RootCA, subject.PublicKey, certauth.PrivKey)
if err != nil {
return nil, err
}

return ca.CreateCSCFromDER(subject, finalCertBytes, nil)
}

func AdditionalExtensions(subject *challenges.ChallengeResult) []pkix.Extension {
res := []pkix.Extension{}
if subject.TypeVal == challenges.GithubWorkflowValue {
if trigger, ok := subject.AdditionalInfo[challenges.GithubWorkflowTrigger]; ok {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2},
Value: []byte(trigger),
})
}

if sha, ok := subject.AdditionalInfo[challenges.GithubWorkflowSha]; ok {
res = append(res, pkix.Extension{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3},
Value: []byte(sha),
})
}
}
return res
}

func IssuerExtension(issuer string) []pkix.Extension {
if issuer == "" {
return nil
}

return []pkix.Extension{{
Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1},
Value: []byte(issuer),
}}
}
29 changes: 29 additions & 0 deletions pkg/ca/x509ca/x509canocgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//go:build !cgo
// +build !cgo

// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package x509ca

import (
"errors"
)

// NewX509CA is a placeholder for erroring with a meaningful message if the
// binary has been built with purego tags.
func NewX509CA() (*X509CA, error) {
return nil, errors.New("binary has been built with no cgo support, PKCS11 not supported")
}
3 changes: 3 additions & 0 deletions pkg/pkcs11/pkcs11.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !purego
// +build !purego

// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
Expand Down

0 comments on commit 48b5188

Please sign in to comment.