Bug 1870290 - land NSS NSS_3_97_BETA1 UPGRADE_NSS_RELEASE, r=keeler

Differential Revision: https://phabricator.services.mozilla.com/D198471
This commit is contained in:
John Schanck 2024-01-16 16:27:07 +00:00
Родитель 8ecc4d2b75
Коммит 8e8e91d1a7
86 изменённых файлов: 24296 добавлений и 39314 удалений

Просмотреть файл

@ -9,7 +9,7 @@ system_lib_option("--with-system-nss", help="Use system NSS")
imply_option("--with-system-nspr", True, when="--with-system-nss")
nss_pkg = pkg_check_modules(
"NSS", "nss >= 3.95", when="--with-system-nss", config=False
"NSS", "nss >= 3.97", when="--with-system-nss", config=False
)
set_config("MOZ_SYSTEM_NSS", True, when="--with-system-nss")

Просмотреть файл

@ -731,6 +731,7 @@ _SGN_VerifyPKCS1DigestInfo
__PK11_SetCertificateNickname
# These symbols are not used by Firefox but are used across NSS library boundaries.
NSS_SecureMemcmpZero
NSS_SecureSelect
PORT_ZAllocAlignedOffset_Util
CERT_FindCertByNicknameOrEmailAddrCX
SECKEY_GetPrivateKeyType

Просмотреть файл

@ -1 +1 @@
660735996d77
NSS_3_97_BETA1

Просмотреть файл

@ -0,0 +1,20 @@
3 Added functions:
'function PK11SymKey* PK11_ConcatSymKeys(PK11SymKey*, PK11SymKey*, CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE)' {PK11_ConcatSymKeys@@NSS_3.2}
'function SECStatus PK11_Decapsulate(SECKEYPrivateKey*, const SECItem*, CK_MECHANISM_TYPE, PK11AttrFlags, CK_FLAGS, PK11SymKey**)' {PK11_Decapsulate@@NSS_3.2}
'function SECStatus PK11_Encapsulate(SECKEYPublicKey*, CK_MECHANISM_TYPE, PK11AttrFlags, CK_FLAGS, PK11SymKey**, SECItem**)' {PK11_Encapsulate@@NSS_3.2}
1 function with some indirect sub-type change:
[C]'function SECStatus CERT_AddOCSPAcceptableResponses(CERTOCSPRequest*, SECOidTag, ...)' at ocsp.c:2202:1 has some indirect sub-type changes:
parameter 2 of type 'typedef SECOidTag' has sub-type changes:
underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
type size hasn't changed
1 enumerator insertion:
'__anonymous_enum__::SEC_OID_XYBER768D00' value '372'
1 enumerator change:
'__anonymous_enum__::SEC_OID_TOTAL' from value '372' to '373' at secoidt.h:34:1

Просмотреть файл

@ -0,0 +1,15 @@
1 function with some indirect sub-type change:
[C]'function SECStatus NSS_GetAlgorithmPolicy(SECOidTag, PRUint32*)' at secoid.c:2265:1 has some indirect sub-type changes:
parameter 1 of type 'typedef SECOidTag' has sub-type changes:
underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
type size hasn't changed
1 enumerator insertion:
'__anonymous_enum__::SEC_OID_XYBER768D00' value '372'
1 enumerator change:
'__anonymous_enum__::SEC_OID_TOTAL' from value '372' to '373' at secoidt.h:34:1

Просмотреть файл

@ -0,0 +1,45 @@
1 function with some indirect sub-type change:
[C]'function PK11SymKey* NSS_CMSContentInfo_GetBulkKey(NSSCMSContentInfo*)' at cmscinfo.c:426:1 has some indirect sub-type changes:
parameter 1 of type 'NSSCMSContentInfo*' has sub-type changes:
in pointed to type 'typedef NSSCMSContentInfo' at cmst.h:54:1:
underlying type 'struct NSSCMSContentInfoStr' at cmst.h:126:1 changed:
type size hasn't changed
1 data member changes (2 filtered):
type of 'NSSCMSContent NSSCMSContentInfoStr::content' changed:
underlying type 'union NSSCMSContentUnion' at cmst.h:113:1 changed:
type size hasn't changed
1 data member changes (3 filtered):
type of 'NSSCMSEncryptedData* NSSCMSContentUnion::encryptedData' changed:
in pointed to type 'typedef NSSCMSEncryptedData' at cmst.h:65:1:
underlying type 'struct NSSCMSEncryptedDataStr' at cmst.h:463:1 changed:
type size hasn't changed
1 data member changes (1 filtered):
type of 'NSSCMSAttribute** NSSCMSEncryptedDataStr::unprotectedAttr' changed:
in pointed to type 'NSSCMSAttribute*':
in pointed to type 'typedef NSSCMSAttribute' at cmst.h:69:1:
underlying type 'struct NSSCMSAttributeStr' at cmst.h:482:1 changed:
type size hasn't changed
1 data member change:
type of 'SECOidData* NSSCMSAttributeStr::typeTag' changed:
in pointed to type 'typedef SECOidData' at secoidt.h:16:1:
underlying type 'struct SECOidDataStr' at secoidt.h:533:1 changed:
type size hasn't changed
1 data member change:
type of 'SECOidTag SECOidDataStr::offset' changed:
underlying type 'enum __anonymous_enum__' at secoidt.h:34:1 changed:
type size hasn't changed
1 enumerator insertion:
'__anonymous_enum__::SEC_OID_XYBER768D00' value '372'
1 enumerator change:
'__anonymous_enum__::SEC_OID_TOTAL' from value '372' to '373' at secoidt.h:34:1

Просмотреть файл

@ -0,0 +1,16 @@
1 function with some indirect sub-type change:
[C]'function SSLKEAType NSS_FindCertKEAType(CERTCertificate*)' at sslcert.c:996:1 has some indirect sub-type changes:
return type changed:
underlying type 'enum __anonymous_enum__' at sslt.h:77:1 changed:
type size hasn't changed
2 enumerator insertions:
'__anonymous_enum__::ssl_kea_ecdh_hybrid' value '8'
'__anonymous_enum__::ssl_kea_ecdh_hybrid_psk' value '9'
1 enumerator change:
'__anonymous_enum__::ssl_kea_size' from value '8' to '10' at sslt.h:77:1

Просмотреть файл

@ -347,15 +347,12 @@ async function scheduleMac(name, base, args = "") {
HOST: "localhost",
},
provisioner: "releng-hardware",
workerType: "nss-1-b-osx-1015",
workerType: `nss-${process.env.MOZ_SCM_LEVEL}-b-osx-1015`,
platform: "mac"
});
// Build base definition.
let build_base_without_command_symbol = merge(mac_base, {
provisioner: "releng-hardware",
workerType: "nss-1-b-osx-1015",
platform: "mac",
maxRunTime: 7200,
artifacts: [{
expires: 24 * 7,

411
security/nss/automation/vendor/kyber/ref/vendor.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,411 @@
#!/usr/bin/python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import io
import os
import requests
import sys
import tarfile
def remove_include_guard(x: io.StringIO, guard: str) -> io.StringIO:
out = io.StringIO()
depth = 0
inside_guard = False
for line in x.readlines():
tokens = line.split()
if tokens and tokens[0] in ["#if", "#ifdef", "#ifndef"]:
depth += 1
if len(tokens) > 1 and tokens[0] == "#ifndef" and tokens[1] == guard:
assert depth == 1, "error: nested include guard"
inside_guard = True
continue
if len(tokens) > 1 and tokens[0] == "#define" and tokens[1] == guard:
continue
if tokens and tokens[0] == "#endif":
depth -= 1
if depth == 0 and inside_guard:
inside_guard = False
continue
out.write(line)
out.seek(0)
return out
def remove_includes(x: io.StringIO) -> io.StringIO:
out = io.StringIO()
for line in x.readlines():
tokens = line.split()
if tokens and tokens[0] == "#include":
continue
out.write(line)
out.seek(0)
return out
# Take the else branch of any #ifdef KYBER90s ... #else ... #endif
def remove_kyber90s(x: io.StringIO) -> io.StringIO:
out = io.StringIO()
states = ["before", "during-drop", "during-keep"]
state = "before"
current_depth = 0
kyber90s_depth = None
for line in x.readlines():
tokens = line.split()
if tokens and tokens[0] in ["#if", "#ifdef", "#ifndef"]:
current_depth += 1
if len(tokens) > 1 and tokens[0] == "#ifdef" and tokens[1] == "KYBER_90S":
assert kyber90s_depth == None, "cannot handle nested #ifdef KYBER90S"
kyber90s_depth = current_depth
state = "during-drop"
continue
if len(tokens) > 1 and tokens[0] == "#ifndef" and tokens[1] == "KYBER_90S":
assert kyber90s_depth == None, "cannot handle nested #ifndef KYBER90S"
kyber90s_depth = current_depth
state = "during-keep"
continue
if current_depth == kyber90s_depth and tokens:
if tokens[0] == "#else":
assert state != "before"
state = "during-keep" if state == "during-drop" else "during-drop"
continue
if tokens[0] == "#elif":
assert False, "cannot handle #elif branch of #ifdef KYBER90S"
if tokens[0] == "#endif":
assert state != "before"
state = "before"
kyber90s_depth = None
current_depth -= 1
continue
if tokens and tokens[0] == "#endif":
current_depth -= 1
if state == "during-drop":
continue
out.write(line)
out.seek(0)
return out
def add_static_to_fns(x: io.StringIO) -> io.StringIO:
out = io.StringIO()
depth = 0
for line in x.readlines():
tokens = line.split()
# assumes return type starts on column 0
if depth == 0 and any(
line.startswith(typ) for typ in ["void", "uint32_t", "int16_t", "int"]
):
out.write("static " + line)
else:
out.write(line)
if "{" in line:
depth += 1
if "}" in line:
depth -= 1
out.seek(0)
return out
def file_block(x: io.StringIO, filename: str) -> io.StringIO:
out = io.StringIO()
out.write(f"\n/** begin: {filename} **/\n")
out.write(x.read().strip())
out.write(f"\n/** end: {filename} **/\n")
out.seek(0)
return out
def test():
assert 0 == len(remove_includes(io.StringIO("#include <stddef.h>")).read())
assert 0 == len(remove_kyber90s(io.StringIO("#ifdef KYBER_90S\nx\n#endif")).read())
test_remove_kyber90s_expect = "#ifdef OTHER\nx\n#else\nx\n#endif"
test_remove_ifdef_kyber90s = f"""
#ifdef KYBER_90S
x
{test_remove_kyber90s_expect}
x
#else
{test_remove_kyber90s_expect}
#endif
"""
test_remove_ifdef_kyber90s_actual = (
remove_kyber90s(io.StringIO(test_remove_ifdef_kyber90s)).read().strip()
)
assert (
test_remove_kyber90s_expect == test_remove_ifdef_kyber90s_actual
), "remove_kyber90s unit test"
test_remove_ifndef_kyber90s = f"""
#ifndef KYBER_90S
{test_remove_kyber90s_expect}
#else
x
{test_remove_kyber90s_expect}
x
#endif
"""
test_remove_ifndef_kyber90s_actual = (
remove_kyber90s(io.StringIO(test_remove_ifndef_kyber90s)).read().strip()
)
assert (
test_remove_kyber90s_expect == test_remove_ifndef_kyber90s_actual
), "remove_kyber90s unit test"
test_add_static_to_fns = """\
void fn() {
int x[3] = {1,2,3};
}"""
assert (
f"static {test_add_static_to_fns}"
== add_static_to_fns(io.StringIO(test_add_static_to_fns)).read()
)
test_remove_include_guard = """\
#ifndef TEST_H
#define TEST_H
#endif"""
assert 0 == len(
remove_include_guard(io.StringIO(test_remove_include_guard), "TEST_H").read()
)
assert (
test_remove_include_guard
== remove_include_guard(
io.StringIO(test_remove_include_guard), "OTHER_H"
).read()
)
def is_hex(s: str) -> bool:
try:
int(s, 16)
except ValueError:
return False
return True
if __name__ == "__main__":
test()
repo = f"https://github.com/pq-crystals/kyber"
out = "kyber-pqcrystals-ref.c"
out_api = "kyber-pqcrystals-ref.h"
out_orig = "kyber-pqcrystals-ref.c.orig"
if len(sys.argv) == 2 and len(sys.argv[1]) >= 6 and is_hex(sys.argv[1]):
commit = sys.argv[1]
print(f"* using commit id {commit}")
else:
print(
f"""\
Usage: python3 {sys.argv[0]} [commit]
where [commit] is an 8+ hex digit commit id from {repo}.
"""
)
sys.exit(1)
short_commit = commit[:8]
tarball_url = f"{repo}/tarball/{commit}"
archive = f"kyber-{short_commit}.tar.gz"
headers = [
"params.h",
"reduce.h",
"ntt.h",
"poly.h",
"cbd.h",
"polyvec.h",
"indcpa.h",
"fips202.h",
"symmetric.h",
"kem.h",
]
sources = [
"reduce.c",
"cbd.c",
"ntt.c",
"poly.c",
"polyvec.c",
"indcpa.c",
"fips202.c",
"symmetric-shake.c",
"kem.c",
]
if not os.path.isfile(archive):
print(f"* fetching {tarball_url}")
req = requests.request(method="GET", url=tarball_url)
if not req.ok:
print(f"* failed: {req.reason}")
sys.exit(1)
with open(archive, "wb") as f:
f.write(req.content)
print(f"* extracting files from {archive}")
with open(archive, "rb") as f:
tarball = tarfile.open(mode="r:gz", fileobj=f)
topdir = tarball.members[0].path
assert (
topdir == f"pq-crystals-kyber-{commit[:7]}"
), "tarball directory structure changed"
# Write a single-file copy without modifications for easy diffing
print(f"* writing unmodified files to {out_orig}")
with open(out_orig, "w") as f:
for filename in headers:
x = tarball.extractfile(f"{topdir}/ref/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
x = file_block(x, "ref/" + filename)
f.write(x.read())
for filename in sources:
x = tarball.extractfile(f"{topdir}/ref/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
x = file_block(x, "ref/" + filename)
f.write(x.read())
comment = io.StringIO()
comment.write(
f"""/*
* SPDX-License-Identifier: Apache-2.0
*
* This file was generated from
* https://github.com/pq-crystals/kyber/commit/{short_commit}
*
* Files from that repository are listed here surrounded by
* "* begin: [file] *" and "* end: [file] *" comments.
*
* The following changes have been made:
* - include guards have been removed,
* - include directives have been removed,
* - "#ifdef KYBER90S" blocks have been evaluated with "KYBER90S" undefined,
* - functions outside of kem.c have been made static.
*/
"""
)
for filename in ["LICENSE", "AUTHORS"]:
comment.write(f"""\n/** begin: ref/{filename} **\n""")
x = tarball.extractfile(f"{topdir}/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
for line in x.readlines():
comment.write(line)
comment.write(f"""** end: ref/{filename} **/\n""")
comment.seek(0)
print(f"* writing modified files to {out}")
with open(out, "w") as f:
f.write(comment.read())
f.write(
"""
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "secport.h"
// We need to provide an implementation of randombytes to avoid an unused
// function warning. We don't use the randomized API in freebl, so we'll make
// calling randombytes an error.
static void randombytes(uint8_t *out, size_t outlen) {
// this memset is to avoid "maybe-uninitialized" warnings that gcc-11 issues
// for the (unused) crypto_kem_keypair and crypto_kem_enc functions.
memset(out, 0, outlen);
assert(0);
}
/*************************************************
* Name: verify
*
* Description: Compare two arrays for equality in constant time.
*
* Arguments: const uint8_t *a: pointer to first byte array
* const uint8_t *b: pointer to second byte array
* size_t len: length of the byte arrays
*
* Returns 0 if the byte arrays are equal, 1 otherwise
**************************************************/
static int verify(const uint8_t *a, const uint8_t *b, size_t len) {
return NSS_SecureMemcmp(a, b, len);
}
/*************************************************
* Name: cmov
*
* Description: Copy len bytes from x to r if b is 1;
* don't modify x if b is 0. Requires b to be in {0,1};
* assumes two's complement representation of negative integers.
* Runs in constant time.
*
* Arguments: uint8_t *r: pointer to output byte array
* const uint8_t *x: pointer to input byte array
* size_t len: Amount of bytes to be copied
* uint8_t b: Condition bit; has to be in {0,1}
**************************************************/
static void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b)
{
NSS_SecureSelect(r, r, x, len, b);
}
"""
)
for filename in headers:
x = tarball.extractfile(f"{topdir}/ref/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
x = remove_include_guard(x, filename.upper().replace(".", "_"))
x = remove_includes(x)
x = remove_kyber90s(x)
if filename not in ["kem.h", "fips202.h"]:
x = add_static_to_fns(x)
x = file_block(x, "ref/" + filename)
f.write(x.read())
for filename in sources:
x = tarball.extractfile(f"{topdir}/ref/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
x = remove_includes(x)
x = remove_kyber90s(x)
if filename not in ["kem.c", "fips202.c"]:
x = add_static_to_fns(x)
x = file_block(x, "ref/" + filename)
f.write(x.read())
print(f"* writing private header to {out_api}")
with open(out_api, "w") as f:
filename = "api.h"
comment.seek(0)
f.write(comment.read())
f.write(
"""
#ifndef KYBER_PQCRYSTALS_REF_H
#define KYBER_PQCRYSTALS_REF_H
"""
)
x = tarball.extractfile(f"{topdir}/ref/{filename}")
x = io.StringIO(x.read().decode("utf-8"))
x = remove_include_guard(x, filename.upper().replace(".", "_"))
x = file_block(x, "ref/" + filename)
f.write(x.read())
f.write(
f"""
#endif // KYBER_PQCRYSTALS_REF_H
"""
)
print(
f"""* done!
You should now:
1) Check the output by running `diff {out_orig} {out}`
2) Move {out} to lib/freebl/{out}
3) Move {out_api} to lib/freebl/{out_api}
4) Delete {out_orig} and {archive}.
"""
)

Просмотреть файл

@ -4206,6 +4206,11 @@ groupNameToNamedGroup(char *name)
return ssl_grp_ffdhe_8192;
}
}
if (PL_strlen(name) == 11) {
if (!strncmp(name, "xyber768d00", 11)) {
return ssl_grp_kem_xyber768d00;
}
}
return ssl_grp_none;
}

Просмотреть файл

@ -225,7 +225,8 @@ PrintParameterUsage()
"-Q enables ALPN for HTTP/1.1 [RFC7301]\n"
"-I comma separated list of enabled groups for TLS key exchange.\n"
" The following values are valid:\n"
" P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n"
" P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192,\n"
" xyber768d00\n"
"-J comma separated list of enabled signature schemes in preference order.\n"
" The following values are valid:\n"
" rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"

Просмотреть файл

@ -304,8 +304,9 @@ PrintParameterUsage()
fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
"%-20s The following values are valid:\n"
"%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
"-I", "", "");
"%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n"
"%-20s xyber768d00\n",
"-I", "", "", "");
fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n"
"%-20s The following values are valid:\n"
"%-20s rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"

Просмотреть файл

@ -10,4 +10,3 @@
*/
#error "Do not include this header file."

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -36,6 +36,7 @@
'dh_unittest.cc',
'ecl_unittest.cc',
'ghash_unittest.cc',
'kyber_unittest.cc',
'mpi_unittest.cc',
'prng_kat_unittest.cc',
'rsa_unittest.cc',

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,293 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
#include "gtest/gtest.h"
#include "blapi.h"
#include "nss_scoped_ptrs.h"
#include "kat/kyber768_kat.h"
namespace nss_test {
class Kyber768Test : public ::testing::Test {};
TEST(Kyber768Test, ConsistencyTest) {
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret2(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret2.get());
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES));
}
TEST(Kyber768Test, InvalidParameterTest) {
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber_invalid, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECFailure, rv);
rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Encapsulate(params_kyber_invalid, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECFailure, rv);
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Decapsulate(params_kyber_invalid, privateKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECFailure, rv);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
}
TEST(Kyber768Test, InvalidPublicKeyTest) {
ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7));
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
shortBuffer.get());
EXPECT_EQ(SECFailure, rv); // short publicKey buffer
}
TEST(Kyber768Test, InvalidCiphertextTest) {
ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7));
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret2(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
shortBuffer.get(), secret.get());
EXPECT_EQ(SECFailure, rv); // short ciphertext input
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
// Modify a random byte in the ciphertext
size_t pos;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos));
EXPECT_EQ(SECSuccess, rv);
uint8_t byte;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(ciphertext->len, KYBER768_CIPHERTEXT_BYTES);
ciphertext->data[pos % KYBER768_CIPHERTEXT_BYTES] ^= (byte | 1);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret2.get());
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_NE(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES));
}
TEST(Kyber768Test, InvalidPrivateKeyTest) {
ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7));
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret2(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber768_round3, nullptr,
shortBuffer.get(), publicKey.get());
EXPECT_EQ(SECFailure, rv); // short privateKey buffer
rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
// Modify a random byte in the private key
size_t pos;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos));
EXPECT_EQ(SECSuccess, rv);
uint8_t byte;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte));
EXPECT_EQ(SECSuccess, rv);
// Modifying the implicit rejection key will not cause decapsulation failure.
EXPECT_EQ(privateKey->len, KYBER768_PRIVATE_KEY_BYTES);
privateKey
->data[pos % (KYBER768_PRIVATE_KEY_BYTES - KYBER_SHARED_SECRET_BYTES)] ^=
(byte | 1);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret2.get());
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_NE(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES));
}
TEST(Kyber768Test, DecapsulationWithModifiedRejectionKeyTest) {
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret2(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret3(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv = Kyber_NewKey(params_kyber768_round3, nullptr, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
rv = Kyber_Encapsulate(params_kyber768_round3, nullptr, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
// Modify a random byte in the ciphertext and decapsulate it
size_t pos;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos));
EXPECT_EQ(SECSuccess, rv);
uint8_t byte;
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(ciphertext->len, KYBER768_CIPHERTEXT_BYTES);
ciphertext->data[pos % KYBER768_CIPHERTEXT_BYTES] ^= (byte | 1);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret2.get());
EXPECT_EQ(SECSuccess, rv);
// Now, modify a random byte in the implicit rejection key and try
// the decapsulation again. The result should be different.
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos));
EXPECT_EQ(SECSuccess, rv);
rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte));
EXPECT_EQ(SECSuccess, rv);
pos = (KYBER768_PRIVATE_KEY_BYTES - KYBER_SHARED_SECRET_BYTES) +
(pos % KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(privateKey->len, KYBER768_PRIVATE_KEY_BYTES);
privateKey->data[pos] ^= (byte | 1);
rv = Kyber_Decapsulate(params_kyber768_round3, privateKey.get(),
ciphertext.get(), secret3.get());
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(secret3->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_NE(0, memcmp(secret2->data, secret3->data, KYBER_SHARED_SECRET_BYTES));
}
TEST(Kyber768Test, KnownAnswersTest) {
ScopedSECItem privateKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PRIVATE_KEY_BYTES));
ScopedSECItem publicKey(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_PUBLIC_KEY_BYTES));
ScopedSECItem ciphertext(
SECITEM_AllocItem(nullptr, nullptr, KYBER768_CIPHERTEXT_BYTES));
ScopedSECItem secret(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
ScopedSECItem secret2(
SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES));
SECStatus rv;
uint8_t digest[SHA256_LENGTH];
for (const auto& kat : KyberKATs) {
SECItem keypair_seed = {siBuffer, (unsigned char*)kat.newKeySeed,
sizeof kat.newKeySeed};
SECItem enc_seed = {siBuffer, (unsigned char*)kat.encapsSeed,
sizeof kat.encapsSeed};
rv = Kyber_NewKey(kat.params, &keypair_seed, privateKey.get(),
publicKey.get());
EXPECT_EQ(SECSuccess, rv);
SHA256_HashBuf(digest, privateKey->data, privateKey->len);
EXPECT_EQ(0, memcmp(kat.privateKeyDigest, digest, sizeof digest));
SHA256_HashBuf(digest, publicKey->data, publicKey->len);
EXPECT_EQ(0, memcmp(kat.publicKeyDigest, digest, sizeof digest));
rv = Kyber_Encapsulate(kat.params, &enc_seed, publicKey.get(),
ciphertext.get(), secret.get());
EXPECT_EQ(SECSuccess, rv);
SHA256_HashBuf(digest, ciphertext->data, ciphertext->len);
EXPECT_EQ(0, memcmp(kat.ciphertextDigest, digest, sizeof digest));
EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(0, memcmp(kat.secret, secret->data, secret->len));
rv = Kyber_Decapsulate(kat.params, privateKey.get(), ciphertext.get(),
secret2.get());
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES);
EXPECT_EQ(0, memcmp(secret->data, secret2->data, secret2->len));
}
}
} // namespace nss_test

