You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

583 line
16 KiB

  1. // run_cavp.go processes CAVP input files and generates suitable response
  2. // files, optionally comparing the results against the provided FAX files.
  3. package main
  4. import (
  5. "bufio"
  6. "errors"
  7. "flag"
  8. "fmt"
  9. "os"
  10. "os/exec"
  11. "path"
  12. "path/filepath"
  13. "runtime"
  14. "strings"
  15. "sync"
  16. "time"
  17. )
  18. var (
  19. oraclePath = flag.String("oracle-bin", "", "Path to the oracle binary")
  20. suiteDir = flag.String("suite-dir", "", "Base directory containing the CAVP test suite")
  21. noFAX = flag.Bool("no-fax", false, "Skip comparing against FAX files")
  22. android = flag.Bool("android", false, "Run tests via ADB")
  23. )
  24. const (
  25. androidTmpPath = "/data/local/tmp/"
  26. androidCAVPPath = androidTmpPath + "cavp"
  27. androidLibCryptoPath = androidTmpPath + "libcrypto.so"
  28. )
  29. // test describes a single request file.
  30. type test struct {
  31. // inFile is the base of the filename without an extension, i.e.
  32. // “ECBMCT128”.
  33. inFile string
  34. // args are the arguments (not including the input filename) to the
  35. // oracle binary.
  36. args []string
  37. // noFAX, if true, indicates that the output cannot be compared against
  38. // the FAX file. (E.g. because the primitive is non-deterministic.)
  39. noFAX bool
  40. }
  41. // nextLineState can be used by FAX next-line function to store state.
  42. type nextLineState struct {
  43. // State used by the KAS test.
  44. nextIsIUTHash bool
  45. }
  46. // testSuite describes a series of tests that are handled by a single oracle
  47. // binary.
  48. type testSuite struct {
  49. // directory is the name of the directory in the CAVP input, i.e. “AES”.
  50. directory string
  51. // suite names the test suite to pass as the first command-line argument.
  52. suite string
  53. // nextLineFunc, if not nil, is the function used to read the next line
  54. // from the FAX file. This can be used to skip lines and/or mutate them
  55. // as needed. The second argument can be used by the scanner to store
  56. // state, if needed. If isWildcard is true on return then line is not
  57. // meaningful and any line from the response file should be accepted.
  58. nextLineFunc func(*bufio.Scanner, *nextLineState) (line string, isWildcard, ok bool)
  59. tests []test
  60. }
  61. func (t *testSuite) getDirectory() string {
  62. return filepath.Join(*suiteDir, t.directory)
  63. }
  64. var aesGCMTests = testSuite{
  65. "AES_GCM",
  66. "aes_gcm",
  67. nil,
  68. []test{
  69. {"gcmDecrypt128", []string{"dec", "aes-128-gcm"}, false},
  70. {"gcmDecrypt256", []string{"dec", "aes-256-gcm"}, false},
  71. {"gcmEncryptExtIV128", []string{"enc", "aes-128-gcm"}, false},
  72. {"gcmEncryptExtIV256", []string{"enc", "aes-256-gcm"}, false},
  73. },
  74. }
  75. var aesTests = testSuite{
  76. "AES",
  77. "aes",
  78. nil,
  79. []test{
  80. {"CBCGFSbox128", []string{"kat", "aes-128-cbc"}, false},
  81. {"CBCGFSbox192", []string{"kat", "aes-192-cbc"}, false},
  82. {"CBCGFSbox256", []string{"kat", "aes-256-cbc"}, false},
  83. {"CBCKeySbox128", []string{"kat", "aes-128-cbc"}, false},
  84. {"CBCKeySbox192", []string{"kat", "aes-192-cbc"}, false},
  85. {"CBCKeySbox256", []string{"kat", "aes-256-cbc"}, false},
  86. {"CBCMMT128", []string{"kat", "aes-128-cbc"}, false},
  87. {"CBCMMT192", []string{"kat", "aes-192-cbc"}, false},
  88. {"CBCMMT256", []string{"kat", "aes-256-cbc"}, false},
  89. {"CBCVarKey128", []string{"kat", "aes-128-cbc"}, false},
  90. {"CBCVarKey192", []string{"kat", "aes-192-cbc"}, false},
  91. {"CBCVarKey256", []string{"kat", "aes-256-cbc"}, false},
  92. {"CBCVarTxt128", []string{"kat", "aes-128-cbc"}, false},
  93. {"CBCVarTxt192", []string{"kat", "aes-192-cbc"}, false},
  94. {"CBCVarTxt256", []string{"kat", "aes-256-cbc"}, false},
  95. {"ECBGFSbox128", []string{"kat", "aes-128-ecb"}, false},
  96. {"ECBGFSbox192", []string{"kat", "aes-192-ecb"}, false},
  97. {"ECBGFSbox256", []string{"kat", "aes-256-ecb"}, false},
  98. {"ECBKeySbox128", []string{"kat", "aes-128-ecb"}, false},
  99. {"ECBKeySbox192", []string{"kat", "aes-192-ecb"}, false},
  100. {"ECBKeySbox256", []string{"kat", "aes-256-ecb"}, false},
  101. {"ECBMMT128", []string{"kat", "aes-128-ecb"}, false},
  102. {"ECBMMT192", []string{"kat", "aes-192-ecb"}, false},
  103. {"ECBMMT256", []string{"kat", "aes-256-ecb"}, false},
  104. {"ECBVarKey128", []string{"kat", "aes-128-ecb"}, false},
  105. {"ECBVarKey192", []string{"kat", "aes-192-ecb"}, false},
  106. {"ECBVarKey256", []string{"kat", "aes-256-ecb"}, false},
  107. {"ECBVarTxt128", []string{"kat", "aes-128-ecb"}, false},
  108. {"ECBVarTxt192", []string{"kat", "aes-192-ecb"}, false},
  109. {"ECBVarTxt256", []string{"kat", "aes-256-ecb"}, false},
  110. // AES Monte-Carlo tests
  111. {"ECBMCT128", []string{"mct", "aes-128-ecb"}, false},
  112. {"ECBMCT192", []string{"mct", "aes-192-ecb"}, false},
  113. {"ECBMCT256", []string{"mct", "aes-256-ecb"}, false},
  114. {"CBCMCT128", []string{"mct", "aes-128-cbc"}, false},
  115. {"CBCMCT192", []string{"mct", "aes-192-cbc"}, false},
  116. {"CBCMCT256", []string{"mct", "aes-256-cbc"}, false},
  117. },
  118. }
  119. var ecdsa2KeyPairTests = testSuite{
  120. "ECDSA2",
  121. "ecdsa2_keypair",
  122. nil,
  123. []test{{"KeyPair", nil, true}},
  124. }
  125. var ecdsa2PKVTests = testSuite{
  126. "ECDSA2",
  127. "ecdsa2_pkv",
  128. nil,
  129. []test{{"PKV", nil, false}},
  130. }
  131. var ecdsa2SigGenTests = testSuite{
  132. "ECDSA2",
  133. "ecdsa2_siggen",
  134. nil,
  135. []test{
  136. {"SigGen", []string{"SigGen"}, true},
  137. {"SigGenComponent", []string{"SigGenComponent"}, true},
  138. },
  139. }
  140. var ecdsa2SigVerTests = testSuite{
  141. "ECDSA2",
  142. "ecdsa2_sigver",
  143. nil,
  144. []test{{"SigVer", nil, false}},
  145. }
  146. var rsa2KeyGenTests = testSuite{
  147. "RSA2",
  148. "rsa2_keygen",
  149. nil,
  150. []test{
  151. {"KeyGen_RandomProbablyPrime3_3", nil, true},
  152. },
  153. }
  154. var rsa2SigGenTests = testSuite{
  155. "RSA2",
  156. "rsa2_siggen",
  157. nil,
  158. []test{
  159. {"SigGen15_186-3", []string{"pkcs15"}, true},
  160. {"SigGenPSS_186-3", []string{"pss"}, true},
  161. },
  162. }
  163. var rsa2SigVerTests = testSuite{
  164. "RSA2",
  165. "rsa2_sigver",
  166. func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
  167. for {
  168. if !s.Scan() {
  169. return "", false, false
  170. }
  171. line := s.Text()
  172. if strings.HasPrefix(line, "p = ") || strings.HasPrefix(line, "d = ") || strings.HasPrefix(line, "SaltVal = ") || strings.HasPrefix(line, "EM with ") {
  173. continue
  174. }
  175. if strings.HasPrefix(line, "q = ") {
  176. // Skip the "q = " line and an additional blank line.
  177. if !s.Scan() ||
  178. len(strings.TrimSpace(s.Text())) > 0 {
  179. return "", false, false
  180. }
  181. continue
  182. }
  183. return line, false, true
  184. }
  185. },
  186. []test{
  187. {"SigVer15_186-3", []string{"pkcs15"}, false},
  188. {"SigVerPSS_186-3", []string{"pss"}, false},
  189. },
  190. }
  191. var hmacTests = testSuite{
  192. "HMAC",
  193. "hmac",
  194. nil,
  195. []test{{"HMAC", nil, false}},
  196. }
  197. var shaTests = testSuite{
  198. "SHA",
  199. "sha",
  200. nil,
  201. []test{
  202. {"SHA1LongMsg", []string{"SHA1"}, false},
  203. {"SHA1ShortMsg", []string{"SHA1"}, false},
  204. {"SHA224LongMsg", []string{"SHA224"}, false},
  205. {"SHA224ShortMsg", []string{"SHA224"}, false},
  206. {"SHA256LongMsg", []string{"SHA256"}, false},
  207. {"SHA256ShortMsg", []string{"SHA256"}, false},
  208. {"SHA384LongMsg", []string{"SHA384"}, false},
  209. {"SHA384ShortMsg", []string{"SHA384"}, false},
  210. {"SHA512LongMsg", []string{"SHA512"}, false},
  211. {"SHA512ShortMsg", []string{"SHA512"}, false},
  212. },
  213. }
  214. var shaMonteTests = testSuite{
  215. "SHA",
  216. "sha_monte",
  217. nil,
  218. []test{
  219. {"SHA1Monte", []string{"SHA1"}, false},
  220. {"SHA224Monte", []string{"SHA224"}, false},
  221. {"SHA256Monte", []string{"SHA256"}, false},
  222. {"SHA384Monte", []string{"SHA384"}, false},
  223. {"SHA512Monte", []string{"SHA512"}, false},
  224. },
  225. }
  226. var ctrDRBGTests = testSuite{
  227. "DRBG800-90A",
  228. "ctr_drbg",
  229. nil,
  230. []test{{"CTR_DRBG", nil, false}},
  231. }
  232. var tdesTests = testSuite{
  233. "TDES",
  234. "tdes",
  235. nil,
  236. []test{
  237. {"TCBCMMT2", []string{"kat", "des-ede-cbc"}, false},
  238. {"TCBCMMT3", []string{"kat", "des-ede3-cbc"}, false},
  239. {"TCBCMonte2", []string{"mct", "des-ede3-cbc"}, false},
  240. {"TCBCMonte3", []string{"mct", "des-ede3-cbc"}, false},
  241. {"TCBCinvperm", []string{"kat", "des-ede3-cbc"}, false},
  242. {"TCBCpermop", []string{"kat", "des-ede3-cbc"}, false},
  243. {"TCBCsubtab", []string{"kat", "des-ede3-cbc"}, false},
  244. {"TCBCvarkey", []string{"kat", "des-ede3-cbc"}, false},
  245. {"TCBCvartext", []string{"kat", "des-ede3-cbc"}, false},
  246. {"TECBMMT2", []string{"kat", "des-ede"}, false},
  247. {"TECBMMT3", []string{"kat", "des-ede3"}, false},
  248. {"TECBMonte2", []string{"mct", "des-ede3"}, false},
  249. {"TECBMonte3", []string{"mct", "des-ede3"}, false},
  250. {"TECBinvperm", []string{"kat", "des-ede3"}, false},
  251. {"TECBpermop", []string{"kat", "des-ede3"}, false},
  252. {"TECBsubtab", []string{"kat", "des-ede3"}, false},
  253. {"TECBvarkey", []string{"kat", "des-ede3"}, false},
  254. {"TECBvartext", []string{"kat", "des-ede3"}, false},
  255. },
  256. }
  257. var keyWrapTests = testSuite{
  258. "KeyWrap38F",
  259. "keywrap",
  260. nil,
  261. []test{
  262. {"KW_AD_128", []string{"dec", "128"}, false},
  263. {"KW_AD_256", []string{"dec", "256"}, false},
  264. {"KW_AE_128", []string{"enc", "128"}, false},
  265. {"KW_AE_256", []string{"enc", "256"}, false},
  266. },
  267. }
  268. var kasTests = testSuite{
  269. "KAS",
  270. "kas",
  271. func(s *bufio.Scanner, state *nextLineState) (line string, isWildcard, ok bool) {
  272. for {
  273. // If the response file will include the IUT hash next,
  274. // return a wildcard signal because this cannot be
  275. // matched against the FAX file.
  276. if state.nextIsIUTHash {
  277. state.nextIsIUTHash = false
  278. return "", true, true
  279. }
  280. if !s.Scan() {
  281. return "", false, false
  282. }
  283. line := s.Text()
  284. if strings.HasPrefix(line, "deCAVS = ") || strings.HasPrefix(line, "Z = ") {
  285. continue
  286. }
  287. if strings.HasPrefix(line, "CAVSHashZZ = ") {
  288. state.nextIsIUTHash = true
  289. }
  290. return line, false, true
  291. }
  292. },
  293. []test{
  294. {"KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_init", []string{"function"}, true},
  295. {"KASFunctionTest_ECCEphemeralUnified_NOKC_ZZOnly_resp", []string{"function"}, true},
  296. {"KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_init", []string{"validity"}, false},
  297. {"KASValidityTest_ECCEphemeralUnified_NOKC_ZZOnly_resp", []string{"validity"}, false},
  298. },
  299. }
  300. var tlsKDFTests = testSuite{
  301. "KDF135",
  302. "tlskdf",
  303. nil,
  304. []test{
  305. {"tls", nil, false},
  306. },
  307. }
  308. var testSuites = []*testSuite{
  309. &aesGCMTests,
  310. &aesTests,
  311. &ctrDRBGTests,
  312. &ecdsa2KeyPairTests,
  313. &ecdsa2PKVTests,
  314. &ecdsa2SigGenTests,
  315. &ecdsa2SigVerTests,
  316. &hmacTests,
  317. &keyWrapTests,
  318. &rsa2KeyGenTests,
  319. &rsa2SigGenTests,
  320. &rsa2SigVerTests,
  321. &shaTests,
  322. &shaMonteTests,
  323. &tdesTests,
  324. &kasTests,
  325. &tlsKDFTests,
  326. }
  327. // testInstance represents a specific test in a testSuite.
  328. type testInstance struct {
  329. suite *testSuite
  330. testIndex int
  331. }
  332. func worker(wg *sync.WaitGroup, work <-chan testInstance) {
  333. defer wg.Done()
  334. for ti := range work {
  335. test := ti.suite.tests[ti.testIndex]
  336. if err := doTest(ti.suite, test); err != nil {
  337. fmt.Fprintf(os.Stderr, "%s\n", err)
  338. os.Exit(2)
  339. }
  340. if !*noFAX && !test.noFAX {
  341. if err := compareFAX(ti.suite, test); err != nil {
  342. fmt.Fprintf(os.Stderr, "%s\n", err)
  343. os.Exit(3)
  344. }
  345. }
  346. }
  347. }
  348. func checkAndroidPrereqs() error {
  349. // The cavp binary, and a matching libcrypto.so, are required to be placed
  350. // in /data/local/tmp before running this script.
  351. if err := exec.Command("adb", "shell", "ls", androidCAVPPath).Run(); err != nil {
  352. return errors.New("failed to list cavp binary; ensure that adb works and cavp binary is in place: " + err.Error())
  353. }
  354. if err := exec.Command("adb", "shell", "ls", androidLibCryptoPath).Run(); err != nil {
  355. return errors.New("failed to list libcrypto.so; ensure that library is in place: " + err.Error())
  356. }
  357. return nil
  358. }
  359. func main() {
  360. flag.Parse()
  361. if *android {
  362. if err := checkAndroidPrereqs(); err != nil {
  363. fmt.Fprintf(os.Stderr, "%s\n", err)
  364. os.Exit(1)
  365. }
  366. } else if len(*oraclePath) == 0 {
  367. fmt.Fprintf(os.Stderr, "Must give -oracle-bin\n")
  368. os.Exit(1)
  369. }
  370. work := make(chan testInstance)
  371. var wg sync.WaitGroup
  372. numWorkers := runtime.NumCPU()
  373. if *android {
  374. numWorkers = 1
  375. }
  376. for i := 0; i < numWorkers; i++ {
  377. wg.Add(1)
  378. go worker(&wg, work)
  379. }
  380. for _, suite := range testSuites {
  381. for i := range suite.tests {
  382. work <- testInstance{suite, i}
  383. }
  384. }
  385. close(work)
  386. wg.Wait()
  387. }
  388. func doTest(suite *testSuite, test test) error {
  389. bin := *oraclePath
  390. var args []string
  391. if *android {
  392. bin = "adb"
  393. args = []string{"shell", "LD_LIBRARY_PATH=" + androidTmpPath, androidCAVPPath}
  394. }
  395. args = append(args, suite.suite)
  396. args = append(args, test.args...)
  397. reqPath := filepath.Join(suite.getDirectory(), "req", test.inFile+".req")
  398. var reqPathOnDevice string
  399. if *android {
  400. reqPathOnDevice = path.Join(androidTmpPath, test.inFile+".req")
  401. if err := exec.Command("adb", "push", reqPath, reqPathOnDevice).Run(); err != nil {
  402. return errors.New("failed to push request file: " + err.Error())
  403. }
  404. args = append(args, reqPathOnDevice)
  405. } else {
  406. args = append(args, reqPath)
  407. }
  408. respDir := filepath.Join(suite.getDirectory(), "resp")
  409. if err := os.Mkdir(respDir, 0755); err != nil && !os.IsExist(err) {
  410. return fmt.Errorf("cannot create resp directory: %s", err)
  411. }
  412. outPath := filepath.Join(respDir, test.inFile+".rsp")
  413. outFile, err := os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
  414. if err != nil {
  415. return fmt.Errorf("cannot open output file for %q %q: %s", suite.getDirectory(), test.inFile, err)
  416. }
  417. defer outFile.Close()
  418. cmd := exec.Command(bin, args...)
  419. cmd.Stdout = outFile
  420. cmd.Stderr = os.Stderr
  421. cmdLine := strings.Join(append([]string{bin}, args...), " ")
  422. startTime := time.Now()
  423. if err := cmd.Run(); err != nil {
  424. return fmt.Errorf("cannot run command for %q %q (%s): %s", suite.getDirectory(), test.inFile, cmdLine, err)
  425. }
  426. fmt.Printf("%s (%ds)\n", cmdLine, int(time.Since(startTime).Seconds()))
  427. if *android {
  428. exec.Command("adb", "shell", "rm", reqPathOnDevice).Run()
  429. }
  430. return nil
  431. }
  432. func canonicalizeLine(in string) string {
  433. if strings.HasPrefix(in, "Result = P (") {
  434. return "Result = P"
  435. }
  436. if strings.HasPrefix(in, "Result = F (") {
  437. return "Result = F"
  438. }
  439. return in
  440. }
  441. func compareFAX(suite *testSuite, test test) error {
  442. nextLineFunc := suite.nextLineFunc
  443. if nextLineFunc == nil {
  444. nextLineFunc = func(s *bufio.Scanner, state *nextLineState) (string, bool, bool) {
  445. if !s.Scan() {
  446. return "", false, false
  447. }
  448. return s.Text(), false, true
  449. }
  450. }
  451. respPath := filepath.Join(suite.getDirectory(), "resp", test.inFile+".rsp")
  452. respFile, err := os.Open(respPath)
  453. if err != nil {
  454. return fmt.Errorf("cannot read output of %q %q: %s", suite.getDirectory(), test.inFile, err)
  455. }
  456. defer respFile.Close()
  457. faxPath := filepath.Join(suite.getDirectory(), "fax", test.inFile+".fax")
  458. faxFile, err := os.Open(faxPath)
  459. if err != nil {
  460. return fmt.Errorf("cannot open fax file for %q %q: %s", suite.getDirectory(), test.inFile, err)
  461. }
  462. defer faxFile.Close()
  463. respScanner := bufio.NewScanner(respFile)
  464. faxScanner := bufio.NewScanner(faxFile)
  465. var nextLineState nextLineState
  466. lineNo := 0
  467. inHeader := true
  468. for respScanner.Scan() {
  469. lineNo++
  470. respLine := respScanner.Text()
  471. var faxLine string
  472. var isWildcard, ok bool
  473. if inHeader && (len(respLine) == 0 || respLine[0] == '#') {
  474. continue
  475. }
  476. for {
  477. haveFaxLine := false
  478. if inHeader {
  479. for {
  480. if faxLine, isWildcard, ok = nextLineFunc(faxScanner, &nextLineState); !ok {
  481. break
  482. }
  483. if len(faxLine) != 0 && faxLine[0] != '#' {
  484. haveFaxLine = true
  485. break
  486. }
  487. }
  488. inHeader = false
  489. } else {
  490. faxLine, isWildcard, haveFaxLine = nextLineFunc(faxScanner, &nextLineState)
  491. }
  492. if !haveFaxLine {
  493. // Ignore blank lines at the end of the generated file.
  494. if len(respLine) == 0 {
  495. break
  496. }
  497. return fmt.Errorf("resp file is longer than fax for %q %q", suite.getDirectory(), test.inFile)
  498. }
  499. if strings.HasPrefix(faxLine, " (Reason: ") {
  500. continue
  501. }
  502. break
  503. }
  504. if isWildcard || canonicalizeLine(faxLine) == canonicalizeLine(respLine) {
  505. continue
  506. }
  507. return fmt.Errorf("resp and fax differ at line %d for %q %q: %q vs %q", lineNo, suite.getDirectory(), test.inFile, respLine, faxLine)
  508. }
  509. if _, _, ok := nextLineFunc(faxScanner, &nextLineState); ok {
  510. return fmt.Errorf("fax file is longer than resp for %q %q", suite.getDirectory(), test.inFile)
  511. }
  512. return nil
  513. }