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