implement mdmctl apply app -sign-identity (#785)

* implement mdmctl apply app -sign-identity

* update go-cpio-odc for macOS compatibility

* update go-cpio-odc for windows compatibility

* update go-cpio-odc to satisfy builder
This commit is contained in:
Kory Prince
2022-04-14 12:09:47 -05:00
committed by GitHub
parent 2f3293cf8c
commit 5495df8c15
5 changed files with 105 additions and 19 deletions

View File

@@ -25,13 +25,16 @@ func (cmd *applyCommand) applyApp(args []string) error {
flagset := flag.NewFlagSet("app", flag.ExitOnError)
var (
flPkgPath = flagset.String("pkg", "", "path to a distribution pkg.")
flOutputPath = flagset.String("out", "", "pkg output path for -sign and -sign-identity (optional, defaults to OS temporary directory)")
flPkgURL = flagset.String("pkg-url", "", "use custom pkg url")
flAppManifest = flagset.String("manifest", "-", `path to an app manifest. optional,
will be created if file does not exist.`)
flHashSize = flagset.Int64("md5size", appmanifest.DefaultMD5Size, "md5 hash size in bytes (optional)")
flSign = flagset.String("sign", "", "sign package before importing, requires specifying a product ID (optional)")
flUpload = flagset.Bool("upload", false, "upload package and/or manifest to micromdm repository.")
flHashSize = flagset.Int64("md5size", appmanifest.DefaultMD5Size, "md5 hash size in bytes (optional)")
flSign = flagset.String("sign", "", "sign package before importing, requires specifying id of developer identity in keychain (optional, macOS only)")
flSignIdentity = flagset.String("sign-identity", "", "sign package before importing, requires specifying path to .p12 developer identity (optional)")
flIdentityPass = flagset.String("password", "", "password used for -sign-identity (optional)")
flUpload = flagset.Bool("upload", false, "upload package and/or manifest to micromdm repository.")
)
flagset.Usage = usageFor(flagset, "mdmctl apply app [flags]")
if err := flagset.Parse(args); err != nil {
@@ -70,13 +73,27 @@ Please rebuild the package and re-run the command.
}
if !signed {
if *flSign == "" {
if *flSign == "" && *flSignIdentity == "" {
flagset.Usage()
return errors.New(`MDM packages must be signed. Provide signed package or Developer ID with -sign flag`)
return errors.New(`MDM packages must be signed. Provide signed package or -sign or -sign-identity flags`)
}
outpath := filepath.Join(os.TempDir(), filepath.Base(*flPkgPath))
if err := signPackage(*flPkgPath, outpath, *flSign); err != nil {
return err
outpath := *flOutputPath
if outpath == "" {
outpath = filepath.Join(os.TempDir(), filepath.Base(*flPkgPath))
}
if outpath == *flPkgPath {
return errors.New("-out can't be the same as -pkg")
}
if *flSign != "" {
if err := signPackage(*flPkgPath, outpath, *flSign); err != nil {
return err
}
} else {
if err := signPackageWithIdentity(*flPkgPath, outpath, *flSignIdentity, *flIdentityPass); err != nil {
return err
}
}
pkg = outpath // use signed package to create the manifest
}

View File

@@ -3,14 +3,31 @@
package main
import "fmt"
import (
"fmt"
"os"
goerrors "errors"
macospkg "github.com/korylprince/go-macos-pkg"
"github.com/pkg/errors"
)
func signPackage(path, outpath, developerID string) error {
fmt.Println("[WARNING] package signing only implemented on macOS")
fmt.Println("[WARNING] package signing with -sign only implemented on macOS. Use -sign-identity instead")
return nil
}
func checkSignature(pkgpath string) (bool, error) {
fmt.Println("[WARNING] package signing only implemented on macOS. An unsigned macOS package will not install with MDM.")
buf, err := os.ReadFile(pkgpath)
if err != nil {
return false, errors.Wrap(err, "reading package")
}
if err = macospkg.VerifyPkg(buf); err != nil {
if goerrors.Is(err, macospkg.ErrNotSigned) {
return false, nil
}
return false, errors.Wrap(err, "verifying package")
}
return true, nil
}

View File

@@ -0,0 +1,36 @@
package main
import (
"crypto/rsa"
"os"
macospkg "github.com/korylprince/go-macos-pkg"
"github.com/pkg/errors"
"golang.org/x/crypto/pkcs12"
)
func signPackageWithIdentity(pkgpath, outpath, identitypath, identitypass string) error {
identity, err := os.ReadFile(identitypath)
if err != nil {
return errors.Wrap(err, "reading identity")
}
key, cert, err := pkcs12.Decode(identity, identitypass)
if err != nil {
return errors.Wrap(err, "decoding identity")
}
pkg, err := os.ReadFile(pkgpath)
if err != nil {
return errors.Wrap(err, "reading package")
}
signed, err := macospkg.SignPkg(pkg, cert, key.(*rsa.PrivateKey))
if err != nil {
return errors.Wrap(err, "signing package")
}
if err = os.WriteFile(outpath, signed, 0644); err != nil {
return errors.Wrap(err, "writing signed package")
}
return nil
}

9
go.mod
View File

@@ -12,14 +12,15 @@ require (
github.com/groob/plist v0.0.0-20220217120414-63fa881b19a5
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0
github.com/kolide/kit v0.0.0-20180912215818-0c28f72eb2b0
github.com/korylprince/go-macos-pkg v1.3.5
github.com/lib/pq v1.0.0
github.com/micromdm/go4 v0.0.0-20210104222236-8a0936d9e451
github.com/micromdm/scep/v2 v2.1.0
github.com/pkg/errors v0.8.0
github.com/pressly/goose v2.3.0+incompatible
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20201021035429-f5854403a974
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
google.golang.org/protobuf v1.27.1
gopkg.in/Masterminds/squirrel.v1 v1.0.0-20170825200431-a6b93000bd21
)
@@ -31,6 +32,8 @@ require (
github.com/go-sql-driver/mysql v1.4.0 // indirect
github.com/go-stack/stack v1.7.0 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/korylprince/go-cpio-odc v0.9.4 // indirect
github.com/korylprince/goxar v0.0.0-20211111233330-e9f257bcdf25 // indirect
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
@@ -38,7 +41,7 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2 // indirect
github.com/ziutek/mymysql v1.5.4 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
golang.org/x/text v0.3.3 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.2.0 // indirect

23
go.sum
View File

@@ -44,6 +44,16 @@ github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0 h1:5B0uxl2lzNRVkJVg+u
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
github.com/kolide/kit v0.0.0-20180912215818-0c28f72eb2b0 h1:8UB0NJBoB/lN2O9zG9+U2klyYE0UhvN2Zrn7HBjhwNY=
github.com/kolide/kit v0.0.0-20180912215818-0c28f72eb2b0/go.mod h1:N3Yv8okDVC/5qZhPA9uxVYRfkp4mD2vrlQiSCWlNCpg=
github.com/korylprince/go-cpio-odc v0.9.3 h1:MGpo1PcJN2ajysEoAhF34zR/Peevo4N+T+OmhDLIUvk=
github.com/korylprince/go-cpio-odc v0.9.3/go.mod h1:1iHsjUXO64Hui0YsubGp0Tm/Uf04Iow2iy+1LJIarMw=
github.com/korylprince/go-cpio-odc v0.9.4 h1:N0Afrp7Z5qCZF8cbpzF5CvyiC/KHK5IcLJwqm5MWpNU=
github.com/korylprince/go-cpio-odc v0.9.4/go.mod h1:1iHsjUXO64Hui0YsubGp0Tm/Uf04Iow2iy+1LJIarMw=
github.com/korylprince/go-macos-pkg v1.3.4 h1:6McQ9bj3p/k/FeqFBHhdvXVvi+ftNcWXj4EWAEuEiz0=
github.com/korylprince/go-macos-pkg v1.3.4/go.mod h1:eLXotCZDK3vBt6AfDg62Fl20lCjrIm5e8V/8Q9YLHIo=
github.com/korylprince/go-macos-pkg v1.3.5 h1:jwwefLR1yRKQPNu51QTwk2B4abIjjISj/BHipcvKKGs=
github.com/korylprince/go-macos-pkg v1.3.5/go.mod h1:jlPGliXXjjCMpISR30/fL60hXKrCJ2LNQSptdx+WQkc=
github.com/korylprince/goxar v0.0.0-20211111233330-e9f257bcdf25 h1:XVf+U+WekiGPPD27w7qI+0Pe8NehaTWPqRuO3BddefY=
github.com/korylprince/goxar v0.0.0-20211111233330-e9f257bcdf25/go.mod h1:Lm6kfGMVHcpiBP6oOZd3ugv2EpQ/dOyW02tVIa3qo2Q=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
@@ -72,18 +82,21 @@ go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvS
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20170726083632-f5079bd7f6f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20170728174421-0f826bdd13b5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=