diff --git a/util/fipstools/acvp/acvptool/acvp.go b/util/fipstools/acvp/acvptool/acvp.go index 473c998148..8cdb89de49 100644 --- a/util/fipstools/acvp/acvptool/acvp.go +++ b/util/fipstools/acvp/acvptool/acvp.go @@ -50,6 +50,7 @@ var ( fetchFlag = flag.String("fetch", "", "Name of primitive to fetch vectors for") expectedOutFlag = flag.String("expected-out", "", "Name of a file to write the expected results to") wrapperPath = flag.String("wrapper", "../../../../build/util/fipstools/acvp/modulewrapper/modulewrapper", "Path to the wrapper binary") + waitForDebugger = flag.Bool("wait-for-debugger", false, "If true, jobs will run one at a time and pause for a debugger to attach") ) type Config struct { @@ -529,12 +530,21 @@ func uploadFromFile(file string, config *Config, sessionTokensCacheDir string) { func main() { flag.Parse() - middle, err := subprocess.New(*wrapperPath) + var args []string + if *waitForDebugger { + args = append(args, "--wait-for-debugger") + } + + middle, err := subprocess.New(*wrapperPath, args...) if err != nil { log.Fatalf("failed to initialise middle: %s", err) } defer middle.Close() + if *waitForDebugger { + log.Printf("attach to process %d to continue", middle.PID()) + } + configBytes, err := middle.Config() if err != nil { log.Fatalf("failed to get config from middle: %s", err) diff --git a/util/fipstools/acvp/acvptool/subprocess/aead.go b/util/fipstools/acvp/acvptool/subprocess/aead.go index 9b70d4f17e..bbc147fc41 100644 --- a/util/fipstools/acvp/acvptool/subprocess/aead.go +++ b/util/fipstools/acvp/acvptool/subprocess/aead.go @@ -92,14 +92,14 @@ func (a *aead) Process(vectorSet []byte, m Transactable) (interface{}, error) { // We automatically assume the IV is given (external) if the IV generation method is not defined. var external_iv bool = true if group.IvGen != "" { - switch group.IvGen { - case "external": - external_iv = true - case "internal": - external_iv = false - default: - return nil, fmt.Errorf("test group %d has unknown iv generation method %q", group.ID, group.IvGen) - } + switch group.IvGen { + case "external": + external_iv = true + case "internal": + external_iv = false + default: + return nil, fmt.Errorf("test group %d has unknown iv generation method %q", group.ID, group.IvGen) + } } op := a.algo + "/seal" @@ -198,21 +198,21 @@ func (a *aead) Process(vectorSet []byte, m Transactable) (interface{}, error) { testResp.CiphertextHex = &ciphertextHex } else { if external_iv { - ciphertext := result[0][:len(result[0])-tagBytes] - ciphertextHex := hex.EncodeToString(ciphertext) - testResp.CiphertextHex = &ciphertextHex - tag := result[0][len(result[0])-tagBytes:] - testResp.TagHex = hex.EncodeToString(tag) + ciphertext := result[0][:len(result[0])-tagBytes] + ciphertextHex := hex.EncodeToString(ciphertext) + testResp.CiphertextHex = &ciphertextHex + tag := result[0][len(result[0])-tagBytes:] + testResp.TagHex = hex.EncodeToString(tag) } else { - // internal IV length is always 12 bytes long - var ivBytes int = 12 - ciphertext := result[0][:len(result[0])-(tagBytes+ivBytes)] - ciphertextHex := hex.EncodeToString(ciphertext) - testResp.CiphertextHex = &ciphertextHex - tag := result[0][len(result[0])-(tagBytes+ivBytes):len(result[0])-ivBytes] - testResp.TagHex = hex.EncodeToString(tag) - iv := result[0][len(result[0])-ivBytes:] - testResp.IVHex = hex.EncodeToString(iv) + // internal IV length is always 12 bytes long + var ivBytes int = 12 + ciphertext := result[0][:len(result[0])-(tagBytes+ivBytes)] + ciphertextHex := hex.EncodeToString(ciphertext) + testResp.CiphertextHex = &ciphertextHex + tag := result[0][len(result[0])-(tagBytes+ivBytes) : len(result[0])-ivBytes] + testResp.TagHex = hex.EncodeToString(tag) + iv := result[0][len(result[0])-ivBytes:] + testResp.IVHex = hex.EncodeToString(iv) } } } else { diff --git a/util/fipstools/acvp/acvptool/subprocess/hkdf.go b/util/fipstools/acvp/acvptool/subprocess/hkdf.go index 35b58eab62..a28fb8989c 100644 --- a/util/fipstools/acvp/acvptool/subprocess/hkdf.go +++ b/util/fipstools/acvp/acvptool/subprocess/hkdf.go @@ -122,9 +122,9 @@ type hkdfTestResponse struct { Passed *bool `json:"testPassed,omitempty"` } -type hkdf struct{} +type kdaHkdfMode struct{} -func (k *hkdf) Process(vectorSet []byte, m Transactable) (interface{}, error) { +func (k *kdaHkdfMode) ProcessKDA(vectorSet []byte, m Transactable) (interface{}, error) { var parsed hkdfTestVectorSet if err := json.Unmarshal(vectorSet, &parsed); err != nil { return nil, err diff --git a/util/fipstools/acvp/acvptool/subprocess/kda.go b/util/fipstools/acvp/acvptool/subprocess/kda.go new file mode 100644 index 0000000000..0bd1bf64fb --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/kda.go @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC +package subprocess + +import ( + "encoding/json" + "fmt" +) + +type kdaPrimitive struct { + modes map[string]kdaModePrimitive +} + +type kdaModePrimitive interface { + ProcessKDA(vectorSet []byte, t Transactable) (interface{}, error) +} + +func (k *kdaPrimitive) Process(vectorSet []byte, t Transactable) (interface{}, error) { + var partial struct { + Mode string `json:"mode"` + } + + if err := json.Unmarshal(vectorSet, &partial); err != nil { + return nil, err + } + + prim, ok := k.modes[partial.Mode] + if !ok { + return nil, fmt.Errorf("unsupported KDA mode(%v)", partial.Mode) + } + + return prim.ProcessKDA(vectorSet, t) +} diff --git a/util/fipstools/acvp/acvptool/subprocess/kda_onestep.go b/util/fipstools/acvp/acvptool/subprocess/kda_onestep.go new file mode 100644 index 0000000000..7b3ba1da94 --- /dev/null +++ b/util/fipstools/acvp/acvptool/subprocess/kda_onestep.go @@ -0,0 +1,179 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +package subprocess + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" +) + +// Processes Vectors defined by https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-kdf-onestep.html +type kdaOneStepMode struct{} + +func (k *kdaOneStepMode) ProcessKDA(vectorSet []byte, m Transactable) (interface{}, error) { + var parsed kdaOneStepTestVectorSet + + if err := json.Unmarshal(vectorSet, &parsed); err != nil { + return nil, err + } + + var respGroups []kdaOneStepTestGroupResponse + for _, group := range parsed.Groups { + group := group + groupResp := kdaOneStepTestGroupResponse{ID: group.ID} + + // determine the test type + var isValidationTest bool + switch group.Type { + case "VAL": + isValidationTest = true + case "AFT": + isValidationTest = false + default: + return nil, fmt.Errorf("unknown test type %q", group.Type) + } + + // get the number of bytes to output and the auxillary function we're using + outBytes, auxFunctionName, auxFuncType, err := group.Configuration.extract() + if err != nil { + return nil, err + } + + for _, test := range group.Tests { + test := test + testResp := kdaOneStepTestCaseResponse{ID: test.ID} + + info := test.fixedInfoBytes() + + var args [][]byte + + args = append(args, test.KDFParameter.Z) + if auxFuncType == hmacAuxFunction { + args = append(args, test.KDFParameter.Salt) + } + args = append(args, info) + args = append(args, uint32le(outBytes)) + + resp, err := m.Transact("KDA/OneStep/"+auxFunctionName, 1, args...) + if err != nil { + return nil, fmt.Errorf("KDA_OneStep operation failed: %s", err) + } + + if isValidationTest { + passed := bytes.Equal(test.DerivedKeyMaterial, resp[0]) + testResp.Passed = &passed + } else { + testResp.DerivedKeyMaterial = resp[0] + } + + groupResp.Tests = append(groupResp.Tests, testResp) + } + respGroups = append(respGroups, groupResp) + + } + + return respGroups, nil +} + +type kdaOneStepTestVectorSet struct { + Groups []kdaOneStepTestGroup `json:"testGroups"` +} + +type kdaOneStepTestGroup struct { + ID uint64 `json:"tgId"` + Type string `json:"testType"` + Configuration kdaOneStepConfiguration `json:"kdfConfiguration"` + Tests []kdaOneStepTest `json:"tests"` +} + +type kdaOneStepConfiguration struct { + Type string `json:"kdfType"` + SaltMethod string `json:"saltMethod"` + FixedInfoPattern string `json:"fixedInfoPattern"` + FixedInfoEncoding string `json:"fixedInfoEncoding"` + AuxFunction string `json:"auxFunction"` + L uint32 `json:"l"` +} + +func (k *kdaOneStepConfiguration) extract() (outLen uint32, auxFunction string, auxFuncType auxFunctionType, err error) { + if k.Type != "oneStep" { + return 0, "", unknownAuxFunction, fmt.Errorf("unexpected kdfType: %v", k.Type) + } + + auxFuncType.setFromString(k.AuxFunction) + + if auxFuncType == unknownAuxFunction { + return 0, "", unknownAuxFunction, fmt.Errorf("unknown auxillary function: %v", k.AuxFunction) + } + + if k.FixedInfoPattern != "uPartyInfo||vPartyInfo" || k.FixedInfoEncoding != "concatenation" { + return 0, "", unknownAuxFunction, fmt.Errorf("unsupported FixedInfo construction, pattern(%v) with encoding(%v)", k.FixedInfoPattern, k.FixedInfoEncoding) + } + + return k.L / 8, k.AuxFunction, auxFuncType, nil +} + +type kdaOneStepTest struct { + ID uint64 `json:"tcId"` + KDFParameter struct { + Type string `json:"kdfType"` + Salt hexEncodedByteString `json:"salt,omitempty"` + Z hexEncodedByteString `json:"z"` + } `json:"kdfParameter"` + FixedInfoPartyU kdaOneStepFixedInfoParty `json:"fixedInfoPartyU"` + FixedInfoPartyV kdaOneStepFixedInfoParty `json:"fixedInfoPartyV"` + DerivedKeyMaterial hexEncodedByteString `json:"dkm,omitempty"` +} + +func (k *kdaOneStepTest) fixedInfoBytes() []byte { + uBytes := k.FixedInfoPartyU.concatenatedBytes() + vBytes := k.FixedInfoPartyV.concatenatedBytes() + v := make([]byte, 0, len(uBytes)+len(vBytes)) + v = append(v, uBytes...) + v = append(v, vBytes...) + return v +} + +type kdaOneStepFixedInfoParty struct { + PartyID hexEncodedByteString `json:"partyId"` + EphemeralData hexEncodedByteString `json:"ephemeralData"` +} + +func (k *kdaOneStepFixedInfoParty) concatenatedBytes() []byte { + v := make([]byte, 0, len(k.PartyID)+len(k.EphemeralData)) + v = append(v, k.PartyID...) + v = append(v, k.EphemeralData...) + return v +} + +type kdaOneStepTestGroupResponse struct { + ID uint64 `json:"tgId"` + Tests []kdaOneStepTestCaseResponse `json:"tests"` +} + +type kdaOneStepTestCaseResponse struct { + ID uint64 `json:"tcId"` + Passed *bool `json:"testPassed,omitempty"` + DerivedKeyMaterial hexEncodedByteString `json:"dkm,omitempty"` +} + +type auxFunctionType uint + +func (a *auxFunctionType) setFromString(v string) { + if strings.HasPrefix(v, "HMAC-") { + *a = hmacAuxFunction + } else if strings.HasPrefix(v, "SHA-") || strings.HasPrefix(v, "SHA2-") || strings.HasPrefix(v, "SHA3-") { + *a = digestAuxFunction + } else { + *a = unknownAuxFunction + } +} + +const ( + unknownAuxFunction auxFunctionType = iota + digestAuxFunction + hmacAuxFunction +) diff --git a/util/fipstools/acvp/acvptool/subprocess/rsa.go b/util/fipstools/acvp/acvptool/subprocess/rsa.go index 8cd83fd812..24b776a15b 100644 --- a/util/fipstools/acvp/acvptool/subprocess/rsa.go +++ b/util/fipstools/acvp/acvptool/subprocess/rsa.go @@ -126,7 +126,7 @@ func processKeyGen(vectorSet []byte, m Transactable) (interface{}, error) { var ret []rsaKeyGenTestGroupResponse for _, group := range parsed.Groups { - group := group + group := group // We support both GDT and AFT tests, which are formatted the same and expect the same output. if !(group.Type == "GDT" || group.Type == "AFT") { return nil, fmt.Errorf("RSA KeyGen test group has type %q, but only GDT and AFT tests are supported", group.Type) @@ -137,7 +137,7 @@ func processKeyGen(vectorSet []byte, m Transactable) (interface{}, error) { } for _, test := range group.Tests { - test := test + test := test results, err := m.Transact("RSA/keyGen", 5, uint32le(group.ModulusBits)) if err != nil { return nil, err @@ -289,7 +289,7 @@ func processSigVer(vectorSet []byte, m Transactable) (interface{}, error) { type rsa struct{} -func (*rsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { +func (r *rsa) Process(vectorSet []byte, m Transactable) (interface{}, error) { var parsed rsaTestVectorSet if err := json.Unmarshal(vectorSet, &parsed); err != nil { return nil, err diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index 0cdea21371..b655b4a4ec 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -18,12 +18,14 @@ package subprocess import ( "encoding/binary" + "encoding/hex" "encoding/json" "errors" "fmt" "io" "os" "os/exec" + "strings" ) // Transactable provides an interface to allow test injection of transactions @@ -63,8 +65,8 @@ type pendingRead struct { } // New returns a new Subprocess middle layer that runs the given binary. -func New(path string) (*Subprocess, error) { - cmd := exec.Command(path) +func New(path string, arg ...string) (*Subprocess, error) { + cmd := exec.Command(path, arg...) cmd.Stderr = os.Stderr stdin, err := cmd.StdinPipe() if err != nil { @@ -137,15 +139,20 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess "ctrDRBG": &drbg{"ctrDRBG", map[string]bool{"AES-128": true, "AES-192": true, "AES-256": true}}, "hmacDRBG": &drbg{"hmacDRBG", map[string]bool{"SHA-1": true, "SHA2-224": true, "SHA2-256": true, "SHA2-384": true, "SHA2-512": true}}, "KDF": &kdfPrimitive{}, - "KDA": &hkdf{}, - "TLS-v1.3": &tls13{}, - "CMAC-AES": &keyedMACPrimitive{"CMAC-AES"}, - "RSA": &rsa{}, - "kdf-components": &kdfComp{"kdf-components"}, - "TLS-v1.2": &kdfComp{"TLS-v1.2"}, - "KAS-ECC-SSC": &kas{}, - "KAS-FFC-SSC": &kasDH{}, - "PBKDF": &pbkdf{}, + "KDA": &kdaPrimitive{ + modes: map[string]kdaModePrimitive{ + "HKDF": &kdaHkdfMode{}, + "OneStep": &kdaOneStepMode{}, + }, + }, + "TLS-v1.3": &tls13{}, + "CMAC-AES": &keyedMACPrimitive{"CMAC-AES"}, + "RSA": &rsa{}, + "kdf-components": &kdfComp{"kdf-components"}, + "TLS-v1.2": &kdfComp{"TLS-v1.2"}, + "KAS-ECC-SSC": &kas{}, + "KAS-FFC-SSC": &kasDH{}, + "PBKDF": &pbkdf{}, } m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives} @@ -201,6 +208,10 @@ func (m *Subprocess) enqueueRead(pending pendingRead) error { return nil } +func (m *Subprocess) PID() int { + return m.cmd.Process.Pid +} + // TransactAsync performs a single request--response pair with the subprocess. // The callback will run at some future point, in a separate goroutine. All // callbacks will, however, be run in the order that TransactAsync was called. @@ -394,3 +405,39 @@ func uint32le(n uint32) []byte { binary.LittleEndian.PutUint32(ret[:], n) return ret[:] } + +type hexEncodedByteString []byte + +func (h *hexEncodedByteString) MarshalJSON() ([]byte, error) { + if h == nil || *h == nil { + return []byte("null"), nil + } + hexStr := strings.ToUpper(hex.EncodeToString(*h)) + return json.Marshal(hexStr) +} + +func (h *hexEncodedByteString) UnmarshalJSON(jsonBytes []byte) error { + var jsonValue interface{} + if err := json.Unmarshal(jsonBytes, &jsonValue); err != nil { + return err + } + + switch v := jsonValue.(type) { + case string: + if len(v) == 0 { + *h = nil + return nil + } + bv, err := hex.DecodeString(v) + if err != nil { + return err + } + *h = bv + case nil: + *h = nil + default: + return fmt.Errorf("HexEncodedBytes doesn't support json type: %T", jsonValue) + } + + return nil +} diff --git a/util/fipstools/acvp/acvptool/subprocess/tls13.go b/util/fipstools/acvp/acvptool/subprocess/tls13.go index 6cbfc04701..1bd9df80c7 100644 --- a/util/fipstools/acvp/acvptool/subprocess/tls13.go +++ b/util/fipstools/acvp/acvptool/subprocess/tls13.go @@ -239,4 +239,4 @@ func concat(slices ...[]byte) []byte { ret = append(ret, slice...) } return ret -} \ No newline at end of file +} diff --git a/util/fipstools/acvp/acvptool/test/expected/KDA-OneStep.bz2 b/util/fipstools/acvp/acvptool/test/expected/KDA-OneStep.bz2 new file mode 100644 index 0000000000..fb1454bf3c Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/expected/KDA-OneStep.bz2 differ diff --git a/util/fipstools/acvp/acvptool/test/tests.json b/util/fipstools/acvp/acvptool/test/tests.json index 262c36593c..6aa28a1d70 100644 --- a/util/fipstools/acvp/acvptool/test/tests.json +++ b/util/fipstools/acvp/acvptool/test/tests.json @@ -30,5 +30,6 @@ {"Wrapper": "modulewrapper", "In": "vectors/RSA-SigGen.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/TLS-1.2-KDF.bz2", "Out": "expected/TLS-1.2-KDF.bz2"}, {"Wrapper": "modulewrapper", "In": "vectors/PBKDF.bz2", "Out": "expected/PBKDF.bz2"}, -{"Wrapper": "modulewrapper", "In": "vectors/KDA-HKDF.bz2", "Out": "expected/KDA-HKDF.bz2"} +{"Wrapper": "modulewrapper", "In": "vectors/KDA-HKDF.bz2", "Out": "expected/KDA-HKDF.bz2"}, +{"Wrapper": "modulewrapper", "In": "vectors/KDA-OneStep.bz2", "Out": "expected/KDA-OneStep.bz2"} ] diff --git a/util/fipstools/acvp/acvptool/test/vectors/KDA-OneStep.bz2 b/util/fipstools/acvp/acvptool/test/vectors/KDA-OneStep.bz2 new file mode 100644 index 0000000000..2da9d9fce3 Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/vectors/KDA-OneStep.bz2 differ diff --git a/util/fipstools/acvp/modulewrapper/main.cc b/util/fipstools/acvp/modulewrapper/main.cc index d7f3053336..4b832cd89f 100644 --- a/util/fipstools/acvp/modulewrapper/main.cc +++ b/util/fipstools/acvp/modulewrapper/main.cc @@ -12,21 +12,23 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include -#include #if defined(_MSC_VER) -#include -#include #include +#include +#include #endif #include #include +#ifndef OPENSSL_WINDOWS +#include +#endif #include "modulewrapper.h" - int main(int argc, char **argv) { if (argc == 2 && strcmp(argv[1], "--version") == 0) { printf("Built for architecture: "); @@ -51,18 +53,27 @@ int main(int argc, char **argv) { CRYPTO_has_asm() ? "yes" : "no"); return 0; + } else if (argc == 2 && strcmp(argv[1], "--wait-for-debugger") == 0) { +#if defined(OPENSSL_WINDOWS) + fprintf(stderr, "-wait-for-debugger is not supported on Windows.\n"); + return 1; +#else + // The debugger will resume the process. + raise(SIGSTOP); +#endif } else if (argc != 1) { - fprintf(stderr, "Usage: %s [--version]\n", argv[0]); + fprintf(stderr, "Usage: %s [--version | --wait-for-debugger]\n", argv[0]); return 4; } #if defined(_MSC_VER) - if (_setmode( _fileno( stdin ), _O_BINARY ) < 0 || _setmode( _fileno( stdout ), _O_BINARY ) < 0) { - fprintf(stderr, "Setting binary mode to stdin/stdout failed.\n"); - return 4; + if (_setmode(_fileno(stdin), _O_BINARY) < 0 || + _setmode(_fileno(stdout), _O_BINARY) < 0) { + fprintf(stderr, "Setting binary mode to stdin/stdout failed.\n"); + return 4; } #endif - + std::unique_ptr buffer = bssl::acvp::RequestBuffer::New(); const bssl::acvp::ReplyCallback write_reply = std::bind( diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 2834651454..6fed8afc66 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include #include #include @@ -35,23 +35,23 @@ #include #include #include -#include #include #include #include #include +#include +#include #include +#include #include #include #include #include -#include #include -#include #include "../../../../crypto/fipsmodule/ec/internal.h" -#include "../../../../crypto/fipsmodule/rand/internal.h" #include "../../../../crypto/fipsmodule/hmac/internal.h" +#include "../../../../crypto/fipsmodule/rand/internal.h" #include "modulewrapper.h" @@ -95,7 +95,7 @@ static bool ReadAll(std::istream *stream, void *in_data, size_t data_len) { } Span> ParseArgsFromStream(std::istream *stream, - RequestBuffer *in_buffer) { + RequestBuffer *in_buffer) { RequestBufferImpl *buffer = static_cast(in_buffer); uint32_t nums[1 + kMaxArgs]; const Span> empty_span; @@ -161,7 +161,8 @@ Span> ParseArgsFromStream(std::istream *stream, return Span>(buffer->args, num_args); } -bool WriteReplyToStream(std::ostream *stream, const std::vector> &spans) { +bool WriteReplyToStream(std::ostream *stream, + const std::vector> &spans) { if (spans.empty() || spans.size() > kMaxArgs) { abort(); } @@ -169,23 +170,26 @@ bool WriteReplyToStream(std::ostream *stream, const std::vectorwrite(reinterpret_cast(nums), sizeof(uint32_t) * (1 + spans.size())); + stream->write(reinterpret_cast(nums), + sizeof(uint32_t) * (1 + spans.size())); for (size_t i = 0; i < spans.size(); i++) { const auto &span = spans[i]; if (span.empty()) { continue; } - stream->write(reinterpret_cast(span.data()), sizeof(uint8_t) * span.size()); + stream->write(reinterpret_cast(span.data()), + sizeof(uint8_t) * span.size()); } stream->flush(); return true; } -static bool GetConfig(const Span args[], ReplyCallback write_reply) { +static bool GetConfig(const Span args[], + ReplyCallback write_reply) { static constexpr char kConfig[] = R"([ { @@ -610,7 +614,7 @@ static bool GetConfig(const Span args[], ReplyCallback write_repl ] }] },)" - R"({ + R"({ "algorithm": "RSA", "mode": "keyGen", "revision": "FIPS186-4", @@ -1121,6 +1125,36 @@ static bool GetConfig(const Span args[], ReplyCallback write_repl "FB", "FC" ] + }, + { + "algorithm": "KDA", + "mode": "OneStep", + "revision": "Sp800-56Cr2", + "prereqVals": [], + "auxFunctions": [ + {"auxFunctionName": "SHA-1"}, + {"auxFunctionName": "SHA2-224"}, + {"auxFunctionName": "SHA2-256"}, + {"auxFunctionName": "SHA2-384"}, + {"auxFunctionName": "SHA2-512"}, + {"auxFunctionName": "SHA2-512/224"}, + {"auxFunctionName": "SHA2-512/256"}, + {"auxFunctionName": "SHA3-224"}, + {"auxFunctionName": "SHA3-256"}, + {"auxFunctionName": "SHA3-384"}, + {"auxFunctionName": "SHA3-512"}, + {"auxFunctionName": "HMAC-SHA-1", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-224", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-256", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-384", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-512", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-512/224", "macSaltMethods": ["default", "random"]}, + {"auxFunctionName": "HMAC-SHA2-512/256", "macSaltMethods": ["default", "random"]} + ], + "fixedInfoPattern": "uPartyInfo||vPartyInfo", + "encoding": ["concatenation"], + "z": [{"min": 224, "max": 8192, "increment": 8}], + "l": 2048 } ])"; return write_reply({Span( @@ -1136,7 +1170,8 @@ static bool Hash(const Span args[], ReplyCallback write_reply) { } template -static bool HashSha3(const Span args[], ReplyCallback write_reply) { +static bool HashSha3(const Span args[], + ReplyCallback write_reply) { uint8_t digest[DigestLength]; const EVP_MD *md = MDFunc(); unsigned int md_out_size = DigestLength; @@ -1147,7 +1182,8 @@ static bool HashSha3(const Span args[], ReplyCallback write_reply } template -static bool HashXof(const Span args[], ReplyCallback write_reply) { +static bool HashXof(const Span args[], + ReplyCallback write_reply) { // NOTE: Max outLen supported by ACVP is 65536 bits (8192 bytes). If that // changes, we'll need to use a bigger stack-allocated array size here. // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-capabilities-registration @@ -1189,7 +1225,7 @@ static bool HashMCT(const Span args[], template static bool HashMCTSha3(const Span args[], - ReplyCallback write_reply) { + ReplyCallback write_reply) { if (args[0].size() != DigestLength) { return false; } @@ -1204,22 +1240,22 @@ static bool HashMCTSha3(const Span args[], memcpy(md[0], args[0].data(), DigestLength); for (size_t i = 1; i <= 1000; i++) { - memcpy(msg[i], md[i-1], DigestLength); + memcpy(msg[i], md[i - 1], DigestLength); EVP_Digest(msg[i], sizeof(msg[i]), md[i], &md_out_size, evp_md, NULL); } - return write_reply( - {Span(md[1000])}); + return write_reply({Span(md[1000])}); } template -static bool HashMCTXof(const Span args[], ReplyCallback write_reply) { - const uint8_t* max_outlen_bytes = args[1].data(); - const uint8_t* min_outlen_bytes = args[2].data(); - const uint8_t* outlen_bytes = args[3].data(); - - // The various output lens are passed to modulewrapper as a length-4 byte array representing - // a little-endian unsigned 32-bit integer. +static bool HashMCTXof(const Span args[], + ReplyCallback write_reply) { + const uint8_t *max_outlen_bytes = args[1].data(); + const uint8_t *min_outlen_bytes = args[2].data(); + const uint8_t *outlen_bytes = args[3].data(); + + // The various output lens are passed to modulewrapper as a length-4 byte + // array representing a little-endian unsigned 32-bit integer. uint32_t min_output_len = CRYPTO_load_u32_le(min_outlen_bytes); uint32_t max_output_len = CRYPTO_load_u32_le(max_outlen_bytes); uint32_t output_len = CRYPTO_load_u32_le(outlen_bytes); @@ -1242,30 +1278,34 @@ static bool HashMCTXof(const Span args[], ReplyCallback write_rep for (size_t i = 1; i < array_len; i++) { md[i].resize(output_len); - size_t msg_size = std::min(md[i-1].size(), 16); - memcpy(msg[i].data(), md[i-1].data(), msg_size); + size_t msg_size = std::min(md[i - 1].size(), 16); + memcpy(msg[i].data(), md[i - 1].data(), msg_size); - EVP_Digest(msg[i].data(), msg[i].size(), md[i].data(), &output_len, MDFunc(), NULL); + EVP_Digest(msg[i].data(), msg[i].size(), md[i].data(), &output_len, + MDFunc(), NULL); - uint16_t rightmost_output_bits = (md[i][output_len - 2] << 8) | md[i][output_len - 1]; + uint16_t rightmost_output_bits = + (md[i][output_len - 2] << 8) | md[i][output_len - 1]; output_len = min_output_len + (rightmost_output_bits % range); } - // We're sending the new output len back to the ACVP tool as a length-4 byte array representing - // a little-endian unsigned 32-bit integer as well. + // We're sending the new output len back to the ACVP tool as a length-4 byte + // array representing a little-endian unsigned 32-bit integer as well. uint8_t new_outlen_bytes[4]; CRYPTO_store_u32_le(new_outlen_bytes, output_len); - return write_reply({Span(md[1000]), Span(new_outlen_bytes)}); + return write_reply( + {Span(md[1000]), Span(new_outlen_bytes)}); } // The following logic conforms to the Large Data Tests described in // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-large-data-tests-for-sha-1- // Which are the same for SHA-1, SHA2, and SHA3 -static unsigned char* BuildLDTMessage(const bssl::Span part_msg, int times) { +static unsigned char *BuildLDTMessage(const bssl::Span part_msg, + int times) { size_t full_msg_size = part_msg.size() * times; - unsigned char* full_msg = (unsigned char*) malloc (full_msg_size); - for(int i = 0; i < times; i++) { + unsigned char *full_msg = (unsigned char *)malloc(full_msg_size); + for (int i = 0; i < times; i++) { memcpy(full_msg + i * part_msg.size(), part_msg.data(), part_msg.size()); } @@ -1274,7 +1314,8 @@ static unsigned char* BuildLDTMessage(const bssl::Span part_msg, template -static bool HashLDT(const Span args[], ReplyCallback write_reply) { +static bool HashLDT(const Span args[], + ReplyCallback write_reply) { uint8_t digest[DigestLength]; int times; memcpy(×, args[1].data(), sizeof(int)); @@ -1287,7 +1328,8 @@ static bool HashLDT(const Span args[], ReplyCallback write_reply) } template -static bool HashLDTSha3(const Span args[], ReplyCallback write_reply) { +static bool HashLDTSha3(const Span args[], + ReplyCallback write_reply) { uint8_t digest[DigestLength]; const EVP_MD *md = MDFunc(); unsigned int md_out_size = DigestLength; @@ -1316,7 +1358,7 @@ static uint32_t GetIterations(const Span iterations_bytes) { memcpy(&iterations, iterations_bytes.data(), sizeof(iterations)); if (iterations == 0 || iterations == UINT32_MAX) { LOG_ERROR("Invalid number of iterations: %x.\n", - static_cast(iterations)); + static_cast(iterations)); abort(); } @@ -1352,7 +1394,8 @@ static bool AES(const Span args[], ReplyCallback write_reply) { } template -static bool AES_XTS(const Span args[], ReplyCallback write_reply) { +static bool AES_XTS(const Span args[], + ReplyCallback write_reply) { const EVP_CIPHER *cipher = EVP_aes_256_xts(); std::vector key(args[0].begin(), args[0].end()); @@ -1364,24 +1407,25 @@ static bool AES_XTS(const Span args[], ReplyCallback write_reply) bssl::ScopedEVP_CIPHER_CTX ctx; int len; - + ctx.Reset(); if (Encrypt) { - if(!EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(), iv.data())) { + if (!EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(), + iv.data())) { LOG_ERROR("Failed XTS encrypt setup"); return false; } - if(!EVP_EncryptUpdate(ctx.get(), out.data(), &len, in.data(), in.size())) { + if (!EVP_EncryptUpdate(ctx.get(), out.data(), &len, in.data(), in.size())) { LOG_ERROR("Failed XTS encrypt"); return false; } - } - else { - if(!EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(), iv.data())) { + } else { + if (!EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(), + iv.data())) { LOG_ERROR("Failed XTS decrypt setup"); return false; } - if(!EVP_DecryptUpdate(ctx.get(), out.data(), &len, in.data(), in.size())) { + if (!EVP_DecryptUpdate(ctx.get(), out.data(), &len, in.data(), in.size())) { LOG_ERROR("Failed XTS decrypt"); return false; } @@ -1392,7 +1436,8 @@ static bool AES_XTS(const Span args[], ReplyCallback write_reply) template -static bool AES_CBC(const Span args[], ReplyCallback write_reply) { +static bool AES_CBC(const Span args[], + ReplyCallback write_reply) { AES_KEY key; if (SetKey(args[0].data(), args[0].size() * 8, &key) != 0) { return false; @@ -1439,7 +1484,8 @@ static bool AES_CBC(const Span args[], ReplyCallback write_reply) {Span(result), Span(prev_result)}); } -static bool AES_CTR(const Span args[], ReplyCallback write_reply) { +static bool AES_CTR(const Span args[], + ReplyCallback write_reply) { static const uint32_t kOneIteration = 1; if (args[3].size() != sizeof(kOneIteration) || memcmp(args[3].data(), &kOneIteration, sizeof(kOneIteration))) { @@ -1481,7 +1527,7 @@ static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span tag_len_span, memcpy(&tag_len_32, tag_len_span.data(), sizeof(tag_len_32)); const EVP_AEAD *aead; - if(nonce.empty()) { + if (nonce.empty()) { // Internally generated IVs switch (key.size()) { case 16: @@ -1498,8 +1544,8 @@ static bool AESGCMSetup(EVP_AEAD_CTX *ctx, Span tag_len_span, // The 12-byte nonce is appended to the tag and is generated internally for // random nonce function. Thus, the "tag" must be extended by 12 bytes // for the purpose of the API. - if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), tag_len_32 + AES_GCM_NONCE_LENGTH, - nullptr)) { + if (!EVP_AEAD_CTX_init(ctx, aead, key.data(), key.size(), + tag_len_32 + AES_GCM_NONCE_LENGTH, nullptr)) { LOG_ERROR("Failed to setup AES-GCM with tag length %u\n", static_cast(tag_len_32)); return false; @@ -1578,7 +1624,8 @@ static bool AESCCMSetup(EVP_AEAD_CTX *ctx, Span tag_len_span, template tag_len_span, Span key, Span nonce)> -static bool AEADSeal(const Span args[], ReplyCallback write_reply) { +static bool AEADSeal(const Span args[], + ReplyCallback write_reply) { Span tag_len_span = args[0]; Span key = args[1]; Span plaintext = args[2]; @@ -1596,11 +1643,12 @@ static bool AEADSeal(const Span args[], ReplyCallback write_reply std::vector out(EVP_AEAD_MAX_OVERHEAD + plaintext.size()); size_t out_len; - if(nonce.empty()) { - // The nonce parameter when using Internal IV generation must be zero-length. - if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), - nullptr, 0, plaintext.data(), - plaintext.size(), ad.data(), ad.size())) { + if (nonce.empty()) { + // The nonce parameter when using Internal IV generation must be + // zero-length. + if (!EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), nullptr, + 0, plaintext.data(), plaintext.size(), ad.data(), + ad.size())) { return false; } } else { @@ -1618,7 +1666,8 @@ static bool AEADSeal(const Span args[], ReplyCallback write_reply template tag_len_span, Span key, Span nonce)> -static bool AEADOpen(const Span args[], ReplyCallback write_reply) { +static bool AEADOpen(const Span args[], + ReplyCallback write_reply) { Span tag_len_span = args[0]; Span key = args[1]; Span ciphertext = args[2]; @@ -1673,7 +1722,8 @@ static bool AESKeyWrapSetup(AES_KEY *out, bool decrypt, Span key, return true; } -static bool AESKeyWrapSeal(const Span args[], ReplyCallback write_reply) { +static bool AESKeyWrapSeal(const Span args[], + ReplyCallback write_reply) { Span key = args[1]; Span plaintext = args[2]; @@ -1693,7 +1743,8 @@ static bool AESKeyWrapSeal(const Span args[], ReplyCallback write return write_reply({Span(out)}); } -static bool AESKeyWrapOpen(const Span args[], ReplyCallback write_reply) { +static bool AESKeyWrapOpen(const Span args[], + ReplyCallback write_reply) { Span key = args[1]; Span ciphertext = args[2]; @@ -1716,7 +1767,8 @@ static bool AESKeyWrapOpen(const Span args[], ReplyCallback write {Span(success_flag), Span(out)}); } -static bool AESPaddedKeyWrapSeal(const Span args[], ReplyCallback write_reply) { +static bool AESPaddedKeyWrapSeal(const Span args[], + ReplyCallback write_reply) { Span key = args[1]; Span plaintext = args[2]; @@ -1738,7 +1790,8 @@ static bool AESPaddedKeyWrapSeal(const Span args[], ReplyCallback return write_reply({Span(out)}); } -static bool AESPaddedKeyWrapOpen(const Span args[], ReplyCallback write_reply) { +static bool AESPaddedKeyWrapOpen(const Span args[], + ReplyCallback write_reply) { Span key = args[1]; Span ciphertext = args[2]; @@ -1810,7 +1863,8 @@ static bool TDES(const Span args[], ReplyCallback write_reply) { } template -static bool TDES_CBC(const Span args[], ReplyCallback write_reply) { +static bool TDES_CBC(const Span args[], + ReplyCallback write_reply) { const EVP_CIPHER *cipher = EVP_des_ede3_cbc(); if (args[0].size() != 24) { @@ -1871,8 +1925,8 @@ static bool TDES_CBC(const Span args[], ReplyCallback write_reply } return write_reply({Span(result), - Span(prev_result), - Span(prev_prev_result)}); + Span(prev_result), + Span(prev_prev_result)}); } template @@ -2004,7 +2058,8 @@ static std::pair, std::vector> GetPublicKeyBytes( return std::make_pair(std::move(x_bytes), std::move(y_bytes)); } -static bool ECDSAKeyGen(const Span args[], ReplyCallback write_reply) { +static bool ECDSAKeyGen(const Span args[], + ReplyCallback write_reply) { bssl::UniquePtr key = ECKeyFromName(args[0]); if (!key || !EC_KEY_generate_key_fips(key.get())) { return false; @@ -2025,7 +2080,8 @@ static bssl::UniquePtr BytesToBIGNUM(Span bytes) { return bn; } -static bool ECDSAKeyVer(const Span args[], ReplyCallback write_reply) { +static bool ECDSAKeyVer(const Span args[], + ReplyCallback write_reply) { bssl::UniquePtr key = ECKeyFromName(args[0]); if (!key) { return false; @@ -2064,16 +2120,17 @@ static const EVP_MD *HashFromName(Span name) { return EVP_sha512_224(); } else if (StringEq(name, "SHA2-512/256")) { return EVP_sha512_256(); - } else if (StringEq(name, "SHAKE-128")) { + } else if (StringEq(name, "SHAKE-128")) { return EVP_shake128(); - } else if (StringEq(name, "SHAKE-256")) { + } else if (StringEq(name, "SHAKE-256")) { return EVP_shake256(); } else { return nullptr; } } -static bool ECDSASigGen(const Span args[], ReplyCallback write_reply) { +static bool ECDSASigGen(const Span args[], + ReplyCallback write_reply) { bssl::UniquePtr key = ECKeyFromName(args[0]); bssl::UniquePtr d = BytesToBIGNUM(args[1]); const EVP_MD *hash = HashFromName(args[2]); @@ -2094,7 +2151,8 @@ static bool ECDSASigGen(const Span args[], ReplyCallback write_re return false; } sig_der.resize(len); - if (!EVP_DigestSign(ctx.get(), sig_der.data(), &len, msg.data(), msg.size())) { + if (!EVP_DigestSign(ctx.get(), sig_der.data(), &len, msg.data(), + msg.size())) { return false; } bssl::UniquePtr sig(ECDSA_SIG_from_bytes(sig_der.data(), len)); @@ -2109,7 +2167,8 @@ static bool ECDSASigGen(const Span args[], ReplyCallback write_re {Span(r_bytes), Span(s_bytes)}); } -static bool ECDSASigVer(const Span args[], ReplyCallback write_reply) { +static bool ECDSASigVer(const Span args[], + ReplyCallback write_reply) { bssl::UniquePtr key = ECKeyFromName(args[0]); const EVP_MD *hash = HashFromName(args[1]); auto msg = args[2]; @@ -2153,7 +2212,8 @@ static bool ECDSASigVer(const Span args[], ReplyCallback write_re return write_reply({Span(reply)}); } -static bool CMAC_AES(const Span args[], ReplyCallback write_reply) { +static bool CMAC_AES(const Span args[], + ReplyCallback write_reply) { uint8_t mac[16]; if (!AES_CMAC(mac, args[1].data(), args[1].size(), args[2].data(), args[2].size())) { @@ -2172,7 +2232,8 @@ static bool CMAC_AES(const Span args[], ReplyCallback write_reply return write_reply({Span(mac, mac_len)}); } -static bool CMAC_AESVerify(const Span args[], ReplyCallback write_reply) { +static bool CMAC_AESVerify(const Span args[], + ReplyCallback write_reply) { // This function is just for testing since libcrypto doesn't do the // verification itself. The regcap doesn't advertise "ver" support. uint8_t mac[16]; @@ -2186,12 +2247,12 @@ static bool CMAC_AESVerify(const Span args[], ReplyCallback write return write_reply({Span(&ok, sizeof(ok))}); } -static std::map>& CachedRSAEVPKeys() { +static std::map> &CachedRSAEVPKeys() { static std::map> keys; return keys; } -static EVP_PKEY* AddRSAKeyToCache(bssl::UniquePtr& rsa, unsigned bits) { +static EVP_PKEY *AddRSAKeyToCache(bssl::UniquePtr &rsa, unsigned bits) { bssl::UniquePtr evp_pkey(EVP_PKEY_new()); if (!evp_pkey || !EVP_PKEY_set1_RSA(evp_pkey.get(), rsa.get())) { return nullptr; @@ -2202,7 +2263,7 @@ static EVP_PKEY* AddRSAKeyToCache(bssl::UniquePtr& rsa, unsigned bits) { return ret; } -static EVP_PKEY* GetRSAKey(unsigned bits) { +static EVP_PKEY *GetRSAKey(unsigned bits) { auto it = CachedRSAEVPKeys().find(bits); if (it != CachedRSAEVPKeys().end()) { return it->second.get(); @@ -2216,7 +2277,8 @@ static EVP_PKEY* GetRSAKey(unsigned bits) { return AddRSAKeyToCache(rsa, bits); } -static bool RSAKeyGen(const Span args[], ReplyCallback write_reply) { +static bool RSAKeyGen(const Span args[], + ReplyCallback write_reply) { uint32_t bits; if (args[0].size() != sizeof(bits)) { return false; @@ -2245,7 +2307,8 @@ static bool RSAKeyGen(const Span args[], ReplyCallback write_repl } template -static bool RSASigGen(const Span args[], ReplyCallback write_reply) { +static bool RSASigGen(const Span args[], + ReplyCallback write_reply) { uint32_t bits; if (args[0].size() != sizeof(bits)) { return false; @@ -2268,12 +2331,14 @@ static bool RSASigGen(const Span args[], ReplyCallback write_repl int padding = UsePSS ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING; if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr, evp_pkey) || !EVP_PKEY_CTX_set_rsa_padding(pctx, padding) || - (UsePSS && !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST)) || + (UsePSS && + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST)) || !EVP_DigestSign(ctx.get(), nullptr, &sig_len, msg.data(), msg.size())) { return false; } sig.resize(sig_len); - if (!EVP_DigestSign(ctx.get(), sig.data(), &sig_len, msg.data(), msg.size())) { + if (!EVP_DigestSign(ctx.get(), sig.data(), &sig_len, msg.data(), + msg.size())) { return false; } @@ -2282,7 +2347,8 @@ static bool RSASigGen(const Span args[], ReplyCallback write_repl } template -static bool RSASigVer(const Span args[], ReplyCallback write_reply) { +static bool RSASigVer(const Span args[], + ReplyCallback write_reply) { const Span n_bytes = args[0]; const Span e_bytes = args[1]; const Span msg = args[2]; @@ -2308,8 +2374,10 @@ static bool RSASigVer(const Span args[], ReplyCallback write_repl int padding = UsePSS ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING; if (!EVP_DigestVerifyInit(ctx.get(), &pctx, md, nullptr, evp_pkey.get()) || !EVP_PKEY_CTX_set_rsa_padding(pctx, padding) || - (UsePSS && !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST)) || - !EVP_DigestVerify(ctx.get(), sig.data(), sig.size(), msg.data(), msg.size())) { + (UsePSS && + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST)) || + !EVP_DigestVerify(ctx.get(), sig.data(), sig.size(), msg.data(), + msg.size())) { ok = 0; } else { ok = 1; @@ -2320,7 +2388,8 @@ static bool RSASigVer(const Span args[], ReplyCallback write_repl } template -static bool TLSKDF(const Span args[], ReplyCallback write_reply) { +static bool TLSKDF(const Span args[], + ReplyCallback write_reply) { const Span out_len_bytes = args[0]; const Span secret = args[1]; const Span label = args[2]; @@ -2467,17 +2536,16 @@ static bool PBKDF(const Span args[], ReplyCallback write_reply) { unsigned int key_len_uint; memcpy(&key_len_uint, key_len.data(), sizeof(key_len_uint)); - key_len_uint = key_len_uint/8; + key_len_uint = key_len_uint / 8; // Get the SHA algorithm we want from the name provided to us - const EVP_MD* hmac_alg = HashFromName(hmac_name); + const EVP_MD *hmac_alg = HashFromName(hmac_name); std::vector out_key(key_len_uint); - if (!PKCS5_PBKDF2_HMAC(reinterpret_cast(password.data()), - password.size(), - salt.data(), salt.size(), - iterations_uint, hmac_alg, - key_len_uint, out_key.data())) { + if (!PKCS5_PBKDF2_HMAC(reinterpret_cast(password.data()), + password.size(), salt.data(), salt.size(), + iterations_uint, hmac_alg, key_len_uint, + out_key.data())) { return false; } @@ -2497,10 +2565,50 @@ static bool HKDF(const Span args[], ReplyCallback write_reply) { std::vector out_key(out_bytes_uint); - if (!::HKDF(out_key.data(), out_bytes_uint, md, - key.data(), key.size(), - salt.data(), salt.size(), - info.data(), info.size())) { + if (!::HKDF(out_key.data(), out_bytes_uint, md, key.data(), key.size(), + salt.data(), salt.size(), info.data(), info.size())) { + return false; + } + + return write_reply({Span(out_key)}); +} + +template +static bool SSKDF_DIGEST(const Span args[], + ReplyCallback write_reply) { + const Span key = args[0]; + const Span info = args[1]; + const Span out_bytes = args[2]; + const EVP_MD *md = MDFunc(); + + uint32_t out_bytes_uint32; + memcpy(&out_bytes_uint32, out_bytes.data(), sizeof(out_bytes_uint32)); + + std::vector out_key(out_bytes_uint32); + if (!::SSKDF_digest(out_key.data(), out_bytes_uint32, md, key.data(), + key.size(), info.data(), info.size())) { + return false; + } + + return write_reply({Span(out_key)}); +} + +template +static bool SSKDF_HMAC(const Span args[], + ReplyCallback write_reply) { + const Span key = args[0]; + const Span salt = args[1]; + const Span info = args[2]; + const Span out_bytes = args[3]; + const EVP_MD *md = MDFunc(); + + uint32_t out_bytes_uint32; + memcpy(&out_bytes_uint32, out_bytes.data(), sizeof(out_bytes_uint32)); + + std::vector out_key(out_bytes_uint32); + if (!::SSKDF_hmac(out_key.data(), out_bytes_uint32, md, key.data(), + key.size(), info.data(), info.size(), salt.data(), + salt.size())) { return false; } @@ -2508,7 +2616,8 @@ static bool HKDF(const Span args[], ReplyCallback write_reply) { } template -static bool SSHKDF(const Span args[], ReplyCallback write_reply) { +static bool SSHKDF(const Span args[], + ReplyCallback write_reply) { const Span key = args[0]; const Span hash = args[1]; const Span session_id = args[2]; @@ -2520,12 +2629,9 @@ static bool SSHKDF(const Span args[], ReplyCallback write_reply) memcpy(&out_bytes_uint, out_bytes.data(), sizeof(out_bytes_uint)); std::vector out(out_bytes_uint); - if (!::SSHKDF(md, - key.data(), key.size(), - hash.data(), hash.size(), - session_id.data(), session_id.size(), - type_val, - out.data(), out_bytes_uint)) { + if (!::SSHKDF(md, key.data(), key.size(), hash.data(), hash.size(), + session_id.data(), session_id.size(), type_val, out.data(), + out_bytes_uint)) { return false; } @@ -2533,7 +2639,8 @@ static bool SSHKDF(const Span args[], ReplyCallback write_reply) } template -static bool HKDF_expand(const Span args[], ReplyCallback write_reply) { +static bool HKDF_expand(const Span args[], + ReplyCallback write_reply) { const Span out_bytes = args[0]; const Span key_in = args[1]; const Span fixed_data = args[2]; @@ -2543,9 +2650,8 @@ static bool HKDF_expand(const Span args[], ReplyCallback write_re memcpy(&out_bytes_uint, out_bytes.data(), sizeof(out_bytes_uint)); std::vector out(out_bytes_uint); - if(!::HKDF_expand(out.data(), out_bytes_uint, md, - key_in.data(), key_in.size(), fixed_data.data(), - fixed_data.size())) { + if (!::HKDF_expand(out.data(), out_bytes_uint, md, key_in.data(), + key_in.size(), fixed_data.data(), fixed_data.size())) { return false; } @@ -2674,36 +2780,84 @@ static struct { {"KDA/HKDF/SHA2-256", 4, HKDF}, {"KDA/HKDF/SHA2-384", 4, HKDF}, {"KDA/HKDF/SHA2-512", 4, HKDF}, - {"SSHKDF/SHA-1/ivCli", 4, SSHKDF}, - {"SSHKDF/SHA2-224/ivCli", 4, SSHKDF}, - {"SSHKDF/SHA2-256/ivCli", 4, SSHKDF}, - {"SSHKDF/SHA2-384/ivCli", 4, SSHKDF}, - {"SSHKDF/SHA2-512/ivCli", 4, SSHKDF}, - {"SSHKDF/SHA-1/ivServ", 4, SSHKDF}, - {"SSHKDF/SHA2-224/ivServ", 4, SSHKDF}, - {"SSHKDF/SHA2-256/ivServ", 4, SSHKDF}, - {"SSHKDF/SHA2-384/ivServ", 4, SSHKDF}, - {"SSHKDF/SHA2-512/ivServ", 4, SSHKDF}, - {"SSHKDF/SHA-1/encryptCli", 4, SSHKDF}, - {"SSHKDF/SHA2-224/encryptCli", 4, SSHKDF}, - {"SSHKDF/SHA2-256/encryptCli", 4, SSHKDF}, - {"SSHKDF/SHA2-384/encryptCli", 4, SSHKDF}, - {"SSHKDF/SHA2-512/encryptCli", 4, SSHKDF}, - {"SSHKDF/SHA-1/encryptServ", 4, SSHKDF}, - {"SSHKDF/SHA2-224/encryptServ", 4, SSHKDF}, - {"SSHKDF/SHA2-256/encryptServ", 4, SSHKDF}, - {"SSHKDF/SHA2-384/encryptServ", 4, SSHKDF}, - {"SSHKDF/SHA2-512/encryptServ", 4, SSHKDF}, - {"SSHKDF/SHA-1/integCli", 4, SSHKDF}, - {"SSHKDF/SHA2-224/integCli", 4, SSHKDF}, - {"SSHKDF/SHA2-256/integCli", 4, SSHKDF}, - {"SSHKDF/SHA2-384/integCli", 4, SSHKDF}, - {"SSHKDF/SHA2-512/integCli", 4, SSHKDF}, - {"SSHKDF/SHA-1/integServ", 4, SSHKDF}, - {"SSHKDF/SHA2-224/integServ", 4, SSHKDF}, - {"SSHKDF/SHA2-256/integServ", 4, SSHKDF}, - {"SSHKDF/SHA2-384/integServ", 4, SSHKDF}, - {"SSHKDF/SHA2-512/integServ", 4, SSHKDF}, + {"KDA/OneStep/SHA-1", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-224", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-256", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-384", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-512", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-512/224", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA2-512/256", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA3-224", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA3-256", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA3-384", 3, SSKDF_DIGEST}, + {"KDA/OneStep/SHA3-512", 3, SSKDF_DIGEST}, + {"KDA/OneStep/HMAC-SHA-1", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-224", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-256", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-384", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-512", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-512/224", 4, SSKDF_HMAC}, + {"KDA/OneStep/HMAC-SHA2-512/256", 4, SSKDF_HMAC}, + {"SSHKDF/SHA-1/ivCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/ivCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/ivCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/ivCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/ivCli", 4, + SSHKDF}, + {"SSHKDF/SHA-1/ivServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/ivServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/ivServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/ivServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/ivServ", 4, + SSHKDF}, + {"SSHKDF/SHA-1/encryptCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/encryptCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/encryptCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/encryptCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/encryptCli", 4, + SSHKDF}, + {"SSHKDF/SHA-1/encryptServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/encryptServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/encryptServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/encryptServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/encryptServ", 4, + SSHKDF}, + {"SSHKDF/SHA-1/integCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/integCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/integCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/integCli", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/integCli", 4, + SSHKDF}, + {"SSHKDF/SHA-1/integServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-224/integServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-256/integServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-384/integServ", 4, + SSHKDF}, + {"SSHKDF/SHA2-512/integServ", 4, + SSHKDF}, {"KDF/Feedback/HMAC-SHA-1", 3, HKDF_expand}, {"KDF/Feedback/HMAC-SHA2-224", 3, HKDF_expand}, {"KDF/Feedback/HMAC-SHA2-256", 3, HKDF_expand},