Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions util/fipstools/acvp/acvptool/subprocess/kts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright (c) 2020, Google Inc.
Comment thread
nhatnghiho marked this conversation as resolved.
Outdated
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

package subprocess

import (
"encoding/json"
"fmt"
)

type ktsVectorSet struct {
Groups []ktsTestGroup `json:"testGroups"`
}

type ktsTestGroup struct {
ID uint64 `json:"tgId"`
Type string `json:"testType"`
Role string `json:"kasRole"`
Scheme string `json:"scheme"`
KtsConfiguration ktsConfiguration `json:"ktsConfiguration"`
Tests []ktsTest `json:"tests"`
L uint32 `json:"l"`
}

type ktsConfiguration struct {
HashAlg string `json:"hashAlg"`
}

type ktsTest struct {
ID uint64 `json:"tcId"`
ServerN hexEncodedByteString `json:"serverN"`
ServerE hexEncodedByteString `json:"serverE"`
IutN hexEncodedByteString `json:"iutN"`
IutE hexEncodedByteString `json:"iutE"`
IutP hexEncodedByteString `json:"iutP"`
IutQ hexEncodedByteString `json:"iutQ"`
IutD hexEncodedByteString `json:"iutD"`
Ct hexEncodedByteString `json:"serverC"`
}

type ktsTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []ktsTestResponse `json:"tests"`
}

type ktsTestResponse struct {
ID uint64 `json:"tcId"`
IutC hexEncodedByteString `json:"iutC,omitempty"`
Dkm hexEncodedByteString `json:"dkm"`
}

type kts struct{}

func (k *kts) Process(vectorSet []byte, m Transactable) (interface{}, error) {
var parsed ktsVectorSet
if err := json.Unmarshal(vectorSet, &parsed); err != nil {
return nil, err
}

// See https://pages.nist.gov/ACVP/draft-hammett-acvp-kas-ifc.html
var ret []ktsTestGroupResponse
for _, group := range parsed.Groups {
group := group
Comment thread
nhatnghiho marked this conversation as resolved.
Outdated
response := ktsTestGroupResponse{
ID: group.ID,
}

if group.Type != "AFT" {
return nil, fmt.Errorf("unknown test type %q", group.Scheme)
}

switch group.Role {
case "initiator", "responder":
break
Comment thread
nhatnghiho marked this conversation as resolved.
Outdated
default:
return nil, fmt.Errorf("unknown role %q", group.Role)
}

if group.Scheme != "KTS-OAEP-basic" {
return nil, fmt.Errorf("unknown scheme %q", group.Scheme)
}

if len(group.KtsConfiguration.HashAlg) == 0 {
return nil, fmt.Errorf("missing hash algorithm")
}

hashAlg := group.KtsConfiguration.HashAlg

var outLenBytes [4]byte
NativeEndian.PutUint32(outLenBytes[:], group.L/8) // Convert bits to bytes

for _, test := range group.Tests {
test := test
if group.Role == "initiator" {
result, err := m.Transact("KTS/OAEP/"+hashAlg+"/transport", 2, outLenBytes[:], nil, test.ServerN, test.ServerE, nil, nil, nil)
if err != nil {
return nil, err
}
response.Tests = append(response.Tests, ktsTestResponse{
ID: test.ID,
IutC: result[0],
Dkm: result[1],
})
} else {
result, err := m.Transact("KTS/OAEP/"+hashAlg+"/receive", 1, outLenBytes[:], test.Ct, test.IutN, test.IutE, test.IutQ, test.IutP, test.IutD)
if err != nil {
return nil, err
}

response.Tests = append(response.Tests, ktsTestResponse{
ID: test.ID,
Dkm: result[0],
})
}
}

ret = append(ret, response)
}

return ret, nil
}
1 change: 1 addition & 0 deletions util/fipstools/acvp/acvptool/subprocess/subprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess
"OneStep": &kdaOneStepMode{},
},
},
"KTS-IFC": &kts{},
"TLS-v1.3": &tls13{},
"CMAC-AES": &keyedMACPrimitive{"CMAC-AES"},
"RSA": &rsa{},
Expand Down
1 change: 1 addition & 0 deletions util/fipstools/acvp/acvptool/test/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
{"Wrapper": "modulewrapper", "In": "vectors/KAS-ECC-SSC.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/KAS-FFC-SSC.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/KDF.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/KTS-IFC.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/ACVP-AES-GCM-internal-IV.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/kdf-components.bz2", "Out": "expected/kdf-components.bz2"},
{"Wrapper": "modulewrapper", "In": "vectors/RSA.bz2", "Out": "expected/RSA.bz2"},
Expand Down
Binary file not shown.
84 changes: 84 additions & 0 deletions util/fipstools/acvp/modulewrapper/modulewrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1484,6 +1484,23 @@ static bool GetConfig(const Span<const uint8_t> args[],
"internal",
"external"
]
},)"
R"({
"algorithm": "KTS-IFC",
"revision": "Sp800-56Br2",
"function": ["keyPairGen", "partialVal"],
"iutId": ["initiator", "responder"],
"keyGenerationMethods": ["rsakpg1-basic", "rsakpg1-prime-factor", "rsakpg1-crt"],
"modulo": [2048, 3072, 4096],
"fixedPubExp": "010001",
"kasRole": ["initiator", "responder"],
"l": 1024,
"scheme": "KTS-OAEP-basic",
"ktsConfiguration": {
"hashAlg": ["SHA-1", "SHA2-224", "SHA2-256", "SHA2-384", "SHA2-512"],
"associatedDataPattern": "uPartyInfo||vPartyInfo",
"encoding": ["concatenation", "none"]
}
}])";
return write_reply({Span<const uint8_t>(
reinterpret_cast<const uint8_t *>(kConfig), sizeof(kConfig) - 1)});
Expand Down Expand Up @@ -2779,6 +2796,71 @@ static bool RSASigVer(const Span<const uint8_t> args[],
return write_reply({Span<const uint8_t>(&ok, 1)});
}

template <const EVP_MD *(MDFunc)(), int Encrypt>
static bool RSA_OAEP(const Span<const uint8_t> args[],
ReplyCallback write_reply) {
const Span<const uint8_t> dkm_len_bytes = args[0];
const Span<const uint8_t> input = args[1];
const Span<const uint8_t> n_bytes = args[2];
const Span<const uint8_t> e_bytes = args[3];
const Span<const uint8_t> q_bytes = args[4];
const Span<const uint8_t> p_bytes = args[5];
const Span<const uint8_t> d_bytes = args[6];

uint32_t dkm_len = 0;
memcpy(&dkm_len, dkm_len_bytes.data(), sizeof(dkm_len));

BIGNUM *n = BN_new();
BIGNUM *e = BN_new();

bssl::UniquePtr<RSA> key(RSA_new());

if (Encrypt) {
Comment thread
nhatnghiho marked this conversation as resolved.
Outdated
// Generate random keying material and encrypt it
if (!BN_bin2bn(n_bytes.data(), n_bytes.size(), n) ||
!BN_bin2bn(e_bytes.data(), e_bytes.size(), e) ||
!RSA_set0_key(key.get(), n, e, nullptr)) {
return false;
}

std::vector<uint8_t> dkm(dkm_len);
RAND_bytes(dkm.data(), dkm.size());

std::vector<uint8_t> ct(RSA_size(key.get()));
size_t ct_len = 0;
if (!RSA_encrypt(key.get(), &ct_len, ct.data(), ct.size(), dkm.data(),
dkm.size(), RSA_PKCS1_OAEP_PADDING)) {
return false;
}
return write_reply({Span<const uint8_t>(ct), Span<const uint8_t>(dkm)});
} else {
BIGNUM *p = BN_new();
BIGNUM *q = BN_new();
BIGNUM *d = BN_new();

if (!BN_bin2bn(n_bytes.data(), n_bytes.size(), n) ||
!BN_bin2bn(e_bytes.data(), e_bytes.size(), e) ||
!BN_bin2bn(d_bytes.data(), d_bytes.size(), d) ||
!BN_bin2bn(p_bytes.data(), p_bytes.size(), p) ||
!BN_bin2bn(q_bytes.data(), q_bytes.size(), q) ||
!RSA_set0_key(key.get(), n, e, d) ||
!RSA_set0_factors(key.get(), p, q)) {
return false;
}

std::vector<uint8_t> dkm(RSA_size(key.get()));
size_t dkm_len = 0;
if (!RSA_decrypt(key.get(), &dkm_len, dkm.data(), dkm.size(), input.data(),
input.size(), RSA_PKCS1_OAEP_PADDING)) {
return false;
}

dkm.resize(dkm_len);
return write_reply({Span<const uint8_t>(dkm)});
}
}


template <const EVP_MD *(MDFunc)()>
static bool TLSKDF(const Span<const uint8_t> args[],
ReplyCallback write_reply) {
Expand Down Expand Up @@ -3674,6 +3756,8 @@ static struct {
{"KDA/OneStep/HMAC-SHA2-512", 4, SSKDF_HMAC<EVP_sha512>},
{"KDA/OneStep/HMAC-SHA2-512/224", 4, SSKDF_HMAC<EVP_sha512_224>},
{"KDA/OneStep/HMAC-SHA2-512/256", 4, SSKDF_HMAC<EVP_sha512_256>},
{"KTS/OAEP/SHA2-256/transport", 7, RSA_OAEP<EVP_sha256, true>},
{"KTS/OAEP/SHA-1/receive", 7, RSA_OAEP<EVP_sha1, false>},
{"SSHKDF/SHA-1/ivCli", 4,
SSHKDF<EVP_sha1, EVP_KDF_SSHKDF_TYPE_INITIAL_IV_CLI_TO_SRV>},
{"SSHKDF/SHA2-224/ivCli", 4,
Expand Down
Loading