├── .github └── workflows │ └── go_test.yml ├── README.md ├── crtlog └── ctlog.go ├── go.mod ├── main.go └── parser ├── parser.go └── parser_test.go /.github/workflows/go_test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests on multi environment 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.18.x] 8 | platform: [ubuntu-latest, macos-latest, windows-latest] 9 | runs-on: ${{ matrix.platform }} 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v1 13 | with: 14 | go-version: ${{ matrix.go-version }} 15 | - name: Checkout code 16 | uses: actions/checkout@v1 17 | - name: Get dependencies 18 | run: go get -v -t -d ./... 19 | - name: Test 20 | run: go test ./... 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | crtsh 2 | === 3 | 4 | `crtsh` is **[crt.sh](https://crt.sh)** Golang utility 5 | 6 | ## Installation 7 | 8 | ```sh 9 | go get github.com/famasoon/crtsh 10 | ``` 11 | 12 | ## Usage 13 | `crtsh` has some option. 14 | 15 | ### `-q` option 16 | The `-q` option is to query to [https://crt.sh](https://crt.sh) 17 | The result is dictionary items which looks like this: 18 | 19 | ```sh 20 | $ crtsh -q example.com 21 | { 22 | Index: 1 23 | Issuer CA ID: 1191 24 | Issuer Name: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA 25 | Name: example.com 26 | Min Cert ID: 987119772 27 | Min Entry TimeStamp: 2018-11-29T13:44:14.118 28 | Not Before: 2018-11-28T00:00:00 29 | Not After: 2020-12-02T12:00:00 30 | Donwload Pem file: https://crt.sh/?d=987119772 31 | } 32 | { 33 | Index: 2 34 | Issuer CA ID: 1191 35 | Issuer Name: C=US, O=DigiCert Inc, CN=DigiCert SHA2 Secure Server CA 36 | Name: example.com 37 | Min Cert ID: 984858191 38 | Min Entry TimeStamp: 2018-11-28T21:20:12.606 39 | Not Before: 2018-11-28T00:00:00 40 | Not After: 2020-12-02T12:00:00 41 | Donwload Pem file: https://crt.sh/?d=984858191 42 | } 43 | { 44 | Index: 3 45 | Issuer CA ID: 1465 46 | Issuer Name: C=US, O="thawte, Inc.", CN=thawte SSL CA - G2 47 | Name: example.com 48 | Min Cert ID: 24564717 49 | Min Entry TimeStamp: 2016-07-14T07:55:01.55 50 | Not Before: 2016-07-14T00:00:00 51 | Not After: 2017-07-14T23:59:59 52 | Donwload Pem file: https://crt.sh/?d=24564717 53 | } 54 | { 55 | Index: 4 56 | Issuer CA ID: 1465 57 | Issuer Name: C=US, O="thawte, Inc.", CN=thawte SSL CA - G2 58 | Name: example.com 59 | Min Cert ID: 24560643 60 | Min Entry TimeStamp: 2016-07-14T07:30:08.461 61 | Not Before: 2016-07-14T00:00:00 62 | Not After: 2018-07-14T23:59:59 63 | Donwload Pem file: https://crt.sh/?d=24560643 64 | } 65 | { 66 | Index: 5 67 | Issuer CA ID: 1465 68 | Issuer Name: C=US, O="thawte, Inc.", CN=thawte SSL CA - G2 69 | Name: example.com 70 | Min Cert ID: 24560621 71 | Min Entry TimeStamp: 2016-07-14T07:25:01.93 72 | Not Before: 2016-07-14T00:00:00 73 | Not After: 2017-07-14T23:59:59 74 | Donwload Pem file: https://crt.sh/?d=24560621 75 | } 76 | { 77 | Index: 6 78 | Issuer CA ID: 1449 79 | Issuer Name: C=US, O=Symantec Corporation, OU=Symantec Trust Network, CN=Symantec Class 3 Secure Server CA - G4 80 | Name: example.com 81 | Min Cert ID: 24558997 82 | Min Entry TimeStamp: 2016-07-14T06:40:02.4 83 | Not Before: 2016-07-14T00:00:00 84 | Not After: 2018-07-14T23:59:59 85 | Donwload Pem file: https://crt.sh/?d=24558997 86 | } 87 | { 88 | Index: 7 89 | Issuer CA ID: 1397 90 | Issuer Name: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA 91 | Name: example.com 92 | Min Cert ID: 10557607 93 | Min Entry TimeStamp: 2015-11-05T14:51:33.941 94 | Not Before: 2015-11-03T00:00:00 95 | Not After: 2018-11-28T12:00:00 96 | Donwload Pem file: https://crt.sh/?d=10557607 97 | } 98 | { 99 | Index: 8 100 | Issuer CA ID: 1397 101 | Issuer Name: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert SHA2 High Assurance Server CA 102 | Name: example.com 103 | Min Cert ID: 5857507 104 | Min Entry TimeStamp: 2014-12-11T14:36:57.201 105 | Not Before: 2014-11-06T00:00:00 106 | Not After: 2015-11-13T12:00:00 107 | Donwload Pem file: https://crt.sh/?d=5857507 108 | } 109 | ``` 110 | 111 | --- 112 | 113 | And `-q` option can use `-o` option. 114 | 115 | The `-o` option only enumerates domains. 116 | 117 | ```sh 118 | $ crtsh -q example.com -o 119 | example.com 120 | example.com 121 | example.com 122 | example.com 123 | example.com 124 | example.com 125 | example.com 126 | example.com 127 | ``` 128 | 129 | --- 130 | 131 | This option can query to use wildcard (% = wildcard) 132 | 133 | For Example: 134 | 135 | ```sh 136 | $ crtsh -q %.example.com -o 137 | www.example.com 138 | www.example.com 139 | www.example.com 140 | *.example.com 141 | *.example.com 142 | m.example.com 143 | www.example.com 144 | dev.example.com 145 | products.example.com 146 | support.example.com 147 | www.example.com 148 | www.example.com 149 | www.example.com 150 | ``` 151 | 152 | We can extract unique URL. 153 | 154 | ```sh 155 | $ crtsh -q %.example.com -o | sort | uniq 156 | *.example.com 157 | dev.example.com 158 | m.example.com 159 | products.example.com 160 | support.example.com 161 | www.example.com 162 | ``` 163 | 164 | ### `-cn` option 165 | The `-cn` option query CommonName. 166 | And this option also can use `-o` option. 167 | For Example: `crtsh -cn ` 168 | 169 | ```sh 170 | $ crtsh -cn test 171 | { 172 | Index: 1 173 | Issuer CA ID: 6831 174 | Issuer Name: C=BE, O=GlobalSign nv-sa, CN=GlobalSign PersonalSign 2 CA - G2 175 | Name: Test 176 | Min Cert ID: 197744191 177 | Min Entry TimeStamp: 2017-08-24T18:23:36.43 178 | Not Before: 2014-07-31T20:44:32 179 | Not After: 2015-08-01T20:44:32 180 | Donwload Pem file: https://crt.sh/?d=197744191 181 | } 182 | { 183 | Index: 2 184 | Issuer CA ID: 750 185 | Issuer Name: emailAddress=contacto@procert.net.ve, L=Chacao, ST=Miranda, OU=Proveedor de Certificados PROCERT, O=Sistema Nacional de Certificacion Electronica, C=VE, CN=PSCProcert 186 | Name: test 187 | Min Cert ID: 197155020 188 | Min Entry TimeStamp: 2017-08-23T22:07:22.88 189 | Not Before: 2017-08-23T13:05:28 190 | Not After: 2018-08-23T13:05:28 191 | Donwload Pem file: https://crt.sh/?d=197155020 192 | } 193 | { 194 | Index: 3 195 | Issuer CA ID: 750 196 | Issuer Name: emailAddress=contacto@procert.net.ve, L=Chacao, ST=Miranda, OU=Proveedor de Certificados PROCERT, O=Sistema Nacional de Certificacion Electronica, C=VE, CN=PSCProcert 197 | Name: test 198 | Min Cert ID: 197073488 199 | Min Entry TimeStamp: 2017-08-23T19:42:20.529 200 | Not Before: 2017-08-23T13:11:13 201 | Not After: 2018-08-23T13:11:13 202 | Donwload Pem file: https://crt.sh/?d=197073488 203 | } 204 | { 205 | Index: 4 206 | Issuer CA ID: 1715 207 | Issuer Name: C=CN, O=CNNIC SHA256 SSL, CN=CNNIC SHA256 SSL 208 | Name: test 209 | Min Cert ID: 7096879 210 | Min Entry TimeStamp: 2015-04-08T00:24:19.637 211 | Not Before: 2014-12-12T06:08:52 212 | Not After: 2015-12-12T06:08:52 213 | Donwload Pem file: https://crt.sh/?d=7096879 214 | } 215 | { 216 | Index: 5 217 | Issuer CA ID: 1715 218 | Issuer Name: C=CN, O=CNNIC SHA256 SSL, CN=CNNIC SHA256 SSL 219 | Name: test 220 | Min Cert ID: 7096563 221 | Min Entry TimeStamp: 2015-04-08T00:11:13.016 222 | Not Before: 2014-12-14T12:00:54 223 | Not After: 2015-12-14T12:00:54 224 | Donwload Pem file: https://crt.sh/?d=7096563 225 | } 226 | { 227 | Index: 6 228 | Issuer CA ID: 29 229 | Issuer Name: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance CA-3 230 | Name: test 231 | Min Cert ID: 4202482 232 | Min Entry TimeStamp: 2014-05-22T23:21:36.633 233 | Not Before: 2011-07-28T00:00:00 234 | Not After: 2014-08-01T12:00:00 235 | Donwload Pem file: https://crt.sh/?d=4202482 236 | } 237 | { 238 | Index: 7 239 | Issuer CA ID: 29 240 | Issuer Name: C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert High Assurance CA-3 241 | Name: test 242 | Min Cert ID: 4202481 243 | Min Entry TimeStamp: 2014-05-22T23:21:33.786 244 | Not Before: 2011-07-28T00:00:00 245 | Not After: 2014-08-01T12:00:00 246 | Donwload Pem file: https://crt.sh/?d=4202481 247 | } 248 | ``` 249 | 250 | 251 | ### `-i` option 252 | The `-i` option parse pem file. 253 | If you set this option, you can enumerate DNS records that was implanted pem file. 254 | I will add more features. 255 | 256 | For Example: `crtsh -i ` 257 | 258 | ```sh 259 | $ crtsh -i 5857507 260 | CertID: 5857507 261 | Enumrate DNS Names: 262 | www.example.org 263 | example.com 264 | example.edu 265 | example.net 266 | example.org 267 | www.example.com 268 | www.example.edu 269 | www.example.net 270 | ``` 271 | 272 | ## Importing 273 | ```go 274 | import ( 275 | "github.com/famasoon/crtsh/ctlog" 276 | "github.com/famasoon/crtsh/parser" 277 | ) 278 | ``` 279 | ## Credit 280 | - This tool is using [https://crt.sh](https://crt.sh) 281 | - Created by FAMASoon 282 | - [Twitter](https://twitter.com/FAMASoon) -------------------------------------------------------------------------------- /crtlog/ctlog.go: -------------------------------------------------------------------------------- 1 | package crtlog 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | // CRTSHURL is URL of crt.sh endpoint 13 | const CRTSHURL string = "https://crt.sh/" 14 | 15 | // CTLogs is CTLog slice 16 | type CTLogs []*CTLog 17 | 18 | // CTLog is result to query crt.sh 19 | // CTLog include some information related CA 20 | type CTLog struct { 21 | IssuerCaID int `json:"issuer_ca_id"` 22 | IssuerName string `json:"issuer_name"` 23 | NameValue string `json:"name_value"` 24 | MinCertID int `json:"min_cert_id"` 25 | MinEntryTimestamp string `json:"min_entry_timestamp"` 26 | NotBefore string `json:"not_before"` 27 | NotAfter string `json:"not_after"` 28 | } 29 | 30 | func queryCrtsh(query string) ([]byte, error) { 31 | req := http.Client{ 32 | Timeout: 60 * time.Second, 33 | } 34 | res, err := req.Get(query) 35 | if err != nil { 36 | return nil, err 37 | } 38 | defer res.Body.Close() 39 | 40 | if res.StatusCode != 200 { 41 | err = fmt.Errorf("can not Access crt.sh") 42 | return nil, err 43 | } 44 | 45 | body, err := ioutil.ReadAll(res.Body) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | return body, nil 51 | } 52 | 53 | func (ctlog CTLog) showFullCTlog() { 54 | fmt.Println("{") 55 | fmt.Printf(" Issuer CA ID: %d\n", ctlog.IssuerCaID) 56 | fmt.Printf(" Issuer Name: %s\n", ctlog.IssuerName) 57 | fmt.Printf(" Name: %s\n", ctlog.NameValue) 58 | fmt.Printf(" Min Cert ID: %d\n", ctlog.MinCertID) 59 | fmt.Printf(" Min Entry TimeStamp: %s\n", ctlog.MinEntryTimestamp) 60 | fmt.Printf(" Not Before: %s\n", ctlog.NotBefore) 61 | fmt.Printf(" Not After: %s\n", ctlog.NotAfter) 62 | fmt.Printf(" Donwload Pem file: %s?d=%d\n", CRTSHURL, ctlog.MinCertID) 63 | fmt.Println("}") 64 | } 65 | 66 | // SearchComon query in crt.sh by common name and print result that 67 | func SearchCommon(query string, onlyDomainFlag bool) error { 68 | var ctlogs CTLogs 69 | 70 | res, err := queryCrtsh(CRTSHURL + "?output=json&CN=" + query) 71 | if err != nil { 72 | return err 73 | } 74 | if err = json.Unmarshal(res, &ctlogs); err != nil { 75 | return err 76 | } 77 | 78 | if onlyDomainFlag { 79 | for _, ctlog := range ctlogs { 80 | fmt.Printf("%s\n", ctlog.NameValue) 81 | } 82 | } else { 83 | for _, ctlog := range ctlogs { 84 | ctlog.showFullCTlog() 85 | } 86 | } 87 | 88 | return nil 89 | } 90 | 91 | // QueryCrt query in crt.sh and print result that 92 | func QueryCrt(query string, onlyDomainFlag bool) error { 93 | var ctlogs CTLogs 94 | 95 | res, err := queryCrtsh(CRTSHURL + "?output=json&q=" + query) 96 | if err != nil { 97 | return err 98 | } 99 | if err = json.Unmarshal(res, &ctlogs); err != nil { 100 | return err 101 | } 102 | 103 | if onlyDomainFlag { 104 | for _, ctlog := range ctlogs { 105 | fmt.Printf("%s\n", ctlog.NameValue) 106 | } 107 | } else { 108 | for _, ctlog := range ctlogs { 109 | ctlog.showFullCTlog() 110 | } 111 | } 112 | 113 | return nil 114 | } 115 | 116 | // GetPemFile download pemfile from crt.sh and dump to []byte 117 | func GetPemFile(certID int) ([]byte, error) { 118 | body, err := queryCrtsh(CRTSHURL + "?d=" + strconv.Itoa(certID)) 119 | if err != nil { 120 | return nil, err 121 | } 122 | 123 | return body, nil 124 | } 125 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/famasoon/crtsh 2 | 3 | go 1.18 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | 9 | "github.com/famasoon/crtsh/crtlog" 10 | "github.com/famasoon/crtsh/parser" 11 | ) 12 | 13 | func showUsage() { 14 | fmt.Println("This tool shows the result of crt.sh") 15 | fmt.Println("Option:") 16 | fmt.Println(" -q Query") 17 | fmt.Println(" -i Min Cert ID") 18 | fmt.Println(" -cn Common Name") 19 | fmt.Printf("Usage: %s -q example.com\n", os.Args[0]) 20 | os.Exit(0) 21 | } 22 | 23 | func run() error { 24 | var ( 25 | query string 26 | certID int 27 | onlyDomainFlag bool 28 | commonName string 29 | ) 30 | flag.StringVar(&query, "q", "", "Query String") 31 | flag.BoolVar(&onlyDomainFlag, "o", false, "Print only domains") 32 | flag.IntVar(&certID, "i", 0, "Min Cert ID") 33 | flag.StringVar(&commonName, "cn", "", "Query string for common name") 34 | flag.Parse() 35 | if query == "" && certID == 0 && commonName == "" { 36 | showUsage() 37 | } 38 | 39 | if query != "" { 40 | err := crtlog.QueryCrt(query, onlyDomainFlag) 41 | if err != nil { 42 | return err 43 | } 44 | } else if certID != 0 { 45 | fmt.Printf("CertID: %d\n", certID) 46 | 47 | err := parser.ParseCTLog(certID) 48 | if err != nil { 49 | return err 50 | } 51 | } else { 52 | err := crtlog.SearchCommon(commonName, onlyDomainFlag) 53 | if err != nil { 54 | return err 55 | } 56 | } 57 | 58 | return nil 59 | } 60 | 61 | func main() { 62 | err := run() 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "crypto/x509" 5 | "encoding/pem" 6 | "fmt" 7 | 8 | "github.com/famasoon/crtsh/crtlog" 9 | ) 10 | 11 | func ParseCTLog(certID int) error { 12 | body, err := crtlog.GetPemFile(certID) 13 | if err != nil { 14 | return err 15 | } 16 | 17 | block, _ := pem.Decode(body) 18 | 19 | cert, err := x509.ParseCertificate(block.Bytes) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | fmt.Println("Enumerate DNS Names:") 25 | for _, dnsName := range enumDNS(cert) { 26 | fmt.Println(dnsName) 27 | } 28 | return nil 29 | } 30 | 31 | // EnumDNS return []string that contain Enumrated DNS names 32 | func enumDNS(cert *x509.Certificate) (DNSrecords []string) { 33 | return cert.DNSNames 34 | } 35 | -------------------------------------------------------------------------------- /parser/parser_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "crypto/x509" 5 | "encoding/pem" 6 | "testing" 7 | ) 8 | 9 | const examplePEM = ` 10 | -----BEGIN CERTIFICATE----- 11 | MIIF6DCCBNCgAwIBAgIQBBHej1O0YvalqGG3EuxrWTANBgkqhkiG9w0BAQsFADBw 12 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 13 | d3cuZGlnaWNlcnQuY29tMS8wLQYDVQQDEyZEaWdpQ2VydCBTSEEyIEhpZ2ggQXNz 14 | dXJhbmNlIFNlcnZlciBDQTAeFw0xNDExMDYwMDAwMDBaFw0xNTExMTMxMjAwMDBa 15 | MIGlMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxML 16 | TG9zIEFuZ2VsZXMxPDA6BgNVBAoTM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBB 17 | c3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczETMBEGA1UECxMKVGVjaG5vbG9neTEY 18 | MBYGA1UEAxMPd3d3LmV4YW1wbGUub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 19 | MIIBCgKCAQEAnmY/UqPRjLZ83+1UdAik5H5ANlOJiNonmNo7ZlX3JA1pPtHLP+bW 20 | rTqeZX/276hrg7DK0k5dMf8r9w7Dt4shPxtL9hvcZpy7wH1nFUEoypKps8u0ITqD 21 | b7gj3dTXzASRgxTSXwYIb6mXC6F+NXzKm0WMJ+txdgq5Xj+byJiuiQUK5NCbovfk 22 | JZ2f8eByppcbGDVai55TZww9Xb29KD+Tp2TnGzpBQMoHRgkMCFEOLiEHjX0HhEv5 23 | wDhltTGgvy7nZrxAH2RRxaHm9vtdXB1ql6Cr6RrosC6JJB4HNTkJzNW0HEbeIHwG 24 | gB4I8gcTYDgn8q4+aM8V74gdfgYI9wdC4wIDAQABo4ICRjCCAkIwHwYDVR0jBBgw 25 | FoAUUWj/kK8CB3U8zNllZGKiErhZcjswHQYDVR0OBBYEFLAAp/Qi6bHOIWEXxMRu 26 | cWTI5gxVMIGBBgNVHREEejB4gg93d3cuZXhhbXBsZS5vcmeCC2V4YW1wbGUuY29t 27 | ggtleGFtcGxlLmVkdYILZXhhbXBsZS5uZXSCC2V4YW1wbGUub3Jngg93d3cuZXhh 28 | bXBsZS5jb22CD3d3dy5leGFtcGxlLmVkdYIPd3d3LmV4YW1wbGUubmV0MA4GA1Ud 29 | DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdQYDVR0f 30 | BG4wbDA0oDKgMIYuaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtc2Vy 31 | dmVyLWczLmNybDA0oDKgMIYuaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTIt 32 | aGEtc2VydmVyLWczLmNybDBCBgNVHSAEOzA5MDcGCWCGSAGG/WwBATAqMCgGCCsG 33 | AQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGDBggrBgEFBQcB 34 | AQR3MHUwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBNBggr 35 | BgEFBQcwAoZBaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hB 36 | MkhpZ2hBc3N1cmFuY2VTZXJ2ZXJDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG 37 | 9w0BAQsFAAOCAQEAXqwhJN7bOXiob/NghAastULTy1TLg/rNY67IgUTWob8V2/Hy 38 | FcSnPiQeWCNly6nqUN0wZUFlOzUTrxoHVsGycg6NESs0+2cYHvrZxGCb3GcPsCX6 39 | bm1CGIFhsCbPMImgg2nC82CfyEvMNHkUDBki7eQwyo26wrKjzayzBboV3HNhxMOl 40 | 5tqpnLRGyyIbKAeKepRO+6cNlvMawUPZWbzNL9UOMMMl6iYk+2ttvpNE288TO/vV 41 | tOiS1jXb8xWWRRZyxrZbpaybPN3qkrNdqxBlyuPIy2u0UKYuovcup8a9x7ZfoJsB 42 | I5JUNzQIPHaH0kP40DdTBNmczS4UiWaoY3pnlw== 43 | -----END CERTIFICATE-----` 44 | 45 | func TestEnumDNS(t *testing.T) { 46 | var tests = []string{ 47 | "www.example.org", 48 | "example.com", 49 | "example.edu", 50 | "example.net", 51 | "example.org", 52 | "www.example.com", 53 | "www.example.edu", 54 | "www.example.net", 55 | } 56 | 57 | block, _ := pem.Decode([]byte(examplePEM)) 58 | if block == nil { 59 | t.Fatal("Can not read pem file") 60 | } 61 | 62 | cert, err := x509.ParseCertificate(block.Bytes) 63 | if err != nil { 64 | t.Fatal("Can not parse certficate") 65 | } 66 | 67 | for key, record := range enumDNS(cert) { 68 | if record != tests[key] { 69 | t.Errorf("#%d: got: %s want %s", key, record, tests[key]) 70 | } 71 | } 72 | } 73 | --------------------------------------------------------------------------------