Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 1 | // Copyright (c) 2020, 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 | |
| 15 | package subprocess |
| 16 | |
| 17 | import ( |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 18 | "encoding/hex" |
| 19 | "encoding/json" |
| 20 | "fmt" |
| 21 | ) |
| 22 | |
| 23 | // The following structures reflect the JSON of CMAC-AES tests. See |
Adam Langley | f0e5ea2 | 2021-05-10 13:04:58 -0700 | [diff] [blame] | 24 | // https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#name-test-vectors |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 25 | |
| 26 | type keyedMACTestVectorSet struct { |
| 27 | Groups []keyedMACTestGroup `json:"testGroups"` |
| 28 | } |
| 29 | |
| 30 | type keyedMACTestGroup struct { |
| 31 | ID uint64 `json:"tgId"` |
| 32 | Type string `json:"testType"` |
| 33 | Direction string `json:"direction"` |
| 34 | MsgBits uint32 `json:"msgLen"` |
| 35 | KeyBits uint32 `json:"keyLen"` |
| 36 | MACBits uint32 `json:"macLen"` |
| 37 | Tests []struct { |
| 38 | ID uint64 `json:"tcId"` |
| 39 | KeyHex string `json:"key"` |
| 40 | MsgHex string `json:"message"` |
| 41 | MACHex string `json:"mac"` |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | type keyedMACTestGroupResponse struct { |
| 46 | ID uint64 `json:"tgId"` |
| 47 | Tests []keyedMACTestResponse `json:"tests"` |
| 48 | } |
| 49 | |
| 50 | type keyedMACTestResponse struct { |
| 51 | ID uint64 `json:"tcId"` |
| 52 | MACHex string `json:"mac,omitempty"` |
| 53 | Passed *bool `json:"testPassed,omitempty"` |
| 54 | } |
| 55 | |
| 56 | type keyedMACPrimitive struct { |
| 57 | algo string |
| 58 | } |
| 59 | |
David Benjamin | 77b6f25 | 2023-05-02 10:14:11 -0400 | [diff] [blame^] | 60 | func (k *keyedMACPrimitive) Process(vectorSet []byte, m Transactable) (any, error) { |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 61 | var vs keyedMACTestVectorSet |
| 62 | if err := json.Unmarshal(vectorSet, &vs); err != nil { |
| 63 | return nil, err |
| 64 | } |
| 65 | |
| 66 | var respGroups []keyedMACTestGroupResponse |
| 67 | for _, group := range vs.Groups { |
| 68 | respGroup := keyedMACTestGroupResponse{ID: group.ID} |
| 69 | |
| 70 | if group.KeyBits%8 != 0 { |
| 71 | return nil, fmt.Errorf("%d bit key in test group %d: fractional bytes not supported", group.KeyBits, group.ID) |
| 72 | } |
| 73 | if group.MsgBits%8 != 0 { |
| 74 | return nil, fmt.Errorf("%d bit message in test group %d: fractional bytes not supported", group.KeyBits, group.ID) |
| 75 | } |
| 76 | if group.MACBits%8 != 0 { |
| 77 | return nil, fmt.Errorf("%d bit MAC in test group %d: fractional bytes not supported", group.KeyBits, group.ID) |
| 78 | } |
| 79 | |
| 80 | var generate bool |
| 81 | switch group.Direction { |
| 82 | case "gen": |
| 83 | generate = true |
| 84 | case "ver": |
| 85 | generate = false |
| 86 | default: |
| 87 | return nil, fmt.Errorf("unknown test direction %q in test group %d", group.Direction, group.ID) |
| 88 | } |
| 89 | |
| 90 | outputBytes := uint32le(group.MACBits / 8) |
| 91 | |
| 92 | for _, test := range group.Tests { |
| 93 | respTest := keyedMACTestResponse{ID: test.ID} |
| 94 | |
| 95 | // Validate input. |
| 96 | if keyBits := uint32(len(test.KeyHex)) * 4; keyBits != group.KeyBits { |
| 97 | return nil, fmt.Errorf("test case %d/%d contains key of length %d bits, but expected %d-bit value", group.ID, test.ID, keyBits, group.KeyBits) |
| 98 | } |
| 99 | if msgBits := uint32(len(test.MsgHex)) * 4; msgBits != group.MsgBits { |
| 100 | return nil, fmt.Errorf("test case %d/%d contains message of length %d bits, but expected %d-bit value", group.ID, test.ID, msgBits, group.MsgBits) |
| 101 | } |
| 102 | |
| 103 | if generate { |
| 104 | if len(test.MACHex) != 0 { |
| 105 | return nil, fmt.Errorf("test case %d/%d contains MAC but should not", group.ID, test.ID) |
| 106 | } |
| 107 | } else { |
| 108 | if macBits := uint32(len(test.MACHex)) * 4; macBits != group.MACBits { |
| 109 | return nil, fmt.Errorf("test case %d/%d contains MAC of length %d bits, but expected %d-bit value", group.ID, test.ID, macBits, group.MACBits) |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | // Set up Transact parameters. |
| 114 | key, err := hex.DecodeString(test.KeyHex) |
| 115 | if err != nil { |
| 116 | return nil, fmt.Errorf("failed to decode KeyHex in test case %d/%d: %v", group.ID, test.ID, err) |
| 117 | } |
| 118 | |
| 119 | msg, err := hex.DecodeString(test.MsgHex) |
| 120 | if err != nil { |
| 121 | return nil, fmt.Errorf("failed to decode MsgHex in test case %d/%d: %v", group.ID, test.ID, err) |
| 122 | } |
| 123 | |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 124 | if generate { |
Adam Langley | 4a196cc | 2021-01-27 16:32:59 -0800 | [diff] [blame] | 125 | result, err := m.Transact(k.algo, 1, outputBytes, key, msg) |
| 126 | if err != nil { |
| 127 | return nil, fmt.Errorf("wrapper %s operation failed: %s", k.algo, err) |
| 128 | } |
| 129 | |
| 130 | calculatedMAC := result[0] |
| 131 | if len(calculatedMAC) != int(group.MACBits/8) { |
| 132 | return nil, fmt.Errorf("%s operation returned incorrect length value", k.algo) |
| 133 | } |
| 134 | |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 135 | respTest.MACHex = hex.EncodeToString(calculatedMAC) |
| 136 | } else { |
| 137 | expectedMAC, err := hex.DecodeString(test.MACHex) |
| 138 | if err != nil { |
| 139 | return nil, fmt.Errorf("failed to decode MACHex in test case %d/%d: %v", group.ID, test.ID, err) |
| 140 | } |
Adam Langley | 4a196cc | 2021-01-27 16:32:59 -0800 | [diff] [blame] | 141 | if 8*len(expectedMAC) != int(group.MACBits) { |
| 142 | return nil, fmt.Errorf("MACHex in test case %d/%d is %x, but should be %d bits", group.ID, test.ID, expectedMAC, group.MACBits) |
| 143 | } |
| 144 | |
| 145 | result, err := m.Transact(k.algo+"/verify", 1, key, msg, expectedMAC) |
| 146 | if err != nil { |
| 147 | return nil, fmt.Errorf("wrapper %s operation failed: %s", k.algo, err) |
| 148 | } |
| 149 | |
| 150 | if len(result[0]) != 1 || (result[0][0]&0xfe) != 0 { |
| 151 | return nil, fmt.Errorf("wrapper %s returned invalid success flag: %x", k.algo, result[0]) |
| 152 | } |
| 153 | |
| 154 | ok := result[0][0] == 1 |
Adam Langley | fb0c05c | 2020-07-01 13:23:55 -0700 | [diff] [blame] | 155 | respTest.Passed = &ok |
| 156 | } |
| 157 | |
| 158 | respGroup.Tests = append(respGroup.Tests, respTest) |
| 159 | } |
| 160 | |
| 161 | respGroups = append(respGroups, respGroup) |
| 162 | } |
| 163 | |
| 164 | return respGroups, nil |
| 165 | } |