Adam Langley | d709b0d | 2019-11-05 11:37:22 -0800 | [diff] [blame] | 1 | // Copyright (c) 2019, Google Inc. |
| 2 | // |
| 3 | // Permission to use, copy, modify, and/or distribute this software for any |
| 4 | // purpose with or without fee is hereby granted, provided that the above |
| 5 | // copyright notice and this permission notice appear in all copies. |
| 6 | // |
| 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 14 | |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 15 | package subprocess |
| 16 | |
| 17 | import ( |
| 18 | "encoding/hex" |
| 19 | "encoding/json" |
| 20 | "fmt" |
| 21 | ) |
| 22 | |
| 23 | // The following structures reflect the JSON of ACVP hash tests. See |
Adam Langley | f0e5ea2 | 2021-05-10 13:04:58 -0700 | [diff] [blame] | 24 | // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-test-vectors |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 25 | |
| 26 | type hashTestVectorSet struct { |
| 27 | Groups []hashTestGroup `json:"testGroups"` |
| 28 | } |
| 29 | |
| 30 | type hashTestGroup struct { |
| 31 | ID uint64 `json:"tgId"` |
| 32 | Type string `json:"testType"` |
| 33 | Tests []struct { |
| 34 | ID uint64 `json:"tcId"` |
| 35 | BitLength uint64 `json:"len"` |
| 36 | MsgHex string `json:"msg"` |
| 37 | } `json:"tests"` |
| 38 | } |
| 39 | |
| 40 | type hashTestGroupResponse struct { |
| 41 | ID uint64 `json:"tgId"` |
| 42 | Tests []hashTestResponse `json:"tests"` |
| 43 | } |
| 44 | |
| 45 | type hashTestResponse struct { |
| 46 | ID uint64 `json:"tcId"` |
| 47 | DigestHex string `json:"md,omitempty"` |
| 48 | MCTResults []hashMCTResult `json:"resultsArray,omitempty"` |
| 49 | } |
| 50 | |
| 51 | type hashMCTResult struct { |
| 52 | DigestHex string `json:"md"` |
| 53 | } |
| 54 | |
| 55 | // hashPrimitive implements an ACVP algorithm by making requests to the |
| 56 | // subprocess to hash strings. |
| 57 | type hashPrimitive struct { |
| 58 | // algo is the ACVP name for this algorithm and also the command name |
| 59 | // given to the subprocess to hash with this hash function. |
| 60 | algo string |
| 61 | // size is the number of bytes of digest that the hash produces. |
| 62 | size int |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 63 | } |
| 64 | |
David Benjamin | 77b6f25 | 2023-05-02 10:14:11 -0400 | [diff] [blame] | 65 | func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (any, error) { |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 66 | var parsed hashTestVectorSet |
| 67 | if err := json.Unmarshal(vectorSet, &parsed); err != nil { |
| 68 | return nil, err |
| 69 | } |
| 70 | |
| 71 | var ret []hashTestGroupResponse |
| 72 | // See |
Adam Langley | f0e5ea2 | 2021-05-10 13:04:58 -0700 | [diff] [blame] | 73 | // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-test-vectors |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 74 | // for details about the tests. |
| 75 | for _, group := range parsed.Groups { |
| 76 | response := hashTestGroupResponse{ |
| 77 | ID: group.ID, |
| 78 | } |
| 79 | |
| 80 | for _, test := range group.Tests { |
| 81 | if uint64(len(test.MsgHex))*4 != test.BitLength { |
| 82 | return nil, fmt.Errorf("test case %d/%d contains hex message of length %d but specifies a bit length of %d", group.ID, test.ID, len(test.MsgHex), test.BitLength) |
| 83 | } |
| 84 | msg, err := hex.DecodeString(test.MsgHex) |
| 85 | if err != nil { |
| 86 | return nil, fmt.Errorf("failed to decode hex in test case %d/%d: %s", group.ID, test.ID, err) |
| 87 | } |
| 88 | |
| 89 | // http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-sha-00.html#rfc.section.3 |
| 90 | switch group.Type { |
| 91 | case "AFT": |
Adam Langley | e24491a | 2022-11-25 21:23:03 +0000 | [diff] [blame^] | 92 | m.TransactAsync(h.algo, 1, [][]byte{msg}, func(result [][]byte) error { |
| 93 | response.Tests = append(response.Tests, hashTestResponse{ |
| 94 | ID: test.ID, |
| 95 | DigestHex: hex.EncodeToString(result[0]), |
| 96 | }) |
| 97 | return nil |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 98 | }) |
| 99 | |
| 100 | case "MCT": |
| 101 | if len(msg) != h.size { |
| 102 | return nil, fmt.Errorf("MCT test case %d/%d contains message of length %d but the digest length is %d", group.ID, test.ID, len(msg), h.size) |
| 103 | } |
| 104 | |
| 105 | testResponse := hashTestResponse{ID: test.ID} |
| 106 | |
Adam Langley | 9fc6174 | 2021-05-06 12:15:07 -0700 | [diff] [blame] | 107 | digest := msg |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 108 | for i := 0; i < 100; i++ { |
Adam Langley | 9fc6174 | 2021-05-06 12:15:07 -0700 | [diff] [blame] | 109 | result, err := m.Transact(h.algo+"/MCT", 1, digest) |
| 110 | if err != nil { |
| 111 | panic(h.algo + " hash operation failed: " + err.Error()) |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Adam Langley | 9fc6174 | 2021-05-06 12:15:07 -0700 | [diff] [blame] | 114 | digest = result[0] |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 115 | testResponse.MCTResults = append(testResponse.MCTResults, hashMCTResult{hex.EncodeToString(digest)}) |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | response.Tests = append(response.Tests, testResponse) |
| 119 | |
| 120 | default: |
| 121 | return nil, fmt.Errorf("test group %d has unknown type %q", group.ID, group.Type) |
| 122 | } |
| 123 | } |
| 124 | |
Adam Langley | e24491a | 2022-11-25 21:23:03 +0000 | [diff] [blame^] | 125 | m.Barrier(func() { |
| 126 | ret = append(ret, response) |
| 127 | }) |
| 128 | } |
| 129 | |
| 130 | if err := m.Flush(); err != nil { |
| 131 | return nil, err |
Adam Langley | b7f0c1b | 2019-07-09 18:02:14 -0700 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | return ret, nil |
| 135 | } |