mirror of
https://github.com/wahyd4/cert-manager.git
synced 2026-08-29 06:57:18 +10:00
Bump vcert to version 'master'
Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
@@ -10,7 +10,7 @@ require (
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/SAP/go-hdb v0.14.1 // indirect
|
||||
github.com/SermoDigital/jose v0.9.1 // indirect
|
||||
github.com/Venafi/vcert v0.0.0-20181029235941-5068538d4d65
|
||||
github.com/Venafi/vcert v0.0.0-20190530133915-e207710a0ab9
|
||||
github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 // indirect
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
@@ -87,7 +87,6 @@ require (
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0 // indirect
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
|
||||
github.com/spf13/cobra v0.0.0-20170905172051-b78744579491
|
||||
github.com/spf13/pflag v1.0.1
|
||||
github.com/stretchr/testify v1.3.0
|
||||
|
||||
@@ -32,8 +32,8 @@ github.com/SermoDigital/jose v0.9.1 h1:atYaHPD3lPICcbK1owly3aPm0iaJGSGPi0WD4vLzn
|
||||
github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/Venafi/vcert v0.0.0-20181029235941-5068538d4d65 h1:An1XpraQx4IkI2i0kcXFS+VjTSK/lRb1ZioZRmTdDMA=
|
||||
github.com/Venafi/vcert v0.0.0-20181029235941-5068538d4d65/go.mod h1:3dpfrCI+31cDZosD+1UX8GFziVFORaegByXtzT1dwNo=
|
||||
github.com/Venafi/vcert v0.0.0-20190530133915-e207710a0ab9 h1:dt3QeZOpoi4ee72KwblGKmX2v6WbVS37yjCeZq6SV9w=
|
||||
github.com/Venafi/vcert v0.0.0-20190530133915-e207710a0ab9/go.mod h1:3sXw16DKVded/kLVDma2veqEUQC7O37h98ims7cIvN4=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
@@ -226,6 +226,7 @@ github.com/hashicorp/vault v0.9.6 h1:AalVi4vunOMSXX7eD8j8WKxkWr2AmG6yvz9o3ITSaMc
|
||||
github.com/hashicorp/vault v0.9.6/go.mod h1:KfSyffbKxoVyspOdlaGVjIuwLobi07qD1bAbosPMpP0=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
||||
@@ -392,6 +393,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190424203555-c05e17bb3b2d/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -436,6 +438,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190425045458-9f0b1ff7b46a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dzugGxJ/SQHoNufZJq1w=
|
||||
golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -491,6 +494,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
|
||||
@@ -543,3 +547,4 @@ sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkW
|
||||
sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
software.sslmate.com/src/go-pkcs12 v0.0.0-20180114231543-2291e8f0f237/go.mod h1:/xvNRWUqm0+/ZMiF4EX00vrSCMsE4/NHb+Pt3freEeQ=
|
||||
|
||||
+14
-6
@@ -25,32 +25,40 @@ import (
|
||||
"github.com/Venafi/vcert/pkg/venafi/tpp"
|
||||
)
|
||||
|
||||
// NewClient returns a connector for either Trust Protection Platform (TPP) or Venafi Cloud based on provided configuration.
|
||||
// Config should have Credentials compatible with the selected ConnectorType.
|
||||
// Returned connector is a concurrency-safe interface to TPP or Venafi Cloud that can be reused without restriction.
|
||||
// Connector can also be of type "fake" for local tests, which doesn`t connect to any backend and all certificates enroll locally.
|
||||
func NewClient(cfg *Config) (endpoint.Connector, error) {
|
||||
var err error
|
||||
|
||||
var connectionTrustBundle *x509.CertPool
|
||||
if cfg.ConnectionTrust != "" {
|
||||
fmt.Println("You specified a trust bundle.")
|
||||
connectionTrustBundle = x509.NewCertPool()
|
||||
if !connectionTrustBundle.AppendCertsFromPEM([]byte(cfg.ConnectionTrust)) {
|
||||
return nil, fmt.Errorf("failed to parse PEM trust bundle")
|
||||
return nil, fmt.Errorf("Failed to parse PEM trust bundle")
|
||||
}
|
||||
}
|
||||
|
||||
var connector endpoint.Connector
|
||||
switch cfg.ConnectorType {
|
||||
case endpoint.ConnectorTypeCloud:
|
||||
connector = cloud.NewConnector(cfg.LogVerbose, connectionTrustBundle)
|
||||
connector, err = cloud.NewConnector(cfg.BaseUrl, cfg.Zone, cfg.LogVerbose, connectionTrustBundle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case endpoint.ConnectorTypeTPP:
|
||||
connector = tpp.NewConnector(cfg.LogVerbose, connectionTrustBundle)
|
||||
connector, err = tpp.NewConnector(cfg.BaseUrl, cfg.Zone, cfg.LogVerbose, connectionTrustBundle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case endpoint.ConnectorTypeFake:
|
||||
connector = fake.NewConnector(cfg.LogVerbose, connectionTrustBundle)
|
||||
default:
|
||||
return nil, fmt.Errorf("ConnectorType is not defined")
|
||||
}
|
||||
|
||||
if cfg.BaseUrl != "" {
|
||||
connector.SetBaseURL(cfg.BaseUrl)
|
||||
}
|
||||
connector.SetZone(cfg.Zone)
|
||||
|
||||
err = connector.Authenticate(cfg.Credentials)
|
||||
|
||||
+38
-32
@@ -26,51 +26,57 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Config is a basic structure for high level initiating connector to Trust Platform (TPP)/Venafi Cloud
|
||||
type Config struct {
|
||||
ConnectorType endpoint.ConnectorType
|
||||
BaseUrl string
|
||||
Zone string
|
||||
Credentials *endpoint.Authentication
|
||||
// ConnectorType specify what do you want to use. May be "Cloud", "TPP" or "Fake" for development.
|
||||
ConnectorType endpoint.ConnectorType
|
||||
// BaseUrl should be specified for Venafi Platform. Optional for Cloud implementations that do not use https://venafi.cloud/.
|
||||
BaseUrl string
|
||||
// Zone is name of a policy zone in Venafi Platform or Cloud. For TPP, if necessary, escape backslash symbols. For example, "test\\zone" or `test\zone`.
|
||||
Zone string
|
||||
// Credentials should contain either User and Password for TPP connections or an APIKey for Cloud.
|
||||
Credentials *endpoint.Authentication
|
||||
// ConnectionTrust may contain a trusted CA or certificate of server if you use self-signed certificate.
|
||||
ConnectionTrust string // *x509.CertPool
|
||||
LogVerbose bool
|
||||
ConfigFile string
|
||||
ConfigSection string
|
||||
}
|
||||
|
||||
func (cfg *Config) LoadFromFile() error {
|
||||
if cfg.ConfigSection == "" {
|
||||
cfg.ConfigSection = ini.DEFAULT_SECTION
|
||||
}
|
||||
log.Printf("Loading configuration from %s section %s", cfg.ConfigFile, cfg.ConfigSection)
|
||||
// LoadFromFile is deprecated. In the future will be rewrited.
|
||||
func LoadConfigFromFile(path, section string) (cfg Config, err error) {
|
||||
|
||||
fname, err := expand(cfg.ConfigFile)
|
||||
if section == "" {
|
||||
section = ini.DEFAULT_SECTION
|
||||
}
|
||||
log.Printf("Loading configuration from %s section %s", path, section)
|
||||
|
||||
fname, err := expand(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %s", err)
|
||||
return cfg, fmt.Errorf("failed to load config: %s", err)
|
||||
}
|
||||
|
||||
iniFile, err := ini.Load(fname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %s", err)
|
||||
return cfg, fmt.Errorf("failed to load config: %s", err)
|
||||
}
|
||||
|
||||
err = validateFile(iniFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %s", err)
|
||||
return cfg, fmt.Errorf("failed to load config: %s", err)
|
||||
}
|
||||
|
||||
ok := func() bool {
|
||||
for _, section := range iniFile.Sections() {
|
||||
if section.Name() == cfg.ConfigSection {
|
||||
for _, s := range iniFile.Sections() {
|
||||
if s.Name() == section {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}()
|
||||
if !ok {
|
||||
return fmt.Errorf("section %s has not been found in %s", cfg.ConfigSection, cfg.ConfigFile)
|
||||
return cfg, fmt.Errorf("section %s has not been found in %s", section, path)
|
||||
}
|
||||
|
||||
var m Dict = iniFile.Section(cfg.ConfigSection).KeysHash()
|
||||
var m dict = iniFile.Section(section).KeysHash()
|
||||
|
||||
var connectorType endpoint.ConnectorType
|
||||
var baseUrl string
|
||||
@@ -98,17 +104,17 @@ func (cfg *Config) LoadFromFile() error {
|
||||
} else if m.has("test_mode") && m["test_mode"] == "true" {
|
||||
connectorType = endpoint.ConnectorTypeFake
|
||||
} else {
|
||||
return fmt.Errorf("failed to load config: connector type cannot be defined")
|
||||
return cfg, fmt.Errorf("failed to load config: connector type cannot be defined")
|
||||
}
|
||||
|
||||
if m.has("trust_bundle") {
|
||||
fname, err := expand(m["trust_bundle"])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load trust-bundle: %s", err)
|
||||
return cfg, fmt.Errorf("failed to load trust-bundle: %s", err)
|
||||
}
|
||||
data, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load trust-bundle: %s", err)
|
||||
return cfg, fmt.Errorf("failed to load trust-bundle: %s", err)
|
||||
}
|
||||
cfg.ConnectionTrust = string(data)
|
||||
}
|
||||
@@ -117,7 +123,7 @@ func (cfg *Config) LoadFromFile() error {
|
||||
cfg.Credentials = auth
|
||||
cfg.BaseUrl = baseUrl
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func expand(path string) (string, error) {
|
||||
@@ -131,18 +137,18 @@ func expand(path string) (string, error) {
|
||||
return filepath.Join(usr.HomeDir, path[1:]), nil
|
||||
}
|
||||
|
||||
type Dict map[string]string
|
||||
type dict map[string]string
|
||||
|
||||
func (d Dict) has(key string) bool {
|
||||
func (d dict) has(key string) bool {
|
||||
if _, ok := d[key]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Set map[string]bool
|
||||
type set map[string]bool
|
||||
|
||||
func (d Set) has(key string) bool {
|
||||
func (d set) has(key string) bool {
|
||||
if _, ok := d[key]; ok {
|
||||
return true
|
||||
}
|
||||
@@ -150,14 +156,14 @@ func (d Set) has(key string) bool {
|
||||
}
|
||||
|
||||
func validateSection(s *ini.Section) error {
|
||||
var TPPValidKeys Set = map[string]bool{
|
||||
var TPPValidKeys set = map[string]bool{
|
||||
"tpp_url": true,
|
||||
"tpp_user": true,
|
||||
"tpp_password": true,
|
||||
"tpp_zone": true,
|
||||
"trust_bundle": true,
|
||||
}
|
||||
var CloudValidKeys Set = map[string]bool{
|
||||
var CloudValidKeys set = map[string]bool{
|
||||
"trust_bundle": true,
|
||||
"cloud_url": true,
|
||||
"cloud_apikey": true,
|
||||
@@ -165,11 +171,11 @@ func validateSection(s *ini.Section) error {
|
||||
}
|
||||
|
||||
log.Printf("Validating configuration section %s", s.Name())
|
||||
var m Dict = s.KeysHash()
|
||||
var m dict = s.KeysHash()
|
||||
|
||||
if m.has("tpp_url") {
|
||||
// looks like TPP config section
|
||||
for k, _ := range m {
|
||||
for k := range m {
|
||||
if !TPPValidKeys.has(k) {
|
||||
return fmt.Errorf("illegal key '%s' in TPP section %s", k, s.Name())
|
||||
}
|
||||
@@ -182,7 +188,7 @@ func validateSection(s *ini.Section) error {
|
||||
}
|
||||
} else if m.has("cloud_apikey") {
|
||||
// looks like Cloud config section
|
||||
for k, _ := range m {
|
||||
for k := range m {
|
||||
if !CloudValidKeys.has(k) {
|
||||
return fmt.Errorf("illegal key '%s' in Cloud section %s", k, s.Name())
|
||||
}
|
||||
|
||||
+206
-54
@@ -17,6 +17,7 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
@@ -30,7 +31,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//EllipticCurve represents the types of supported elliptic curves
|
||||
// EllipticCurve represents the types of supported elliptic curves
|
||||
type EllipticCurve int
|
||||
|
||||
func (ec *EllipticCurve) String() string {
|
||||
@@ -48,7 +49,7 @@ func (ec *EllipticCurve) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
//Set the elliptic cuve value via a string
|
||||
// Set EllipticCurve value via a string
|
||||
func (ec *EllipticCurve) Set(value string) error {
|
||||
switch strings.ToLower(value) {
|
||||
case "p521":
|
||||
@@ -60,24 +61,34 @@ func (ec *EllipticCurve) Set(value string) error {
|
||||
case "p224":
|
||||
*ec = EllipticCurveP224
|
||||
default:
|
||||
*ec = EllipticCurveP521
|
||||
*ec = EllipticCurveDefault
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
//EllipticCurveP521 represents the P521 curve
|
||||
// EllipticCurveP521 represents the P521 curve
|
||||
EllipticCurveP521 EllipticCurve = iota
|
||||
//EllipticCurveP224 represents the P224 curve
|
||||
// EllipticCurveP224 represents the P224 curve
|
||||
EllipticCurveP224
|
||||
//EllipticCurveP256 represents the P256 curve
|
||||
// EllipticCurveP256 represents the P256 curve
|
||||
EllipticCurveP256
|
||||
//EllipticCurveP384 represents the P384 curve
|
||||
// EllipticCurveP384 represents the P384 curve
|
||||
EllipticCurveP384
|
||||
EllipticCurveDefault = EllipticCurveP521
|
||||
|
||||
defaultRSAlength int = 2048
|
||||
)
|
||||
|
||||
//KeyType represents the types of supported keys
|
||||
func AllSupportedCurves() []EllipticCurve {
|
||||
return []EllipticCurve{EllipticCurveP521, EllipticCurveP224, EllipticCurveP256, EllipticCurveP384}
|
||||
}
|
||||
func AllSupportedKeySizes() []int {
|
||||
return []int{512, 1024, 2048, 4096, 8192}
|
||||
}
|
||||
|
||||
// KeyType represents the types of supported keys
|
||||
type KeyType int
|
||||
|
||||
func (kt *KeyType) String() string {
|
||||
@@ -91,59 +102,75 @@ func (kt *KeyType) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
//Set the key type via a string
|
||||
func (kt *KeyType) X509Type() x509.PublicKeyAlgorithm {
|
||||
switch *kt {
|
||||
case KeyTypeRSA:
|
||||
return x509.RSA
|
||||
case KeyTypeECDSA:
|
||||
return x509.ECDSA
|
||||
}
|
||||
return x509.UnknownPublicKeyAlgorithm
|
||||
}
|
||||
|
||||
// Set the key type via a string
|
||||
func (kt *KeyType) Set(value string) error {
|
||||
switch strings.ToLower(value) {
|
||||
case "rsa":
|
||||
*kt = KeyTypeRSA
|
||||
case "ecdsa":
|
||||
*kt = KeyTypeECDSA
|
||||
default:
|
||||
return nil
|
||||
case "ecdsa", "ec", "ecc":
|
||||
*kt = KeyTypeECDSA
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return fmt.Errorf("unknow key type: %s", value) //todo: check all calls
|
||||
}
|
||||
|
||||
const (
|
||||
//KeyTypeRSA represents a key type of RSA
|
||||
// KeyTypeRSA represents a key type of RSA
|
||||
KeyTypeRSA KeyType = iota
|
||||
//KeyTypeECDSA represents a key type of ECDSA
|
||||
// KeyTypeECDSA represents a key type of ECDSA
|
||||
KeyTypeECDSA
|
||||
)
|
||||
|
||||
type CSrOriginOption int
|
||||
|
||||
const (
|
||||
// LocalGeneratedCSR - this vcert library generates CSR internally based on Request data
|
||||
LocalGeneratedCSR CSrOriginOption = iota // local generation is default.
|
||||
// ServiceGeneratedCSR - server generate CSR internally based on zone configuration and data from Request
|
||||
ServiceGeneratedCSR
|
||||
// UserProvidedCSR - client provides CSR from external resource and vcert library just check and send this CSR to server
|
||||
UserProvidedCSR
|
||||
)
|
||||
|
||||
//Request contains data needed to generate a certificate request
|
||||
// Request contains data needed to generate a certificate request
|
||||
// CSR is a PEM-encoded Certificate Signing Request
|
||||
type Request struct {
|
||||
CADN string
|
||||
Subject pkix.Name
|
||||
DNSNames []string
|
||||
EmailAddresses []string
|
||||
IPAddresses []net.IP
|
||||
Attributes []pkix.AttributeTypeAndValueSET
|
||||
SignatureAlgorithm x509.SignatureAlgorithm
|
||||
PublicKeyAlgorithm x509.PublicKeyAlgorithm
|
||||
FriendlyName string
|
||||
KeyType KeyType
|
||||
KeyLength int
|
||||
KeyCurve EllipticCurve
|
||||
CSR []byte
|
||||
PrivateKey interface{}
|
||||
CsrOrigin CSrOriginOption
|
||||
PickupID string
|
||||
ChainOption ChainOption
|
||||
KeyPassword string
|
||||
FetchPrivateKey bool
|
||||
Thumbprint string /* this one is here because *Request is used in RetrieveCertificate(),
|
||||
it should be refactored so that RetrieveCertificate() uses
|
||||
some abstract search object, instead of *Request{PickupID} */
|
||||
Timeout time.Duration
|
||||
//CSR []byte // should be a PEM-encoded CSR
|
||||
csr []byte // should be a PEM-encoded CSR
|
||||
PrivateKey crypto.Signer
|
||||
CsrOrigin CSrOriginOption
|
||||
PickupID string
|
||||
//Cloud Certificate ID
|
||||
CertID string
|
||||
ChainOption ChainOption
|
||||
KeyPassword string
|
||||
FetchPrivateKey bool
|
||||
/* Thumbprint is here because *Request is used in RetrieveCertificate().
|
||||
Code should be refactored so that RetrieveCertificate() uses some abstract search object, instead of *Request{PickupID} */
|
||||
Thumbprint string
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
type RevocationRequest struct {
|
||||
@@ -172,13 +199,52 @@ type ImportRequest struct {
|
||||
|
||||
type ImportResponse struct {
|
||||
CertificateDN string `json:",omitempty"`
|
||||
CertId string `json:",omitempty"`
|
||||
CertificateVaultId int `json:",omitempty"`
|
||||
Guid string `json:",omitempty"`
|
||||
PrivateKeyVaultId int `json:",omitempty"`
|
||||
}
|
||||
|
||||
//GenerateRequest generates a certificate request
|
||||
func GenerateRequest(request *Request, privateKey interface{}) error {
|
||||
// SetCSR sets CSR from PEM or DER format
|
||||
func (request *Request) SetCSR(csr []byte) error {
|
||||
pemBlock, _ := pem.Decode(csr)
|
||||
if pemBlock != nil {
|
||||
if pemBlock.Type == "CERTIFICATE REQUEST" {
|
||||
request.csr = csr
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//Determine CSR type and use appropriate function
|
||||
parsedCSR, err := x509.ParseCertificateRequest(csr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if parsedCSR != nil {
|
||||
request.csr = pem.EncodeToMemory(GetCertificateRequestPEMBlock(csr))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Can't determine CSR type for %s", csr)
|
||||
}
|
||||
|
||||
// GetCSR returns CSR in PEM format
|
||||
func (request Request) GetCSR() []byte {
|
||||
return request.csr
|
||||
}
|
||||
|
||||
// GenerateRequest generates a certificate request
|
||||
// Please use method Request.GenerateCSR()
|
||||
// TODO: Remove usage from all libraries, deprecated
|
||||
func GenerateRequest(request *Request, privateKey crypto.Signer) error {
|
||||
pk := request.PrivateKey
|
||||
request.PrivateKey = privateKey
|
||||
err := request.GenerateCSR()
|
||||
request.PrivateKey = pk
|
||||
return err
|
||||
}
|
||||
|
||||
// GenerateCSR creates CSR for sending to server based on data from Request fields. It rewrites CSR field if it`s already filled.
|
||||
func (request *Request) GenerateCSR() error {
|
||||
certificateRequest := x509.CertificateRequest{}
|
||||
certificateRequest.Subject = request.Subject
|
||||
certificateRequest.DNSNames = request.DNSNames
|
||||
@@ -186,32 +252,118 @@ func GenerateRequest(request *Request, privateKey interface{}) error {
|
||||
certificateRequest.IPAddresses = request.IPAddresses
|
||||
certificateRequest.Attributes = request.Attributes
|
||||
|
||||
csr, err := x509.CreateCertificateRequest(rand.Reader, &certificateRequest, privateKey)
|
||||
csr, err := x509.CreateCertificateRequest(rand.Reader, &certificateRequest, request.PrivateKey)
|
||||
if err != nil {
|
||||
csr = nil
|
||||
}
|
||||
request.CSR = csr
|
||||
|
||||
err = request.SetCSR(csr)
|
||||
//request.CSR = pem.EncodeToMemory(GetCertificateRequestPEMBlock(csr))
|
||||
return err
|
||||
}
|
||||
|
||||
func publicKey(priv interface{}) interface{} {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
case *ecdsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
default:
|
||||
// GeneratePrivateKey creates private key (if it doesn`t already exist) based on request.KeyType, request.KeyLength and request.KeyCurve fileds
|
||||
func (request *Request) GeneratePrivateKey() error {
|
||||
if request.PrivateKey != nil {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
switch request.KeyType {
|
||||
case KeyTypeECDSA:
|
||||
request.PrivateKey, err = GenerateECDSAPrivateKey(request.KeyCurve)
|
||||
case KeyTypeRSA:
|
||||
if request.KeyLength == 0 {
|
||||
request.KeyLength = defaultRSAlength
|
||||
}
|
||||
request.PrivateKey, err = GenerateRSAPrivateKey(request.KeyLength)
|
||||
default:
|
||||
return fmt.Errorf("Unable to generate certificate request, key type %s is not supported", request.KeyType.String())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func PublicKey(priv interface{}) interface{} {
|
||||
// CheckCertificate validate that certificate returned by server matches data in request object. It can be used for control server.
|
||||
func (request *Request) CheckCertificate(certPEM string) error {
|
||||
pemBlock, _ := pem.Decode([]byte(certPEM))
|
||||
if pemBlock == nil {
|
||||
return fmt.Errorf("invalid pem format certificate %s", certPEM)
|
||||
}
|
||||
if pemBlock.Type != "CERTIFICATE" {
|
||||
return fmt.Errorf("invalid pem type %s (expect CERTIFICATE)", pemBlock.Type)
|
||||
}
|
||||
cert, err := x509.ParseCertificate(pemBlock.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if request.PrivateKey != nil {
|
||||
if request.KeyType.X509Type() != cert.PublicKeyAlgorithm {
|
||||
return fmt.Errorf("unmatched key type: %s, %s", request.KeyType.X509Type(), cert.PublicKeyAlgorithm)
|
||||
}
|
||||
switch cert.PublicKeyAlgorithm {
|
||||
case x509.RSA:
|
||||
certPubKey := cert.PublicKey.(*rsa.PublicKey)
|
||||
reqPubkey, ok := request.PrivateKey.Public().(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("request KeyType not matched with real PrivateKey type")
|
||||
}
|
||||
|
||||
if certPubKey.N.Cmp(reqPubkey.N) != 0 {
|
||||
return fmt.Errorf("unmatched key modules")
|
||||
}
|
||||
case x509.ECDSA:
|
||||
certPubkey := cert.PublicKey.(*ecdsa.PublicKey)
|
||||
reqPubkey, ok := request.PrivateKey.Public().(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("request KeyType not matched with real PrivateKey type")
|
||||
}
|
||||
if certPubkey.X.Cmp(reqPubkey.X) != 0 {
|
||||
return fmt.Errorf("unmatched X for eliptic keys")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown key algorythm %d", cert.PublicKeyAlgorithm)
|
||||
}
|
||||
} else if len(request.csr) != 0 {
|
||||
pemBlock, _ := pem.Decode(request.csr)
|
||||
if pemBlock == nil {
|
||||
return fmt.Errorf("bad csr: %s", string(request.csr))
|
||||
}
|
||||
csr, err := x509.ParseCertificateRequest(pemBlock.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cert.PublicKeyAlgorithm != csr.PublicKeyAlgorithm {
|
||||
return fmt.Errorf("unmatched key type: %s, %s", cert.PublicKeyAlgorithm, csr.PublicKeyAlgorithm)
|
||||
}
|
||||
switch csr.PublicKeyAlgorithm {
|
||||
case x509.RSA:
|
||||
certPubKey := cert.PublicKey.(*rsa.PublicKey)
|
||||
reqPubKey := csr.PublicKey.(*rsa.PublicKey)
|
||||
if certPubKey.N.Cmp(reqPubKey.N) != 0 {
|
||||
return fmt.Errorf("unmatched key modules")
|
||||
}
|
||||
case x509.ECDSA:
|
||||
certPubKey := cert.PublicKey.(*ecdsa.PublicKey)
|
||||
reqPubKey := csr.PublicKey.(*ecdsa.PublicKey)
|
||||
if certPubKey.X.Cmp(reqPubKey.X) != 0 {
|
||||
return fmt.Errorf("unmatched X for eliptic keys")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func publicKey(priv crypto.Signer) crypto.PublicKey {
|
||||
if priv != nil {
|
||||
return priv.Public()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PublicKey(priv crypto.Signer) crypto.PublicKey {
|
||||
return publicKey(priv)
|
||||
}
|
||||
|
||||
//GetPrivateKeyPEMBock gets the private key as a PEM data block
|
||||
func GetPrivateKeyPEMBock(key interface{}) (*pem.Block, error) {
|
||||
// GetPrivateKeyPEMBock gets the private key as a PEM data block
|
||||
func GetPrivateKeyPEMBock(key crypto.Signer) (*pem.Block, error) { // TODO: Change to crypto.Signer type
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
|
||||
@@ -226,8 +378,8 @@ func GetPrivateKeyPEMBock(key interface{}) (*pem.Block, error) {
|
||||
}
|
||||
}
|
||||
|
||||
//GetEncryptedPrivateKeyPEMBock gets the private key as an encrypted PEM data block
|
||||
func GetEncryptedPrivateKeyPEMBock(key interface{}, password []byte) (*pem.Block, error) {
|
||||
// GetEncryptedPrivateKeyPEMBock gets the private key as an encrypted PEM data block
|
||||
func GetEncryptedPrivateKeyPEMBock(key crypto.Signer, password []byte) (*pem.Block, error) { // TODO: Change to crypto.Signer type
|
||||
switch k := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return x509.EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(k), password, x509.PEMCipherAES256)
|
||||
@@ -242,17 +394,17 @@ func GetEncryptedPrivateKeyPEMBock(key interface{}, password []byte) (*pem.Block
|
||||
}
|
||||
}
|
||||
|
||||
//GetCertificatePEMBlock gets the certificate as a PEM data block
|
||||
// GetCertificatePEMBlock gets the certificate as a PEM data block
|
||||
func GetCertificatePEMBlock(cert []byte) *pem.Block {
|
||||
return &pem.Block{Type: "CERTIFICATE", Bytes: cert}
|
||||
}
|
||||
|
||||
//GetCertificateRequestPEMBlock gets the certificate request as a PEM data block
|
||||
// GetCertificateRequestPEMBlock gets the certificate request as a PEM data block
|
||||
func GetCertificateRequestPEMBlock(request []byte) *pem.Block {
|
||||
return &pem.Block{Type: "CERTIFICATE REQUEST", Bytes: request}
|
||||
}
|
||||
|
||||
//GenerateECDSAPrivateKey generates a new ecdsa private key using the curve specified
|
||||
// GenerateECDSAPrivateKey generates a new ecdsa private key using the curve specified
|
||||
func GenerateECDSAPrivateKey(curve EllipticCurve) (*ecdsa.PrivateKey, error) {
|
||||
var priv *ecdsa.PrivateKey
|
||||
var c elliptic.Curve
|
||||
@@ -277,7 +429,7 @@ func GenerateECDSAPrivateKey(curve EllipticCurve) (*ecdsa.PrivateKey, error) {
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
//GenerateRSAPrivateKey generates a new rsa private key using the size specified
|
||||
// GenerateRSAPrivateKey generates a new rsa private key using the size specified
|
||||
func GenerateRSAPrivateKey(size int) (*rsa.PrivateKey, error) {
|
||||
priv, err := rsa.GenerateKey(rand.Reader, size)
|
||||
if err != nil {
|
||||
@@ -287,16 +439,16 @@ func GenerateRSAPrivateKey(size int) (*rsa.PrivateKey, error) {
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// NewRequest duplicates new Request object based on issued certificate
|
||||
func NewRequest(cert *x509.Certificate) *Request {
|
||||
req := &Request{}
|
||||
// 1st fill with *cert content
|
||||
|
||||
// First populate with *cert content
|
||||
req.Subject = cert.Subject
|
||||
req.DNSNames = cert.DNSNames
|
||||
req.EmailAddresses = cert.EmailAddresses
|
||||
req.IPAddresses = cert.IPAddresses
|
||||
req.SignatureAlgorithm = cert.SignatureAlgorithm
|
||||
req.PublicKeyAlgorithm = cert.PublicKeyAlgorithm
|
||||
switch pub := cert.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
req.KeyType = KeyTypeRSA
|
||||
@@ -304,8 +456,8 @@ func NewRequest(cert *x509.Certificate) *Request {
|
||||
case *ecdsa.PublicKey:
|
||||
req.KeyType = KeyTypeECDSA
|
||||
req.KeyLength = pub.Curve.Params().BitSize
|
||||
// TODO: req.KeyCurve = pub.Curve.Params().Name...
|
||||
default: // case *dsa.PublicKey:
|
||||
// TODO: req.KeyCurve = pub.Curve.Params().Name ...
|
||||
default: // case *dsa.PublicKey
|
||||
// vcert only works with RSA & ECDSA
|
||||
}
|
||||
return req
|
||||
|
||||
+13
-6
@@ -17,6 +17,7 @@
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
@@ -55,7 +56,7 @@ type PEMCollection struct {
|
||||
}
|
||||
|
||||
//NewPEMCollection creates a PEMCollection based on the data being passed in
|
||||
func NewPEMCollection(certificate *x509.Certificate, privateKey interface{}, privateKeyPassword []byte) (*PEMCollection, error) {
|
||||
func NewPEMCollection(certificate *x509.Certificate, privateKey crypto.Signer, privateKeyPassword []byte) (*PEMCollection, error) { //todo: change to crypto.Signer type
|
||||
collection := PEMCollection{}
|
||||
if certificate != nil {
|
||||
collection.Certificate = string(pem.EncodeToMemory(GetCertificatePEMBlock(certificate.Raw)))
|
||||
@@ -63,7 +64,7 @@ func NewPEMCollection(certificate *x509.Certificate, privateKey interface{}, pri
|
||||
if privateKey != nil {
|
||||
var p *pem.Block
|
||||
var err error
|
||||
if privateKeyPassword != nil && len(privateKeyPassword) > 0 {
|
||||
if len(privateKeyPassword) > 0 {
|
||||
p, err = GetEncryptedPrivateKeyPEMBock(privateKey, privateKeyPassword)
|
||||
} else {
|
||||
p, err = GetPrivateKeyPEMBock(privateKey)
|
||||
@@ -114,14 +115,20 @@ func PEMCollectionFromBytes(certBytes []byte, chainOrder ChainOption) (*PEMColle
|
||||
collection, err = NewPEMCollection(chain[len(chain)-1], nil, nil)
|
||||
if len(chain) > 1 && chainOrder != ChainOptionIgnore {
|
||||
for _, caCert := range chain[:len(chain)-1] {
|
||||
collection.AddChainElement(caCert)
|
||||
err = collection.AddChainElement(caCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
collection, err = NewPEMCollection(chain[0], nil, nil)
|
||||
if len(chain) > 1 && chainOrder != ChainOptionIgnore {
|
||||
for _, caCert := range chain[1:] {
|
||||
collection.AddChainElement(caCert)
|
||||
err = collection.AddChainElement(caCert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,13 +144,13 @@ func PEMCollectionFromBytes(certBytes []byte, chainOrder ChainOption) (*PEMColle
|
||||
}
|
||||
|
||||
//AddPrivateKey adds a Private Key to the PEMCollection. Note that the collection can only contain one private key
|
||||
func (col *PEMCollection) AddPrivateKey(privateKey interface{}, privateKeyPassword []byte) error {
|
||||
func (col *PEMCollection) AddPrivateKey(privateKey crypto.Signer, privateKeyPassword []byte) error { //todo: change to crypto.Signer type
|
||||
if col.PrivateKey != "" {
|
||||
return fmt.Errorf("The PEM Collection can only contain one private key")
|
||||
}
|
||||
var p *pem.Block
|
||||
var err error
|
||||
if privateKeyPassword != nil && len(privateKeyPassword) > 0 {
|
||||
if len(privateKeyPassword) > 0 {
|
||||
p, err = GetEncryptedPrivateKeyPEMBock(privateKey, privateKeyPassword)
|
||||
} else {
|
||||
p, err = GetPrivateKeyPEMBock(privateKey)
|
||||
|
||||
+99
-96
@@ -19,10 +19,11 @@ package endpoint
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"log"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
)
|
||||
|
||||
// ConnectorType represents the available connectors
|
||||
@@ -55,22 +56,30 @@ func (t ConnectorType) String() string {
|
||||
|
||||
// Connector provides a common interface for external communications with TPP or Venafi Cloud
|
||||
type Connector interface {
|
||||
// GetType returns a connector type (cloud/TPP/fake). Can be useful because some features are not supported by a Cloud connection.
|
||||
GetType() ConnectorType
|
||||
SetBaseURL(url string) (err error)
|
||||
// SetZone sets a zone (by name) for requests with this connector.
|
||||
SetZone(z string)
|
||||
Ping() (err error)
|
||||
Register(email string) (err error)
|
||||
// Authenticate is usually called by NewClient and it is not required that you manually call it.
|
||||
Authenticate(auth *Authentication) (err error)
|
||||
ReadZoneConfiguration(zone string) (config *ZoneConfiguration, err error)
|
||||
// ReadPolicyConfiguration returns information about zone policies. It can be used for checking request compatibility with policies.
|
||||
ReadPolicyConfiguration() (policy *Policy, err error)
|
||||
// ReadZoneConfiguration returns the zone configuration. A zone configuration includes zone policy and additional zone information.
|
||||
ReadZoneConfiguration() (config *ZoneConfiguration, err error)
|
||||
// GenerateRequest update certificate.Request with data from zone configuration.
|
||||
GenerateRequest(config *ZoneConfiguration, req *certificate.Request) (err error)
|
||||
RequestCertificate(req *certificate.Request, zone string) (requestID string, err error)
|
||||
// RequestCertificate makes a request to the server with data for enrolling the certificate.
|
||||
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)
|
||||
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.
|
||||
ImportCertificate(req *certificate.ImportRequest) (*certificate.ImportResponse, error)
|
||||
}
|
||||
|
||||
// Authentication provides a data construct for authentication data
|
||||
// Authentication provides a struct for authentication data. Either specify User and Password for Trust Platform or specify an APIKey for Cloud.
|
||||
type Authentication struct {
|
||||
User string
|
||||
Password string
|
||||
@@ -99,28 +108,37 @@ func (err ErrCertificatePending) Error() string {
|
||||
return fmt.Sprintf("Issuance is pending. You may try retrieving the certificate later using Pickup ID: %s\n\tStatus: %s", err.CertificateID, err.Status)
|
||||
}
|
||||
|
||||
// ZoneConfiguration provides a common structure for certificate request data provided by the remote endpoint
|
||||
type ZoneConfiguration struct {
|
||||
Organization string
|
||||
OrganizationLocked bool
|
||||
OrganizationalUnit []string
|
||||
Country string
|
||||
CountryLocked bool
|
||||
Province string
|
||||
ProvinceLocked bool
|
||||
Locality string
|
||||
LocalityLocked bool
|
||||
|
||||
// Policy is struct that contains restrictions for certificates. Most of the fields contains list of regular expression.
|
||||
// For satisfying policies, all values in the certificate field must match AT LEAST ONE regular expression in corresponding policy field.
|
||||
type Policy struct {
|
||||
SubjectCNRegexes []string
|
||||
SubjectORegexes []string
|
||||
SubjectOURegexes []string
|
||||
SubjectSTRegexes []string
|
||||
SubjectLRegexes []string
|
||||
SubjectCRegexes []string
|
||||
SANRegexes []string
|
||||
|
||||
// AllowedKeyConfigurations lists all allowed key configurations. Certificate key configuration have to be listed in this list.
|
||||
// For example: If key has type RSA and length 2048 bit for satisfying the policy, that list must contain AT LEAST ONE configuration with type RSA and value 2048 in KeySizes list of this configuration.
|
||||
AllowedKeyConfigurations []AllowedKeyConfiguration
|
||||
KeySizeLocked bool
|
||||
// DnsSanRegExs is a list of regular expressions that show allowable DNS names in SANs.
|
||||
DnsSanRegExs []string
|
||||
// IpSanRegExs is a list of regular expressions that show allowable DNS names in SANs.
|
||||
IpSanRegExs []string
|
||||
EmailSanRegExs []string
|
||||
UriSanRegExs []string
|
||||
UpnSanRegExs []string
|
||||
AllowWildcards bool
|
||||
AllowKeyReuse bool
|
||||
}
|
||||
|
||||
// ZoneConfiguration provides a common structure for certificate request data provided by the remote endpoint
|
||||
type ZoneConfiguration struct {
|
||||
Organization string
|
||||
OrganizationalUnit []string
|
||||
Country string
|
||||
Province string
|
||||
Locality string
|
||||
Policy
|
||||
|
||||
HashAlgorithm x509.SignatureAlgorithm
|
||||
|
||||
@@ -142,33 +160,34 @@ func NewZoneConfiguration() *ZoneConfiguration {
|
||||
return &zc
|
||||
}
|
||||
|
||||
// ValidateCertificateRequest validates the request against the zone configuration
|
||||
func (z *ZoneConfiguration) ValidateCertificateRequest(request *certificate.Request) error {
|
||||
if !isComponentValid(z.SubjectCNRegexes, []string{request.Subject.CommonName}) {
|
||||
// ValidateCertificateRequest validates the request against the Policy
|
||||
func (p *Policy) ValidateCertificateRequest(request *certificate.Request) error {
|
||||
if !isComponentValid(p.SubjectCNRegexes, []string{request.Subject.CommonName}) {
|
||||
return fmt.Errorf("The requested CN does not match any of the allowed CN regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SubjectORegexes, request.Subject.Organization) {
|
||||
if !isComponentValid(p.SubjectORegexes, request.Subject.Organization) {
|
||||
return fmt.Errorf("The requested Organization does not match any of the allowed Organization regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SubjectOURegexes, request.Subject.OrganizationalUnit) {
|
||||
if !isComponentValid(p.SubjectOURegexes, request.Subject.OrganizationalUnit) {
|
||||
return fmt.Errorf("The requested Organizational Unit does not match any of the allowed Organization Unit regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SubjectSTRegexes, request.Subject.Province) {
|
||||
if !isComponentValid(p.SubjectSTRegexes, request.Subject.Province) {
|
||||
return fmt.Errorf("The requested State/Province does not match any of the allowed State/Province regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SubjectLRegexes, request.Subject.Locality) {
|
||||
if !isComponentValid(p.SubjectLRegexes, request.Subject.Locality) {
|
||||
return fmt.Errorf("The requested Locality does not match any of the allowed Locality regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SubjectCRegexes, request.Subject.Country) {
|
||||
if !isComponentValid(p.SubjectCRegexes, request.Subject.Country) {
|
||||
return fmt.Errorf("The requested Country does not match any of the allowed Country regular expressions")
|
||||
}
|
||||
if !isComponentValid(z.SANRegexes, request.DNSNames) {
|
||||
if !isComponentValid(p.DnsSanRegExs, request.DNSNames) {
|
||||
return fmt.Errorf("The requested Subject Alternative Name does not match any of the allowed Country regular expressions")
|
||||
}
|
||||
//todo: add ip, email and over cheking
|
||||
|
||||
if z.AllowedKeyConfigurations != nil && len(z.AllowedKeyConfigurations) > 0 {
|
||||
if p.AllowedKeyConfigurations != nil && len(p.AllowedKeyConfigurations) > 0 {
|
||||
match := false
|
||||
for _, keyConf := range z.AllowedKeyConfigurations {
|
||||
for _, keyConf := range p.AllowedKeyConfigurations {
|
||||
if keyConf.KeyType == request.KeyType {
|
||||
if request.KeyLength > 0 {
|
||||
for _, size := range keyConf.KeySizes {
|
||||
@@ -194,88 +213,73 @@ func (z *ZoneConfiguration) ValidateCertificateRequest(request *certificate.Requ
|
||||
}
|
||||
|
||||
func isComponentValid(regexes []string, component []string) bool {
|
||||
if regexes != nil && len(regexes) > 0 && component != nil {
|
||||
regexOk := false
|
||||
for _, subReg := range regexes {
|
||||
matchedAny := false
|
||||
reg := regexp.MustCompile(subReg)
|
||||
for _, c := range component {
|
||||
if reg.FindStringIndex(c) != nil {
|
||||
matchedAny = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if matchedAny {
|
||||
regexOk = true
|
||||
if len(regexes) == 0 || len(component) == 0 {
|
||||
return true
|
||||
}
|
||||
regexOk := false
|
||||
for _, subReg := range regexes {
|
||||
matchedAny := false
|
||||
reg, err := regexp.Compile(subReg)
|
||||
if err != nil {
|
||||
log.Printf("Bad regexp: %s", subReg)
|
||||
return false
|
||||
}
|
||||
for _, c := range component {
|
||||
if reg.FindStringIndex(c) != nil {
|
||||
matchedAny = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return regexOk
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// UpdateCertificateRequest updates a certificate request based on the zone configurataion retrieved from the remote endpoint
|
||||
func (z *ZoneConfiguration) UpdateCertificateRequest(request *certificate.Request) {
|
||||
if (request.Subject.Organization == nil || len(request.Subject.Organization) == 0) && z.Organization != "" {
|
||||
request.Subject.Organization = []string{z.Organization}
|
||||
} else {
|
||||
if z.OrganizationLocked && !strings.EqualFold(request.Subject.Organization[0], z.Organization) {
|
||||
request.Subject.Organization = []string{z.Organization}
|
||||
if matchedAny {
|
||||
regexOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (request.Subject.OrganizationalUnit == nil || len(request.Subject.OrganizationalUnit) == 0) && z.OrganizationalUnit != nil {
|
||||
return regexOk
|
||||
}
|
||||
|
||||
// UpdateCertificateRequest updates a certificate request based on the zone configuration retrieved from the remote endpoint
|
||||
func (z *ZoneConfiguration) UpdateCertificateRequest(request *certificate.Request) {
|
||||
if len(request.Subject.Organization) == 0 && z.Organization != "" {
|
||||
request.Subject.Organization = []string{z.Organization}
|
||||
}
|
||||
|
||||
if len(request.Subject.OrganizationalUnit) == 0 && z.OrganizationalUnit != nil {
|
||||
request.Subject.OrganizationalUnit = z.OrganizationalUnit
|
||||
}
|
||||
|
||||
if (request.Subject.Country == nil || len(request.Subject.Country) == 0) && z.Country != "" {
|
||||
if len(request.Subject.Country) == 0 && z.Country != "" {
|
||||
request.Subject.Country = []string{z.Country}
|
||||
} else {
|
||||
if z.CountryLocked && !strings.EqualFold(request.Subject.Country[0], z.Country) {
|
||||
request.Subject.Country = []string{z.Country}
|
||||
}
|
||||
}
|
||||
if (request.Subject.Province == nil || len(request.Subject.Province) == 0) && z.Province != "" {
|
||||
|
||||
if len(request.Subject.Province) == 0 && z.Province != "" {
|
||||
request.Subject.Province = []string{z.Province}
|
||||
} else {
|
||||
if z.ProvinceLocked && !strings.EqualFold(request.Subject.Province[0], z.Province) {
|
||||
request.Subject.Province = []string{z.Province}
|
||||
}
|
||||
}
|
||||
if (request.Subject.Locality == nil || len(request.Subject.Locality) == 0) && z.Locality != "" {
|
||||
|
||||
if len(request.Subject.Locality) == 0 && z.Locality != "" {
|
||||
request.Subject.Locality = []string{z.Locality}
|
||||
} else {
|
||||
if z.LocalityLocked && !strings.EqualFold(request.Subject.Locality[0], z.Locality) {
|
||||
request.Subject.Locality = []string{z.Locality}
|
||||
}
|
||||
}
|
||||
if z.HashAlgorithm != 0 {
|
||||
|
||||
if z.HashAlgorithm != x509.UnknownSignatureAlgorithm {
|
||||
request.SignatureAlgorithm = z.HashAlgorithm
|
||||
} else {
|
||||
request.SignatureAlgorithm = x509.SHA256WithRSA
|
||||
}
|
||||
|
||||
if z.KeySizeLocked {
|
||||
for _, keyConf := range z.AllowedKeyConfigurations {
|
||||
if keyConf.KeyType == request.KeyType {
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(keyConf.KeySizes)))
|
||||
request.KeyLength = keyConf.KeySizes[0]
|
||||
}
|
||||
}
|
||||
} else if z.AllowedKeyConfigurations != nil {
|
||||
if len(z.AllowedKeyConfigurations) != 0 {
|
||||
foundMatch := false
|
||||
for _, keyConf := range z.AllowedKeyConfigurations {
|
||||
if keyConf.KeyType == request.KeyType {
|
||||
foundMatch = true
|
||||
switch request.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
if z.AllowedKeyConfigurations[0].KeyCurves != nil {
|
||||
request.KeyCurve = z.AllowedKeyConfigurations[0].KeyCurves[0]
|
||||
if len(keyConf.KeyCurves) != 0 {
|
||||
request.KeyCurve = keyConf.KeyCurves[0]
|
||||
} else {
|
||||
request.KeyCurve = certificate.EllipticCurveP256
|
||||
request.KeyCurve = certificate.EllipticCurveDefault
|
||||
}
|
||||
case certificate.KeyTypeRSA:
|
||||
if keyConf.KeySizes != nil {
|
||||
if len(keyConf.KeySizes) != 0 {
|
||||
sizeOK := false
|
||||
for _, size := range keyConf.KeySizes {
|
||||
if size == request.KeyLength {
|
||||
@@ -293,18 +297,19 @@ func (z *ZoneConfiguration) UpdateCertificateRequest(request *certificate.Reques
|
||||
}
|
||||
}
|
||||
if !foundMatch {
|
||||
request.KeyType = z.AllowedKeyConfigurations[0].KeyType
|
||||
configuration := z.AllowedKeyConfigurations[0]
|
||||
request.KeyType = configuration.KeyType
|
||||
switch request.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
if z.AllowedKeyConfigurations[0].KeyCurves != nil {
|
||||
request.KeyCurve = z.AllowedKeyConfigurations[0].KeyCurves[0]
|
||||
if len(configuration.KeyCurves) != 0 {
|
||||
request.KeyCurve = configuration.KeyCurves[0]
|
||||
} else {
|
||||
request.KeyCurve = certificate.EllipticCurveP256
|
||||
request.KeyCurve = certificate.EllipticCurveDefault
|
||||
}
|
||||
case certificate.KeyTypeRSA:
|
||||
if z.AllowedKeyConfigurations[0].KeySizes != nil {
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(z.AllowedKeyConfigurations[0].KeySizes)))
|
||||
request.KeyLength = z.AllowedKeyConfigurations[0].KeySizes[0]
|
||||
if len(configuration.KeySizes) != 0 {
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(configuration.KeySizes)))
|
||||
request.KeyLength = configuration.KeySizes[0]
|
||||
} else {
|
||||
request.KeyLength = 2048
|
||||
}
|
||||
@@ -316,6 +321,4 @@ func (z *ZoneConfiguration) UpdateCertificateRequest(request *certificate.Reques
|
||||
request.KeyLength = 2048
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
+85
-13
@@ -16,14 +16,19 @@
|
||||
|
||||
package cloud
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type certificatePolicy struct {
|
||||
CertificatePolicyType certificatePolicyType `json:"certificatePolicyType,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
CompanyID string `json:"companyId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
SystemGenerated bool `json:"systemGeneratedate,omitempty"`
|
||||
SystemGenerated bool `json:"systemGenerated,omitempty"`
|
||||
CreationDateString string `json:"creationDate,omitempty"`
|
||||
CreationDate time.Time `json:"-"`
|
||||
CertificateProviderID string `json:"certificateProviderId,omitempty"`
|
||||
@@ -32,7 +37,7 @@ type certificatePolicy struct {
|
||||
SubjectOURegexes []string `json:"subjectOURegexes,omitempty"`
|
||||
SubjectSTRegexes []string `json:"subjectSTRegexes,omitempty"`
|
||||
SubjectLRegexes []string `json:"subjectLRegexes,omitempty"`
|
||||
SubjectCRegexes []string `json:"subjectCRegexes,omitempty"`
|
||||
SubjectCRegexes []string `json:"subjectCValues,omitempty"`
|
||||
SANRegexes []string `json:"sanRegexes,omitempty"`
|
||||
KeyTypes []allowedKeyType `json:"keyTypes,omitempty"`
|
||||
KeyReuse bool `json:"keyReuse,omitempty"`
|
||||
@@ -47,20 +52,87 @@ type certificatePolicyType string
|
||||
|
||||
const (
|
||||
certificatePolicyTypeIdentity certificatePolicyType = "CERTIFICATE_IDENTITY"
|
||||
certificatePolicyTypeUse = "CERTIFICATE_USE"
|
||||
certificatePolicyTypeUse certificatePolicyType = "CERTIFICATE_USE"
|
||||
)
|
||||
|
||||
type keyType string
|
||||
|
||||
const (
|
||||
keyTypeRSA keyType = "RSA"
|
||||
keyTypeDSA = "DSA"
|
||||
keyTypeEC = "EC"
|
||||
keyTypeGost3410 = "GOST3410"
|
||||
keyTypeECGost3410 = "ECGOST3410"
|
||||
keyTypeReserved3 = "RESERVED3"
|
||||
keyTypeUnknown = "UNKNOWN"
|
||||
)
|
||||
func (cp certificatePolicy) toPolicy() (p endpoint.Policy) {
|
||||
addStartEnd := func(s string) string {
|
||||
if !strings.HasPrefix(s, "^") {
|
||||
s = "^" + s
|
||||
}
|
||||
if !strings.HasSuffix(s, "$") {
|
||||
s = s + "$"
|
||||
}
|
||||
return s
|
||||
}
|
||||
addStartEndToArray := func(ss []string) []string {
|
||||
a := make([]string, len(ss))
|
||||
for i, s := range ss {
|
||||
a[i] = addStartEnd(s)
|
||||
}
|
||||
return a
|
||||
}
|
||||
p.SubjectCNRegexes = addStartEndToArray(cp.SubjectCNRegexes)
|
||||
p.SubjectOURegexes = addStartEndToArray(cp.SubjectOURegexes)
|
||||
p.SubjectCRegexes = addStartEndToArray(cp.SubjectCRegexes)
|
||||
p.SubjectSTRegexes = addStartEndToArray(cp.SubjectSTRegexes)
|
||||
p.SubjectLRegexes = addStartEndToArray(cp.SubjectLRegexes)
|
||||
p.SubjectORegexes = addStartEndToArray(cp.SubjectORegexes)
|
||||
p.DnsSanRegExs = addStartEndToArray(cp.SANRegexes)
|
||||
p.AllowKeyReuse = cp.KeyReuse
|
||||
allowWildCards := false
|
||||
for _, s := range p.SubjectCNRegexes {
|
||||
if strings.HasPrefix(s, "^.*") {
|
||||
allowWildCards = true
|
||||
}
|
||||
}
|
||||
if !allowWildCards {
|
||||
for _, s := range p.DnsSanRegExs {
|
||||
if strings.HasPrefix(s, "^.*") {
|
||||
allowWildCards = true
|
||||
}
|
||||
}
|
||||
}
|
||||
p.AllowWildcards = allowWildCards
|
||||
for _, kt := range cp.KeyTypes {
|
||||
keyConfiguration := endpoint.AllowedKeyConfiguration{}
|
||||
if err := keyConfiguration.KeyType.Set(string(kt.KeyType)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyConfiguration.KeySizes = kt.KeyLengths[:]
|
||||
p.AllowedKeyConfigurations = append(p.AllowedKeyConfigurations, keyConfiguration)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isNotRegexp(s string) bool {
|
||||
matched, err := regexp.MatchString(`[a-zA-Z0-9 ]+`, s)
|
||||
if !matched || err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (cp certificatePolicy) toZoneConfig(zc *endpoint.ZoneConfiguration) {
|
||||
if len(cp.SubjectCRegexes) > 0 && isNotRegexp(cp.SubjectCRegexes[0]) {
|
||||
zc.Country = cp.SubjectCRegexes[0]
|
||||
}
|
||||
if len(cp.SubjectORegexes) > 0 && isNotRegexp(cp.SubjectORegexes[0]) {
|
||||
zc.Organization = cp.SubjectORegexes[0]
|
||||
}
|
||||
if len(cp.SubjectSTRegexes) > 0 && isNotRegexp(cp.SubjectSTRegexes[0]) {
|
||||
zc.Province = cp.SubjectSTRegexes[0]
|
||||
}
|
||||
if len(cp.SubjectLRegexes) > 0 && isNotRegexp(cp.SubjectLRegexes[0]) {
|
||||
zc.Locality = cp.SubjectLRegexes[0]
|
||||
}
|
||||
for _, ou := range cp.SubjectOURegexes {
|
||||
if isNotRegexp(ou) {
|
||||
zc.OrganizationalUnit = append(zc.OrganizationalUnit, ou)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
"signatureAlgorithm":{"type":"string","enum":["MD2_WITH_RSA_ENCRYPTION","MD5_WITH_RSA_ENCRYPTION","SHA1_WITH_RSA_ENCRYPTION","SHA1_WITH_RSA_ENCRYPTION2","SHA256_WITH_RSA_ENCRYPTION","SHA384_WITH_RSA_ENCRYPTION","SHA512_WITH_RSA_ENCRYPTION","ID_DSA_WITH_SHA1","dsaWithSHA1","EC_DSA_WITH_SHA1","EC_DSA_WITH_SHA224","EC_DSA_WITH_SHA256","EC_DSA_WITH_SHA384","EC_DSA_WITH_SHA512","UNKNOWN","SHA1_WITH_RSAandMGF1","GOST_R3411_94_WITH_GOST_R3410_2001","GOST_R3411_94_WITH_GOST_R3410_94"]},
|
||||
|
||||
+113
-47
@@ -17,15 +17,19 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
type apiKey struct {
|
||||
@@ -93,13 +97,49 @@ type CertificateStatusErrorInformation struct {
|
||||
Args []string `json:"args,omitempty"`
|
||||
}
|
||||
|
||||
type importRequestEndpointCert struct {
|
||||
Certificate string `json:"certificate"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
}
|
||||
|
||||
type importRequestEndpointProtocol struct {
|
||||
Certificates []string `json:"certificates"`
|
||||
Ciphers []interface{} `json:"ciphers"` //todo: check type
|
||||
Protocol string `json:"protocol"`
|
||||
}
|
||||
|
||||
type importRequestEndpoint struct {
|
||||
Alpn bool `json:"alpn"`
|
||||
Certificates []importRequestEndpointCert `json:"certificates"`
|
||||
ClientRenegotiation bool `json:"clientRenegotiation"`
|
||||
Drown bool `json:"drown"`
|
||||
Heartbleed bool `json:"heartbleed"`
|
||||
Host string `json:"host"`
|
||||
HSTS bool `json:"hsts"`
|
||||
IP string `json:"ip"`
|
||||
LogJam int `json:"logJam"`
|
||||
Npn bool `json:"npn"`
|
||||
OCSP int `json:"ocsp"` //default 1
|
||||
Poodle bool `json:"poodle"`
|
||||
PoodleTls bool `json:"poodleTls"`
|
||||
Port int `json:"port"`
|
||||
Protocols []importRequestEndpointProtocol `json:"protocols"`
|
||||
SecureRenegotiation bool `json:"secureRenegotiation"`
|
||||
Sloth bool `json:"sloth"`
|
||||
}
|
||||
|
||||
type importRequest struct {
|
||||
ZoneName string `json:"zoneName"`
|
||||
NetworkID string `json:"networkId"`
|
||||
Endpoints []importRequestEndpoint `json:"endpoints"`
|
||||
}
|
||||
|
||||
//GenerateRequest generates a CertificateRequest based on the zone configuration, and returns the request along with the private key.
|
||||
func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *certificate.Request) (err error) {
|
||||
switch req.CsrOrigin {
|
||||
case certificate.LocalGeneratedCSR:
|
||||
var pk interface{}
|
||||
if config == nil {
|
||||
config, err = c.ReadZoneConfiguration(c.zone)
|
||||
config, err = c.ReadZoneConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read zone configuration: %s", err)
|
||||
}
|
||||
@@ -109,33 +149,18 @@ func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *cer
|
||||
return err
|
||||
}
|
||||
config.UpdateCertificateRequest(req)
|
||||
switch req.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
pk, err = certificate.GenerateECDSAPrivateKey(req.KeyCurve)
|
||||
case certificate.KeyTypeRSA:
|
||||
pk, err = certificate.GenerateRSAPrivateKey(req.KeyLength)
|
||||
default:
|
||||
return fmt.Errorf("Unable to generate certificate request, key type %s is not supported", req.KeyType.String())
|
||||
}
|
||||
if err != nil {
|
||||
if err := req.GeneratePrivateKey(); err != nil {
|
||||
return err
|
||||
}
|
||||
req.PrivateKey = pk
|
||||
err = certificate.GenerateRequest(req, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.CSR = pem.EncodeToMemory(certificate.GetCertificateRequestPEMBlock(req.CSR))
|
||||
return nil
|
||||
|
||||
err = req.GenerateCSR()
|
||||
return
|
||||
case certificate.UserProvidedCSR:
|
||||
if req.CSR == nil || len(req.CSR) == 0 {
|
||||
if len(req.GetCSR()) == 0 {
|
||||
return fmt.Errorf("CSR was supposed to be provided by user, but it's empty")
|
||||
}
|
||||
return nil
|
||||
|
||||
case certificate.ServiceGeneratedCSR:
|
||||
req.CSR = nil
|
||||
return nil
|
||||
|
||||
default:
|
||||
@@ -143,32 +168,68 @@ func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *cer
|
||||
}
|
||||
}
|
||||
|
||||
//SetBaseURL allows overriding the default URL used to communicate with Venafi Cloud
|
||||
func (c *Connector) SetBaseURL(url string) error {
|
||||
if url == "" {
|
||||
return fmt.Errorf("base URL cannot be empty")
|
||||
}
|
||||
modified := strings.ToLower(url)
|
||||
reg := regexp.MustCompile("^http(|s)://")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified = "https://" + modified
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "https://")
|
||||
}
|
||||
reg = regexp.MustCompile("/v1(|/)$")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified += "v1/"
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "/v1/")
|
||||
}
|
||||
c.baseURL = modified
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Connector) getURL(resource urlResource) string {
|
||||
return fmt.Sprintf("%s%s", c.baseURL, resource)
|
||||
}
|
||||
|
||||
func (c *Connector) request(method string, url string, data interface{}, authNotRequired ...bool) (statusCode int, statusText string, body []byte, err error) {
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
if !(len(authNotRequired) == 1 && authNotRequired[0]) {
|
||||
err = fmt.Errorf("Must be autheticated to retieve certificate")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var payload io.Reader
|
||||
var b []byte
|
||||
if method == "POST" {
|
||||
b, _ = json.Marshal(data)
|
||||
payload = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
r, err := http.NewRequest(method, url, payload)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.apiKey != "" {
|
||||
r.Header.Add("tppl-api-key", c.apiKey)
|
||||
}
|
||||
if method == "POST" {
|
||||
r.Header.Add("Accept", "application/json")
|
||||
r.Header.Add("content-type", "application/json")
|
||||
} else {
|
||||
r.Header.Add("Accept", "*/*")
|
||||
}
|
||||
r.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := http.DefaultClient.Do(r)
|
||||
if res != nil {
|
||||
statusCode = res.StatusCode
|
||||
statusText = res.Status
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, err = ioutil.ReadAll(res.Body)
|
||||
// Do not enable trace in production
|
||||
trace := false // IMPORTANT: sensitive information can be diclosured
|
||||
// I hope you know what are you doing
|
||||
if trace {
|
||||
log.Println("#################")
|
||||
if method == "POST" {
|
||||
log.Printf("JSON sent for %s\n%s\n", url, string(b))
|
||||
} else {
|
||||
log.Printf("%s request sent to %s\n", method, url)
|
||||
}
|
||||
log.Printf("Response:\n%s\n", string(body))
|
||||
} else if c.verbose {
|
||||
log.Printf("Got %s status for %s %s\n", statusText, method, url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseUserDetailsResult(expectedStatusCode int, httpStatusCode int, httpStatus string, body []byte) (*userDetails, error) {
|
||||
if httpStatusCode == expectedStatusCode {
|
||||
resp, err := parseUserDetailsData(body)
|
||||
@@ -350,3 +411,8 @@ func parseCertificateRequestData(b []byte) (*certificateRequestResponse, error)
|
||||
func newPEMCollectionFromResponse(data []byte, chainOrder certificate.ChainOption) (*certificate.PEMCollection, error) {
|
||||
return certificate.PEMCollectionFromBytes(data, chainOrder)
|
||||
}
|
||||
|
||||
func certThumprint(asn1 []byte) string {
|
||||
h := sha1.Sum(asn1)
|
||||
return strings.ToUpper(fmt.Sprintf("%x", h))
|
||||
}
|
||||
|
||||
+8
-20
@@ -17,8 +17,6 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"time"
|
||||
)
|
||||
@@ -41,7 +39,7 @@ type zone struct {
|
||||
CertificatePolicyIDs certificatePolicyID `json:"certificatePolicyIds,omitempty"`
|
||||
DefaultCertificateIdentityPolicy string `json:"defaultCertificateIdentityPolicyId,omitempty"`
|
||||
DefaultCertificateUsePolicy string `json:"defaultCertificateUsePolicyId,omitempty"`
|
||||
SystemGenerated bool `json:"systemGeneratedate,omitempty"`
|
||||
SystemGenerated bool `json:"systemGenerated,omitempty"`
|
||||
CreationDateString string `json:"creationDate,omitempty"`
|
||||
CreationDate time.Time `json:"-"`
|
||||
}
|
||||
@@ -51,24 +49,14 @@ type certificatePolicyID struct {
|
||||
CertificateUse []string `json:"CERTIFICATE_USE,omitempty"`
|
||||
}
|
||||
|
||||
func (z *zone) GetZoneConfiguration(ud *userDetails, policy *certificatePolicy) *endpoint.ZoneConfiguration {
|
||||
zoneConfig := endpoint.ZoneConfiguration{}
|
||||
|
||||
if policy != nil {
|
||||
if policy.KeyTypes != nil {
|
||||
certKeyType := certificate.KeyTypeRSA
|
||||
for _, kt := range policy.KeyTypes {
|
||||
certKeyType.Set(fmt.Sprintf("%s", kt.KeyType))
|
||||
keyConfiguration := endpoint.AllowedKeyConfiguration{}
|
||||
keyConfiguration.KeyType = certKeyType
|
||||
for _, size := range kt.KeyLengths {
|
||||
keyConfiguration.KeySizes = append(keyConfiguration.KeySizes, size)
|
||||
}
|
||||
zoneConfig.AllowedKeyConfigurations = append(zoneConfig.AllowedKeyConfigurations, keyConfiguration)
|
||||
}
|
||||
}
|
||||
func (z *zone) getZoneConfiguration(ud *userDetails, policy *certificatePolicy) (zoneConfig *endpoint.ZoneConfiguration) {
|
||||
zoneConfig = endpoint.NewZoneConfiguration()
|
||||
if policy == nil {
|
||||
return
|
||||
}
|
||||
return &zoneConfig
|
||||
zoneConfig.Policy = policy.toPolicy()
|
||||
policy.toZoneConfig(zoneConfig)
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
+251
-331
@@ -17,17 +17,18 @@
|
||||
package cloud
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
const apiURL = "api.venafi.cloud/v1/"
|
||||
@@ -35,26 +36,29 @@ const apiURL = "api.venafi.cloud/v1/"
|
||||
type urlResource string
|
||||
|
||||
const (
|
||||
urlResourceUserAccounts urlResource = "useraccounts"
|
||||
urlResourcePing = "ping"
|
||||
urlResourceZones = "zones"
|
||||
urlResourceZoneByTag = urlResourceZones + "/tag/%s"
|
||||
urlResourceCertificatePolicies = "certificatepolicies"
|
||||
urlResourcePoliciesByID = urlResourceCertificatePolicies + "%s"
|
||||
urlResourcePoliciesForZoneByID = urlResourceCertificatePolicies + "?zoneId=%s"
|
||||
urlResourceCertificateRequests = "certificaterequests"
|
||||
urlResourceCertificateStatus = urlResourceCertificateRequests + "/%s"
|
||||
urlResourceCertificateRetrieve = urlResourceCertificateRequests + "/%s/certificate"
|
||||
urlResourceCertificateSearch = "certificatesearch"
|
||||
urlResourceManagedCertificates = "managedcertificates"
|
||||
urlResourceManagedCertificateById = urlResourceManagedCertificates + "/%s"
|
||||
urlResourceUserAccounts urlResource = "useraccounts"
|
||||
urlResourcePing = "ping"
|
||||
urlResourceZones = "zones"
|
||||
urlResourceZoneByTag = urlResourceZones + "/tag/%s"
|
||||
urlResourceCertificatePolicies = "certificatepolicies"
|
||||
urlResourcePoliciesByID = urlResourceCertificatePolicies + "/%s"
|
||||
urlResourcePoliciesForZoneByID = urlResourceCertificatePolicies + "?zoneId=%s"
|
||||
urlResourceCertificateRequests = "certificaterequests"
|
||||
urlResourceCertificateStatus = urlResourceCertificateRequests + "/%s"
|
||||
urlResourceCertificateRetrieveViaCSR = urlResourceCertificateRequests + "/%s/certificate"
|
||||
urlResourceCertificateRetrieve = "certificates/%s"
|
||||
urlResourceCertificateRetrievePem = urlResourceCertificateRetrieve + "/encoded"
|
||||
urlResourceCertificateSearch = "certificatesearch"
|
||||
urlResourceManagedCertificates = "managedcertificates"
|
||||
urlResourceManagedCertificateByID = urlResourceManagedCertificates + "/%s"
|
||||
urlResourceDiscovery = "discovery"
|
||||
)
|
||||
|
||||
type condorChainOption string
|
||||
|
||||
const (
|
||||
condorChainOptionRootFirst condorChainOption = "ROOT_FIRST"
|
||||
condorChainOptionRootLast = "EE_FIRST"
|
||||
condorChainOptionRootLast condorChainOption = "EE_FIRST"
|
||||
)
|
||||
|
||||
// Connector contains the base data needed to communicate with the Venafi Cloud servers
|
||||
@@ -68,10 +72,37 @@ type Connector struct {
|
||||
}
|
||||
|
||||
// NewConnector creates a new Venafi Cloud Connector object used to communicate with Venafi Cloud
|
||||
func NewConnector(verbose bool, trust *x509.CertPool) *Connector {
|
||||
c := Connector{verbose: verbose, trust: trust}
|
||||
c.SetBaseURL(apiURL)
|
||||
return &c
|
||||
func NewConnector(url string, zone string, verbose bool, trust *x509.CertPool) (*Connector, error) {
|
||||
c := Connector{verbose: verbose, trust: trust, zone: zone}
|
||||
var err error
|
||||
c.baseURL, err = normalizeURL(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
//normalizeURL allows overriding the default URL used to communicate with Venafi Cloud
|
||||
func normalizeURL(url string) (normalizedURL string, err error) {
|
||||
if url == "" {
|
||||
url = apiURL
|
||||
//return "", fmt.Errorf("base URL cannot be empty")
|
||||
}
|
||||
modified := strings.ToLower(url)
|
||||
reg := regexp.MustCompile("^http(|s)://")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified = "https://" + modified
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "https://")
|
||||
}
|
||||
reg = regexp.MustCompile("/v1(|/)$")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified += "v1/"
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "/v1/")
|
||||
}
|
||||
normalizedURL = modified
|
||||
return normalizedURL, nil
|
||||
}
|
||||
|
||||
func (c *Connector) SetZone(z string) {
|
||||
@@ -82,108 +113,59 @@ func (c *Connector) GetType() endpoint.ConnectorType {
|
||||
return endpoint.ConnectorTypeCloud
|
||||
}
|
||||
|
||||
//Ping attempts to connect to the Venafi Cloud API and returns an errror if it cannot
|
||||
// Ping attempts to connect to the Venafi Cloud API and returns an errror if it cannot
|
||||
func (c *Connector) Ping() (err error) {
|
||||
url := c.getURL(urlResourcePing)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = fmt.Errorf("Unexpected status code on Venafi Cloud ping. Status: %d %s", resp.StatusCode, resp.Status)
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
//Authenticate authenticates the user with Venafi Cloud using the provided API Key
|
||||
// Authenticate authenticates the user with Venafi Cloud using the provided API Key
|
||||
func (c *Connector) Authenticate(auth *endpoint.Authentication) (err error) {
|
||||
if auth == nil {
|
||||
return fmt.Errorf("failed to authenticate: missing credentials")
|
||||
}
|
||||
c.apiKey = auth.APIKey
|
||||
url := c.getURL(urlResourceUserAccounts)
|
||||
b := []byte{}
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("GET", url, reader)
|
||||
statusCode, status, body, err := c.request("GET", url, nil, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
ud, err := parseUserDetailsResult(http.StatusOK, statusCode, status, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ud, err := parseUserDetailsResult(http.StatusOK, resp.StatusCode, resp.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
|
||||
return err
|
||||
return
|
||||
}
|
||||
c.user = ud
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
//Register registers a new user with Venafi Cloud
|
||||
func (c *Connector) Register(email string) (err error) {
|
||||
b, err := json.Marshal(userAccount{Username: email, UserAccountType: "API"})
|
||||
|
||||
url := c.getURL(urlResourceUserAccounts)
|
||||
|
||||
reader := bytes.NewReader(b)
|
||||
resp, err := http.Post(url, "application/json", reader)
|
||||
func (c *Connector) ReadPolicyConfiguration() (policy *endpoint.Policy, err error) {
|
||||
config, err := c.ReadZoneConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//the user has already been registered and there is nothing to parse
|
||||
if resp.StatusCode == http.StatusAccepted {
|
||||
return nil
|
||||
}
|
||||
ud, err := parseUserDetailsResult(http.StatusCreated, resp.StatusCode, resp.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
c.user = ud
|
||||
return nil
|
||||
policy = &config.Policy
|
||||
return
|
||||
}
|
||||
|
||||
//ReadZoneConfiguration reads the Zone information needed for generating and requesting a certificate from Venafi Cloud
|
||||
func (c *Connector) ReadZoneConfiguration(zone string) (config *endpoint.ZoneConfiguration, err error) {
|
||||
z, err := c.getZoneByTag(zone)
|
||||
// ReadZoneConfiguration reads the Zone information needed for generating and requesting a certificate from Venafi Cloud
|
||||
func (c *Connector) ReadZoneConfiguration() (config *endpoint.ZoneConfiguration, err error) {
|
||||
if c.zone == "" {
|
||||
return nil, fmt.Errorf("empty zone name")
|
||||
}
|
||||
z, err := c.getZoneByTag(c.zone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, err := c.getPoliciesByID([]string{z.DefaultCertificateIdentityPolicy, z.DefaultCertificateUsePolicy})
|
||||
config = z.GetZoneConfiguration(c.user, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = z.getZoneConfiguration(c.user, p)
|
||||
return config, nil
|
||||
}
|
||||
|
||||
//RequestCertificate submits the CSR to the Venafi Cloud API for processing
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (requestID string, err error) {
|
||||
|
||||
if zone == "" {
|
||||
zone = c.zone
|
||||
}
|
||||
|
||||
// RequestCertificate submits the CSR to the Venafi Cloud API for processing
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request) (requestID string, err error) {
|
||||
if req.CsrOrigin == certificate.ServiceGeneratedCSR {
|
||||
return "", fmt.Errorf("service generated CSR is not supported by Saas service")
|
||||
}
|
||||
@@ -192,34 +174,18 @@ func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (r
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
return "", fmt.Errorf("Must be autheticated to request a certificate")
|
||||
}
|
||||
z, err := c.getZoneByTag(zone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
b, _ := json.Marshal(certificateRequest{ZoneID: z.ID, CSR: string(req.CSR)})
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("POST", url, reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("content-type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
z, err := c.getZoneByTag(c.zone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cr, err := parseCertificateRequestResult(resp.StatusCode, resp.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
statusCode, status, body, err := c.request("POST", url, certificateRequest{ZoneID: z.ID, CSR: string(req.GetCSR())})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cr, err := parseCertificateRequestResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
requestID = cr.CertificateRequests[0].ID
|
||||
@@ -227,61 +193,41 @@ func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (r
|
||||
return requestID, nil
|
||||
}
|
||||
|
||||
func (c *Connector) getCertificateStatus(requestID string) (*certificateStatus, error) {
|
||||
var err error
|
||||
func (c *Connector) getCertificateStatus(requestID string) (certStatus *certificateStatus, err error) {
|
||||
url := c.getURL(urlResourceCertificateStatus)
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
err = fmt.Errorf("Must be autheticated to retieve certificate")
|
||||
return nil, err
|
||||
}
|
||||
url = fmt.Sprintf(url, requestID)
|
||||
|
||||
b := []byte{}
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("GET", url, reader)
|
||||
statusCode, _, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("Accept", "application/json")
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
var data = &certificateStatus{}
|
||||
err = json.Unmarshal(body, data)
|
||||
if statusCode == http.StatusOK {
|
||||
certStatus = &certificateStatus{}
|
||||
err = json.Unmarshal(body, certStatus)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse certificate request status response: %s", err)
|
||||
}
|
||||
return data, nil
|
||||
default:
|
||||
if body != nil {
|
||||
respErrors, err := parseResponseErrors(body)
|
||||
if err == nil {
|
||||
respError := fmt.Sprintf("Unexpected status code on Venafi Cloud certificate search. Status: %d\n", resp.StatusCode)
|
||||
for _, e := range respErrors {
|
||||
respError += fmt.Sprintf("Error Code: %d Error: %s\n", e.Code, e.Message)
|
||||
}
|
||||
return nil, fmt.Errorf(respError)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Unexpected status code on Venafi Cloud certificate search. Status: %d", resp.StatusCode)
|
||||
return
|
||||
}
|
||||
respErrors, err := parseResponseErrors(body)
|
||||
if err == nil {
|
||||
respError := fmt.Sprintf("Unexpected status code on Venafi Cloud certificate search. Status: %d\n", statusCode)
|
||||
for _, e := range respErrors {
|
||||
respError += fmt.Sprintf("Error Code: %d Error: %s\n", e.Code, e.Message)
|
||||
}
|
||||
return nil, fmt.Errorf(respError)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Unexpected status code on Venafi Cloud certificate search. Status: %d", statusCode)
|
||||
|
||||
}
|
||||
|
||||
//RetrieveCertificate retrieves the certificate for the specified ID
|
||||
// RetrieveCertificate retrieves the certificate for the specified ID
|
||||
func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error) {
|
||||
|
||||
if req.FetchPrivateKey {
|
||||
return nil, fmt.Errorf("Failed to retrieve private key from Venafi Cloud service: not supported")
|
||||
}
|
||||
|
||||
if req.PickupID == "" && req.Thumbprint != "" {
|
||||
if req.PickupID == "" && req.CertID == "" && req.Thumbprint != "" {
|
||||
// search cert by Thumbprint and fill pickupID
|
||||
var certificateRequestId string
|
||||
searchResult, err := c.searchCertificatesByFingerprint(req.Thumbprint)
|
||||
@@ -299,7 +245,12 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates
|
||||
if certificateRequestId != "" && certificateRequestId != c.CertificateRequestId {
|
||||
isOnlyOneCertificateRequestId = false
|
||||
}
|
||||
certificateRequestId = c.CertificateRequestId
|
||||
if c.CertificateRequestId != "" {
|
||||
certificateRequestId = c.CertificateRequestId
|
||||
}
|
||||
if c.Id != "" {
|
||||
req.CertID = c.Id
|
||||
}
|
||||
}
|
||||
if !isOnlyOneCertificateRequestId {
|
||||
return nil, fmt.Errorf("More than one CertificateRequestId was found with the same Fingerprint: %s", reqIds)
|
||||
@@ -309,66 +260,78 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
for {
|
||||
status, err := c.getCertificateStatus(req.PickupID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to retrieve: %s", err)
|
||||
//Wait for certificate to be issued by checking it's PickupID
|
||||
//If certID is filled then certificate should be already issued.
|
||||
if req.CertID == "" {
|
||||
for {
|
||||
if req.PickupID == "" {
|
||||
break
|
||||
}
|
||||
status, err := c.getCertificateStatus(req.PickupID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to retrieve: %s", err)
|
||||
}
|
||||
if status.Status == "ISSUED" {
|
||||
break // to fetch the cert itself
|
||||
} else if status.Status == "FAILED" {
|
||||
return nil, fmt.Errorf("Failed to retrieve certificate. Status: %v", status)
|
||||
}
|
||||
// status.Status == "REQUESTED" || status.Status == "PENDING"
|
||||
if req.Timeout == 0 {
|
||||
return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID, Status: status.Status}
|
||||
}
|
||||
if time.Now().After(startTime.Add(req.Timeout)) {
|
||||
return nil, endpoint.ErrRetrieveCertificateTimeout{CertificateID: req.PickupID}
|
||||
}
|
||||
// fmt.Printf("pending... %s\n", status.Status)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
if status.Status == "ISSUED" {
|
||||
break // to fetch the cert itself
|
||||
} else if status.Status == "FAILED" {
|
||||
return nil, fmt.Errorf("Failed to retrieve certificate. Status: %v", status)
|
||||
}
|
||||
// status.Status == "REQUESTED" || status.Status == "PENDING"
|
||||
if req.Timeout == 0 {
|
||||
return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID, Status: status.Status}
|
||||
}
|
||||
if time.Now().After(startTime.Add(req.Timeout)) {
|
||||
return nil, endpoint.ErrRetrieveCertificateTimeout{CertificateID: req.PickupID}
|
||||
}
|
||||
// fmt.Printf("pending... %s\n", status.Status)
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
url := c.getURL(urlResourceCertificateRetrieve)
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
return nil, fmt.Errorf("Must be autheticated to retieve certificate")
|
||||
}
|
||||
url = fmt.Sprintf(url, req.PickupID)
|
||||
url += "?chainOrder=%s&format=PEM"
|
||||
switch req.ChainOption {
|
||||
case certificate.ChainOptionRootFirst:
|
||||
url = fmt.Sprintf(url, condorChainOptionRootFirst)
|
||||
default:
|
||||
url = fmt.Sprintf(url, condorChainOptionRootLast)
|
||||
}
|
||||
b := []byte{}
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("GET", url, reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("Accept", "text/plain")
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return newPEMCollectionFromResponse(body, req.ChainOption)
|
||||
} else if resp.StatusCode == http.StatusConflict { // Http Status Code 409 means the certificate has not been signed by the ca yet.
|
||||
return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID}
|
||||
} else {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
|
||||
switch {
|
||||
case req.CertID != "":
|
||||
url := c.getURL(urlResourceCertificateRetrievePem)
|
||||
url = fmt.Sprintf(url, req.CertID)
|
||||
statusCode, status, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Failed to retrieve certificate. StatusCode: %d -- Status: %s -- Server Data: %s", statusCode, status, body)
|
||||
}
|
||||
return newPEMCollectionFromResponse(body, certificate.ChainOptionIgnore)
|
||||
case req.PickupID != "":
|
||||
url := c.getURL(urlResourceCertificateRetrieveViaCSR)
|
||||
url = fmt.Sprintf(url, req.PickupID)
|
||||
url += "?chainOrder=%s&format=PEM"
|
||||
switch req.ChainOption {
|
||||
case certificate.ChainOptionRootFirst:
|
||||
url = fmt.Sprintf(url, condorChainOptionRootFirst)
|
||||
default:
|
||||
url = fmt.Sprintf(url, condorChainOptionRootLast)
|
||||
}
|
||||
statusCode, status, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if statusCode == http.StatusOK {
|
||||
certificates, err = newPEMCollectionFromResponse(body, req.ChainOption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = req.CheckCertificate(certificates.Certificate)
|
||||
return certificates, err
|
||||
} else if statusCode == http.StatusConflict { // Http Status Code 409 means the certificate has not been signed by the ca yet.
|
||||
return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Failed to retrieve certificate. StatusCode: %d -- Status: %s -- Server Data: %s", statusCode, status, body) //todo:remove body from err
|
||||
}
|
||||
return nil, fmt.Errorf("Failed to retrieve certificate. StatusCode: %d -- Status: %s -- Server Data: %s", resp.StatusCode, resp.Status, body)
|
||||
}
|
||||
return nil, fmt.Errorf("Couldn't retrieve certificate because both PickupID and CertId are empty")
|
||||
}
|
||||
|
||||
// RevokeCertificate attempts to revoke the certificate
|
||||
@@ -423,7 +386,7 @@ func (c *Connector) RenewCertificate(renewReq *certificate.RenewalRequest) (requ
|
||||
return "", fmt.Errorf("failed to submit renewal request for certificate: ManagedCertificateId is empty, certificate status is %s", previousRequest.Status)
|
||||
}
|
||||
|
||||
if managedCertificateId == "" {
|
||||
if zoneId == "" {
|
||||
return "", fmt.Errorf("failed to submit renewal request for certificate: ZoneId is empty, certificate status is %s", previousRequest.Status)
|
||||
}
|
||||
|
||||
@@ -451,40 +414,20 @@ func (c *Connector) RenewCertificate(renewReq *certificate.RenewalRequest) (requ
|
||||
return "", fmt.Errorf("Must be autheticated to request a certificate")
|
||||
}
|
||||
|
||||
req := certificateRequest{
|
||||
ZoneID: zoneId,
|
||||
ExistingManagedCertificateId: managedCertificateId,
|
||||
}
|
||||
if renewReq.CertificateRequest != nil && 0 < len(renewReq.CertificateRequest.CSR) {
|
||||
req.CSR = string(renewReq.CertificateRequest.CSR)
|
||||
req := certificateRequest{ZoneID: zoneId, ExistingManagedCertificateId: managedCertificateId}
|
||||
if renewReq.CertificateRequest != nil && len(renewReq.CertificateRequest.GetCSR()) != 0 {
|
||||
req.CSR = string(renewReq.CertificateRequest.GetCSR())
|
||||
req.ReuseCSR = false
|
||||
} else {
|
||||
req.ReuseCSR = true
|
||||
}
|
||||
b, _ := json.Marshal(req)
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("POST", url, reader)
|
||||
statusCode, status, body, err := c.request("POST", url, req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("content-type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return
|
||||
}
|
||||
|
||||
cr, err := parseCertificateRequestResult(resp.StatusCode, resp.Status, body)
|
||||
cr, err := parseCertificateRequestResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Failed to renew certificate: %s", err)
|
||||
}
|
||||
return cr.CertificateRequests[0].ID, nil
|
||||
@@ -496,65 +439,33 @@ func (c *Connector) getZoneByTag(tag string) (*zone, error) {
|
||||
return nil, fmt.Errorf("Must be autheticated to read the zone configuration")
|
||||
}
|
||||
url = fmt.Sprintf(url, tag)
|
||||
b := []byte{}
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("GET", url, reader)
|
||||
statusCode, status, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
z, err := parseZoneConfigurationResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z, err := parseZoneConfigurationResult(resp.StatusCode, resp.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
return z, nil
|
||||
}
|
||||
|
||||
func (c *Connector) getPoliciesByID(ids []string) (*certificatePolicy, error) {
|
||||
policy := new(certificatePolicy)
|
||||
url := c.getURL(urlResourcePoliciesByID)
|
||||
if c.user == nil {
|
||||
return nil, fmt.Errorf("Must be autheticated to read the zone configuration")
|
||||
}
|
||||
for _, id := range ids {
|
||||
url := c.getURL(urlResourcePoliciesByID)
|
||||
url = fmt.Sprintf(url, id)
|
||||
b := []byte{}
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("GET", url, reader)
|
||||
statusCode, status, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
p, err := parseCertificatePolicyResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, err := parseCertificatePolicyResult(resp.StatusCode, resp.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
switch p.CertificatePolicyType {
|
||||
case certificatePolicyTypeIdentity:
|
||||
policy.SubjectCNRegexes = p.SubjectCNRegexes
|
||||
@@ -564,11 +475,9 @@ func (c *Connector) getPoliciesByID(ids []string) (*certificatePolicy, error) {
|
||||
policy.SubjectLRegexes = p.SubjectLRegexes
|
||||
policy.SubjectCRegexes = p.SubjectCRegexes
|
||||
policy.SANRegexes = p.SANRegexes
|
||||
break
|
||||
case certificatePolicyTypeUse:
|
||||
policy.KeyTypes = p.KeyTypes
|
||||
policy.KeyReuse = p.KeyReuse
|
||||
break
|
||||
}
|
||||
}
|
||||
return policy, nil
|
||||
@@ -579,36 +488,11 @@ func (c *Connector) searchCertificates(req *SearchRequest) (*CertificateSearchRe
|
||||
var err error
|
||||
|
||||
url := c.getURL(urlResourceCertificateSearch)
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
err = fmt.Errorf("Must be autheticated")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(req)
|
||||
reader := bytes.NewReader(b)
|
||||
request, err := http.NewRequest("POST", url, reader)
|
||||
statusCode, _, body, err := c.request("POST", url, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("content-type", "application/json")
|
||||
request.Header.Add("accept", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.verbose {
|
||||
fmt.Printf("REQ: %s\n", b)
|
||||
fmt.Printf("RES: %s\n", body)
|
||||
}
|
||||
|
||||
searchResult, err := ParseCertificateSearchResponse(resp.StatusCode, body)
|
||||
searchResult, err := ParseCertificateSearchResponse(statusCode, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -653,35 +537,14 @@ type managedCertificate struct {
|
||||
|
||||
func (c *Connector) getManagedCertificate(managedCertId string) (*managedCertificate, error) {
|
||||
var err error
|
||||
url := c.getURL(urlResourceManagedCertificateById)
|
||||
url := c.getURL(urlResourceManagedCertificateByID)
|
||||
url = fmt.Sprintf(url, managedCertId)
|
||||
if c.user == nil || c.user.Company == nil {
|
||||
err = fmt.Errorf("Must be autheticated")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("GET", url, nil)
|
||||
statusCode, _, body, err := c.request("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("tppl-api-key", c.apiKey)
|
||||
request.Header.Add("accept", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.verbose {
|
||||
fmt.Printf("REQ: %s\n", url)
|
||||
fmt.Printf("RES: %s\n", body)
|
||||
}
|
||||
|
||||
switch resp.StatusCode {
|
||||
switch statusCode {
|
||||
case http.StatusOK:
|
||||
var res = &managedCertificate{}
|
||||
err = json.Unmarshal(body, res)
|
||||
@@ -693,18 +556,75 @@ func (c *Connector) getManagedCertificate(managedCertId string) (*managedCertifi
|
||||
if body != nil {
|
||||
respErrors, err := parseResponseErrors(body)
|
||||
if err == nil {
|
||||
respError := fmt.Sprintf("Unexpected status code on Venafi Cloud certificate search. Status: %d\n", resp.StatusCode)
|
||||
respError := fmt.Sprintf("Unexpected status code on Venafi Cloud certificate search. Status: %d\n", statusCode)
|
||||
for _, e := range respErrors {
|
||||
respError += fmt.Sprintf("Error Code: %d Error: %s\n", e.Code, e.Message)
|
||||
}
|
||||
return nil, fmt.Errorf(respError)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Unexpected status code on Venafi Cloud certificate search. Status: %d", resp.StatusCode)
|
||||
return nil, fmt.Errorf("Unexpected status code on Venafi Cloud certificate search. Status: %d", statusCode)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *Connector) ImportCertificate(req *certificate.ImportRequest) (*certificate.ImportResponse, error) {
|
||||
return nil, fmt.Errorf("import is not supported")
|
||||
pBlock, _ := pem.Decode([]byte(req.CertificateData))
|
||||
if pBlock == nil {
|
||||
return nil, fmt.Errorf("can`t parse certificate")
|
||||
}
|
||||
zone := req.PolicyDN
|
||||
if zone == "" {
|
||||
zone = c.zone
|
||||
}
|
||||
base64.StdEncoding.EncodeToString(pBlock.Bytes)
|
||||
fingerprint := certThumprint(pBlock.Bytes)
|
||||
e := importRequestEndpoint{
|
||||
OCSP: 1,
|
||||
Certificates: []importRequestEndpointCert{
|
||||
{
|
||||
Certificate: base64.StdEncoding.EncodeToString(pBlock.Bytes),
|
||||
Fingerprint: fingerprint,
|
||||
},
|
||||
},
|
||||
Protocols: []importRequestEndpointProtocol{
|
||||
{
|
||||
Certificates: []string{fingerprint},
|
||||
},
|
||||
},
|
||||
}
|
||||
request := importRequest{
|
||||
ZoneName: zone,
|
||||
Endpoints: []importRequestEndpoint{e},
|
||||
}
|
||||
|
||||
url := c.getURL(urlResourceDiscovery)
|
||||
statusCode, status, body, err := c.request("POST", url, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var r struct {
|
||||
CreatedCertificates int
|
||||
CreatedInstances int
|
||||
UpdatedCertificates int
|
||||
UpdatedInstances int
|
||||
}
|
||||
err = json.Unmarshal(body, &r)
|
||||
if statusCode != http.StatusCreated {
|
||||
return nil, fmt.Errorf("bad server status responce %d %s", statusCode, status)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("can`t unmarshal json response %s", err)
|
||||
} else if !(r.CreatedCertificates == 1 || r.UpdatedCertificates == 1) {
|
||||
return nil, fmt.Errorf("certificate was not imported on unknown reason")
|
||||
}
|
||||
foundCert, err := c.searchCertificatesByFingerprint(fingerprint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(foundCert.Certificates) != 1 {
|
||||
return nil, fmt.Errorf("certificate has been imported but could not be found on platform after that")
|
||||
}
|
||||
cert := foundCert.Certificates[0]
|
||||
resp := &certificate.ImportResponse{CertificateDN: cert.SubjectCN[0], CertId: cert.Id}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
+8
-8
@@ -50,13 +50,13 @@ type Paging struct {
|
||||
|
||||
const (
|
||||
EQ Operator = "EQ"
|
||||
FIND = "FIND"
|
||||
GT = "GT"
|
||||
GTE = "GTE"
|
||||
IN = "IN"
|
||||
LT = "LT"
|
||||
LTE = "LTE"
|
||||
MATCH = "MATCH"
|
||||
FIND Operator = "FIND"
|
||||
GT Operator = "GT"
|
||||
GTE Operator = "GTE"
|
||||
IN Operator = "IN"
|
||||
LT Operator = "LT"
|
||||
LTE Operator = "LTE"
|
||||
MATCH Operator = "MATCH"
|
||||
)
|
||||
|
||||
type CertificateSearchResponse struct {
|
||||
@@ -69,7 +69,7 @@ type Certificate struct {
|
||||
ManagedCertificateId string `json:"managedCertificateId"`
|
||||
CertificateRequestId string `json:"certificateRequestId"`
|
||||
SubjectCN []string `json:"subjectCN"`
|
||||
/*...and many more fields... */
|
||||
/* ... and many more fields ... */
|
||||
}
|
||||
|
||||
func ParseCertificateSearchResponse(httpStatusCode int, body []byte) (searchResult *CertificateSearchResponse, err error) {
|
||||
|
||||
+46
-25
@@ -17,17 +17,19 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
type Connector struct {
|
||||
@@ -44,17 +46,12 @@ func (c *Connector) GetType() endpoint.ConnectorType {
|
||||
}
|
||||
|
||||
func (c *Connector) SetZone(z string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Connector) Ping() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Connector) Register(email string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Connector) Authenticate(auth *endpoint.Authentication) (err error) {
|
||||
return
|
||||
}
|
||||
@@ -71,8 +68,7 @@ func validateRequest(req *certificate.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (requestID string, err error) {
|
||||
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request) (requestID string, err error) {
|
||||
err = validateRequest(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("certificate request validation fail: %s", err)
|
||||
@@ -83,7 +79,7 @@ func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (r
|
||||
switch req.CsrOrigin {
|
||||
case certificate.LocalGeneratedCSR, certificate.UserProvidedCSR:
|
||||
// should return CSR as requestID payload
|
||||
fakeRequest.CSR = base64.StdEncoding.EncodeToString(req.CSR)
|
||||
fakeRequest.CSR = base64.StdEncoding.EncodeToString(req.GetCSR())
|
||||
|
||||
case certificate.ServiceGeneratedCSR:
|
||||
// should return certificate.Request as requestID payload
|
||||
@@ -114,7 +110,7 @@ func issueCertificate(csr *x509.CertificateRequest) ([]byte, error) {
|
||||
nameSet[name] = true
|
||||
}
|
||||
uniqNames := []string{}
|
||||
for name, _ := range nameSet {
|
||||
for name := range nameSet {
|
||||
uniqNames = append(uniqNames, name)
|
||||
}
|
||||
csr.DNSNames = uniqNames
|
||||
@@ -159,33 +155,29 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (pcc *certific
|
||||
}
|
||||
|
||||
var csrPEMbytes []byte
|
||||
var pk interface{}
|
||||
var pk crypto.Signer
|
||||
|
||||
if fakeRequest.CSR != "" {
|
||||
csrPEMbytes, err = base64.StdEncoding.DecodeString(fakeRequest.CSR)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
req := fakeRequest.Req
|
||||
|
||||
switch req.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
req.PrivateKey, err = certificate.GenerateECDSAPrivateKey(req.KeyCurve)
|
||||
case certificate.KeyTypeRSA:
|
||||
req.PrivateKey, err = certificate.GenerateRSAPrivateKey(req.KeyLength)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unable to generate certificate request, key type %s is not supported", req.KeyType.String())
|
||||
}
|
||||
err = req.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req.DNSNames = append(req.DNSNames, "fake-service-generated."+req.Subject.CommonName)
|
||||
|
||||
err = certificate.GenerateRequest(req, req.PrivateKey)
|
||||
err = req.GenerateCSR()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
csrPEMbytes = pem.EncodeToMemory(certificate.GetCertificateRequestPEMBlock(req.CSR))
|
||||
csrPEMbytes = req.GetCSR()
|
||||
pk = req.PrivateKey
|
||||
}
|
||||
|
||||
@@ -216,11 +208,17 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (pcc *certific
|
||||
certBytes = append(cert_pem, []byte(caCertPEM)...)
|
||||
}
|
||||
pcc, err = certificate.PEMCollectionFromBytes(certBytes, req.ChainOption)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// no key password -- no key
|
||||
if pk != nil && req.KeyPassword != "" {
|
||||
pcc.AddPrivateKey(pk, []byte(req.KeyPassword))
|
||||
err = pcc.AddPrivateKey(pk, []byte(req.KeyPassword))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = req.CheckCertificate(pcc.Certificate)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -229,7 +227,7 @@ func (c *Connector) RevokeCertificate(revReq *certificate.RevocationRequest) (er
|
||||
return fmt.Errorf("revocation is not supported in -test-mode")
|
||||
}
|
||||
|
||||
func (c *Connector) ReadZoneConfiguration(zone string) (config *endpoint.ZoneConfiguration, err error) {
|
||||
func (c *Connector) ReadZoneConfiguration() (config *endpoint.ZoneConfiguration, err error) {
|
||||
return endpoint.NewZoneConfiguration(), nil
|
||||
}
|
||||
|
||||
@@ -241,3 +239,26 @@ func (c *Connector) RenewCertificate(revReq *certificate.RenewalRequest) (reques
|
||||
func (c *Connector) ImportCertificate(req *certificate.ImportRequest) (*certificate.ImportResponse, error) {
|
||||
return nil, fmt.Errorf("import is not supported in -test-mode")
|
||||
}
|
||||
|
||||
func (c *Connector) ReadPolicyConfiguration() (policy *endpoint.Policy, err error) {
|
||||
policy = &endpoint.Policy{
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]endpoint.AllowedKeyConfiguration{
|
||||
{certificate.KeyTypeRSA, certificate.AllSupportedKeySizes(), nil},
|
||||
{certificate.KeyTypeECDSA, nil, certificate.AllSupportedCurves()},
|
||||
},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
[]string{".*"},
|
||||
true,
|
||||
true,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+4
-20
@@ -17,48 +17,32 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
func (c *Connector) SetBaseURL(url string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//GenerateRequest creates a new certificate request, based on the zone/policy configuration and the user data
|
||||
func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *certificate.Request) (err error) {
|
||||
|
||||
switch req.CsrOrigin {
|
||||
case certificate.LocalGeneratedCSR:
|
||||
switch req.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
req.PrivateKey, err = certificate.GenerateECDSAPrivateKey(req.KeyCurve)
|
||||
case certificate.KeyTypeRSA:
|
||||
if req.KeyLength == 0 {
|
||||
req.KeyLength = 2048
|
||||
}
|
||||
req.PrivateKey, err = certificate.GenerateRSAPrivateKey(req.KeyLength)
|
||||
default:
|
||||
return fmt.Errorf("Unable to generate certificate request, key type %s is not supported", req.KeyType.String())
|
||||
}
|
||||
err = req.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = certificate.GenerateRequest(req, req.PrivateKey)
|
||||
err = req.GenerateCSR()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.CSR = pem.EncodeToMemory(certificate.GetCertificateRequestPEMBlock(req.CSR))
|
||||
|
||||
case certificate.UserProvidedCSR:
|
||||
if req.CSR == nil {
|
||||
if req.GetCSR() == nil {
|
||||
return fmt.Errorf("CSR was supposed to be provided by user, but it's empty")
|
||||
}
|
||||
|
||||
case certificate.ServiceGeneratedCSR:
|
||||
req.CSR = nil
|
||||
return nil
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Unexpected option in PrivateKeyOrigin")
|
||||
|
||||
+120
-259
@@ -17,18 +17,16 @@
|
||||
package tpp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
// Connector contains the base data needed to communicate with a TPP Server
|
||||
@@ -41,9 +39,38 @@ type Connector struct {
|
||||
}
|
||||
|
||||
// NewConnector creates a new TPP Connector object used to communicate with TPP
|
||||
func NewConnector(verbose bool, trust *x509.CertPool) *Connector {
|
||||
c := Connector{trust: trust, verbose: verbose}
|
||||
return &c
|
||||
func NewConnector(url string, zone string, verbose bool, trust *x509.CertPool) (*Connector, error) {
|
||||
c := Connector{verbose: verbose, trust: trust, zone: zone}
|
||||
var err error
|
||||
c.baseURL, err = normalizeURL(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// normalizeURL normalizes the base URL used to communicate with TPP
|
||||
func normalizeURL(url string) (normalizedURL string, err error) {
|
||||
var baseUrlRegex = regexp.MustCompile(`^https://[a-z\d]+[-a-z\d.]+[a-z\d][:\d]*/vedsdk/$`)
|
||||
modified := strings.ToLower(url)
|
||||
if strings.HasPrefix(modified, "http://") {
|
||||
modified = "https://" + modified[7:]
|
||||
} else if !strings.HasPrefix(modified, "https://") {
|
||||
modified = "https://" + modified
|
||||
}
|
||||
if !strings.HasSuffix(modified, "/") {
|
||||
modified = modified + "/"
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(modified, "vedsdk/") {
|
||||
modified += "vedsdk/"
|
||||
}
|
||||
if loc := baseUrlRegex.FindStringIndex(modified); loc == nil {
|
||||
return "", fmt.Errorf("The specified TPP URL is invalid. %s\nExpected TPP URL format 'https://tpp.company.com/vedsdk/'", url)
|
||||
}
|
||||
|
||||
normalizedURL = modified
|
||||
return normalizedURL, nil
|
||||
}
|
||||
|
||||
func (c *Connector) SetZone(z string) {
|
||||
@@ -56,28 +83,14 @@ func (c *Connector) GetType() endpoint.ConnectorType {
|
||||
|
||||
//Ping attempts to connect to the TPP Server WebSDK API and returns an errror if it cannot
|
||||
func (c *Connector) Ping() (err error) {
|
||||
url, err := c.getURL("")
|
||||
statusCode, status, _, err := c.request("GET", "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if res.StatusCode != http.StatusOK {
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
err = fmt.Errorf("%s", string(body))
|
||||
if statusCode != http.StatusOK {
|
||||
err = fmt.Errorf(status)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//Register does nothing for TPP
|
||||
func (c *Connector) Register(email string) (err error) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
// Authenticate authenticates the user to the TPP
|
||||
@@ -85,33 +98,17 @@ func (c *Connector) Authenticate(auth *endpoint.Authentication) (err error) {
|
||||
if auth == nil {
|
||||
return fmt.Errorf("failed to authenticate: missing credentials")
|
||||
}
|
||||
url, err := c.getURL(urlResourceAuthorize)
|
||||
statusCode, status, body, err := c.request("POST", urlResourceAuthorize, authorizeResquest{Username: auth.User, Password: auth.Password})
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(authorizeResquest{Username: auth.User, Password: auth.Password})
|
||||
payload := bytes.NewReader(b)
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
if err == nil {
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
|
||||
key, err := parseAuthorizeResult(res.StatusCode, res.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", urlResourceAuthorize, strings.Replace(fmt.Sprintf("%s", b), auth.Password, "********", -1))
|
||||
}
|
||||
return err
|
||||
}
|
||||
c.apiKey = key
|
||||
return nil
|
||||
key, err := parseAuthorizeResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return err
|
||||
c.apiKey = key
|
||||
return
|
||||
}
|
||||
|
||||
func wrapAltNames(req *certificate.Request) (items []sanItem) {
|
||||
@@ -127,6 +124,7 @@ func wrapAltNames(req *certificate.Request) (items []sanItem) {
|
||||
return items
|
||||
}
|
||||
|
||||
//todo:remove unused
|
||||
func wrapKeyType(kt certificate.KeyType) string {
|
||||
switch kt {
|
||||
case certificate.KeyTypeRSA:
|
||||
@@ -143,13 +141,15 @@ func prepareRequest(req *certificate.Request, zone string) (tppReq certificateRe
|
||||
case certificate.LocalGeneratedCSR, certificate.UserProvidedCSR:
|
||||
tppReq = certificateRequest{
|
||||
PolicyDN: getPolicyDN(zone),
|
||||
PKCS10: string(req.CSR),
|
||||
CADN: req.CADN,
|
||||
PKCS10: string(req.GetCSR()),
|
||||
ObjectName: req.FriendlyName,
|
||||
DisableAutomaticRenewal: true}
|
||||
|
||||
case certificate.ServiceGeneratedCSR:
|
||||
tppReq = certificateRequest{
|
||||
PolicyDN: getPolicyDN(zone),
|
||||
CADN: req.CADN,
|
||||
ObjectName: req.FriendlyName,
|
||||
Subject: req.Subject.CommonName, // TODO: there is some problem because Subject is not only CN
|
||||
SubjectAltNames: wrapAltNames(req),
|
||||
@@ -172,43 +172,19 @@ func prepareRequest(req *certificate.Request, zone string) (tppReq certificateRe
|
||||
}
|
||||
|
||||
// RequestCertificate submits the CSR to TPP returning the DN of the requested Certificate
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request, zone string) (requestID string, err error) {
|
||||
func (c *Connector) RequestCertificate(req *certificate.Request) (requestID string, err error) {
|
||||
|
||||
if zone == "" {
|
||||
zone = c.zone
|
||||
}
|
||||
|
||||
tppCertificateRequest, err := prepareRequest(req, zone)
|
||||
tppCertificateRequest, err := prepareRequest(req, c.zone)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(tppCertificateRequest)
|
||||
|
||||
url, err := c.getURL(urlResourceCertificateRequest)
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificateRequest, tppCertificateRequest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
payload := bytes.NewReader(b)
|
||||
request, _ := http.NewRequest("POST", url, payload)
|
||||
request.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
request.Header.Add("content-type", "application/json")
|
||||
request.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(request)
|
||||
|
||||
requestID, err = parseRequestResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
requestID, err = parseRequestResult(res.StatusCode, res.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", urlResourceCertificateRequest, b)
|
||||
}
|
||||
return "", fmt.Errorf("%s: %s", err, string(body))
|
||||
return "", fmt.Errorf("%s: %s", err, string(body)) //todo: remove body from error
|
||||
}
|
||||
req.PickupID = requestID
|
||||
return requestID, nil
|
||||
@@ -248,12 +224,18 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates
|
||||
|
||||
startTime := time.Now()
|
||||
for {
|
||||
retrieveResponse, err := c.retrieveCertificateOnce(certReq)
|
||||
var retrieveResponse *certificateRetrieveResponse
|
||||
retrieveResponse, err = c.retrieveCertificateOnce(certReq)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to retrieve: %s", err)
|
||||
}
|
||||
if retrieveResponse.CertificateData != "" {
|
||||
return newPEMCollectionFromResponse(retrieveResponse.CertificateData, req.ChainOption)
|
||||
certificates, err = newPEMCollectionFromResponse(retrieveResponse.CertificateData, req.ChainOption)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = req.CheckCertificate(certificates.Certificate)
|
||||
return
|
||||
}
|
||||
if req.Timeout == 0 {
|
||||
return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID, Status: retrieveResponse.Status}
|
||||
@@ -266,34 +248,14 @@ func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates
|
||||
}
|
||||
|
||||
func (c *Connector) retrieveCertificateOnce(certReq certificateRetrieveRequest) (*certificateRetrieveResponse, error) {
|
||||
url, err := c.getURL(urlResourceCertificateRetrieve)
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificateRetrieve, certReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(certReq)
|
||||
|
||||
payload := bytes.NewReader(b)
|
||||
r, _ := http.NewRequest("POST", url, payload)
|
||||
r.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
r.Header.Add("content-type", "application/json")
|
||||
r.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(r)
|
||||
|
||||
retrieveResponse, err := parseRetrieveResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
retrieveResponse, err := parseRetrieveResult(res.StatusCode, res.Status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", urlResourceCertificateRetrieve, b)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &retrieveResponse, nil
|
||||
}
|
||||
|
||||
@@ -319,38 +281,18 @@ func (c *Connector) RenewCertificate(renewReq *certificate.RenewalRequest) (requ
|
||||
return "", fmt.Errorf("failed to create renewal request: CertificateDN or Thumbprint required")
|
||||
}
|
||||
|
||||
url, err := c.getURL(urlResourceCertificateRenew)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var r = certificateRenewRequest{}
|
||||
r.CertificateDN = renewReq.CertificateDN
|
||||
if renewReq.CertificateRequest != nil && len(renewReq.CertificateRequest.CSR) > 0 {
|
||||
r.PKCS10 = string(renewReq.CertificateRequest.CSR)
|
||||
if renewReq.CertificateRequest != nil && len(renewReq.CertificateRequest.GetCSR()) != 0 {
|
||||
r.PKCS10 = string(renewReq.CertificateRequest.GetCSR())
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(r)
|
||||
payload := bytes.NewReader(b)
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificateRenew, r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
response, err := parseRenewResult(res.StatusCode, res.Status, body)
|
||||
response, err := parseRenewResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", url, b)
|
||||
log.Printf("Response: %s", string(body))
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
if !response.Success {
|
||||
@@ -361,11 +303,6 @@ func (c *Connector) RenewCertificate(renewReq *certificate.RenewalRequest) (requ
|
||||
|
||||
// RevokeCertificate attempts to revoke the certificate
|
||||
func (c *Connector) RevokeCertificate(revReq *certificate.RevocationRequest) (err error) {
|
||||
url, err := c.getURL(urlResourceCertificateRevoke)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reason, ok := RevocationReasonsMap[revReq.Reason]
|
||||
if !ok {
|
||||
return fmt.Errorf("could not parse revocation reason `%s`", revReq.Reason)
|
||||
@@ -378,28 +315,13 @@ func (c *Connector) RevokeCertificate(revReq *certificate.RevocationRequest) (er
|
||||
revReq.Comments,
|
||||
revReq.Disable,
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(r)
|
||||
payload := bytes.NewReader(b)
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificateRevoke, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
revokeResponse, err := parseRevokeResult(res.StatusCode, res.Status, body)
|
||||
revokeResponse, err := parseRevokeResult(statusCode, status, body)
|
||||
if err != nil {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", urlResourceCertificateRevoke, b)
|
||||
}
|
||||
return err
|
||||
return
|
||||
}
|
||||
if !revokeResponse.Success {
|
||||
return fmt.Errorf("Revocation error: %s", revokeResponse.Error)
|
||||
@@ -407,128 +329,67 @@ func (c *Connector) RevokeCertificate(revReq *certificate.RevocationRequest) (er
|
||||
return
|
||||
}
|
||||
|
||||
//ReadZoneConfiguration reads the policy data from TPP to get locked and pre-configured values for certificate requests
|
||||
func (c *Connector) ReadZoneConfiguration(zone string) (config *endpoint.ZoneConfiguration, err error) {
|
||||
zoneConfig := endpoint.NewZoneConfiguration()
|
||||
zoneConfig.HashAlgorithm = x509.SHA256WithRSA
|
||||
policyDN := getPolicyDN(zone)
|
||||
keyType := certificate.KeyTypeRSA
|
||||
func (c *Connector) ReadPolicyConfiguration() (policy *endpoint.Policy, err error) {
|
||||
if c.zone == "" {
|
||||
return nil, fmt.Errorf("empty zone")
|
||||
}
|
||||
rq := struct{ PolicyDN string }{getPolicyDN(c.zone)}
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificatePolicy, rq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var r struct {
|
||||
Policy serverPolicy
|
||||
}
|
||||
if statusCode == http.StatusOK {
|
||||
err = json.Unmarshal(body, &r)
|
||||
p := r.Policy.toPolicy()
|
||||
policy = &p
|
||||
} else {
|
||||
return nil, fmt.Errorf("Invalid status: %s Server data: %s", status, body)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
url, err := c.getURL(urlResourceFindPolicy)
|
||||
//ReadZoneConfiguration reads the policy data from TPP to get locked and pre-configured values for certificate requests
|
||||
func (c *Connector) ReadZoneConfiguration() (config *endpoint.ZoneConfiguration, err error) {
|
||||
if c.zone == "" {
|
||||
return nil, fmt.Errorf("empty zone")
|
||||
}
|
||||
zoneConfig := endpoint.NewZoneConfiguration()
|
||||
zoneConfig.HashAlgorithm = x509.SHA256WithRSA //todo: check this can have problem with ECDSA key
|
||||
rq := struct{ PolicyDN string }{getPolicyDN(c.zone)}
|
||||
statusCode, status, body, err := c.request("POST", urlResourceCertificatePolicy, rq)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var r struct {
|
||||
Policy serverPolicy
|
||||
}
|
||||
if statusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("Invalid status: %s Server response: %s", status, string(body))
|
||||
}
|
||||
err = json.Unmarshal(body, &r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attributes := []string{tppAttributeOrg, tppAttributeOrgUnit, tppAttributeCountry, tppAttributeState, tppAttributeLocality, tppAttributeKeyAlgorithm, tppAttributeKeySize, tppAttributeEllipticCurve, tppAttributeRequestHash, tppAttributeManagementType, tppAttributeManualCSR}
|
||||
for _, attrib := range attributes {
|
||||
b, _ := json.Marshal(policyRequest{ObjectDN: policyDN, Class: "X509 Certificate", AttributeName: attrib})
|
||||
payload := bytes.NewReader(b)
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
|
||||
if err == nil {
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
|
||||
tppData, err := parseConfigResult(res.StatusCode, res.Status, body)
|
||||
if tppData.Error == "" && (err != nil || tppData.Values == nil || len(tppData.Values) == 0) {
|
||||
continue
|
||||
} else if tppData.Error != "" && tppData.Result == 400 { //object does not exist
|
||||
return nil, fmt.Errorf(tppData.Error)
|
||||
}
|
||||
|
||||
switch attrib {
|
||||
case tppAttributeOrg:
|
||||
zoneConfig.Organization = tppData.Values[0]
|
||||
zoneConfig.OrganizationLocked = tppData.Locked
|
||||
case tppAttributeOrgUnit:
|
||||
zoneConfig.OrganizationalUnit = tppData.Values
|
||||
case tppAttributeCountry:
|
||||
zoneConfig.Country = tppData.Values[0]
|
||||
zoneConfig.CountryLocked = tppData.Locked
|
||||
case tppAttributeState:
|
||||
zoneConfig.Province = tppData.Values[0]
|
||||
zoneConfig.ProvinceLocked = tppData.Locked
|
||||
case tppAttributeLocality:
|
||||
zoneConfig.Locality = tppData.Values[0]
|
||||
zoneConfig.LocalityLocked = tppData.Locked
|
||||
case tppAttributeKeyAlgorithm:
|
||||
err = keyType.Set(tppData.Values[0])
|
||||
if err == nil {
|
||||
zoneConfig.AllowedKeyConfigurations = []endpoint.AllowedKeyConfiguration{endpoint.AllowedKeyConfiguration{KeyType: keyType}}
|
||||
}
|
||||
case tppAttributeKeySize:
|
||||
temp, err := strconv.Atoi(tppData.Values[0])
|
||||
if err == nil {
|
||||
zoneConfig.AllowedKeyConfigurations = []endpoint.AllowedKeyConfiguration{endpoint.AllowedKeyConfiguration{KeyType: keyType, KeySizes: []int{temp}}}
|
||||
zoneConfig.KeySizeLocked = tppData.Locked
|
||||
}
|
||||
case tppAttributeEllipticCurve:
|
||||
curve := certificate.EllipticCurveP256
|
||||
err = curve.Set(tppData.Values[0])
|
||||
if err == nil {
|
||||
zoneConfig.AllowedKeyConfigurations = []endpoint.AllowedKeyConfiguration{endpoint.AllowedKeyConfiguration{KeyType: certificate.KeyTypeECDSA, KeyCurves: []certificate.EllipticCurve{curve}}}
|
||||
zoneConfig.KeySizeLocked = tppData.Locked
|
||||
}
|
||||
case tppAttributeRequestHash:
|
||||
alg, err := strconv.Atoi(tppData.Values[0])
|
||||
if err == nil {
|
||||
switch alg {
|
||||
case pkcs10HashAlgorithmSha1:
|
||||
zoneConfig.HashAlgorithm = x509.SHA1WithRSA
|
||||
case pkcs10HashAlgorithmSha384:
|
||||
zoneConfig.HashAlgorithm = x509.SHA384WithRSA
|
||||
case pkcs10HashAlgorithmSha512:
|
||||
zoneConfig.HashAlgorithm = x509.SHA512WithRSA
|
||||
default:
|
||||
zoneConfig.HashAlgorithm = x509.SHA256WithRSA
|
||||
}
|
||||
}
|
||||
case tppAttributeManagementType, tppAttributeManualCSR:
|
||||
if tppData.Locked {
|
||||
zoneConfig.CustomAttributeValues[attrib] = tppData.Values[0]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if c.verbose {
|
||||
log.Printf("JSON sent for %s\n%s", urlResourceFindPolicy, b)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
p := r.Policy.toPolicy()
|
||||
r.Policy.toZoneConfig(zoneConfig)
|
||||
zoneConfig.Policy = p
|
||||
return zoneConfig, nil
|
||||
}
|
||||
|
||||
func (c *Connector) ImportCertificate(r *certificate.ImportRequest) (*certificate.ImportResponse, error) {
|
||||
url, err := c.getURL(urlResourceCertificateImport)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.PolicyDN == "" {
|
||||
r.PolicyDN = getPolicyDN(c.zone)
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(r)
|
||||
payload := bytes.NewReader(b)
|
||||
req, _ := http.NewRequest("POST", url, payload)
|
||||
req.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
req.Header.Add("content-type", "application/json")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(req)
|
||||
statusCode, _, body, err := c.request("POST", urlResourceCertificateImport, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, _ := ioutil.ReadAll(res.Body)
|
||||
|
||||
switch res.StatusCode {
|
||||
switch statusCode {
|
||||
case http.StatusOK:
|
||||
|
||||
var response = &certificate.ImportResponse{}
|
||||
@@ -546,6 +407,6 @@ func (c *Connector) ImportCertificate(r *certificate.ImportRequest) (*certificat
|
||||
}
|
||||
return nil, fmt.Errorf("%s", errorResponse.Error)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected response status %d: %s", res.StatusCode, string(b))
|
||||
return nil, fmt.Errorf("unexpected response status %d: %s", statusCode, string(body))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-25
@@ -19,7 +19,6 @@ package tpp
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
@@ -53,33 +52,12 @@ func (c *Connector) searchCertificates(req *SearchRequest) (*CertificateSearchRe
|
||||
|
||||
var err error
|
||||
|
||||
url, _ := c.getURL(urlResourceCertificateSearch)
|
||||
|
||||
url = fmt.Sprintf("%s?%s", url, strings.Join(*req, "&"))
|
||||
|
||||
request, err := http.NewRequest("GET", url, nil)
|
||||
url := fmt.Sprintf("%s?%s", urlResourceCertificateSearch, strings.Join(*req, "&"))
|
||||
statusCode, _, body, err := c.request("GET", urlResource(url), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
request.Header.Add("cache-control", "no-cache")
|
||||
request.Header.Add("accept", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.verbose {
|
||||
fmt.Printf("REQ: %s\n", url)
|
||||
fmt.Printf("RES: %s\n", body)
|
||||
}
|
||||
|
||||
searchResult, err := ParseCertificateSearchResponse(resp.StatusCode, body)
|
||||
searchResult, err := ParseCertificateSearchResponse(statusCode, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+282
-103
@@ -17,17 +17,21 @@
|
||||
package tpp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
)
|
||||
|
||||
const defaultKeySize = 2048
|
||||
@@ -73,7 +77,7 @@ type certificateRetrieveResponse struct {
|
||||
|
||||
type RevocationReason int
|
||||
|
||||
// this maps *certificate.RevocationRequest.Reason to TPP-specific webSDK codes
|
||||
// RevocationReasonsMap maps *certificate.RevocationRequest.Reason to TPP-specific webSDK codes
|
||||
var RevocationReasonsMap = map[string]RevocationReason{
|
||||
"": 0, // NoReason
|
||||
"none": 0, //
|
||||
@@ -145,13 +149,14 @@ type urlResource string
|
||||
|
||||
const (
|
||||
urlResourceAuthorize urlResource = "authorize/"
|
||||
urlResourceCertificateRequest = "certificates/request"
|
||||
urlResourceCertificateRetrieve = "certificates/retrieve"
|
||||
urlResourceFindPolicy = "config/findpolicy"
|
||||
urlResourceCertificateRevoke = "certificates/revoke"
|
||||
urlResourceCertificateRenew = "certificates/renew"
|
||||
urlResourceCertificateSearch = "certificates/"
|
||||
urlResourceCertificateImport = "certificates/import"
|
||||
urlResourceCertificateRequest urlResource = "certificates/request"
|
||||
urlResourceCertificateRetrieve urlResource = "certificates/retrieve"
|
||||
urlResourceFindPolicy urlResource = "config/findpolicy"
|
||||
urlResourceCertificateRevoke urlResource = "certificates/revoke"
|
||||
urlResourceCertificateRenew urlResource = "certificates/renew"
|
||||
urlResourceCertificateSearch urlResource = "certificates/"
|
||||
urlResourceCertificateImport urlResource = "certificates/import"
|
||||
urlResourceCertificatePolicy urlResource = "certificates/checkpolicy"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -201,36 +206,6 @@ func retrieveChainOptionFromString(order string) retrieveChainOption {
|
||||
}
|
||||
}
|
||||
|
||||
// SetBaseURL sets the base URL used to cummuncate with TPP
|
||||
func (c *Connector) SetBaseURL(url string) error {
|
||||
modified := strings.ToLower(url)
|
||||
reg := regexp.MustCompile("^http(|s)://")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified = "https://" + modified
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "https://")
|
||||
}
|
||||
reg = regexp.MustCompile("^https://.+?/")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified = modified + "/"
|
||||
}
|
||||
|
||||
reg = regexp.MustCompile("/vedsdk(|/)$")
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified += "vedsdk/"
|
||||
} else {
|
||||
modified = reg.ReplaceAllString(modified, "/vedsdk/")
|
||||
}
|
||||
|
||||
reg = regexp.MustCompile("^https://[a-z\\d]+[-a-z\\d.]+[a-z\\d][:\\d]*/vedsdk/$")
|
||||
if loc := reg.FindStringIndex(modified); loc == nil {
|
||||
return fmt.Errorf("The specified TPP URL is invalid. %s\nExpected TPP URL format 'https://tpp.company.com/vedsdk/'", url)
|
||||
}
|
||||
|
||||
c.baseURL = modified
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Connector) getURL(resource urlResource) (string, error) {
|
||||
if c.baseURL == "" {
|
||||
return "", fmt.Errorf("The Host URL has not been set")
|
||||
@@ -238,19 +213,70 @@ func (c *Connector) getURL(resource urlResource) (string, error) {
|
||||
return fmt.Sprintf("%s%s", c.baseURL, resource), nil
|
||||
}
|
||||
|
||||
func (c *Connector) request(method string, resource urlResource, data interface{}) (statusCode int, statusText string, body []byte, err error) {
|
||||
url, err := c.getURL(resource)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var payload io.Reader
|
||||
var b []byte
|
||||
if method == "POST" {
|
||||
b, _ = json.Marshal(data)
|
||||
payload = bytes.NewReader(b)
|
||||
}
|
||||
|
||||
r, _ := http.NewRequest(method, url, payload)
|
||||
if c.apiKey != "" {
|
||||
r.Header.Add("x-venafi-api-key", c.apiKey)
|
||||
}
|
||||
r.Header.Add("content-type", "application/json")
|
||||
r.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := c.getHTTPClient().Do(r)
|
||||
if res != nil {
|
||||
statusCode = res.StatusCode
|
||||
statusText = res.Status
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
body, err = ioutil.ReadAll(res.Body)
|
||||
// Do not enable trace in production
|
||||
trace := false // IMPORTANT: sensitive information can be diclosured
|
||||
// I hope you know what are you doing
|
||||
if trace {
|
||||
log.Println("#################")
|
||||
if method == "POST" {
|
||||
log.Printf("JSON sent for %s\n%s\n", url, string(b))
|
||||
} else {
|
||||
log.Printf("%s request sent to %s\n", method, url)
|
||||
}
|
||||
log.Printf("Response:\n%s\n", string(body))
|
||||
} else if c.verbose {
|
||||
log.Printf("Got %s status for %s %s\n", statusText, method, url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Connector) getHTTPClient() *http.Client {
|
||||
if c.trust != nil {
|
||||
tr := &http.Transport{TLSClientConfig: &tls.Config{RootCAs: c.trust}}
|
||||
return &http.Client{Transport: tr}
|
||||
tlsConfig := http.DefaultTransport.(*http.Transport).TLSClientConfig
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = &tls.Config{}
|
||||
}
|
||||
tlsConfig.RootCAs = c.trust
|
||||
return &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
|
||||
}
|
||||
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
//GenerateRequest creates a new certificate request, based on the zone/policy configuration and the user data
|
||||
// GenerateRequest creates a new certificate request, based on the zone/policy configuration and the user data
|
||||
func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *certificate.Request) (err error) {
|
||||
if config == nil {
|
||||
config, err = c.ReadZoneConfiguration(c.zone)
|
||||
config, err = c.ReadZoneConfiguration()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read zone configuration: %s", err)
|
||||
}
|
||||
@@ -268,42 +294,32 @@ func (c *Connector) GenerateRequest(config *endpoint.ZoneConfiguration, req *cer
|
||||
if config.CustomAttributeValues[tppAttributeManualCSR] == "0" {
|
||||
return fmt.Errorf("Unable to request certificate by local generated CSR when zone configuration is 'Manual Csr' = 0")
|
||||
}
|
||||
switch req.KeyType {
|
||||
case certificate.KeyTypeECDSA:
|
||||
req.PrivateKey, err = certificate.GenerateECDSAPrivateKey(req.KeyCurve)
|
||||
case certificate.KeyTypeRSA:
|
||||
req.PrivateKey, err = certificate.GenerateRSAPrivateKey(req.KeyLength)
|
||||
default:
|
||||
return fmt.Errorf("Unable to generate certificate request, key type %s is not supported", req.KeyType.String())
|
||||
}
|
||||
err = req.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = certificate.GenerateRequest(req, req.PrivateKey)
|
||||
err = req.GenerateCSR()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.CSR = pem.EncodeToMemory(certificate.GetCertificateRequestPEMBlock(req.CSR))
|
||||
|
||||
case certificate.UserProvidedCSR:
|
||||
if config.CustomAttributeValues[tppAttributeManualCSR] == "0" {
|
||||
return fmt.Errorf("Unable to request certificate with user provided CSR when zone configuration is 'Manual Csr' = 0")
|
||||
}
|
||||
if req.CSR == nil || len(req.CSR) == 0 {
|
||||
if len(req.GetCSR()) == 0 {
|
||||
return fmt.Errorf("CSR was supposed to be provided by user, but it's empty")
|
||||
}
|
||||
|
||||
case certificate.ServiceGeneratedCSR:
|
||||
req.CSR = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPolicyDN(zone string) string {
|
||||
modified := zone
|
||||
reg := regexp.MustCompile("^\\\\VED\\\\Policy")
|
||||
reg := regexp.MustCompile(`^\\VED\\Policy`)
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
reg = regexp.MustCompile("^\\\\")
|
||||
reg = regexp.MustCompile(`^\\`)
|
||||
if reg.FindStringIndex(modified) == nil {
|
||||
modified = "\\" + modified
|
||||
}
|
||||
@@ -325,14 +341,9 @@ func parseAuthorizeResult(httpStatusCode int, httpStatus string, body []byte) (s
|
||||
}
|
||||
}
|
||||
|
||||
func parseAuthorizeData(b []byte) (authorizeResponse, error) {
|
||||
var data authorizeResponse
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
func parseAuthorizeData(b []byte) (data authorizeResponse, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func parseConfigResult(httpStatusCode int, httpStatus string, body []byte) (tppData tppPolicyData, err error) {
|
||||
@@ -349,14 +360,9 @@ func parseConfigResult(httpStatusCode int, httpStatus string, body []byte) (tppD
|
||||
}
|
||||
}
|
||||
|
||||
func parseConfigData(b []byte) (tppPolicyData, error) {
|
||||
var data tppPolicyData
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
func parseConfigData(b []byte) (data tppPolicyData, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func parseRequestResult(httpStatusCode int, httpStatus string, body []byte) (string, error) {
|
||||
@@ -372,14 +378,9 @@ func parseRequestResult(httpStatusCode int, httpStatus string, body []byte) (str
|
||||
}
|
||||
}
|
||||
|
||||
func parseRequestData(b []byte) (certificateRequestResponse, error) {
|
||||
var data certificateRequestResponse
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
func parseRequestData(b []byte) (data certificateRequestResponse, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func parseRetrieveResult(httpStatusCode int, httpStatus string, body []byte) (certificateRetrieveResponse, error) {
|
||||
@@ -396,14 +397,9 @@ func parseRetrieveResult(httpStatusCode int, httpStatus string, body []byte) (ce
|
||||
}
|
||||
}
|
||||
|
||||
func parseRetrieveData(b []byte) (certificateRetrieveResponse, error) {
|
||||
var data certificateRetrieveResponse
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
// fmt.Printf("\n\n%s\n\n%+v\n\n", string(b), data)
|
||||
return data, nil
|
||||
func parseRetrieveData(b []byte) (data certificateRetrieveResponse, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func parseRevokeResult(httpStatusCode int, httpStatus string, body []byte) (certificateRevokeResponse, error) {
|
||||
@@ -420,13 +416,9 @@ func parseRevokeResult(httpStatusCode int, httpStatus string, body []byte) (cert
|
||||
}
|
||||
}
|
||||
|
||||
func parseRevokeData(b []byte) (certificateRevokeResponse, error) {
|
||||
var data certificateRevokeResponse
|
||||
err := json.Unmarshal(b, &data)
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
func parseRevokeData(b []byte) (data certificateRevokeResponse, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func parseRenewResult(httpStatusCode int, httpStatus string, body []byte) (resp certificateRenewResponse, err error) {
|
||||
@@ -437,10 +429,9 @@ func parseRenewResult(httpStatusCode int, httpStatus string, body []byte) (resp
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseRenewData(b []byte) (certificateRenewResponse, error) {
|
||||
var data certificateRenewResponse
|
||||
err := json.Unmarshal(b, &data)
|
||||
return data, err
|
||||
func parseRenewData(b []byte) (data certificateRenewResponse, err error) {
|
||||
err = json.Unmarshal(b, &data)
|
||||
return
|
||||
}
|
||||
|
||||
func newPEMCollectionFromResponse(base64Response string, chainOrder certificate.ChainOption) (*certificate.PEMCollection, error) {
|
||||
@@ -454,3 +445,191 @@ func newPEMCollectionFromResponse(base64Response string, chainOrder certificate.
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type _strValue struct {
|
||||
Locked bool
|
||||
Value string
|
||||
}
|
||||
|
||||
type serverPolicy struct {
|
||||
CertificateAuthority _strValue
|
||||
CsrGeneration _strValue
|
||||
KeyGeneration _strValue
|
||||
KeyPair struct {
|
||||
KeyAlgorithm _strValue
|
||||
KeySize struct {
|
||||
Locked bool
|
||||
Value int
|
||||
}
|
||||
EllipticCurve struct {
|
||||
Locked bool
|
||||
Value string
|
||||
}
|
||||
}
|
||||
ManagementType _strValue
|
||||
|
||||
PrivateKeyReuseAllowed bool
|
||||
SubjAltNameDnsAllowed bool
|
||||
SubjAltNameEmailAllowed bool
|
||||
SubjAltNameIpAllowed bool
|
||||
SubjAltNameUpnAllowed bool
|
||||
SubjAltNameUriAllowed bool
|
||||
Subject struct {
|
||||
City _strValue
|
||||
Country _strValue
|
||||
Organization _strValue
|
||||
OrganizationalUnit struct {
|
||||
Locked bool
|
||||
Values []string
|
||||
}
|
||||
|
||||
State _strValue
|
||||
}
|
||||
UniqueSubjectEnforced bool
|
||||
WhitelistedDomains []string
|
||||
WildcardsAllowed bool
|
||||
}
|
||||
|
||||
func (sp serverPolicy) toZoneConfig(zc *endpoint.ZoneConfiguration) {
|
||||
zc.Country = sp.Subject.Country.Value
|
||||
zc.Organization = sp.Subject.Organization.Value
|
||||
zc.OrganizationalUnit = sp.Subject.OrganizationalUnit.Values
|
||||
zc.Province = sp.Subject.State.Value
|
||||
zc.Locality = sp.Subject.City.Value
|
||||
}
|
||||
|
||||
func (sp serverPolicy) toPolicy() (p endpoint.Policy) {
|
||||
addStartEnd := func(s string) string {
|
||||
if !strings.HasPrefix(s, "^") {
|
||||
s = "^" + s
|
||||
}
|
||||
if !strings.HasSuffix(s, "$") {
|
||||
s = s + "$"
|
||||
}
|
||||
return s
|
||||
}
|
||||
escapeOne := func(s string) string {
|
||||
return addStartEnd(regexp.QuoteMeta(s))
|
||||
}
|
||||
escapeArray := func(l []string) []string {
|
||||
escaped := make([]string, len(l))
|
||||
for i, r := range l {
|
||||
escaped[i] = escapeOne(r)
|
||||
}
|
||||
return escaped
|
||||
}
|
||||
const allAllowedRegex = ".*"
|
||||
if len(sp.WhitelistedDomains) == 0 {
|
||||
p.SubjectCNRegexes = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.SubjectCNRegexes = make([]string, len(sp.WhitelistedDomains))
|
||||
for i, d := range sp.WhitelistedDomains {
|
||||
if sp.WildcardsAllowed {
|
||||
p.SubjectCNRegexes[i] = addStartEnd(".*" + regexp.QuoteMeta("."+d))
|
||||
} else {
|
||||
p.SubjectCNRegexes[i] = escapeOne(d)
|
||||
}
|
||||
}
|
||||
}
|
||||
if sp.Subject.OrganizationalUnit.Locked {
|
||||
p.SubjectOURegexes = escapeArray(sp.Subject.OrganizationalUnit.Values)
|
||||
} else {
|
||||
p.SubjectOURegexes = []string{allAllowedRegex}
|
||||
}
|
||||
if sp.Subject.Organization.Locked {
|
||||
p.SubjectORegexes = []string{escapeOne(sp.Subject.Organization.Value)}
|
||||
} else {
|
||||
p.SubjectORegexes = []string{allAllowedRegex}
|
||||
}
|
||||
if sp.Subject.City.Locked {
|
||||
p.SubjectLRegexes = []string{escapeOne(sp.Subject.City.Value)}
|
||||
} else {
|
||||
p.SubjectLRegexes = []string{allAllowedRegex}
|
||||
}
|
||||
if sp.Subject.State.Locked {
|
||||
p.SubjectSTRegexes = []string{escapeOne(sp.Subject.State.Value)}
|
||||
} else {
|
||||
p.SubjectSTRegexes = []string{allAllowedRegex}
|
||||
}
|
||||
if sp.Subject.Country.Locked {
|
||||
p.SubjectCRegexes = []string{escapeOne(sp.Subject.Country.Value)}
|
||||
} else {
|
||||
p.SubjectCRegexes = []string{allAllowedRegex}
|
||||
}
|
||||
if sp.SubjAltNameDnsAllowed {
|
||||
if len(sp.WhitelistedDomains) == 0 {
|
||||
p.DnsSanRegExs = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.DnsSanRegExs = make([]string, len(sp.WhitelistedDomains))
|
||||
for i, d := range sp.WhitelistedDomains {
|
||||
if sp.WildcardsAllowed {
|
||||
p.DnsSanRegExs[i] = addStartEnd(".*" + regexp.QuoteMeta("."+d))
|
||||
} else {
|
||||
p.DnsSanRegExs[i] = escapeOne(d)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.DnsSanRegExs = []string{}
|
||||
}
|
||||
if sp.SubjAltNameIpAllowed {
|
||||
p.IpSanRegExs = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.IpSanRegExs = []string{}
|
||||
}
|
||||
if sp.SubjAltNameEmailAllowed {
|
||||
p.EmailSanRegExs = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.EmailSanRegExs = []string{}
|
||||
}
|
||||
if sp.SubjAltNameUriAllowed {
|
||||
p.UriSanRegExs = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.UriSanRegExs = []string{}
|
||||
}
|
||||
if sp.SubjAltNameUpnAllowed {
|
||||
p.UpnSanRegExs = []string{allAllowedRegex}
|
||||
} else {
|
||||
p.UpnSanRegExs = []string{}
|
||||
}
|
||||
if sp.KeyPair.KeyAlgorithm.Locked {
|
||||
var keyType certificate.KeyType
|
||||
if err := keyType.Set(sp.KeyPair.KeyAlgorithm.Value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key := endpoint.AllowedKeyConfiguration{KeyType: keyType}
|
||||
if keyType == certificate.KeyTypeRSA {
|
||||
if sp.KeyPair.KeySize.Locked {
|
||||
for _, i := range certificate.AllSupportedKeySizes() {
|
||||
if i >= sp.KeyPair.KeySize.Value {
|
||||
key.KeySizes = append(key.KeySizes, i)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
key.KeySizes = certificate.AllSupportedKeySizes()
|
||||
}
|
||||
} else {
|
||||
var curve certificate.EllipticCurve
|
||||
if sp.KeyPair.EllipticCurve.Locked {
|
||||
if err := curve.Set(sp.KeyPair.EllipticCurve.Value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
key.KeyCurves = append(key.KeyCurves, curve)
|
||||
} else {
|
||||
key.KeyCurves = certificate.AllSupportedCurves()
|
||||
}
|
||||
|
||||
}
|
||||
p.AllowedKeyConfigurations = append(p.AllowedKeyConfigurations, key)
|
||||
} else {
|
||||
p.AllowedKeyConfigurations = append(p.AllowedKeyConfigurations, endpoint.AllowedKeyConfiguration{
|
||||
KeyType: certificate.KeyTypeRSA, KeySizes: certificate.AllSupportedKeySizes(),
|
||||
})
|
||||
p.AllowedKeyConfigurations = append(p.AllowedKeyConfigurations, endpoint.AllowedKeyConfiguration{
|
||||
KeyType: certificate.KeyTypeECDSA, KeyCurves: certificate.AllSupportedCurves(),
|
||||
})
|
||||
}
|
||||
p.AllowWildcards = sp.WildcardsAllowed
|
||||
p.AllowKeyReuse = sp.PrivateKeyReuseAllowed
|
||||
return
|
||||
}
|
||||
|
||||
+8
-11
@@ -13,19 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
VCert is a Go library, SDK, and command line utility designed to simplify key generation and enrollment of machine identities (also known as SSL/TLS certificates and keys) that comply with enterprise security policy by using the Venafi Platform or Venafi Cloud.
|
||||
*/
|
||||
package vcert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//ProjectName contains the friendly name of the vcert utiltity
|
||||
const ProjectName string = "Venafi Certificate Utility"
|
||||
//projectName contains the friendly name of the vcert utiltity
|
||||
const projectName string = "Venafi Certificate Utility"
|
||||
|
||||
var (
|
||||
versionString string
|
||||
versionBuildTimeStamp string
|
||||
versionString string
|
||||
)
|
||||
|
||||
//GetFormattedVersionString gets a friendly printable string to represent the version
|
||||
@@ -33,13 +35,8 @@ func GetFormattedVersionString() string {
|
||||
if versionBuildTimeStamp != "" {
|
||||
versionBuildTimeStamp = fmt.Sprintf("\tBuild Timestamp: %s\n", versionBuildTimeStamp)
|
||||
}
|
||||
return fmt.Sprintf("%s\n\tVersion: %s\n%s", ProjectName, GetVersionString(), versionBuildTimeStamp)
|
||||
}
|
||||
|
||||
//GetVersionString gets a simple version string
|
||||
func GetVersionString() string {
|
||||
if versionString == "" {
|
||||
versionString = "3.18.3.1"
|
||||
versionString = "Unknown"
|
||||
}
|
||||
return versionString
|
||||
return fmt.Sprintf("%s\n\tVersion: %s\n%s", projectName, versionString, versionBuildTimeStamp)
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ github.com/NYTimes/gziphandler
|
||||
github.com/PuerkitoBio/purell
|
||||
# github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
|
||||
github.com/PuerkitoBio/urlesc
|
||||
# github.com/Venafi/vcert v0.0.0-20181029235941-5068538d4d65
|
||||
# github.com/Venafi/vcert v0.0.0-20190530133915-e207710a0ab9
|
||||
github.com/Venafi/vcert
|
||||
github.com/Venafi/vcert/pkg/certificate
|
||||
github.com/Venafi/vcert/pkg/endpoint
|
||||
|
||||
Reference in New Issue
Block a user