-
Notifications
You must be signed in to change notification settings - Fork 53
/
crt-lists.go
173 lines (153 loc) · 5.16 KB
/
crt-lists.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package runtime
import (
"fmt"
"regexp"
"strconv"
"strings"
native_errors "github.com/haproxytech/client-native/v5/errors"
)
type CrtLists []*CrtList
type CrtList struct {
File string
}
type CrtListEntries []*CrtListEntry
type CrtListEntry struct {
File string
SSLBindConfig string
SNIFilter []string
LineNumber int
}
// ShowCrtLists returns CrtList files description from runtime
func (s *SingleRuntime) ShowCrtLists() (CrtLists, error) {
response, err := s.ExecuteWithResponse("show ssl crt-list")
if err != nil {
return nil, fmt.Errorf("%s %w", err.Error(), native_errors.ErrNotFound)
}
return s.parseCrtLists(response), nil
}
// parseCrtLists parses output from `show crt-list` command and return array of crt-list files
// First line in output represents format and is ignored
// Sample output format:
// /etc/ssl/crt-list
// /etc/ssl/...
func (s *SingleRuntime) parseCrtLists(output string) CrtLists {
output = strings.TrimSpace(output)
if output == "" {
return nil
}
crtLists := CrtLists{}
lines := strings.Split(output, "\n")
for _, line := range lines {
c := s.parseCrtList(line)
if c != nil {
crtLists = append(crtLists, c)
}
}
return crtLists
}
// parseCrtList parses one line from CrtList files array and return it structured
func (s *SingleRuntime) parseCrtList(line string) *CrtList {
if line == "" {
return nil
}
crtList := &CrtList{
File: line,
}
return crtList
}
// GetCrtList returns one structured runtime CrtList file
func (s *SingleRuntime) GetCrtList(file string) (*CrtList, error) {
crtLists, err := s.ShowCrtLists()
if err != nil {
return nil, err
}
for _, m := range crtLists {
if m.File == file {
return m, nil
}
}
return nil, fmt.Errorf("%s %w", file, native_errors.ErrNotFound)
}
// ShowCrtListEntries returns one CrtList runtime entries
func (s *SingleRuntime) ShowCrtListEntries(file string) (CrtListEntries, error) {
cmd := fmt.Sprintf("show ssl crt-list -n %s", file)
response, err := s.ExecuteWithResponse(cmd)
if err != nil {
return nil, fmt.Errorf("%s %w", err.Error(), native_errors.ErrNotFound)
}
return ParseCrtListEntries(response)
}
// ParseCrtListEntries parses array of entries in one CrtList file
// One line sample entry:
// /etc/ssl/cert-0.pem !*.crt-test.platform.domain.com !connectivitynotification.platform.domain.com !connectivitytunnel.platform.domain.com !authentication.cert.another.domain.com !*.authentication.cert.another.domain.com
// /etc/ssl/cert-1.pem [verify optional ca-file /etc/ssl/ca-file-1.pem] *.crt-test.platform.domain.com !connectivitynotification.platform.domain.com !connectivitytunnel.platform.domain.com !authentication.cert.another.domain.com !*.authentication.cert.another.domain.com
// /etc/ssl/cert-2.pem [verify required ca-file /etc/ssl/ca-file-2.pem]
func ParseCrtListEntries(output string) (CrtListEntries, error) {
output = strings.TrimSpace(output)
if output == "" || strings.HasPrefix(output, "didn't find the specified filename") {
return nil, native_errors.ErrNotFound
}
ce := CrtListEntries{}
lines := strings.Split(strings.TrimSpace(output), "\n")
for _, line := range lines {
entry := parseCrtListEntry(line)
if entry != nil {
ce = append(ce, entry)
}
}
return ce, nil
}
// parseCrtListEntry parses one entry in one CrtList file/runtime and returns it structured
// example:
// cert1.pem
// cert2.pem [alpn h2,http/1.1]
// certW.pem *.domain.tld !secure.domain.tld
// certS.pem [curves X25519:P-256 ciphers ECDHE-ECDSA-AES256-GCM-SHA384] secure.domain.tld
func parseCrtListEntry(line string) *CrtListEntry {
if line == "" || strings.HasPrefix(strings.TrimSpace(line), "#") {
return nil
}
c := &CrtListEntry{}
re := regexp.MustCompile(`(\S+)(?:\s\[(.*)\])?(?:\s(.*))?`)
matches := re.FindStringSubmatch(line)
if matches != nil {
split := strings.Split(matches[1], ":")
linenumber, _ := strconv.ParseInt(split[1], 0, 32)
c.LineNumber = int(linenumber)
c.File = split[0]
c.SSLBindConfig = matches[2]
c.SNIFilter = strings.Fields(matches[3])
}
return c
}
// AddCrtListEntry adds an entry into the CrtList file
func (s *SingleRuntime) AddCrtListEntry(crtList string, entry CrtListEntry) error {
cmd := fmt.Sprintf("add ssl crt-list %s <<\n%s", crtList, entry.File)
if entry.SSLBindConfig != "" {
cmd = fmt.Sprintf("%s [%s]", cmd, entry.SSLBindConfig)
}
for _, sni := range entry.SNIFilter {
cmd = fmt.Sprintf("%s %s", cmd, sni)
}
cmd += "\n"
response, err := s.ExecuteWithResponse(cmd)
if err != nil {
return fmt.Errorf("%s %w", err.Error(), native_errors.ErrGeneral)
}
if !strings.Contains(response, "Success") {
return fmt.Errorf("%s %w", response, native_errors.ErrGeneral)
}
return nil
}
// DeleteCrtListEntry deletes all the CrtList entries from the CrtList by its id
func (s *SingleRuntime) DeleteCrtListEntry(crtList, certFile string, lineNumber int) error {
cmd := fmt.Sprintf("del ssl crt-list %s %s:%v", crtList, certFile, lineNumber)
response, err := s.ExecuteWithResponse(cmd)
if err != nil {
return fmt.Errorf("%s %w", err.Error(), native_errors.ErrNotFound)
}
if !strings.Contains(response, "deleted in crtlist") {
return fmt.Errorf("%s %w", response, native_errors.ErrGeneral)
}
return nil
}