-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
121 lines (110 loc) · 3 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"bytes"
"crypto/tls"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"net"
"os"
"os/exec"
"strings"
"time"
)
// https://stackoverflow.com/a/46735876
func getCertificatesPEM(dialTimeout int, address string) ([]byte, error) {
dialer := &net.Dialer{
Timeout: time.Duration(dialTimeout) * time.Second,
}
conn, err := tls.DialWithDialer(dialer, "tcp", address, &tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
if strings.Contains(err.Error(), "i/o timeout") {
fmt.Printf("Timed out connecting to %s, waited %d seconds\n", address, dialTimeout)
fmt.Println("if you are confident that you can connect, consider increasing the timeout with --timeout 30, for 30 seconds")
return []byte(""), err
}
return []byte(""), err
}
defer conn.Close()
var b bytes.Buffer
for _, cert := range conn.ConnectionState().PeerCertificates {
err := pem.Encode(&b, &pem.Block{
Type: "CERTIFICATE",
Bytes: cert.Raw,
})
if err != nil {
return []byte(""), err
}
}
certs := b.Bytes()
return certs, nil
}
func updateFedora(certs []byte, pemName string) {
path := "/etc/pki/ca-trust/source/anchors/" + pemName
err := ioutil.WriteFile(path, certs, 0644)
if err != nil {
if strings.Contains(err.Error(), "permission denied") {
fmt.Println(err)
fmt.Println(" Try running with sudo, sudo !!")
os.Exit(1)
}
fmt.Println(err)
os.Exit(1)
}
cmd := exec.Command("update-ca-trust")
err = cmd.Run()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func main() {
uriPtr := flag.String("uri", "", "A hostname and port, jmainguy.com:443 for example")
pemPtr := flag.String("pem", "", "pem file to write to, same name as host.port.pem by default, as interpretted from uri")
updateFedoraPtr := flag.Bool("updateFedora", false, "write pem to /etc/pki/ca-trust/source/anchors and run update-ca-trust")
timeoutPtr := flag.Int("timeout", 10, "Timeout in seconds")
flag.Parse()
if *uriPtr == "" {
flag.PrintDefaults()
fmt.Println("")
fmt.Println(" To save jmainguy.com:443 cert, run certificatedownloader --uri jmainguy.com:443 for example")
fmt.Println("")
os.Exit(1)
}
// Replace https:// and / with "", this will allow a host like https://jmainguy.com/ to be passed
// Even though, you really shouldnt be passing it in this format
uri := strings.ReplaceAll(*uriPtr, "https://", "")
uri = strings.ReplaceAll(uri, "/", "")
uriArray := strings.Split(uri, ":")
if len(uriArray) == 1 {
uri = uri + ":443"
} else if len(uriArray) > 2 {
fmt.Printf("Please format uri as host:port, you provided %s\n", uri)
}
certs, err := getCertificatesPEM(*timeoutPtr, uri)
var pemName string
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if *pemPtr == "" {
pemName = strings.ReplaceAll(uri, ":", ".")
} else {
pemName = *pemPtr
}
if !strings.HasSuffix(pemName, ".pem") {
pemName = pemName + ".pem"
}
if *updateFedoraPtr {
updateFedora(certs, pemName)
} else {
err = ioutil.WriteFile(pemName, certs, 0644)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
}