Просмотреть файл

@ -8,8 +8,9 @@ MODULE = nss
# we'll need to figure out how to get these symbols linked
# in before we include these tests:
# mpi_unittest.cc
# mpi_unittest.cc
# ghash_unittest.cc
# kyber_unittest.cc
CPPSRCS = \
dh_unittest.cc \
ecl_unittest.cc \

Просмотреть файл

@ -0,0 +1,239 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
/* The tests are taken from the RFC 9474. */
#include "gtest/gtest.h"
#include <stdint.h>
#include "blapi.h"
#include "nss_scoped_ptrs.h"
#include "secerr.h"
namespace nss_test {
class RSABlindTest : public ::testing::Test {
protected:
std::vector<uint8_t> hexStringToBytes(std::string s) {
std::vector<uint8_t> bytes;
for (size_t i = 0; i < s.length(); i += 2) {
bytes.push_back(std::stoul(s.substr(i, 2), nullptr, 16));
}
return bytes;
}
void TestRSABlind(HASH_HashType hashAlg, const size_t nLen,
std::string modulus_str, std::string e_str,
std::string d_str, std::string m_str, std::string salt_str,
std::string random_str, PRBool isDeterministic,
std::string sign_expected_str) {
std::vector<uint8_t> m = hexStringToBytes(m_str);
std::vector<uint8_t> salt = hexStringToBytes(salt_str);
std::vector<uint8_t> random = hexStringToBytes(random_str);
std::vector<uint8_t> signature_expected =
hexStringToBytes(sign_expected_str);
std::vector<uint8_t> modulus_v = hexStringToBytes(modulus_str);
std::vector<uint8_t> e_v = hexStringToBytes(e_str);
std::vector<uint8_t> d_v = hexStringToBytes(d_str);
SECItem empty = {siBuffer, nullptr, 0};
SECItem modulus = {siBuffer, modulus_v.data(),
(unsigned int)modulus_v.size()};
SECItem e = {siBuffer, e_v.data(), (unsigned int)e_v.size()};
SECItem d = {siBuffer, d_v.data(), (unsigned int)d_v.size()};
RSAPrivateKey key = {NULL, empty, modulus, e, d,
empty, empty, empty, empty, empty};
RSAPublicKey pkS = {NULL, key.modulus, key.publicExponent};
SECStatus rv = SECFailure;
size_t preparedMessageLen = m.size();
if (!isDeterministic) {
/* + 32 bytes of randomness. */
preparedMessageLen += 32;
}
std::vector<PRUint8> preparedMessage(nLen);
std::vector<PRUint8> blindedMsg(nLen);
std::vector<PRUint8> blindedSig(nLen);
std::vector<PRUint8> inv(nLen);
std::vector<PRUint8> signature(nLen);
PORT_Memset(preparedMessage.data(), 0, nLen);
PORT_Memset(blindedMsg.data(), 0, nLen);
PORT_Memset(blindedSig.data(), 0, nLen);
PORT_Memset(inv.data(), 0, nLen);
PORT_Memset(signature.data(), 0, nLen);
rv = RSABlinding_Prepare(preparedMessage.data(), preparedMessageLen,
m.data(), m.size(), isDeterministic);
EXPECT_EQ(SECSuccess, rv);
rv = RSABlinding_Blind(hashAlg, blindedMsg.data(), nLen, inv.data(), nLen,
preparedMessage.data(), preparedMessageLen,
salt.data(), salt.size(), &pkS, random.data(),
random.size());
EXPECT_EQ(SECSuccess, rv);
rv = RSABlinding_BlindSign(blindedSig.data(), nLen, blindedMsg.data(), nLen,
&key, &pkS);
EXPECT_EQ(SECSuccess, rv);
rv = RSABlinding_Finalize(hashAlg, signature.data(), preparedMessage.data(),
preparedMessageLen, blindedSig.data(), nLen,
inv.data(), nLen, &pkS, salt.size());
EXPECT_EQ(0, memcmp(signature.data(), signature_expected.data(), nLen));
EXPECT_EQ(rv, SECSuccess);
}
};
TEST_F(RSABlindTest, TestRSABlind) {
TestRSABlind(
HASH_AlgSHA384, 512,
"aec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635"
"c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6"
"c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f8"
"9b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472ae"
"d74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dc"
"af9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c"
"2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda9420497455"
"7ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd"
"2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c6"
"3a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215"
"fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14ac"
"fc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e"
"5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae8"
"4f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc"
"19b3b32948bdead5",
"010001",
"0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1"
"f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71"
"cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60"
"cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45"
"c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b"
"49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1"
"b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb3210"
"0b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c368"
"0a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a"
"73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db"
"690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a"
"3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d"
"7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3"
"c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e2"
"41f4ecfeb877a051",
"8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfe"
"c5fdbb36331372ebefedae7d",
"051722b35f458781397c3a671a7d3bd3096503940e4c4f1aaa269d60300ce449555cd734"
"0100df9d46944c5356825abf",
"44f6af51f31e03943acf6fb47e805ce4794cb0861772d78890952d20f7aa76a2b841f18d"
"290f6e02beda82f7d2a560ffd7af727019269699e67dbf8e7f60946515b253b9cda85706"
"984ffb3176633e5135e73ca0bf8371df50a170286fb56399a0fd093d1a16b62ea5a60096"
"0016e14f0079e7aa5824676adddea4ebaca2ec0473b462b8a50d57c962c1fcd68949f46f"
"62beb9867f04db169508f0a3c8df0f67149b1425a0e1fc0321f0ab55b9208d515cfa8be6"
"d82e7273f7c59b861c24b82dd379809fc0a21783ecc247d2e431311658359e7d18095327"
"26536b89ccf684269eff88a9a33898091d28d6ffae70185d6cc8699c177dff5db4849e74"
"b259405675b01c53eecc5ec03819ce000cf79f3da883653b85b3822e27d130791d67e339"
"554d75393b2c210bf6f684b7c0f4a953187959563269d6ece8fa9a28b786b095ef81564c"
"e02cfb68ec801258704b9311f6ef5aaf7cdac4266931e462364c27b4468689e9906aabe6"
"669aebdc67510c7bc5016083b862039aacbee7ca15ae62b6b35287538adab56d2c9220bf"
"b14e91e6ea4f42a159aeb3dbaffbea17b012594ed8f939411ea1e9177ec9a4cb3168463b"
"a603340b2858d76bf8f9ae6197e2cdf0dd5636b32ea383ed377bd7f655ac8078a5bc49de"
"a8cf27b2dcc22d81d734ea8d5c1643b3082fd1627933305fe962f326e614a3f3a74dac61"
"ac09439a3e05f255",
PR_TRUE,
"6fef8bf9bc182cd8cf7ce45c7dcf0e6f3e518ae48f06f3c670c649ac737a8b8119a34d51"
"641785be151a697ed7825fdfece82865123445eab03eb4bb91cecf4d6951738495f84811"
"51b62de869658573df4e50a95c17c31b52e154ae26a04067d5ecdc1592c287550bb982a5"
"bb9c30fd53a768cee6baabb3d483e9f1e2da954c7f4cf492fe3944d2fe456c1ecaf08403"
"69e33fb4010e6b44bb1d721840513524d8e9a3519f40d1b81ae34fb7a31ee6b7ed641cb1"
"6c2ac999004c2191de0201457523f5a4700dd649267d9286f5c1d193f1454c9f868a5781"
"6bf5ff76c838a2eeb616a3fc9976f65d4371deecfbab29362caebdff69c635fe5a2113da"
"4d4d8c24f0b16a0584fa05e80e607c5d9a2f765f1f069f8d4da21f27c2a3b5c984b4ab24"
"899bef46c6d9323df4862fe51ce300fca40fb539c3bb7fe2dcc9409e425f2d3b95e70e9c"
"49c5feb6ecc9d43442c33d50003ee936845892fb8be475647da9a080f5bc7f8a716590b3"
"745c2209fe05b17992830ce15f32c7b22cde755c8a2fe50bd814a0434130b807dc1b7218"
"d4e85342d70695a5d7f29306f25623ad1e8aa08ef71b54b8ee447b5f64e73d09bdd6c3b7"
"ca224058d7c67cc7551e9241688ada12d859cb7646fbd3ed8b34312f3b49d69802f0eaa1"
"1bc4211c2f7a29cd5c01ed01a39001c5856fab36228f5ee2f2e1110811872fe7c865c42e"
"d59029c706195d52"
);
}
TEST_F(RSABlindTest, TestRSABlindEmptySalt) {
TestRSABlind(
HASH_AlgSHA384, 512,
"aec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635"
"c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6"
"c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f8"
"9b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472ae"
"d74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dc"
"af9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c"
"2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda9420497455"
"7ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd"
"2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c6"
"3a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215"
"fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14ac"
"fc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e"
"5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae8"
"4f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc"
"19b3b32948bdead5",
"010001",
"0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1"
"f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71"
"cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60"
"cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45"
"c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b"
"49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1"
"b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb3210"
"0b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c368"
"0a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a"
"73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db"
"690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a"
"3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d"
"7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3"
"c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e2"
"41f4ecfeb877a051",
"8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfe"
"c5fdbb36331372ebefedae7d",
"",
"44f6af51f31e03943acf6fb47e805ce4794cb0861772d78890952d20f7aa76a2b841f18d"
"290f6e02beda82f7d2a560ffd7af727019269699e67dbf8e7f60946515b253b9cda85706"
"984ffb3176633e5135e73ca0bf8371df50a170286fb56399a0fd093d1a16b62ea5a60096"
"0016e14f0079e7aa5824676adddea4ebaca2ec0473b462b8a50d57c962c1fcd68949f46f"
"62beb9867f04db169508f0a3c8df0f67149b1425a0e1fc0321f0ab55b9208d515cfa8be6"
"d82e7273f7c59b861c24b82dd379809fc0a21783ecc247d2e431311658359e7d18095327"
"26536b89ccf684269eff88a9a33898091d28d6ffae70185d6cc8699c177dff5db4849e74"
"b259405675b01c53eecc5ec03819ce000cf79f3da883653b85b3822e27d130791d67e339"
"554d75393b2c210bf6f684b7c0f4a953187959563269d6ece8fa9a28b786b095ef81564c"
"e02cfb68ec801258704b9311f6ef5aaf7cdac4266931e462364c27b4468689e9906aabe6"
"669aebdc67510c7bc5016083b862039aacbee7ca15ae62b6b35287538adab56d2c9220bf"
"b14e91e6ea4f42a159aeb3dbaffbea17b012594ed8f939411ea1e9177ec9a4cb3168463b"
"a603340b2858d76bf8f9ae6197e2cdf0dd5636b32ea383ed377bd7f655ac8078a5bc49de"
"a8cf27b2dcc22d81d734ea8d5c1643b3082fd1627933305fe962f326e614a3f3a74dac61"
"ac09439a3e05f255",
PR_TRUE,
"4454b6983ff01cb28545329f394936efa42ed231e15efbc025fdaca00277acf0c8e00e3d"
"8b0ecebd35b057b8ebfc14e1a7097368a4abd20b555894ccef3d1b9528c6bcbda6b95376"
"bef230d0f1feff0c1064c62c60a7ae7431d1fdfa43a81eed9235e363e1ffa0b2797aba6a"
"ad6082fcd285e14fc8b71de6b9c87cb4059c7dc1e96ae1e63795a1e9af86b9073d1d848a"
"ef3eca8a03421bcd116572456b53bcfd4dabb0a9691f1fabda3ed0ce357aee2cfee5b1a0"
"eb226f69716d4e011d96eede5e38a9acb531a64336a0d5b0bae3ab085b658692579a3767"
"40ff6ce69e89b06f360520b864e33d82d029c808248a19e18e31f0ecd16fac5cd4870f8d"
"3ebc1c32c718124152dc905672ab0b7af48bf7d1ac1ff7b9c742549c91275ab105458ae3"
"7621757add83482bbcf779e777bbd61126e93686635d4766aedf5103cf7978f3856ccac9"
"e28d21a850dbb03c811128616d315d717be1c2b6254f8509acae862042c034530329ce15"
"ca2e2f6b1f5fd59272746e3918c748c0eb810bf76884fa10fcf749326bbfaa5ba285a018"
"6a22e4f628dbf178d3bb5dc7e165ca73f6a55ecc14c4f5a26c4693ce5da032264cbec319"
"b12ddb9787d0efa4fcf1e5ccee35ad85ecd453182df9ed735893f830b570faae8be0f6fe"
"2e571a4e0d927cba4debd368d3b4fca33ec6251897a137cf75474a32ac8256df5e5ffa51"
"8b88b43fb6f63a24"
);
}
} // namespace nss_test

Просмотреть файл

@ -84,6 +84,30 @@ SECOidTag JsonReader::ReadHash() {
return SEC_OID_UNKNOWN;
}
SECStatus JsonReader::ReadSECStatus() {
std::string s = ReadString();
if (s == "SECSuccess") {
return SECSuccess;
} else if (s == "SECFailure") {
return SECFailure;
} else if (s == "SECWouldBlock") {
return SECWouldBlock;
}
ADD_FAILURE() << "unknown SECStatus";
return SECFailure;
}
bool JsonReader::ReadBool() {
std::string s = ReadString();
if (s == "true") {
return true;
} else if (s == "false") {
return false;
}
ADD_FAILURE() << "not a bool";
return false;
}
bool JsonReader::NextItem(uint8_t h, uint8_t t) {
SkipWhitespace();
switch (uint8_t c = take()) {

Просмотреть файл

@ -39,6 +39,8 @@ class JsonReader {
std::string ReadLabel();
std::vector<uint8_t> ReadHex();
SECOidTag ReadHash();
SECStatus ReadSECStatus();
bool ReadBool();
bool NextItem(uint8_t h = '{', uint8_t t = '}');
bool NextItemArray() { return NextItem('[', ']'); }

Просмотреть файл

@ -29,6 +29,7 @@ CPPSRCS = \
pk11_ike_unittest.cc \
pk11_import_unittest.cc \
pk11_kbkdf.cc \
pk11_kem_unittest.cc \
pk11_keygen.cc \
pk11_key_unittest.cc \
pk11_module_unittest.cc \
@ -41,6 +42,7 @@ CPPSRCS = \
pk11_rsapss_unittest.cc \
pk11_signature_test.cc \
pk11_seed_cbc_unittest.cc \
pk11_symkey_unittest.cc \
$(NULL)
DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\"

Просмотреть файл

@ -9,9 +9,11 @@
#include "pk11pub.h"
#include "testvectors/kw-vectors.h"
#include "testvectors/kwp-vectors.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include "json_reader.h"
extern std::string g_source_dir;
namespace nss_test {
@ -107,17 +109,61 @@ class Pkcs11AESKeyWrapKwpTest
}
}
}
};
void WrapUnwrap(keywrap_vector testvector) {
TEST_F(Pkcs11AESKeyWrapKwpTest, TestVectors) {
std::string testvectors =
::g_source_dir + "/../common/testvectors/kwp-vectors.json";
JsonReader r(testvectors);
r.NextItem();
ASSERT_EQ("numberOfTests", r.ReadLabel());
uint64_t expected_count = r.ReadInt();
uint64_t count = 0;
r.NextItem();
ASSERT_EQ("tests", r.ReadLabel());
while (r.NextItemArray()) {
count++;
keywrap_vector testvector;
uint8_t seen = 0;
while (r.NextItem()) {
std::string n = r.ReadLabel();
if (n == "tcId") {
seen |= 1;
testvector.test_id = r.ReadInt();
} else if (n == "key") {
seen |= 2;
testvector.key = r.ReadHex();
} else if (n == "msg") {
seen |= 4;
testvector.msg = r.ReadHex();
} else if (n == "ct") {
seen |= 8;
testvector.ct = r.ReadHex();
} else if (n == "wrapRv") {
seen |= 16;
testvector.tests[Action::WRAP].expect_rv = r.ReadSECStatus();
} else if (n == "wrapMatch") {
seen |= 32;
testvector.tests[Action::WRAP].output_match = r.ReadBool();
} else if (n == "unwrapRv") {
seen |= 64;
testvector.tests[Action::UNWRAP].expect_rv = r.ReadSECStatus();
} else if (n == "unwrapMatch") {
seen |= 128;
testvector.tests[Action::UNWRAP].output_match = r.ReadBool();
}
}
EXPECT_EQ(seen, 255);
WrapUnwrap(testvector.key.data(), testvector.key.size(),
testvector.msg.data(), testvector.msg.size(),
testvector.ct.data(), testvector.ct.size(), testvector.tests,
testvector.test_id);
}
};
EXPECT_EQ(count, expected_count);
}
TEST_P(Pkcs11AESKeyWrapKwpTest, TestVectors) { WrapUnwrap(GetParam()); }
INSTANTIATE_TEST_SUITE_P(Pkcs11NistAESKWPTest, Pkcs11AESKeyWrapKwpTest,
::testing::ValuesIn(kNistAesKWPVectors));
} // namespace nss_test

Просмотреть файл

@ -34,6 +34,7 @@
'pk11_ike_unittest.cc',
'pk11_import_unittest.cc',
'pk11_kbkdf.cc',
'pk11_kem_unittest.cc',
'pk11_keygen.cc',
'pk11_key_unittest.cc',
'pk11_module_unittest.cc',
@ -45,6 +46,7 @@
'pk11_rsapkcs1_unittest.cc',
'pk11_rsapss_unittest.cc',
'pk11_seed_cbc_unittest.cc',
'pk11_symkey_unittest.cc',
'pk11_signature_test.cc',
'<(DEPTH)/gtests/common/gtests.cc'
],

Просмотреть файл

