mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 09:54:42 +00:00
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:
parent
8ecc4d2b75
commit
8e8e91d1a7
@ -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
vendored
Normal file
411
security/nss/automation/vendor/kyber/ref/vendor.py
vendored
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."
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
15005
security/nss/gtests/common/testvectors/kwp-vectors.json
Normal file
15005
security/nss/gtests/common/testvectors/kwp-vectors.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -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',
|
||||
|
2525
security/nss/gtests/freebl_gtest/kat/kyber768_kat.h
Normal file
2525
security/nss/gtests/freebl_gtest/kat/kyber768_kat.h
Normal file
File diff suppressed because it is too large
Load Diff
293
security/nss/gtests/freebl_gtest/kyber_unittest.cc
Normal file
293
security/nss/gtests/freebl_gtest/kyber_unittest.cc
Normal file
@ -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 \
|
||||
|
239
security/nss/gtests/freebl_gtest/rsablind_unittest.cc
Normal file
239
security/nss/gtests/freebl_gtest/rsablind_unittest.cc
Normal file
@ -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
|
||||
|
118
security/nss/gtests/pk11_gtest/pk11_kem_unittest.cc
Normal file
118
security/nss/gtests/pk11_gtest/pk11_kem_unittest.cc
Normal file
@ -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_;
|
||||
}
|
||||
|
155
security/nss/gtests/pk11_gtest/pk11_symkey_unittest.cc
Normal file
155
security/nss/gtests/pk11_gtest/pk11_symkey_unittest.cc
Normal file
@ -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.
|
||||
|
273
security/nss/gtests/ssl_gtest/tls_xyber_unittest.cc
Normal file
273
security/nss/gtests/ssl_gtest/tls_xyber_unittest.cc
Normal file
@ -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, ¤t_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, ©k->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': [
|
||||
|
2693
security/nss/lib/freebl/kyber-pqcrystals-ref.c
Normal file
2693
security/nss/lib/freebl/kyber-pqcrystals-ref.c
Normal file
File diff suppressed because it is too large
Load Diff
144
security/nss/lib/freebl/kyber-pqcrystals-ref.h
Normal file
144
security/nss/lib/freebl/kyber-pqcrystals-ref.h
Normal file
@ -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
|
205
security/nss/lib/freebl/kyber.c
Normal file
205
security/nss/lib/freebl/kyber.c
Normal file
@ -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 */
|
||||
|
471
security/nss/lib/freebl/rsa_blind.c
Normal file
471
security/nss/lib/freebl/rsa_blind.c
Normal file
@ -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,
|
||||
¶m, 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,
|
||||
©OfLeft, ©OfRight);
|
||||
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'
|
||||
|
366
security/nss/lib/softoken/kem.c
Normal file
366
security/nss/lib/softoken/kem.c
Normal file
@ -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;
|
||||
}
|
34
security/nss/lib/softoken/kem.h
Normal file
34
security/nss/lib/softoken/kem.h
Normal file
@ -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,
|
||||
¶mSet, &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',
|
||||
|
32
security/nss/lib/util/kyber.h
Normal file
32
security/nss/lib/util/kyber.h
Normal file
@ -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 ]
|
||||
|
Loading…
Reference in New Issue
Block a user