diff --git a/docs/guides/templating.md b/docs/guides/templating.md index a08c9dd81..0b9441717 100644 --- a/docs/guides/templating.md +++ b/docs/guides/templating.md @@ -156,6 +156,8 @@ In addition to that you can use over 200+ [sprig functions](http://masterminds.g | pkcs12keyPass | Same as `pkcs12key`. Uses the provided password to decrypt the PKCS#12 archive. | | pkcs12cert | Extracts all certificates from a PKCS#12 archive and orders them if possible. If disjunct or multiple leaf certs are provided they are returned as-is.
Sort order: `leaf / intermediate(s) / root`. | | pkcs12certPass | Same as `pkcs12cert`. Uses the provided password to decrypt the PKCS#12 archive. | +| pemToPkcs12 | Takes a PEM encoded certificate and key and creates a base64 enoded PKCS#12 archive. | +| pemToPkcs12Pass | Same as `pemToPkcs12`. Uses the provided password to encrypt the PKCS#12 archive. | | filterPEM | Filters PEM blocks with a specific type from a list of PEM blocks. | | jwkPublicKeyPem | Takes an json-serialized JWK and returns an PEM block of type `PUBLIC KEY` that contains the public key. [See here](https://golang.org/pkg/crypto/x509/#MarshalPKIXPublicKey) for details. | | jwkPrivateKeyPem | Takes an json-serialized JWK as `string` and returns an PEM block of type `PRIVATE KEY` that contains the private key in PKCS #8 format. [See here](https://golang.org/pkg/crypto/x509/#MarshalPKCS8PrivateKey) for details. | diff --git a/e2e/go.mod b/e2e/go.mod index aec0b66c3..8ea056f02 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -68,7 +68,7 @@ require ( k8s.io/utils v0.0.0-20240102154912-e7106e64919e sigs.k8s.io/controller-runtime v0.17.2 sigs.k8s.io/yaml v1.4.0 - software.sslmate.com/src/go-pkcs12 v0.2.0 + software.sslmate.com/src/go-pkcs12 v0.4.0 ) require ( diff --git a/e2e/go.sum b/e2e/go.sum index f0b323317..c9c1b3eae 100644 --- a/e2e/go.sum +++ b/e2e/go.sum @@ -525,7 +525,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -957,5 +956,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+s sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= -software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/go.mod b/go.mod index 70abf719f..22ed901b8 100644 --- a/go.mod +++ b/go.mod @@ -86,6 +86,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/tidwall/sjson v1.2.5 sigs.k8s.io/yaml v1.4.0 + software.sslmate.com/src/go-pkcs12 v0.4.0 ) require ( diff --git a/go.sum b/go.sum index 772f8ecaa..17d95a10b 100644 --- a/go.sum +++ b/go.sum @@ -1340,3 +1340,5 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77Vzej sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= +software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/pkg/template/v2/pkcs12.go b/pkg/template/v2/pkcs12.go index 8dd9b5d8f..f0897ee8f 100644 --- a/pkg/template/v2/pkcs12.go +++ b/pkg/template/v2/pkcs12.go @@ -17,10 +17,12 @@ package template import ( "bytes" "crypto/x509" + "encoding/base64" "encoding/pem" "fmt" "golang.org/x/crypto/pkcs12" + gopkcs12 "software.sslmate.com/src/go-pkcs12" ) func pkcs12keyPass(pass, input string) (string, error) { @@ -108,3 +110,29 @@ func pkcs12certPass(pass, input string) (string, error) { func pkcs12cert(input string) (string, error) { return pkcs12certPass("", input) } + +func pemToPkcs12(cert, key string) (string, error) { + return pemToPkcs12Pass(cert, key, "") +} + +func pemToPkcs12Pass(cert, key, pass string) (string, error) { + certPem, _ := pem.Decode([]byte(cert)) + keyPem, _ := pem.Decode([]byte(key)) + + parsedCert, err := x509.ParseCertificate(certPem.Bytes) + if err != nil { + return "", err + } + + parsedKey, err := parsePrivateKey(keyPem.Bytes) + if err != nil { + return "", err + } + + pfx, err := gopkcs12.Modern.Encode(parsedKey, parsedCert, nil, pass) + if err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(pfx), nil +} diff --git a/pkg/template/v2/template.go b/pkg/template/v2/template.go index 8afd5f961..e7684e618 100644 --- a/pkg/template/v2/template.go +++ b/pkg/template/v2/template.go @@ -32,6 +32,9 @@ var tplFuncs = tpl.FuncMap{ "pkcs12cert": pkcs12cert, "pkcs12certPass": pkcs12certPass, + "pemToPkcs12": pemToPkcs12, + "pemToPkcs12Pass": pemToPkcs12Pass, + "filterPEM": filterPEM, "jwkPublicKeyPem": jwkPublicKeyPem,