@ -89,6 +89,8 @@ class Pk11KeyImportTestBase : public ::testing::Test {
return pub_key->u.dh.publicValue;
case ecKey:
return pub_key->u.ec.publicValue;
case kyberKey:
return pub_key->u.kyber.publicValue;
case fortezzaKey: /* depricated */
case nullKey:
/* didn't use default here so we can catch new key types at compile time

Просмотреть файл

@ -0,0 +1,118 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include "pk11_keygen.h"
#include "pk11pub.h"
#include "blapi.h"
namespace nss_test {
class Pkcs11KEMTest : public ::testing::Test {
protected:
PK11SymKey *Encapsulate(const ScopedSECKEYPublicKey &pub,
CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags,
CK_FLAGS opFlags, ScopedSECItem *ciphertext) {
PK11SymKey *sharedSecretRawPtr;
SECItem *ciphertextRawPtr;
EXPECT_EQ(SECSuccess,
PK11_Encapsulate(pub.get(), target, attrFlags, opFlags,
&sharedSecretRawPtr, &ciphertextRawPtr));
ciphertext->reset(ciphertextRawPtr);
return sharedSecretRawPtr;
}
PK11SymKey *Decapsulate(const ScopedSECKEYPrivateKey &priv,
const ScopedSECItem &ciphertext,
CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags,
CK_FLAGS opFlags) {
PK11SymKey *sharedSecretRawPtr;
EXPECT_EQ(SECSuccess,
PK11_Decapsulate(priv.get(), ciphertext.get(), target, attrFlags,
opFlags, &sharedSecretRawPtr));
return sharedSecretRawPtr;
}
SECItem *getRawKeyData(const ScopedPK11SymKey &key) {
SECStatus rv = PK11_ExtractKeyValue(key.get());
EXPECT_EQ(SECSuccess, rv);
SECItem *keyData = PK11_GetKeyData(key.get());
EXPECT_NE(nullptr, keyData);
EXPECT_NE(nullptr, keyData->data);
return keyData;
}
void checkSymKeyAttributeValue(const ScopedPK11SymKey &key,
CK_ATTRIBUTE_TYPE attr,
uint8_t *expectedValue) {
SECItem attrValue;
EXPECT_EQ(SECSuccess, PK11_ReadRawAttribute(PK11_TypeSymKey, key.get(),
attr, &attrValue));
EXPECT_EQ(0, memcmp(expectedValue, attrValue.data, attrValue.len));
SECITEM_FreeItem(&attrValue, PR_FALSE);
}
};
TEST_F(Pkcs11KEMTest, KemConsistencyTest) {
Pkcs11KeyPairGenerator generator(CKM_NSS_KYBER_KEY_PAIR_GEN);
ScopedSECKEYPrivateKey priv;
ScopedSECKEYPublicKey pub;
generator.GenerateKey(&priv, &pub, false);
ASSERT_EQ((unsigned int)KYBER768_PUBLIC_KEY_BYTES,
(unsigned int)pub->u.kyber.publicValue.len);
// Copy the public key to simulate receiving the key as an octet string
ScopedSECKEYPublicKey pubCopy(SECKEY_CopyPublicKey(pub.get()));
ASSERT_NE(nullptr, pubCopy);
ScopedPK11SlotInfo slot(PK11_GetBestSlot(CKM_NSS_KYBER, nullptr));
ASSERT_NE(nullptr, slot);
ASSERT_NE((unsigned int)CK_INVALID_HANDLE,
PK11_ImportPublicKey(slot.get(), pubCopy.get(), PR_FALSE));
ScopedSECItem ciphertext;
ScopedPK11SymKey sharedSecret(Encapsulate(
pubCopy, CKM_SALSA20_POLY1305, PK11_ATTR_PRIVATE | PK11_ATTR_UNMODIFIABLE,
CKF_ENCRYPT, &ciphertext));
ASSERT_EQ((unsigned int)KYBER768_CIPHERTEXT_BYTES,
(unsigned int)ciphertext->len);
ASSERT_EQ(CKM_SALSA20_POLY1305, PK11_GetMechanism(sharedSecret.get()));
CK_BBOOL ckTrue = CK_TRUE;
CK_BBOOL ckFalse = CK_FALSE;
checkSymKeyAttributeValue(sharedSecret, CKA_PRIVATE, &ckTrue);
checkSymKeyAttributeValue(sharedSecret, CKA_MODIFIABLE, &ckFalse);
checkSymKeyAttributeValue(sharedSecret, CKA_ENCRYPT, &ckTrue);
ScopedPK11SymKey sharedSecret2(
Decapsulate(priv, ciphertext, CKM_SALSA20_POLY1305,
PK11_ATTR_PRIVATE | PK11_ATTR_UNMODIFIABLE, CKF_ENCRYPT));
ASSERT_EQ(CKM_SALSA20_POLY1305, PK11_GetMechanism(sharedSecret2.get()));
checkSymKeyAttributeValue(sharedSecret2, CKA_PRIVATE, &ckTrue);
checkSymKeyAttributeValue(sharedSecret2, CKA_MODIFIABLE, &ckFalse);
checkSymKeyAttributeValue(sharedSecret2, CKA_ENCRYPT, &ckTrue);
EXPECT_EQ(0, SECITEM_CompareItem(getRawKeyData(sharedSecret),
getRawKeyData(sharedSecret2)));
}
} // namespace nss_test

Просмотреть файл

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "kyber.h"
#include "pk11_keygen.h"
#include "pk11pub.h"
@ -104,6 +105,15 @@ class EcParamHolder : public ParamHolder {
std::unique_ptr<uint8_t[]> extra_;
};
class KyberParamHolder : public ParamHolder {
public:
KyberParamHolder(CK_NSS_KEM_PARAMETER_SET_TYPE aParams) : mParams(aParams) {}
void* get() override { return &mParams; }
private:
CK_NSS_KEM_PARAMETER_SET_TYPE mParams;
};
std::unique_ptr<ParamHolder> Pkcs11KeyPairGenerator::MakeParams() const {
switch (mech_) {
case CKM_RSA_PKCS_KEY_PAIR_GEN:
@ -136,6 +146,11 @@ std::unique_ptr<ParamHolder> Pkcs11KeyPairGenerator::MakeParams() const {
std::cerr << "Generate EC pair on " << curve_ << std::endl;
return std::unique_ptr<ParamHolder>(new EcParamHolder(curve_));
case CKM_NSS_KYBER_KEY_PAIR_GEN:
std::cerr << "Generate Kyber768 pair" << std::endl;
return std::unique_ptr<ParamHolder>(
new KyberParamHolder(CKP_NSS_KYBER_768_ROUND3));
default:
ADD_FAILURE() << "unknown OID " << mech_;
}

Просмотреть файл

@ -0,0 +1,155 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include <assert.h>
#include <limits.h>
#include <prinit.h>
#include <nss.h>
#include <pk11pub.h>
namespace nss_test {
uint8_t kKeyData[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
SECItem kFull = {siBuffer, (unsigned char *)kKeyData, 16};
SECItem kLeftHalf = {siBuffer, (unsigned char *)kKeyData, 8};
SECItem kRightHalf = {siBuffer, (unsigned char *)kKeyData + 8, 8};
class Pkcs11SymKeyTest : public ::testing::Test {
protected:
PK11SymKey *ImportSymKey(PK11SlotInfo *slot, SECItem *key_data) {
PK11SymKey *out = PK11_ImportSymKey(slot, CKM_NULL, PK11_OriginUnwrap,
CKA_DERIVE, key_data, nullptr);
EXPECT_NE(nullptr, out);
return out;
}
void CheckKeyData(SECItem &expected, PK11SymKey *actual) {
ASSERT_NE(nullptr, actual);
SECStatus rv = PK11_ExtractKeyValue(actual);
ASSERT_EQ(SECSuccess, rv);
SECItem *keyData = PK11_GetKeyData(actual);
ASSERT_NE(nullptr, keyData);
ASSERT_NE(nullptr, keyData->data);
ASSERT_EQ(expected.len, keyData->len);
ASSERT_EQ(0, memcmp(expected.data, keyData->data, keyData->len));
}
void SetSensitive(PK11SymKey *key) {
ASSERT_NE(nullptr, key);
CK_BBOOL cktrue = CK_TRUE;
SECItem attrValue = {siBuffer, &cktrue, sizeof(CK_BBOOL)};
EXPECT_EQ(SECSuccess, PK11_WriteRawAttribute(PK11_TypeSymKey, key,
CKA_SENSITIVE, &attrValue));
}
void CheckIsSensitive(PK11SymKey *key) {
ASSERT_NE(nullptr, key);
StackSECItem attrValue;
ASSERT_EQ(SECSuccess, PK11_ReadRawAttribute(PK11_TypeSymKey, key,
CKA_SENSITIVE, &attrValue));
ASSERT_EQ(attrValue.len, sizeof(CK_BBOOL));
EXPECT_EQ(*(CK_BBOOL *)attrValue.data, CK_TRUE);
}
void SetNotExtractable(PK11SymKey *key) {
ASSERT_NE(nullptr, key);
CK_BBOOL ckfalse = CK_FALSE;
SECItem attrValue = {siBuffer, &ckfalse, sizeof(CK_BBOOL)};
EXPECT_EQ(SECSuccess, PK11_WriteRawAttribute(PK11_TypeSymKey, key,
CKA_EXTRACTABLE, &attrValue));
}
void CheckIsNotExtractable(PK11SymKey *key) {
ASSERT_NE(nullptr, key);
StackSECItem attrValue;
ASSERT_EQ(SECSuccess, PK11_ReadRawAttribute(PK11_TypeSymKey, key,
CKA_EXTRACTABLE, &attrValue));
ASSERT_EQ(attrValue.len, sizeof(CK_BBOOL));
EXPECT_EQ(*(CK_BBOOL *)attrValue.data, CK_FALSE);
}
};
TEST_F(Pkcs11SymKeyTest, ConcatSymKeyTest) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_NE(nullptr, slot);
ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf));
ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf));
ScopedPK11SymKey key(
PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckKeyData(kFull, key.get());
}
// Test that the derived key is sensitive if either input is.
TEST_F(Pkcs11SymKeyTest, SensitiveConcatSymKeyTest) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_NE(nullptr, slot);
ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf));
SetSensitive(left.get());
ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf));
ScopedPK11SymKey key(
PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckIsSensitive(key.get());
// Again with left and right swapped
ScopedPK11SymKey key2(
PK11_ConcatSymKeys(right.get(), left.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckIsSensitive(key2.get());
}
// Test that the derived key is extractable if either input is.
TEST_F(Pkcs11SymKeyTest, NotExtractableConcatSymKeyTest) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_NE(nullptr, slot);
ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf));
SetNotExtractable(left.get());
ScopedPK11SymKey right(ImportSymKey(slot.get(), &kRightHalf));
ScopedPK11SymKey key(
PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckIsNotExtractable(key.get());
ScopedPK11SymKey key2(
PK11_ConcatSymKeys(right.get(), left.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckIsNotExtractable(key2.get());
}
// Test that keys in different slots are moved to the same slot for derivation.
// The PK11SymKey.data fields are set in PK11_ImportSymKey, so this just
// re-imports the key data.
TEST_F(Pkcs11SymKeyTest, CrossSlotConcatSymKeyTest) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_NE(nullptr, slot);
ScopedPK11SlotInfo slot2(PK11_GetInternalKeySlot());
ASSERT_NE(nullptr, slot2);
EXPECT_NE(slot, slot2);
ScopedPK11SymKey left(ImportSymKey(slot.get(), &kLeftHalf));
ScopedPK11SymKey right(ImportSymKey(slot2.get(), &kRightHalf));
ScopedPK11SymKey key(
PK11_ConcatSymKeys(left.get(), right.get(), CKM_HKDF_DERIVE, CKA_DERIVE));
CheckKeyData(kFull, key.get());
}
} // namespace nss_test

Просмотреть файл

@ -59,6 +59,7 @@ CPPSRCS = \
tls_psk_unittest.cc \
tls_subcerts_unittest.cc \
tls_ech_unittest.cc \
tls_xyber_unittest.cc \
$(SSLKEYLOGFILE_FILES) \
$(NULL)

Просмотреть файл

@ -59,7 +59,8 @@
'tls_protect.cc',
'tls_psk_unittest.cc',
'tls_subcerts_unittest.cc',
'tls_grease_unittest.cc'
'tls_grease_unittest.cc',
'tls_xyber_unittest.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',

Просмотреть файл

@ -490,16 +490,19 @@ void TlsAgent::DisableAllCiphers() {
}
}
// Not actually all groups, just the onece that we are actually willing
// Not actually all groups, just the ones that we are actually willing
// to use.
const std::vector<SSLNamedGroup> kAllDHEGroups = {
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192};
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192,
ssl_grp_kem_xyber768d00,
};
const std::vector<SSLNamedGroup> kECDHEGroups = {
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1};
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
ssl_grp_ec_secp521r1, ssl_grp_kem_xyber768d00,
};
const std::vector<SSLNamedGroup> kFFDHEGroups = {
ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_ffdhe_4096,
@ -508,7 +511,12 @@ const std::vector<SSLNamedGroup> kFFDHEGroups = {
// Defined because the big DHE groups are ridiculously slow.
const std::vector<SSLNamedGroup> kFasterDHEGroups = {
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072};
ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_kem_xyber768d00,
};
const std::vector<SSLNamedGroup> kEcdhHybridGroups = {
ssl_grp_kem_xyber768d00,
};
void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) {
EXPECT_TRUE(EnsureTlsSetup());
@ -536,6 +544,9 @@ void TlsAgent::EnableGroupsByKeyExchange(SSLKEAType kea) {
case ssl_kea_ecdh:
ConfigNamedGroups(kECDHEGroups);
break;
case ssl_kea_ecdh_hybrid:
ConfigNamedGroups(kEcdhHybridGroups);
break;
default:
break;
}
@ -672,6 +683,7 @@ void TlsAgent::CheckKEA(SSLKEAType kea, SSLNamedGroup kea_group,
if (kea_size == 0) {
switch (kea_group) {
case ssl_grp_ec_curve25519:
case ssl_grp_kem_xyber768d00:
kea_size = 255;
break;
case ssl_grp_ec_secp256r1:

Просмотреть файл

@ -55,6 +55,7 @@ const extern std::vector<SSLNamedGroup> kAllDHEGroups;
const extern std::vector<SSLNamedGroup> kECDHEGroups;
const extern std::vector<SSLNamedGroup> kFFDHEGroups;
const extern std::vector<SSLNamedGroup> kFasterDHEGroups;
const extern std::vector<SSLNamedGroup> kEcdhHybridGroups;
// These functions are called from callbacks. They use bare pointers because
// TlsAgent sets up the callback and it doesn't know who owns it.

Просмотреть файл

@ -0,0 +1,273 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ssl.h"
#include "sslerr.h"
#include "sslproto.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
#include "nss_scoped_ptrs.h"
#include "tls_connect.h"
#include "tls_filter.h"
#include "tls_parser.h"
namespace nss_test {
TEST_P(TlsKeyExchangeTest13, Xyber768d00Supported) {
EnsureKeyShareSetup();
ConfigNamedGroups({ssl_grp_kem_xyber768d00});
Connect();
CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_xyber768d00, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsKeyExchangeTest, Tls12ClientXyber768d00NotSupported) {
EnsureKeyShareSetup();
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
client_->DisableAllCiphers();
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(
client_->ssl_fd(),
kECDHEGroups.size() + kEcdhHybridGroups.size()));
Connect();
std::vector<SSLNamedGroup> groups = GetGroupDetails(groups_capture_);
for (auto group : groups) {
EXPECT_NE(group, ssl_grp_kem_xyber768d00);
}
}
TEST_P(TlsKeyExchangeTest13, Tls12ServerXyber768d00NotSupported) {
if (variant_ == ssl_variant_datagram) {
/* Bug 1874451 - reenable this test */
return;
}
EnsureKeyShareSetup();
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
client_->DisableAllCiphers();
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
client_->ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519});
EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
server_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
server_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
server_->ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519});
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsKeyExchangeTest13, Xyber768d00DisabledByPolicy) {
EnsureKeyShareSetup();
ConfigNamedGroups({ssl_grp_kem_xyber768d00, ssl_grp_ec_secp256r1});
ASSERT_EQ(SECSuccess, NSS_SetAlgorithmPolicy(SEC_OID_XYBER768D00, 0,
NSS_USE_ALG_IN_SSL_KX));
ASSERT_EQ(SECSuccess, NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY,
NSS_USE_POLICY_IN_SSL, 0));
Connect();
CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
ASSERT_EQ(SECSuccess, NSS_SetAlgorithmPolicy(SEC_OID_XYBER768D00,
NSS_USE_ALG_IN_SSL_KX, 0));
ASSERT_EQ(SECSuccess, NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY,
NSS_USE_POLICY_IN_SSL, 0));
}
class XyberShareDamager : public TlsExtensionFilter {
public:
typedef enum {
downgrade,
extend,
truncate,
zero_ecdh,
modify_ecdh,
modify_kyber,
} damage_type;
XyberShareDamager(const std::shared_ptr<TlsAgent>& a, damage_type damage)
: TlsExtensionFilter(a), damage_(damage) {}
virtual PacketFilter::Action FilterExtension(uint16_t extension_type,
const DataBuffer& input,
DataBuffer* output) {
if (extension_type != ssl_tls13_key_share_xtn) {
return KEEP;
}
// Find the Xyber768d00 share
size_t offset = 0;
if (agent()->role() == TlsAgent::CLIENT) {
offset += 2; // skip KeyShareClientHello length
}
uint32_t named_group;
uint32_t named_group_len;
input.Read(offset, 2, &named_group);
input.Read(offset + 2, 2, &named_group_len);
while (named_group != ssl_grp_kem_xyber768d00) {
offset += 2 + 2 + named_group_len;
input.Read(offset, 2, &named_group);
input.Read(offset + 2, 2, &named_group_len);
}
EXPECT_EQ(named_group, ssl_grp_kem_xyber768d00);
DataBuffer xyber_key_share(input.data() + offset, 2 + 2 + named_group_len);
// Damage the Xyber768d00 share
unsigned char* ecdh_component = xyber_key_share.data() + 2 + 2;
unsigned char* kyber_component =
xyber_key_share.data() + 2 + 2 + X25519_PUBLIC_KEY_BYTES;
switch (damage_) {
case XyberShareDamager::downgrade:
// Downgrade a Xyber768d00 share to X25519
xyber_key_share.Truncate(2 + 2 + X25519_PUBLIC_KEY_BYTES);
xyber_key_share.Write(0, ssl_grp_ec_curve25519, 2);
xyber_key_share.Write(2, X25519_PUBLIC_KEY_BYTES, 2);
break;
case XyberShareDamager::truncate:
// Truncate a Xyber768d00 share after the X25519 component
xyber_key_share.Truncate(2 + 2 + X25519_PUBLIC_KEY_BYTES);
xyber_key_share.Write(2, X25519_PUBLIC_KEY_BYTES, 2);
break;
case XyberShareDamager::extend:
// Append 4 bytes to a Xyber768d00 share
uint32_t current_len;
xyber_key_share.Read(2, 2, &current_len);
xyber_key_share.Write(xyber_key_share.len(), current_len, 4);
xyber_key_share.Write(2, current_len + 4, 2);
break;
case XyberShareDamager::zero_ecdh:
// Replace an X25519 component with 0s
memset(ecdh_component, 0, X25519_PUBLIC_KEY_BYTES);
break;
case XyberShareDamager::modify_ecdh:
// Flip a bit in the X25519 component
ecdh_component[0] ^= 0x01;
break;
case XyberShareDamager::modify_kyber:
// Flip a bit in the Kyber component
kyber_component[0] ^= 0x01;
break;
}
*output = input;
output->Splice(xyber_key_share, offset, 2 + 2 + named_group_len);
// Fix the KeyShareClientHello length if necessary
if (agent()->role() == TlsAgent::CLIENT &&
xyber_key_share.len() != 2 + 2 + named_group_len) {
output->Write(0, output->len() - 2, 2);
}
return CHANGE;
}
private:
damage_type damage_;
};
class TlsXyberDamageTest
: public TlsConnectTestBase,
public ::testing::WithParamInterface<XyberShareDamager::damage_type> {
public:
TlsXyberDamageTest()
: TlsConnectTestBase(ssl_variant_stream, SSL_LIBRARY_VERSION_TLS_1_3) {}
protected:
void Damage(const std::shared_ptr<TlsAgent>& agent) {
EnsureTlsSetup();
client_->ConfigNamedGroups(
{ssl_grp_ec_curve25519, ssl_grp_kem_xyber768d00});
server_->ConfigNamedGroups(
{ssl_grp_kem_xyber768d00, ssl_grp_ec_curve25519});
EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
MakeTlsFilter<XyberShareDamager>(agent, GetParam());
}
};
TEST_P(TlsXyberDamageTest, DamageClientShare) {
Damage(client_);
switch (GetParam()) {
case XyberShareDamager::extend:
case XyberShareDamager::truncate:
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
break;
case XyberShareDamager::zero_ecdh:
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SEC_ERROR_INVALID_KEY);
break;
case XyberShareDamager::downgrade:
case XyberShareDamager::modify_ecdh:
case XyberShareDamager::modify_kyber:
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
break;
}
}
TEST_P(TlsXyberDamageTest, DamageServerShare) {
Damage(server_);
switch (GetParam()) {
case XyberShareDamager::extend:
case XyberShareDamager::truncate:
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
break;
case XyberShareDamager::zero_ecdh:
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
ConnectExpectFail();
client_->CheckErrorCode(SEC_ERROR_INVALID_KEY);
break;
case XyberShareDamager::downgrade:
case XyberShareDamager::modify_ecdh:
case XyberShareDamager::modify_kyber:
client_->ExpectSendAlert(kTlsAlertBadRecordMac);
server_->ExpectSendAlert(kTlsAlertBadRecordMac);
ConnectExpectFail();
client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
break;
}
}
INSTANTIATE_TEST_SUITE_P(TlsXyberDamageTest, TlsXyberDamageTest,
::testing::Values(XyberShareDamager::downgrade,
XyberShareDamager::extend,
XyberShareDamager::truncate,
XyberShareDamager::zero_ecdh,
XyberShareDamager::modify_ecdh,
XyberShareDamager::modify_kyber));
} // namespace nss_test

Просмотреть файл

@ -5,6 +5,7 @@
#define _KEYTHI_H_ 1
#include "eccutil.h"
#include "kyber.h"
#include "plarena.h"
#include "pkcs11t.h"
#include "secmodt.h"
@ -33,7 +34,8 @@ typedef enum {
keaKey = 5, /* deprecated */
ecKey = 6,
rsaPssKey = 7,
rsaOaepKey = 8
rsaOaepKey = 8,
kyberKey = 9,
} KeyType;
/*
@ -174,6 +176,16 @@ struct SECKEYKEAPublicKeyStr {
};
typedef struct SECKEYKEAPublicKeyStr SECKEYKEAPublicKey;
/*
** Kyber Public Key structure
*/
struct SECKEYKyberPublicKeyStr {
KyberParams params;
SECItem publicValue;
};
typedef struct SECKEYKyberPublicKeyStr SECKEYKyberPublicKey;
/*
** A Generic public key object.
*/
@ -189,6 +201,7 @@ struct SECKEYPublicKeyStr {
SECKEYKEAPublicKey kea;
SECKEYFortezzaPublicKey fortezza;
SECKEYECPublicKey ec;
SECKEYKyberPublicKey kyber;
} u;
};
typedef struct SECKEYPublicKeyStr SECKEYPublicKey;

Просмотреть файл

@ -1255,6 +1255,11 @@ SECKEY_CopyPublicKey(const SECKEYPublicKey *pubk)
break;
case nullKey:
return copyk;
case kyberKey:
copyk->u.kyber.params = pubk->u.kyber.params;
rv = SECITEM_CopyItem(arena, &copyk->u.kyber.publicValue,
&pubk->u.kyber.publicValue);
break;
default:
PORT_SetError(SEC_ERROR_INVALID_KEY);
rv = SECFailure;

Просмотреть файл

