...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package fixchain
16
17 import (
18 "bytes"
19 "encoding/json"
20 "encoding/pem"
21 "errors"
22 "fmt"
23
24 "github.com/google/certificate-transparency-go/x509"
25 )
26
27 type errorType int
28
29
30 const (
31 None errorType = iota
32 ParseFailure
33 CannotFetchURL
34 FixFailed
35 LogPostFailed
36 VerifyFailed
37 )
38
39
40 type FixError struct {
41 Type errorType
42 Cert *x509.Certificate
43 Chain []*x509.Certificate
44 URL string
45 Bad []byte
46 Error error
47 }
48
49
50 func (e FixError) Equal(f *FixError) bool {
51 if f == nil || e.Type != f.Type || e.URL != f.URL || !bytes.Equal(e.Bad, f.Bad) {
52 return false
53 }
54
55 if e.Cert != nil {
56 if f.Cert == nil || !e.Cert.Equal(f.Cert) {
57 return false
58 }
59 } else if f.Cert != nil {
60 return false
61 }
62
63 if len(e.Chain) != len(f.Chain) {
64 return false
65 }
66 for i := range e.Chain {
67 if !e.Chain[i].Equal(f.Chain[i]) {
68 return false
69 }
70 }
71
72 if e.Error != nil {
73 if f.Error == nil || e.Error.Error() != f.Error.Error() {
74 return false
75 }
76 } else if f.Error != nil {
77 return false
78 }
79
80 return true
81 }
82
83
84 func (e FixError) TypeString() string {
85 switch e.Type {
86 case None:
87 return "None"
88 case ParseFailure:
89 return "ParseFailure"
90 case CannotFetchURL:
91 return "CannotFetchURL"
92 case FixFailed:
93 return "FixFailed"
94 case LogPostFailed:
95 return "LogPostFailed"
96 case VerifyFailed:
97 return "VerifyFailed"
98 default:
99 return fmt.Sprintf("Type %d", e.Type)
100 }
101 }
102
103
104 func (e FixError) String() string {
105 s := e.TypeString() + "\n"
106 if e.Error != nil {
107 s += "Error: " + e.Error.Error() + "\n"
108 }
109 if e.URL != "" {
110 s += "URL: " + e.URL + "\n"
111 }
112 if e.Bad != nil {
113 s += "Bad: " + dumpPEM(e.Bad)
114 }
115 if e.Cert != nil {
116 s += "Cert: " + dumpPEM(e.Cert.Raw)
117 }
118 if e.Chain != nil {
119 s += "Chain: " + dumpChainPEM(e.Chain)
120 }
121 return s
122 }
123
124
125 func (e FixError) MarshalJSON() ([]byte, error) {
126 var m struct {
127 Type string
128 Cert []byte
129 Chain [][]byte
130 URL string
131 Bad []byte
132 Error string
133 Code int
134 }
135 m.Type = e.TypeString()
136 if e.Cert != nil {
137 m.Cert = e.Cert.Raw
138 }
139 for _, c := range e.Chain {
140 m.Chain = append(m.Chain, c.Raw)
141 }
142 m.URL = e.URL
143 m.Bad = e.Bad
144 if e.Error != nil {
145 m.Error = e.Error.Error()
146 }
147
148 return json.Marshal(m)
149 }
150
151
152 func UnmarshalJSON(b []byte) (*FixError, error) {
153 var u struct {
154 Type string
155 Cert []byte
156 Chain [][]byte
157 URL string
158 Bad []byte
159 Error string
160 Code int
161 }
162 err := json.Unmarshal(b, &u)
163 if err != nil {
164 return nil, err
165 }
166
167 ferr := &FixError{}
168 switch u.Type {
169 case "None":
170 ferr.Type = None
171 case "ParseFailure":
172 ferr.Type = ParseFailure
173 case "CannotFetchURL":
174 ferr.Type = CannotFetchURL
175 case "FixFailed":
176 ferr.Type = FixFailed
177 case "LogPostFailed":
178 ferr.Type = LogPostFailed
179 case "VerifyFailed":
180 ferr.Type = VerifyFailed
181 default:
182 return nil, errors.New("cannot parse FixError Type")
183 }
184
185 if u.Cert != nil {
186 cert, err := x509.ParseCertificate(u.Cert)
187 if x509.IsFatal(err) {
188 return nil, fmt.Errorf("cannot parse FixError Cert: %s", err)
189 }
190 ferr.Cert = cert
191 }
192
193 for _, c := range u.Chain {
194 cert, err := x509.ParseCertificate(c)
195 if x509.IsFatal(err) {
196 return nil, fmt.Errorf("cannot parse FixError Chain: %s", err)
197 }
198 ferr.Chain = append(ferr.Chain, cert)
199 }
200
201 ferr.URL = u.URL
202 ferr.Bad = u.Bad
203 if u.Error != "" {
204 ferr.Error = errors.New(u.Error)
205 }
206
207 return ferr, nil
208 }
209
210 func dumpChainPEM(chain []*x509.Certificate) string {
211 var p string
212 for _, cert := range chain {
213 p += dumpPEM(cert.Raw)
214 }
215 return p
216 }
217
218 func dumpPEM(cert []byte) string {
219 b := pem.Block{Type: "CERTIFICATE", Bytes: cert}
220 return string(pem.EncodeToMemory(&b))
221 }
222
View as plain text