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, ¬FoundErr) 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 }