@ -12,6 +12,7 @@
#include "hasht.h"
#include "cmac.h"
#include "alghmac.h"
#include "kyber.h"
SEC_BEGIN_PROTOS
@ -281,7 +282,7 @@ RSA_CheckSignRecover(RSAPublicKey *key,
*/
/* Generate a new random value within the interval [2, q-1].
*/
*/
extern SECStatus DSA_NewRandom(PLArenaPool *arena, const SECItem *q,
SECItem *random);
@ -433,7 +434,7 @@ JPAKE_Verify(PLArenaPool *arena, const PQGParams *pqg,
* base and x2s will be allocated in the arena. The arena is *not* optional so
* do not pass NULL for the arena parameter. The arena should be zeroed when it
* is freed.
*/
*/
SECStatus
JPAKE_Round2(PLArenaPool *arena, const SECItem *p, const SECItem *q,
const SECItem *gx1, const SECItem *gx3, const SECItem *gx4,
@ -1878,7 +1879,7 @@ extern void BL_SetForkState(PRBool forked);
/*
** pepare an ECParam structure from DEREncoded params
*/
*/
extern SECStatus EC_FillParams(PLArenaPool *arena,
const SECItem *encodedParams, ECParams *params);
extern SECStatus EC_DecodeParams(const SECItem *encodedParams,
@ -1896,6 +1897,30 @@ extern int EC_GetPointSize(const ECParams *params);
*/
extern int EC_GetScalarSize(const ECParams *params);
/* Generate a Kyber key pair with parameters given by |params|. If |seed| is
* null this function generates its own randomness internally, otherwise the
* key is derived from |seed| using the method defined by |params|. The caller
* is responsible for allocating appropriately sized `privKey` and `pubKey`
* items.
*/
extern SECStatus Kyber_NewKey(KyberParams params, const SECItem *seed, SECItem *privKey, SECItem *pubKey);
/* Encapsulate a random secret to the Kyber public key `pubKey`. If `seed` is
* null this function generates its own randomness internally, otherwise the
* secret is derived from `seed` using the method defined by `params`. The
* caller is responsible for allocating appropriately sized `ciphertext` and
* `secret` items. Returns an error if any arguments' length is incompatible
* with `params`.
*/
extern SECStatus Kyber_Encapsulate(KyberParams params, const SECItem *seed, const SECItem *pubKey, SECItem *ciphertext, SECItem *secret);
/* Decapsulate a secret from a Kyber ciphertext `ciphertext` using the private
* key `privKey`. The caller is responsible for allocating an appropriately sized
* `secret` item. Returns an error if any arguments' length is incompatible
* with `params`.
*/
extern SECStatus Kyber_Decapsulate(KyberParams params, const SECItem *privKey, const SECItem *ciphertext, SECItem *secret);
SEC_END_PROTOS
#endif /* _BLAPI_H_ */

Просмотреть файл

@ -10,6 +10,7 @@
#include "blapit.h"
#include "mpi.h"
#include "hasht.h"
/* max block size of supported block ciphers */
#define MAX_BLOCK_SIZE 16
@ -82,6 +83,16 @@ SEC_END_PROTOS
SECStatus RSA_Init();
SECStatus generate_prime(mp_int *prime, int primeLen);
SECStatus
RSA_EMSAEncodePSS(unsigned char *em,
unsigned int emLen,
unsigned int emBits,
const unsigned char *mHash,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,
unsigned int saltLen);
/* Freebl state. */
PRBool aesni_support();
PRBool clmul_support();

Просмотреть файл

@ -12,7 +12,7 @@
#endif
#include "blapi.h"
#include "seccomon.h" /* Required for RSA and DSA. */
#include "seccomon.h" /* Required for RSA. */
#include "secerr.h"
#include "prtypes.h"
#include "secitem.h"
@ -125,14 +125,6 @@ DllMain(
#define FIPS_RSA_SIGNATURE_LENGTH 256 /* 2048-bits */
#define FIPS_RSA_MODULUS_LENGTH 256 /* 2048-bits */
/* FIPS preprocessor directives for DSA. */
#define FIPS_DSA_TYPE siBuffer
#define FIPS_DSA_DIGEST_LENGTH 20 /* 160-bits */
#define FIPS_DSA_SUBPRIME_LENGTH 20 /* 160-bits */
#define FIPS_DSA_SIGNATURE_LENGTH 40 /* 320-bits */
#define FIPS_DSA_PRIME_LENGTH 128 /* 1024-bits */
#define FIPS_DSA_BASE_LENGTH 128 /* 1024-bits */
/* FIPS preprocessor directives for RNG. */
#define FIPS_RNG_XKEY_LENGTH 32 /* 256-bits */
@ -1666,151 +1658,6 @@ freebl_fips_EC_PowerUpSelfTest()
return (SECSuccess);
}
static SECStatus
freebl_fips_DSA_PowerUpSelfTest(void)
{
/* DSA Known P (1024-bits), Q (160-bits), and G (1024-bits) Values. */
static const PRUint8 dsa_P[] = {
0x80, 0xb0, 0xd1, 0x9d, 0x6e, 0xa4, 0xf3, 0x28,
0x9f, 0x24, 0xa9, 0x8a, 0x49, 0xd0, 0x0c, 0x63,
0xe8, 0x59, 0x04, 0xf9, 0x89, 0x4a, 0x5e, 0xc0,
0x6d, 0xd2, 0x67, 0x6b, 0x37, 0x81, 0x83, 0x0c,
0xfe, 0x3a, 0x8a, 0xfd, 0xa0, 0x3b, 0x08, 0x91,
0x1c, 0xcb, 0xb5, 0x63, 0xb0, 0x1c, 0x70, 0xd0,
0xae, 0xe1, 0x60, 0x2e, 0x12, 0xeb, 0x54, 0xc7,
0xcf, 0xc6, 0xcc, 0xae, 0x97, 0x52, 0x32, 0x63,
0xd3, 0xeb, 0x55, 0xea, 0x2f, 0x4c, 0xd5, 0xd7,
0x3f, 0xda, 0xec, 0x49, 0x27, 0x0b, 0x14, 0x56,
0xc5, 0x09, 0xbe, 0x4d, 0x09, 0x15, 0x75, 0x2b,
0xa3, 0x42, 0x0d, 0x03, 0x71, 0xdf, 0x0f, 0xf4,
0x0e, 0xe9, 0x0c, 0x46, 0x93, 0x3d, 0x3f, 0xa6,
0x6c, 0xdb, 0xca, 0xe5, 0xac, 0x96, 0xc8, 0x64,
0x5c, 0xec, 0x4b, 0x35, 0x65, 0xfc, 0xfb, 0x5a,
0x1b, 0x04, 0x1b, 0xa1, 0x0e, 0xfd, 0x88, 0x15
};
static const PRUint8 dsa_Q[] = {
0xad, 0x22, 0x59, 0xdf, 0xe5, 0xec, 0x4c, 0x6e,
0xf9, 0x43, 0xf0, 0x4b, 0x2d, 0x50, 0x51, 0xc6,
0x91, 0x99, 0x8b, 0xcf
};
static const PRUint8 dsa_G[] = {
0x78, 0x6e, 0xa9, 0xd8, 0xcd, 0x4a, 0x85, 0xa4,
0x45, 0xb6, 0x6e, 0x5d, 0x21, 0x50, 0x61, 0xf6,
0x5f, 0xdf, 0x5c, 0x7a, 0xde, 0x0d, 0x19, 0xd3,
0xc1, 0x3b, 0x14, 0xcc, 0x8e, 0xed, 0xdb, 0x17,
0xb6, 0xca, 0xba, 0x86, 0xa9, 0xea, 0x51, 0x2d,
0xc1, 0xa9, 0x16, 0xda, 0xf8, 0x7b, 0x59, 0x8a,
0xdf, 0xcb, 0xa4, 0x67, 0x00, 0x44, 0xea, 0x24,
0x73, 0xe5, 0xcb, 0x4b, 0xaf, 0x2a, 0x31, 0x25,
0x22, 0x28, 0x3f, 0x16, 0x10, 0x82, 0xf7, 0xeb,
0x94, 0x0d, 0xdd, 0x09, 0x22, 0x14, 0x08, 0x79,
0xba, 0x11, 0x0b, 0xf1, 0xff, 0x2d, 0x67, 0xac,
0xeb, 0xb6, 0x55, 0x51, 0x69, 0x97, 0xa7, 0x25,
0x6b, 0x9c, 0xa0, 0x9b, 0xd5, 0x08, 0x9b, 0x27,
0x42, 0x1c, 0x7a, 0x69, 0x57, 0xe6, 0x2e, 0xed,
0xa9, 0x5b, 0x25, 0xe8, 0x1f, 0xd2, 0xed, 0x1f,
0xdf, 0xe7, 0x80, 0x17, 0xba, 0x0d, 0x4d, 0x38
};
/* DSA Known Random Values (known random key block is 160-bits) */
/* and (known random signature block is 160-bits). */
static const PRUint8 dsa_known_random_key_block[] = {
"Mozilla Rules World!"
};
static const PRUint8 dsa_known_random_signature_block[] = {
"Random DSA Signature"
};
/* DSA Known Digest (160-bits) */
static const PRUint8 dsa_known_digest[] = { "DSA Signature Digest" };
/* DSA Known Signature (320-bits). */
static const PRUint8 dsa_known_signature[] = {
0x25, 0x7c, 0x3a, 0x79, 0x32, 0x45, 0xb7, 0x32,
0x70, 0xca, 0x62, 0x63, 0x2b, 0xf6, 0x29, 0x2c,
0x22, 0x2a, 0x03, 0xce, 0x48, 0x15, 0x11, 0x72,
0x7b, 0x7e, 0xf5, 0x7a, 0xf3, 0x10, 0x3b, 0xde,
0x34, 0xc1, 0x9e, 0xd7, 0x27, 0x9e, 0x77, 0x38
};
/* DSA variables. */
DSAPrivateKey *dsa_private_key;
SECStatus dsa_status;
SECItem dsa_signature_item;
SECItem dsa_digest_item;
DSAPublicKey dsa_public_key;
PRUint8 dsa_computed_signature[FIPS_DSA_SIGNATURE_LENGTH];
static const PQGParams dsa_pqg = {
NULL,
{ FIPS_DSA_TYPE, (unsigned char *)dsa_P, FIPS_DSA_PRIME_LENGTH },
{ FIPS_DSA_TYPE, (unsigned char *)dsa_Q, FIPS_DSA_SUBPRIME_LENGTH },
{ FIPS_DSA_TYPE, (unsigned char *)dsa_G, FIPS_DSA_BASE_LENGTH }
};
/*******************************************/
/* Generate a DSA public/private key pair. */
/*******************************************/
/* Generate a DSA public/private key pair. */
dsa_status = DSA_NewKeyFromSeed(&dsa_pqg, dsa_known_random_key_block,
&dsa_private_key);
if (dsa_status != SECSuccess) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return (SECFailure);
}
/* construct public key from private key. */
dsa_public_key.params = dsa_private_key->params;
dsa_public_key.publicValue = dsa_private_key->publicValue;
/*************************************************/
/* DSA Single-Round Known Answer Signature Test. */
/*************************************************/
dsa_signature_item.data = dsa_computed_signature;
dsa_signature_item.len = sizeof dsa_computed_signature;
dsa_digest_item.data = (unsigned char *)dsa_known_digest;
dsa_digest_item.len = SHA1_LENGTH;
/* Perform DSA signature process. */
dsa_status = DSA_SignDigestWithSeed(dsa_private_key,
&dsa_signature_item,
&dsa_digest_item,
dsa_known_random_signature_block);
if ((dsa_status != SECSuccess) ||
(dsa_signature_item.len != FIPS_DSA_SIGNATURE_LENGTH) ||
(PORT_Memcmp(dsa_computed_signature, dsa_known_signature,
FIPS_DSA_SIGNATURE_LENGTH) != 0)) {
dsa_status = SECFailure;
} else {
/****************************************************/
/* DSA Single-Round Known Answer Verification Test. */
/****************************************************/
/* Perform DSA verification process. */
dsa_status = DSA_VerifyDigest(&dsa_public_key,
&dsa_signature_item,
&dsa_digest_item);
}
PORT_FreeArena(dsa_private_key->params.arena, PR_TRUE);
/* Don't free public key, it uses same arena as private key */
/* Verify DSA signature. */
if (dsa_status != SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return (SECSuccess);
}
static SECStatus
freebl_fips_DH_PowerUpSelfTest(void)
{
@ -1946,26 +1793,7 @@ loser:
static SECStatus
freebl_fips_RNG_PowerUpSelfTest(void)
{
static const PRUint8 Q[] = {
0x85, 0x89, 0x9c, 0x77, 0xa3, 0x79, 0xff, 0x1a,
0x86, 0x6f, 0x2f, 0x3e, 0x2e, 0xf9, 0x8c, 0x9c,
0x9d, 0xef, 0xeb, 0xed
};
static const PRUint8 GENX[] = {
0x65, 0x48, 0xe3, 0xca, 0xac, 0x64, 0x2d, 0xf7,
0x7b, 0xd3, 0x4e, 0x79, 0xc9, 0x7d, 0xa6, 0xa8,
0xa2, 0xc2, 0x1f, 0x8f, 0xe9, 0xb9, 0xd3, 0xa1,
0x3f, 0xf7, 0x0c, 0xcd, 0xa6, 0xca, 0xbf, 0xce,
0x84, 0x0e, 0xb6, 0xf1, 0x0d, 0xbe, 0xa9, 0xa3
};
static const PRUint8 rng_known_DSAX[] = {
0x7a, 0x86, 0xf1, 0x7f, 0xbd, 0x4e, 0x6e, 0xd9,
0x0a, 0x26, 0x21, 0xd0, 0x19, 0xcb, 0x86, 0x73,
0x10, 0x1f, 0x60, 0xd7
};
SECStatus rng_status = SECSuccess;
PRUint8 DSAX[FIPS_DSA_SUBPRIME_LENGTH];
/*******************************************/
/* Run the SP 800-90 Health tests */
@ -1976,20 +1804,6 @@ freebl_fips_RNG_PowerUpSelfTest(void)
return SECFailure;
}
/*******************************************/
/* Generate DSAX fow given Q. */
/*******************************************/
rng_status = FIPS186Change_ReduceModQForDSA(GENX, Q, DSAX);
/* Verify DSAX to perform the RNG integrity check */
if ((rng_status != SECSuccess) ||
(PORT_Memcmp(DSAX, rng_known_DSAX,
(FIPS_DSA_SUBPRIME_LENGTH)) != 0)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return (SECSuccess);
}
@ -2077,12 +1891,6 @@ freebl_fipsPowerUpSelfTest(unsigned int tests)
/* RSA Power-Up SelfTest(s). */
rv = freebl_fips_RSA_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;
/* DSA Power-Up SelfTest(s). */
rv = freebl_fips_DSA_PowerUpSelfTest();
if (rv != SECSuccess)
return rv;

Просмотреть файл

@ -942,10 +942,10 @@
[ 'target_arch=="arm"', {
# When the compiler uses the softfloat ABI, we want to use the compatible softfp ABI when enabling NEON for these objects.
# Confusingly, __SOFTFP__ is the name of the define for the softfloat ABI, not for the softfp ABI.
'softfp_cflags': '<!(${CC:-cc} -o - -E -dM - ${CFLAGS} < /dev/null | grep __SOFTFP__ > /dev/null && echo -mfloat-abi=softfp || true)',
'softfp_cflags': '<!(sh -c "${CC:-cc} -o - -E -dM - ${CFLAGS} < /dev/null | grep __SOFTFP__ > /dev/null && echo -mfloat-abi=softfp || true")',
}],
[ 'target_arch=="ppc64" or target_arch=="ppc64le"', {
'ppc_abi': '<!(${CC:-cc} -dM -E - < /dev/null | awk \'$2 == "_CALL_ELF" {print $3}\')',
'ppc_abi': '<!(sh -c "${CC:-cc} -dM -E - < /dev/null | awk \'\\$2 == \\"_CALL_ELF\\" {print \\$3}\'")',
}],
],
}

Просмотреть файл

@ -46,6 +46,8 @@
'gcm.c',
'hmacct.c',
'jpake.c',
'kyber.c',
'kyber-pqcrystals-ref.c',
'ldvector.c',
'md2.c',
'md5.c',
@ -59,6 +61,7 @@
'rawhash.c',
'rijndael.c',
'rsa.c',
'rsa_blind.c',
'rsapkcs.c',
'sha_fast.c',
'shvfy.c',
@ -69,6 +72,12 @@
'sha3.c',
'shake.c',
],
'defines': [
# For kyber-pqcrystals-ref.c. If we ever decide to support Kyber512 or
# Kyber1024, we'll need to build separate static libraries with different
# values of KYBER_K.
'KYBER_K=3',
],
'conditions': [
[ 'OS=="linux" or OS=="android"', {
'conditions': [

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,144 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* This file was generated from
* https://github.com/pq-crystals/kyber/commit/e0d1c6ff
*
* Files from that repository are listed here surrounded by
* "* begin: [file] *" and "* end: [file] *" comments.
*
* The following changes have been made:
* - include guards have been removed,
* - include directives have been removed,
* - "#ifdef KYBER90S" blocks have been evaluated with "KYBER90S" undefined,
* - functions outside of kem.c have been made static.
*/
/** begin: ref/LICENSE **
Public Domain (https://creativecommons.org/share-your-work/public-domain/cc0/);
or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
For Keccak and AES we are using public-domain
code from sources and by authors listed in
comments on top of the respective files.
** end: ref/LICENSE **/
/** begin: ref/AUTHORS **
Joppe Bos,
Léo Ducas,
Eike Kiltz,
Tancrède Lepoint,
Vadim Lyubashevsky,
John Schanck,
Peter Schwabe,
Gregor Seiler,
Damien Stehlé
** end: ref/AUTHORS **/
#ifndef KYBER_PQCRYSTALS_REF_H
#define KYBER_PQCRYSTALS_REF_H
/** begin: ref/api.h **/
#include <stdint.h>
#define pqcrystals_kyber512_SECRETKEYBYTES 1632
#define pqcrystals_kyber512_PUBLICKEYBYTES 800
#define pqcrystals_kyber512_CIPHERTEXTBYTES 768
#define pqcrystals_kyber512_KEYPAIRCOINBYTES 64
#define pqcrystals_kyber512_ENCCOINBYTES 32
#define pqcrystals_kyber512_BYTES 32
#define pqcrystals_kyber512_ref_SECRETKEYBYTES pqcrystals_kyber512_SECRETKEYBYTES
#define pqcrystals_kyber512_ref_PUBLICKEYBYTES pqcrystals_kyber512_PUBLICKEYBYTES
#define pqcrystals_kyber512_ref_CIPHERTEXTBYTES pqcrystals_kyber512_CIPHERTEXTBYTES
#define pqcrystals_kyber512_ref_KEYPAIRCOINBYTES pqcrystals_kyber512_KEYPAIRCOINBYTES
#define pqcrystals_kyber512_ref_ENCCOINBYTES pqcrystals_kyber512_ENCCOINBYTES
#define pqcrystals_kyber512_ref_BYTES pqcrystals_kyber512_BYTES
int pqcrystals_kyber512_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber512_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber512_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber512_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber512_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#define pqcrystals_kyber512_90s_ref_SECRETKEYBYTES pqcrystals_kyber512_SECRETKEYBYTES
#define pqcrystals_kyber512_90s_ref_PUBLICKEYBYTES pqcrystals_kyber512_PUBLICKEYBYTES
#define pqcrystals_kyber512_90s_ref_CIPHERTEXTBYTES pqcrystals_kyber512_CIPHERTEXTBYTES
#define pqcrystals_kyber512_90s_ref_KEYPAIRCOINBYTES pqcrystals_kyber512_KEYPAIRCOINBYTES
#define pqcrystals_kyber512_90s_ref_ENCCOINBYTES pqcrystals_kyber512_ENCCOINBYTES
#define pqcrystals_kyber512_90s_ref_BYTES pqcrystals_kyber512_BYTES
int pqcrystals_kyber512_90s_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber512_90s_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber512_90s_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber512_90s_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber512_90s_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#define pqcrystals_kyber768_SECRETKEYBYTES 2400
#define pqcrystals_kyber768_PUBLICKEYBYTES 1184
#define pqcrystals_kyber768_CIPHERTEXTBYTES 1088
#define pqcrystals_kyber768_KEYPAIRCOINBYTES 64
#define pqcrystals_kyber768_ENCCOINBYTES 32
#define pqcrystals_kyber768_BYTES 32
#define pqcrystals_kyber768_ref_SECRETKEYBYTES pqcrystals_kyber768_SECRETKEYBYTES
#define pqcrystals_kyber768_ref_PUBLICKEYBYTES pqcrystals_kyber768_PUBLICKEYBYTES
#define pqcrystals_kyber768_ref_CIPHERTEXTBYTES pqcrystals_kyber768_CIPHERTEXTBYTES
#define pqcrystals_kyber768_ref_KEYPAIRCOINBYTES pqcrystals_kyber768_KEYPAIRCOINBYTES
#define pqcrystals_kyber768_ref_ENCCOINBYTES pqcrystals_kyber768_ENCCOINBYTES
#define pqcrystals_kyber768_ref_BYTES pqcrystals_kyber768_BYTES
int pqcrystals_kyber768_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber768_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber768_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber768_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber768_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#define pqcrystals_kyber768_90s_ref_SECRETKEYBYTES pqcrystals_kyber768_SECRETKEYBYTES
#define pqcrystals_kyber768_90s_ref_PUBLICKEYBYTES pqcrystals_kyber768_PUBLICKEYBYTES
#define pqcrystals_kyber768_90s_ref_CIPHERTEXTBYTES pqcrystals_kyber768_CIPHERTEXTBYTES
#define pqcrystals_kyber768_90s_ref_KEYPAIRCOINBYTES pqcrystals_kyber768_KEYPAIRCOINBYTES
#define pqcrystals_kyber768_90s_ref_ENCCOINBYTES pqcrystals_kyber768_ENCCOINBYTES
#define pqcrystals_kyber768_90s_ref_BYTES pqcrystals_kyber768_BYTES
int pqcrystals_kyber768_90s_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber768_90s_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber768_90s_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber768_90s_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber768_90s_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#define pqcrystals_kyber1024_SECRETKEYBYTES 3168
#define pqcrystals_kyber1024_PUBLICKEYBYTES 1568
#define pqcrystals_kyber1024_CIPHERTEXTBYTES 1568
#define pqcrystals_kyber1024_KEYPAIRCOINBYTES 64
#define pqcrystals_kyber1024_ENCCOINBYTES 32
#define pqcrystals_kyber1024_BYTES 32
#define pqcrystals_kyber1024_ref_SECRETKEYBYTES pqcrystals_kyber1024_SECRETKEYBYTES
#define pqcrystals_kyber1024_ref_PUBLICKEYBYTES pqcrystals_kyber1024_PUBLICKEYBYTES
#define pqcrystals_kyber1024_ref_CIPHERTEXTBYTES pqcrystals_kyber1024_CIPHERTEXTBYTES
#define pqcrystals_kyber1024_ref_KEYPAIRCOINBYTES pqcrystals_kyber1024_KEYPAIRCOINBYTES
#define pqcrystals_kyber1024_ref_ENCCOINBYTES pqcrystals_kyber1024_ENCCOINBYTES
#define pqcrystals_kyber1024_ref_BYTES pqcrystals_kyber1024_BYTES
int pqcrystals_kyber1024_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber1024_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber1024_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber1024_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber1024_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
#define pqcrystals_kyber1024_90s_ref_SECRETKEYBYTES pqcrystals_kyber1024_SECRETKEYBYTES
#define pqcrystals_kyber1024_90s_ref_PUBLICKEYBYTES pqcrystals_kyber1024_PUBLICKEYBYTES
#define pqcrystals_kyber1024_90s_ref_CIPHERTEXTBYTES pqcrystals_kyber1024_CIPHERTEXTBYTES
#define pqcrystals_kyber1024_90s_ref_KEYPAIRCOINBYTES pqcrystals_kyber1024_KEYPAIRCOINBYTES
#define pqcrystals_kyber1024_90s_ref_ENCCOINBYTES pqcrystals_kyber1024_ENCCOINBYTES
#define pqcrystals_kyber1024_90s_ref_BYTES pqcrystals_kyber1024_BYTES
int pqcrystals_kyber1024_90s_ref_keypair_derand(uint8_t *pk, uint8_t *sk, const uint8_t *coins);
int pqcrystals_kyber1024_90s_ref_keypair(uint8_t *pk, uint8_t *sk);
int pqcrystals_kyber1024_90s_ref_enc_derand(uint8_t *ct, uint8_t *ss, const uint8_t *pk, const uint8_t *coins);
int pqcrystals_kyber1024_90s_ref_enc(uint8_t *ct, uint8_t *ss, const uint8_t *pk);
int pqcrystals_kyber1024_90s_ref_dec(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);
/** end: ref/api.h **/
#endif // KYBER_PQCRYSTALS_REF_H

Просмотреть файл

@ -0,0 +1,205 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include <stdbool.h>
#include "blapi.h"
#include "secerr.h"
#include "secitem.h"
#include "kyber-pqcrystals-ref.h"
#include "kyber.h"
/* Consistency check between kyber-pqcrystals-ref.h and kyber.h */
PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == pqcrystals_kyber768_PUBLICKEYBYTES);
PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == pqcrystals_kyber768_SECRETKEYBYTES);
PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == pqcrystals_kyber768_CIPHERTEXTBYTES);
PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == pqcrystals_kyber768_BYTES);
PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == pqcrystals_kyber768_KEYPAIRCOINBYTES);
PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == pqcrystals_kyber768_ENCCOINBYTES);
static bool
valid_params(KyberParams params)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return true;
default:
return false;
}
}
static bool
valid_pubkey(KyberParams params, const SECItem *pubkey)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return pubkey && pubkey->len == KYBER768_PUBLIC_KEY_BYTES;
default:
return false;
}
}
static bool
valid_privkey(KyberParams params, const SECItem *privkey)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return privkey && privkey->len == KYBER768_PRIVATE_KEY_BYTES;
default:
return false;
}
}
static bool
valid_ciphertext(KyberParams params, const SECItem *ciphertext)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return ciphertext && ciphertext->len == KYBER768_CIPHERTEXT_BYTES;
default:
return false;
}
}
static bool
valid_secret(KyberParams params, const SECItem *secret)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return secret && secret->len == KYBER_SHARED_SECRET_BYTES;
default:
return false;
}
}
static bool
valid_keypair_seed(KyberParams params, const SECItem *seed)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return !seed || seed->len == KYBER_KEYPAIR_COIN_BYTES;
default:
return false;
}
}
static bool
valid_enc_seed(KyberParams params, const SECItem *seed)
{
switch (params) {
case params_kyber768_round3:
return !seed;
case params_kyber768_round3_test_mode:
return !seed || seed->len == KYBER_SHARED_SECRET_BYTES;
default:
return false;
}
}
SECStatus
Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey)
{
if (!valid_params(params)) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
if (!(valid_keypair_seed(params, keypair_seed) && valid_privkey(params, privkey) && valid_pubkey(params, pubkey))) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
uint8_t randbuf[KYBER_KEYPAIR_COIN_BYTES];
uint8_t *coins;
if (keypair_seed) {
coins = keypair_seed->data;
} else {
if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return SECFailure;
}
coins = randbuf;
}
if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins);
} else {
/* unreachable */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
SECStatus
Kyber_Encapsulate(KyberParams params, const SECItem *enc_seed, const SECItem *pubkey, SECItem *ciphertext, SECItem *secret)
{
if (!valid_params(params)) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
if (!(valid_enc_seed(params, enc_seed) && valid_pubkey(params, pubkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
uint8_t randbuf[KYBER_ENC_COIN_BYTES];
uint8_t *coins;
if (enc_seed) {
coins = enc_seed->data;
} else {
if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
PORT_SetError(SEC_ERROR_NEED_RANDOM);
return SECFailure;
}
coins = randbuf;
}
if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins);
} else {
/* unreachable */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
SECStatus
Kyber_Decapsulate(KyberParams params, const SECItem *privkey, const SECItem *ciphertext, SECItem *secret)
{
if (!valid_params(params)) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data);
} else {
// unreachable
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}

Просмотреть файл

@ -432,6 +432,12 @@ static const struct FREEBLVectorStr vector = {
SHAKE_256_Hash,
/* End of version 3.026 */
Kyber_NewKey,
Kyber_Encapsulate,
Kyber_Decapsulate,
/* End of version 3.027 */
};
const FREEBLVector*

Просмотреть файл

@ -2828,3 +2828,29 @@ SHAKE_256_Hash(unsigned char *dest, PRUint32 dest_length, const char *src)
return SECFailure;
return (vector->p_SHAKE_256_Hash)(dest, dest_length, src);
}
/* ============== New for 3.0027 =============================== */
SECStatus
Kyber_NewKey(KyberParams params, const SECItem *seed, SECItem *privKey, SECItem *pubKey)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return SECFailure;
return (vector->p_Kyber_NewKey)(params, seed, privKey, pubKey);
}
SECStatus
Kyber_Encapsulate(KyberParams params, const SECItem *seed, const SECItem *pubKey, SECItem *ciphertext, SECItem *secret)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return SECFailure;
return (vector->p_Kyber_Encapsulate)(params, seed, pubKey, ciphertext, secret);
}
SECStatus
Kyber_Decapsulate(KyberParams params, const SECItem *privKey, const SECItem *ciphertext, SECItem *secret)
{
if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
return SECFailure;
return (vector->p_Kyber_Decapsulate)(params, privKey, ciphertext, secret);
}

