• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 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	"bytes"
19	"encoding/hex"
20	"encoding/json"
21	"fmt"
22)
23
24// The following structures reflect the JSON of ACVP KAS KDF tests. See
25// https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-hkdf.html
26
27type hkdfTestVectorSet struct {
28	Groups []hkdfTestGroup `json:"testGroups"`
29}
30
31type hkdfTestGroup struct {
32	ID     uint64            `json:"tgId"`
33	Type   string            `json:"testType"` // AFT or VAL
34	Config hkdfConfiguration `json:"kdfConfiguration"`
35	Tests  []hkdfTest        `json:"tests"`
36}
37
38type hkdfTest struct {
39	ID          uint64         `json:"tcId"`
40	Params      hkdfParameters `json:"kdfParameter"`
41	PartyU      hkdfPartyInfo  `json:"fixedInfoPartyU"`
42	PartyV      hkdfPartyInfo  `json:"fixedInfoPartyV"`
43	ExpectedHex string         `json:"dkm"`
44}
45
46type hkdfConfiguration struct {
47	Type               string `json:"kdfType"`
48	OutputBits         uint32 `json:"l"`
49	HashName           string `json:"hmacAlg"`
50	FixedInfoPattern   string `json:"fixedInfoPattern"`
51	FixedInputEncoding string `json:"fixedInfoEncoding"`
52}
53
54func (c *hkdfConfiguration) extract() (outBytes uint32, hashName string, err error) {
55	if c.Type != "hkdf" ||
56		c.FixedInfoPattern != "uPartyInfo||vPartyInfo" ||
57		c.FixedInputEncoding != "concatenation" ||
58		c.OutputBits%8 != 0 {
59		return 0, "", fmt.Errorf("KDA not configured for HKDF: %#v", c)
60	}
61
62	return c.OutputBits / 8, c.HashName, nil
63}
64
65type hkdfParameters struct {
66	SaltHex string `json:"salt"`
67	KeyHex  string `json:"z"`
68}
69
70func (p *hkdfParameters) extract() (key, salt []byte, err error) {
71	salt, err = hex.DecodeString(p.SaltHex)
72	if err != nil {
73		return nil, nil, err
74	}
75
76	key, err = hex.DecodeString(p.KeyHex)
77	if err != nil {
78		return nil, nil, err
79	}
80
81	return key, salt, nil
82}
83
84type hkdfPartyInfo struct {
85	IDHex    string `json:"partyId"`
86	ExtraHex string `json:"ephemeralData"`
87}
88
89func (p *hkdfPartyInfo) data() ([]byte, error) {
90	ret, err := hex.DecodeString(p.IDHex)
91	if err != nil {
92		return nil, err
93	}
94
95	if len(p.ExtraHex) > 0 {
96		extra, err := hex.DecodeString(p.ExtraHex)
97		if err != nil {
98			return nil, err
99		}
100		ret = append(ret, extra...)
101	}
102
103	return ret, nil
104}
105
106type hkdfTestGroupResponse struct {
107	ID    uint64             `json:"tgId"`
108	Tests []hkdfTestResponse `json:"tests"`
109}
110
111type hkdfTestResponse struct {
112	ID     uint64 `json:"tcId"`
113	KeyOut string `json:"dkm,omitempty"`
114	Passed *bool  `json:"testPassed,omitempty"`
115}
116
117type hkdf struct{}
118
119func (k *hkdf) Process(vectorSet []byte, m Transactable) (any, error) {
120	var parsed hkdfTestVectorSet
121	if err := json.Unmarshal(vectorSet, &parsed); err != nil {
122		return nil, err
123	}
124
125	var respGroups []hkdfTestGroupResponse
126	for _, group := range parsed.Groups {
127		group := group
128		groupResp := hkdfTestGroupResponse{ID: group.ID}
129
130		var isValidationTest bool
131		switch group.Type {
132		case "VAL":
133			isValidationTest = true
134		case "AFT":
135			isValidationTest = false
136		default:
137			return nil, fmt.Errorf("unknown test type %q", group.Type)
138		}
139
140		outBytes, hashName, err := group.Config.extract()
141		if err != nil {
142			return nil, err
143		}
144
145		for _, test := range group.Tests {
146			test := test
147			testResp := hkdfTestResponse{ID: test.ID}
148
149			key, salt, err := test.Params.extract()
150			if err != nil {
151				return nil, err
152			}
153			uData, err := test.PartyU.data()
154			if err != nil {
155				return nil, err
156			}
157			vData, err := test.PartyV.data()
158			if err != nil {
159				return nil, err
160			}
161
162			var expected []byte
163			if isValidationTest {
164				expected, err = hex.DecodeString(test.ExpectedHex)
165				if err != nil {
166					return nil, err
167				}
168			}
169
170			info := make([]byte, 0, len(uData)+len(vData))
171			info = append(info, uData...)
172			info = append(info, vData...)
173
174			m.TransactAsync("HKDF/"+hashName, 1, [][]byte{key, salt, info, uint32le(outBytes)}, func(result [][]byte) error {
175				if len(result[0]) != int(outBytes) {
176					return fmt.Errorf("HKDF operation resulted in %d bytes but wanted %d", len(result[0]), outBytes)
177				}
178				if isValidationTest {
179					passed := bytes.Equal(expected, result[0])
180					testResp.Passed = &passed
181				} else {
182					testResp.KeyOut = hex.EncodeToString(result[0])
183				}
184
185				groupResp.Tests = append(groupResp.Tests, testResp)
186				return nil
187			})
188		}
189
190		m.Barrier(func() {
191			respGroups = append(respGroups, groupResp)
192		})
193	}
194
195	if err := m.Flush(); err != nil {
196		return nil, err
197	}
198
199	return respGroups, nil
200}
201