Skip to content

Commit

Permalink
Merge pull request #184 from Venafi/vcert-keystore
Browse files Browse the repository at this point in the history
Support for CSR service generated on VaaS
  • Loading branch information
angelmoo authored Nov 16, 2021
2 parents 171269e + d565d9e commit fa666c5
Show file tree
Hide file tree
Showing 16 changed files with 812 additions and 27 deletions.
17 changes: 17 additions & 0 deletions cmd/vcert/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ func doCommandEnroll1(c *cli.Context) error {
req.ChainOption = certificate.ChainOptionFromString(flags.chainOption)
req.KeyPassword = flags.keyPassword

req.Timeout = time.Duration(180) * time.Second
pcc, err = retrieveCertificate(connector, req, time.Duration(flags.timeout)*time.Second)
if err != nil {
return err
Expand All @@ -343,6 +344,14 @@ func doCommandEnroll1(c *cli.Context) error {
}
}

if connector.GetType() == endpoint.ConnectorTypeCloud && (flags.format == Pkcs12 || flags.format == JKSFormat) && flags.csrOption == "service" {
privKey, err := util.DecryptPkcs8PrivateKey(pcc.PrivateKey, flags.keyPassword)
if err != nil {
return err
}
pcc.PrivateKey = privKey
}

result := &Result{
Pcc: pcc,
PickupId: flags.pickupID,
Expand Down Expand Up @@ -768,6 +777,14 @@ func doCommandPickup1(c *cli.Context) error {
}
logf("Successfully retrieved request for %s", flags.pickupID)

if connector.GetType() == endpoint.ConnectorTypeCloud && (flags.format == Pkcs12 || flags.format == JKSFormat) && IsCSRServiceVaaSGenerated(c.Command.Name) {
privKey, err := util.DecryptPkcs8PrivateKey(pcc.PrivateKey, flags.keyPassword)
if err != nil {
return err
}
pcc.PrivateKey = privKey
}

result := &Result{
Pcc: pcc,
PickupId: flags.pickupID,
Expand Down
9 changes: 7 additions & 2 deletions cmd/vcert/passwords.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ func readPasswordsFromInputFlags(commandName string, cf *commandFlags) error {
}
}

if commandName == commandSshPickupName || commandName == commandSshEnrollName || commandName == commandEnrollName || commandName == commandGenCSRName || commandName == commandRenewName || commandName == commandPickupName && (cf.format == "pkcs12" || cf.format == JKSFormat) {
cloudSerViceGenerated := IsCSRServiceVaaSGenerated(commandName)

if commandName == commandSshPickupName || commandName == commandSshEnrollName || commandName == commandEnrollName || commandName == commandGenCSRName || commandName == commandRenewName || commandName == commandPickupName && (cf.format == "pkcs12" || cf.format == JKSFormat || cloudSerViceGenerated) {
var keyPasswordNotNeeded = false

keyPasswordNotNeeded = keyPasswordNotNeeded || (cf.csrOption == "service" && cf.noPickup)
keyPasswordNotNeeded = keyPasswordNotNeeded || (strings.Index(cf.csrOption, "file:") == 0)
keyPasswordNotNeeded = keyPasswordNotNeeded || (cf.csrOption == "service" && cf.url == "")
if commandName == commandSshEnrollName {
keyPasswordNotNeeded = keyPasswordNotNeeded || (cf.sshCertPubKey != SshCertPubKeyServ && cf.sshCertPubKey != SshCertPubKeyLocal) || cf.sshCertKeyPassphrase != ""
}
Expand All @@ -72,6 +73,10 @@ func readPasswordsFromInputFlags(commandName string, cf *commandFlags) error {
keyPasswordNotNeeded = cf.sshCertKeyPassphrase != ""
}

if cloudSerViceGenerated {
keyPasswordNotNeeded = false
}

if !keyPasswordNotNeeded {
if cf.keyPassword == "" && !cf.noPrompt {
fmt.Printf("Enter key passphrase:")
Expand Down
16 changes: 13 additions & 3 deletions cmd/vcert/result_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ func (o *Output) AsPKCS12(c *Config) ([]byte, error) {
privKey, err = x509.ParseECPrivateKey(privDER)
case "RSA PRIVATE KEY":
privKey, err = x509.ParsePKCS1PrivateKey(privDER)
if err != nil {
privKey, err = x509.ParsePKCS8PrivateKey(privDER)
}
default:
return nil, fmt.Errorf("unexpected private key PEM type: %s", p.Type)
}
Expand Down Expand Up @@ -164,9 +167,13 @@ func (o *Output) AsJKS(c *Config) ([]byte, error) {
//decrypting the PK because due the restriction that always will be requested the key password
//to the user(--key-password or pass phrase value from prompt) for jks format then the PK always
//will be encrypted with the key password provided
privDER, err = x509.DecryptPEMBlock(p, []byte(c.KeyPassword))
if err != nil {
return nil, fmt.Errorf("private key PEM decryption error: %s", err)
if x509.IsEncryptedPEMBlock(p) {
privDER, err = x509.DecryptPEMBlock(p, []byte(c.KeyPassword))
if err != nil {
return nil, fmt.Errorf("private key PEM decryption error: %s", err)
}
} else {
privDER = p.Bytes
}

//Unmarshalling the PK
Expand All @@ -177,6 +184,9 @@ func (o *Output) AsJKS(c *Config) ([]byte, error) {
privKey, err = x509.ParseECPrivateKey(privDER)
case "RSA PRIVATE KEY":
privKey, err = x509.ParsePKCS1PrivateKey(privDER)
if err != nil {
privKey, err = x509.ParsePKCS8PrivateKey(privDER)
}
default:
return nil, fmt.Errorf("unexpected private key PEM type: %s", p.Type)
}
Expand Down
25 changes: 25 additions & 0 deletions cmd/vcert/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"github.com/Venafi/vcert/v4"
"github.com/Venafi/vcert/v4/pkg/policy"
"github.com/spf13/viper"
"github.com/urfave/cli/v2"
"gopkg.in/yaml.v2"
"io"
"io/ioutil"
Expand All @@ -50,6 +52,7 @@ const (
vCertTrustBundle = "VCERT_TRUST_BUNDLE"

JKSFormat = "jks"
Pkcs12 = "pkcs12"
Sha256 = "SHA256"
SshCertPubKeyServ = "service"
SshCertPubKeyFilePreff = "file:"
Expand Down Expand Up @@ -669,3 +672,25 @@ func AddLineEnding(s string) string {
}
return s
}

func IsCSRServiceVaaSGenerated(commandName string) bool {
cloudSerViceGenerated := false
if commandName == commandPickupName {
context := &cli.Context{
Command: &cli.Command{
Name: commandPickupName,
},
}
cfg, err := buildConfig(context, &flags)
if err == nil {
connector, err := vcert.NewClient(&cfg)
if err == nil && endpoint.ConnectorTypeCloud == connector.GetType() {
var req = &certificate.Request{
PickupID: flags.pickupID,
}
cloudSerViceGenerated, _ = connector.IsCSRServiceGenerated(req)
}
}
}
return cloudSerViceGenerated
}
6 changes: 6 additions & 0 deletions cmd/vcert/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@ func validatePickupFlags1(commandName string) error {
if err != nil {
return err
}

cloudSerViceGenerated := IsCSRServiceVaaSGenerated(commandName)
if cloudSerViceGenerated && flags.noPrompt && (flags.keyPassword == "") {
return fmt.Errorf("key-password is required")
}

err = readData(commandName)
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ require (
github.com/pavel-v-chernykh/keystore-go/v4 v4.1.0
github.com/spf13/viper v1.7.0
github.com/urfave/cli/v2 v2.1.1
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
gopkg.in/ini.v1 v1.51.0
gopkg.in/yaml.v2 v2.4.0
software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237
Expand Down
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
Expand All @@ -196,6 +198,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down Expand Up @@ -228,6 +233,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand All @@ -249,12 +255,19 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
1 change: 1 addition & 0 deletions pkg/endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ type Connector interface {
RequestCertificate(req *certificate.Request) (requestID string, err error)
// RetrieveCertificate immediately returns an enrolled certificate. Otherwise, RetrieveCertificate waits and retries during req.Timeout.
RetrieveCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error)
IsCSRServiceGenerated(req *certificate.Request) (bool, error)
RevokeCertificate(req *certificate.RevocationRequest) error
RenewCertificate(req *certificate.RenewalRequest) (requestID string, err error)
// ImportCertificate adds an existing certificate to Venafi Platform even if the certificate was not issued by Venafi Cloud or Venafi Platform. For information purposes.
Expand Down
9 changes: 5 additions & 4 deletions pkg/util/constants.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package util

const (
IssuerHintMicrosoft = "MICROSOFT"
IssuerHintDigicert = "DIGICERT"
IssuerHintEntrust = "ENTRUST"
PathSeparator = "\\"
IssuerHintMicrosoft = "MICROSOFT"
IssuerHintDigicert = "DIGICERT"
IssuerHintEntrust = "ENTRUST"
PathSeparator = "\\"
ApplicationServerTypeID = "784938d1-ef0d-11eb-9461-7bb533ba575b"
)
58 changes: 58 additions & 0 deletions pkg/util/utils.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package util

import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"encoding/json"
"encoding/pem"
"fmt"
"github.com/youmark/pkcs8"
"os"
"time"
)

Expand All @@ -14,3 +21,54 @@ func GetJsonAsString(i interface{}) (s string) {
s = string(byte)
return
}

func SaveZipFile(path string, dataByte []byte) error {

file, err := os.OpenFile(path+".zip", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)

if err != nil {
return err
}

defer file.Close()

_, err = file.Write(dataByte)

if err != nil {
return err
}

return nil
}

func DecryptPkcs8PrivateKey(privateKey, password string) (string, error) {

block, _ := pem.Decode([]byte(privateKey))
key, _, err := pkcs8.ParsePrivateKey(block.Bytes, []byte(password))

if err != nil {
return "", err
}

var pemType string

switch key.(type) {
case *rsa.PrivateKey:
pemType = "RSA PRIVATE KEY"
case *ecdsa.PrivateKey:
pemType = "EC PRIVATE KEY"
case ed25519.PrivateKey:
pemType = "PRIVATE KEY"
default:
return "", fmt.Errorf("failed to determine private key type")
}
privateKeyBytes, err := pkcs8.MarshalPrivateKey(key, nil, nil)

if err != nil {
return "", err
}

pemBytes := pem.EncodeToMemory(&pem.Block{Type: pemType, Bytes: privateKeyBytes})

return string(pemBytes), nil
}
36 changes: 34 additions & 2 deletions pkg/venafi/cloud/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type certificateRequestResponseData struct {
SubjectDN string `json:"subjectDN,omitempty"`
CreationDateString string `json:"creationDate,omitempty"`
CreationDate time.Time `json:"-"`
CertificateIds []string `json:"certificateIds,omitempty"`
}

type certificateRequestClientInfo struct {
Expand All @@ -86,6 +87,33 @@ type certificateRequest struct {
CertificateUsageMetadata []certificateUsageMetadata `json:"certificateUsageMetadata,omitempty"`
ReuseCSR bool `json:"reuseCSR,omitempty"`
ValidityPeriod string `json:"validityPeriod,omitempty"`
IsVaaSGenerated bool `json:"isVaaSGenerated,omitempty"`
CsrAttributes CsrAttributes `json:"csrAttributes,omitempty"`
ApplicationServerTypeId string `json:"applicationServerTypeId,omitempty"`
}

type CsrAttributes struct {
CommonName *string `json:"commonName,omitempty"`
Organization *string `json:"organization,omitempty"`
OrganizationalUnits []string `json:"organizationalUnits,omitempty"`
Locality *string `json:"locality,omitempty"`
State *string `json:"state,omitempty"`
Country *string `json:"country,omitempty"`
SubjectAlternativeNamesByType *SubjectAlternativeNamesByType `json:"subjectAlternativeNamesByType,omitempty"`
}
type SubjectAlternativeNamesByType struct {
DnsNames []string `json:"dnsNames,omitempty"`
}

type KeyStoreRequest struct {
ExportFormat string `json:"exportFormat,omitempty"`
EncryptedPrivateKeyPassphrase string `json:"encryptedPrivateKeyPassphrase"`
EncryptedKeystorePassphrase string `json:"encryptedKeystorePassphrase"`
CertificateLabel string `json:"certificateLabel"`
}

type EdgeEncryptionKey struct {
Key string `json:"key,omitempty"`
}

type certificateStatus struct {
Expand Down Expand Up @@ -541,7 +569,7 @@ func createAppUpdateRequest(applicationDetails *ApplicationDetails, cit *certifi
return request
}

func buildPolicySpecification(cit *certificateTemplate, info *policy.CertificateAuthorityInfo) *policy.PolicySpecification {
func buildPolicySpecification(cit *certificateTemplate, info *policy.CertificateAuthorityInfo, removeRegex bool) *policy.PolicySpecification {
if cit == nil {
return nil
}
Expand All @@ -551,7 +579,11 @@ func buildPolicySpecification(cit *certificateTemplate, info *policy.Certificate
var pol policy.Policy

if len(cit.SubjectCNRegexes) > 0 {
pol.Domains = policy.RemoveRegex(cit.SubjectCNRegexes)
if removeRegex {
pol.Domains = policy.RemoveRegex(cit.SubjectCNRegexes)
} else {
pol.Domains = cit.SubjectCNRegexes
}
}

wildCard := isWildCard(cit.SubjectCNRegexes)
Expand Down
Loading

0 comments on commit fa666c5

Please sign in to comment.