Просмотреть файл

@ -10,7 +10,7 @@
#include "blapi.h"
#define FREEBL_VERSION 0x0326
#define FREEBL_VERSION 0x0327
struct FREEBLVectorStr {
@ -338,8 +338,8 @@ struct FREEBLVectorStr {
/* Version 3.006 came to here */
/* no modification to FREEBLVectorStr itself
* but ECParamStr was modified
*/
* but ECParamStr was modified
*/
/* Version 3.007 came to here */
@ -910,6 +910,14 @@ struct FREEBLVectorStr {
/* Version 3.026 came to here */
SECStatus (*p_Kyber_NewKey)(KyberParams params, const SECItem *seed, SECItem *privKey, SECItem *pubKey);
SECStatus (*p_Kyber_Encapsulate)(KyberParams params, const SECItem *seed, const SECItem *pubKey, SECItem *ciphertext, SECItem *secret);
SECStatus (*p_Kyber_Decapsulate)(KyberParams params, const SECItem *privKey, const SECItem *ciphertext, SECItem *secret);
/* Version 3.027 came to here */
/* Add new function pointers at the end of this struct and bump
* FREEBL_VERSION at the beginning of this file. */
};
@ -1012,3 +1020,9 @@ typedef SECStatus (*F_RC2_InitContext)(RC2Context *cx,
typedef RC2Context *(*F_RC2_AllocateContext)(void);
#endif
typedef SECStatus (*F_Kyber_NewKey)(KyberParams params, const SECItem *seed, SECItem *privKey, SECItem *pubKey);
typedef SECStatus (*F_Kyber_Encapsulate)(KyberParams params, const SECItem *seed, const SECItem *pubKey, SECItem *ciphertext, SECItem *secret);
typedef SECStatus (*F_Kyber_Decapsulate)(KyberParams params, const SECItem *privKey, const SECItem *ciphertext, SECItem *secret);

Просмотреть файл

@ -75,6 +75,11 @@ DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" \
-DSHLIB_VERSION=\"$(LIBRARY_VERSION)\" \
-DSOFTOKEN_SHLIB_VERSION=\"$(SOFTOKEN_LIBRARY_VERSION)\"
# We only support one parameter set, Kyber768, which has K=3. If we decide
# to support more parameters, we'll need to build separate objects from
# kyber-pqcrystals-ref.c using different values of KYBER_K.
DEFINES += -DKYBER_K=3
REQUIRES =
EXPORTS = \
@ -148,11 +153,14 @@ CSRCS = \
pqg.c \
dsa.c \
rsa.c \
rsa_blind.c \
rsapkcs.c \
shvfy.c \
tlsprfalg.c \
jpake.c \
secmpi.c \
kyber.c \
kyber-pqcrystals-ref.c \
$(MPI_SRCS) \
$(MPCPU_SRCS) \
$(ECL_SRCS) \

Просмотреть файл

@ -186,9 +186,9 @@ HASH_ResultLen(HASH_HashType type)
return hash_obj->length;
}
static SECStatus
HASH_HashBuf(HASH_HashType type, unsigned char *dest,
const unsigned char *src, PRUint32 src_len)
SECStatus
PQG_HashBuf(HASH_HashType type, unsigned char *dest,
const unsigned char *src, PRUint32 src_len)
{
const SECHashObject *hash_obj = HASH_GetRawHashObject(type);
void *hashcx = NULL;
@ -385,7 +385,7 @@ addToSeedThenHash(HASH_HashType hashtype,
if (rv != SECSuccess) {
return rv;
}
rv = HASH_HashBuf(hashtype, hashOutBuf, str.data, str.len); /* hash result */
rv = PQG_HashBuf(hashtype, hashOutBuf, str.data, str.len); /* hash result */
if (str.data)
SECITEM_ZfreeItem(&str, PR_FALSE);
return rv;
@ -457,7 +457,7 @@ makeQ2fromSeed(
** Step 6.
** "Compute U = hash[SEED] mod 2**N-1]."
**/
CHECK_SEC_OK(HASH_HashBuf(hashtype, U, seed->data, seed->len));
CHECK_SEC_OK(PQG_HashBuf(hashtype, U, seed->data, seed->len));
/* mod 2**N . Step 7 will explicitly set the top bit to 1, so no need
* to handle mod 2**N-1 */
if (hashLen > N_bytes) {
@ -784,7 +784,7 @@ makePrimefromSeedShaweTaylor(
step_5:
/* Step 5 c = Hash(prime_seed) xor Hash(prime_seed+1). */
CHECK_SEC_OK(HASH_HashBuf(hashtype, x, prime_seed->data, prime_seed->len));
CHECK_SEC_OK(PQG_HashBuf(hashtype, x, prime_seed->data, prime_seed->len));
CHECK_SEC_OK(addToSeedThenHash(hashtype, prime_seed, 1, seedlen, &x[hashlen]));
for (i = 0; i < hashlen; i++) {
x[i] = x[i] ^ x[i + hashlen];

Просмотреть файл

@ -11,6 +11,9 @@
#ifndef _PQG_H_
#define _PQG_H_ 1
SECStatus
PQG_HashBuf(HASH_HashType type, unsigned char *dest,
const unsigned char *src, PRUint32 src_len);
/* PQG_GetLength returns the significant bytes in the SECItem object (that is
* the length of the object minus any leading zeros. Any SECItem may be used,
* though this function is usually used for P, Q, or G values */

Просмотреть файл

@ -0,0 +1,471 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Implementation of RSA Blind Signatures.
* (https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/)
*/
#ifdef FREEBL_NO_DEPEND
#include "stubs.h"
#endif
#include "secerr.h"
#include "blapi.h"
#include "mpi.h"
#include "secitem.h"
#include "prerr.h"
#include "blapii.h"
#include "secmpi.h"
#include "mpi-priv.h"
#include "pqg.h"
/*#define RSA_DEBUG*/
#define MP_DIGIT_BYTE (MP_DIGIT_BIT / PR_BITS_PER_BYTE)
#ifdef RSA_DEBUG
void
rsaBlind_Print(PRUint8* m, size_t t)
{
for (int i = 0; i < t; i++) {
if (i % 16 == 0)
printf("\n");
printf("%02x ", m[i]);
}
printf("\n \n");
}
void
mp_print_buf(mp_int* mp)
{
for (int i = MP_USED(mp) - 1; i >= 0; i--) {
if (i % 2 == 1)
printf("\n");
printf("%016lx ", (long unsigned int)MP_DIGIT(mp, i));
}
printf("\n \n");
}
#endif
/*
* 4.1. Prepare
* There are two types of preparation functions:
* an identity preparation function, and a randomized preparation function.
* The identity preparation function returns the input message without transformation,
* i.e., msg = PrepareIdentity(msg).
* The randomized preparation function augments the input message with fresh randomness.
*
* Inputs:
* - msg, message to be signed, a byte string
*
* Outputs:
* - input_msg, a byte string that is 32 bytes longer than msg
* Steps:
* 1. msgPrefix = random(32)
* 2. input_msg = concat(msgPrefix, msg)
* 3. output input_msg
*/
SECStatus
RSABlinding_Prepare(PRUint8* preparedMessage, size_t preparedMessageLen, const PRUint8* msg,
size_t msgLen, PRBool isDeterministic)
{
if (!preparedMessage || !msg) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* The identity preparation function: */
if (isDeterministic) {
if (preparedMessageLen < msgLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Memcpy(preparedMessage, msg, msgLen);
}
/* The randomized preparation function: */
else {
/* 1. msgPrefix = random(32)*/
PRUint8 lenRandom = 32;
if (msgLen > UINT32_MAX - lenRandom) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
if (preparedMessageLen < msgLen + lenRandom) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
RNG_GenerateGlobalRandomBytes(preparedMessage, lenRandom);
/* 2. input_msg = concat(msgPrefix, msg)*/
PORT_Memcpy(preparedMessage + lenRandom, msg, msgLen);
}
return SECSuccess;
}
/* RSA Blind Signatures
* Blind(pkS, msg)
* Parameters:
* - kLen, the length in bytes of the RSA modulus n
* - Hash, the hash function used to hash the message
* - MGF, the mask generation function
* - sLen, the length in bytes of the salt
*
* Inputs:
* - pkS, server public key (n, e)
* - msg, message to be signed, a byte string
*
* Outputs:
* - blinded_msg, a byte string of length kLen
* - inv, an integer used to unblind the signature in Finalize
*/
/* The length of the random buffer is n. */
SECStatus
RSABlinding_Blind(HASH_HashType hashAlg, PRUint8* blindedMsg, size_t blindedMsgLen,
PRUint8* inv, size_t invLen, const PRUint8* msg, size_t msgLen,
const PRUint8* salt, size_t saltLen,
RSAPublicKey* pkS, const PRUint8* randomBuf, size_t randomBufLen)
{
if (!blindedMsgLen || !inv || !msg || !pkS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
mp_err err = MP_OKAY;
const size_t modulus_len = pkS->modulus.len;
if (blindedMsgLen != modulus_len || invLen != modulus_len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (randomBufLen != 0 && randomBufLen != modulus_len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((PRUint64)pkS->modulus.len * PR_BITS_PER_BYTE - 1 > UINT32_MAX) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
PRUint8* encoded_msg = PORT_ZAlloc(modulus_len);
PRUint8* rBuf = PORT_ZAlloc(modulus_len);
PRUint8* xBuf = PORT_ZAlloc(modulus_len);
mp_int m, n, r, mask, invR, rsavp1, blindSign;
MP_DIGITS(&m) = 0;
MP_DIGITS(&invR) = 0;
MP_DIGITS(&rsavp1) = 0;
MP_DIGITS(&blindSign) = 0;
MP_DIGITS(&n) = 0;
MP_DIGITS(&r) = 0;
MP_DIGITS(&mask) = 0;
CHECK_MPI_OK(mp_init(&m));
CHECK_MPI_OK(mp_init(&invR));
CHECK_MPI_OK(mp_init(&rsavp1));
CHECK_MPI_OK(mp_init(&blindSign));
CHECK_MPI_OK(mp_init(&r));
CHECK_MPI_OK(mp_init(&n));
CHECK_MPI_OK(mp_init(&mask));
CHECK_MPI_OK(mp_read_unsigned_octets(&n, pkS->modulus.data, pkS->modulus.len));
SECStatus rv = SECFailure;
size_t bit_len_n = pkS->modulus.len * PR_BITS_PER_BYTE - 1;
if (!randomBuf || randomBufLen == 0) {
CHECK_MPI_OK(mp_2expt(&mask, bit_len_n + 1));
CHECK_MPI_OK(mp_sub_d(&mask, 1, &mask));
do {
CHECK_MPI_OK(mpp_random_secure(&r));
for (size_t i = 0; i < mask.alloc; i++) {
r.dp[i] = mask.dp[i] & r.dp[i];
}
} while (mp_cmp(&r, &n) != MP_LT);
CHECK_MPI_OK(mp_init_copy(&r, &mask));
} else {
CHECK_MPI_OK(mp_read_unsigned_octets(&r, randomBuf, pkS->modulus.len));
}
/* 1. encoded_msg = EMSA-PSS-ENCODE(msg, bit_len(n)). */
PRUint8 msgHash[HASH_LENGTH_MAX] = { 0 };
rv = PQG_HashBuf(hashAlg, msgHash, msg, msgLen);
if (rv != SECSuccess) {
goto cleanup;
}
rv = RSA_EMSAEncodePSS(encoded_msg, pkS->modulus.len, bit_len_n, msgHash, hashAlg, hashAlg, salt, saltLen);
/* 2. If EMSA-PSS-ENCODE raises an error, raise the error and stop. */
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_FAILED_TO_ENCODE_DATA);
goto cleanup;
}
#ifdef RSA_DEBUG
printf("encoded_msg: \n");
rsaBlind_Print(encoded_msg, modulus_len);
#endif
/* 3. m = bytes_to_int(encoded_msg). */
CHECK_MPI_OK(mp_read_unsigned_octets(&m, encoded_msg, pkS->modulus.len));
/* 4. c = mp_is_coprime(m, n).
** 5. If c is false, raise an "invalid input" error and stop.
** 7. inv = inverse_mod(r, n)
*/
err = mp_invmod(&r, &n, &invR);
if (err == MP_UNDEF) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto cleanup;
} else if (err) {
goto cleanup;
}
#ifdef RSA_DEBUG
printf("inverse r: \n");
mp_print_buf(&invR);
#endif
/* 9. x = RSAVP1(pkS, r)*/
CHECK_MPI_OK(mp_to_fixlen_octets(&r, rBuf, pkS->modulus.len));
rv = RSA_PublicKeyOp(pkS, xBuf, rBuf);
if (rv != SECSuccess) {
goto cleanup;
}
CHECK_MPI_OK(mp_read_unsigned_octets(&rsavp1, xBuf, pkS->modulus.len));
#ifdef RSA_DEBUG
printf("x (RSAVP1): \n");
mp_print_buf(&rsavp1);
#endif
/* 10. z = m * x mod n*/
CHECK_MPI_OK(mp_mulmod(&m, &rsavp1, &n, &blindSign));
#ifdef RSA_DEBUG
printf("blindSign: \n");
mp_print_buf(&blindSign);
#endif
CHECK_MPI_OK(mp_to_fixlen_octets(&blindSign, blindedMsg, blindedMsgLen));
CHECK_MPI_OK(mp_to_fixlen_octets(&invR, inv, invLen));
cleanup:
mp_clear(&m);
mp_clear(&n);
mp_clear(&r);
mp_clear(&invR);
mp_clear(&rsavp1);
mp_clear(&blindSign);
mp_clear(&mask);
PORT_Free(encoded_msg);
PORT_Free(rBuf);
PORT_Free(xBuf);
if (err) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
return rv;
}
/* 4.3. BlindSign
* BlindSign(skS, blinded_msg)
*
* Parameters:
* - kLen, the length in bytes of the RSA modulus n
*
* Inputs:
* - skS, server private key
* - blinded_msg, encoded and blinded message to be signed, a byte string
*/
SECStatus
RSABlinding_BlindSign(PRUint8* blindSig, size_t blindSigLen,
const PRUint8* blindedMsg, size_t blindedMsgLen, RSAPrivateKey* skS, RSAPublicKey* pkS)
{
SECStatus rv = SECSuccess;
if (!blindSig || !blindedMsg || !skS) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if ((blindSigLen != skS->modulus.len) || (skS->modulus.len != pkS->modulus.len) || (blindedMsgLen != skS->modulus.len)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PRUint8* sBuf = (PRUint8*)PORT_Alloc(skS->modulus.len);
PRUint8* mPrimeBuf = (PRUint8*)PORT_Alloc(pkS->modulus.len);
mp_err err = MP_OKAY;
mp_int z, mPrime;
MP_DIGITS(&z) = 0;
MP_DIGITS(&mPrime) = 0;
CHECK_MPI_OK(mp_init(&z));
CHECK_MPI_OK(mp_init(&mPrime));
CHECK_MPI_OK(mp_read_unsigned_octets(&z, blindedMsg, skS->modulus.len));
/* 2. s = rsasp1(skS, z). */
rv = RSA_PrivateKeyOp(skS, sBuf, blindedMsg);
if (rv != SECSuccess) {
goto cleanup;
}
#ifdef RSA_DEBUG
printf("Blinded Signature: \n");
mp_print_buf(&s);
#endif
/* 3. mPrime = rsavp1(pkS, s). */
rv = RSA_PublicKeyOp(pkS, mPrimeBuf, sBuf);
if (rv != SECSuccess) {
goto cleanup;
}
CHECK_MPI_OK(mp_read_unsigned_octets(&mPrime, mPrimeBuf, skS->modulus.len));
#ifdef RSA_DEBUG
printf("mPrime: \n");
mp_print_buf(&mPrime);
#endif
/* 4. If m != m', raise "signing failure" and stop. */
PRBool isBlindedMsgCorrect = mp_cmp(&mPrime, &z) == 0;
/* 5. blind_sig = int_to_bytes(s, kLen). */
if (isBlindedMsgCorrect) {
PORT_Memcpy(blindSig, sBuf, skS->modulus.len);
}
cleanup:
mp_clear(&z);
mp_clear(&mPrime);
PORT_Free(sBuf);
PORT_Free(mPrimeBuf);
if (err) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
/*
* 4.4. Finalize.
* Finalize validates the server's response, unblinds the message to produce a signature,
* verifies it for correctness, and outputs the signature upon success.
*
* Parameters:
* - kLen, the length in bytes of the RSA modulus n
* - Hash, the hash function used to hash the message
* - MGF, the mask generation function
* - sLen, the length in bytes of the salt
*
* Inputs:
* - pkS, server public key (n, e)
* - msg, message to be signed, a byte string
* - blind_sig, signed and blinded element, a byte string of
* length kLen
* - inv, inverse of the blind, an integer
*
* Outputs:
* - sig, a byte string of length kLen
*
* Blinded Signature Len should be the same as modulus len.
*/
SECStatus
RSABlinding_Finalize(HASH_HashType hashAlg, PRUint8* signature, const PRUint8* msg, PRUint32 msgLen,
const PRUint8* blindSig, size_t blindSigLen,
const PRUint8* inv, size_t invLen, RSAPublicKey* pkS, size_t saltLen)
{
if (!signature || !msg || !blindSig || !inv || !pkS || msgLen == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (blindSigLen != pkS->modulus.len || invLen != pkS->modulus.len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
mp_err err = MP_OKAY;
SECStatus rv = SECFailure;
mp_int inv_mp, blindSig_mp, n_mp, sig_mp;
MP_DIGITS(&inv_mp) = 0;
MP_DIGITS(&blindSig_mp) = 0;
MP_DIGITS(&n_mp) = 0;
MP_DIGITS(&sig_mp) = 0;
CHECK_MPI_OK(mp_init(&n_mp));
CHECK_MPI_OK(mp_init(&inv_mp));
CHECK_MPI_OK(mp_init(&blindSig_mp));
CHECK_MPI_OK(mp_init(&sig_mp));
CHECK_MPI_OK(mp_read_unsigned_octets(&n_mp, pkS->modulus.data, pkS->modulus.len));
CHECK_MPI_OK(mp_read_unsigned_octets(&blindSig_mp, blindSig, pkS->modulus.len));
CHECK_MPI_OK(mp_read_unsigned_octets(&inv_mp, inv, pkS->modulus.len));
/* 3. s = z * inv mod n. */
CHECK_MPI_OK(mp_mulmod(&blindSig_mp, &inv_mp, &n_mp, &sig_mp));
#ifdef RSA_DEBUG
printf("Computed Signature : \n");
mp_print_buf(&sig_mp);
#endif
CHECK_MPI_OK(mp_to_fixlen_octets(&sig_mp, signature, pkS->modulus.len));
PRUint8 mHash[HASH_LENGTH_MAX] = { 0 };
rv = PQG_HashBuf(hashAlg, mHash, msg, msgLen);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_DATA);
goto cleanup;
}
/* 5. result = RSASSA-PSS-VERIFY(pkS, msg, sig) with Hash, MGF, and sLen as defined in the parameters. */
rv = RSA_CheckSignPSS(pkS, hashAlg, hashAlg, saltLen, signature, sig_mp.used * MP_DIGIT_BYTE, mHash, 0);
/* If result = "valid signature", output sig, else raise "invalid signature" and stop. */
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
}
#ifdef RSA_DEBUG
if (rv == SECFailure) {
printf("%s\n", "RSA CheckSignPSS has failed. ");
} else {
printf("%s\n", "RSA CheckSignPSS has succeeded. ");
}
#endif
cleanup:
mp_clear(&inv_mp);
mp_clear(&blindSig_mp);
mp_clear(&n_mp);
mp_clear(&sig_mp);
if (err) {
MP_TO_SEC_ERROR(err);
return SECFailure;
}
return rv;
}

Просмотреть файл

@ -1234,15 +1234,15 @@ loser:
* emBits from the RFC is just modBits - 1, see section 8.1.1.
* We only support MGF1 as the MGF.
*/
static SECStatus
emsa_pss_encode(unsigned char *em,
unsigned int emLen,
unsigned int emBits,
const unsigned char *mHash,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,
unsigned int saltLen)
SECStatus
RSA_EMSAEncodePSS(unsigned char *em,
unsigned int emLen,
unsigned int emBits,
const unsigned char *mHash,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,
unsigned int saltLen)
{
const SECHashObject *hash;
void *hash_context;
@ -1458,8 +1458,8 @@ RSA_SignPSS(RSAPrivateKey *key,
emLen--;
em++;
}
rv = emsa_pss_encode(em, emLen, modulusBits - 1, input, hashAlg,
maskHashAlg, salt, saltLength);
rv = RSA_EMSAEncodePSS(em, emLen, modulusBits - 1, input, hashAlg,
maskHashAlg, salt, saltLength);
if (rv != SECSuccess)
goto done;

Просмотреть файл

@ -236,6 +236,9 @@ VFY_CreateContext;
VFY_DestroyContext;
VFY_End;
VFY_Update;
PK11_Encapsulate;
PK11_Decapsulate;
PK11_ConcatSymKeys;
;+#
;+# The following symbols are exported only to make libsmime3.so work.
;+# These are still private!!!

Просмотреть файл

@ -44,6 +44,9 @@ pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey)
case ecKey:
pubKeyIndex = &pubKey->u.ec.publicValue;
break;
case kyberKey:
pubKeyIndex = &pubKey->u.kyber.publicValue;
break;
default:
return NULL;
}
@ -73,6 +76,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
CK_ATTRIBUTE theTemplate[11];
CK_ATTRIBUTE *signedattr = NULL;
CK_ATTRIBUTE *attrs = theTemplate;
CK_NSS_KEM_PARAMETER_SET_TYPE kemParams;
SECItem *ckaId = NULL;
SECItem *pubValue = NULL;
int signedcount = 0;
@ -216,6 +220,25 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
attrs++;
}
break;
case kyberKey:
keyType = CKK_NSS_KYBER;
switch (pubKey->u.kyber.params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
kemParams = CKP_NSS_KYBER_768_ROUND3;
break;
default:
kemParams = CKP_INVALID_ID;
break;
}
PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
&kemParams,
sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
attrs++;
PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.kyber.publicValue.data,
pubKey->u.kyber.publicValue.len);
attrs++;
break;
default:
if (ckaId) {
SECITEM_FreeItem(ckaId, PR_TRUE);
@ -225,7 +248,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
}
templateCount = attrs - theTemplate;
PORT_Assert(templateCount <= (sizeof(theTemplate) / sizeof(CK_ATTRIBUTE)));
if (pubKey->keyType != ecKey) {
if (pubKey->keyType != ecKey && pubKey->keyType != kyberKey) {
PORT_Assert(signedattr);
signedcount = attrs - signedattr;
for (attrs = signedattr; signedcount; attrs++, signedcount--) {
@ -597,7 +620,7 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id)
CK_ATTRIBUTE template[8];
CK_ATTRIBUTE *attrs = template;
CK_ATTRIBUTE *modulus, *exponent, *base, *prime, *subprime, *value;
CK_ATTRIBUTE *ecparams;
CK_ATTRIBUTE *ecparams, *kemParams;
/* if we didn't know the key type, get it */
if (keyType == nullKey) {
@ -619,6 +642,9 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id)
case CKK_EC:
keyType = ecKey;
break;
case CKK_NSS_KYBER:
keyType = kyberKey;
break;
default:
PORT_SetError(SEC_ERROR_BAD_KEY);
return NULL;
@ -773,6 +799,40 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, CK_OBJECT_HANDLE id)
&pubKey->u.ec.DEREncodedParams, value,
&pubKey->u.ec.publicValue);
break;
case kyberKey:
value = attrs;
PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0);
attrs++;
kemParams = attrs;
PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET, NULL, 0);
attrs++;
templateCount = attrs - template;
PR_ASSERT(templateCount <= sizeof(template) / sizeof(CK_ATTRIBUTE));
crv = PK11_GetAttributes(arena, slot, id, template, templateCount);
if (crv != CKR_OK)
break;
if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_NSS_KYBER)) {
crv = CKR_OBJECT_HANDLE_INVALID;
break;
}
if (kemParams->ulValueLen != sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE)) {
crv = CKR_OBJECT_HANDLE_INVALID;
break;
}
CK_NSS_KEM_PARAMETER_SET_TYPE *pPK11Params = kemParams->pValue;
switch (*pPK11Params) {
case CKP_NSS_KYBER_768_ROUND3:
pubKey->u.kyber.params = params_kyber768_round3;
break;
default:
pubKey->u.kyber.params = params_kyber_invalid;
break;
}
crv = pk11_Attr2SecItem(arena, value, &pubKey->u.kyber.publicValue);
break;
case fortezzaKey:
case nullKey:
default:
@ -826,6 +886,9 @@ PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType,
case CKK_EC:
keyType = ecKey;
break;
case CKK_NSS_KYBER:
keyType = kyberKey;
break;
default:
break;
}
@ -1209,6 +1272,17 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
};
SECKEYECParams *ecParams;
CK_ATTRIBUTE kyberPubTemplate[] = {
{ CKA_NSS_PARAMETER_SET, NULL, 0 },
{ CKA_TOKEN, NULL, 0 },
{ CKA_DERIVE, NULL, 0 },
{ CKA_WRAP, NULL, 0 },
{ CKA_VERIFY, NULL, 0 },
{ CKA_VERIFY_RECOVER, NULL, 0 },
{ CKA_ENCRYPT, NULL, 0 },
{ CKA_MODIFIABLE, NULL, 0 },
};
/*CK_ULONG key_size = 0;*/
CK_ATTRIBUTE *pubTemplate;
int privCount = 0;
@ -1216,6 +1290,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
PK11RSAGenParams *rsaParams;
SECKEYPQGParams *dsaParams;
SECKEYDHParams *dhParams;
CK_NSS_KEM_PARAMETER_SET_TYPE *kemParams;
CK_MECHANISM mechanism;
CK_MECHANISM test_mech;
CK_MECHANISM test_mech2;
@ -1413,6 +1488,17 @@ PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
test_mech2.mechanism = CKM_ECDSA;
}
break;
case CKM_NSS_KYBER_KEY_PAIR_GEN:
kemParams = (CK_NSS_KEM_PARAMETER_SET_TYPE *)param;
attrs = kyberPubTemplate;
PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
kemParams,
sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
attrs++;
pubTemplate = kyberPubTemplate;
keyType = kyberKey;
test_mech.mechanism = CKM_NSS_KYBER;
break;
default:
PORT_SetError(SEC_ERROR_BAD_KEY);
return NULL;

