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 PKCS12 archive bundle to self-signed certificate resource #69

Closed
wants to merge 5 commits into from
Closed
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
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ go 1.14
require (
github.com/hashicorp/terraform-plugin-sdk v1.14.0
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
software.sslmate.com/src/go-pkcs12 v0.0.0-20200619203921-c9ed90bd32dc
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,5 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
software.sslmate.com/src/go-pkcs12 v0.0.0-20200619203921-c9ed90bd32dc h1:EsxyX6d5CU9zIK74f0y5OeDRFoQalEMHz1Jdvo4K16g=
software.sslmate.com/src/go-pkcs12 v0.0.0-20200619203921-c9ed90bd32dc/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
35 changes: 35 additions & 0 deletions tls/resource_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,25 @@ func resourceCertificateCommonSchema() map[string]*schema.Schema {
Description: "If true, the generated certificate will include a subject key identifier.",
ForceNew: true,
},

"certificate_p12": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
},

"certificate_p12_password": {
Type: schema.TypeString,
Optional: true,
Default: "",
Sensitive: true,
},
}
}

func createCertificate(d *schema.ResourceData, template, parent *x509.Certificate, pub crypto.PublicKey, priv interface{}) error {
var err error
var caCerts []*x509.Certificate

template.NotBefore = now()
template.NotAfter = template.NotBefore.Add(time.Duration(d.Get("validity_period_hours").(int)) * time.Hour)
Expand Down Expand Up @@ -185,6 +199,27 @@ func createCertificate(d *schema.ResourceData, template, parent *x509.Certificat
}
certPem := string(pem.EncodeToMemory(&pem.Block{Type: pemCertType, Bytes: certBytes}))

private_key, err := parsePrivateKey(d, "private_key_pem", "key_algorithm")
// Set PKCS12 data. This is only set if there is a private key present.
if err != nil {
vadimkuznetsov marked this conversation as resolved.
Show resolved Hide resolved
d.Set("certificate_p12", "")
} else {
cert, err := x509.ParseCertificate(certBytes)
if err != nil {
return fmt.Errorf("certificate parse error: %s", err)
}

// caCerts = append(caCerts, parent)

password := d.Get("certificate_p12_password").(string)
pkcs12B64, err := toPkcs12(private_key, cert, caCerts, password)
if err != nil {
return fmt.Errorf("to pfx error: %s", err)
}

d.Set("certificate_p12", string(pkcs12B64))
}

validFromBytes, err := template.NotBefore.MarshalText()
if err != nil {
return fmt.Errorf("error serializing validity_start_time: %s", err)
Expand Down
15 changes: 15 additions & 0 deletions tls/util.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package tls

import (
"crypto/rand"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"golang.org/x/crypto/ssh"
"software.sslmate.com/src/go-pkcs12"
)

func decodePEM(d *schema.ResourceData, pemKey, pemType string) (*pem.Block, error) {
Expand Down Expand Up @@ -103,3 +106,15 @@ func readPublicKey(d *schema.ResourceData, rsaKey interface{}) error {
}
return nil
}

func toPkcs12(privateKey interface{}, cert *x509.Certificate, caCerts []*x509.Certificate, password string) ([]byte, error) {

pkcs12Data, err := pkcs12.Encode(rand.Reader, privateKey, cert, caCerts, password)
if err != nil {
return nil, err
}

buf := make([]byte, base64.StdEncoding.EncodedLen(len(pkcs12Data)))
base64.StdEncoding.Encode(buf, pkcs12Data)
return buf, nil
}
4 changes: 4 additions & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,7 @@ google.golang.org/grpc/stats
google.golang.org/grpc/status
google.golang.org/grpc/tap
google.golang.org/grpc/test/bufconn
# software.sslmate.com/src/go-pkcs12 v0.0.0-20200619203921-c9ed90bd32dc
## explicit
software.sslmate.com/src/go-pkcs12
software.sslmate.com/src/go-pkcs12/internal/rc2
4 changes: 4 additions & 0 deletions website/docs/r/locally_signed_cert.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ The following attributes are exported:
[RFC3339](https://tools.ietf.org/html/rfc3339) timestamp.
* `validity_end_time` - The time until which the certificate is invalid, as an
[RFC3339](https://tools.ietf.org/html/rfc3339) timestamp.
* `certificate_p12` -The certificate, intermediate, and the private key archived as a p12 file.
The data is base64 encoded (including padding), and its password is configurable via the
certificate_p12_password argument.
This field is empty if creating a locally signed certificate from a CSR.

## Automatic Renewal

Expand Down
7 changes: 7 additions & 0 deletions website/docs/r/self_signed_cert.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ The following arguments are supported:
the subject key identifier. Defaults to `false`, in which case the subject
key identifier is not set at all.

* `certificate_p12_password` - (Optional) Password to be used when generating the P12 file
stored in certificate_p12. Defaults to an empty string.

The `allowed_uses` list accepts the following keywords, combining the set of flags defined by
both [Key Usage](https://tools.ietf.org/html/rfc5280#section-4.2.1.3) and
[Extended Key Usage](https://tools.ietf.org/html/rfc5280#section-4.2.1.12) in
Expand Down Expand Up @@ -130,6 +133,10 @@ The following attributes are exported:
[RFC3339](https://tools.ietf.org/html/rfc3339) timestamp.
* `validity_end_time` - The time until which the certificate is invalid, as an
[RFC3339](https://tools.ietf.org/html/rfc3339) timestamp.
* `certificate_p12` -The certificate, intermediate, and the private key archived as a p12 file.
The data is base64 encoded (including padding),
and its password is configurable via the certificate_p12_password argument.
This field is empty if creating a locally signed certificate from a CSR.

## Automatic Renewal

Expand Down