Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add entitlements support #314

Merged
merged 8 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ linters:
enable:
- asciicheck
- bodyclose
- depguard
- dogsled
- dupl
- errcheck
Expand Down Expand Up @@ -69,4 +68,5 @@ linters:
# - varcheck # deprecated (since v1.49.0) due to: The owner seems to have abandoned the linter. Replaced by unused.
# - deadcode # deprecated (since v1.49.0) due to: The owner seems to have abandoned the linter. Replaced by unused.
# - structcheck # deprecated (since v1.49.0) due to: The owner seems to have abandoned the linter. Replaced by unused.
# - rowserrcheck # we're not using sql.Rows at all in the codebase
# - rowserrcheck # we're not using sql.Rows at all in the codebase
# - depguard # this requires additional configuration https://github.com/golangci/golangci-lint/issues/3877#issuecomment-1573760321
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ GLOW_CMD = $(TEMP_DIR)/glow

# Tool versions #################################
QUILL_VERSION = latest
GOLANG_CI_VERSION = v1.52.2
GOLANG_CI_VERSION = v1.57.2
GOBOUNCER_VERSION = v0.4.0
GORELEASER_VERSION = v1.17.0
GOSIMPORTS_VERSION = v0.3.8
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func Describe(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

var err error
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/embedded_certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func EmbeddedCerts(app clio.Application) *cobra.Command {
Use: "embedded-certificates",
Short: "show the certificates embedded into quill (typically the Apple root and intermediate certs)",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

var err error
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/extract_certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func ExtractCertificates(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

certs, err := extractCertificates(opts.Path, opts.Leaf)
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/notarize.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func Notarize(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

// TODO: verify path is a signed darwin binary
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/p12_attach_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func P12AttachChain(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

newFilename, err := writeP12WithChain(opts.Path, opts.P12.Password, opts.Keychain.Path, true)
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/p12_describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func P12Describe(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

description, err := describeP12(opts.Path, opts.Password)
Expand Down
3 changes: 2 additions & 1 deletion cmd/quill/cli/commands/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Sign(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

return sign(opts.Path, opts.Signing)
Expand Down Expand Up @@ -72,6 +72,7 @@ func sign(binPath string, opts options.Signing) error {

cfg.WithIdentity(opts.Identity)
cfg.WithTimestampServer(opts.TimestampServer)
cfg.WithEntitlements(opts.Entitlements)

return quill.Sign(cfg)
}
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/sign_and_notarize.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func SignAndNotarize(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

err := sign(opts.Path, opts.Signing)
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/submission_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func SubmissionList(app clio.Application) *cobra.Command {
Use: "list",
Short: "list previous submissions to Apple's Notary service",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(_ *cobra.Command, _ []string) error {
defer bus.Exit()

log.Info("fetching previous submissions")
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/submission_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func SubmissionLogs(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, _ []string) error {
defer bus.Exit()

log.Infof("fetching submission logs for %q", opts.ID)
Expand Down
2 changes: 1 addition & 1 deletion cmd/quill/cli/commands/submission_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func SubmissionStatus(app clio.Application) *cobra.Command {
return nil
},
),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, _ []string) error {
defer bus.Exit()

log.Infof("checking submission status for %q", opts.ID)
Expand Down
9 changes: 8 additions & 1 deletion cmd/quill/cli/options/signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ type Signing struct {
FailWithoutFullChain bool `yaml:"fail-without-full-chain" json:"fail-without-full-chain" mapstructure:"fail-without-full-chain"`

// unbound options
Password string `yaml:"password" json:"password" mapstructure:"password"`
Password string `yaml:"password" json:"password" mapstructure:"password"`
Entitlements string `yaml:"entitlements" json:"entitlements" mapstructure:"entitlements"`
}

func DefaultSigning() Signing {
Expand Down Expand Up @@ -60,6 +61,12 @@ func (o *Signing) AddFlags(flags fangs.FlagSet) {
"ad-hoc", "",
"perform ad-hoc signing. No cryptographic signature is included and --p12 key and certificate input are not needed. Do NOT use this option for production builds.",
)

flags.StringVarP(
&o.Entitlements,
"entitlements", "",
"path to an XML file containing the entitlements for the binary being signed",
)
}

func (o *Signing) DescribeFields(d fangs.FieldDescriptionSet) {
Expand Down
5 changes: 3 additions & 2 deletions quill/extract/details.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ func (d Details) String(hideVerboseData bool) (r string) {
for idx, req := range d.SuperBlob.Requirements {
r += fmt.Sprintf("\nRequirements (block %d):\n", idx+1) + doIndent(req.String(), " ")
}
if d.SuperBlob.Entitlements != nil {
r += "\nEntitlements:\n" + doIndent(d.SuperBlob.Entitlements.String(), " ")
}
}

// TODO: add entitlements

return r
}

Expand Down
21 changes: 17 additions & 4 deletions quill/extract/entitlements.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
package extract

type EntitlementDetails struct {
Blob BlobDetails `json:"blob"`
Blob BlobDetails `json:"blob"`
Entitlements string `json:"entitlements,omitempty"`
EntitlementsDER []byte `json:"entitlements_der,omitempty"`
}

func getEntitlements(_ File) []EntitlementDetails {
// TODO
return nil
func getEntitlements(m File) *EntitlementDetails {
entitlements := m.blacktopFile.CodeSignature().Entitlements
entitlementsDER := m.blacktopFile.CodeSignature().EntitlementsDER
if entitlements == "" && entitlementsDER == nil {
return nil
}
return &EntitlementDetails{
Entitlements: entitlements,
EntitlementsDER: entitlementsDER,
}
}

func (e EntitlementDetails) String() string {
return e.Entitlements
}
2 changes: 1 addition & 1 deletion quill/extract/super_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ type SuperBlobDetails struct {
Size uint32 `json:"size"`
CodeDirectories []CodeDirectoryDetails `json:"codeDirectories"`
Requirements []RequirementDetails `json:"requirements"`
Entitlements []EntitlementDetails `json:"entitlements"`
Entitlements *EntitlementDetails `json:"entitlements"`
Signatures []SignatureDetails `json:"signatures"`
}

Expand Down
2 changes: 1 addition & 1 deletion quill/pki/apple/internal/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func extractCertLinks(selection *goquery.Selection, u string) []Link {
baseURL := parsedURL.Scheme + "://" + parsedURL.Host

// Find all <tr> elements in the selection
selection.Find("li").Each(func(i int, row *goquery.Selection) {
selection.Find("li").Each(func(_ int, row *goquery.Selection) {
// Find the <a> element in the first <td> in the row
link := row.Find("a")

Expand Down
20 changes: 18 additions & 2 deletions quill/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type SigningConfig struct {
SigningMaterial pki.SigningMaterial
Identity string
Path string
Entitlements string
}

func NewSigningConfigFromPEMs(binaryPath, certificate, privateKey, password string, failWithoutFullChain bool) (*SigningConfig, error) {
Expand Down Expand Up @@ -66,6 +67,11 @@ func (c *SigningConfig) WithTimestampServer(url string) *SigningConfig {
return c
}

func (c *SigningConfig) WithEntitlements(path string) *SigningConfig {
c.Entitlements = path
return c
}

func Sign(cfg SigningConfig) error {
f, err := os.Open(cfg.Path)
if err != nil {
Expand Down Expand Up @@ -212,14 +218,24 @@ func signSingleBinary(cfg SigningConfig) error {
log.Warnf("only ad-hoc signing, which means that anyone can alter the binary contents without you knowing (there is no cryptographic signature)")
}

entitlementsXML := ""
if cfg.Entitlements != "" {
log.Infof("Loading entitlements from %s", cfg.Entitlements)
data, err := os.ReadFile(cfg.Entitlements)
if err != nil {
return err
}
entitlementsXML = string(data)
}

// (patch) add empty LcCodeSignature loader (offset and size references are not set)
if err = m.AddEmptyCodeSigningCmd(); err != nil {
return err
}

// first pass: add the signed data with the dummy loader
log.Debugf("estimating signing material size")
superBlobSize, sbBytes, err := sign.GenerateSigningSuperBlob(cfg.Identity, m, cfg.SigningMaterial, 0)
superBlobSize, sbBytes, err := sign.GenerateSigningSuperBlob(cfg.Identity, m, cfg.SigningMaterial, entitlementsXML, 0)
if err != nil {
return fmt.Errorf("failed to add signing data on pass=1: %w", err)
}
Expand All @@ -232,7 +248,7 @@ func signSingleBinary(cfg SigningConfig) error {

// second pass: now that all of the sizing is right, let's do it again with the final contents (replacing the hashes and signature)
log.Debug("creating signature for binary")
_, sbBytes, err = sign.GenerateSigningSuperBlob(cfg.Identity, m, cfg.SigningMaterial, superBlobSize)
_, sbBytes, err = sign.GenerateSigningSuperBlob(cfg.Identity, m, cfg.SigningMaterial, entitlementsXML, superBlobSize)
if err != nil {
return fmt.Errorf("failed to add signing data on pass=2: %w", err)
}
Expand Down
Loading
Loading