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 }