Просмотреть файл

@ -177,6 +177,7 @@ PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
break;
case keaKey:
case fortezzaKey:
case kyberKey:
case nullKey:
/* fall through and return false */
break;

Просмотреть файл

@ -424,6 +424,8 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type, unsigned long len)
case CKM_TLS_PRF_GENERAL:
case CKM_NSS_TLS_PRF_GENERAL_SHA256:
return CKK_GENERIC_SECRET;
case CKM_NSS_KYBER_KEY_PAIR_GEN:
return CKK_NSS_KYBER;
default:
return pk11_lookup(type)->keyType;
}

Просмотреть файл

@ -134,7 +134,7 @@ PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,
}
/*
* Read in a single attribute into As a Ulong.
* Read in a single attribute into a Ulong.
*/
CK_ULONG
PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id,

Просмотреть файл

@ -245,6 +245,8 @@ static const oidValDef curveOptList[] = {
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
{ CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
{ CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00,
NSS_USE_ALG_IN_SSL_KX },
/* ANSI X9.62 named elliptic curves (characteristic two field) */
{ CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },

Просмотреть файл

@ -424,6 +424,11 @@ PK11SymKey *PK11_PubDeriveWithKDF(SECKEYPrivateKey *privKey,
CK_ATTRIBUTE_TYPE operation, int keySize,
CK_ULONG kdf, SECItem *sharedData, void *wincx);
/*
* Concatenate a pair of symmetric keys.
*/
PK11SymKey *PK11_ConcatSymKeys(PK11SymKey *left, PK11SymKey *right, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation);
/*
* unwrap a new key with a symetric key.
* PK11_Unwrap returns a key which can do exactly one operation, and is
@ -812,6 +817,42 @@ SECStatus PK11_VerifyWithMechanism(SECKEYPublicKey *key,
const SECItem *param, const SECItem *sig,
const SECItem *hash, void *wincx);
/**********************************************************************
* Key Encapsulation Mechanisms
**********************************************************************/
/*
* Using the given |pubKey|, generate a shared secret in |outKey| and an
* encapsulation of it in |ciphertext|. |outKey| will have usage attributes as
* specified in |attrFlags| and operation attributes as specified in |opFlags|.
*
* The function asserts that |pubKey|, |outKey|, and |ciphertext| are not NULL.
* If an error occurs, no allocations are made to |outKey| and |ciphertext|;
* otherwise (if SECSuccess is returned) allocations are made to |outKey| and
* |ciphertext| and the caller is responsible for freeing the memory occupied
* by these structures.
*/
SECStatus PK11_Encapsulate(SECKEYPublicKey *pubKey, CK_MECHANISM_TYPE target,
PK11AttrFlags attrFlags, CK_FLAGS opFlags,
PK11SymKey **outKey, SECItem **outCiphertext);
/*
* Using the given |privKey|, decapsulate |ciphertext| and put the resulting
* shared secret in |outKey|. |outKey| will have usage attributes as specified
* in |attrFlags| and operation attributes as specified in |opFlags|.
*
* The function asserts that |privKey|, |ciphertext|, and |outKey| are not NULL.
* If an error occurs, |outKey| is not allocated; otherwise (if SECSuccess is
* returned) |outKey| is allocated and the caller is responsible for freeing
* the memory occupied by it.
*/
SECStatus
PK11_Decapsulate(SECKEYPrivateKey *privKey, const SECItem *ciphertext,
CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags,
CK_FLAGS opFlags, PK11SymKey **outKey);
/**********************************************************************
* Crypto Contexts
**********************************************************************/

Просмотреть файл

@ -7,6 +7,7 @@
*/
#include <stddef.h>
#include <limits.h>
#include "seccomon.h"
#include "secmod.h"
@ -1847,6 +1848,32 @@ pk11_ConcatenateBaseAndKey(PK11SymKey *base,
&param, target, operation, keySize);
}
PK11SymKey *
PK11_ConcatSymKeys(PK11SymKey *left, PK11SymKey *right, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation)
{
PK11SymKey *out = NULL;
PK11SymKey *copyOfLeft = NULL;
PK11SymKey *copyOfRight = NULL;
if ((left == NULL) || (right == NULL)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
SECStatus rv = PK11_SymKeysToSameSlot(target, operation, operation,
left, right,
&copyOfLeft, &copyOfRight);
if (rv != SECSuccess) {
/* error code already set */
return NULL;
}
out = pk11_ConcatenateBaseAndKey(copyOfLeft ? copyOfLeft : left, copyOfRight ? copyOfRight : right, target, operation, 0);
PK11_FreeSymKey(copyOfLeft);
PK11_FreeSymKey(copyOfRight);
return out;
}
/* Create a new key whose value is the hash of tobehashed.
* type is the mechanism for the derived key.
*/
@ -2104,6 +2131,7 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
case rsaKey:
case rsaPssKey:
case rsaOaepKey:
case kyberKey:
case nullKey:
PORT_SetError(SEC_ERROR_BAD_KEY);
break;
@ -3045,3 +3073,225 @@ PK11_GetSymKeyHandle(PK11SymKey *symKey)
{
return symKey->objectID;
}
static CK_ULONG
pk11_KyberCiphertextLength(SECKEYKyberPublicKey *pubKey)
{
switch (pubKey->params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return KYBER768_CIPHERTEXT_BYTES;
default:
// unreachable
return 0;
}
}
static CK_ULONG
pk11_KEMCiphertextLength(SECKEYPublicKey *pubKey)
{
switch (pubKey->keyType) {
case kyberKey:
return pk11_KyberCiphertextLength(&pubKey->u.kyber);
default:
// unreachable
PORT_Assert(0);
return 0;
}
}
SECStatus
PK11_Encapsulate(SECKEYPublicKey *pubKey, CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags, CK_FLAGS opFlags, PK11SymKey **outKey, SECItem **outCiphertext)
{
PORT_Assert(pubKey);
PORT_Assert(outKey);
PORT_Assert(outCiphertext);
PK11SlotInfo *slot = pubKey->pkcs11Slot;
PK11SymKey *sharedSecret = NULL;
SECItem *ciphertext = NULL;
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
unsigned int templateCount;
CK_ATTRIBUTE *attrs;
CK_BBOOL cktrue = CK_TRUE;
CK_BBOOL ckfalse = CK_FALSE;
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_INTERFACE_PTR KEMInterface = NULL;
CK_UTF8CHAR_PTR KEMInterfaceName = (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface";
CK_VERSION KEMInterfaceVersion = { 1, 0 };
CK_NSS_KEM_FUNCTIONS *KEMInterfaceFunctions = NULL;
CK_RV crv;
*outKey = NULL;
*outCiphertext = NULL;
CK_MECHANISM_TYPE kemType;
switch (pubKey->keyType) {
case kyberKey:
kemType = CKM_NSS_KYBER;
break;
default:
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
CK_NSS_KEM_PARAMETER_SET_TYPE kemParameterSet = PK11_ReadULongAttribute(slot, pubKey->pkcs11ID, CKA_NSS_PARAMETER_SET);
CK_MECHANISM mech = { kemType, &kemParameterSet, sizeof(kemParameterSet) };
sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
if (sharedSecret == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
sharedSecret->origin = PK11_OriginGenerated;
attrs = keyTemplate;
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
attrs++;
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
attrs++;
attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
templateCount = attrs - keyTemplate;
PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
crv = PK11_GETTAB(slot)->C_GetInterface(KEMInterfaceName, &KEMInterfaceVersion, &KEMInterface, 0);
if (crv != CKR_OK) {
goto error;
}
KEMInterfaceFunctions = (CK_NSS_KEM_FUNCTIONS *)(KEMInterface->pFunctionList);
CK_ULONG ciphertextLen = pk11_KEMCiphertextLength(pubKey);
ciphertext = SECITEM_AllocItem(NULL, NULL, ciphertextLen);
if (ciphertext == NULL) {
crv = CKR_HOST_MEMORY;
goto error;
}
pk11_EnterKeyMonitor(sharedSecret);
crv = KEMInterfaceFunctions->C_Encapsulate(sharedSecret->session,
&mech,
pubKey->pkcs11ID,
keyTemplate,
templateCount,
&sharedSecret->objectID,
ciphertext->data,
&ciphertextLen);
pk11_ExitKeyMonitor(sharedSecret);
if (crv != CKR_OK) {
goto error;
}
PORT_Assert(ciphertextLen == ciphertext->len);
*outKey = sharedSecret;
*outCiphertext = ciphertext;
return SECSuccess;
error:
PORT_SetError(PK11_MapError(crv));
PK11_FreeSymKey(sharedSecret);
SECITEM_FreeItem(ciphertext, PR_TRUE);
return SECFailure;
}
SECStatus
PK11_Decapsulate(SECKEYPrivateKey *privKey, const SECItem *ciphertext, CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags, CK_FLAGS opFlags, PK11SymKey **outKey)
{
PORT_Assert(privKey);
PORT_Assert(ciphertext);
PORT_Assert(outKey);
PK11SlotInfo *slot = privKey->pkcs11Slot;
PK11SymKey *sharedSecret;
CK_ATTRIBUTE keyTemplate[MAX_TEMPL_ATTRS];
unsigned int templateCount;
CK_ATTRIBUTE *attrs;
CK_BBOOL cktrue = CK_TRUE;
CK_BBOOL ckfalse = CK_FALSE;
CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_INTERFACE_PTR KEMInterface = NULL;
CK_UTF8CHAR_PTR KEMInterfaceName = (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface";
CK_VERSION KEMInterfaceVersion = { 1, 0 };
CK_NSS_KEM_FUNCTIONS *KEMInterfaceFunctions = NULL;
CK_RV crv;
*outKey = NULL;
CK_MECHANISM_TYPE kemType;
switch (privKey->keyType) {
case kyberKey:
kemType = CKM_NSS_KYBER;
break;
default:
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
CK_NSS_KEM_PARAMETER_SET_TYPE kemParameterSet = PK11_ReadULongAttribute(slot, privKey->pkcs11ID, CKA_NSS_PARAMETER_SET);
CK_MECHANISM mech = { kemType, &kemParameterSet, sizeof(kemParameterSet) };
sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
if (sharedSecret == NULL) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
sharedSecret->origin = PK11_OriginUnwrap;
attrs = keyTemplate;
PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
attrs++;
PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
attrs++;
attrs += pk11_AttrFlagsToAttributes(attrFlags, attrs, &cktrue, &ckfalse);
attrs += pk11_OpFlagsToAttributes(opFlags, attrs, &cktrue);
templateCount = attrs - keyTemplate;
PR_ASSERT(templateCount <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
crv = PK11_GETTAB(slot)->C_GetInterface(KEMInterfaceName, &KEMInterfaceVersion, &KEMInterface, 0);
if (crv != CKR_OK) {
PORT_SetError(PK11_MapError(crv));
goto error;
}
KEMInterfaceFunctions = (CK_NSS_KEM_FUNCTIONS *)(KEMInterface->pFunctionList);
pk11_EnterKeyMonitor(sharedSecret);
crv = KEMInterfaceFunctions->C_Decapsulate(sharedSecret->session,
&mech,
privKey->pkcs11ID,
ciphertext->data,
ciphertext->len,
keyTemplate,
templateCount,
&sharedSecret->objectID);
pk11_ExitKeyMonitor(sharedSecret);
if (crv != CKR_OK) {
goto error;
}
*outKey = sharedSecret;
return SECSuccess;
error:
PK11_FreeSymKey(sharedSecret);
return SECFailure;
}

Просмотреть файл

@ -93,7 +93,8 @@ static PK11SlotList
pk11_tlsSlotList,
pk11_randomSlotList,
pk11_sha256SlotList,
pk11_sha512SlotList; /* slots do SHA512 and SHA384 */
pk11_sha512SlotList, /* slots do SHA512 and SHA384 */
pk11_kyberSlotList;
/************************************************************
* Generic Slot List and Slot List element manipulations
@ -848,6 +849,7 @@ PK11_InitSlotLists(void)
pk11_InitSlotListStatic(&pk11_randomSlotList);
pk11_InitSlotListStatic(&pk11_sha256SlotList);
pk11_InitSlotListStatic(&pk11_sha512SlotList);
pk11_InitSlotListStatic(&pk11_kyberSlotList);
return SECSuccess;
}
@ -874,6 +876,7 @@ PK11_DestroySlotLists(void)
pk11_FreeSlotListStatic(&pk11_randomSlotList);
pk11_FreeSlotListStatic(&pk11_sha256SlotList);
pk11_FreeSlotListStatic(&pk11_sha512SlotList);
pk11_FreeSlotListStatic(&pk11_kyberSlotList);
return;
}
@ -956,6 +959,8 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type)
return &pk11_ideaSlotList;
case CKM_FAKE_RANDOM:
return &pk11_randomSlotList;
case CKM_NSS_KYBER_KEY_PAIR_GEN:
return &pk11_kyberSlotList;
}
return NULL;
}

Просмотреть файл

@ -63,7 +63,7 @@
'SHLIB_PREFIX=\"<(dll_prefix)\"',
'NSS_SHLIB_VERSION=\"3\"',
'SOFTOKEN_SHLIB_VERSION=\"3\"'
]
],
},
'variables': {
'module': 'nss'

Просмотреть файл

@ -0,0 +1,366 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blapi.h"
#include "kem.h"
#include "pkcs11i.h"
#include "pkcs11n.h"
#include "secitem.h"
#include "secport.h"
#include "softoken.h"
KyberParams
sftk_kyber_PK11ParamToInternal(CK_NSS_KEM_PARAMETER_SET_TYPE pk11ParamSet)
{
switch (pk11ParamSet) {
case CKP_NSS_KYBER_768_ROUND3:
return params_kyber768_round3;
default:
return params_kyber_invalid;
}
}
SECItem *
sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem *pubkey)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return SECITEM_AllocItem(NULL, pubkey, KYBER768_PUBLIC_KEY_BYTES);
default:
return NULL;
}
}
SECItem *
sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem *privkey)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return SECITEM_AllocItem(NULL, privkey, KYBER768_PRIVATE_KEY_BYTES);
default:
return NULL;
}
}
SECItem *
sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem *ciphertext)
{
switch (params) {
case params_kyber768_round3:
case params_kyber768_round3_test_mode:
return SECITEM_AllocItem(NULL, ciphertext, KYBER768_CIPHERTEXT_BYTES);
default:
return NULL;
}
}
static PRBool
sftk_kyber_ValidateParams(const CK_NSS_KEM_PARAMETER_SET_TYPE *params)
{
if (!params) {
return PR_FALSE;
}
switch (*params) {
case CKP_NSS_KYBER_768_ROUND3:
return PR_TRUE;
default:
return PR_FALSE;
}
}
static PRBool
sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism)
{
if (!pMechanism) {
return PR_FALSE;
}
switch (pMechanism->mechanism) {
case CKM_NSS_KYBER:
return pMechanism->ulParameterLen == sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE) && sftk_kyber_ValidateParams(pMechanism->pParameter);
default:
return PR_FALSE;
}
}
static CK_ULONG
sftk_kem_CiphertextLen(CK_MECHANISM_PTR pMechanism)
{
/* Assumes pMechanism has been validated with sftk_kem_ValidateMechanism */
if (pMechanism->mechanism != CKM_NSS_KYBER) {
PORT_Assert(0);
return 0;
}
CK_NSS_KEM_PARAMETER_SET_TYPE *pParameterSet = pMechanism->pParameter;
switch (*pParameterSet) {
case CKP_NSS_KYBER_768_ROUND3:
return KYBER768_CIPHERTEXT_BYTES;
default:
/* unreachable if pMechanism has been validated */
PORT_Assert(0);
return 0;
}
}
/* C_Encapsulate takes a public encapsulation key hPublicKey, a secret
* phKey, and outputs a ciphertext (i.e. encapsulaton) of this secret in
* pCiphertext. */
CK_RV
NSC_Encapsulate(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPublicKey,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
/* out */ CK_OBJECT_HANDLE_PTR phKey,
/* out */ CK_BYTE_PTR pCiphertext,
/* out */ CK_ULONG_PTR pulCiphertextLen)
{
SFTKSession *session = NULL;
SFTKSlot *slot = NULL;
SFTKObject *key = NULL;
SFTKObject *encapsulationKeyObject = NULL;
SFTKAttribute *encapsulationKey = NULL;
CK_RV crv;
SFTKFreeStatus status;
CHECK_FORK();
if (!pMechanism || !phKey || !pulCiphertextLen) {
return CKR_ARGUMENTS_BAD;
}
if (!sftk_kem_ValidateMechanism(pMechanism)) {
return CKR_MECHANISM_INVALID;
}
CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
if (!pCiphertext || *pulCiphertextLen < ciphertextLen) {
*pulCiphertextLen = ciphertextLen;
return CKR_KEY_SIZE_RANGE;
}
*phKey = CK_INVALID_HANDLE;
session = sftk_SessionFromHandle(hSession);
if (session == NULL) {
return CKR_SESSION_HANDLE_INVALID;
}
slot = sftk_SlotFromSessionHandle(hSession);
if (slot == NULL) {
crv = CKR_SESSION_HANDLE_INVALID;
goto cleanup;
}
key = sftk_NewObject(slot);
if (key == NULL) {
crv = CKR_HOST_MEMORY;
goto cleanup;
}
for (unsigned long int i = 0; i < ulAttributeCount; i++) {
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
if (crv != CKR_OK) {
goto cleanup;
}
}
encapsulationKeyObject = sftk_ObjectFromHandle(hPublicKey, session);
if (encapsulationKeyObject == NULL) {
crv = CKR_KEY_HANDLE_INVALID;
goto cleanup;
}
encapsulationKey = sftk_FindAttribute(encapsulationKeyObject, CKA_VALUE);
if (encapsulationKey == NULL) {
crv = CKR_KEY_HANDLE_INVALID;
goto cleanup;
}
SECItem ciphertext = { siBuffer, pCiphertext, ciphertextLen };
SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen };
/* The length of secretBuf can be increased if we ever support other KEMs */
uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
switch (pMechanism->mechanism) {
case CKM_NSS_KYBER: {
PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
SECStatus rv = Kyber_Encapsulate(kyberParams, /* seed */ NULL, &pubKey, &ciphertext, &secret);
if (rv != SECSuccess) {
crv = CKR_FUNCTION_FAILED;
goto cleanup;
}
crv = sftk_forceAttribute(key, CKA_VALUE, sftk_item_expand(&secret));
if (crv != CKR_OK) {
goto cleanup;
}
crv = sftk_handleObject(key, session);
if (crv != CKR_OK) {
goto cleanup;
}
/* We wrote the ciphertext out directly in Kyber_Encapsulate */
*phKey = key->handle;
*pulCiphertextLen = ciphertext.len;
break;
}
default:
crv = CKR_MECHANISM_INVALID;
goto cleanup;
}
cleanup:
if (session) {
sftk_FreeSession(session);
}
if (key) {
status = sftk_FreeObject(key);
if (status == SFTK_DestroyFailure) {
return CKR_DEVICE_ERROR;
}
}
if (encapsulationKeyObject) {
status = sftk_FreeObject(encapsulationKeyObject);
if (status == SFTK_DestroyFailure) {
return CKR_DEVICE_ERROR;
}
}
if (encapsulationKey) {
sftk_FreeAttribute(encapsulationKey);
}
return crv;
}
CK_RV
NSC_Decapsulate(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPrivateKey,
CK_BYTE_PTR pCiphertext,
CK_ULONG ulCiphertextLen,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
/* out */ CK_OBJECT_HANDLE_PTR phKey)
{
SFTKSession *session = NULL;
SFTKSlot *slot = NULL;
SFTKObject *key = NULL;
SFTKObject *decapsulationKeyObject = NULL;
SFTKAttribute *decapsulationKey = NULL;
CK_RV crv;
SFTKFreeStatus status;
CHECK_FORK();
if (!pMechanism || !pCiphertext || !pTemplate || !phKey) {
return CKR_ARGUMENTS_BAD;
}
if (!sftk_kem_ValidateMechanism(pMechanism)) {
return CKR_MECHANISM_INVALID;
}
CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
if (ulCiphertextLen < ciphertextLen) {
return CKR_ARGUMENTS_BAD;
}
*phKey = CK_INVALID_HANDLE;
session = sftk_SessionFromHandle(hSession);
if (session == NULL) {
return CKR_SESSION_HANDLE_INVALID;
}
slot = sftk_SlotFromSessionHandle(hSession);
if (slot == NULL) {
crv = CKR_SESSION_HANDLE_INVALID;
goto cleanup;
}
key = sftk_NewObject(slot);
if (key == NULL) {
crv = CKR_HOST_MEMORY;
goto cleanup;
}
for (unsigned long int i = 0; i < ulAttributeCount; i++) {
crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
if (crv != CKR_OK) {
goto cleanup;
}
}
decapsulationKeyObject = sftk_ObjectFromHandle(hPrivateKey, session);
if (decapsulationKeyObject == NULL) {
crv = CKR_KEY_HANDLE_INVALID;
goto cleanup;
}
decapsulationKey = sftk_FindAttribute(decapsulationKeyObject, CKA_VALUE);
if (decapsulationKey == NULL) {
crv = CKR_KEY_HANDLE_INVALID;
goto cleanup;
}
SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue, decapsulationKey->attrib.ulValueLen };
SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen };
/* The length of secretBuf can be increased if we ever support other KEMs */
uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
switch (pMechanism->mechanism) {
case CKM_NSS_KYBER: {
PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
SECStatus rv = Kyber_Decapsulate(kyberParams, &privKey, &ciphertext, &secret);
if (rv != SECSuccess) {
crv = CKR_FUNCTION_FAILED;
goto cleanup;
}
crv = sftk_forceAttribute(key, CKA_VALUE, sftk_item_expand(&secret));
if (crv != CKR_OK) {
goto cleanup;
}
crv = sftk_handleObject(key, session);
if (crv != CKR_OK) {
goto cleanup;
}
*phKey = key->handle;
break;
}
default:
crv = CKR_MECHANISM_INVALID;
goto cleanup;
}
cleanup:
if (session) {
sftk_FreeSession(session);
}
if (key) {
status = sftk_FreeObject(key);
if (status == SFTK_DestroyFailure) {
return CKR_DEVICE_ERROR;
}
}
if (decapsulationKeyObject) {
status = sftk_FreeObject(decapsulationKeyObject);
if (status == SFTK_DestroyFailure) {
return CKR_DEVICE_ERROR;
}
}
if (decapsulationKey) {
sftk_FreeAttribute(decapsulationKey);
}
return crv;
}

Просмотреть файл

@ -0,0 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SOFTOKEN_KEM_H
#define SOFTOKEN_KEM_H
#include "pkcs11.h"
KyberParams sftk_kyber_PK11ParamToInternal(CK_NSS_KEM_PARAMETER_SET_TYPE pk11ParamSet);
SECItem* sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem* pubkey);
SECItem* sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem* privkey);
SECItem* sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem* ciphertext);
CK_RV NSC_Encapsulate(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPublicKey,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey,
CK_BYTE_PTR pCiphertext,
CK_ULONG_PTR pulCiphertextLen);
CK_RV NSC_Decapsulate(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPrivateKey,
CK_BYTE_PTR pCiphertext,
CK_ULONG ulCiphertextLen,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey);
#endif // SOFTOKEN_KEM_H

Просмотреть файл

@ -38,6 +38,7 @@ CSRCS = \
fipstest.c \
fipstokn.c \
kbkdf.c \
kem.c \
lowkey.c \
lowpbe.c \
padbuf.c \

Просмотреть файл

@ -37,6 +37,7 @@
#include "secasn1.h"
#include "secerr.h"
#include "lgglue.h"
#include "kem.h"
PRBool parentForkedAfterC_Initialize;
@ -170,6 +171,12 @@ CK_NSS_FIPS_FUNCTIONS sftk_fips_funcList = {
nsc_NSSGetFIPSStatus
};
CK_NSS_KEM_FUNCTIONS sftk_kem_funcList = {
{ 1, 0 },
NSC_Encapsulate,
NSC_Decapsulate
};
/*
* Array is orderd by default first
*/
@ -177,10 +184,11 @@ static CK_INTERFACE nss_interfaces[] = {
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_funcList_v2, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
{ (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS },
{ (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface", &sftk_kem_funcList, NSS_INTERFACE_FLAGS }
};
/* must match the count of interfaces in nss_interfaces above */
#define NSS_INTERFACE_COUNT 4
#define NSS_INTERFACE_COUNT 5
/* List of DES Weak Keys */
typedef unsigned char desKey[8];
@ -630,11 +638,14 @@ static const struct mechanismList mechanisms[] = {
/* -------------------- Constant Time TLS MACs ----------------------- */
{ CKM_NSS_HMAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
{ CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
/* --------------------IPSEC ----------------------- */
/* -------------------- IPSEC ----------------------- */
{ CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
{ CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
{ CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
{ CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE }
{ CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
/* -------------------- Kyber Operations ----------------------- */
{ CKM_NSS_KYBER_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
{ CKM_NSS_KYBER, { 0, 0, 0 }, PR_TRUE },
};
static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
@ -1076,6 +1087,16 @@ sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
recover = CK_FALSE;
wrap = CK_FALSE;
break;
case CKK_NSS_KYBER:
if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
return CKR_TEMPLATE_INCOMPLETE;
}
derive = CK_FALSE;
verify = CK_FALSE;
encrypt = CK_FALSE;
recover = CK_FALSE;
wrap = CK_FALSE;
break;
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
@ -1275,6 +1296,15 @@ sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYP
derive = CK_TRUE;
createObjectInfo = PR_FALSE;
break;
case CKK_NSS_KYBER:
if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
return CKR_TEMPLATE_INCOMPLETE;
}
if (!sftk_hasAttribute(object, CKA_VALUE)) {
return CKR_TEMPLATE_INCOMPLETE;
}
encrypt = sign = recover = wrap = CK_FALSE;
break;
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
@ -1957,6 +1987,9 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
crv = CKR_ATTRIBUTE_VALUE_INVALID;
}
break;
case CKK_NSS_KYBER:
crv = CKR_OK;
break;
default:
crv = CKR_KEY_TYPE_INCONSISTENT;
break;
@ -2111,6 +2144,9 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
}
break;
case CKK_NSS_KYBER:
break;
default:
crv = CKR_KEY_TYPE_INCONSISTENT;
break;

Просмотреть файл

@ -38,6 +38,8 @@
#include "softoken.h"
#include "secasn1.h"
#include "secerr.h"
#include "kem.h"
#include "kyber.h"
#include "prprf.h"
#include "prenv.h"
@ -5278,6 +5280,9 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession,
ECPrivateKey *ecPriv;
ECParams *ecParams;
/* Kyber */
CK_NSS_KEM_PARAMETER_SET_TYPE ckKyberParamSet;
CHECK_FORK();
if (!slot) {
@ -5300,6 +5305,11 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession,
continue;
}
if (pPublicKeyTemplate[i].type == CKA_NSS_PARAMETER_SET) {
ckKyberParamSet = *(CK_NSS_KEM_PARAMETER_SET_TYPE *)pPublicKeyTemplate[i].pValue;
continue;
}
crv = sftk_AddAttributeType(publicKey,
sftk_attr_expand(&pPublicKeyTemplate[i]));
if (crv != CKR_OK)
@ -5692,6 +5702,53 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession,
PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
break;
case CKM_NSS_KYBER_KEY_PAIR_GEN:
sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
key_type = CKK_NSS_KYBER;
SECItem privKey = { siBuffer, NULL, 0 };
SECItem pubKey = { siBuffer, NULL, 0 };
KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(ckKyberParamSet);
if (!sftk_kyber_AllocPrivKeyItem(kyberParams, &privKey)) {
crv = CKR_HOST_MEMORY;
goto kyber_done;
}
if (!sftk_kyber_AllocPubKeyItem(kyberParams, &pubKey)) {
crv = CKR_HOST_MEMORY;
goto kyber_done;
}
rv = Kyber_NewKey(kyberParams, NULL, &privKey, &pubKey);
if (rv != SECSuccess) {
crv = sftk_MapCryptError(PORT_GetError());
goto kyber_done;
}
crv = sftk_AddAttributeType(publicKey, CKA_VALUE, sftk_item_expand(&pubKey));
if (crv != CKR_OK) {
goto kyber_done;
}
crv = sftk_AddAttributeType(publicKey, CKA_NSS_PARAMETER_SET,
&ckKyberParamSet, sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
if (crv != CKR_OK) {
goto kyber_done;
}
crv = sftk_AddAttributeType(privateKey, CKA_VALUE,
sftk_item_expand(&privKey));
if (crv != CKR_OK) {
goto kyber_done;
}
crv = sftk_AddAttributeType(privateKey, CKA_NSS_PARAMETER_SET,
&ckKyberParamSet, sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
if (crv != CKR_OK) {
goto kyber_done;
}
crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
sftk_item_expand(&pubKey));
kyber_done:
SECITEM_ZfreeItem(&privKey, PR_FALSE);
SECITEM_FreeItem(&pubKey, PR_FALSE);
break;
default:
crv = CKR_MECHANISM_INVALID;
}
@ -5775,7 +5832,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hSession,
&cktrue, sizeof(CK_BBOOL));
}
if (crv == CKR_OK) {
if (crv == CKR_OK && key_type != CKK_NSS_KYBER) {
/* Perform FIPS 140-2 pairwise consistency check. */
crv = sftk_PairwiseConsistencyCheck(hSession, slot,
publicKey, privateKey, key_type);
@ -7184,6 +7241,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
CK_ULONG keySize = 0;
CK_RV crv = CKR_OK;
CK_BBOOL cktrue = CK_TRUE;
CK_BBOOL ckfalse = CK_FALSE;
CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
CK_OBJECT_CLASS classType = CKO_SECRET_KEY;
CK_KEY_DERIVATION_STRING_DATA *stringPtr;
@ -8112,7 +8170,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
#endif /* NSS_DISABLE_DEPRECATED_SEED */
case CKM_CONCATENATE_BASE_AND_KEY: {
SFTKObject *newKey;
SFTKObject *paramKey;
crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE);
if (crv != CKR_OK)
@ -8124,27 +8182,35 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
break;
}
newKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
pMechanism->pParameter,
session);
paramKey = sftk_ObjectFromHandle(*(CK_OBJECT_HANDLE *)
pMechanism->pParameter,
session);
sftk_FreeSession(session);
if (newKey == NULL) {
if (paramKey == NULL) {
crv = CKR_KEY_HANDLE_INVALID;
break;
}
if (sftk_isTrue(newKey, CKA_SENSITIVE)) {
crv = sftk_forceAttribute(newKey, CKA_SENSITIVE, &cktrue,
if (sftk_isTrue(paramKey, CKA_SENSITIVE)) {
crv = sftk_forceAttribute(key, CKA_SENSITIVE, &cktrue,
sizeof(CK_BBOOL));
if (crv != CKR_OK) {
sftk_FreeObject(newKey);
sftk_FreeObject(paramKey);
break;
}
}
att2 = sftk_FindAttribute(newKey, CKA_VALUE);
if (sftk_hasAttribute(paramKey, CKA_EXTRACTABLE) && !sftk_isTrue(paramKey, CKA_EXTRACTABLE)) {
crv = sftk_forceAttribute(key, CKA_EXTRACTABLE, &ckfalse, sizeof(CK_BBOOL));
if (crv != CKR_OK) {
sftk_FreeObject(paramKey);
break;
}
}
att2 = sftk_FindAttribute(paramKey, CKA_VALUE);
if (att2 == NULL) {
sftk_FreeObject(newKey);
sftk_FreeObject(paramKey);
crv = CKR_KEY_HANDLE_INVALID;
break;
}
@ -8152,7 +8218,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
if (keySize == 0)
keySize = tmpKeySize;
if (keySize > tmpKeySize) {
sftk_FreeObject(newKey);
sftk_FreeObject(paramKey);
sftk_FreeAttribute(att2);
crv = CKR_TEMPLATE_INCONSISTENT;
break;
@ -8160,7 +8226,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
buf = (unsigned char *)PORT_Alloc(tmpKeySize);
if (buf == NULL) {
sftk_FreeAttribute(att2);
sftk_FreeObject(newKey);
sftk_FreeObject(paramKey);
crv = CKR_HOST_MEMORY;
break;
}
@ -8172,7 +8238,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession,
crv = sftk_forceAttribute(key, CKA_VALUE, buf, keySize);
PORT_ZFree(buf, tmpKeySize);
sftk_FreeAttribute(att2);
sftk_FreeObject(newKey);
sftk_FreeObject(paramKey);
break;
}

Просмотреть файл

@ -49,6 +49,7 @@
'fipstokn.c',
'jpakesftk.c',
'kbkdf.c',
'kem.c',
'lowkey.c',
'lowpbe.c',
'padbuf.c',
@ -71,7 +72,7 @@
'sources': [
'lgglue.c',
]
}]
}],
]
},
},

Просмотреть файл

@ -600,3 +600,6 @@ ER3(SSL_ERROR_ECH_FAILED, (SSL_ERROR_BASE + 190),
ER3(SSL_ERROR_ECH_REQUIRED_ALERT, (SSL_ERROR_BASE + 191),
"SSL peer reported ECH required.")
ER3(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE, (SSL_ERROR_BASE + 140),
"SSL received a malformed hybrid key share handshake extension.")

Просмотреть файл

@ -375,6 +375,8 @@ static const CK_MECHANISM_TYPE kea_alg_defs[] = {
CKM_ECDH1_DERIVE, /* ssl_kea_ecdh_psk */
CKM_DH_PKCS_DERIVE, /* ssl_kea_dh_psk */
CKM_INVALID_MECHANISM, /* ssl_kea_tls13_any */
CKM_INVALID_MECHANISM, /* ssl_kea_ecdh_hybrid */
CKM_INVALID_MECHANISM, /* ssl_kea_ecdh_hybrid_psk */
};
PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size);
@ -733,6 +735,13 @@ ssl_KEAEnabled(const sslSocket *ss, SSLKEAType keaType)
case ssl_kea_ecdh_psk:
return ssl_NamedGroupTypeEnabled(ss, ssl_kea_ecdh);
case ssl_kea_ecdh_hybrid:
case ssl_kea_ecdh_hybrid_psk:
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
return ssl_NamedGroupTypeEnabled(ss, ssl_kea_ecdh_hybrid);
case ssl_kea_tls13_any:
return PR_TRUE;
@ -3467,7 +3476,8 @@ ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
* data into a 48-byte value, and does not expect to return the version.
*/
PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh));
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh_hybrid));
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;
@ -3545,7 +3555,8 @@ tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
* TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
* mode. Bug 1198298 */
PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh));
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh_hybrid));
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;

