tsigkey.go raw
1 package internal
2
3 import (
4 "bufio"
5 "fmt"
6 "os"
7 "strings"
8 )
9
10 type Key struct {
11 Name string
12 Algorithm string
13 Secret string
14 }
15
16 // ReadTSIGFile reads TSIG key file generated with `tsig-keygen`.
17 func ReadTSIGFile(filename string) (*Key, error) {
18 file, err := os.Open(filename)
19 if err != nil {
20 return nil, fmt.Errorf("open file: %w", err)
21 }
22
23 defer func() { _ = file.Close() }()
24
25 key := &Key{}
26
27 var read bool
28
29 scanner := bufio.NewScanner(file)
30 for scanner.Scan() {
31 line := strings.TrimSpace(strings.TrimSuffix(scanner.Text(), ";"))
32
33 if line == "" {
34 continue
35 }
36
37 if read && line == "}" {
38 break
39 }
40
41 fields := strings.Fields(line)
42
43 switch {
44 case fields[0] == "key":
45 read = true
46
47 if len(fields) != 3 {
48 return nil, fmt.Errorf("invalid key line: %s", line)
49 }
50
51 key.Name = safeUnquote(fields[1])
52
53 case !read:
54 continue
55
56 default:
57 if len(fields) != 2 {
58 continue
59 }
60
61 v := safeUnquote(fields[1])
62
63 switch safeUnquote(fields[0]) {
64 case "algorithm":
65 key.Algorithm = v
66 case "secret":
67 key.Secret = v
68 default:
69 continue
70 }
71 }
72 }
73
74 return key, nil
75 }
76
77 func safeUnquote(v string) string {
78 if len(v) < 2 {
79 // empty or single character string
80 return v
81 }
82
83 if v[0] == '"' && v[len(v)-1] == '"' {
84 // string wrapped in quotes
85 return v[1 : len(v)-1]
86 }
87
88 return v
89 }
90