github.com/Venafi/vcert/v5@v5.10.2/pkg/endpoint/endpoint.go (about)

     1  /*
     2   * Copyright 2018-2023 Venafi, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *  http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package endpoint
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"crypto/ed25519"
    22  	"crypto/rsa"
    23  	"crypto/x509"
    24  	"encoding/pem"
    25  	"errors"
    26  	"fmt"
    27  	"net"
    28  	"net/http"
    29  	"regexp"
    30  	"time"
    31  
    32  	"github.com/Venafi/vcert/v5/pkg/certificate"
    33  	"github.com/Venafi/vcert/v5/pkg/domain"
    34  	"github.com/Venafi/vcert/v5/pkg/policy"
    35  )
    36  
    37  const SDKName = "Venafi VCert-Go"
    38  
    39  var LocalIP string
    40  
    41  // ConnectorType represents the available connectors
    42  type ConnectorType int
    43  
    44  const (
    45  	ConnectorTypeUndefined ConnectorType = iota
    46  	// ConnectorTypeFake is a fake connector for tests
    47  	ConnectorTypeFake
    48  	// ConnectorTypeCloud represents the Cloud connector type
    49  	ConnectorTypeCloud
    50  	// ConnectorTypeTPP represents the TPP connector type
    51  	ConnectorTypeTPP
    52  	// ConnectorTypeFirefly represents the Firefly connector type
    53  	ConnectorTypeFirefly
    54  )
    55  
    56  func init() {
    57  	LocalIP = getPrimaryNetAddr()
    58  }
    59  
    60  func (t ConnectorType) String() string {
    61  	switch t {
    62  	case ConnectorTypeUndefined:
    63  		return "Undefined Endpoint"
    64  	case ConnectorTypeFake:
    65  		return "Fake Endpoint"
    66  	case ConnectorTypeCloud:
    67  		return "Venafi as a Service"
    68  	case ConnectorTypeTPP:
    69  		return "Trust Protection Platform"
    70  	case ConnectorTypeFirefly:
    71  		return "Firefly"
    72  	default:
    73  		return fmt.Sprintf("unexpected connector type: %d", t)
    74  	}
    75  }
    76  
    77  // Connector provides a common interface for external communications with TPP or Venafi Cloud
    78  type Connector interface {
    79  	// GetType returns a connector type (cloud/TPP/fake). Can be useful because some features are not supported by a Cloud connection.
    80  	GetType() ConnectorType
    81  	// SetZone sets a zone (by name) for requests with this connector.
    82  	SetZone(z string)
    83  	// SetHTTPClient allows to set custom http.Client to this Connector.
    84  	SetHTTPClient(client *http.Client)
    85  	Ping() (err error)
    86  	// Authenticate is usually called by NewClient and it is not required that you manually call it.
    87  	Authenticate(auth *Authentication) (err error)
    88  
    89  	// ReadPolicyConfiguration returns information about zone policies. It can be used for checking request compatibility with policies.
    90  	ReadPolicyConfiguration() (policy *Policy, err error)
    91  	// ReadZoneConfiguration returns the zone configuration. A zone configuration includes zone policy and additional zone information.
    92  	ReadZoneConfiguration() (config *ZoneConfiguration, err error)
    93  	// GetZonesByParent returns a list of valid zones specified by parent
    94  	GetZonesByParent(parent string) ([]string, error)
    95  	// GenerateRequest update certificate.Request with data from zone configuration.
    96  	GenerateRequest(config *ZoneConfiguration, req *certificate.Request) (err error)
    97  
    98  	// ResetCertificate resets the state of a certificate.
    99  	// This function is idempotent, i.e., it won't fail if there is nothing to be reset.
   100  	ResetCertificate(req *certificate.Request, restart bool) (err error)
   101  	// RequestCertificate makes a request to the server with data for enrolling the certificate.
   102  	RequestCertificate(req *certificate.Request) (requestID string, err error)
   103  	// RetrieveCertificate immediately returns an enrolled certificate. Otherwise, RetrieveCertificate waits and retries during req.Timeout.
   104  	RetrieveCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error)
   105  	ProvisionCertificate(req *domain.ProvisioningRequest, options *domain.ProvisioningOptions) (*domain.ProvisioningMetadata, error)
   106  	IsCSRServiceGenerated(req *certificate.Request) (bool, error)
   107  	RevokeCertificate(req *certificate.RevocationRequest) error
   108  	RenewCertificate(req *certificate.RenewalRequest) (requestID string, err error)
   109  	RetireCertificate(req *certificate.RetireRequest) error
   110  	// ImportCertificate adds an existing certificate to Venafi Platform even if the certificate was not issued by Venafi Cloud or Venafi Platform. For information purposes.
   111  	ImportCertificate(req *certificate.ImportRequest) (*certificate.ImportResponse, error)
   112  	// ListCertificates returns a list of certificates from inventory that matches the filter
   113  	ListCertificates(filter Filter) ([]certificate.CertificateInfo, error)
   114  	SearchCertificates(req *certificate.SearchRequest) (*certificate.CertSearchResponse, error)
   115  	// SearchCertificate returns a valid certificate
   116  	//
   117  	// If it returns no error, the certificate returned should be the latest [1]
   118  	// exact matching zone [2], CN and sans.DNS [3] provided, with a minimum
   119  	// validity of `certMinTimeLeft`
   120  	//
   121  	// [1] the one with the longest validity; field named ValidTo for TPP and
   122  	// validityEnd for VaaS
   123  	// [2] application name for VaaS
   124  	// [3] an array of strings representing the DNS names
   125  	SearchCertificate(zone string, cn string, sans *certificate.Sans, certMinTimeLeft time.Duration) (*certificate.CertificateInfo, error)
   126  	RetrieveCertificateMetaData(dn string) (*certificate.CertificateMetaData, error)
   127  
   128  	SetPolicy(name string, ps *policy.PolicySpecification) (string, error)
   129  	GetPolicy(name string) (*policy.PolicySpecification, error)
   130  
   131  	RequestSSHCertificate(req *certificate.SshCertRequest) (response *certificate.SshCertificateObject, err error)
   132  	RetrieveSSHCertificate(req *certificate.SshCertRequest) (response *certificate.SshCertificateObject, err error)
   133  	RetrieveSshConfig(ca *certificate.SshCaTemplateRequest) (*certificate.SshConfig, error)
   134  	RetrieveAvailableSSHTemplates() ([]certificate.SshAvaliableTemplate, error)
   135  
   136  	// SynchronousRequestCertificate makes a request to the server with data for enrolling the certificate and returns the enrolled certificate.
   137  	SynchronousRequestCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error)
   138  	// SupportSynchronousRequestCertificate returns if the connector support synchronous calls to request a certificate.
   139  	SupportSynchronousRequestCertificate() bool
   140  
   141  	RetrieveSystemVersion() (string, error)
   142  	WriteLog(req *LogRequest) error
   143  	// SetUserAgent sets the value of the UserAgent header in HTTP requests to
   144  	// Venafi API endpoints by this connector.
   145  	// The default is `vcert/v5`.
   146  	// Further reading: https://www.rfc-editor.org/rfc/rfc9110#field.user-agent
   147  	SetUserAgent(userAgent string)
   148  }
   149  
   150  type Filter struct {
   151  	Limit       *int
   152  	WithExpired bool
   153  }
   154  
   155  // todo: replace with verror
   156  // ErrRetrieveCertificateTimeout provides a common error structure for a timeout while retrieving a certificate
   157  type ErrRetrieveCertificateTimeout struct {
   158  	CertificateID string
   159  }
   160  
   161  func (err ErrRetrieveCertificateTimeout) Error() string {
   162  	return fmt.Sprintf("Operation timed out. You may try retrieving the certificate later using Pickup ID: %s", err.CertificateID)
   163  }
   164  
   165  // todo: replace with verror
   166  // ErrCertificatePending provides a common error structure for a timeout while retrieving a certificate
   167  type ErrCertificatePending struct {
   168  	CertificateID string
   169  	Status        string
   170  }
   171  
   172  func (err ErrCertificatePending) Error() string {
   173  	if err.Status == "" {
   174  		return fmt.Sprintf("Issuance is pending. You may try retrieving the certificate later using Pickup ID: %s", err.CertificateID)
   175  	}
   176  	return fmt.Sprintf("Issuance is pending. You may try retrieving the certificate later using Pickup ID: %s\n\tStatus: %s", err.CertificateID, err.Status)
   177  }
   178  
   179  type ErrCertificateRejected struct {
   180  	CertificateID string
   181  	Status        string
   182  }
   183  
   184  func (err ErrCertificateRejected) Error() string {
   185  	if err.Status == "" {
   186  		return fmt.Sprintf("Certificate request was rejected. You may need to verify the certificate id: %s", err.CertificateID)
   187  	}
   188  	return fmt.Sprintf("Status: %s", err.Status)
   189  }
   190  
   191  // Policy is struct that contains restrictions for certificates. Most of the fields contains list of regular expression.
   192  // For satisfying policies, all values in the certificate field must match AT LEAST ONE regular expression in corresponding policy field.
   193  type Policy struct {
   194  	SubjectCNRegexes []string
   195  	SubjectORegexes  []string
   196  	SubjectOURegexes []string
   197  	SubjectSTRegexes []string
   198  	SubjectLRegexes  []string
   199  	SubjectCRegexes  []string
   200  	// AllowedKeyConfigurations lists all allowed key configurations. Certificate key configuration have to be listed in this list.
   201  	// 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.
   202  	AllowedKeyConfigurations []AllowedKeyConfiguration
   203  	// DnsSanRegExs is a list of regular expressions that show allowable DNS names in SANs.
   204  	DnsSanRegExs []string
   205  	// IpSanRegExs is a list of regular expressions that show allowable DNS names in SANs.
   206  	IpSanRegExs    []string
   207  	EmailSanRegExs []string
   208  	UriSanRegExs   []string
   209  	UpnSanRegExs   []string
   210  	AllowWildcards bool
   211  	AllowKeyReuse  bool
   212  }
   213  
   214  // ZoneConfiguration provides a common structure for certificate request data provided by the remote endpoint
   215  type ZoneConfiguration struct {
   216  	Organization       string
   217  	OrganizationalUnit []string
   218  	Country            string
   219  	Province           string
   220  	Locality           string
   221  	Policy
   222  	HashAlgorithm         x509.SignatureAlgorithm
   223  	CustomAttributeValues map[string]string
   224  	KeyConfiguration      *AllowedKeyConfiguration
   225  }
   226  
   227  type LogRequest struct {
   228  	LogID     string `json:"ID,omitempty"`
   229  	Component string `json:",omitempty"`
   230  	Text1     string `json:",omitempty"`
   231  	Text2     string `json:",omitempty"`
   232  	Value1    string `json:",omitempty"`
   233  	Value2    string `json:",omitempty"`
   234  	SourceIp  string `json:",omitempty"`
   235  	Severity  string `json:",omitempty"`
   236  }
   237  
   238  // AllowedKeyConfiguration contains an allowed key type with its sizes or curves
   239  type AllowedKeyConfiguration struct {
   240  	KeyType   certificate.KeyType
   241  	KeySizes  []int
   242  	KeyCurves []certificate.EllipticCurve
   243  }
   244  
   245  // NewZoneConfiguration creates a new zone configuration which creates the map used in the configuration
   246  func NewZoneConfiguration() *ZoneConfiguration {
   247  	zc := ZoneConfiguration{}
   248  	zc.CustomAttributeValues = make(map[string]string)
   249  
   250  	return &zc
   251  }
   252  
   253  // ValidateCertificateRequest validates the request against the Policy
   254  func (p *Policy) ValidateCertificateRequest(request *certificate.Request) error {
   255  
   256  	const (
   257  		emailError            = "email addresses %v do not match regular expressions: %v"
   258  		ipError               = "IP addresses %v do not match regular expressions: %v"
   259  		uriError              = "URIs %v do not match regular expressions: %v"
   260  		organizationError     = "organization %v doesn't match regular expressions: %v"
   261  		organizationUnitError = "organization unit %v doesn't match regular expressions: %v"
   262  		countryError          = "country %v doesn't match regular expressions: %v"
   263  		locationError         = "location %v doesn't match regular expressions: %v"
   264  		provinceError         = "state (province) %v doesn't match regular expressions: %v"
   265  		keyError              = "the requested Key Type and Size do not match any of the allowed Key Types and Sizes"
   266  	)
   267  	err := p.SimpleValidateCertificateRequest(*request)
   268  	if err != nil {
   269  		return err
   270  	}
   271  	csr := request.GetCSR()
   272  	if len(csr) > 0 {
   273  		pemBlock, _ := pem.Decode(csr)
   274  		parsedCSR, err := x509.ParseCertificateRequest(pemBlock.Bytes)
   275  		if err != nil {
   276  			return err
   277  		}
   278  		if !isComponentValid(parsedCSR.EmailAddresses, p.EmailSanRegExs, true) {
   279  			return fmt.Errorf(emailError, p.EmailSanRegExs, p.EmailSanRegExs)
   280  		}
   281  		ips := make([]string, len(parsedCSR.IPAddresses))
   282  		for i, ip := range parsedCSR.IPAddresses {
   283  			ips[i] = ip.String()
   284  		}
   285  		if !isComponentValid(ips, p.IpSanRegExs, true) {
   286  			return fmt.Errorf(ipError, p.IpSanRegExs, p.IpSanRegExs)
   287  		}
   288  		uris := make([]string, len(parsedCSR.URIs))
   289  		for i, uri := range parsedCSR.URIs {
   290  			uris[i] = uri.String()
   291  		}
   292  		if !isComponentValid(uris, p.UriSanRegExs, true) {
   293  			return fmt.Errorf(uriError, uris, p.UriSanRegExs)
   294  		}
   295  		if !isComponentValid(parsedCSR.Subject.Organization, p.SubjectORegexes, false) {
   296  			return fmt.Errorf(organizationError, p.SubjectORegexes, p.SubjectORegexes)
   297  		}
   298  
   299  		if !isComponentValid(parsedCSR.Subject.OrganizationalUnit, p.SubjectOURegexes, false) {
   300  			return fmt.Errorf(organizationUnitError, parsedCSR.Subject.OrganizationalUnit, p.SubjectOURegexes)
   301  		}
   302  
   303  		if !isComponentValid(parsedCSR.Subject.Country, p.SubjectCRegexes, false) {
   304  			return fmt.Errorf(countryError, parsedCSR.Subject.Country, p.SubjectCRegexes)
   305  		}
   306  
   307  		if !isComponentValid(parsedCSR.Subject.Locality, p.SubjectLRegexes, false) {
   308  			return fmt.Errorf(locationError, parsedCSR.Subject.Locality, p.SubjectLRegexes)
   309  		}
   310  
   311  		if !isComponentValid(parsedCSR.Subject.Province, p.SubjectSTRegexes, false) {
   312  			return fmt.Errorf(provinceError, parsedCSR.Subject.Province, p.SubjectSTRegexes)
   313  		}
   314  		if len(p.AllowedKeyConfigurations) > 0 {
   315  			var keyValid bool
   316  			if parsedCSR.PublicKeyAlgorithm == x509.RSA {
   317  				pubkey, ok := parsedCSR.PublicKey.(*rsa.PublicKey)
   318  				if ok {
   319  					keyValid = checkKey(certificate.KeyTypeRSA, pubkey.Size()*8, "", p.AllowedKeyConfigurations)
   320  				} else {
   321  					return fmt.Errorf("invalid key in csr")
   322  				}
   323  			} else if parsedCSR.PublicKeyAlgorithm == x509.ECDSA {
   324  				pubkey, ok := parsedCSR.PublicKey.(*ecdsa.PublicKey)
   325  				if ok {
   326  					keyValid = checkKey(certificate.KeyTypeECDSA, 0, pubkey.Curve.Params().Name, p.AllowedKeyConfigurations)
   327  				} else {
   328  					return fmt.Errorf("invalid key in csr")
   329  				}
   330  			} else if parsedCSR.PublicKeyAlgorithm == x509.Ed25519 {
   331  				_, ok := parsedCSR.PublicKey.(*ed25519.PublicKey)
   332  				if ok {
   333  					keyValid = checkKey(certificate.KeyTypeECDSA, 0, "ed25519", p.AllowedKeyConfigurations)
   334  				} else {
   335  					return fmt.Errorf("invalid key in csr")
   336  				}
   337  			}
   338  			if !keyValid {
   339  				return errors.New(keyError)
   340  			}
   341  		}
   342  
   343  	} else {
   344  		//todo: add ip, email, uri cheking
   345  		if !isComponentValid(request.Subject.Organization, p.SubjectORegexes, false) {
   346  			return fmt.Errorf(organizationError, request.Subject.Organization, p.SubjectORegexes)
   347  		}
   348  		if !isComponentValid(request.Subject.OrganizationalUnit, p.SubjectOURegexes, false) {
   349  			return fmt.Errorf(organizationUnitError, request.Subject.OrganizationalUnit, p.SubjectOURegexes)
   350  		}
   351  		if !isComponentValid(request.Subject.Province, p.SubjectSTRegexes, false) {
   352  			return fmt.Errorf(provinceError, request.Subject.Province, p.SubjectSTRegexes)
   353  		}
   354  		if !isComponentValid(request.Subject.Locality, p.SubjectLRegexes, false) {
   355  			return fmt.Errorf(locationError, request.Subject.Locality, p.SubjectLRegexes)
   356  		}
   357  		if !isComponentValid(request.Subject.Country, p.SubjectCRegexes, false) {
   358  			return fmt.Errorf(countryError, request.Subject.Country, p.SubjectCRegexes)
   359  		}
   360  
   361  		if len(p.AllowedKeyConfigurations) > 0 {
   362  			if !checkKey(request.KeyType, request.KeyLength, request.KeyCurve.String(), p.AllowedKeyConfigurations) {
   363  				return errors.New(keyError)
   364  			}
   365  		}
   366  	}
   367  
   368  	return nil
   369  }
   370  
   371  // SimpleValidateCertificateRequest functions just check Common Name and SANs mathching with policies
   372  func (p *Policy) SimpleValidateCertificateRequest(request certificate.Request) error {
   373  	csr := request.GetCSR()
   374  	const (
   375  		cnError   = "common name %s is not allowed in this policy: %v"
   376  		SANsError = "DNS SANs %v do not match regular expressions: %v"
   377  	)
   378  	if len(csr) > 0 {
   379  		pemBlock, _ := pem.Decode(csr)
   380  		parsedCSR, err := x509.ParseCertificateRequest(pemBlock.Bytes)
   381  		if err != nil {
   382  			return err
   383  		}
   384  		if !checkStringByRegexp(parsedCSR.Subject.CommonName, p.SubjectCNRegexes) {
   385  			return fmt.Errorf(cnError, parsedCSR.Subject.CommonName, p.SubjectCNRegexes)
   386  		}
   387  		if !isComponentValid(parsedCSR.DNSNames, p.DnsSanRegExs, true) {
   388  			return fmt.Errorf(SANsError, parsedCSR.DNSNames, p.DnsSanRegExs)
   389  		}
   390  	} else {
   391  		if !checkStringByRegexp(request.Subject.CommonName, p.SubjectCNRegexes) {
   392  			return fmt.Errorf(cnError, request.Subject.CommonName, p.SubjectCNRegexes)
   393  		}
   394  		if !isComponentValid(request.DNSNames, p.DnsSanRegExs, true) {
   395  			return fmt.Errorf(SANsError, request.DNSNames, p.DnsSanRegExs)
   396  		}
   397  	}
   398  	return nil
   399  }
   400  
   401  func checkKey(kt certificate.KeyType, bitsize int, curveStr string, allowed []AllowedKeyConfiguration) (valid bool) {
   402  	for _, allowedKey := range allowed {
   403  		if allowedKey.KeyType == kt {
   404  			switch allowedKey.KeyType {
   405  			case certificate.KeyTypeRSA:
   406  				return intInSlice(bitsize, allowedKey.KeySizes)
   407  			case certificate.KeyTypeECDSA:
   408  				var curve certificate.EllipticCurve
   409  				if err := curve.Set(curveStr); err != nil {
   410  					return false
   411  				}
   412  				return curveInSlice(curve, allowedKey.KeyCurves)
   413  			case certificate.KeyTypeED25519:
   414  				// ED25519 Key is fixed by its own on size.
   415  				// Currently, as VaaS sees ED25519 as another curve, we do two things:
   416  				// 1. If from flow of:
   417  				// -> cfg = ReadZoneConfiguration()
   418  				// -> cfg.ValidateCertificateRequest(enrollRequest)
   419  				// -> cfg.UpdateCertificateRequest(enrollReq)
   420  				// we allow the user on setting the EllipticCurve or to leave it empty
   421  				auxCurve := certificate.EllipticCurveED25519
   422  				if curveStr == "" || curveStr == auxCurve.String() {
   423  					return true
   424  				}
   425  			default:
   426  				return
   427  			}
   428  		} else if kt == certificate.KeyTypeED25519 && allowedKey.KeyType == certificate.KeyTypeECDSA {
   429  			// 2. else we validate as policy returns to us ED25199 as an elliptic curve from ECDSA from VaaS
   430  			// flow - You already have a configuration, you read from it and you validate the policy against it:
   431  			// -> policy = cfg.ReadPolicyConfiguration()
   432  			// -> err = policy.ValidateCertificateRequest(enrollRequest)
   433  			var curve certificate.EllipticCurve
   434  			if err := curve.Set("ed25519"); err != nil {
   435  				return false
   436  			}
   437  			return curveInSlice(curve, allowedKey.KeyCurves)
   438  		}
   439  	}
   440  	return
   441  }
   442  
   443  func intInSlice(i int, s []int) bool {
   444  	for _, j := range s {
   445  		if i == j {
   446  			return true
   447  		}
   448  	}
   449  	return false
   450  }
   451  
   452  func curveInSlice(i certificate.EllipticCurve, s []certificate.EllipticCurve) bool {
   453  	for _, j := range s {
   454  		if i == j {
   455  			return true
   456  		}
   457  	}
   458  	return false
   459  }
   460  
   461  func checkStringByRegexp(s string, regexs []string) bool {
   462  	for _, r := range regexs {
   463  		matched, err := regexp.MatchString(r, s)
   464  		if err == nil && matched {
   465  			return true
   466  		}
   467  	}
   468  	return false
   469  }
   470  
   471  func isComponentValid(ss []string, regexs []string, optional bool) bool {
   472  	if optional && len(ss) == 0 {
   473  		return true
   474  	}
   475  	if len(ss) == 0 {
   476  		ss = []string{""}
   477  	}
   478  	for _, s := range ss {
   479  		if !checkStringByRegexp(s, regexs) {
   480  			return false
   481  		}
   482  	}
   483  	return true
   484  }
   485  
   486  // UpdateCertificateRequest updates a certificate request based on the zone configuration retrieved from the remote endpoint
   487  func (z *ZoneConfiguration) UpdateCertificateRequest(request *certificate.Request) {
   488  	if len(request.Subject.Organization) == 0 && z.Organization != "" {
   489  		request.Subject.Organization = []string{z.Organization}
   490  	}
   491  
   492  	if len(request.Subject.OrganizationalUnit) == 0 && z.OrganizationalUnit != nil {
   493  		request.Subject.OrganizationalUnit = z.OrganizationalUnit
   494  	}
   495  
   496  	if len(request.Subject.Country) == 0 && z.Country != "" {
   497  		request.Subject.Country = []string{z.Country}
   498  	}
   499  
   500  	if len(request.Subject.Province) == 0 && z.Province != "" {
   501  		request.Subject.Province = []string{z.Province}
   502  	}
   503  
   504  	if len(request.Subject.Locality) == 0 && z.Locality != "" {
   505  		request.Subject.Locality = []string{z.Locality}
   506  	}
   507  
   508  	if z.HashAlgorithm != x509.UnknownSignatureAlgorithm {
   509  		request.SignatureAlgorithm = z.HashAlgorithm
   510  	} else {
   511  		request.SignatureAlgorithm = x509.SHA256WithRSA
   512  	}
   513  
   514  	if z.KeyConfiguration != nil {
   515  		if request.KeyType.String() == "" {
   516  			request.KeyType = z.KeyConfiguration.KeyType
   517  		}
   518  		if request.KeyType == certificate.KeyTypeRSA {
   519  			if len(z.KeyConfiguration.KeySizes) != 0 && request.KeyLength == 0 {
   520  				request.KeyLength = z.KeyConfiguration.KeySizes[0]
   521  			}
   522  		}
   523  		if request.KeyType == certificate.KeyTypeECDSA {
   524  			if len(z.KeyConfiguration.KeyCurves) != 0 && request.KeyCurve == certificate.EllipticCurveNotSet {
   525  				request.KeyCurve = z.KeyConfiguration.KeyCurves[0]
   526  			}
   527  		}
   528  	} else {
   529  		// Zone config has no key length parameters, so we just pass user's -key-size or fall to default 2048
   530  		if request.KeyType == certificate.KeyTypeRSA && request.KeyLength == 0 {
   531  			request.KeyLength = 2048
   532  		}
   533  	}
   534  }
   535  
   536  func getPrimaryNetAddr() string {
   537  	conn, err := net.Dial("udp", "8.8.8.8:80")
   538  	if err != nil {
   539  		return "0.0.0.0"
   540  	}
   541  	defer conn.Close()
   542  	return conn.LocalAddr().(*net.UDPAddr).IP.String()
   543  }