Просмотреть файл

@ -862,6 +862,7 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
unsigned int i;
PRBool ec;
PRBool ec_hybrid = PR_FALSE;
PRBool ff = PR_FALSE;
PRBool found = PR_FALSE;
SECStatus rv;
@ -878,7 +879,7 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECSuccess;
}
} else {
ec = ff = PR_TRUE;
ec = ec_hybrid = ff = PR_TRUE;
}
/* Mark the location of the length. */
@ -895,6 +896,9 @@ ssl_SendSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
if (group->keaType == ssl_kea_ecdh && !ec) {
continue;
}
if (group->keaType == ssl_kea_ecdh_hybrid && !ec_hybrid) {
continue;
}
if (group->keaType == ssl_kea_dh && !ff) {
continue;
}

Просмотреть файл

@ -285,6 +285,8 @@ typedef enum {
/* ECH rejected and public name authentication failed. */
SSL_ERROR_ECH_FAILED = (SSL_ERROR_BASE + 190),
SSL_ERROR_ECH_REQUIRED_ALERT = (SSL_ERROR_BASE + 191),
SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE = (SSL_ERROR_BASE + 192),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;

Просмотреть файл

@ -128,7 +128,7 @@ typedef enum { SSLAppOpRead = 0,
#define DTLS_RETRANSMIT_FINISHED_MS 30000
/* default number of entries in namedGroupPreferences */
#define SSL_NAMED_GROUP_COUNT 31
#define SSL_NAMED_GROUP_COUNT 32
/* The maximum DH and RSA bit-length supported. */
#define SSL_MAX_DH_KEY_BITS 8192
@ -908,6 +908,8 @@ struct sslEphemeralKeyPairStr {
PRCList link;
const sslNamedGroupDef *group;
sslKeyPair *keys;
sslKeyPair *kemKeys;
SECItem *kemCt;
};
struct ssl3DHParamsStr {

Просмотреть файл

@ -167,6 +167,7 @@ const sslNamedGroupDef ssl_named_groups[] = {
ECGROUP(secp256r1, 256, SECP256R1, PR_TRUE),
ECGROUP(secp384r1, 384, SECP384R1, PR_TRUE),
ECGROUP(secp521r1, 521, SECP521R1, PR_TRUE),
{ ssl_grp_kem_xyber768d00, 256, ssl_kea_ecdh_hybrid, SEC_OID_XYBER768D00, PR_TRUE },
FFGROUP(2048),
FFGROUP(3072),
FFGROUP(4096),
@ -4096,6 +4097,8 @@ ssl_NewEphemeralKeyPair(const sslNamedGroupDef *group,
PR_INIT_CLIST(&pair->link);
pair->group = group;
pair->keys = keys;
pair->kemKeys = NULL;
pair->kemCt = NULL;
return pair;
}
@ -4110,9 +4113,19 @@ ssl_CopyEphemeralKeyPair(sslEphemeralKeyPair *keyPair)
return NULL; /* error already set */
}
pair->kemCt = NULL;
if (keyPair->kemCt) {
pair->kemCt = SECITEM_DupItem(keyPair->kemCt);
if (!pair->kemCt) {
PORT_Free(pair);
return NULL;
}
}
PR_INIT_CLIST(&pair->link);
pair->group = keyPair->group;
pair->keys = ssl_GetKeyPairRef(keyPair->keys);
pair->kemKeys = keyPair->kemKeys ? ssl_GetKeyPairRef(keyPair->kemKeys) : NULL;
return pair;
}
@ -4125,6 +4138,8 @@ ssl_FreeEphemeralKeyPair(sslEphemeralKeyPair *keyPair)
}
ssl_FreeKeyPair(keyPair->keys);
ssl_FreeKeyPair(keyPair->kemKeys);
SECITEM_FreeItem(keyPair->kemCt, PR_TRUE);
PR_REMOVE_LINK(&keyPair->link);
PORT_Free(keyPair);
}

Просмотреть файл

