• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
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 KDF tests. See
25// https://pages.nist.gov/ACVP/draft-celi-acvp-kdf-tls.html#name-test-vectors
26
27type kdfTestVectorSet struct {
28	Groups []kdfTestGroup `json:"testGroups"`
29}
30
31type kdfTestGroup struct {
32	ID uint64 `json:"tgId"`
33	// KDFMode can take the values "counter", "feedback", or
34	// "double pipeline iteration".
35	KDFMode         string `json:"kdfMode"`
36	MACMode         string `json:"macMode"`
37	CounterLocation string `json:"counterLocation"`
38	OutputBits      uint32 `json:"keyOutLength"`
39	CounterBits     uint32 `json:"counterLength"`
40	ZeroIV          bool   `json:"zeroLengthIv"`
41
42	Tests []struct {
43		ID       uint64 `json:"tcId"`
44		Key      string `json:"keyIn"`
45		Deferred bool   `json:"deferred"`
46	}
47}
48
49type kdfTestGroupResponse struct {
50	ID    uint64            `json:"tgId"`
51	Tests []kdfTestResponse `json:"tests"`
52}
53
54type kdfTestResponse struct {
55	ID        uint64 `json:"tcId"`
56	KeyIn     string `json:"keyIn,omitempty"`
57	FixedData string `json:"fixedData"`
58	KeyOut    string `json:"keyOut"`
59}
60
61type kdfPrimitive struct{}
62
63func (k *kdfPrimitive) Process(vectorSet []byte, m Transactable) (interface{}, error) {
64	var parsed kdfTestVectorSet
65	if err := json.Unmarshal(vectorSet, &parsed); err != nil {
66		return nil, err
67	}
68
69	var respGroups []kdfTestGroupResponse
70	for _, group := range parsed.Groups {
71		groupResp := kdfTestGroupResponse{ID: group.ID}
72
73		if group.OutputBits%8 != 0 {
74			return nil, fmt.Errorf("%d bit key in test group %d: fractional bytes not supported", group.OutputBits, group.ID)
75		}
76
77		if group.KDFMode != "counter" {
78			// feedback mode would need the IV to be handled.
79			// double-pipeline mode is not useful.
80			return nil, fmt.Errorf("KDF mode %q not supported", group.KDFMode)
81		}
82
83		switch group.CounterLocation {
84		case "after fixed data", "before fixed data":
85			break
86		default:
87			return nil, fmt.Errorf("Label location %q not supported", group.CounterLocation)
88		}
89
90		counterBits := uint32le(group.CounterBits)
91		outputBytes := uint32le(group.OutputBits / 8)
92
93		for _, test := range group.Tests {
94			testResp := kdfTestResponse{ID: test.ID}
95
96			var key []byte
97			if test.Deferred {
98				if len(test.Key) != 0 {
99					return nil, fmt.Errorf("key provided in deferred test case %d/%d", group.ID, test.ID)
100				}
101			} else {
102				var err error
103				if key, err = hex.DecodeString(test.Key); err != nil {
104					return nil, fmt.Errorf("failed to decode Key in test case %d/%d: %v", group.ID, test.ID, err)
105				}
106			}
107
108			// Make the call to the crypto module.
109			resp, err := m.Transact("KDF-counter", 3, outputBytes, []byte(group.MACMode), []byte(group.CounterLocation), key, counterBits)
110			if err != nil {
111				return nil, fmt.Errorf("wrapper KDF operation failed: %s", err)
112			}
113
114			// Parse results.
115			testResp.ID = test.ID
116			if test.Deferred {
117				testResp.KeyIn = hex.EncodeToString(resp[0])
118			}
119			testResp.FixedData = hex.EncodeToString(resp[1])
120			testResp.KeyOut = hex.EncodeToString(resp[2])
121
122			if !test.Deferred && !bytes.Equal(resp[0], key) {
123				return nil, fmt.Errorf("wrapper returned a different key for non-deferred KDF operation")
124			}
125
126			groupResp.Tests = append(groupResp.Tests, testResp)
127		}
128		respGroups = append(respGroups, groupResp)
129	}
130
131	return respGroups, nil
132}
133