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

     1  /*
     2   * Copyright 2018 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  	// nolint:gosec // Although use weak cryptographic primitive (G401), we still needed it for test process only
    21  	"crypto/sha1"
    22  	"encoding/json"
    23  	"encoding/pem"
    24  	"fmt"
    25  	"net/http"
    26  	neturl "net/url"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/Venafi/vcert/v5/pkg/certificate"
    31  )
    32  
    33  type SearchRequest []string
    34  
    35  type ConfigReadDNRequest struct {
    36  	ObjectDN      string `json:",omitempty"`
    37  	AttributeName string `json:",omitempty"`
    38  }
    39  
    40  type ConfigReadDNResponse struct {
    41  	Result int      `json:",omitempty"`
    42  	Values []string `json:",omitempty"`
    43  }
    44  
    45  type CertificateDetailsResponse struct {
    46  	CustomFields []struct {
    47  		Name  string
    48  		Value []string
    49  	}
    50  	Consumers []string
    51  	Disabled  bool `json:",omitempty"`
    52  }
    53  
    54  func (c *Connector) searchCertificatesByFingerprint(fp string) (*certificate.CertSearchResponse, error) {
    55  	fp = strings.Replace(fp, ":", "", -1)
    56  	fp = strings.Replace(fp, ".", "", -1)
    57  	fp = strings.ToUpper(fp)
    58  
    59  	var req certificate.SearchRequest
    60  	req = append(req, fmt.Sprintf("Thumbprint=%s", fp))
    61  
    62  	return c.SearchCertificates(&req)
    63  }
    64  
    65  func (c *Connector) configReadDN(req ConfigReadDNRequest) (resp ConfigReadDNResponse, err error) {
    66  
    67  	statusCode, status, body, err := c.request("POST", urlResourceConfigReadDn, req)
    68  	if err != nil {
    69  		return resp, err
    70  	}
    71  
    72  	if statusCode == http.StatusOK {
    73  		err = json.Unmarshal(body, &resp)
    74  		if err != nil {
    75  			return resp, err
    76  		}
    77  	} else {
    78  		return resp, fmt.Errorf("unexpected status code on %s. Status: %s", urlResourceConfigReadDn, status)
    79  	}
    80  
    81  	return resp, nil
    82  }
    83  
    84  func (c *Connector) searchCertificateDetails(guid string) (*CertificateDetailsResponse, error) {
    85  	var err error
    86  
    87  	url := fmt.Sprintf("%s%s", urlResourceCertificateSearch, guid)
    88  	statusCode, _, body, err := c.request("GET", urlResource(url), nil)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	return parseCertificateDetailsResponse(statusCode, body)
    93  }
    94  
    95  func parseCertificateDetailsResponse(statusCode int, body []byte) (searchResult *CertificateDetailsResponse, err error) {
    96  	switch statusCode {
    97  	case http.StatusOK:
    98  		var searchResult = &CertificateDetailsResponse{}
    99  		err = json.Unmarshal(body, searchResult)
   100  		if err != nil {
   101  			return nil, fmt.Errorf("Failed to parse search results: %s, body: %s", err, body)
   102  		}
   103  		return searchResult, nil
   104  	default:
   105  		if body != nil {
   106  			return nil, NewResponseError(body)
   107  		} else {
   108  			return nil, fmt.Errorf("Unexpected status code on certificate search. Status: %d", statusCode)
   109  		}
   110  	}
   111  }
   112  
   113  func ParseCertificateSearchResponse(httpStatusCode int, body []byte) (searchResult *certificate.CertSearchResponse, err error) {
   114  	switch httpStatusCode {
   115  	case http.StatusOK:
   116  		var searchResult = &certificate.CertSearchResponse{}
   117  		err = json.Unmarshal(body, searchResult)
   118  		if err != nil {
   119  			return nil, fmt.Errorf("Failed to parse search results: %s, body: %s", err, body)
   120  		}
   121  		return searchResult, nil
   122  	default:
   123  		if body != nil {
   124  			return nil, NewResponseError(body)
   125  		} else {
   126  			return nil, fmt.Errorf("Unexpected status code on certificate search. Status: %d", httpStatusCode)
   127  		}
   128  	}
   129  }
   130  
   131  type CertificateSearchResponse struct {
   132  	Certificates []CertificateSearchInfo `json:"Certificates"`
   133  	Count        int                     `json:"TotalCount"`
   134  }
   135  
   136  type CertificateSearchInfo struct {
   137  	CreatedOn   string
   138  	DN          string
   139  	Guid        string
   140  	Name        string
   141  	ParentDn    string
   142  	SchemaClass string
   143  	X509        certificate.CertificateInfo
   144  }
   145  
   146  func parseSearchCertificateResponse(httpStatusCode int, body []byte) (certificates *CertificateSearchResponse, err error) {
   147  	switch httpStatusCode {
   148  	case http.StatusOK:
   149  		var searchResult = &CertificateSearchResponse{}
   150  		err = json.Unmarshal(body, searchResult)
   151  		if err != nil {
   152  			return nil, fmt.Errorf("Failed to parse search results: %s, body: %s", err, body)
   153  		}
   154  		return searchResult, nil
   155  	default:
   156  		if body != nil {
   157  			return nil, NewResponseError(body)
   158  		} else {
   159  			return nil, fmt.Errorf("Unexpected status code on certificate search. Status: %d", httpStatusCode)
   160  		}
   161  	}
   162  }
   163  
   164  func formatSearchCertificateArguments(cn string, sans *certificate.Sans, certMinTimeLeft time.Duration) string {
   165  	// get future (or past) date for certificate validation
   166  	date := time.Now().Add(certMinTimeLeft)
   167  	// create request arguments
   168  	req := make([]string, 0)
   169  
   170  	if cn != "" {
   171  		req = append(req, fmt.Sprintf("CN=%s", cn))
   172  	}
   173  
   174  	if sans != nil && sans.DNS != nil {
   175  		req = append(req, fmt.Sprintf("SAN-DNS=%s", strings.Join(sans.DNS, ",")))
   176  	}
   177  
   178  	req = append(req, fmt.Sprintf("ValidToGreater=%s", neturl.QueryEscape(date.Format(time.RFC3339))))
   179  
   180  	return strings.Join(req, "&")
   181  }
   182  
   183  func calcThumbprint(cert string) string {
   184  	p, _ := pem.Decode([]byte(cert))
   185  	// nolint:gosec // Although use weak cryptographic primitive (G401), we still needed it for test process only
   186  	h := sha1.New()
   187  	h.Write(p.Bytes)
   188  	buf := h.Sum(nil)
   189  	return strings.ToUpper(fmt.Sprintf("%x", buf))
   190  }