@ -83,6 +83,8 @@ typedef enum {
ssl_kea_ecdh_psk = 5,
ssl_kea_dh_psk = 6,
ssl_kea_tls13_any = 7,
ssl_kea_ecdh_hybrid = 8,
ssl_kea_ecdh_hybrid_psk = 9,
ssl_kea_size /* number of ssl_kea_ algorithms */
} SSLKEAType;
@ -257,8 +259,9 @@ typedef enum {
ssl_grp_ffdhe_4096 = 258,
ssl_grp_ffdhe_6144 = 259,
ssl_grp_ffdhe_8192 = 260,
ssl_grp_none = 65537, /* special value */
ssl_grp_ffdhe_custom = 65538 /* special value */
ssl_grp_kem_xyber768d00 = 25497, /* draft-tls-westerbaan-xyber768d00-02 */
ssl_grp_none = 65537, /* special value */
ssl_grp_ffdhe_custom = 65538 /* special value */
} SSLNamedGroup;
typedef struct SSLExtraServerCertDataStr {

Просмотреть файл

@ -6,6 +6,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "sslt.h"
#include "stdarg.h"
#include "cert.h"
#include "ssl.h"
@ -366,17 +367,90 @@ tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
return SECSuccess;
}
static SECStatus
tls13_CreateKEMKeyPair(sslSocket *ss, const sslNamedGroupDef *groupDef,
sslKeyPair **outKeyPair)
{
PORT_Assert(groupDef);
if (groupDef->name != ssl_grp_kem_xyber768d00) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
sslKeyPair *keyPair = NULL;
SECKEYPrivateKey *privKey = NULL;
SECKEYPublicKey *pubKey = NULL;
CK_MECHANISM_TYPE mechanism = CKM_NSS_KYBER_KEY_PAIR_GEN;
CK_NSS_KEM_PARAMETER_SET_TYPE paramSet = CKP_NSS_KYBER_768_ROUND3;
PK11SlotInfo *slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);
if (!slot) {
goto loser;
}
privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism,
&paramSet, &pubKey, PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE,
CKF_DERIVE, CKF_DERIVE, ss->pkcs11PinArg);
PK11_FreeSlot(slot);
if (!privKey || !pubKey) {
goto loser;
}
keyPair = ssl_NewKeyPair(privKey, pubKey);
if (!keyPair) {
goto loser;
}
SSL_TRC(50, ("%d: SSL[%d]: Create Kyber ephemeral key %d",
SSL_GETPID(), ss ? ss->fd : NULL, groupDef->name));
PRINT_BUF(50, (ss, "Public Key", pubKey->u.kyber.publicValue.data,
pubKey->u.kyber.publicValue.len));
#ifdef TRACE
if (ssl_trace >= 50) {
SECItem d = { siBuffer, NULL, 0 };
SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_VALUE, &d);
if (rv == SECSuccess) {
PRINT_BUF(50, (ss, "Private Key", d.data, d.len));
SECITEM_FreeItem(&d, PR_FALSE);
} else {
SSL_TRC(50, ("Error extracting private key"));
}
}
#endif
*outKeyPair = keyPair;
return SECSuccess;
loser:
SECKEY_DestroyPrivateKey(privKey);
SECKEY_DestroyPublicKey(pubKey);
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
return SECFailure;
}
SECStatus
tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
sslEphemeralKeyPair **keyPair)
sslEphemeralKeyPair **outKeyPair)
{
SECStatus rv;
const ssl3DHParams *params;
sslEphemeralKeyPair *keyPair = NULL;
PORT_Assert(groupDef);
switch (groupDef->keaType) {
case ssl_kea_ecdh_hybrid:
if (groupDef->name != ssl_grp_kem_xyber768d00) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = ssl_CreateECDHEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_ec_curve25519), &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
keyPair->group = groupDef;
break;
case ssl_kea_ecdh:
rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, keyPair);
rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
@ -384,7 +458,7 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
case ssl_kea_dh:
params = ssl_GetDHEParams(groupDef);
PORT_Assert(params->name != ssl_grp_ffdhe_custom);
rv = ssl_CreateDHEKeyPair(groupDef, params, keyPair);
rv = ssl_CreateDHEKeyPair(groupDef, params, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
@ -395,7 +469,18 @@ tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
return SECFailure;
}
return rv;
// If we're creating an ECDH + KEM hybrid share and we're the client, then
// we still need to generate the KEM key pair. Otherwise we're done.
if (groupDef->keaType == ssl_kea_ecdh_hybrid && !ss->sec.isServer) {
rv = tls13_CreateKEMKeyPair(ss, groupDef, &keyPair->kemKeys);
if (rv != SECSuccess) {
ssl_FreeEphemeralKeyPair(keyPair);
return SECFailure;
}
}
*outKeyPair = keyPair;
return SECSuccess;
}
SECStatus
@ -566,6 +651,117 @@ tls13_ImportDHEKeyShare(SECKEYPublicKey *peerKey,
return SECSuccess;
}
static SECStatus
tls13_ImportKEMKeyShare(SECKEYPublicKey *peerKey, TLS13KeyShareEntry *entry)
{
SECItem pk = { siBuffer, NULL, 0 };
SECStatus rv;
if (entry->group->name != ssl_grp_kem_xyber768d00) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
pk.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
pk.len = entry->key_exchange.len - X25519_PUBLIC_KEY_BYTES;
peerKey->keyType = kyberKey;
peerKey->u.kyber.params = params_kyber768_round3;
rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.kyber.publicValue, &pk);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_HandleKEMCiphertext(sslSocket *ss, TLS13KeyShareEntry *entry, sslKeyPair *keyPair, PK11SymKey **outKey)
{
SECItem ct = { siBuffer, NULL, 0 };
SECStatus rv;
switch (entry->group->name) {
case ssl_grp_kem_xyber768d00:
if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
return SECFailure;
}
ct.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
ct.len = entry->key_exchange.len - X25519_PUBLIC_KEY_BYTES;
break;
default:
PORT_Assert(0);
ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE, PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE, CKF_DERIVE, outKey);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
}
return rv;
}
static SECStatus
tls13_HandleKEMKey(sslSocket *ss,
TLS13KeyShareEntry *entry,
PK11SymKey **key,
SECItem **ciphertext)
{
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_OBJECT_HANDLE handle;
SECStatus rv;
PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey);
if (peerKey == NULL) {
goto loser;
}
peerKey->arena = &arena.arena;
peerKey->pkcs11Slot = NULL;
peerKey->pkcs11ID = CK_INVALID_HANDLE;
rv = tls13_ImportKEMKeyShare(peerKey, entry);
if (rv != SECSuccess) {
goto loser;
}
PK11SlotInfo *slot = PK11_GetBestSlot(CKM_NSS_KYBER, ss->pkcs11PinArg);
if (!slot) {
goto loser;
}
handle = PK11_ImportPublicKey(slot, peerKey, PR_FALSE);
PK11_FreeSlot(slot); /* peerKey holds a slot reference on success. */
if (handle == CK_INVALID_HANDLE) {
goto loser;
}
rv = PK11_Encapsulate(peerKey,
CKM_HKDF_DERIVE, PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE,
CKF_DERIVE, key, ciphertext);
/* Destroy the imported public key */
PORT_Assert(peerKey->pkcs11Slot);
PK11_DestroyObject(peerKey->pkcs11Slot, peerKey->pkcs11ID);
PK11_FreeSlot(peerKey->pkcs11Slot);
PORT_DestroyCheapArena(&arena);
return SECSuccess;
loser:
PORT_DestroyCheapArena(&arena);
return SECFailure;
}
SECStatus
tls13_HandleKeyShare(sslSocket *ss,
TLS13KeyShareEntry *entry,
@ -576,7 +772,6 @@ tls13_HandleKeyShare(sslSocket *ss,
PORTCheapArenaPool arena;
SECKEYPublicKey *peerKey;
CK_MECHANISM_TYPE mechanism;
PRErrorCode errorCode;
PK11SymKey *key;
SECStatus rv;
int keySize = 0;
@ -591,6 +786,17 @@ tls13_HandleKeyShare(sslSocket *ss,
peerKey->pkcs11ID = CK_INVALID_HANDLE;
switch (entry->group->keaType) {
case ssl_kea_ecdh_hybrid:
if (entry->group->name != ssl_grp_kem_xyber768d00 || entry->key_exchange.len < X25519_PUBLIC_KEY_BYTES) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
goto loser;
}
rv = ssl_ImportECDHKeyShare(peerKey,
entry->key_exchange.data,
X25519_PUBLIC_KEY_BYTES,
ssl_LookupNamedGroup(ssl_grp_ec_curve25519));
mechanism = CKM_ECDH1_DERIVE;
break;
case ssl_kea_ecdh:
rv = ssl_ImportECDHKeyShare(peerKey,
entry->key_exchange.data,
@ -621,14 +827,13 @@ tls13_HandleKeyShare(sslSocket *ss,
ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
goto loser;
}
*out = key;
PORT_DestroyCheapArena(&arena);
return SECSuccess;
loser:
PORT_DestroyCheapArena(&arena);
errorCode = PORT_GetError(); /* don't overwrite the error code */
tls13_FatalError(ss, errorCode, illegal_parameter);
return SECFailure;
}
@ -2369,6 +2574,9 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare)
{
SECStatus rv;
sslEphemeralKeyPair *keyPair; /* ours */
SECItem *ciphertext = NULL;
PK11SymKey *dheSecret = NULL;
PK11SymKey *kemSecret = NULL;
SSL_TRC(3, ("%d: TLS13[%d]: handle client_key_share handshake",
SSL_GETPID(), ss->fd));
@ -2402,8 +2610,38 @@ tls13_HandleClientKeyShare(sslSocket *ss, TLS13KeyShareEntry *peerShare)
rv = tls13_HandleKeyShare(ss, peerShare, keyPair->keys,
tls13_GetHash(ss),
&ss->ssl3.hs.dheSecret);
return rv; /* Error code set already. */
&dheSecret);
if (rv != SECSuccess) {
goto loser; /* Error code already set. */
}
if (peerShare->group->keaType == ssl_kea_ecdh_hybrid) {
rv = tls13_HandleKEMKey(ss, peerShare, &kemSecret, &ciphertext);
if (rv != SECSuccess) {
goto loser; /* Error set by tls13_HandleKEMKey */
}
// We may need to handle different "combiners" here in the future. For
// now this is specific to xyber768d00.
PORT_Assert(peerShare->group->name == ssl_grp_kem_xyber768d00);
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
if (!ss->ssl3.hs.dheSecret) {
goto loser; /* Error set by PK11_ConcatSymKeys */
}
keyPair->kemCt = ciphertext;
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
} else {
ss->ssl3.hs.dheSecret = dheSecret;
}
return SECSuccess;
loser:
SECITEM_FreeItem(ciphertext, PR_TRUE);
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
/*
@ -3165,6 +3403,11 @@ tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group)
ss->statelessResume ? ssl_kea_ecdh_psk : ssl_kea_ecdh;
ss->sec.keaType = ssl_kea_ecdh;
break;
case ssl_kea_ecdh_hybrid:
ss->ssl3.hs.kea_def_mutable.exchKeyType =
ss->statelessResume ? ssl_kea_ecdh_hybrid_psk : ssl_kea_ecdh_hybrid;
ss->sec.keaType = ssl_kea_ecdh_hybrid;
break;
case ssl_kea_dh:
ss->ssl3.hs.kea_def_mutable.exchKeyType =
ss->statelessResume ? ssl_kea_dh_psk : ssl_kea_dh;
@ -3186,6 +3429,8 @@ tls13_HandleServerKeyShare(sslSocket *ss)
SECStatus rv;
TLS13KeyShareEntry *entry;
sslEphemeralKeyPair *keyPair;
PK11SymKey *dheSecret = NULL;
PK11SymKey *kemSecret = NULL;
SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
SSL_GETPID(), ss->fd));
@ -3212,14 +3457,39 @@ tls13_HandleServerKeyShare(sslSocket *ss)
rv = tls13_HandleKeyShare(ss, entry, keyPair->keys,
tls13_GetHash(ss),
&ss->ssl3.hs.dheSecret);
if (rv != SECSuccess)
return SECFailure; /* Error code set by caller. */
&dheSecret);
if (rv != SECSuccess) {
goto loser; /* Error code already set. */
}
if (entry->group->keaType == ssl_kea_ecdh_hybrid) {
rv = tls13_HandleKEMCiphertext(ss, entry, keyPair->kemKeys, &kemSecret);
if (rv != SECSuccess) {
goto loser; /* Error set by tls13_HandleKEMCiphertext */
}
// We may need to handle different "combiners" here in the future. For
// now this is specific to xyber768d00.
PORT_Assert(entry->group->name == ssl_grp_kem_xyber768d00);
ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
if (!ss->ssl3.hs.dheSecret) {
goto loser; /* Error set by PK11_ConcatSymKeys */
}
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
} else {
ss->ssl3.hs.dheSecret = dheSecret;
}
tls13_SetKeyExchangeType(ss, entry->group);
ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->keys->pubKey);
return SECSuccess;
loser:
PK11_FreeSymKey(dheSecret);
PK11_FreeSymKey(kemSecret);
FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
return SECFailure;
}
/*

Просмотреть файл

@ -49,60 +49,62 @@ tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/*
* [draft-ietf-tls-tls13-11] Section 6.3.2.3.
* [RFC 8446] Section 4.2.8.
*
* struct {
* NamedGroup group;
* opaque key_exchange<1..2^16-1>;
* } KeyShareEntry;
*
* struct {
* select (role) {
* case client:
* KeyShareEntry client_shares<4..2^16-1>;
*
* case server:
* KeyShareEntry server_share;
* }
* } KeyShare;
*
* DH is Section 6.3.2.3.1.
*
* opaque dh_Y<1..2^16-1>;
*
* ECDH is Section 6.3.2.3.2.
*
* opaque point <1..2^8-1>;
*/
PRUint32
tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
tls13_SizeOfKeyShareEntry(const sslEphemeralKeyPair *keyPair)
{
/* Size = NamedGroup(2) + length(2) + opaque<?> share */
PRUint32 size = 2 + 2;
const SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
switch (pubKey->keyType) {
case ecKey:
return 2 + 2 + pubKey->u.ec.publicValue.len;
size += pubKey->u.ec.publicValue.len;
break;
case dhKey:
return 2 + 2 + pubKey->u.dh.prime.len;
size += pubKey->u.dh.prime.len;
break;
default:
PORT_Assert(0);
return 0;
}
return 0;
if (keyPair->kemKeys) {
PORT_Assert(!keyPair->kemCt);
PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00);
pubKey = keyPair->kemKeys->pubKey;
size += pubKey->u.kyber.publicValue.len;
}
if (keyPair->kemCt) {
PORT_Assert(!keyPair->kemKeys);
PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00);
size += keyPair->kemCt->len;
}
return size;
}
SECStatus
tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
SECKEYPublicKey *pubKey)
tls13_EncodeKeyShareEntry(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
{
SECStatus rv;
unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
unsigned int size = tls13_SizeOfKeyShareEntry(keyPair);
rv = sslBuffer_AppendNumber(buf, group, 2);
rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2);
if (rv != SECSuccess)
return rv;
rv = sslBuffer_AppendNumber(buf, size - 4, 2);
if (rv != SECSuccess)
return rv;
const SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
switch (pubKey->keyType) {
case ecKey:
rv = sslBuffer_Append(buf, pubKey->u.ec.publicValue.data,
@ -117,6 +119,22 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
break;
}
if (rv != SECSuccess) {
return rv;
}
if (keyPair->kemKeys) {
PORT_Assert(!keyPair->kemCt);
PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00);
pubKey = keyPair->kemKeys->pubKey;
rv = sslBuffer_Append(buf, pubKey->u.kyber.publicValue.data, pubKey->u.kyber.publicValue.len);
}
if (keyPair->kemCt) {
PORT_Assert(!keyPair->kemKeys);
PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00);
rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len);
}
return rv;
}
@ -147,9 +165,7 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
cursor != &ss->ephemeralKeyPairs;
cursor = PR_NEXT_LINK(cursor)) {
sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
rv = tls13_EncodeKeyShareEntry(buf,
keyPair->group->name,
keyPair->keys->pubKey);
rv = tls13_EncodeKeyShareEntry(buf, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
@ -392,8 +408,7 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name,
keyPair->keys->pubKey);
rv = tls13_EncodeKeyShareEntry(buf, keyPair);
if (rv != SECSuccess) {
return SECFailure;
}

Просмотреть файл

@ -87,9 +87,8 @@ SECStatus tls13_ServerSendHrrCookieXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
SECStatus tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp);
PRUint32 tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey);
SECStatus tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
SECKEYPublicKey *pubKey);
PRUint32 tls13_SizeOfKeyShareEntry(const sslEphemeralKeyPair *keyPair);
SECStatus tls13_EncodeKeyShareEntry(sslBuffer *buf, sslEphemeralKeyPair *keyPair);
SECStatus tls13_ServerHandleInnerEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECItem *data);
SECStatus tls13_ServerHandleOuterEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,

Просмотреть файл

@ -5,6 +5,8 @@
#ifndef _FREEBL_H_
#define _FREEBL_H_
#define X25519_PUBLIC_KEY_BYTES 32U
/* deprecated */
typedef enum {
ECPoint_Uncompressed,

Просмотреть файл

@ -16,6 +16,7 @@
'ciferfam.h',
'eccutil.h',
'hasht.h',
'kyber.h',
'nssb64.h',
'nssb64t.h',
'nssilckt.h',

Просмотреть файл

@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef KYBER_UTIL_H
#define KYBER_UTIL_H
#define KYBER768_PUBLIC_KEY_BYTES 1184U
#define KYBER768_PRIVATE_KEY_BYTES 2400U
#define KYBER768_CIPHERTEXT_BYTES 1088U
#define KYBER_SHARED_SECRET_BYTES 32U
#define KYBER_KEYPAIR_COIN_BYTES 64U
#define KYBER_ENC_COIN_BYTES 32U
typedef enum {
params_kyber_invalid,
/*
* The Kyber768 parameters specified in version 3.02 of the NIST submission
* https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
*/
params_kyber768_round3,
/*
* Identical to params_kyber768_round3 except that this parameter set allows
* the use of a seed in `Kyber_Encapsulate` for testing.
*/
params_kyber768_round3_test_mode,
} KyberParams;
#endif /* KYBER_UTIL_H */

Просмотреть файл

@ -9,6 +9,7 @@ EXPORTS = \
ciferfam.h \
eccutil.h \
hasht.h \
kyber.h \
nssb64.h \
nssb64t.h \
nsslocks.h \

Просмотреть файл

@ -55,6 +55,8 @@
#define CKK_NSS_CHACHA20 (CKK_NSS + 4)
#define CKK_NSS_KYBER (CKK_NSS + 5)
/*
* NSS-defined certificate types
*
@ -107,6 +109,8 @@
#define CKA_NSS_VALIDATION_LEVEL (CKA_NSS + 38)
#define CKA_NSS_VALIDATION_MODULE_ID (CKA_NSS + 39)
#define CKA_NSS_PARAMETER_SET (CKA_NSS + 40)
/*
* Trust attributes:
*
@ -258,6 +262,10 @@
#define CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA (CKM_NSS + 43)
#define CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA (CKM_NSS + 44)
/* Kyber */
#define CKM_NSS_KYBER_KEY_PAIR_GEN (CKM_NSS + 45)
#define CKM_NSS_KYBER (CKM_NSS + 46)
/*
* HISTORICAL:
* Do not attempt to use these. They are only used by NSS's internal
@ -277,6 +285,10 @@
#define CKM_TLS_PRF_GENERAL 0x80000373UL
/* Parameter set identifiers */
#define CKP_NSS (CKM_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
#define CKP_NSS_KYBER_768_ROUND3 (CKP_NSS + 1)
/* FIPS Indicator defines */
#define CKS_NSS_UNINITIALIZED 0xffffffffUL
#define CKS_NSS_FIPS_NOT_OK 0UL
@ -355,6 +367,8 @@ typedef struct CK_NSS_AEAD_PARAMS {
/* NSS specific types */
typedef CK_ULONG CK_NSS_VALIDATION_TYPE;
typedef CK_ULONG CK_NSS_KEM_PARAMETER_SET_TYPE;
/* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms.
See RFC 5869.
@ -622,6 +636,32 @@ typedef struct CK_NSS_FIPS_FUNCTIONS {
CK_NSS_GetFIPSStatus NSC_NSSGetFIPSStatus;
} CK_NSS_FIPS_FUNCTIONS;
/* KEM interface. This may move to the normal PKCS #11 table in the future. For
* now it's called "Vendor NSS KEM Interface" */
typedef CK_RV (*CK_NSS_Encapsulate)(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPublicKey,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey,
CK_BYTE_PTR pCiphertext,
CK_ULONG_PTR pulCiphertextLen);
typedef CK_RV (*CK_NSS_Decapsulate)(CK_SESSION_HANDLE hSession,
CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hPrivateKey,
CK_BYTE_PTR pCiphertext,
CK_ULONG ulCiphertextLen,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_OBJECT_HANDLE_PTR phKey);
typedef struct CK_NSS_KEM_FUNCTIONS {
CK_VERSION version;
CK_NSS_Encapsulate C_Encapsulate;
CK_NSS_Decapsulate C_Decapsulate;
} CK_NSS_KEM_FUNCTIONS;
/* There was an inconsistency between the spec and the header file in defining
* the CK_GCM_PARAMS structure. The authoritative reference is the header file,
* but NSS used the spec when adding it to its own header. In V3 we've

Просмотреть файл

@ -1815,6 +1815,9 @@ const static SECOidData oids[SEC_OID_TOTAL] = {
OD(hmac_sha3_256, SEC_OID_HMAC_SHA3_256, "HMAC SHA3-256", CKM_SHA3_256_HMAC, INVALID_CERT_EXTENSION),
OD(hmac_sha3_384, SEC_OID_HMAC_SHA3_384, "HMAC SHA3-384", CKM_SHA3_384_HMAC, INVALID_CERT_EXTENSION),
OD(hmac_sha3_512, SEC_OID_HMAC_SHA3_512, "HMAC SHA3-512", CKM_SHA3_512_HMAC, INVALID_CERT_EXTENSION),
ODE(SEC_OID_XYBER768D00,
"X25519+Kyber768 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
};
/* PRIVATE EXTENDED SECOID Table

Просмотреть файл

@ -512,6 +512,8 @@ typedef enum {
SEC_OID_HMAC_SHA3_384 = 370,
SEC_OID_HMAC_SHA3_512 = 371,
SEC_OID_XYBER768D00 = 372,
SEC_OID_TOTAL
} SECOidTag;

Просмотреть файл

@ -58,7 +58,7 @@ cipher_init()
# the function does not use the -1 -2 offsets
# because ./bltest -T -m ecdsa -S -d returns the self-test of all test vectors provided
########################################################################
cipher_ecdsa()
cipher_without_offset()
{
echo "bltest -T -m $PARAM -d $CIPHERTESTDIR"
${PROFTOOL} ${BINDIR}/bltest${PROG_SUFFIX} -T -m $PARAM -d $CIPHERTESTDIR
@ -66,17 +66,7 @@ cipher_ecdsa()
html_msg 1 $EXP_RET "$TESTNAME"
echo "$failedStr"
fi
}
cipher_sha3()
{
echo "bltest -T -m $PARAM -d $CIPHERTESTDIR"
${PROFTOOL} ${BINDIR}/bltest${PROG_SUFFIX} -T -m $PARAM -d $CIPHERTESTDIR
if [ $? -ne 0 ]; then
html_msg 1 $EXP_RET "$TESTNAME"
echo "$failedStr"
fi
}
}
############################## cipher_main #############################
# local shell function to test NSS ciphers
@ -91,10 +81,10 @@ cipher_main()
echo "$SCRIPTNAME: $TESTNAME --------------------------------"
failedStr=""
res=0
if [[ "$TESTNAME" == "ECDSA Sign" || "$TESTNAME" == "ECDSA Verify" ]] ; then
cipher_ecdsa
elif [[ "$TESTNAME" == "SHA3 224 Hash" || "$TESTNAME" == "SHA3 256 Hash" || "$TESTNAME" == "SHA3 384 Hash" || "$TESTNAME" == "SHA3 512 Hash" ]] ; then
cipher_sha3
if [[ "$TESTNAME" == "ECDSA Sign" || "$TESTNAME" == "ECDSA Verify"
|| "$TESTNAME" == "SHA3 224 Hash" || "$TESTNAME" == "SHA3 256 Hash"
|| "$TESTNAME" == "SHA3 384 Hash" || "$TESTNAME" == "SHA3 512 Hash" ]] ; then
cipher_without_offset
else
inOff=0
while [ $inOff -lt 8 ]