blob: 92ddc1bc4731ef9aecca1d9b58f014968d191465 [file] [log] [blame]
Adam Langleyaaa40452017-04-28 09:00:03 -07001// run_cavp.go processes CAVP input files and generates suitable response
2// files, optionally comparing the results against the provided FAX files.
3package main
4
5import (
6 "bufio"
7 "flag"
8 "fmt"
9 "os"
10 "os/exec"
11 "path/filepath"
Adam Langley02690f72017-05-03 16:34:42 -070012 "runtime"
Adam Langleyaaa40452017-04-28 09:00:03 -070013 "strings"
Adam Langley02690f72017-05-03 16:34:42 -070014 "sync"
15 "time"
Adam Langleyaaa40452017-04-28 09:00:03 -070016)
17
18var (
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -070019 oraclePath = flag.String("oracle-bin", "", "Path to the oracle binary")
20 suiteDir = flag.String("suite-dir", "", "Base directory containing the CAVP test suite")
David Benjaminb3aaffa2017-05-17 13:08:26 -040021 noFAX = flag.Bool("no-fax", false, "Skip comparing against FAX files")
Adam Langleyaaa40452017-04-28 09:00:03 -070022)
23
24// test describes a single request file.
25type test struct {
26 // inFile is the base of the filename without an extension, i.e.
27 // “ECBMCT128”.
28 inFile string
29 // args are the arguments (not including the input filename) to the
30 // oracle binary.
David Benjamin90801c12017-04-28 17:08:45 -040031 args []string
Adam Langleyaaa40452017-04-28 09:00:03 -070032 // noFAX, if true, indicates that the output cannot be compared against
33 // the FAX file. (E.g. because the primitive is non-deterministic.)
34 noFAX bool
35}
36
37// testSuite describes a series of tests that are handled by a single oracle
38// binary.
39type testSuite struct {
40 // directory is the name of the directory in the CAVP input, i.e. “AES”.
41 directory string
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -070042 // suite names the test suite to pass as the first command-line argument.
43 suite string
David Benjamin83a9a262017-05-02 15:34:47 -040044 // faxScanFunc, if not nil, is the function to use instead of
45 // (*bufio.Scanner).Scan. This can be used to skip lines.
46 faxScanFunc func(*bufio.Scanner) bool
47 tests []test
Adam Langleyaaa40452017-04-28 09:00:03 -070048}
49
Martin Kreichgauer61e8d362017-04-28 14:21:58 -070050func (t *testSuite) getDirectory() string {
51 return filepath.Join(*suiteDir, t.directory)
52}
53
Adam Langleyaaa40452017-04-28 09:00:03 -070054var aesGCMTests = testSuite{
55 "AES_GCM",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -070056 "aes_gcm",
David Benjamin83a9a262017-05-02 15:34:47 -040057 nil,
Adam Langleyaaa40452017-04-28 09:00:03 -070058 []test{
59 {"gcmDecrypt128", []string{"dec", "aes-128-gcm"}, false},
60 {"gcmDecrypt256", []string{"dec", "aes-256-gcm"}, false},
Adam Langley563924b2017-05-30 11:43:25 -070061 {"gcmEncryptExtIV128", []string{"enc", "aes-128-gcm"}, false},
62 {"gcmEncryptExtIV256", []string{"enc", "aes-256-gcm"}, false},
Adam Langleyaaa40452017-04-28 09:00:03 -070063 },
64}
65
66var aesTests = testSuite{
67 "AES",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -070068 "aes",
David Benjamin83a9a262017-05-02 15:34:47 -040069 nil,
Adam Langleyaaa40452017-04-28 09:00:03 -070070 []test{
Martin Kreichgauer61e8d362017-04-28 14:21:58 -070071 {"CBCGFSbox128", []string{"kat", "aes-128-cbc"}, false},
72 {"CBCGFSbox192", []string{"kat", "aes-192-cbc"}, false},
73 {"CBCGFSbox256", []string{"kat", "aes-256-cbc"}, false},
74 {"CBCKeySbox128", []string{"kat", "aes-128-cbc"}, false},
75 {"CBCKeySbox192", []string{"kat", "aes-192-cbc"}, false},
76 {"CBCKeySbox256", []string{"kat", "aes-256-cbc"}, false},
77 {"CBCMMT128", []string{"kat", "aes-128-cbc"}, false},
78 {"CBCMMT192", []string{"kat", "aes-192-cbc"}, false},
79 {"CBCMMT256", []string{"kat", "aes-256-cbc"}, false},
80 {"CBCVarKey128", []string{"kat", "aes-128-cbc"}, false},
81 {"CBCVarKey192", []string{"kat", "aes-192-cbc"}, false},
82 {"CBCVarKey256", []string{"kat", "aes-256-cbc"}, false},
83 {"CBCVarTxt128", []string{"kat", "aes-128-cbc"}, false},
84 {"CBCVarTxt192", []string{"kat", "aes-192-cbc"}, false},
85 {"CBCVarTxt256", []string{"kat", "aes-256-cbc"}, false},
86 {"ECBGFSbox128", []string{"kat", "aes-128-ecb"}, false},
87 {"ECBGFSbox192", []string{"kat", "aes-192-ecb"}, false},
88 {"ECBGFSbox256", []string{"kat", "aes-256-ecb"}, false},
89 {"ECBKeySbox128", []string{"kat", "aes-128-ecb"}, false},
90 {"ECBKeySbox192", []string{"kat", "aes-192-ecb"}, false},
91 {"ECBKeySbox256", []string{"kat", "aes-256-ecb"}, false},
92 {"ECBMMT128", []string{"kat", "aes-128-ecb"}, false},
93 {"ECBMMT192", []string{"kat", "aes-192-ecb"}, false},
94 {"ECBMMT256", []string{"kat", "aes-256-ecb"}, false},
95 {"ECBVarKey128", []string{"kat", "aes-128-ecb"}, false},
96 {"ECBVarKey192", []string{"kat", "aes-192-ecb"}, false},
97 {"ECBVarKey256", []string{"kat", "aes-256-ecb"}, false},
98 {"ECBVarTxt128", []string{"kat", "aes-128-ecb"}, false},
99 {"ECBVarTxt192", []string{"kat", "aes-192-ecb"}, false},
100 {"ECBVarTxt256", []string{"kat", "aes-256-ecb"}, false},
101 // AES Monte-Carlo tests
102 {"ECBMCT128", []string{"mct", "aes-128-ecb"}, false},
103 {"ECBMCT192", []string{"mct", "aes-192-ecb"}, false},
104 {"ECBMCT256", []string{"mct", "aes-256-ecb"}, false},
105 {"CBCMCT128", []string{"mct", "aes-128-cbc"}, false},
106 {"CBCMCT192", []string{"mct", "aes-192-cbc"}, false},
107 {"CBCMCT256", []string{"mct", "aes-256-cbc"}, false},
Adam Langleyaaa40452017-04-28 09:00:03 -0700108 },
109}
110
David Benjamineb599892017-05-01 14:56:22 -0400111var ecdsa2KeyPairTests = testSuite{
112 "ECDSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700113 "ecdsa2_keypair",
David Benjamin83a9a262017-05-02 15:34:47 -0400114 nil,
David Benjamineb599892017-05-01 14:56:22 -0400115 []test{{"KeyPair", nil, true}},
116}
117
David Benjamin90801c12017-04-28 17:08:45 -0400118var ecdsa2PKVTests = testSuite{
119 "ECDSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700120 "ecdsa2_pkv",
David Benjamin83a9a262017-05-02 15:34:47 -0400121 nil,
David Benjamin90801c12017-04-28 17:08:45 -0400122 []test{{"PKV", nil, false}},
123}
124
David Benjamin9abf84c2017-04-30 14:37:16 -0400125var ecdsa2SigGenTests = testSuite{
126 "ECDSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700127 "ecdsa2_siggen",
David Benjamin83a9a262017-05-02 15:34:47 -0400128 nil,
David Benjamin9abf84c2017-04-30 14:37:16 -0400129 []test{
130 {"SigGen", []string{"SigGen"}, true},
131 {"SigGenComponent", []string{"SigGenComponent"}, true},
132 },
133}
134
David Benjamin0c292ed2017-04-28 17:41:28 -0400135var ecdsa2SigVerTests = testSuite{
136 "ECDSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700137 "ecdsa2_sigver",
David Benjamin83a9a262017-05-02 15:34:47 -0400138 nil,
David Benjamin0c292ed2017-04-28 17:41:28 -0400139 []test{{"SigVer", nil, false}},
140}
141
Steven Valdez9b7228c2017-05-03 11:23:27 -0400142var rsa2KeyGenTests = testSuite{
143 "RSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700144 "rsa2_keygen",
Steven Valdez9b7228c2017-05-03 11:23:27 -0400145 nil,
146 []test{
147 {"KeyGen_RandomProbablyPrime3_3", nil, true},
148 },
149}
150
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400151var rsa2SigGenTests = testSuite{
152 "RSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700153 "rsa2_siggen",
David Benjamin83a9a262017-05-02 15:34:47 -0400154 nil,
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400155 []test{
156 {"SigGen15_186-3", []string{"pkcs15"}, true},
David Benjamin8209a7c2017-05-02 15:02:01 -0400157 {"SigGenPSS_186-3", []string{"pss"}, true},
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400158 },
159}
160
161var rsa2SigVerTests = testSuite{
162 "RSA2",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700163 "rsa2_sigver",
David Benjamin83a9a262017-05-02 15:34:47 -0400164 func(s *bufio.Scanner) bool {
165 for {
166 if !s.Scan() {
167 return false
168 }
169
170 line := s.Text()
171 if strings.HasPrefix(line, "p = ") || strings.HasPrefix(line, "d = ") || strings.HasPrefix(line, "SaltVal = ") || strings.HasPrefix(line, "EM with ") {
172 continue
173 }
174 if strings.HasPrefix(line, "q = ") {
175 // Skip the "q = " line and an additional blank line.
176 if !s.Scan() {
177 return false
178 }
179 if len(strings.TrimSpace(s.Text())) > 0 {
180 return false
181 }
182 continue
183 }
184 return true
185 }
186 },
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400187 []test{
David Benjamin83a9a262017-05-02 15:34:47 -0400188 {"SigVer15_186-3", []string{"pkcs15"}, false},
189 {"SigVerPSS_186-3", []string{"pss"}, false},
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400190 },
191}
192
Steven Valdez493b2a42017-05-01 17:02:01 -0400193var hmacTests = testSuite{
194 "HMAC",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700195 "hmac",
David Benjamin83a9a262017-05-02 15:34:47 -0400196 nil,
Steven Valdez493b2a42017-05-01 17:02:01 -0400197 []test{{"HMAC", nil, false}},
198}
199
Steven Valdezb8a35502017-04-28 16:17:54 -0400200var shaTests = testSuite{
201 "SHA",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700202 "sha",
David Benjamin83a9a262017-05-02 15:34:47 -0400203 nil,
Steven Valdezb8a35502017-04-28 16:17:54 -0400204 []test{
205 {"SHA1LongMsg", []string{"SHA1"}, false},
206 {"SHA1ShortMsg", []string{"SHA1"}, false},
207 {"SHA224LongMsg", []string{"SHA224"}, false},
208 {"SHA224ShortMsg", []string{"SHA224"}, false},
209 {"SHA256LongMsg", []string{"SHA256"}, false},
210 {"SHA256ShortMsg", []string{"SHA256"}, false},
211 {"SHA384LongMsg", []string{"SHA384"}, false},
212 {"SHA384ShortMsg", []string{"SHA384"}, false},
213 {"SHA512LongMsg", []string{"SHA512"}, false},
214 {"SHA512ShortMsg", []string{"SHA512"}, false},
215 },
216}
217
218var shaMonteTests = testSuite{
219 "SHA",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700220 "sha_monte",
David Benjamin83a9a262017-05-02 15:34:47 -0400221 nil,
Steven Valdezb8a35502017-04-28 16:17:54 -0400222 []test{
223 {"SHA1Monte", []string{"SHA1"}, false},
224 {"SHA224Monte", []string{"SHA224"}, false},
225 {"SHA256Monte", []string{"SHA256"}, false},
226 {"SHA384Monte", []string{"SHA384"}, false},
227 {"SHA512Monte", []string{"SHA512"}, false},
228 },
229}
230
Adam Langleyb387e222017-05-01 10:54:03 -0700231var ctrDRBGTests = testSuite{
232 "DRBG800-90A",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700233 "ctr_drbg",
David Benjamin83a9a262017-05-02 15:34:47 -0400234 nil,
Adam Langleyb387e222017-05-01 10:54:03 -0700235 []test{{"CTR_DRBG", nil, false}},
236}
237
Martin Kreichgauer2b2676f2017-05-01 11:56:43 -0700238var tdesTests = testSuite{
239 "TDES",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700240 "tdes",
David Benjamin83a9a262017-05-02 15:34:47 -0400241 nil,
Martin Kreichgauer2b2676f2017-05-01 11:56:43 -0700242 []test{
Martin Kreichgauer6dd055d2017-05-01 15:31:43 -0700243 {"TCBCMMT2", []string{"kat", "des-ede-cbc"}, false},
244 {"TCBCMMT3", []string{"kat", "des-ede3-cbc"}, false},
245 {"TCBCMonte2", []string{"mct", "des-ede3-cbc"}, false},
246 {"TCBCMonte3", []string{"mct", "des-ede3-cbc"}, false},
Martin Kreichgauer2b2676f2017-05-01 11:56:43 -0700247 {"TCBCinvperm", []string{"kat", "des-ede3-cbc"}, false},
248 {"TCBCpermop", []string{"kat", "des-ede3-cbc"}, false},
249 {"TCBCsubtab", []string{"kat", "des-ede3-cbc"}, false},
250 {"TCBCvarkey", []string{"kat", "des-ede3-cbc"}, false},
251 {"TCBCvartext", []string{"kat", "des-ede3-cbc"}, false},
Martin Kreichgauer6dd055d2017-05-01 15:31:43 -0700252 {"TECBMMT2", []string{"kat", "des-ede"}, false},
253 {"TECBMMT3", []string{"kat", "des-ede3"}, false},
254 {"TECBMonte2", []string{"mct", "des-ede3"}, false},
255 {"TECBMonte3", []string{"mct", "des-ede3"}, false},
Martin Kreichgauer2b2676f2017-05-01 11:56:43 -0700256 {"TECBinvperm", []string{"kat", "des-ede3"}, false},
257 {"TECBpermop", []string{"kat", "des-ede3"}, false},
258 {"TECBsubtab", []string{"kat", "des-ede3"}, false},
259 {"TECBvarkey", []string{"kat", "des-ede3"}, false},
260 {"TECBvartext", []string{"kat", "des-ede3"}, false},
261 },
262}
263
Martin Kreichgauerbe5c67d2017-05-03 11:17:50 -0700264var keyWrapTests = testSuite{
265 "KeyWrap38F",
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700266 "keywrap",
Martin Kreichgauerbe5c67d2017-05-03 11:17:50 -0700267 nil,
268 []test{
269 {"KW_AD_128", []string{"dec", "128"}, false},
270 {"KW_AD_256", []string{"dec", "256"}, false},
271 {"KW_AE_128", []string{"enc", "128"}, false},
272 {"KW_AE_256", []string{"enc", "256"}, false},
273 },
274}
275
Adam Langleyaaa40452017-04-28 09:00:03 -0700276var allTestSuites = []*testSuite{
277 &aesGCMTests,
278 &aesTests,
Adam Langleyb387e222017-05-01 10:54:03 -0700279 &ctrDRBGTests,
David Benjamineb599892017-05-01 14:56:22 -0400280 &ecdsa2KeyPairTests,
David Benjamin90801c12017-04-28 17:08:45 -0400281 &ecdsa2PKVTests,
David Benjamin9abf84c2017-04-30 14:37:16 -0400282 &ecdsa2SigGenTests,
David Benjamin0c292ed2017-04-28 17:41:28 -0400283 &ecdsa2SigVerTests,
Martin Kreichgauerbe5c67d2017-05-03 11:17:50 -0700284 &hmacTests,
285 &keyWrapTests,
Steven Valdez9b7228c2017-05-03 11:23:27 -0400286 &rsa2KeyGenTests,
Steven Valdezd1c89cd2017-05-02 11:32:13 -0400287 &rsa2SigGenTests,
288 &rsa2SigVerTests,
Steven Valdezb8a35502017-04-28 16:17:54 -0400289 &shaTests,
290 &shaMonteTests,
Martin Kreichgauer2b2676f2017-05-01 11:56:43 -0700291 &tdesTests,
Adam Langleyaaa40452017-04-28 09:00:03 -0700292}
293
Adam Langley02690f72017-05-03 16:34:42 -0700294// testInstance represents a specific test in a testSuite.
295type testInstance struct {
296 suite *testSuite
297 testIndex int
298}
299
300func worker(wg *sync.WaitGroup, work <-chan testInstance) {
301 defer wg.Done()
302
303 for ti := range work {
304 test := ti.suite.tests[ti.testIndex]
305
306 if err := doTest(ti.suite, test); err != nil {
307 fmt.Fprintf(os.Stderr, "%s\n", err)
308 os.Exit(2)
309 }
310
David Benjaminb3aaffa2017-05-17 13:08:26 -0400311 if !*noFAX && !test.noFAX {
Adam Langley02690f72017-05-03 16:34:42 -0700312 if err := compareFAX(ti.suite, test); err != nil {
313 fmt.Fprintf(os.Stderr, "%s\n", err)
314 os.Exit(3)
315 }
316 }
317 }
318}
319
Adam Langleyaaa40452017-04-28 09:00:03 -0700320func main() {
321 flag.Parse()
322
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700323 if len(*oraclePath) == 0 {
324 fmt.Fprintf(os.Stderr, "Must give -oracle-bin\n")
Adam Langleyaaa40452017-04-28 09:00:03 -0700325 os.Exit(1)
326 }
327
Adam Langley02690f72017-05-03 16:34:42 -0700328 work := make(chan testInstance)
329 var wg sync.WaitGroup
Adam Langleyaaa40452017-04-28 09:00:03 -0700330
Adam Langley02690f72017-05-03 16:34:42 -0700331 for i := 0; i < runtime.NumCPU(); i++ {
332 wg.Add(1)
333 go worker(&wg, work)
334 }
335
336 for _, suite := range allTestSuites {
337 for i := range suite.tests {
338 work <- testInstance{suite, i}
Adam Langleyaaa40452017-04-28 09:00:03 -0700339 }
340 }
Adam Langley02690f72017-05-03 16:34:42 -0700341
342 close(work)
343 wg.Wait()
Adam Langleyaaa40452017-04-28 09:00:03 -0700344}
345
346func doTest(suite *testSuite, test test) error {
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700347 args := []string{suite.suite}
Adam Langleyaaa40452017-04-28 09:00:03 -0700348 args = append(args, test.args...)
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700349 args = append(args, filepath.Join(suite.getDirectory(), "req", test.inFile+".req"))
Adam Langleyaaa40452017-04-28 09:00:03 -0700350
Adam Langley148ea892017-05-03 13:35:47 -0700351 outPath := filepath.Join(suite.getDirectory(), "resp", test.inFile+".rsp")
Adam Langleyaaa40452017-04-28 09:00:03 -0700352 outFile, err := os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
353 if err != nil {
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700354 return fmt.Errorf("cannot open output file for %q %q: %s", suite.getDirectory(), test.inFile, err)
Adam Langleyaaa40452017-04-28 09:00:03 -0700355 }
356 defer outFile.Close()
357
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700358 cmd := exec.Command(*oraclePath, args...)
Adam Langleyaaa40452017-04-28 09:00:03 -0700359 cmd.Stdout = outFile
360 cmd.Stderr = os.Stderr
361
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700362 cmdLine := strings.Join(append([]string{*oraclePath}, args...), " ")
Adam Langley02690f72017-05-03 16:34:42 -0700363 startTime := time.Now()
Adam Langleyaaa40452017-04-28 09:00:03 -0700364 if err := cmd.Run(); err != nil {
Martin Kreichgauerddfcc6a2017-05-03 14:12:39 -0700365 return fmt.Errorf("cannot run command for %q %q (%s): %s", suite.getDirectory(), test.inFile, cmdLine, err)
Adam Langleyaaa40452017-04-28 09:00:03 -0700366 }
367
Adam Langley02690f72017-05-03 16:34:42 -0700368 fmt.Printf("%s (%ds)\n", cmdLine, int(time.Since(startTime).Seconds()))
369
Adam Langleyaaa40452017-04-28 09:00:03 -0700370 return nil
371}
372
David Benjamin90801c12017-04-28 17:08:45 -0400373func canonicalizeLine(in string) string {
374 if strings.HasPrefix(in, "Result = P (") {
375 return "Result = P"
376 }
377 if strings.HasPrefix(in, "Result = F (") {
378 return "Result = F"
379 }
380 return in
381}
382
Adam Langleyaaa40452017-04-28 09:00:03 -0700383func compareFAX(suite *testSuite, test test) error {
David Benjamin83a9a262017-05-02 15:34:47 -0400384 faxScanFunc := suite.faxScanFunc
385 if faxScanFunc == nil {
386 faxScanFunc = (*bufio.Scanner).Scan
387 }
388
Adam Langley148ea892017-05-03 13:35:47 -0700389 respPath := filepath.Join(suite.getDirectory(), "resp", test.inFile+".rsp")
Adam Langleyaaa40452017-04-28 09:00:03 -0700390 respFile, err := os.Open(respPath)
391 if err != nil {
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700392 return fmt.Errorf("cannot read output of %q %q: %s", suite.getDirectory(), test.inFile, err)
Adam Langleyaaa40452017-04-28 09:00:03 -0700393 }
394 defer respFile.Close()
395
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700396 faxPath := filepath.Join(suite.getDirectory(), "fax", test.inFile+".fax")
Adam Langleyaaa40452017-04-28 09:00:03 -0700397 faxFile, err := os.Open(faxPath)
398 if err != nil {
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700399 return fmt.Errorf("cannot open fax file for %q %q: %s", suite.getDirectory(), test.inFile, err)
Adam Langleyaaa40452017-04-28 09:00:03 -0700400 }
401 defer faxFile.Close()
402
403 respScanner := bufio.NewScanner(respFile)
404 faxScanner := bufio.NewScanner(faxFile)
405
406 lineNo := 0
407 inHeader := true
408
409 for respScanner.Scan() {
410 lineNo++
411 respLine := respScanner.Text()
412 var faxLine string
413
414 if inHeader && (len(respLine) == 0 || respLine[0] == '#') {
415 continue
416 }
417
418 for {
419 haveFaxLine := false
420
421 if inHeader {
David Benjamin83a9a262017-05-02 15:34:47 -0400422 for faxScanFunc(faxScanner) {
Adam Langleyaaa40452017-04-28 09:00:03 -0700423 faxLine = faxScanner.Text()
424 if len(faxLine) != 0 && faxLine[0] != '#' {
425 haveFaxLine = true
426 break
427 }
428 }
429
430 inHeader = false
431 } else {
David Benjamin83a9a262017-05-02 15:34:47 -0400432 if faxScanFunc(faxScanner) {
Adam Langleyaaa40452017-04-28 09:00:03 -0700433 faxLine = faxScanner.Text()
434 haveFaxLine = true
435 }
436 }
437
438 if !haveFaxLine {
Steven Valdez493b2a42017-05-01 17:02:01 -0400439 // Ignore blank lines at the end of the generated file.
440 if len(respLine) == 0 {
441 break
442 }
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700443 return fmt.Errorf("resp file is longer than fax for %q %q", suite.getDirectory(), test.inFile)
Adam Langleyaaa40452017-04-28 09:00:03 -0700444 }
445
446 if strings.HasPrefix(faxLine, " (Reason: ") {
447 continue
448 }
449
450 break
451 }
452
David Benjamin90801c12017-04-28 17:08:45 -0400453 if canonicalizeLine(faxLine) == canonicalizeLine(respLine) {
Adam Langleyaaa40452017-04-28 09:00:03 -0700454 continue
455 }
456
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700457 return fmt.Errorf("resp and fax differ at line %d for %q %q: %q vs %q", lineNo, suite.getDirectory(), test.inFile, respLine, faxLine)
Adam Langleyaaa40452017-04-28 09:00:03 -0700458 }
459
David Benjamin83a9a262017-05-02 15:34:47 -0400460 if faxScanFunc(faxScanner) {
Martin Kreichgauer61e8d362017-04-28 14:21:58 -0700461 return fmt.Errorf("fax file is longer than resp for %q %q", suite.getDirectory(), test.inFile)
Adam Langleyaaa40452017-04-28 09:00:03 -0700462 }
463
464 return nil
465}