Commit d0478ef4 authored by Robert Relyea's avatar Robert Relyea

Bug 1496124 - Populate public values for imported private keys, r=mt

--HG--
extra : rebase_source : 6df6aad46f988901e197846c7845c9e845be84d7
extra : amend_source : cdc2c9bc29b9108ad6d481c3a2feef16d17a9dc3
extra : histedit_source : a9f67483dca90f1cb4207a480a2b84bebbd1baa0%2C99c4cdc7706e59ab4bd225caf6d17585c2adf0a3
parent 85e5c1c0
......@@ -56,6 +56,7 @@ NSS_SRCDIRS = \
p7sign \
p7verify \
pk12util \
pk11importtest \
pk11ectest \
pk11gcmtest \
pk11mode \
......
#! gmake
#
# 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/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include ../platlibs.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################
include ../platrules.mk
# 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/.
CORE_DEPTH = ../..
MODULE = nss
CSRCS = pk11importtest.c \
$(NULL)
REQUIRES = seccmd
PROGRAM = pk11importtest
This diff is collapsed.
# 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/.
{
'includes': [
'../../coreconf/config.gypi',
'../../cmd/platlibs.gypi'
],
'targets': [
{
'target_name': 'pk11importtest',
'type': 'executable',
'sources': [
'pk11importtest.c'
],
'dependencies': [
'<(DEPTH)/exports.gyp:dbm_exports',
'<(DEPTH)/exports.gyp:nss_exports'
]
}
],
'variables': {
'module': 'nss'
}
}
......@@ -11,6 +11,7 @@
#include "cert.h"
#include "keyhi.h"
#include "p12.h"
#include "pk11pqg.h"
#include "pk11pub.h"
#include "pkcs11uri.h"
......@@ -41,6 +42,7 @@ struct ScopedDelete {
void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
void operator()(PQGParams* pqg) { PK11_PQG_DestroyParams(pqg); }
void operator()(SEC_PKCS12DecoderContext* dcx) {
SEC_PKCS12DecoderFinish(dcx);
}
......@@ -66,6 +68,7 @@ SCOPED(CERTName);
SCOPED(CERTSubjectPublicKeyInfo);
SCOPED(PK11SlotInfo);
SCOPED(PK11SymKey);
SCOPED(PQGParams);
SCOPED(PRFileDesc);
SCOPED(SECAlgorithmID);
SCOPED(SECKEYEncryptedPrivateKeyInfo);
......@@ -82,4 +85,9 @@ SCOPED(CERTDistNames);
#undef SCOPED
struct StackSECItem : public SECItem {
StackSECItem() : SECItem({siBuffer, nullptr, 0}) {}
~StackSECItem() { SECITEM_FreeItem(this, PR_FALSE); }
};
#endif // nss_scoped_ptrs_h__
......@@ -33,6 +33,7 @@ struct ScopedMaybeDelete {
SCOPED(SECAlgorithmID);
SCOPED(SECItem);
SCOPED(PK11URI);
SCOPED(PLArenaPool);
#undef SCOPED
......
......@@ -10,7 +10,23 @@
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
const char *workdir = "";
uint32_t flags = NSS_INIT_READONLY;
for (int i = 0; i < argc; i++) {
if (!strcmp(argv[i], "-d")) {
if (i + 1 >= argc) {
PR_fprintf(PR_STDERR, "Usage: %s [-d <dir> [-w]]\n", argv[0]);
exit(2);
}
workdir = argv[i + 1];
i++;
} else if (!strcmp(argv[i], "-w")) {
flags &= ~NSS_INIT_READONLY;
}
}
if (NSS_Initialize(workdir, "", "", SECMOD_DB, flags) != SECSuccess) {
return 1;
}
if (NSS_SetDomesticPolicy() != SECSuccess) {
......
......@@ -13,6 +13,7 @@ CPPSRCS = \
pk11_ecdsa_unittest.cc \
pk11_encrypt_derive_unittest.cc \
pk11_export_unittest.cc \
pk11_import_unittest.cc \
pk11_pbkdf2_unittest.cc \
pk11_prf_unittest.cc \
pk11_prng_unittest.cc \
......@@ -33,4 +34,3 @@ EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)cpputil.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) \
$(NULL)
......@@ -18,6 +18,7 @@
'pk11_curve25519_unittest.cc',
'pk11_ecdsa_unittest.cc',
'pk11_encrypt_derive_unittest.cc',
'pk11_import_unittest.cc',
'pk11_pbkdf2_unittest.cc',
'pk11_prf_unittest.cc',
'pk11_prng_unittest.cc',
......
......@@ -1677,6 +1677,92 @@ PK11_MakeKEAPubKey(unsigned char *keyData, int length)
return pubk;
}
SECStatus
SECKEY_SetPublicValue(SECKEYPrivateKey *privKey, SECItem *publicValue)
{
SECStatus rv;
SECKEYPublicKey pubKey;
PLArenaPool *arena;
PK11SlotInfo *slot = privKey->pkcs11Slot;
CK_OBJECT_HANDLE privKeyID = privKey->pkcs11ID;
if (privKey == NULL || publicValue == NULL ||
publicValue->data == NULL || publicValue->len == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
pubKey.arena = NULL;
pubKey.keyType = privKey->keyType;
pubKey.pkcs11Slot = NULL;
pubKey.pkcs11ID = CK_INVALID_HANDLE;
/* can't use PORT_InitCheapArena here becase SECKEY_DestroyPublic is used
* to free it, and it uses PORT_FreeArena which not only frees the
* underlying arena, it also frees the allocated arena struct. */
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
pubKey.arena = arena;
if (arena == NULL) {
return SECFailure;
}
rv = SECFailure;
switch (privKey->keyType) {
default:
/* error code already set to SECFailure */
break;
case rsaKey:
pubKey.u.rsa.modulus = *publicValue;
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PUBLIC_EXPONENT,
arena, &pubKey.u.rsa.publicExponent);
break;
case dsaKey:
pubKey.u.dsa.publicValue = *publicValue;
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
arena, &pubKey.u.dsa.params.prime);
if (rv != SECSuccess) {
break;
}
rv = PK11_ReadAttribute(slot, privKeyID, CKA_SUBPRIME,
arena, &pubKey.u.dsa.params.subPrime);
if (rv != SECSuccess) {
break;
}
rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
arena, &pubKey.u.dsa.params.base);
break;
case dhKey:
pubKey.u.dh.publicValue = *publicValue;
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
arena, &pubKey.u.dh.prime);
if (rv != SECSuccess) {
break;
}
rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
arena, &pubKey.u.dh.base);
break;
case ecKey:
pubKey.u.ec.publicValue = *publicValue;
pubKey.u.ec.encoding = ECPoint_Undefined;
pubKey.u.ec.size = 0;
rv = PK11_ReadAttribute(slot, privKeyID, CKA_EC_PARAMS,
arena, &pubKey.u.ec.DEREncodedParams);
break;
}
if (rv == SECSuccess) {
rv = PK11_ImportPublicKey(slot, &pubKey, PR_TRUE);
}
/* Even though pubKey is stored on the stack, we've allocated
* some of it's data from the arena. SECKEY_DestroyPublicKey
* destroys keys by freeing the arena, so this will clean up all
* the data we allocated specifically for the key above. It will
* also free any slot references which we may have picked up in
* PK11_ImportPublicKey. It won't delete the underlying key if
* its a Token/Permanent key (which it will be if
* PK11_ImportPublicKey succeeds). */
SECKEY_DestroyPublicKey(&pubKey);
return rv;
}
/*
* NOTE: This function doesn't return a SECKEYPrivateKey struct to represent
* the new private key object. If it were to create a session object that
......@@ -1802,12 +1888,6 @@ try_faulty_3des:
nickname, publicValue, isPerm, isPrivate,
key_type, usage, usageCount, wincx);
if (privKey) {
if (privk) {
*privk = privKey;
} else {
SECKEY_DestroyPrivateKey(privKey);
}
privKey = NULL;
rv = SECSuccess;
goto done;
}
......@@ -1837,6 +1917,25 @@ try_faulty_3des:
rv = SECFailure;
done:
if ((rv == SECSuccess) && isPerm) {
/* If we are importing a token object,
* create the corresponding public key.
* If this fails, just continue as the target
* token simply might not support persistant
* public keys. Such tokens are usable, but
* need to be authenticated before searching
* for user certs. */
(void)SECKEY_SetPublicValue(privKey, publicValue);
}
if (privKey) {
if (privk) {
*privk = privKey;
} else {
SECKEY_DestroyPrivateKey(privKey);
}
privKey = NULL;
}
if (crypto_param != NULL) {
SECITEM_ZfreeItem(crypto_param, PR_TRUE);
}
......
......@@ -1815,8 +1815,6 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
break; /* key was not DER encoded, no need to unwrap */
}
PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519);
/* handle the encoded case */
if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) &&
pubKey->u.ec.publicValue.len > keyLen) {
......@@ -1827,7 +1825,13 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
SEC_ASN1_GET(SEC_OctetStringTemplate),
&pubKey->u.ec.publicValue);
/* nope, didn't decode correctly */
if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) {
if ((rv != SECSuccess) || (publicValue.len != keyLen)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
break;
}
/* we don't handle compressed points except in the case of ECCurve25519 */
if ((pubKey->u.ec.ecParams.fieldID.type != ec_field_plain) &&
(publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)) {
crv = CKR_ATTRIBUTE_VALUE_INVALID;
break;
}
......
......@@ -168,6 +168,7 @@
'cmd/pk11ectest/pk11ectest.gyp:pk11ectest',
'cmd/pk11gcmtest/pk11gcmtest.gyp:pk11gcmtest',
'cmd/pk11mode/pk11mode.gyp:pk11mode',
'cmd/pk11importtest/pk11importtest.gyp:pk11importtest',
'cmd/pk1sign/pk1sign.gyp:pk1sign',
'cmd/pp/pp.gyp:pp',
'cmd/rsaperf/rsaperf.gyp:rsaperf',
......
......@@ -252,7 +252,15 @@ dbtest_main()
else
html_passed "Nicknane conflict test-setting nickname conflict was correctly rejected"
fi
# import a token private key and make sure the corresponding public key is
# created
${BINDIR}/pk11importtest -d ${CONFLICT_DIR} -f ${R_PWFILE}
ret=$?
if [ $ret -ne 0 ]; then
html_failed "Importing Token Private Key does not create the corrresponding Public Key"
else
html_passed "Importing Token Private Key correctly creates the corrresponding Public Key"
fi
}
################## main #################################################
......
......@@ -23,6 +23,7 @@
gtest_init()
{
cd "$(dirname "$1")"
SOURCE_DIR="$PWD"/../..
if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ]; then
cd ../common
. ./init.sh
......@@ -33,6 +34,7 @@ gtest_init()
if [ -z "${CLEANUP}" ] ; then # if nobody else is responsible for
CLEANUP="${SCRIPTNAME}" # cleaning this script will do it
fi
}
########################## gtest_start #############################
......@@ -42,7 +44,7 @@ gtest_start()
{
echo "gtests: ${GTESTS}"
for i in ${GTESTS}; do
if [ ! -f ${BINDIR}/$i ]; then
if [ ! -f "${BINDIR}/$i" ]; then
html_unknown "Skipping $i (not built)"
continue
fi
......@@ -50,20 +52,22 @@ gtest_start()
html_head "$i"
if [ ! -d "$GTESTDIR" ]; then
mkdir -p "$GTESTDIR"
echo "${BINDIR}/certutil" -N -d "$GTESTDIR" --empty-password 2>&1
"${BINDIR}/certutil" -N -d "$GTESTDIR" --empty-password 2>&1
fi
cd "$GTESTDIR"
GTESTREPORT="$GTESTDIR/report.xml"
PARSED_REPORT="$GTESTDIR/report.parsed"
echo "executing $i"
${BINDIR}/$i "${SOURCE_DIR}/gtests/freebl_gtest/kat/Hash_DRBG.rsp" \
-d "$GTESTDIR" --gtest_output=xml:"${GTESTREPORT}" \
--gtest_filter="${GTESTFILTER-*}"
"${BINDIR}/$i" "${SOURCE_DIR}/gtests/freebl_gtest/kat/Hash_DRBG.rsp" \
-d "$GTESTDIR" -w --gtest_output=xml:"${GTESTREPORT}" \
--gtest_filter="${GTESTFILTER:-*}"
html_msg $? 0 "$i run successfully"
echo "test output dir: ${GTESTREPORT}"
echo "executing sed to parse the xml report"
sed -f ${COMMON}/parsegtestreport.sed "${GTESTREPORT}" > "${PARSED_REPORT}"
sed -f "${COMMON}/parsegtestreport.sed" "$GTESTREPORT" > "$PARSED_REPORT"
echo "processing the parsed report"
cat "${PARSED_REPORT}" | while read result name; do
cat "$PARSED_REPORT" | while read result name; do
if [ "$result" = "notrun" ]; then
echo "$name" SKIPPED
elif [ "$result" = "run" ]; then
......@@ -78,13 +82,12 @@ gtest_start()
gtest_cleanup()
{
html "</TABLE><BR>"
cd ${QADIR}
cd "${QADIR}"
. common/cleanup.sh
}
################## main #################################################
GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest"
SOURCE_DIR="$PWD"/../..
gtest_init $0
GTESTS="${GTESTS:-prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest}"
gtest_init "$0"
gtest_start
gtest_cleanup
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment