acvp: add support for KAS

Change-Id: Ida3ec65e81398881a71828dc1d51cf80be41bdbb
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/44444
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
chromium-5359
Adam Langley 4 years ago committed by CQ bot account: commit-bot@chromium.org
parent a6b6b804a0
commit 0898b077a3
  1. 162
      util/fipstools/acvp/acvptool/subprocess/kas.go
  2. 1
      util/fipstools/acvp/acvptool/subprocess/subprocess.go
  3. 88
      util/fipstools/acvp/modulewrapper/modulewrapper.cc

@ -0,0 +1,162 @@
// Copyright (c) 2020, Google Inc.
//
// 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 (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
)
type kasVectorSet struct {
Groups []kasTestGroup `json:"testGroups"`
}
type kasTestGroup struct {
ID uint64 `json:"tgId"`
Type string `json:"testType"`
Curve string `json:"domainParameterGenerationMode"`
Role string `json:"kasRole"`
Scheme string `json:"scheme"`
Tests []kasTest `json:"tests"`
}
type kasTest struct {
ID uint64 `json:"tcId"`
XHex string `json:"ephemeralPublicServerX"`
YHex string `json:"ephemeralPublicServerY"`
PrivateKeyHex string `json:"ephemeralPrivateIut"`
ResultHex string `json:"z"`
}
type kasTestGroupResponse struct {
ID uint64 `json:"tgId"`
Tests []kasTestResponse `json:"tests"`
}
type kasTestResponse struct {
ID uint64 `json:"tcId"`
XHex string `json:"ephemeralPublicIutX,omitempty"`
YHex string `json:"ephemeralPublicIutY,omitempty"`
ResultHex string `json:"z,omitempty"`
Passed *bool `json:"testPassed,omitempty"`
}
type kas struct{}
func (k *kas) Process(vectorSet []byte, m Transactable) (interface{}, error) {
var parsed kasVectorSet
if err := json.Unmarshal(vectorSet, &parsed); err != nil {
return nil, err
}
// See https://usnistgov.github.io/ACVP/draft-hammett-acvp-kas-ssc-ecc.html
var ret []kasTestGroupResponse
for _, group := range parsed.Groups {
response := kasTestGroupResponse{
ID: group.ID,
}
var privateKeyGiven bool
switch group.Type {
case "AFT":
privateKeyGiven = false
case "VAL":
privateKeyGiven = true
default:
return nil, fmt.Errorf("unknown test type %q", group.Type)
}
switch group.Curve {
case "P-224", "P-256", "P-384", "P-521":
break
default:
return nil, fmt.Errorf("unknown curve %q", group.Curve)
}
switch group.Role {
case "initiator", "responder":
break
default:
return nil, fmt.Errorf("unknown role %q", group.Role)
}
if group.Scheme != "ephemeralUnified" {
return nil, fmt.Errorf("unknown scheme %q", group.Scheme)
}
method := "ECDH/" + group.Curve
for _, test := range group.Tests {
if len(test.XHex) == 0 || len(test.YHex) == 0 {
return nil, fmt.Errorf("%d/%d is missing peer's point", group.ID, test.ID)
}
peerX, err := hex.DecodeString(test.XHex)
if err != nil {
return nil, err
}
peerY, err := hex.DecodeString(test.YHex)
if err != nil {
return nil, err
}
if (len(test.PrivateKeyHex) != 0) != privateKeyGiven {
return nil, fmt.Errorf("%d/%d incorrect private key presence", group.ID, test.ID)
}
if privateKeyGiven {
privateKey, err := hex.DecodeString(test.PrivateKeyHex)
if err != nil {
return nil, err
}
expectedOutput, err := hex.DecodeString(test.ResultHex)
if err != nil {
return nil, err
}
result, err := m.Transact(method, 3, peerX, peerY, privateKey)
if err != nil {
return nil, err
}
ok := bytes.Equal(result[2], expectedOutput)
response.Tests = append(response.Tests, kasTestResponse{
ID: test.ID,
Passed: &ok,
})
} else {
result, err := m.Transact(method, 3, peerX, peerY, nil)
if err != nil {
return nil, err
}
response.Tests = append(response.Tests, kasTestResponse{
ID: test.ID,
XHex: hex.EncodeToString(result[0]),
YHex: hex.EncodeToString(result[1]),
ResultHex: hex.EncodeToString(result[2]),
})
}
}
ret = append(ret, response)
}
return ret, nil
}

@ -97,6 +97,7 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess
"CMAC-AES": &keyedMACPrimitive{"CMAC-AES"},
"RSA": &rsa{},
"kdf-components": &tlsKDF{},
"KAS-ECC-SSC": &kas{},
}
m.primitives["ECDSA"] = &ecdsa{"ECDSA", map[string]bool{"P-224": true, "P-256": true, "P-384": true, "P-521": true}, m.primitives}

@ -32,6 +32,7 @@
#include <openssl/digest.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
#include <openssl/ecdh.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/hmac.h>
@ -40,6 +41,7 @@
#include <openssl/sha.h>
#include <openssl/span.h>
#include "../../../../crypto/fipsmodule/ec/internal.h"
#include "../../../../crypto/fipsmodule/rand/internal.h"
#include "../../../../crypto/fipsmodule/tls/internal.h"
@ -717,6 +719,24 @@ static bool GetConfig(const Span<const uint8_t> args[]) {
"SHA2-384",
"SHA2-512"
]
},
{
"algorithm": "KAS-ECC-SSC",
"revision": "Sp800-56Ar3",
"scheme": {
"ephemeralUnified": {
"kasRole": [
"initiator",
"responder"
]
}
},
"domainParameterGenerationMethods": [
"P-224",
"P-256",
"P-384",
"P-521"
]
}
])";
return WriteReply(
@ -1594,6 +1614,70 @@ static bool TLSKDF(const Span<const uint8_t> args[]) {
return WriteReply(STDOUT_FILENO, out);
}
template <int Nid>
static bool ECDH(const Span<const uint8_t> args[]) {
bssl::UniquePtr<BIGNUM> their_x(BytesToBIGNUM(args[0]));
bssl::UniquePtr<BIGNUM> their_y(BytesToBIGNUM(args[1]));
const Span<const uint8_t> private_key = args[2];
bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(Nid));
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
const EC_GROUP *const group = EC_KEY_get0_group(ec_key.get());
bssl::UniquePtr<EC_POINT> their_point(EC_POINT_new(group));
if (!EC_POINT_set_affine_coordinates_GFp(
group, their_point.get(), their_x.get(), their_y.get(), ctx.get())) {
fprintf(stderr, "Invalid peer point for ECDH.\n");
return false;
}
if (!private_key.empty()) {
bssl::UniquePtr<BIGNUM> our_k(BytesToBIGNUM(private_key));
if (!EC_KEY_set_private_key(ec_key.get(), our_k.get())) {
fprintf(stderr, "EC_KEY_set_private_key failed.\n");
return false;
}
bssl::UniquePtr<EC_POINT> our_pub(EC_POINT_new(group));
if (!EC_POINT_mul(group, our_pub.get(), our_k.get(), nullptr, nullptr,
ctx.get()) ||
!EC_KEY_set_public_key(ec_key.get(), our_pub.get())) {
fprintf(stderr, "Calculating public key failed.\n");
return false;
}
} else if (!EC_KEY_generate_key_fips(ec_key.get())) {
fprintf(stderr, "EC_KEY_generate_key_fips failed.\n");
return false;
}
// The output buffer is one larger than |EC_MAX_BYTES| so that truncation
// can be detected.
std::vector<uint8_t> output(EC_MAX_BYTES + 1);
const int out_len =
ECDH_compute_key(output.data(), output.size(), their_point.get(),
ec_key.get(), /*kdf=*/nullptr);
if (out_len < 0) {
fprintf(stderr, "ECDH_compute_key failed.\n");
return false;
} else if (static_cast<size_t>(out_len) == output.size()) {
fprintf(stderr, "ECDH_compute_key output may have been truncated.\n");
return false;
}
output.resize(static_cast<size_t>(out_len));
const EC_POINT *pub = EC_KEY_get0_public_key(ec_key.get());
bssl::UniquePtr<BIGNUM> x(BN_new());
bssl::UniquePtr<BIGNUM> y(BN_new());
if (!EC_POINT_get_affine_coordinates_GFp(group, pub, x.get(), y.get(),
ctx.get())) {
fprintf(stderr, "EC_POINT_get_affine_coordinates_GFp failed.\n");
return false;
}
return WriteReply(STDOUT_FILENO, BIGNUMBytes(x.get()), BIGNUMBytes(y.get()),
output);
}
static constexpr struct {
const char name[kMaxNameLength + 1];
uint8_t expected_args;
@ -1660,6 +1744,10 @@ static constexpr struct {
{"TLSKDF/1.2/SHA2-256", 5, TLSKDF<EVP_sha256>},
{"TLSKDF/1.2/SHA2-384", 5, TLSKDF<EVP_sha384>},
{"TLSKDF/1.2/SHA2-512", 5, TLSKDF<EVP_sha512>},
{"ECDH/P-224", 3, ECDH<NID_secp224r1>},
{"ECDH/P-256", 3, ECDH<NID_X9_62_prime256v1>},
{"ECDH/P-384", 3, ECDH<NID_secp384r1>},
{"ECDH/P-521", 3, ECDH<NID_secp521r1>},
};
int main() {

Loading…
Cancel
Save