This repository has been archived by the owner on Apr 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
/
certificate_export.go
99 lines (83 loc) · 2.82 KB
/
certificate_export.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
package cmd
import (
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"os"
"github.com/bpicode/fritzctl/config"
"github.com/bpicode/fritzctl/internal/console"
"github.com/bpicode/fritzctl/internal/stringutils"
"github.com/spf13/cobra"
)
var certExportCmd = &cobra.Command{
Use: "export",
Short: "Export the TLS certificate offered by the FRITZ!Box",
Long: `Export TLS certificate offered by the FRITZ!Box to stdout, encoded in PEM format.
The output can be redirected to a file or copied from the terminal output.
Use the data beginning with "-----BEGIN CERTIFICATE-----" and ending with "-----END CERTIFICATE-----".`,
Example: "fritzctl certificate export > /path/to/certificate.pem",
RunE: certExport,
}
func init() {
certCmd.AddCommand(certExportCmd)
}
func certExport(_ *cobra.Command, _ []string) error {
cfg := mustReadConfig()
conn := mustConnect(cfg)
defer conn.Close()
crt := mustHaveCert(conn)
logCrt(&printableCert{crt}, os.Stderr)
writeCrt(crt, os.Stdout)
return nil
}
func mustReadConfig() *config.Config {
c, err := cfg(defaultConfigPlaces...)
assertNoErr(err, "cannot parse configuration")
return c
}
func mustConnect(cfg *config.Config) *tls.Conn {
conn, err := tls.Dial("tcp", connectionString(cfg), &tls.Config{InsecureSkipVerify: true})
assertNoErr(err, "certificate export failed, cannot connect to remote")
return conn
}
func mustHaveCert(conn *tls.Conn) *x509.Certificate {
state := conn.ConnectionState()
assertTrue(len(state.PeerCertificates) > 0, errors.New("certificate export failed, list of peer certificates is empty"))
crt := state.PeerCertificates[len(state.PeerCertificates)-1]
return crt
}
func writeCrt(crt *x509.Certificate, w io.Writer) {
p := pem.Block{Type: "CERTIFICATE", Bytes: crt.Raw}
pem.Encode(w, &p)
}
func logCrt(crt *printableCert, w io.Writer) {
fmt.Fprintf(w, "%s %s\n", console.Cyan("Serial Number: "), crt.serial())
fmt.Fprintf(w, "%s %s\n", console.Cyan("Issued to: "), crt.issuedTo())
fmt.Fprintf(w, "%s %s\n", console.Cyan("Validity: "), crt.validity())
fmt.Fprintf(w, "%s %s\n", console.Cyan("SHA-256 fingerprint:"), crt.fingerprintSHA256())
}
func connectionString(cfg *config.Config) string {
return fmt.Sprintf("%s:%s", cfg.Host, stringutils.DefaultIfEmpty(cfg.Port, "443"))
}
type printableCert struct {
*x509.Certificate
}
func (c *printableCert) serial() string {
sn := c.SerialNumber.Bytes
return hex.EncodeToString(sn())
}
func (c *printableCert) fingerprintSHA256() string {
sum256 := sha256.Sum256(c.Raw)
return hex.EncodeToString(sum256[:])
}
func (c *printableCert) issuedTo() string {
return fmt.Sprintf("CN='%s' O='%s'", c.Subject.CommonName, c.Subject.Organization)
}
func (c *printableCert) validity() string {
return fmt.Sprintf("from %s to %s", c.NotBefore, c.NotAfter)
}