github.com/Venafi/vcert/v5@v5.10.2/pkg/venafi/tpp/connector.go (about)

     1  /*
     2   * Copyright 2018-2025 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 tpp
    18  
    19  import (
    20  	"crypto/x509"
    21  	"encoding/json"
    22  	"encoding/pem"
    23  	"errors"
    24  	"fmt"
    25  	"log"
    26  	"net/http"
    27  	"net/mail"
    28  	neturl "net/url"
    29  	"regexp"
    30  	"strconv"
    31  	"strings"
    32  	"time"
    33  
    34  	"github.com/Venafi/vcert/v5/pkg/certificate"
    35  	"github.com/Venafi/vcert/v5/pkg/domain"
    36  	"github.com/Venafi/vcert/v5/pkg/endpoint"
    37  	"github.com/Venafi/vcert/v5/pkg/policy"
    38  	"github.com/Venafi/vcert/v5/pkg/util"
    39  	"github.com/Venafi/vcert/v5/pkg/verror"
    40  )
    41  
    42  // Connector contains the base data needed to communicate with a TPP Server
    43  type Connector struct {
    44  	baseURL     string
    45  	apiKey      string
    46  	accessToken string
    47  	verbose     bool
    48  	Identity    identity
    49  	trust       *x509.CertPool
    50  	zone        string
    51  	client      *http.Client
    52  	userAgent   string
    53  }
    54  
    55  func (c *Connector) IsCSRServiceGenerated(req *certificate.Request) (bool, error) {
    56  	panic("operation is not supported yet")
    57  }
    58  
    59  func (c *Connector) RetrieveSshConfig(ca *certificate.SshCaTemplateRequest) (*certificate.SshConfig, error) {
    60  	return RetrieveSshConfig(c, ca)
    61  }
    62  
    63  func (c *Connector) RetrieveAvailableSSHTemplates() (response []certificate.SshAvaliableTemplate, err error) {
    64  	return GetAvailableSshTemplates(c)
    65  }
    66  
    67  // NewConnector creates a new TPP Connector object used to communicate with TPP
    68  func NewConnector(url string, zone string, verbose bool, trust *x509.CertPool) (*Connector, error) {
    69  	c := Connector{verbose: verbose, trust: trust, zone: zone, userAgent: util.DefaultUserAgent}
    70  	var err error
    71  	c.baseURL, err = normalizeURL(url)
    72  	if err != nil {
    73  		return nil, fmt.Errorf("%w: failed to normalize URL: %v", verror.UserDataError, err)
    74  	}
    75  	return &c, nil
    76  }
    77  
    78  // normalizeURL normalizes the base URL used to communicate with TPP
    79  func normalizeURL(url string) (normalizedURL string, err error) {
    80  
    81  	var baseUrlRegex = regexp.MustCompile(`^https://[a-z\d]+[-a-z\d.]+[a-z\d][:\d]*/$`)
    82  
    83  	modified := util.NormalizeUrl(url)
    84  
    85  	modified = strings.TrimSuffix(modified, "vedsdk/")
    86  
    87  	if loc := baseUrlRegex.FindStringIndex(modified); loc == nil {
    88  		return "", fmt.Errorf("The specified TPP URL is invalid. %s\nExpected TPP URL format 'https://tpp.company.com/vedsdk/'", url)
    89  	}
    90  
    91  	return modified, nil
    92  }
    93  
    94  func (c *Connector) SetZone(z string) {
    95  	c.zone = z
    96  }
    97  
    98  func (c *Connector) SetUserAgent(userAgent string) {
    99  	c.userAgent = userAgent
   100  }
   101  
   102  func (c *Connector) GetType() endpoint.ConnectorType {
   103  	return endpoint.ConnectorTypeTPP
   104  }
   105  
   106  // Ping attempts to connect to the TPP Server WebSDK API and returns an error if it cannot
   107  func (c *Connector) Ping() (err error) {
   108  
   109  	//Extended timeout to allow the server to wake up
   110  	c.getHTTPClient().Timeout = time.Second * 90
   111  	statusCode, status, _, err := c.request("GET", "vedsdk/", nil)
   112  	if err != nil {
   113  		return
   114  	}
   115  	if statusCode != http.StatusOK {
   116  		err = errors.New(status)
   117  	}
   118  	return
   119  }
   120  
   121  // Authenticate authenticates the user to the TPP
   122  func (c *Connector) Authenticate(auth *endpoint.Authentication) (err error) {
   123  	defer func() {
   124  		if err != nil {
   125  			err = fmt.Errorf("%w: %s", verror.AuthError, err)
   126  		}
   127  	}()
   128  
   129  	if auth == nil {
   130  		return fmt.Errorf("failed to authenticate: missing credentials")
   131  	}
   132  
   133  	if auth.ClientId == "" {
   134  		auth.ClientId = defaultClientID
   135  	}
   136  
   137  	if auth.User != "" && auth.Password != "" {
   138  		data := authorizeResquest{Username: auth.User, Password: auth.Password}
   139  		result, err := processAuthData(c, urlResourceAuthorize, data)
   140  		if err != nil {
   141  			return err
   142  		}
   143  
   144  		resp := result.(authorizeResponse)
   145  		c.apiKey = resp.APIKey
   146  
   147  		if c.client != nil {
   148  			c.Identity, err = c.retrieveSelfIdentity()
   149  			if err != nil {
   150  				return err
   151  			}
   152  		}
   153  		return nil
   154  
   155  	} else if auth.RefreshToken != "" {
   156  		data := oauthRefreshAccessTokenRequest{Client_id: auth.ClientId, Refresh_token: auth.RefreshToken}
   157  		result, err := processAuthData(c, urlResourceRefreshAccessToken, data)
   158  		if err != nil {
   159  			return err
   160  		}
   161  
   162  		resp := result.(OauthRefreshAccessTokenResponse)
   163  		c.accessToken = resp.Access_token
   164  		auth.RefreshToken = resp.Refresh_token
   165  		if c.client != nil {
   166  			c.Identity, err = c.retrieveSelfIdentity()
   167  			if err != nil {
   168  				return err
   169  			}
   170  		}
   171  		return nil
   172  
   173  	} else if auth.AccessToken != "" {
   174  		c.accessToken = auth.AccessToken
   175  
   176  		if c.client != nil {
   177  			c.Identity, err = c.retrieveSelfIdentity()
   178  			if err != nil {
   179  				return err
   180  			}
   181  		}
   182  		return nil
   183  	}
   184  	return fmt.Errorf("failed to authenticate: can't determine valid credentials set")
   185  }
   186  
   187  // GetRefreshToken Get OAuth refresh and access token
   188  func (c *Connector) GetRefreshToken(auth *endpoint.Authentication) (resp OauthGetRefreshTokenResponse, err error) {
   189  
   190  	if auth == nil {
   191  		return resp, fmt.Errorf("failed to authenticate: missing credentials")
   192  	}
   193  
   194  	if auth.Scope == "" {
   195  		auth.Scope = defaultScope
   196  	}
   197  	if auth.ClientId == "" {
   198  		auth.ClientId = defaultClientID
   199  	}
   200  
   201  	if auth.User != "" && auth.Password != "" {
   202  		data := oauthGetRefreshTokenRequest{Username: auth.User, Password: auth.Password, Scope: auth.Scope, Client_id: auth.ClientId}
   203  		result, err := processAuthData(c, urlResourceAuthorizeOAuth, data)
   204  		if err != nil {
   205  			return resp, err
   206  		}
   207  		resp = result.(OauthGetRefreshTokenResponse)
   208  		return resp, nil
   209  
   210  	} else if auth.ClientPKCS12 {
   211  		data := oauthCertificateTokenRequest{Client_id: auth.ClientId, Scope: auth.Scope}
   212  		result, err := processAuthData(c, urlResourceAuthorizeCertificate, data)
   213  		if err != nil {
   214  			return resp, err
   215  		}
   216  
   217  		resp = result.(OauthGetRefreshTokenResponse)
   218  		return resp, nil
   219  	}
   220  
   221  	return resp, fmt.Errorf("failed to authenticate: missing credentials")
   222  }
   223  
   224  // RefreshAccessToken Refresh OAuth access token
   225  func (c *Connector) RefreshAccessToken(auth *endpoint.Authentication) (resp OauthRefreshAccessTokenResponse, err error) {
   226  
   227  	if auth == nil {
   228  		return resp, fmt.Errorf("failed to authenticate: missing credentials")
   229  	}
   230  
   231  	if auth.ClientId == "" {
   232  		auth.ClientId = defaultClientID
   233  	}
   234  
   235  	if auth.RefreshToken != "" {
   236  		data := oauthRefreshAccessTokenRequest{Client_id: auth.ClientId, Refresh_token: auth.RefreshToken}
   237  		result, err := processAuthData(c, urlResourceRefreshAccessToken, data)
   238  		if err != nil {
   239  			return resp, err
   240  		}
   241  		resp = result.(OauthRefreshAccessTokenResponse)
   242  		return resp, nil
   243  	} else {
   244  		return resp, fmt.Errorf("failed to authenticate: missing refresh token")
   245  	}
   246  }
   247  
   248  // VerifyAccessToken - call to check whether token is valid and, if so, return its properties
   249  func (c *Connector) VerifyAccessToken(auth *endpoint.Authentication) (resp OauthVerifyTokenResponse, err error) {
   250  
   251  	if auth == nil {
   252  		return resp, fmt.Errorf("failed to authenticate: missing credentials")
   253  	}
   254  
   255  	if auth.AccessToken != "" {
   256  		c.accessToken = auth.AccessToken
   257  		statusCode, statusText, body, err := c.request("GET", urlResourceAuthorizeVerify, nil)
   258  		if err != nil {
   259  			return resp, err
   260  		}
   261  
   262  		if statusCode == http.StatusOK {
   263  			var result = &OauthVerifyTokenResponse{}
   264  			err = json.Unmarshal(body, result)
   265  			if err != nil {
   266  				return resp, fmt.Errorf("failed to parse verify token response: %s, body: %s", err, body)
   267  			}
   268  			return *result, nil
   269  		}
   270  		return resp, fmt.Errorf("failed to verify token. Message: %s", statusText)
   271  	}
   272  
   273  	return resp, fmt.Errorf("failed to authenticate: missing access token")
   274  }
   275  
   276  // RevokeAccessToken - call to revoke token so that it can never be used again
   277  func (c *Connector) RevokeAccessToken(auth *endpoint.Authentication) (err error) {
   278  
   279  	if auth == nil {
   280  		return fmt.Errorf("failed to authenticate: missing credentials")
   281  	}
   282  
   283  	if auth.AccessToken != "" {
   284  		c.accessToken = auth.AccessToken
   285  		statusCode, statusText, _, err := c.request("GET", urlResourceRevokeAccessToken, nil)
   286  		if err != nil {
   287  			return err
   288  		}
   289  
   290  		if statusCode == http.StatusOK {
   291  			return nil
   292  		}
   293  		return fmt.Errorf("failed to revoke token. Message: %s", statusText)
   294  	}
   295  
   296  	return fmt.Errorf("failed to authenticate: missing access token")
   297  }
   298  
   299  func processAuthData(c *Connector, url urlResource, data interface{}) (resp interface{}, err error) {
   300  	statusCode, status, body, err := c.request("POST", url, data)
   301  	if err != nil {
   302  		return resp, err
   303  	}
   304  
   305  	var getRefresh OauthGetRefreshTokenResponse
   306  	var refreshAccess OauthRefreshAccessTokenResponse
   307  	var authorize authorizeResponse
   308  
   309  	if statusCode == http.StatusOK {
   310  		switch data.(type) {
   311  		case oauthGetRefreshTokenRequest:
   312  			err = json.Unmarshal(body, &getRefresh)
   313  			if err != nil {
   314  				return resp, err
   315  			}
   316  			resp = getRefresh
   317  		case oauthRefreshAccessTokenRequest:
   318  			err = json.Unmarshal(body, &refreshAccess)
   319  			if err != nil {
   320  				return resp, err
   321  			}
   322  			resp = refreshAccess
   323  		case authorizeResquest:
   324  			err = json.Unmarshal(body, &authorize)
   325  			if err != nil {
   326  				return resp, err
   327  			}
   328  			resp = authorize
   329  		case oauthCertificateTokenRequest:
   330  			err = json.Unmarshal(body, &getRefresh)
   331  			if err != nil {
   332  				return resp, err
   333  			}
   334  			resp = getRefresh
   335  		default:
   336  			return resp, fmt.Errorf("can not determine data type")
   337  		}
   338  	} else {
   339  		return resp, fmt.Errorf("unexpected status code on TPP Authorize. Status: %s", status)
   340  	}
   341  
   342  	return resp, nil
   343  }
   344  
   345  func (c *Connector) isAuthServerReachable() (bool, error) {
   346  	url := urlResourceAuthorizeIsAuthServer
   347  
   348  	// Extended timeout to allow the server to wake up
   349  	c.getHTTPClient().Timeout = time.Second * 90
   350  	statusCode, statusText, _, err := c.request("GET", url, nil)
   351  	if err != nil {
   352  		return false, fmt.Errorf("error while cheking the authentication server. URL: %s; Error: %v", url, err)
   353  	}
   354  
   355  	if statusCode == http.StatusAccepted && strings.Contains(statusText, "Venafi Authentication Server") {
   356  		return true, nil
   357  	}
   358  	return false, fmt.Errorf("invalid authentication server. URL: %s; Status Code: %d; Status Text: %s", url, statusCode, statusText)
   359  }
   360  
   361  func wrapAltNames(req *certificate.Request) (items []sanItem) {
   362  	for _, name := range req.EmailAddresses {
   363  		items = append(items, sanItem{1, name})
   364  	}
   365  	for _, name := range req.DNSNames {
   366  		items = append(items, sanItem{2, name})
   367  	}
   368  	for _, name := range req.IPAddresses {
   369  		items = append(items, sanItem{7, name.String()})
   370  	}
   371  	for _, name := range req.URIs {
   372  		items = append(items, sanItem{6, name.String()})
   373  	}
   374  	for _, name := range req.UPNs {
   375  		items = append(items, sanItem{0, name})
   376  	}
   377  	return items
   378  }
   379  
   380  func prepareLegacyMetadata(c *Connector, metaItems []customField, dn string) ([]guidData, error) {
   381  	metadataItems, err := c.requestAllMetadataItems(dn)
   382  	if nil != err {
   383  		return nil, err
   384  	}
   385  	customFieldsGUIDMap := make(map[string]string)
   386  	for _, item := range metadataItems {
   387  		customFieldsGUIDMap[item.Label] = item.Guid
   388  	}
   389  
   390  	var requestGUIDData []guidData
   391  	for _, item := range metaItems {
   392  		guid, prs := customFieldsGUIDMap[item.Name]
   393  		if prs {
   394  			requestGUIDData = append(requestGUIDData, guidData{guid, item.Values})
   395  		}
   396  	}
   397  	return requestGUIDData, nil
   398  }
   399  
   400  // requestAllMetadataItems returns all possible metadata items for a DN
   401  func (c *Connector) requestAllMetadataItems(dn string) ([]metadataItem, error) {
   402  	statusCode, status, body, err := c.request("POST", urlResourceAllMetadataGet, metadataGetItemsRequest{dn})
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	if statusCode != http.StatusOK {
   407  		return nil, fmt.Errorf("Unexpected http status code while fetching metadata items. %d-%s", statusCode, status)
   408  	}
   409  
   410  	var response metadataGetItemsResponse
   411  	err = json.Unmarshal(body, &response)
   412  	return response.Items, err
   413  }
   414  
   415  // requestMetadataItems returns metadata items for a DN that have a value stored
   416  func (c *Connector) requestMetadataItems(dn string) ([]metadataKeyValueSet, error) {
   417  	statusCode, status, body, err := c.request("POST", urlResourceMetadataGet, metadataGetItemsRequest{dn})
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  	if statusCode != http.StatusOK {
   422  		return nil, fmt.Errorf("Unexpected http status code while fetching certificate metadata items. %d-%s", statusCode, status)
   423  	}
   424  	var response metadataGetResponse
   425  	err = json.Unmarshal(body, &response)
   426  	return response.Data, err
   427  }
   428  
   429  // Retrieve user's self identity
   430  func (c *Connector) retrieveSelfIdentity() (response identity, err error) {
   431  
   432  	var respIndentities = &identitiesResponse{}
   433  
   434  	statusCode, statusText, body, err := c.request("GET", urlRetrieveSelfIdentity, nil)
   435  	if err != nil {
   436  		log.Printf("Failed to get the used user. Error: %v", err)
   437  		return identity{}, err
   438  	}
   439  
   440  	switch statusCode {
   441  	case http.StatusOK:
   442  		err = json.Unmarshal(body, respIndentities)
   443  		if err != nil {
   444  			return identity{}, fmt.Errorf("failed to parse identity response: %s, body: %s", err, body)
   445  		}
   446  
   447  		if (respIndentities != nil) && (len(respIndentities.Identities) > 0) {
   448  			return respIndentities.Identities[0], nil
   449  		}
   450  	case http.StatusUnauthorized:
   451  		return identity{}, verror.AuthError
   452  	}
   453  	return identity{}, fmt.Errorf("failed to get Self. Status code: %d, Status text: %s", statusCode, statusText)
   454  }
   455  
   456  // RetrieveSystemVersion returns the TPP system version of the connector context
   457  func (c *Connector) RetrieveSystemVersion() (string, error) {
   458  	statusCode, status, body, err := c.request("GET", urlResourceSystemStatusVersion, "")
   459  	if err != nil {
   460  		return "", err
   461  	}
   462  	//Put in hint for authentication scope 'configuration'
   463  	switch statusCode {
   464  	case 200:
   465  	case 401:
   466  		return "", fmt.Errorf("http status code '%s' was returned by the server. Hint: OAuth scope 'configuration' is required when using custom fields", status)
   467  	default:
   468  		return "", fmt.Errorf("Unexpected http status code while fetching TPP version. %s", status)
   469  	}
   470  
   471  	var response struct{ Version string }
   472  	err = json.Unmarshal(body, &response)
   473  	return response.Version, err
   474  }
   475  
   476  // setCertificateMetadata submits the metadata to TPP for storage returning the lock status of the metadata stored
   477  func (c *Connector) setCertificateMetadata(metadataRequest metadataSetRequest) (bool, error) {
   478  	if metadataRequest.DN == "" {
   479  		return false, fmt.Errorf("DN must be provided to setCertificateMetaData")
   480  	}
   481  	if len(metadataRequest.GuidData) == 0 && metadataRequest.KeepExisting {
   482  		return false, nil
   483  	} //Not an error, but there is nothing to do
   484  
   485  	statusCode, status, body, err := c.request("POST", urlResourceMetadataSet, metadataRequest)
   486  	if err != nil {
   487  		return false, err
   488  	}
   489  	if statusCode != http.StatusOK {
   490  		return false, fmt.Errorf("Unexpected http status code while setting metadata items. %d-%s", statusCode, status)
   491  	}
   492  
   493  	var result = metadataSetResponse{}
   494  	err = json.Unmarshal(body, &result)
   495  	if err != nil {
   496  		return false, err
   497  	}
   498  
   499  	switch result.Result {
   500  	case 0:
   501  		break
   502  	case 17:
   503  		return false, fmt.Errorf("custom field value not a valid list item. Server returned error %v", result.Result)
   504  	default:
   505  		return false, fmt.Errorf("return code %v was returned while adding metadata to %v. Please refer to the Metadata Result Codes in the TPP WebSDK API documentation to determine if further action is needed", result.Result, metadataRequest.DN)
   506  	}
   507  	return result.Locked, nil
   508  }
   509  
   510  func (c *Connector) prepareRequest(req *certificate.Request, zone string) (tppReq certificateRequest, err error) {
   511  	switch req.CsrOrigin {
   512  	case certificate.LocalGeneratedCSR, certificate.UserProvidedCSR:
   513  		tppReq.PKCS10 = string(req.GetCSR())
   514  	case certificate.ServiceGeneratedCSR:
   515  		tppReq.Subject = req.Subject.CommonName // TODO: there is some problem because Subject is not only CN
   516  		if !req.OmitSANs {
   517  			tppReq.SubjectAltNames = wrapAltNames(req)
   518  		}
   519  	default:
   520  		return tppReq, fmt.Errorf("Unexpected option in PrivateKeyOrigin")
   521  	}
   522  
   523  	tppReq.CertificateType = "AUTO"
   524  	tppReq.PolicyDN = getPolicyDN(zone)
   525  	tppReq.CADN = req.CADN
   526  	tppReq.ObjectName = req.FriendlyName
   527  	tppReq.DisableAutomaticRenewal = true
   528  	customFieldsMap := make(map[string][]string)
   529  	origin := endpoint.SDKName
   530  	for _, f := range req.CustomFields {
   531  		switch f.Type {
   532  		case certificate.CustomFieldPlain:
   533  			customFieldsMap[f.Name] = append(customFieldsMap[f.Name], f.Value)
   534  		case certificate.CustomFieldOrigin:
   535  			origin = f.Value
   536  		}
   537  	}
   538  	tppReq.CASpecificAttributes = append(tppReq.CASpecificAttributes, nameValuePair{Name: "Origin", Value: origin})
   539  	tppReq.Origin = origin
   540  
   541  	validityDuration := req.ValidityDuration
   542  
   543  	// DEPRECATED: ValidityHours is deprecated in favor of ValidityDuration, but we
   544  	// still support it for backwards compatibility.
   545  	if validityDuration == nil && req.ValidityHours > 0 { //nolint:staticcheck
   546  		duration := time.Duration(req.ValidityHours) * time.Hour //nolint:staticcheck
   547  		validityDuration = &duration
   548  	}
   549  
   550  	if validityDuration != nil {
   551  		formattedExpirationDate := time.Now().Add(*validityDuration).Format(time.RFC3339)
   552  
   553  		var attributeNames []string
   554  
   555  		switch req.IssuerHint {
   556  		case util.IssuerHintDigicert:
   557  			attributeNames = []string{"DigiCert CA:Specific End Date"}
   558  		case util.IssuerHintMicrosoft:
   559  			attributeNames = []string{"Microsoft CA:Specific End Date"}
   560  		case util.IssuerHintEntrust:
   561  			attributeNames = []string{"EntrustNET CA:Specific End Date"}
   562  		case util.IssuerHintAllIssuers:
   563  			attributeNames = []string{
   564  				"Microsoft CA:Specific End Date",
   565  				"DigiCert CA:Specific End Date",
   566  				"EntrustNET CA:Specific End Date",
   567  				"Specific End Date",
   568  			}
   569  		case util.IssuerHintGeneric:
   570  			attributeNames = []string{"Specific End Date"}
   571  		default:
   572  			return tppReq, fmt.Errorf("invalid issuer hint: %s", req.IssuerHint.String())
   573  		}
   574  
   575  		for _, attributeName := range attributeNames {
   576  			tppReq.CASpecificAttributes = append(tppReq.CASpecificAttributes, nameValuePair{
   577  				Name:  attributeName,
   578  				Value: formattedExpirationDate,
   579  			})
   580  		}
   581  	}
   582  
   583  	// Resolve emails to TPP identities if needed.
   584  	var contacts []IdentityEntry
   585  	if req.Contacts != nil {
   586  		var err error
   587  		prefixedUniversals, err := c.resolvePrefixedUniversals(req.Contacts)
   588  		if err != nil {
   589  			return tppReq, fmt.Errorf("failed to find contact identities: %w", err)
   590  		}
   591  		for _, prefixedUniversal := range prefixedUniversals {
   592  			contacts = append(contacts, IdentityEntry{PrefixedUniversal: prefixedUniversal})
   593  		}
   594  	}
   595  	tppReq.Contacts = contacts
   596  
   597  	for name, value := range customFieldsMap {
   598  		tppReq.CustomFields = append(tppReq.CustomFields, customField{name, value})
   599  	}
   600  	if req.Location != nil {
   601  		if req.Location.Instance == "" {
   602  			return tppReq, fmt.Errorf("%w: instance value for Location should not be empty", verror.UserDataError)
   603  		}
   604  		workload := req.Location.Workload
   605  		if workload == "" {
   606  			workload = defaultWorkloadName
   607  		}
   608  
   609  		deviceDN := getPolicyDN(zone)
   610  		if req.Location.Zone != "" {
   611  			deviceDN = getPolicyDN(req.Location.Zone)
   612  		}
   613  
   614  		dev := device{
   615  			PolicyDN:   deviceDN,
   616  			ObjectName: req.Location.Instance,
   617  			Host:       req.Location.Instance,
   618  			Applications: []application{
   619  				{
   620  					ObjectName: workload,
   621  					Class:      "Basic",
   622  					DriverName: "appbasic",
   623  				},
   624  			},
   625  		}
   626  		if req.Location.TLSAddress != "" {
   627  			host, port, err := parseHostPort(req.Location.TLSAddress)
   628  			if err != nil {
   629  				return tppReq, err
   630  			}
   631  			dev.Applications[0].ValidationHost = host
   632  			dev.Applications[0].ValidationPort = port
   633  		}
   634  		tppReq.Devices = append(tppReq.Devices, dev)
   635  	}
   636  	switch req.KeyType {
   637  	case certificate.KeyTypeRSA:
   638  		tppReq.KeyAlgorithm = "RSA"
   639  		tppReq.KeyBitSize = req.KeyLength
   640  	case certificate.KeyTypeECDSA:
   641  		tppReq.KeyAlgorithm = "ECC"
   642  		tppReq.EllipticCurve = req.KeyCurve.String()
   643  	}
   644  
   645  	//Setting the certificate will be re-enabled.
   646  	//From https://docs.venafi.com/Docs/currentSDK/TopNav/Content/SDK/WebSDK/r-SDK-POST-Certificates-request.php
   647  	//Reenable (Optional) The action to control a previously disabled certificate:
   648  	//
   649  	//    - false: Default. Do not renew a previously disabled certificate.
   650  	//    - true: Clear the Disabled attribute, reenable, and then renew the certificate (in this request). Reuse the same CertificateDN, that is also known as a Certificate object.
   651  	tppReq.Reenable = true
   652  
   653  	// If "Timeout" is defined by the user in the request, we use it in order to
   654  	// override API's timeout for the CA to finish issuance. In TLSPDC this means
   655  	// using WorkToDoTimeout attribute.
   656  	// We make sure to get the seconds from
   657  	// "Timeout" as it is a "TimeDuration" and remote (TLSPDC) only expects value in seconds.
   658  	if req.Timeout > 0 {
   659  		seconds := int64(req.Timeout.Seconds())
   660  		secondsString := strconv.FormatInt(seconds, 10)
   661  		tppReq.WorkToDoTimeout = secondsString
   662  	}
   663  
   664  	return tppReq, err
   665  }
   666  
   667  func (c *Connector) proccessLocation(req *certificate.Request) error {
   668  	certDN := getCertificateDN(c.zone, req.FriendlyName, req.Subject.CommonName)
   669  	guid, err := c.configDNToGuid(certDN)
   670  	if err != nil {
   671  		return fmt.Errorf("unable to retrieve certificate guid: %s", err)
   672  	}
   673  	if guid == "" {
   674  		if c.verbose {
   675  			log.Printf("certificate with DN %s doesn't exists so no need to check if it is associated with any instances", certDN)
   676  		}
   677  		return nil
   678  	}
   679  	details, err := c.searchCertificateDetails(guid)
   680  	if err != nil {
   681  		return err
   682  	}
   683  	if len(details.Consumers) == 0 {
   684  		log.Printf("There were no instances associated with certificate %s", certDN)
   685  		return nil
   686  	}
   687  	if c.verbose {
   688  		log.Printf("checking associated instances from:\n %s", details.Consumers)
   689  	}
   690  	var device string
   691  	requestedDevice := getDeviceDN(stripBackSlashes(c.zone), *req.Location)
   692  
   693  	for _, device = range details.Consumers {
   694  		if c.verbose {
   695  			log.Printf("comparing requested instance %s to %s", requestedDevice, device)
   696  		}
   697  		if device == requestedDevice {
   698  			if req.Location.Replace {
   699  				err = c.dissociate(certDN, device)
   700  				if err != nil {
   701  					return err
   702  				}
   703  			} else {
   704  				return fmt.Errorf("%w: instance %s already exists, change the value or use --replace-instance", verror.UserDataError, device)
   705  			}
   706  		}
   707  	}
   708  	return nil
   709  }
   710  
   711  // RequestCertificate submits the CSR to TPP returning the DN of the requested
   712  // Certificate.
   713  func (c *Connector) RequestCertificate(req *certificate.Request) (requestID string, err error) {
   714  	if req.Location != nil {
   715  		err = c.proccessLocation(req)
   716  		if err != nil {
   717  			return
   718  		}
   719  	}
   720  
   721  	tppCertificateRequest, err := c.prepareRequest(req, c.zone)
   722  	if err != nil {
   723  		return "", err
   724  	}
   725  
   726  	statusCode, status, body, err := c.request("POST", urlResourceCertificateRequest, tppCertificateRequest)
   727  	if err != nil {
   728  		return "", err
   729  	}
   730  	requestID, err = parseRequestResult(statusCode, status, body)
   731  	if err != nil {
   732  		return "", err
   733  	}
   734  	req.PickupID = requestID
   735  
   736  	if len(req.CustomFields) == 0 {
   737  		return
   738  	}
   739  
   740  	// Handle legacy TPP custom field API
   741  	//Get the saved metadata for the current certificate, deep compare the
   742  	//saved metadata to the requested metadata. If all items match then no further
   743  	//changes need to be made. If they do not match, they try to update them using
   744  	//the 19.2 WebSDK calls
   745  	metadataItems, err := c.requestMetadataItems(requestID)
   746  	if err != nil {
   747  		log.Println(err)
   748  		return
   749  	}
   750  	//prepare struct for search
   751  	metadata := make(map[string]map[string]struct{})
   752  	for _, item := range metadataItems {
   753  		metadata[item.Key.Label] = make(map[string]struct{})
   754  		for _, v := range item.Value {
   755  			metadata[item.Key.Label][v] = struct{}{} //empty struct has zero size
   756  		}
   757  	}
   758  	//Deep compare the request metadata to the fetched metadata
   759  	var allItemsFound = true
   760  	for _, cf := range tppCertificateRequest.CustomFields {
   761  		values, prs := metadata[cf.Name]
   762  		if !prs {
   763  			allItemsFound = false
   764  			break
   765  		}
   766  		for _, value := range cf.Values {
   767  			_, prs := values[value]
   768  			if !prs {
   769  				//Found the field by name, but couldn't find one of the values
   770  				allItemsFound = false
   771  			}
   772  		}
   773  	}
   774  
   775  	if allItemsFound {
   776  		return
   777  	}
   778  	log.Println("Saving metadata custom field using 19.2 method")
   779  	//Create a metadata/set command with the metadata from tppCertificateRequest
   780  	guidItems, err := prepareLegacyMetadata(c, tppCertificateRequest.CustomFields, requestID)
   781  	if err != nil {
   782  		log.Println(err)
   783  		return
   784  	}
   785  	requestData := metadataSetRequest{requestID, guidItems, true}
   786  	//c.request with the metadata request
   787  	_, err = c.setCertificateMetadata(requestData)
   788  	if err != nil {
   789  		log.Println(err)
   790  	}
   791  	return
   792  }
   793  
   794  // SynchronousRequestCertificate It's not supported yet in TPP
   795  func (c *Connector) SynchronousRequestCertificate(_ *certificate.Request) (certificates *certificate.PEMCollection, err error) {
   796  	panic("operation is not supported yet")
   797  }
   798  
   799  // SupportSynchronousRequestCertificate returns if the connector support synchronous calls to request a certificate.
   800  func (c *Connector) SupportSynchronousRequestCertificate() bool {
   801  	return false
   802  }
   803  
   804  type ErrCertNotFound struct {
   805  	error
   806  }
   807  
   808  func (e *ErrCertNotFound) Error() string {
   809  	return e.error.Error()
   810  }
   811  
   812  func (e *ErrCertNotFound) Unwrap() error {
   813  	return e.error
   814  }
   815  
   816  func IsCertNotFound(err error) bool {
   817  	notFoundErr := &ErrCertNotFound{}
   818  	return errors.As(err, &notFoundErr)
   819  }
   820  
   821  // This function is idempotent, i.e., it won't fail if there is nothing to be
   822  // reset. It returns an error of type *ErrCertNotFound if the certificate is not
   823  // found.
   824  func (c *Connector) ResetCertificate(req *certificate.Request, restart bool) (err error) {
   825  	certificateDN := getCertificateDN(c.zone, req.FriendlyName, req.Subject.CommonName)
   826  
   827  	statusCode, status, body, err := c.request("POST", urlResourceCertificateReset, certificateResetRequest{
   828  		CertificateDN: certificateDN,
   829  		Restart:       restart,
   830  	})
   831  	if err != nil {
   832  		return fmt.Errorf("while resetting: %w", err)
   833  	}
   834  
   835  	switch {
   836  	case statusCode == http.StatusOK:
   837  		return nil
   838  	case statusCode == http.StatusBadRequest:
   839  		var decodedResetResponse certificateRequestResponse
   840  		if err := json.Unmarshal(body, &decodedResetResponse); err != nil {
   841  			return fmt.Errorf("failed to decode reset response: HTTP %d: %s: %s", statusCode, status, body)
   842  		}
   843  
   844  		// No need to error out if the certificate was already reset.
   845  		if decodedResetResponse.Error == "Reset is not completed. No reset is required for the certificate." {
   846  			return nil
   847  		}
   848  
   849  		if strings.HasSuffix(decodedResetResponse.Error, "does not exist or you do not have sufficient rights to the object.") {
   850  			return &ErrCertNotFound{errors.New(decodedResetResponse.Error)}
   851  		}
   852  
   853  		return fmt.Errorf("while resetting: %s", decodedResetResponse.Error)
   854  	default:
   855  		return fmt.Errorf("while resetting. Status: %s, Body: %s", status, string(body))
   856  	}
   857  }
   858  
   859  func (c *Connector) GetPolicy(name string) (*policy.PolicySpecification, error) {
   860  	var ps *policy.PolicySpecification
   861  	var tp policy.TppPolicy
   862  
   863  	log.Println("Collecting policy attributes")
   864  
   865  	if !strings.HasPrefix(name, util.PathSeparator) {
   866  		name = util.PathSeparator + name
   867  	}
   868  
   869  	if !strings.HasPrefix(name, policy.RootPath) {
   870  		name = policy.RootPath + name
   871  
   872  	}
   873  
   874  	tp.Name = &name
   875  
   876  	var checkPolicyResponse policy.CheckPolicyResponse
   877  
   878  	req := policy.CheckPolicyRequest{
   879  		PolicyDN: name,
   880  	}
   881  	_, _, body, err := c.request("POST", urlResourceCheckPolicy, req)
   882  
   883  	if err != nil {
   884  		return nil, err
   885  	}
   886  
   887  	err = json.Unmarshal(body, &checkPolicyResponse)
   888  	if err != nil {
   889  		return nil, err
   890  	}
   891  
   892  	if checkPolicyResponse.Error != "" {
   893  		return nil, errors.New(checkPolicyResponse.Error)
   894  	}
   895  
   896  	log.Println("Building policy")
   897  	ps, err = policy.BuildPolicySpecificationForTPP(checkPolicyResponse)
   898  	if err != nil {
   899  		return nil, err
   900  	}
   901  
   902  	userNames, error := c.retrieveUserNamesForPolicySpecification(name)
   903  	if error != nil {
   904  		return nil, error
   905  	}
   906  	ps.Users = userNames
   907  
   908  	return ps, nil
   909  }
   910  
   911  func (c *Connector) retrieveUserNamesForPolicySpecification(policyName string) ([]string, error) {
   912  	values, _, error := getPolicyAttribute(c, policy.TppContact, policyName)
   913  	if error != nil {
   914  		return nil, error
   915  	}
   916  	if values != nil {
   917  		var users []string
   918  		for _, prefixedUniversal := range values {
   919  			validateIdentityRequest := ValidateIdentityRequest{
   920  				ID: IdentityInformation{
   921  					PrefixedUniversal: prefixedUniversal,
   922  				},
   923  			}
   924  
   925  			validateIdentityResponse, error := c.validateIdentity(validateIdentityRequest)
   926  			if error != nil {
   927  				return nil, error
   928  			}
   929  
   930  			users = append(users, validateIdentityResponse.ID.Name)
   931  		}
   932  
   933  		return users, nil
   934  	}
   935  
   936  	return nil, nil
   937  }
   938  
   939  func (c *Connector) validateIdentity(validateIdentityRequest ValidateIdentityRequest) (*ValidateIdentityResponse, error) {
   940  
   941  	statusCode, status, body, err := c.request("POST", urlResourceValidateIdentity, validateIdentityRequest)
   942  	if err != nil {
   943  		return nil, err
   944  	}
   945  	validateIdentityResponse, err := parseValidateIdentityResponse(statusCode, status, body)
   946  	if err != nil {
   947  		return nil, err
   948  	}
   949  	return &validateIdentityResponse, nil
   950  }
   951  
   952  func PolicyExist(policyName string, c *Connector) (bool, error) {
   953  
   954  	req := policy.PolicyExistPayloadRequest{
   955  		ObjectDN: policyName,
   956  	}
   957  	_, _, body, err := c.request("POST", urlResourceIsValidPolicy, req)
   958  
   959  	if err != nil {
   960  		return false, err
   961  	}
   962  	var response policy.PolicyIsValidResponse
   963  	err = json.Unmarshal(body, &response)
   964  
   965  	if err != nil {
   966  		return false, err
   967  	}
   968  
   969  	//if error is not null then the policy doesn't exists
   970  	if response.Result == 1 && response.PolicyObject.DN != "" {
   971  		return true, nil
   972  	} else if (response.Error != "") && (response.Result == 400) {
   973  		return false, nil
   974  	} else {
   975  		return false, errors.New(response.Error)
   976  	}
   977  
   978  }
   979  
   980  func (c *Connector) SetPolicy(name string, ps *policy.PolicySpecification) (string, error) {
   981  
   982  	//validate policy specification and policy
   983  	err := policy.ValidateTppPolicySpecification(ps)
   984  
   985  	if err != nil {
   986  		return "", err
   987  	}
   988  
   989  	log.Printf("policy specification is valid")
   990  	var status string
   991  	tppPolicy := policy.BuildTppPolicy(ps)
   992  	if !strings.HasPrefix(name, util.PathSeparator) {
   993  		name = util.PathSeparator + name
   994  	}
   995  
   996  	if !strings.HasPrefix(name, policy.RootPath) {
   997  		name = policy.RootPath + name
   998  
   999  	}
  1000  
  1001  	tppPolicy.Name = &name
  1002  
  1003  	//validate if the policy exists
  1004  	policyExists, err := PolicyExist(name, c)
  1005  	if err != nil {
  1006  		return "", err
  1007  	}
  1008  
  1009  	if policyExists {
  1010  		log.Printf("found existing policy folder: %s", name)
  1011  	} else {
  1012  
  1013  		//validate if the parent exist
  1014  		parent := policy.GetParent(name)
  1015  
  1016  		parentExist, err := PolicyExist(parent, c)
  1017  		if err != nil {
  1018  			return "", err
  1019  		}
  1020  
  1021  		if parent != policy.RootPath && !parentExist {
  1022  
  1023  			return "", fmt.Errorf("the policy's parent doesn't exists")
  1024  
  1025  		}
  1026  	}
  1027  
  1028  	//step 1 create root policy folder.
  1029  	if !policyExists {
  1030  
  1031  		log.Printf("creating policy folder: %s", name)
  1032  
  1033  		req := policy.PolicyPayloadRequest{
  1034  			Class:    policy.PolicyClass,
  1035  			ObjectDN: *(tppPolicy.Name),
  1036  		}
  1037  
  1038  		_, _, _, err = c.request("POST", urlResourceCreatePolicy, req)
  1039  
  1040  		if err != nil {
  1041  			return "", err
  1042  		}
  1043  	}
  1044  	//step 2 create policy's attributes.
  1045  
  1046  	log.Printf("updating certificate policy attributes")
  1047  
  1048  	//create Approver
  1049  	if tppPolicy.Approver != nil {
  1050  		_, _, _, err = createPolicyAttribute(c, policy.TppApprover, tppPolicy.Approver, *(tppPolicy.Name), true)
  1051  		if err != nil {
  1052  			return "", err
  1053  		}
  1054  	}
  1055  	if policyExists {
  1056  		err = resetTPPAttributes(*(tppPolicy.Name), c)
  1057  		if err != nil {
  1058  			return "", err
  1059  		}
  1060  	}
  1061  
  1062  	//set Contacts
  1063  	status, err = c.setContact(&tppPolicy)
  1064  	if err != nil {
  1065  		return "", err
  1066  	}
  1067  
  1068  	//create Domain Suffix Whitelist
  1069  	if tppPolicy.ManagementType != nil {
  1070  		_, status, _, err = createPolicyAttribute(c, policy.TppManagementType, []string{tppPolicy.ManagementType.Value}, *(tppPolicy.Name), tppPolicy.ManagementType.Locked)
  1071  		if err != nil {
  1072  			return "", err
  1073  		}
  1074  	}
  1075  
  1076  	//create Domain Suffix Whitelist
  1077  	if tppPolicy.DomainSuffixWhitelist != nil {
  1078  		_, status, _, err = createPolicyAttribute(c, policy.TppDomainSuffixWhitelist, tppPolicy.DomainSuffixWhitelist, *(tppPolicy.Name), true)
  1079  		if err != nil {
  1080  			return "", err
  1081  		}
  1082  	}
  1083  
  1084  	//create Prohibit Wildcard
  1085  	if tppPolicy.ProhibitWildcard != nil {
  1086  		_, status, _, err = createPolicyAttribute(c, policy.TppProhibitWildcard, []string{strconv.Itoa(*(tppPolicy.ProhibitWildcard))}, *(tppPolicy.Name), false)
  1087  		if err != nil {
  1088  			return "", err
  1089  		}
  1090  	}
  1091  
  1092  	//create Certificate Authority
  1093  	if tppPolicy.CertificateAuthority != nil {
  1094  		_, status, _, err = createPolicyAttribute(c, policy.TppCertificateAuthority, []string{*(tppPolicy.CertificateAuthority)}, *(tppPolicy.Name), false)
  1095  		if err != nil {
  1096  			return "", err
  1097  		}
  1098  	}
  1099  
  1100  	//create Organization attribute
  1101  	if tppPolicy.Organization != nil {
  1102  		_, status, _, err = createPolicyAttribute(c, policy.TppOrganization, []string{tppPolicy.Organization.Value}, *(tppPolicy.Name), tppPolicy.Organization.Locked)
  1103  		if err != nil {
  1104  			return "", err
  1105  		}
  1106  	}
  1107  
  1108  	//create Organizational Unit attribute
  1109  	if tppPolicy.OrganizationalUnit != nil {
  1110  		_, status, _, err = createPolicyAttribute(c, policy.TppOrganizationalUnit, tppPolicy.OrganizationalUnit.Value, *(tppPolicy.Name), tppPolicy.OrganizationalUnit.Locked)
  1111  		if err != nil {
  1112  			return "", err
  1113  		}
  1114  	}
  1115  	//create City attribute
  1116  	if tppPolicy.City != nil {
  1117  		_, status, _, err = createPolicyAttribute(c, policy.TppCity, []string{tppPolicy.City.Value}, *(tppPolicy.Name), tppPolicy.City.Locked)
  1118  		if err != nil {
  1119  			return "", err
  1120  		}
  1121  	}
  1122  
  1123  	//create State attribute
  1124  	if tppPolicy.State != nil {
  1125  		_, status, _, err = createPolicyAttribute(c, policy.TppState, []string{tppPolicy.State.Value}, *(tppPolicy.Name), tppPolicy.State.Locked)
  1126  		if err != nil {
  1127  			return "", err
  1128  		}
  1129  	}
  1130  
  1131  	//create Country attribute
  1132  	if tppPolicy.Country != nil {
  1133  		_, status, _, err = createPolicyAttribute(c, policy.TppCountry, []string{tppPolicy.Country.Value}, *(tppPolicy.Name), tppPolicy.Country.Locked)
  1134  		if err != nil {
  1135  			return "", err
  1136  		}
  1137  	}
  1138  
  1139  	// Check the TPP version is 25.x or greater
  1140  	tppVersionNumber := -1
  1141  	tppVersion, err := c.RetrieveSystemVersion()
  1142  	if err != nil {
  1143  		return "", err
  1144  	}
  1145  	if strings.Contains(tppVersion, ".") {
  1146  		tppVersionNumber, err = strconv.Atoi(strings.Split(tppVersion, ".")[0])
  1147  		if err != nil {
  1148  			return "", err
  1149  		}
  1150  	}
  1151  
  1152  	if tppVersionNumber >= 25 {
  1153  		// create "PKIX Parameter Set" attribute
  1154  		var pkixOid string
  1155  		if tppPolicy.PkixParameterSet != nil {
  1156  			_, status, _, err = createPolicyAttribute(c, policy.TppPkixParameterSetPolicy, tppPolicy.PkixParameterSet.Value, *(tppPolicy.Name), tppPolicy.PkixParameterSet.Locked)
  1157  			if err != nil {
  1158  				return "", err
  1159  			}
  1160  		} else {
  1161  			// For backward compatibility, if the "PKIX Parameter Set" is not set, we need to set it using the "Key Algorithm",
  1162  			// "Key Bit Strength" and "Elliptic Curve" attribute values
  1163  			if tppPolicy.KeyAlgorithm != nil {
  1164  				if algValues, ok := policy.KeyAlgorithmsToPKIX[tppPolicy.KeyAlgorithm.Value]; ok {
  1165  					if tppPolicy.KeyBitStrength != nil {
  1166  						pkixOid = algValues[tppPolicy.KeyBitStrength.Value]
  1167  					}
  1168  					if tppPolicy.EllipticCurve != nil && strings.ToUpper(tppPolicy.KeyAlgorithm.Value) != "RSA" {
  1169  						pkixOid = algValues[tppPolicy.EllipticCurve.Value]
  1170  					}
  1171  					if pkixOid != "" {
  1172  						_, _, _, err = createPolicyAttribute(c, policy.TppPkixParameterSetPolicy, []string{pkixOid}, *(tppPolicy.Name), tppPolicy.KeyAlgorithm.Locked)
  1173  						if err != nil {
  1174  							return "", err
  1175  						}
  1176  						// set the "PKIX Parameter Set Default" attribute value as well
  1177  						_, status, _, err = createPolicyAttribute(c, policy.TppPkixParameterSetPolicyDefault, []string{pkixOid}, *(tppPolicy.Name), tppPolicy.KeyAlgorithm.Locked)
  1178  						if err != nil {
  1179  							return "", err
  1180  						}
  1181  					}
  1182  				}
  1183  			}
  1184  		}
  1185  
  1186  		// create "PKIX Parameter Set Default" attribute
  1187  		if tppPolicy.PkixParameterSetDefault != nil {
  1188  			_, status, _, err = createPolicyAttribute(c, policy.TppPkixParameterSetPolicyDefault, []string{tppPolicy.PkixParameterSetDefault.Value}, *(tppPolicy.Name), tppPolicy.PkixParameterSetDefault.Locked)
  1189  			if err != nil {
  1190  				return "", err
  1191  			}
  1192  		}
  1193  	} else {
  1194  		//create Key Algorithm attribute
  1195  		if tppPolicy.KeyAlgorithm != nil {
  1196  			_, status, _, err = createPolicyAttribute(c, policy.TppKeyAlgorithm, []string{tppPolicy.KeyAlgorithm.Value}, *(tppPolicy.Name), tppPolicy.KeyAlgorithm.Locked)
  1197  			if err != nil {
  1198  				return "", err
  1199  			}
  1200  		}
  1201  		//create Key Bit Strength
  1202  		if tppPolicy.KeyBitStrength != nil {
  1203  			_, status, _, err = createPolicyAttribute(c, policy.TppKeyBitStrength, []string{tppPolicy.KeyBitStrength.Value}, *(tppPolicy.Name), tppPolicy.KeyBitStrength.Locked)
  1204  			if err != nil {
  1205  				return "", err
  1206  			}
  1207  		}
  1208  		//create Elliptic Curve attribute
  1209  		if tppPolicy.EllipticCurve != nil {
  1210  			_, status, _, err = createPolicyAttribute(c, policy.TppEllipticCurve, []string{tppPolicy.EllipticCurve.Value}, *(tppPolicy.Name), tppPolicy.EllipticCurve.Locked)
  1211  			if err != nil {
  1212  				return "", err
  1213  			}
  1214  		}
  1215  	}
  1216  
  1217  	//create Manual Csr attribute
  1218  	if tppPolicy.ManualCsr != nil {
  1219  		_, status, _, err = createPolicyAttribute(c, policy.ServiceGenerated, []string{tppPolicy.ManualCsr.Value}, *(tppPolicy.Name), tppPolicy.ManualCsr.Locked)
  1220  		if err != nil {
  1221  			return "", err
  1222  		}
  1223  	}
  1224  
  1225  	if tppPolicy.ProhibitedSANType != nil {
  1226  		_, status, _, err = createPolicyAttribute(c, policy.TppProhibitedSANTypes, tppPolicy.ProhibitedSANType, *(tppPolicy.Name), false)
  1227  		if err != nil {
  1228  			return "", err
  1229  		}
  1230  	}
  1231  
  1232  	//Allow "Private Key Reuse" & "Want Renewal"
  1233  	if tppPolicy.AllowPrivateKeyReuse != nil {
  1234  		_, status, _, err = createPolicyAttribute(c, policy.TppAllowPrivateKeyReuse, []string{strconv.Itoa(*(tppPolicy.AllowPrivateKeyReuse))}, *(tppPolicy.Name), true)
  1235  		if err != nil {
  1236  			return "", err
  1237  		}
  1238  	}
  1239  
  1240  	if tppPolicy.WantRenewal != nil {
  1241  		_, status, _, err = createPolicyAttribute(c, policy.TppWantRenewal, []string{strconv.Itoa(*(tppPolicy.WantRenewal))}, *(tppPolicy.Name), true)
  1242  		if err != nil {
  1243  			return "", err
  1244  		}
  1245  	}
  1246  
  1247  	log.Printf("policy successfully applied to %s", name)
  1248  
  1249  	return status, nil
  1250  }
  1251  
  1252  func (c *Connector) setContact(tppPolicy *policy.TppPolicy) (status string, err error) {
  1253  
  1254  	if tppPolicy.Contact != nil {
  1255  		contacts, err := c.resolvePrefixedUniversals(tppPolicy.Contact)
  1256  		if err != nil {
  1257  			return "", fmt.Errorf("an error happened trying to resolve the contacts: %w", err)
  1258  		}
  1259  		if contacts != nil {
  1260  			tppPolicy.Contact = contacts
  1261  
  1262  			_, status, _, err = createPolicyAttribute(c, policy.TppContact, tppPolicy.Contact, *(tppPolicy.Name), true)
  1263  			if err != nil {
  1264  				return "", err
  1265  			}
  1266  		}
  1267  	}
  1268  
  1269  	return status, nil
  1270  }
  1271  
  1272  func (c *Connector) resolvePrefixedUniversals(filters []string) ([]string, error) {
  1273  	prefixedUniversals := make([]string, 0)
  1274  	identities, err := c.resolveIdentities(filters)
  1275  	if err != nil {
  1276  		return nil, err
  1277  	}
  1278  	for _, identityEntry := range identities {
  1279  		prefixedUniversals = append(prefixedUniversals, identityEntry.PrefixedUniversal)
  1280  	}
  1281  
  1282  	return prefixedUniversals, nil
  1283  }
  1284  
  1285  func (c *Connector) resolveIdentities(filters []string) ([]*IdentityEntry, error) {
  1286  	identities := make([]*IdentityEntry, 0)
  1287  	uniqueContacts := getUniqueStringSlice(filters)
  1288  	for _, contact := range uniqueContacts {
  1289  		identityEntry, err := c.getIdentity(contact)
  1290  		if err != nil {
  1291  			return nil, err
  1292  		}
  1293  		identities = append(identities, identityEntry)
  1294  	}
  1295  
  1296  	return identities, nil
  1297  }
  1298  
  1299  func getUniqueStringSlice(stringSlice []string) []string {
  1300  	keys := make(map[string]bool)
  1301  	var list []string
  1302  	for _, entry := range stringSlice {
  1303  		if _, found := keys[entry]; !found {
  1304  			keys[entry] = true
  1305  			list = append(list, entry)
  1306  		}
  1307  	}
  1308  	return list
  1309  }
  1310  
  1311  // Searches for identities that are an exact match of the filter. When two
  1312  // identities are found for the same filter, the first identity found is
  1313  // returned.
  1314  func (c *Connector) getIdentity(filter string) (*IdentityEntry, error) {
  1315  	if filter == "" {
  1316  		return nil, fmt.Errorf("identity string cannot be null")
  1317  	}
  1318  
  1319  	req := BrowseIdentitiesRequest{
  1320  		Filter:       filter,
  1321  		Limit:        2,
  1322  		IdentityType: policy.AllIdentities,
  1323  	}
  1324  
  1325  	resp, err := c.browseIdentities(req)
  1326  	if err != nil {
  1327  		return nil, err
  1328  	}
  1329  
  1330  	// When TPP looks for a username that matches the filter, an implicit
  1331  	// wildcard is added to the end of the filter string. For example, imagining
  1332  	// that `jsmith` and `jsmithson` are existing identities, searching for
  1333  	// `jsmith` will return both `jsmith` and `jsmithson`. In the case of local
  1334  	// identities, `jsmith` will always be returned first. But in the case of AD
  1335  	// and LDAP, the order of these results may be different, and `jsmithson`
  1336  	// may be unexpectedly returned first. This same problem may appear when an
  1337  	// AD or LDAP provider has been configured to access the local identities:
  1338  	// `jsmithson` may get returned first if `jsmithson` only exists in AD
  1339  	// (because the AD results are returned before the local identities).
  1340  	//
  1341  	// The wildcard problem only affects usernames, not emails. That's because
  1342  	// the LDAP query recommended for enabling user search by email in the
  1343  	// Venafi Configuration Console is based on exact match, unlike `anr` used
  1344  	// for searching usernames. Thus, we do not need to check for an exact match
  1345  	// when an email is provided.
  1346  
  1347  	_, err = mail.ParseAddress(filter)
  1348  	isEmail := err == nil
  1349  
  1350  	switch {
  1351  	case len(resp.Identities) == 0:
  1352  		return nil, fmt.Errorf("no identity found for '%s'", filter)
  1353  	case len(resp.Identities) >= 1 && !isEmail:
  1354  		// The username case: we need to ignore the results that are prefixes of
  1355  		// the queried username. For example, if the filter is `jsmith`, we
  1356  		// ignore `jsmithson` and `jsmithers`.
  1357  		for _, identity := range resp.Identities {
  1358  			if identity.Name == filter {
  1359  				return &identity, nil
  1360  			}
  1361  		}
  1362  		return nil, fmt.Errorf("it was not possible to find the user %s", filter)
  1363  	case len(resp.Identities) >= 1 && isEmail:
  1364  		// The email case: we do not need to filter out anything. So let's
  1365  		// arbitrarily return the first identity.
  1366  		return &resp.Identities[0], nil
  1367  	}
  1368  
  1369  	// The above switch cases must catch 100% of the cases. If we arrive here,
  1370  	// it means that we have made a programming mistake.
  1371  	return nil, fmt.Errorf("this was not supposed to happen, please report to the developer team: browseIdentities returned %d identities for the filter '%s' and none of the switch cases matched, but the switch cases are expected to catch 100%% of the cases", len(resp.Identities), filter)
  1372  }
  1373  
  1374  func (c *Connector) browseIdentities(browseReq BrowseIdentitiesRequest) (*BrowseIdentitiesResponse, error) {
  1375  
  1376  	statusCode, status, body, err := c.request("POST", urlResourceBrowseIdentities, browseReq)
  1377  	if err != nil {
  1378  		return nil, err
  1379  	}
  1380  	browseIdentitiesResponse, err := parseBrowseIdentitiesResult(statusCode, status, body)
  1381  	if err != nil {
  1382  		return nil, err
  1383  	}
  1384  	return &browseIdentitiesResponse, nil
  1385  }
  1386  
  1387  // RetrieveCertificate attempts to retrieve the requested certificate
  1388  func (c *Connector) RetrieveCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error) {
  1389  
  1390  	includeChain := req.ChainOption != certificate.ChainOptionIgnore
  1391  	rootFirstOrder := includeChain && req.ChainOption == certificate.ChainOptionRootFirst
  1392  
  1393  	if req.PickupID == "" && req.Thumbprint != "" {
  1394  		// search cert by Thumbprint and fill pickupID
  1395  		searchResult, err := c.searchCertificatesByFingerprint(req.Thumbprint)
  1396  		if err != nil {
  1397  			return nil, fmt.Errorf("Failed to create renewal request: %s", err)
  1398  		}
  1399  		if len(searchResult.Certificates) == 0 {
  1400  			return nil, fmt.Errorf("No certificate found using fingerprint %s", req.Thumbprint)
  1401  		}
  1402  		if len(searchResult.Certificates) > 1 {
  1403  			return nil, fmt.Errorf("Error: more than one CertificateRequestId was found with the same thumbprint")
  1404  		}
  1405  		req.PickupID = searchResult.Certificates[0].CertificateRequestId
  1406  	}
  1407  
  1408  	certReq := certificateRetrieveRequest{
  1409  		CertificateDN:  req.PickupID,
  1410  		Format:         "base64",
  1411  		RootFirstOrder: rootFirstOrder,
  1412  		IncludeChain:   includeChain,
  1413  	}
  1414  	if req.CsrOrigin == certificate.ServiceGeneratedCSR || req.FetchPrivateKey {
  1415  		certReq.IncludePrivateKey = true
  1416  		if req.KeyType == certificate.KeyTypeRSA {
  1417  			certReq.Format = "Base64 (PKCS #8)"
  1418  		}
  1419  		certReq.Password = req.KeyPassword
  1420  	}
  1421  
  1422  	startTime := time.Now()
  1423  	for {
  1424  		var retrieveResponse *certificateRetrieveResponse
  1425  		retrieveResponse, err = c.retrieveCertificateOnce(certReq)
  1426  		if err != nil {
  1427  			return nil, fmt.Errorf("unable to retrieve: %s", err)
  1428  		}
  1429  		if retrieveResponse.CertificateData != "" {
  1430  			certificates, err = newPEMCollectionFromResponse(retrieveResponse.CertificateData, req.ChainOption)
  1431  			if err != nil {
  1432  				return
  1433  			}
  1434  			err = req.CheckCertificate(certificates.Certificate)
  1435  			return
  1436  		}
  1437  		if req.Timeout == 0 {
  1438  			return nil, endpoint.ErrCertificatePending{CertificateID: req.PickupID, Status: retrieveResponse.Status}
  1439  		}
  1440  		if time.Now().After(startTime.Add(req.Timeout)) {
  1441  			return nil, endpoint.ErrRetrieveCertificateTimeout{CertificateID: req.PickupID}
  1442  		}
  1443  		time.Sleep(2 * time.Second)
  1444  	}
  1445  }
  1446  
  1447  func (c *Connector) retrieveCertificateOnce(certReq certificateRetrieveRequest) (*certificateRetrieveResponse, error) {
  1448  	statusCode, status, body, err := c.request("POST", urlResourceCertificateRetrieve, certReq)
  1449  	if err != nil {
  1450  		return nil, err
  1451  	}
  1452  	retrieveResponse, err := parseRetrieveResult(statusCode, status, body)
  1453  	if err != nil {
  1454  		return nil, err
  1455  	}
  1456  	return &retrieveResponse, nil
  1457  }
  1458  
  1459  func (c *Connector) putCertificateInfo(dn string, attributes []nameSliceValuePair) error {
  1460  	guid, err := c.configDNToGuid(dn)
  1461  	if err != nil {
  1462  		return err
  1463  	}
  1464  	statusCode, _, _, err := c.request("PUT", urlResourceCertificate+urlResource(guid), struct{ AttributeData []nameSliceValuePair }{attributes})
  1465  	if err != nil {
  1466  		return err
  1467  	}
  1468  	if statusCode != http.StatusOK {
  1469  		return fmt.Errorf("unexpected status code: %v", statusCode)
  1470  	}
  1471  	return nil
  1472  }
  1473  
  1474  func (c *Connector) prepareRenewalRequest(renewReq *certificate.RenewalRequest) error {
  1475  	if renewReq.CertificateRequest != nil && len(renewReq.CertificateRequest.GetCSR()) != 0 {
  1476  		return nil
  1477  	}
  1478  
  1479  	searchReq := &certificate.Request{
  1480  		PickupID: renewReq.CertificateDN,
  1481  	}
  1482  
  1483  	// here we fetch old cert anyway
  1484  	oldPcc, err := c.RetrieveCertificate(searchReq)
  1485  	if err != nil {
  1486  		return fmt.Errorf("Failed to fetch old certificate by id %s: %s", renewReq.CertificateDN, err)
  1487  	}
  1488  	oldCertBlock, _ := pem.Decode([]byte(oldPcc.Certificate))
  1489  	if oldCertBlock == nil || oldCertBlock.Type != "CERTIFICATE" {
  1490  		return fmt.Errorf("Failed to fetch old certificate by id %s: PEM parse error", renewReq.CertificateDN)
  1491  	}
  1492  	oldCert, err := x509.ParseCertificate(oldCertBlock.Bytes)
  1493  	if err != nil {
  1494  		return fmt.Errorf("Failed to fetch old certificate by id %s: %s", renewReq.CertificateDN, err)
  1495  	}
  1496  	if renewReq.CertificateRequest == nil {
  1497  		renewReq.CertificateRequest = certificate.NewRequest(oldCert)
  1498  	}
  1499  	err = c.GenerateRequest(&endpoint.ZoneConfiguration{}, renewReq.CertificateRequest)
  1500  	return err
  1501  }
  1502  
  1503  // RenewCertificate attempts to renew the certificate
  1504  func (c *Connector) RenewCertificate(renewReq *certificate.RenewalRequest) (requestID string, err error) {
  1505  	if renewReq.Thumbprint != "" && renewReq.CertificateDN == "" {
  1506  		// search by Thumbprint and fill *renewReq.CertificateDN
  1507  		searchResult, err := c.searchCertificatesByFingerprint(renewReq.Thumbprint)
  1508  		if err != nil {
  1509  			return "", fmt.Errorf("Failed to create renewal request: %s", err)
  1510  		}
  1511  		if len(searchResult.Certificates) == 0 {
  1512  			return "", fmt.Errorf("No certificate found using fingerprint %s", renewReq.Thumbprint)
  1513  		}
  1514  		if len(searchResult.Certificates) > 1 {
  1515  			return "", fmt.Errorf("Error: more than one CertificateRequestId was found with the same thumbprint")
  1516  		}
  1517  
  1518  		renewReq.CertificateDN = searchResult.Certificates[0].CertificateRequestId
  1519  	}
  1520  	if renewReq.CertificateDN == "" {
  1521  		return "", fmt.Errorf("failed to create renewal request: CertificateDN or Thumbprint required")
  1522  	}
  1523  	if renewReq.CertificateRequest != nil && renewReq.CertificateRequest.OmitSANs {
  1524  		// if OmitSANSs flag is presented we need to clean SANs values in TPP
  1525  		// for preventing adding them to renew request on TPP side
  1526  		err = c.putCertificateInfo(renewReq.CertificateDN, []nameSliceValuePair{
  1527  			{"X509 SubjectAltName DNS", nil},
  1528  			{"X509 SubjectAltName IPAddress", nil},
  1529  			{"X509 SubjectAltName RFC822", nil},
  1530  			{"X509 SubjectAltName URI", nil},
  1531  			{"X509 SubjectAltName OtherName UPN", nil},
  1532  		})
  1533  		if err != nil {
  1534  			return "", fmt.Errorf("can't clean SANs values for certificate on server side: %v", err)
  1535  		}
  1536  	}
  1537  	//err = c.prepareRenewalRequest(renewReq) todo: uncomment on refactoring
  1538  	//if err != nil {
  1539  	//	return "", err
  1540  	//}
  1541  	var r = certificateRenewRequest{}
  1542  	r.CertificateDN = renewReq.CertificateDN
  1543  	if renewReq.CertificateRequest != nil && len(renewReq.CertificateRequest.GetCSR()) != 0 {
  1544  		r.PKCS10 = string(renewReq.CertificateRequest.GetCSR())
  1545  	}
  1546  	statusCode, status, body, err := c.request("POST", urlResourceCertificateRenew, r)
  1547  	if err != nil {
  1548  		return "", err
  1549  	}
  1550  
  1551  	response, err := parseRenewResult(statusCode, status, body)
  1552  	if err != nil {
  1553  		return "", err
  1554  	}
  1555  	if !response.Success {
  1556  		return "", fmt.Errorf("Certificate Renewal error: %s", response.Error)
  1557  	}
  1558  	return renewReq.CertificateDN, nil
  1559  }
  1560  
  1561  // RevokeCertificate attempts to revoke the certificate
  1562  func (c *Connector) RevokeCertificate(revReq *certificate.RevocationRequest) (err error) {
  1563  	reason, ok := RevocationReasonsMap[revReq.Reason]
  1564  	if !ok {
  1565  		return fmt.Errorf("could not parse revocation reason `%s`", revReq.Reason)
  1566  	}
  1567  
  1568  	var r = certificateRevokeRequest{
  1569  		revReq.CertificateDN,
  1570  		revReq.Thumbprint,
  1571  		reason,
  1572  		revReq.Comments,
  1573  		revReq.Disable,
  1574  	}
  1575  	statusCode, status, body, err := c.request("POST", urlResourceCertificateRevoke, r)
  1576  	if err != nil {
  1577  		return err
  1578  	}
  1579  	revokeResponse, err := parseRevokeResult(statusCode, status, body)
  1580  	if err != nil {
  1581  		return
  1582  	}
  1583  	if !revokeResponse.Success {
  1584  		return fmt.Errorf("Revocation error: %s", revokeResponse.Error)
  1585  	}
  1586  	return
  1587  }
  1588  
  1589  func (c *Connector) RetireCertificate(req *certificate.RetireRequest) (err error) {
  1590  
  1591  	if req.CertificateDN == "" && req.Thumbprint != "" {
  1592  		// search cert by Thumbprint and fill pickupID
  1593  		searchResult, err := c.searchCertificatesByFingerprint(req.Thumbprint)
  1594  		if err != nil {
  1595  			return fmt.Errorf("Failed to create retire request: %s", err)
  1596  		}
  1597  		if len(searchResult.Certificates) == 0 {
  1598  			return fmt.Errorf("No certificate found using fingerprint %s", req.Thumbprint)
  1599  		}
  1600  		if len(searchResult.Certificates) > 1 {
  1601  			return fmt.Errorf("Error: more than one CertificateRequestId was found with the same thumbprint")
  1602  		}
  1603  		req.CertificateDN = searchResult.Certificates[0].CertificateRequestId
  1604  	} else if req.CertificateDN == "" && req.Thumbprint == "" {
  1605  		return fmt.Errorf("failed to create retire request: CertificateDN or Thumbprint required")
  1606  	}
  1607  
  1608  	retireSliceValuePair := []nameSliceValuePair{{Name: "Disabled", Value: []string{"1"}}}
  1609  
  1610  	err = c.putCertificateInfo(req.CertificateDN, retireSliceValuePair)
  1611  	return err
  1612  }
  1613  
  1614  var zoneNonFoundregexp = regexp.MustCompile("PolicyDN: .+ does not exist")
  1615  
  1616  func (c *Connector) ReadPolicyConfiguration() (policy *endpoint.Policy, err error) {
  1617  	if c.zone == "" {
  1618  		return nil, fmt.Errorf("empty zone")
  1619  	}
  1620  	rq := struct{ PolicyDN string }{getPolicyDN(c.zone)}
  1621  	statusCode, status, body, err := c.request("POST", urlResourceCertificatePolicy, rq)
  1622  	if err != nil {
  1623  		return
  1624  	}
  1625  	var r struct {
  1626  		Policy serverPolicy
  1627  		Error  string
  1628  	}
  1629  	if statusCode == http.StatusOK {
  1630  		err = json.Unmarshal(body, &r)
  1631  		if err != nil {
  1632  			return nil, err
  1633  		}
  1634  		p := r.Policy.toPolicy()
  1635  		policy = &p
  1636  	} else if statusCode == http.StatusBadRequest {
  1637  		err = json.Unmarshal(body, &r)
  1638  		if err != nil {
  1639  			return nil, err
  1640  		}
  1641  		if zoneNonFoundregexp.Match([]byte(r.Error)) {
  1642  			return nil, verror.ZoneNotFoundError
  1643  		}
  1644  	} else {
  1645  		return nil, fmt.Errorf("Invalid status: %s Server data: %s", status, body)
  1646  	}
  1647  	return
  1648  }
  1649  
  1650  // ReadZoneConfiguration reads the policy data from TPP to get locked and pre-configured values for certificate requests
  1651  func (c *Connector) ReadZoneConfiguration() (config *endpoint.ZoneConfiguration, err error) {
  1652  	if c.zone == "" {
  1653  		return nil, fmt.Errorf("empty zone")
  1654  	}
  1655  	zoneConfig := endpoint.NewZoneConfiguration()
  1656  	zoneConfig.HashAlgorithm = x509.SHA256WithRSA //todo: check this can have problem with ECDSA key
  1657  	rq := struct{ PolicyDN string }{getPolicyDN(c.zone)}
  1658  	statusCode, status, body, err := c.request("POST", urlResourceCertificatePolicy, rq)
  1659  	if err != nil {
  1660  		return
  1661  	}
  1662  	var r struct {
  1663  		Policy serverPolicy
  1664  		Error  string
  1665  	}
  1666  	if statusCode == http.StatusOK {
  1667  		err = json.Unmarshal(body, &r)
  1668  		if err != nil {
  1669  			return nil, err
  1670  		}
  1671  		p := r.Policy.toPolicy()
  1672  		r.Policy.toZoneConfig(zoneConfig)
  1673  		zoneConfig.Policy = p
  1674  		return zoneConfig, nil
  1675  	} else if statusCode == http.StatusBadRequest {
  1676  		err = json.Unmarshal(body, &r)
  1677  		if err != nil {
  1678  			return nil, err
  1679  		}
  1680  		if zoneNonFoundregexp.Match([]byte(r.Error)) {
  1681  			return nil, verror.ZoneNotFoundError
  1682  		}
  1683  	}
  1684  	return nil, fmt.Errorf("Invalid status: %s Server response: %s", status, string(body))
  1685  
  1686  }
  1687  
  1688  func (c *Connector) ImportCertificate(req *certificate.ImportRequest) (*certificate.ImportResponse, error) {
  1689  	r := importRequest{
  1690  		PolicyDN:        req.PolicyDN,
  1691  		ObjectName:      req.ObjectName,
  1692  		CertificateData: req.CertificateData,
  1693  		PrivateKeyData:  req.PrivateKeyData,
  1694  		Password:        req.Password,
  1695  		Reconcile:       req.Reconcile,
  1696  	}
  1697  
  1698  	if r.PolicyDN == "" {
  1699  		r.PolicyDN = getPolicyDN(c.zone)
  1700  	}
  1701  
  1702  	origin := endpoint.SDKName + " (+)" // standard suffix needed to differentiate certificates imported from enrolled in TPP
  1703  	for _, f := range req.CustomFields {
  1704  		if f.Type == certificate.CustomFieldOrigin {
  1705  			origin = f.Value + " (+)"
  1706  		}
  1707  	}
  1708  	statusCode, _, body, err := c.request("POST", urlResourceCertificateImport, r)
  1709  	if err != nil {
  1710  		return nil, fmt.Errorf("%w: %v", verror.ServerTemporaryUnavailableError, err)
  1711  	}
  1712  	switch statusCode {
  1713  	case http.StatusOK:
  1714  		var response = &certificate.ImportResponse{}
  1715  		err := json.Unmarshal(body, response)
  1716  		if err != nil {
  1717  			return nil, fmt.Errorf("%w: failed to decode import response message: %s", verror.ServerError, err)
  1718  		}
  1719  		err = c.putCertificateInfo(response.CertificateDN, []nameSliceValuePair{{Name: "Origin", Value: []string{origin}}})
  1720  		if err != nil {
  1721  			log.Println(err)
  1722  		}
  1723  		return response, nil
  1724  	case http.StatusBadRequest:
  1725  		var errorResponse = &struct{ Error string }{}
  1726  		err := json.Unmarshal(body, errorResponse)
  1727  		if err != nil {
  1728  			return nil, fmt.Errorf("%w: failed to decode error message: %s", verror.ServerBadDataResponce, err)
  1729  		}
  1730  		return nil, fmt.Errorf("%w: can't import certificate %s", verror.ServerBadDataResponce, errorResponse.Error)
  1731  	default:
  1732  		return nil, fmt.Errorf("%w: unexpected response status %d: %s", verror.ServerTemporaryUnavailableError, statusCode, string(body))
  1733  	}
  1734  }
  1735  
  1736  func (c *Connector) SearchCertificates(req *certificate.SearchRequest) (*certificate.CertSearchResponse, error) {
  1737  
  1738  	var err error
  1739  
  1740  	url := fmt.Sprintf("%s?%s", urlResourceCertificateSearch, strings.Join(*req, "&"))
  1741  	statusCode, _, body, err := c.request("GET", urlResource(url), nil)
  1742  	if err != nil {
  1743  		return nil, err
  1744  	}
  1745  	searchResult, err := ParseCertificateSearchResponse(statusCode, body)
  1746  	if err != nil {
  1747  		return nil, err
  1748  	}
  1749  	return searchResult, nil
  1750  }
  1751  
  1752  func (c *Connector) SearchCertificate(zone string, cn string, sans *certificate.Sans, certMinTimeLeft time.Duration) (certificateInfo *certificate.CertificateInfo, err error) {
  1753  	// format arguments for request
  1754  	req := formatSearchCertificateArguments(cn, sans, certMinTimeLeft)
  1755  
  1756  	// perform request
  1757  	url := fmt.Sprintf("%s?%s", urlResourceCertificateSearch, req)
  1758  	statusCode, _, body, err := c.request("GET", urlResource(url), nil)
  1759  	if err != nil {
  1760  		return nil, err
  1761  	}
  1762  	searchResult, err := parseSearchCertificateResponse(statusCode, body)
  1763  	if err != nil {
  1764  		return nil, err
  1765  	}
  1766  
  1767  	// fail if no certificate is returned from api
  1768  	if searchResult.Count == 0 {
  1769  		return nil, verror.NoCertificateFoundError
  1770  	}
  1771  
  1772  	// map (convert) response to an array of CertificateInfo, only add those
  1773  	// certificates whose Zone matches ours
  1774  	certificates := make([]*certificate.CertificateInfo, 0)
  1775  	n := 0
  1776  	policyDn := getPolicyDN(zone)
  1777  	for _, cert := range searchResult.Certificates {
  1778  		if cert.ParentDn == policyDn {
  1779  			match := cert.X509
  1780  			certificates = append(certificates, &match)
  1781  			certificates[n].ID = cert.Guid
  1782  			n = n + 1
  1783  		}
  1784  	}
  1785  
  1786  	// fail if no certificates found with matching zone
  1787  	if n == 0 {
  1788  		return nil, verror.NoCertificateWithMatchingZoneFoundError
  1789  	}
  1790  
  1791  	// at this point all certificates belong to our zone, the next step is
  1792  	// finding the newest valid certificate matching the provided sans
  1793  	return certificate.FindNewestCertificateWithSans(certificates, sans)
  1794  }
  1795  
  1796  func (c *Connector) SetHTTPClient(client *http.Client) {
  1797  	c.client = client
  1798  }
  1799  
  1800  func (c *Connector) WriteLog(logReq *endpoint.LogRequest) error {
  1801  	statusCode, httpStatus, body, err := c.request("POST", urlResourceLog, logReq)
  1802  	if err != nil {
  1803  		return err
  1804  	}
  1805  
  1806  	err = checkLogResponse(statusCode, httpStatus, body)
  1807  	if err != nil {
  1808  		return err
  1809  	}
  1810  	return nil
  1811  }
  1812  
  1813  func (c *Connector) ListCertificates(filter endpoint.Filter) ([]certificate.CertificateInfo, error) {
  1814  	if c.zone == "" {
  1815  		return nil, fmt.Errorf("empty zone")
  1816  	}
  1817  	min := func(i, j int) int {
  1818  		if i < j {
  1819  			return i
  1820  		}
  1821  		return j
  1822  	}
  1823  	const batchSize = 500
  1824  	limit := 100000000
  1825  	if filter.Limit != nil {
  1826  		limit = *filter.Limit
  1827  	}
  1828  	var buf [][]certificate.CertificateInfo
  1829  	for offset := 0; limit > 0; limit, offset = limit-batchSize, offset+batchSize {
  1830  		var b []certificate.CertificateInfo
  1831  		var err error
  1832  		b, err = c.getCertsBatch(offset, min(limit, batchSize), filter.WithExpired)
  1833  		if err != nil {
  1834  			return nil, err
  1835  		}
  1836  		buf = append(buf, b)
  1837  		if len(b) < min(limit, batchSize) {
  1838  			break
  1839  		}
  1840  	}
  1841  	sumLen := 0
  1842  	for _, b := range buf {
  1843  		sumLen += len(b)
  1844  	}
  1845  	infos := make([]certificate.CertificateInfo, sumLen)
  1846  	offset := 0
  1847  	for _, b := range buf {
  1848  		copy(infos[offset:], b[:])
  1849  		offset += len(b)
  1850  	}
  1851  	return infos, nil
  1852  }
  1853  
  1854  func (c *Connector) getCertsBatch(offset, limit int, withExpired bool) ([]certificate.CertificateInfo, error) {
  1855  	url := urlResourceCertificatesList + urlResource(
  1856  		"?ParentDNRecursive="+neturl.QueryEscape(getPolicyDN(c.zone))+
  1857  			"&limit="+fmt.Sprintf("%d", limit)+
  1858  			"&offset="+fmt.Sprintf("%d", offset))
  1859  	if !withExpired {
  1860  		url += urlResource("&ValidToGreater=" + neturl.QueryEscape(time.Now().Format(time.RFC3339)))
  1861  	}
  1862  	statusCode, status, body, err := c.request("GET", url, nil)
  1863  	if err != nil {
  1864  		return nil, err
  1865  	}
  1866  	if statusCode != 200 {
  1867  		return nil, fmt.Errorf("can`t get certificates list: %d %s\n%s", statusCode, status, string(body))
  1868  	}
  1869  	var r struct {
  1870  		Certificates []struct {
  1871  			DN   string
  1872  			X509 certificate.CertificateInfo
  1873  		}
  1874  	}
  1875  	err = json.Unmarshal(body, &r)
  1876  	if err != nil {
  1877  		return nil, err
  1878  	}
  1879  	infos := make([]certificate.CertificateInfo, len(r.Certificates))
  1880  	for i, c := range r.Certificates {
  1881  		c.X509.ID = c.DN
  1882  		infos[i] = c.X509
  1883  	}
  1884  	return infos, nil
  1885  }
  1886  
  1887  func parseHostPort(s string) (host string, port string, err error) {
  1888  	slice := strings.Split(s, ":")
  1889  	if len(slice) != 2 {
  1890  		err = fmt.Errorf("%w: bad address %s.  should be host:port.", verror.UserDataError, s)
  1891  		return
  1892  	}
  1893  	host = slice[0]
  1894  	port = slice[1]
  1895  	return
  1896  }
  1897  
  1898  func (c *Connector) dissociate(certDN, applicationDN string) error {
  1899  	req := struct {
  1900  		CertificateDN string
  1901  		ApplicationDN []string
  1902  		DeleteOrphans bool
  1903  	}{
  1904  		certDN,
  1905  		[]string{applicationDN},
  1906  		true,
  1907  	}
  1908  	log.Println("Dissociating device", applicationDN)
  1909  	statusCode, status, body, err := c.request("POST", urlResourceCertificatesDissociate, req)
  1910  	if err != nil {
  1911  		return err
  1912  	}
  1913  	if statusCode != 200 {
  1914  		return fmt.Errorf("%w: We have problem with server response.\n  status: %s\n  body: %s\n", verror.ServerBadDataResponce, status, body)
  1915  	}
  1916  	return nil
  1917  }
  1918  
  1919  func (c *Connector) associate(certDN, applicationDN string, pushToNew bool) error {
  1920  	req := struct {
  1921  		CertificateDN string
  1922  		ApplicationDN []string
  1923  		PushToNew     bool
  1924  	}{
  1925  		certDN,
  1926  		[]string{applicationDN},
  1927  		pushToNew,
  1928  	}
  1929  	log.Println("Associating device", applicationDN)
  1930  	statusCode, status, body, err := c.request("POST", urlResourceCertificatesAssociate, req)
  1931  	if err != nil {
  1932  		return err
  1933  	}
  1934  	if statusCode != 200 {
  1935  		log.Printf("We have problem with server response.\n  status: %s\n  body: %s\n", status, body)
  1936  		return verror.ServerBadDataResponce
  1937  	}
  1938  	return nil
  1939  }
  1940  
  1941  func (c *Connector) configDNToGuid(objectDN string) (guid string, err error) {
  1942  
  1943  	req := struct {
  1944  		ObjectDN string
  1945  	}{
  1946  		objectDN,
  1947  	}
  1948  
  1949  	var resp struct {
  1950  		ClassName        string `json:",omitempty"`
  1951  		GUID             string `json:",omitempty"`
  1952  		HierarchicalGUID string `json:",omitempty"`
  1953  		Revision         int    `json:",omitempty"`
  1954  		Result           int    `json:",omitempty"`
  1955  	}
  1956  
  1957  	log.Println("Getting guid for object DN", objectDN)
  1958  	statusCode, status, body, err := c.request("POST", urlResourceConfigDnToGuid, req)
  1959  
  1960  	if err != nil {
  1961  		return guid, err
  1962  	}
  1963  
  1964  	if statusCode == http.StatusOK {
  1965  		err = json.Unmarshal(body, &resp)
  1966  		if err != nil {
  1967  			return guid, fmt.Errorf("failed to parse DNtoGuid results: %s, body: %s", err, body)
  1968  		}
  1969  	} else {
  1970  		return guid, fmt.Errorf("request to %s failed: %s\n%s", urlResourceConfigDnToGuid, status, body)
  1971  	}
  1972  
  1973  	if statusCode != 200 {
  1974  		return "", verror.ServerBadDataResponce
  1975  	}
  1976  
  1977  	if resp.Result == 400 {
  1978  		log.Printf("object with DN %s doesn't exist", objectDN)
  1979  		return "", nil
  1980  	}
  1981  
  1982  	if resp.Result != 1 {
  1983  		return "", fmt.Errorf("result code %d is not success.", resp.Result)
  1984  	}
  1985  	return resp.GUID, nil
  1986  
  1987  }
  1988  
  1989  func (c *Connector) findObjectsOfClass(req *findObjectsOfClassRequest) (*findObjectsOfClassResponse, error) {
  1990  	statusCode, statusString, body, err := c.request("POST", urlResourceFindObjectsOfClass, req)
  1991  	if err != nil {
  1992  		return nil, err
  1993  	}
  1994  	response, err := parseFindObjectsOfClassResponse(statusCode, statusString, body)
  1995  	if err != nil {
  1996  		return nil, err
  1997  	}
  1998  	return &response, nil
  1999  }
  2000  
  2001  // GetZonesByParent returns a list of valid zones for a TPP parent folder specified by parent
  2002  func (c *Connector) GetZonesByParent(parent string) ([]string, error) {
  2003  	zones := make([]string, 0)
  2004  
  2005  	parentFolderDn := parent
  2006  	if !strings.HasPrefix(parentFolderDn, "\\VED\\Policy") {
  2007  		parentFolderDn = fmt.Sprintf("\\VED\\Policy\\%s", parentFolderDn)
  2008  	}
  2009  
  2010  	request := findObjectsOfClassRequest{
  2011  		Class:    "Policy",
  2012  		ObjectDN: parentFolderDn,
  2013  	}
  2014  	response, err := c.findObjectsOfClass(&request)
  2015  	if err != nil {
  2016  		return nil, err
  2017  	}
  2018  
  2019  	for _, folder := range response.PolicyObjects {
  2020  		// folder.DN will always start with \VED\Policy but short form is preferrable since both are supported
  2021  		zones = append(zones, strings.Replace(folder.DN, "\\VED\\Policy\\", "", 1))
  2022  	}
  2023  	return zones, nil
  2024  }
  2025  
  2026  func createPolicyAttribute(c *Connector, at string, av []string, n string, l bool) (statusCode int, statusText string, body []byte, err error) {
  2027  
  2028  	request := policy.PolicySetAttributePayloadRequest{
  2029  		Locked:        l,
  2030  		ObjectDN:      n,
  2031  		Class:         policy.PolicyAttributeClass,
  2032  		AttributeName: at,
  2033  		Values:        av,
  2034  	}
  2035  	// if is locked is a policy value
  2036  	// if is not locked then is a default.
  2037  
  2038  	statusCode, statusText, body, err = c.request("POST", urlResourceWritePolicy, request)
  2039  	if err != nil {
  2040  		return statusCode, statusText, body, err
  2041  	}
  2042  
  2043  	var response policy.PolicySetAttributeResponse
  2044  
  2045  	err = json.Unmarshal(body, &response)
  2046  	if err != nil {
  2047  		return statusCode, statusText, body, err
  2048  	}
  2049  
  2050  	if response.Error != "" {
  2051  		err = errors.New(response.Error)
  2052  		return statusCode, statusText, body, err
  2053  	}
  2054  
  2055  	return statusCode, statusText, body, err
  2056  }
  2057  
  2058  func getPolicyAttribute(c *Connector, at string, n string) (s []string, b *bool, err error) {
  2059  
  2060  	request := policy.PolicyGetAttributePayloadRequest{
  2061  		ObjectDN:      n,
  2062  		Class:         policy.PolicyAttributeClass,
  2063  		AttributeName: at,
  2064  		Values:        []string{"1"},
  2065  	}
  2066  	// if is locked is a policy value
  2067  	// if is not locked then is a default.
  2068  	_, _, body, err := c.request("POST", urlResourceReadPolicy, request)
  2069  	if err != nil {
  2070  		return nil, nil, err
  2071  	}
  2072  
  2073  	var response policy.PolicyGetAttributeResponse
  2074  	err = json.Unmarshal(body, &response)
  2075  
  2076  	if err != nil {
  2077  		return nil, nil, err
  2078  	}
  2079  
  2080  	if len(response.Values) > 0 {
  2081  		return response.Values, &response.Locked, nil
  2082  	}
  2083  	//no value set and no error.
  2084  	return nil, nil, nil
  2085  }
  2086  
  2087  func resetTPPAttributes(zone string, c *Connector) error {
  2088  
  2089  	//reset Contact
  2090  	err := resetTPPAttribute(c, policy.TppContact, zone)
  2091  	if err != nil {
  2092  		return err
  2093  	}
  2094  
  2095  	//reset Domain Suffix Whitelist
  2096  	err = resetTPPAttribute(c, policy.TppDomainSuffixWhitelist, zone)
  2097  	if err != nil {
  2098  		return err
  2099  	}
  2100  
  2101  	//reset Prohibit Wildcard
  2102  	err = resetTPPAttribute(c, policy.TppProhibitWildcard, zone)
  2103  	if err != nil {
  2104  		return err
  2105  	}
  2106  
  2107  	//reset Certificate Authority
  2108  	err = resetTPPAttribute(c, policy.TppCertificateAuthority, zone)
  2109  	if err != nil {
  2110  		return err
  2111  	}
  2112  
  2113  	//reset Organization attribute
  2114  	err = resetTPPAttribute(c, policy.TppOrganization, zone)
  2115  	if err != nil {
  2116  		return err
  2117  	}
  2118  
  2119  	//reset Organizational Unit attribute
  2120  	err = resetTPPAttribute(c, policy.TppOrganizationalUnit, zone)
  2121  	if err != nil {
  2122  		return err
  2123  	}
  2124  
  2125  	//reset City attribute
  2126  	err = resetTPPAttribute(c, policy.TppCity, zone)
  2127  	if err != nil {
  2128  		return err
  2129  	}
  2130  
  2131  	//reset State attribute
  2132  	err = resetTPPAttribute(c, policy.TppState, zone)
  2133  	if err != nil {
  2134  		return err
  2135  	}
  2136  
  2137  	//reset Country attribute
  2138  	err = resetTPPAttribute(c, policy.TppCountry, zone)
  2139  	if err != nil {
  2140  		return err
  2141  	}
  2142  
  2143  	//reset Key Algorithm attribute
  2144  	err = resetTPPAttribute(c, policy.TppKeyAlgorithm, zone)
  2145  	if err != nil {
  2146  		return err
  2147  	}
  2148  
  2149  	//reset Key Bit Strength
  2150  	err = resetTPPAttribute(c, policy.TppKeyBitStrength, zone)
  2151  	if err != nil {
  2152  		return err
  2153  	}
  2154  
  2155  	//reset Elliptic Curve attribute
  2156  	err = resetTPPAttribute(c, policy.TppEllipticCurve, zone)
  2157  	if err != nil {
  2158  		return err
  2159  	}
  2160  
  2161  	//reset PKIX Parameter Set Policy Default attribute
  2162  	err = resetTPPAttribute(c, policy.TppPkixParameterSetPolicyDefault, zone)
  2163  	if err != nil {
  2164  		return err
  2165  	}
  2166  	//reset PKIX Parameter Set Policy attribute
  2167  	err = resetTPPAttribute(c, policy.TppPkixParameterSetPolicy, zone)
  2168  	if err != nil {
  2169  		return err
  2170  	}
  2171  
  2172  	//reset Manual Csr attribute
  2173  	err = resetTPPAttribute(c, policy.ServiceGenerated, zone)
  2174  	if err != nil {
  2175  		return err
  2176  	}
  2177  
  2178  	//reset Manual Csr attribute
  2179  	err = resetTPPAttribute(c, policy.TppProhibitedSANTypes, zone)
  2180  	if err != nil {
  2181  		return err
  2182  	}
  2183  
  2184  	//reset Allow Private Key Reuse" & "Want Renewal
  2185  	err = resetTPPAttribute(c, policy.TppAllowPrivateKeyReuse, zone)
  2186  	if err != nil {
  2187  		return err
  2188  	}
  2189  
  2190  	err = resetTPPAttribute(c, policy.TppWantRenewal, zone)
  2191  	if err != nil {
  2192  		return err
  2193  	}
  2194  
  2195  	err = resetTPPAttribute(c, policy.TppManagementType, zone)
  2196  	if err != nil {
  2197  		return err
  2198  	}
  2199  
  2200  	return nil
  2201  }
  2202  
  2203  func resetTPPAttribute(c *Connector, at, zone string) error {
  2204  
  2205  	request := policy.ClearTTPAttributesRequest{
  2206  		ObjectDN:      zone,
  2207  		Class:         policy.PolicyAttributeClass,
  2208  		AttributeName: at,
  2209  	}
  2210  	// if is locked is a policy value
  2211  	// if is not locked then is a default.
  2212  
  2213  	_, _, body, err := c.request("POST", urlResourceCleanPolicy, request)
  2214  	if err != nil {
  2215  		return err
  2216  	}
  2217  
  2218  	var response policy.PolicySetAttributeResponse
  2219  
  2220  	err = json.Unmarshal(body, &response)
  2221  	if err != nil {
  2222  		return err
  2223  	}
  2224  
  2225  	if response.Error != "" {
  2226  		err = errors.New(response.Error)
  2227  		return err
  2228  	}
  2229  
  2230  	return nil
  2231  }
  2232  
  2233  func (c *Connector) RequestSSHCertificate(req *certificate.SshCertRequest) (response *certificate.SshCertificateObject, err error) {
  2234  
  2235  	return RequestSshCertificate(c, req)
  2236  
  2237  }
  2238  
  2239  func (c *Connector) RetrieveSSHCertificate(req *certificate.SshCertRequest) (response *certificate.SshCertificateObject, err error) {
  2240  	return RetrieveSshCertificate(c, req)
  2241  }
  2242  
  2243  func (c *Connector) ProvisionCertificate(_ *domain.ProvisioningRequest, _ *domain.ProvisioningOptions) (*domain.ProvisioningMetadata, error) {
  2244  	panic("operation is not supported yet")
  2245  }
  2246  
  2247  func (c *Connector) RetrieveCertificateMetaData(dn string) (*certificate.CertificateMetaData, error) {
  2248  
  2249  	//first step convert dn to guid
  2250  	request := DNToGUIDRequest{ObjectDN: dn}
  2251  	statusCode, status, body, err := c.request("POST", urlResourceDNToGUID, request)
  2252  
  2253  	if err != nil {
  2254  		return nil, err
  2255  	}
  2256  
  2257  	guidInfo, err := parseDNToGUIDRequestResponse(statusCode, status, body)
  2258  
  2259  	if err != nil {
  2260  		return nil, err
  2261  	}
  2262  
  2263  	//second step get certificate metadata
  2264  	url := fmt.Sprintf("%s%s", urlResourceCertificate, guidInfo.GUID)
  2265  
  2266  	statusCode, status, body, err = c.request("GET", urlResource(url), nil)
  2267  
  2268  	if err != nil {
  2269  		return nil, err
  2270  	}
  2271  
  2272  	data, err := parseCertificateMetaData(statusCode, status, body)
  2273  	if err != nil {
  2274  		return nil, err
  2275  	}
  2276  
  2277  	return data, nil
  2278  
  2279  }
  2280  
  2281  func checkLogResponse(httpStatusCode int, httpStatus string, body []byte) error {
  2282  	switch httpStatusCode {
  2283  	case http.StatusOK:
  2284  		logData, err := parseLogResponse(body)
  2285  		if err != nil {
  2286  			return err
  2287  		} else if logData.LogResult == 1 {
  2288  			return fmt.Errorf("The Log Server failed to store the event in the event log")
  2289  		} else {
  2290  			return nil
  2291  		}
  2292  	default:
  2293  		return fmt.Errorf("Unexpected status code on TPP Post Log request.\n Status:\n %s. \n Body:\n %s\n", httpStatus, body)
  2294  	}
  2295  }
  2296  
  2297  func parseDNToGUIDRequestResponse(httpStatusCode int, httpStatus string, body []byte) (*DNToGUIDResponse, error) {
  2298  	switch httpStatusCode {
  2299  	case http.StatusOK, http.StatusCreated:
  2300  		reqData, err := parseDNToGUIDResponseData(body)
  2301  		if err != nil {
  2302  			return nil, err
  2303  		}
  2304  		return reqData, nil
  2305  	default:
  2306  		return nil, fmt.Errorf("Unexpected status code on TPP DN to GUID request.\n Status:\n %s. \n Body:\n %s\n", httpStatus, body)
  2307  	}
  2308  }
  2309  
  2310  func parseDNToGUIDResponseData(b []byte) (data *DNToGUIDResponse, err error) {
  2311  	err = json.Unmarshal(b, &data)
  2312  	return
  2313  }
  2314  
  2315  func parseCertificateMetaData(httpStatusCode int, httpStatus string, body []byte) (*certificate.CertificateMetaData, error) {
  2316  	switch httpStatusCode {
  2317  	case http.StatusOK, http.StatusCreated:
  2318  		reqData, err := parseCertificateMetaDataResponse(body)
  2319  		if err != nil {
  2320  			return nil, err
  2321  		}
  2322  		return reqData, nil
  2323  	default:
  2324  		return nil, fmt.Errorf("Unexpected status code on TPP DN to GUID request.\n Status:\n %s. \n Body:\n %s\n", httpStatus, body)
  2325  	}
  2326  }
  2327  
  2328  func parseCertificateMetaDataResponse(b []byte) (data *certificate.CertificateMetaData, err error) {
  2329  	err = json.Unmarshal(b, &data)
  2330  	return
  2331  }