From 43a7ce8639c998917cdc829ffdf71b3463e32d4e Mon Sep 17 00:00:00 2001 From: wangtiga Date: Tue, 3 Oct 2023 22:15:57 +0800 Subject: [PATCH 1/3] add export-pfx command, reference by https://github.com/square/certstrap/pull/52/files#top --- .gitignore | 3 +- README.md | 15 ++++++- certstrap.go | 3 +- cmd/export_pfx.go | 110 ++++++++++++++++++++++++++++++++++++++++++++++ depot/pkix.go | 37 +++++++++++++++- go.mod | 9 ++-- go.sum | 60 +++++++++++++++++++++---- 7 files changed, 221 insertions(+), 16 deletions(-) create mode 100644 cmd/export_pfx.go diff --git a/.gitignore b/.gitignore index 336d34b..2675c61 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ certstrap # Nice to have in .gitignore .idea/ # .DS_Store file sometimes generated by Mac computers -.DS_Store \ No newline at end of file +.DS_Store +*.swp diff --git a/README.md b/README.md index 339038f..9fcfd32 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,20 @@ Created out/Alice.crt from out/Alice.csr signed by out/CertAuth.key ``` #### PKCS Format: -If you'd like to convert your certificate and key to PKCS12 format, simply run: + +If you'd like to convert your certificate and key to PKCS12 format, + +simply run export-pfx: + +``` +$ certstrap export-pfx Alice --chain "Alice,CertAuth" + openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt -certfile ca.crt +``` +`Alice.key` and `Alice.crt` make up the leaf private key and certificate pair of your choosing (generated by a `sign` command), +with `CertAuth.crt` being the certificate authority certificate that was used to sign it. The output PKCS12 file is `Alice.pfx` + +or simply run openssl: + ``` $ openssl pkcs12 -export -out outputCert.p12 -inkey inputKey.key -in inputCert.crt -certfile CA.crt ``` diff --git a/certstrap.go b/certstrap.go index a8666af..ef5fe38 100644 --- a/certstrap.go +++ b/certstrap.go @@ -25,7 +25,7 @@ import ( "github.com/urfave/cli" ) -var release = "1.3.0" +var release = "1.3.0-pfx" func main() { app := cli.NewApp() @@ -47,6 +47,7 @@ func main() { cmd.NewCertRequestCommand(), cmd.NewSignCommand(), cmd.NewRevokeCommand(), + cmd.NewExportPfxCommand(), } app.Before = func(c *cli.Context) error { return cmd.InitDepot(c.String("depot-path")) diff --git a/cmd/export_pfx.go b/cmd/export_pfx.go new file mode 100644 index 0000000..5b2c5f3 --- /dev/null +++ b/cmd/export_pfx.go @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 2018 Marco Stolze (alias mcpride) + * + * 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 cmd + +import ( + "fmt" + "os" + "strings" + + //"github.com/codegangsta/cli" + //"github.com/mcpride/certstrap/depot" + //"github.com/mcpride/certstrap/pkix" + "github.com/square/certstrap/depot" + "github.com/square/certstrap/pkix" + "github.com/urfave/cli" +) + +// ExportPfxCommand sets up a "export-pfx" command to export certificate chain to personal information exchange format +func NewExportPfxCommand() cli.Command { + return cli.Command{ + Name: "export-pfx", + Usage: "Export certificate chain to personal information exchange format", + Description: "Export certificate chain for host to personal information exchange format, including root certificate and key.", + Flags: []cli.Flag{ + cli.StringFlag{Name: "passphrase", Value: "", Usage: "Passphrase to de- and encrypt private-key PEM block"}, + cli.StringFlag{Name: "chain", Value: "", Usage: "Names of chained parent certificates; comma delimited"}, + cli.BoolFlag{Name: "stdout", Usage: "Print signing request to stdout in addition to saving file"}, + }, + Action: exportPfxAction, + } +} + +func exportPfxAction(c *cli.Context) { + var err error + + if len(c.Args()) != 1 { + fmt.Fprintln(os.Stderr, "One name must be provided.") + os.Exit(1) + } + + formattedName := strings.Replace(c.Args()[0], " ", "_", -1) + + if depot.CheckPersonalInformationExchange(d, formattedName) { + fmt.Fprintln(os.Stderr, "PFX has existed!") + os.Exit(1) + } + + passphrase := []byte{} + + key, err := depot.GetPrivateKey(d, formattedName) + if err != nil { + passphrase, err = getPassPhrase(c, "Certificate key") + if err != nil { + fmt.Fprintln(os.Stderr, "Get certificate key error:", err) + os.Exit(1) + } + key, err = depot.GetEncryptedPrivateKey(d, formattedName, passphrase) + if err != nil { + fmt.Fprintln(os.Stderr, "Get certificate key error:", err) + os.Exit(1) + } + } + + cert, err := depot.GetCertificate(d, formattedName) + if err != nil { + fmt.Fprintln(os.Stderr, "Get certificate error:", err) + os.Exit(1) + } + + caCrts := []*pkix.Certificate{} + if c.IsSet("chain") { + var formattedCAName string + chain := strings.Split(c.String("chain"), ",") + for i := range chain { + formattedCAName = strings.Replace(chain[i], " ", "_", -1) + ca, err := depot.GetCertificate(d, formattedCAName) + if err != nil { + fmt.Fprintln(os.Stderr, "Get chained certificate error:", err) + os.Exit(1) + } + caCrts = append(caCrts, ca) + } + } + + pfxBytes, err := depot.PutPersonalInformationExchange(d, formattedName, cert, key, caCrts, passphrase) + if err != nil { + fmt.Fprintln(os.Stderr, "Export certificate chain to personal information exchange format failed:", err) + os.Exit(1) + } else { + fmt.Printf("Created %s/%s.pfx from %s/%s.crt and %s/%s.key\n", depotDir, formattedName, depotDir, formattedName, depotDir, formattedName) + } + + if c.Bool("stdout") { + fmt.Printf(string(pfxBytes[:])) + } +} diff --git a/depot/pkix.go b/depot/pkix.go index 8a90eb8..dc70aea 100644 --- a/depot/pkix.go +++ b/depot/pkix.go @@ -18,9 +18,12 @@ package depot import ( + "crypto/rand" + "crypto/x509" "strings" "github.com/square/certstrap/pkix" + "software.sslmate.com/src/go-pkcs12" ) const ( @@ -28,6 +31,7 @@ const ( csrSuffix = ".csr" privKeySuffix = ".key" crlSuffix = ".crl" + pfxSuffix = ".pfx" ) // CrtTag returns a tag corresponding to a certificate @@ -50,6 +54,11 @@ func CrlTag(prefix string) *Tag { return &Tag{prefix + crlSuffix, LeafPerm} } +// PfxTag returns a tag corresponding to a personal information exchange +func PfxTag(prefix string) *Tag { + return &Tag{prefix + pfxSuffix, LeafPerm} +} + // GetNameFromCrtTag returns the host name from a certificate file tag func GetNameFromCrtTag(tag *Tag) string { return getName(tag, crtSuffix) @@ -112,6 +121,11 @@ func CheckCertificateSigningRequest(d Depot, name string) bool { return d.Check(CsrTag(name)) } +// CheckPersonalInformationExchange checks the depot for existence of a pfx file for a given name +func CheckPersonalInformationExchange(d Depot, name string) bool { + return d.Check(PfxTag(name)) +} + // GetCertificateSigningRequest retrieves a certificate signing request file for a given host name from the depot func GetCertificateSigningRequest(d Depot, name string) (crt *pkix.CertificateSigningRequest, err error) { b, err := d.Get(CsrTag(name)) @@ -176,7 +190,28 @@ func PutCertificateRevocationList(d Depot, name string, crl *pkix.CertificateRev return d.Put(CrlTag(name), b) } -//GetCertificateRevocationList gets a CRL file for a given name and ca in the depot. +// PutPersonalInformationExchange creates a Personal Information Exchange certificate file for a given name in the depot +func PutPersonalInformationExchange(d Depot, name string, crt *pkix.Certificate, key *pkix.Key, caCrts []*pkix.Certificate, passphrase []byte) ([]byte, error) { + c, err := crt.GetRawCertificate() + if err != nil { + return nil, err + } + chain := []*x509.Certificate{} + for i := range caCrts { + cc, err := caCrts[i].GetRawCertificate() + if err != nil { + return nil, err + } + chain = append(chain, cc) + } + b, err := pkcs12.Encode(rand.Reader, key.Private, c, chain, string(passphrase)) + if err != nil { + return nil, err + } + return b, d.Put(PfxTag(name), b) +} + +// GetCertificateRevocationList gets a CRL file for a given name and ca in the depot. func GetCertificateRevocationList(d Depot, name string) (*pkix.CertificateRevocationList, error) { b, err := d.Get(CrlTag(name)) if err != nil { diff --git a/go.mod b/go.mod index 704432e..e798fce 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,8 @@ go 1.18 require ( github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c github.com/urfave/cli v1.22.13 - go.step.sm/crypto v0.25.1 + go.step.sm/crypto v0.16.2 + software.sslmate.com/src/go-pkcs12 v0.2.1 ) require ( @@ -13,7 +14,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - golang.org/x/crypto v0.6.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/term v0.5.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/term v0.10.0 // indirect ) diff --git a/go.sum b/go.sum index 2f183e3..5e00cd8 100644 --- a/go.sum +++ b/go.sum @@ -1,39 +1,83 @@ +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= +github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/urfave/cli v1.22.13 h1:wsLILXG8qCJNse/qAgLNf23737Cx05GflHg/PJGe1Ok= github.com/urfave/cli v1.22.13/go.mod h1:VufqObjsMTF2BBwKawpx9R8eAneNEWhoO0yx8Vd+FkE= -go.step.sm/crypto v0.25.1 h1:e08ioZBiZoHrWG0tJOUDPwqoF3PTRiFebINDEw3yPpo= -go.step.sm/crypto v0.25.1/go.mod h1:4pUEuZ+4OAf2f70RgW5oRv/rJudibcAAWQg5prC3DT8= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +go.step.sm/crypto v0.16.2 h1:Pr9aazTwWBBZNogUsOqhOrPSdwAa9pPs+lMB602lnDA= +go.step.sm/crypto v0.16.2/go.mod h1:1WkTOTY+fOX/RY4TnZREp6trQAsBHRQ7nu6QJBiNQF8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +software.sslmate.com/src/go-pkcs12 v0.2.1 h1:tbT1jjaeFOF230tzOIRJ6U5S1jNqpsSyNjzDd58H3J8= +software.sslmate.com/src/go-pkcs12 v0.2.1/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= From 997ec711b4b11f7a47c4a5aa152d389bc84becf7 Mon Sep 17 00:00:00 2001 From: wangtiga Date: Tue, 24 Oct 2023 22:47:28 +0800 Subject: [PATCH 2/3] tidy code --- README.md | 9 +++------ cmd/export_pfx.go | 11 +++++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9fcfd32..4b27be7 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,9 @@ Created out/Alice.crt from out/Alice.csr signed by out/CertAuth.key If you'd like to convert your certificate and key to PKCS12 format, -simply run export-pfx: - ``` -$ certstrap export-pfx Alice --chain "Alice,CertAuth" - openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt -certfile ca.crt +$ ./certstrap export-pfx Alice --chain "CertAuth" +Created out/Alice.pfx from out/Alice.crt and out/Alice.key with chain [out/CertAuth.crt] ``` `Alice.key` and `Alice.crt` make up the leaf private key and certificate pair of your choosing (generated by a `sign` command), with `CertAuth.crt` being the certificate authority certificate that was used to sign it. The output PKCS12 file is `Alice.pfx` @@ -96,9 +94,8 @@ with `CertAuth.crt` being the certificate authority certificate that was used to or simply run openssl: ``` -$ openssl pkcs12 -export -out outputCert.p12 -inkey inputKey.key -in inputCert.crt -certfile CA.crt +$ openssl pkcs12 -export -out out/Alice.pfx -inkey out/Alice.key -in out/Alice.crt -certfile out/CertAuth.crt ``` -`inputKey.key` and `inputCert.crt` make up the leaf private key and certificate pair of your choosing (generated by a `sign` command), with `CA.crt` being the certificate authority certificate that was used to sign it. The output PKCS12 file is `outputCert.p12` ### Key Algorithms: Certstrap supports curves P-224, P-256, P-384, P-521, and Ed25519. Curve names can be specified by name as part of the `init` and `request_cert` commands: diff --git a/cmd/export_pfx.go b/cmd/export_pfx.go index 5b2c5f3..5d129e5 100644 --- a/cmd/export_pfx.go +++ b/cmd/export_pfx.go @@ -21,9 +21,6 @@ import ( "os" "strings" - //"github.com/codegangsta/cli" - //"github.com/mcpride/certstrap/depot" - //"github.com/mcpride/certstrap/pkix" "github.com/square/certstrap/depot" "github.com/square/certstrap/pkix" "github.com/urfave/cli" @@ -82,6 +79,7 @@ func exportPfxAction(c *cli.Context) { } caCrts := []*pkix.Certificate{} + var formattedCANames []string = []string{} if c.IsSet("chain") { var formattedCAName string chain := strings.Split(c.String("chain"), ",") @@ -93,6 +91,7 @@ func exportPfxAction(c *cli.Context) { os.Exit(1) } caCrts = append(caCrts, ca) + formattedCANames = append(formattedCANames, fmt.Sprintf("%s/%s.crt", depotDir, formattedCAName)) } } @@ -101,7 +100,11 @@ func exportPfxAction(c *cli.Context) { fmt.Fprintln(os.Stderr, "Export certificate chain to personal information exchange format failed:", err) os.Exit(1) } else { - fmt.Printf("Created %s/%s.pfx from %s/%s.crt and %s/%s.key\n", depotDir, formattedName, depotDir, formattedName, depotDir, formattedName) + fmt.Printf("Created %s/%s.pfx from %s/%s.crt and %s/%s.key", depotDir, formattedName, depotDir, formattedName, depotDir, formattedName) + if len(formattedCANames) > 0 { + fmt.Printf(" with chain %s", formattedCANames) + } + fmt.Printf("\n") } if c.Bool("stdout") { From ffe2a7a9e235cc5c2fcc94fdef3f36e934c3b741 Mon Sep 17 00:00:00 2001 From: wangtiga Date: Wed, 25 Oct 2023 23:09:39 +0800 Subject: [PATCH 3/3] tidy code --- certstrap.go | 2 +- cmd/export_pfx.go | 3 ++- go.mod | 2 +- go.sum | 46 ++-------------------------------------------- 4 files changed, 6 insertions(+), 47 deletions(-) diff --git a/certstrap.go b/certstrap.go index ef5fe38..eeeefcb 100644 --- a/certstrap.go +++ b/certstrap.go @@ -25,7 +25,7 @@ import ( "github.com/urfave/cli" ) -var release = "1.3.0-pfx" +var release = "1.3.0" func main() { app := cli.NewApp() diff --git a/cmd/export_pfx.go b/cmd/export_pfx.go index 5d129e5..cb35b3e 100644 --- a/cmd/export_pfx.go +++ b/cmd/export_pfx.go @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2018 Marco Stolze (alias mcpride) + * Copyright 2015 Square Inc. + * Copyright 2014 CoreOS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/go.mod b/go.mod index e798fce..c039ddf 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c github.com/urfave/cli v1.22.13 - go.step.sm/crypto v0.16.2 + go.step.sm/crypto v0.25.1 software.sslmate.com/src/go-pkcs12 v0.2.1 ) diff --git a/go.sum b/go.sum index 5e00cd8..342a377 100644 --- a/go.sum +++ b/go.sum @@ -1,80 +1,38 @@ -filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c h1:kQWxfPIHVLbgLzphqk3QUflDy9QdksZR4ygR807bpy0= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/urfave/cli v1.22.13 h1:wsLILXG8qCJNse/qAgLNf23737Cx05GflHg/PJGe1Ok= github.com/urfave/cli v1.22.13/go.mod h1:VufqObjsMTF2BBwKawpx9R8eAneNEWhoO0yx8Vd+FkE= -go.step.sm/crypto v0.16.2 h1:Pr9aazTwWBBZNogUsOqhOrPSdwAa9pPs+lMB602lnDA= -go.step.sm/crypto v0.16.2/go.mod h1:1WkTOTY+fOX/RY4TnZREp6trQAsBHRQ7nu6QJBiNQF8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +go.step.sm/crypto v0.25.1 h1:e08ioZBiZoHrWG0tJOUDPwqoF3PTRiFebINDEw3yPpo= +go.step.sm/crypto v0.25.1/go.mod h1:4pUEuZ+4OAf2f70RgW5oRv/rJudibcAAWQg5prC3DT8= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=