Blame SOURCES/nss-3.39-create-public-key-on-private-import.patch

76e454
# HG changeset patch
76e454
# User Robert Relyea <rrelyea@redhat.com>
76e454
# Date 1544226862 28800
76e454
#      Fri Dec 07 15:54:22 2018 -0800
76e454
# Node ID 521a5b2f10cc197b9349df033f9d3cca0b5226c5
76e454
# Parent  5ac4d4904afae59149bb1fab49c3b21244a51a22
76e454
try: -b do -u all - p all -t all
76e454
76e454
diff --git a/cmd/manifest.mn b/cmd/manifest.mn
76e454
--- a/cmd/manifest.mn
76e454
+++ b/cmd/manifest.mn
76e454
@@ -51,16 +51,17 @@ NSS_SRCDIRS = \
76e454
  ocspclnt  \
76e454
  ocspresp \
76e454
  oidcalc  \
76e454
  p7content  \
76e454
  p7env  \
76e454
  p7sign  \
76e454
  p7verify  \
76e454
  pk12util \
76e454
+ pk11import \
76e454
  pk11ectest \
76e454
  pk11gcmtest \
76e454
  pk11mode \
76e454
  pk1sign  \
76e454
  pp  \
76e454
  pwdecrypt \
76e454
  rsaperf \
76e454
  rsapoptst \
76e454
diff --git a/cmd/pk11import/Makefile b/cmd/pk11import/Makefile
76e454
new file mode 100644
76e454
--- /dev/null
76e454
+++ b/cmd/pk11import/Makefile
76e454
@@ -0,0 +1,43 @@
76e454
+#! gmake
76e454
+#
76e454
+# This Source Code Form is subject to the terms of the Mozilla Public
76e454
+# License, v. 2.0. If a copy of the MPL was not distributed with this
76e454
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
76e454
+
76e454
+#######################################################################
76e454
+# (1) Include initial platform-independent assignments (MANDATORY).   #
76e454
+#######################################################################
76e454
+
76e454
+include manifest.mn
76e454
+
76e454
+#######################################################################
76e454
+# (2) Include "global" configuration information. (OPTIONAL)          #
76e454
+#######################################################################
76e454
+
76e454
+include $(CORE_DEPTH)/coreconf/config.mk
76e454
+
76e454
+#######################################################################
76e454
+# (3) Include "component" configuration information. (OPTIONAL)       #
76e454
+#######################################################################
76e454
+
76e454
+#######################################################################
76e454
+# (4) Include "local" platform-dependent assignments (OPTIONAL).      #
76e454
+#######################################################################
76e454
+
76e454
+include ../platlibs.mk
76e454
+
76e454
+#######################################################################
76e454
+# (5) Execute "global" rules. (OPTIONAL)                              #
76e454
+#######################################################################
76e454
+
76e454
+include $(CORE_DEPTH)/coreconf/rules.mk
76e454
+
76e454
+#######################################################################
76e454
+# (6) Execute "component" rules. (OPTIONAL)                           #
76e454
+#######################################################################
76e454
+
76e454
+#######################################################################
76e454
+# (7) Execute "local" rules. (OPTIONAL).                              #
76e454
+#######################################################################
76e454
+
76e454
+include ../platrules.mk
76e454
diff --git a/cmd/pk11import/manifest.mn b/cmd/pk11import/manifest.mn
76e454
new file mode 100644
76e454
--- /dev/null
76e454
+++ b/cmd/pk11import/manifest.mn
76e454
@@ -0,0 +1,15 @@
76e454
+# This Source Code Form is subject to the terms of the Mozilla Public
76e454
+# License, v. 2.0. If a copy of the MPL was not distributed with this
76e454
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
76e454
+
76e454
+CORE_DEPTH = ../..
76e454
+
76e454
+MODULE = nss
76e454
+
76e454
+CSRCS = pk11import.c	\
76e454
+	$(NULL)
76e454
+
76e454
+REQUIRES = seccmd
76e454
+
76e454
+PROGRAM = pk11import
76e454
+
76e454
diff --git a/cmd/pk11import/pk11import.c b/cmd/pk11import/pk11import.c
76e454
new file mode 100644
76e454
--- /dev/null
76e454
+++ b/cmd/pk11import/pk11import.c
76e454
@@ -0,0 +1,410 @@
76e454
+/* This Source Code Form is subject to the terms of the Mozilla Public
76e454
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
76e454
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
76e454
+
76e454
+#include "secutil.h"
76e454
+#include "secmod.h"
76e454
+#include "cert.h"
76e454
+#include "secoid.h"
76e454
+#include "nss.h"
76e454
+#include "pk11pub.h"
76e454
+#include "pk11pqg.h"
76e454
+
76e454
+/* NSPR 2.0 header files */
76e454
+#include "prinit.h"
76e454
+#include "prprf.h"
76e454
+#include "prsystem.h"
76e454
+#include "prmem.h"
76e454
+/* Portable layer header files */
76e454
+#include "plstr.h"
76e454
+
76e454
+SECOidData *
76e454
+getCurveFromString(char *curve_name)
76e454
+{
76e454
+    SECOidTag tag = SEC_OID_SECG_EC_SECP256R1;
76e454
+
76e454
+    if (PORT_Strcasecmp(curve_name, "NISTP256") == 0) {
76e454
+    } else if (PORT_Strcasecmp(curve_name, "NISTP384") == 0) {
76e454
+        tag = SEC_OID_SECG_EC_SECP384R1;
76e454
+    } else if (PORT_Strcasecmp(curve_name, "NISTP521") == 0) {
76e454
+        tag = SEC_OID_SECG_EC_SECP521R1;
76e454
+    } else if (PORT_Strcasecmp(curve_name, "Curve25519") == 0) {
76e454
+        tag = SEC_OID_CURVE25519;
76e454
+    }
76e454
+    return SECOID_FindOIDByTag(tag);
76e454
+}
76e454
+
76e454
+void
76e454
+dumpItem(const char *label, const SECItem *item)
76e454
+{
76e454
+    int i;
76e454
+    printf("%s = [%d bytes] {", label, item->len);
76e454
+    for (i = 0; i < item->len; i++) {
76e454
+        if ((i & 0xf) == 0)
76e454
+            printf("\n    ");
76e454
+        else
76e454
+            printf(", ");
76e454
+        printf("%02x", item->data[i]);
76e454
+    }
76e454
+    printf("};\n");
76e454
+}
76e454
+
76e454
+SECStatus
76e454
+handleEncryptedPrivateImportTest(char *progName, PK11SlotInfo *slot,
76e454
+                                 char *testname, CK_MECHANISM_TYPE genMech, void *params, void *pwArgs)
76e454
+{
76e454
+    SECStatus rv = SECSuccess;
76e454
+    SECItem privID = { 0 };
76e454
+    SECItem pubID = { 0 };
76e454
+    SECItem pubValue = { 0 };
76e454
+    SECItem pbePwItem = { 0 };
76e454
+    SECItem nickname = { 0 };
76e454
+    SECItem token = { 0 };
76e454
+    SECKEYPublicKey *pubKey = NULL;
76e454
+    SECKEYPrivateKey *privKey = NULL;
76e454
+    PK11GenericObject *objs = NULL;
76e454
+    PK11GenericObject *obj = NULL;
76e454
+    SECKEYEncryptedPrivateKeyInfo *epki = NULL;
76e454
+    PRBool keyFound = 0;
76e454
+    KeyType keyType;
76e454
+
76e454
+    fprintf(stderr, "Testing %s PrivateKeyImport ***********************\n",
76e454
+            testname);
76e454
+
76e454
+    /* generate a temp key */
76e454
+    privKey = PK11_GenerateKeyPair(slot, genMech, params, &pubKey,
76e454
+                                   PR_FALSE, PR_TRUE, pwArgs);
76e454
+    if (privKey == NULL) {
76e454
+        SECU_PrintError(progName, "PK11_GenerateKeyPair Failed");
76e454
+        goto cleanup;
76e454
+    }
76e454
+
76e454
+    /* wrap the temp key */
76e454
+    pbePwItem.data = (unsigned char *)"pw";
76e454
+    pbePwItem.len = 2;
76e454
+    epki = PK11_ExportEncryptedPrivKeyInfo(slot, SEC_OID_AES_256_CBC,
76e454
+                                           &pbePwItem, privKey, 1, NULL);
76e454
+    if (epki == NULL) {
76e454
+        SECU_PrintError(progName, "PK11_ExportEncryptedPrivKeyInfo Failed");
76e454
+        goto cleanup;
76e454
+    }
76e454
+
76e454
+    /* Save the public value, which we will need on import */
76e454
+    keyType = pubKey->keyType;
76e454
+    switch (keyType) {
76e454
+        case rsaKey:
76e454
+            SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.rsa.modulus);
76e454
+            break;
76e454
+        case dhKey:
76e454
+            SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dh.publicValue);
76e454
+            break;
76e454
+        case dsaKey:
76e454
+            SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dsa.publicValue);
76e454
+            break;
76e454
+        case ecKey:
76e454
+            SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.ec.publicValue);
76e454
+            break;
76e454
+        default:
76e454
+            fprintf(stderr, "Unknown keytype = %d\n", keyType);
76e454
+            goto cleanup;
76e454
+    }
76e454
+    dumpItem("pubValue", &pubValue);
76e454
+
76e454
+    /* when Asymetric keys represent session keys, those session keys are
76e454
+     * destroyed when we destroy the Asymetric key representations */
76e454
+    SECKEY_DestroyPublicKey(pubKey);
76e454
+    pubKey = NULL;
76e454
+    SECKEY_DestroyPrivateKey(privKey);
76e454
+    privKey = NULL;
76e454
+
76e454
+    /* unwrap the temp key as a perm */
76e454
+    nickname.data = (unsigned char *)"testKey";
76e454
+    nickname.len = sizeof("testKey");
76e454
+    rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(slot, epki, &pbePwItem,
76e454
+                                                        &nickname, &pubValue, PR_TRUE, PR_TRUE, keyType, 0, &privKey, NULL);
76e454
+    if (rv != SECSuccess) {
76e454
+        SECU_PrintError(progName, "PK11_ImportEncryptedPrivateKeyInfo Failed");
76e454
+        goto cleanup;
76e454
+    }
76e454
+
76e454
+    /* verify the public key exists */
76e454
+    rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_ID, &privID);
76e454
+    if (rv != SECSuccess) {
76e454
+        SECU_PrintError(progName,
76e454
+                        "Couldn't read CKA_ID from pub key, checking next key");
76e454
+        goto cleanup;
76e454
+    }
76e454
+    dumpItem("privKey CKA_ID", &privID);
76e454
+    objs = PK11_FindGenericObjects(slot, CKO_PUBLIC_KEY);
76e454
+    for (obj = objs; obj; obj = PK11_GetNextGenericObject(obj)) {
76e454
+        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pubID);
76e454
+        if (rv != SECSuccess) {
76e454
+            SECU_PrintError(progName,
76e454
+                            "Couldn't read CKA_ID from pub key, checking next key");
76e454
+            continue;
76e454
+        }
76e454
+        dumpItem("pubKey CKA_ID", &pubID);
76e454
+        if (!SECITEM_ItemsAreEqual(&privID, &pubID)) {
76e454
+            fprintf(stderr,
76e454
+                    "CKA_ID does not match priv key, checking next key\n");
76e454
+            SECITEM_FreeItem(&pubID, PR_FALSE);
76e454
+            continue;
76e454
+        }
76e454
+        SECITEM_FreeItem(&pubID, PR_FALSE);
76e454
+        rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token);
76e454
+        if (rv == SECSuccess) {
76e454
+            if (token.len == 1) {
76e454
+                keyFound = token.data[0];
76e454
+            }
76e454
+            SECITEM_FreeItem(&token, PR_FALSE);
76e454
+        }
76e454
+        if (keyFound) {
76e454
+            printf("matching public key found\n");
76e454
+            break;
76e454
+        }
76e454
+        printf("Matching key was not a token key, checking next key\n");
76e454
+    }
76e454
+cleanup:
76e454
+    if (objs) {
76e454
+        PK11_DestroyGenericObjects(objs);
76e454
+    }
76e454
+    if (pubValue.data) {
76e454
+        SECITEM_FreeItem(&pubValue, PR_FALSE);
76e454
+    }
76e454
+    if (privID.data) {
76e454
+        SECITEM_FreeItem(&privID, PR_FALSE);
76e454
+    }
76e454
+    if (epki) {
76e454
+        PORT_FreeArena(epki->arena, PR_TRUE);
76e454
+    }
76e454
+    if (pubKey) {
76e454
+        SECKEY_DestroyPublicKey(pubKey);
76e454
+    }
76e454
+    if (privKey) {
76e454
+        SECKEY_DestroyPrivateKey(privKey);
76e454
+    }
76e454
+    fprintf(stderr, "%s PrivateKeyImport %s ***********************\n",
76e454
+            testname, keyFound ? "PASSED" : "FAILED");
76e454
+    return keyFound ? SECSuccess : SECFailure;
76e454
+}
76e454
+
76e454
+static const char *const usageInfo[] = {
76e454
+    "pk11import - test PK11_PrivateKeyImport()"
76e454
+    "Options:",
76e454
+    " -d certdir            directory containing cert database",
76e454
+    " -k keysize            size of the rsa, dh, and dsa key to test (default 1024)",
76e454
+    " -C ecc_curve          ecc curve (default )",
76e454
+    " -f pwFile             file to fetch the password from",
76e454
+    " -p pwString           password",
76e454
+    " -r                    skip rsa test",
76e454
+    " -D                    skip dsa test",
76e454
+    " -h                    skip dh test",
76e454
+    " -e                    skip ec test",
76e454
+};
76e454
+static int nUsageInfo = sizeof(usageInfo) / sizeof(char *);
76e454
+
76e454
+static void
76e454
+Usage(char *progName, FILE *outFile)
76e454
+{
76e454
+    int i;
76e454
+    fprintf(outFile, "Usage:  %s [ commands ] options\n", progName);
76e454
+    for (i = 0; i < nUsageInfo; i++)
76e454
+        fprintf(outFile, "%s\n", usageInfo[i]);
76e454
+    exit(-1);
76e454
+}
76e454
+
76e454
+enum {
76e454
+    opt_CertDir,
76e454
+    opt_KeySize,
76e454
+    opt_ECCurve,
76e454
+    opt_PWFile,
76e454
+    opt_PWString,
76e454
+    opt_NoRSA,
76e454
+    opt_NoDSA,
76e454
+    opt_NoDH,
76e454
+    opt_NoEC
76e454
+};
76e454
+
76e454
+static secuCommandFlag options[] =
76e454
+    {
76e454
+      { /* opt_CertDir          */ 'd', PR_TRUE, 0, PR_FALSE },
76e454
+      { /* opt_KeySize          */ 'k', PR_TRUE, 0, PR_FALSE },
76e454
+      { /* opt_ECCurve          */ 'C', PR_TRUE, 0, PR_FALSE },
76e454
+      { /* opt_PWFile           */ 'f', PR_TRUE, 0, PR_FALSE },
76e454
+      { /* opt_PWString         */ 'p', PR_TRUE, 0, PR_FALSE },
76e454
+      { /* opt_NORSA            */ 'r', PR_FALSE, 0, PR_FALSE },
76e454
+      { /* opt_NoDSA            */ 'D', PR_FALSE, 0, PR_FALSE },
76e454
+      { /* opt_NoDH             */ 'h', PR_FALSE, 0, PR_FALSE },
76e454
+      { /* opt_NoEC             */ 'e', PR_FALSE, 0, PR_FALSE },
76e454
+    };
76e454
+
76e454
+int
76e454
+main(int argc, char **argv)
76e454
+{
76e454
+    char *progName;
76e454
+    SECStatus rv;
76e454
+    secuCommand args;
76e454
+    PK11SlotInfo *slot = NULL;
76e454
+    PRBool failed = PR_FALSE;
76e454
+    secuPWData pwArgs = { PW_NONE, 0 };
76e454
+    PRBool doRSA = PR_TRUE;
76e454
+    PRBool doDSA = PR_TRUE;
76e454
+    PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */
76e454
+    PRBool doEC = PR_TRUE;
76e454
+    PQGParams *pqgParams = NULL;
76e454
+    int keySize;
76e454
+
76e454
+    args.numCommands = 0;
76e454
+    args.numOptions = sizeof(options) / sizeof(secuCommandFlag);
76e454
+    args.commands = NULL;
76e454
+    args.options = options;
76e454
+
76e454
+#ifdef XP_PC
76e454
+    progName = strrchr(argv[0], '\\');
76e454
+#else
76e454
+    progName = strrchr(argv[0], '/');
76e454
+#endif
76e454
+    progName = progName ? progName + 1 : argv[0];
76e454
+
76e454
+    rv = SECU_ParseCommandLine(argc, argv, progName, &args);
76e454
+    if (SECSuccess != rv) {
76e454
+        Usage(progName, stderr);
76e454
+    }
76e454
+
76e454
+    /*  Set the certdb directory (default is ~/.netscape) */
76e454
+    rv = NSS_InitReadWrite(SECU_ConfigDirectory(args.options[opt_CertDir].arg));
76e454
+    if (rv != SECSuccess) {
76e454
+        SECU_PrintPRandOSError(progName);
76e454
+        return 255;
76e454
+    }
76e454
+    PK11_SetPasswordFunc(SECU_GetModulePassword);
76e454
+
76e454
+    /* below here, goto cleanup */
76e454
+    SECU_RegisterDynamicOids();
76e454
+
76e454
+    /* handle the arguments */
76e454
+    if (args.options[opt_PWFile].arg) {
76e454
+        pwArgs.source = PW_FROMFILE;
76e454
+        pwArgs.data = args.options[opt_PWFile].arg;
76e454
+    }
76e454
+    if (args.options[opt_PWString].arg) {
76e454
+        pwArgs.source = PW_PLAINTEXT;
76e454
+        pwArgs.data = args.options[opt_PWString].arg;
76e454
+    }
76e454
+    if (args.options[opt_NoRSA].activated) {
76e454
+        doRSA = PR_FALSE;
76e454
+    }
76e454
+    if (args.options[opt_NoDSA].activated) {
76e454
+        doDSA = PR_FALSE;
76e454
+    }
76e454
+    if (args.options[opt_NoDH].activated) {
76e454
+        doDH = PR_FALSE;
76e454
+    }
76e454
+    if (args.options[opt_NoEC].activated) {
76e454
+        doEC = PR_FALSE;
76e454
+    }
76e454
+
76e454
+    slot = PK11_GetInternalKeySlot();
76e454
+    if (slot == NULL) {
76e454
+        SECU_PrintError(progName, "Couldn't find the internal key slot\n");
76e454
+        return 255;
76e454
+    }
76e454
+    rv = PK11_Authenticate(slot, PR_TRUE, &pwArgs);
76e454
+    if (rv != SECSuccess) {
76e454
+        SECU_PrintError(progName, "Failed to log into slot");
76e454
+        PK11_FreeSlot(slot);
76e454
+        return 255;
76e454
+    }
76e454
+
76e454
+    keySize = 1024;
76e454
+    if (args.options[opt_KeySize].activated &&
76e454
+        args.options[opt_KeySize].arg) {
76e454
+        keySize = atoi(args.options[opt_KeySize].arg);
76e454
+    }
76e454
+
76e454
+    if (doDSA || doDH) {
76e454
+        PQGVerify *pqgVfy;
76e454
+        rv = PK11_PQG_ParamGenV2(keySize, 0, keySize / 16, &pqgParams, &pqgVfy);
76e454
+        if (rv == SECSuccess) {
76e454
+            PK11_PQG_DestroyVerify(pqgVfy);
76e454
+        } else {
76e454
+            SECU_PrintError(progName,
76e454
+                            "PK11_PQG_ParamGenV2 failed, can't test DH or DSA");
76e454
+            doDSA = doDH = PR_FALSE;
76e454
+            failed = PR_TRUE;
76e454
+        }
76e454
+    }
76e454
+
76e454
+    if (doRSA) {
76e454
+        PK11RSAGenParams rsaParams;
76e454
+        rsaParams.keySizeInBits = keySize;
76e454
+        rsaParams.pe = 0x010001;
76e454
+        rv = handleEncryptedPrivateImportTest(progName, slot, "RSA",
76e454
+                                              CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pwArgs);
76e454
+        if (rv != SECSuccess) {
76e454
+            fprintf(stderr, "RSA Import Failed!\n");
76e454
+            failed = PR_TRUE;
76e454
+        }
76e454
+    }
76e454
+    if (doDSA) {
76e454
+        rv = handleEncryptedPrivateImportTest(progName, slot, "DSA",
76e454
+                                              CKM_DSA_KEY_PAIR_GEN, pqgParams, &pwArgs);
76e454
+        if (rv != SECSuccess) {
76e454
+            fprintf(stderr, "DSA Import Failed!\n");
76e454
+            failed = PR_TRUE;
76e454
+        }
76e454
+    }
76e454
+    if (doDH) {
76e454
+        SECKEYDHParams dhParams;
76e454
+        dhParams.prime = pqgParams->prime;
76e454
+        dhParams.base = pqgParams->base;
76e454
+        rv = handleEncryptedPrivateImportTest(progName, slot, "DH",
76e454
+                                              CKM_DH_PKCS_KEY_PAIR_GEN, &dhParams, &pwArgs);
76e454
+        if (rv != SECSuccess) {
76e454
+            fprintf(stderr, "DH Import Failed!\n");
76e454
+            failed = PR_TRUE;
76e454
+        }
76e454
+    }
76e454
+    if (doEC) {
76e454
+        SECKEYECParams ecParams;
76e454
+        SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
76e454
+        if (args.options[opt_ECCurve].activated &&
76e454
+            args.options[opt_ECCurve].arg) {
76e454
+            curve = getCurveFromString(args.options[opt_ECCurve].arg);
76e454
+        }
76e454
+        ecParams.data = PORT_Alloc(curve->oid.len + 2);
76e454
+        if (ecParams.data == NULL) {
76e454
+            rv = SECFailure;
76e454
+            goto ec_failed;
76e454
+        }
76e454
+        ecParams.data[0] = SEC_ASN1_OBJECT_ID;
76e454
+        ecParams.data[1] = (unsigned char)curve->oid.len;
76e454
+        PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len);
76e454
+        ecParams.len = curve->oid.len + 2;
76e454
+        rv = handleEncryptedPrivateImportTest(progName, slot, "ECC",
76e454
+                                              CKM_EC_KEY_PAIR_GEN, &ecParams, &pwArgs);
76e454
+        PORT_Free(ecParams.data);
76e454
+    ec_failed:
76e454
+        if (rv != SECSuccess) {
76e454
+            fprintf(stderr, "ECC Import Failed!\n");
76e454
+            failed = PR_TRUE;
76e454
+        }
76e454
+    }
76e454
+
76e454
+    if (pqgParams) {
76e454
+        PK11_PQG_DestroyParams(pqgParams);
76e454
+    }
76e454
+
76e454
+    if (slot) {
76e454
+        PK11_FreeSlot(slot);
76e454
+    }
76e454
+
76e454
+    rv = NSS_Shutdown();
76e454
+    if (rv != SECSuccess) {
76e454
+        fprintf(stderr, "Shutdown failed\n");
76e454
+        SECU_PrintPRandOSError(progName);
76e454
+        return 255;
76e454
+    }
76e454
+
76e454
+    return failed ? 1 : 0;
76e454
+}
76e454
diff --git a/cmd/pk11import/pk11import.gyp b/cmd/pk11import/pk11import.gyp
76e454
new file mode 100644
76e454
--- /dev/null
76e454
+++ b/cmd/pk11import/pk11import.gyp
76e454
@@ -0,0 +1,25 @@
76e454
+# This Source Code Form is subject to the terms of the Mozilla Public
76e454
+# License, v. 2.0. If a copy of the MPL was not distributed with this
76e454
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
76e454
+{
76e454
+  'includes': [
76e454
+    '../../coreconf/config.gypi',
76e454
+    '../../cmd/platlibs.gypi'
76e454
+  ],
76e454
+  'targets': [
76e454
+    {
76e454
+      'target_name': 'pk11import',
76e454
+      'type': 'executable',
76e454
+      'sources': [
76e454
+        'pk11import.c'
76e454
+      ],
76e454
+      'dependencies': [
76e454
+        '<(DEPTH)/exports.gyp:dbm_exports',
76e454
+        '<(DEPTH)/exports.gyp:nss_exports'
76e454
+      ]
76e454
+    }
76e454
+  ],
76e454
+  'variables': {
76e454
+    'module': 'nss'
76e454
+  }
76e454
+}
76e454
diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c
76e454
--- a/lib/pk11wrap/pk11akey.c
76e454
+++ b/lib/pk11wrap/pk11akey.c
76e454
@@ -1672,16 +1672,96 @@ PK11_MakeKEAPubKey(unsigned char *keyDat
76e454
     rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData);
76e454
     if (rv != SECSuccess) {
76e454
         PORT_FreeArena(arena, PR_FALSE);
76e454
         return NULL;
76e454
     }
76e454
     return pubk;
76e454
 }
76e454
 
76e454
+SECStatus
76e454
+SECKEY_SetPublicValue(SECKEYPrivateKey *privKey, SECItem *publicValue)
76e454
+{
76e454
+    SECStatus rv;
76e454
+    SECKEYPublicKey pubKey;
76e454
+    PLArenaPool *arena;
76e454
+    PK11SlotInfo *slot = privKey->pkcs11Slot;
76e454
+    CK_OBJECT_HANDLE privKeyID = privKey->pkcs11ID;
76e454
+
76e454
+    pubKey.arena = NULL;
76e454
+    pubKey.keyType = privKey->keyType;
76e454
+    pubKey.pkcs11Slot = NULL;
76e454
+    pubKey.pkcs11ID = CK_INVALID_HANDLE;
76e454
+    /* can't use PORT_InitCheapArena here becase SECKEY_DestroyPublic is used
76e454
+      * to free it, and it uses PORT_FreeArena which not only frees the 
76e454
+      * underlying arena, it also frees the allocated arena struct. */
76e454
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
76e454
+    pubKey.arena = arena;
76e454
+    if (arena == NULL) {
76e454
+        return SECFailure;
76e454
+    }
76e454
+    rv = SECFailure;
76e454
+    switch (privKey->keyType) {
76e454
+        default:
76e454
+            /* error code already set to SECFailure */
76e454
+            break;
76e454
+        case rsaKey:
76e454
+            pubKey.u.rsa.modulus = *publicValue;
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_PUBLIC_EXPONENT,
76e454
+                                    arena, &pubKey.u.rsa.publicExponent);
76e454
+            break;
76e454
+        case dsaKey:
76e454
+            pubKey.u.dsa.publicValue = *publicValue;
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
76e454
+                                    arena, &pubKey.u.dsa.params.prime);
76e454
+            if (rv != SECSuccess) {
76e454
+                break;
76e454
+            }
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_SUBPRIME,
76e454
+                                    arena, &pubKey.u.dsa.params.subPrime);
76e454
+            if (rv != SECSuccess) {
76e454
+                break;
76e454
+            }
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
76e454
+                                    arena, &pubKey.u.dsa.params.base);
76e454
+            break;
76e454
+        case dhKey:
76e454
+            pubKey.u.dh.publicValue = *publicValue;
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
76e454
+                                    arena, &pubKey.u.dh.prime);
76e454
+            if (rv != SECSuccess) {
76e454
+                break;
76e454
+            }
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
76e454
+                                    arena, &pubKey.u.dh.base);
76e454
+            break;
76e454
+        case ecKey:
76e454
+            pubKey.u.ec.publicValue = *publicValue;
76e454
+            pubKey.u.ec.encoding = ECPoint_Undefined;
76e454
+            pubKey.u.ec.size = 0;
76e454
+            rv = PK11_ReadAttribute(slot, privKeyID, CKA_EC_PARAMS,
76e454
+                                    arena, &pubKey.u.ec.DEREncodedParams);
76e454
+            break;
76e454
+    }
76e454
+    if (rv == SECSuccess) {
76e454
+        rv = PK11_ImportPublicKey(slot, &pubKey, PR_TRUE);
76e454
+    }
76e454
+    /* Even though pubKey is stored on the stack, we've allocated
76e454
+     * some of it's data from the arena. SECKEY_DestroyPublicKey
76e454
+     * destroys keys by freeing the arena, so this will clean up all
76e454
+     * the data we allocated specifically for the key above. It will
76e454
+     * also free any slot references which we may have picked up in
76e454
+     * PK11_ImportPublicKey. It won't delete the underlying key if
76e454
+     * its a Token/Permanent key (which it will be if
76e454
+     * PK11_ImportPublicKey succeeds). */
76e454
+    SECKEY_DestroyPublicKey(&pubKey);
76e454
+
76e454
+    return rv;
76e454
+}
76e454
+
76e454
 /*
76e454
  * NOTE: This function doesn't return a SECKEYPrivateKey struct to represent
76e454
  * the new private key object.  If it were to create a session object that
76e454
  * could later be looked up by its nickname, it would leak a SECKEYPrivateKey.
76e454
  * So isPerm must be true.
76e454
  */
76e454
 SECStatus
76e454
 PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot,
76e454
@@ -1797,22 +1877,16 @@ try_faulty_3des:
76e454
 
76e454
     PORT_Assert(usage != NULL);
76e454
     PORT_Assert(usageCount != 0);
76e454
     privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType,
76e454
                                  crypto_param, &epki->encryptedData,
76e454
                                  nickname, publicValue, isPerm, isPrivate,
76e454
                                  key_type, usage, usageCount, wincx);
76e454
     if (privKey) {
76e454
-        if (privk) {
76e454
-            *privk = privKey;
76e454
-        } else {
76e454
-            SECKEY_DestroyPrivateKey(privKey);
76e454
-        }
76e454
-        privKey = NULL;
76e454
         rv = SECSuccess;
76e454
         goto done;
76e454
     }
76e454
 
76e454
     /* if we are unable to import the key and the pbeMechType is
76e454
      * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that
76e454
      * the encrypted blob was created with a buggy key generation method
76e454
      * which is described in the PKCS 12 implementation notes.  So we
76e454
@@ -1832,16 +1906,35 @@ try_faulty_3des:
76e454
         faulty3DES = PR_TRUE;
76e454
         goto try_faulty_3des;
76e454
     }
76e454
 
76e454
     /* key import really did fail */
76e454
     rv = SECFailure;
76e454
 
76e454
 done:
76e454
+    if ((rv == SECSuccess) && isPerm) {
76e454
+        /* If we are importing a token object,
76e454
+         * create the corresponding public key.
76e454
+         * If this fails, just continue as the target
76e454
+         * token simply might not support persistant
76e454
+         * public keys. Such tokens are usable, but
76e454
+         * need to be authenticated before searching
76e454
+         * for user certs. */
76e454
+        (void)SECKEY_SetPublicValue(privKey, publicValue);
76e454
+    }
76e454
+
76e454
+    if (privKey) {
76e454
+        if (privk) {
76e454
+            *privk = privKey;
76e454
+        } else {
76e454
+            SECKEY_DestroyPrivateKey(privKey);
76e454
+        }
76e454
+        privKey = NULL;
76e454
+    }
76e454
     if (crypto_param != NULL) {
76e454
         SECITEM_ZfreeItem(crypto_param, PR_TRUE);
76e454
     }
76e454
 
76e454
     if (key != NULL) {
76e454
         PK11_FreeSymKey(key);
76e454
     }
76e454
 
76e454
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
76e454
--- a/lib/softoken/pkcs11.c
76e454
+++ b/lib/softoken/pkcs11.c
76e454
@@ -1810,29 +1810,36 @@ sftk_GetPubKey(SFTKObject *object, CK_KE
76e454
                  * Some curves are always pressumed to be non-DER.
76e454
                  */
76e454
                 if (pubKey->u.ec.publicValue.len == keyLen &&
76e454
                     (pubKey->u.ec.ecParams.fieldID.type == ec_field_plain ||
76e454
                      pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED)) {
76e454
                     break; /* key was not DER encoded, no need to unwrap */
76e454
                 }
76e454
 
76e454
-                PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519);
76e454
+                /* The PKCS #11 spec says that the Params should be DER encoded. Even though the params from the
76e454
+                 * Certificate aren't according the the ECCurve 25519 spec. We should accept this encoding.
76e454
+                PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519); */
76e454
 
76e454
                 /* handle the encoded case */
76e454
                 if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) &&
76e454
                     pubKey->u.ec.publicValue.len > keyLen) {
76e454
                     SECItem publicValue;
76e454
                     SECStatus rv;
76e454
 
76e454
                     rv = SEC_QuickDERDecodeItem(arena, &publicValue,
76e454
                                                 SEC_ASN1_GET(SEC_OctetStringTemplate),
76e454
                                                 &pubKey->u.ec.publicValue);
76e454
                     /* nope, didn't decode correctly */
76e454
-                    if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) {
76e454
+                    if ((rv != SECSuccess) || (publicValue.len != keyLen)) {
76e454
+                        crv = CKR_ATTRIBUTE_VALUE_INVALID;
76e454
+                        break;
76e454
+                    }
76e454
+                    /* we don't handle compressed points except in the case of ECCurve25519 */
76e454
+                    if ((pubKey->u.ec.ecParams.fieldID.type != ec_field_plain) && (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)) {
76e454
                         crv = CKR_ATTRIBUTE_VALUE_INVALID;
76e454
                         break;
76e454
                     }
76e454
                     /* replace our previous with the decoded key */
76e454
                     pubKey->u.ec.publicValue = publicValue;
76e454
                     break;
76e454
                 }
76e454
                 crv = CKR_ATTRIBUTE_VALUE_INVALID;
76e454
diff --git a/nss.gyp b/nss.gyp
76e454
--- a/nss.gyp
76e454
+++ b/nss.gyp
76e454
@@ -159,16 +159,17 @@
76e454
             'cmd/oidcalc/oidcalc.gyp:oidcalc',
76e454
             'cmd/p7content/p7content.gyp:p7content',
76e454
             'cmd/p7env/p7env.gyp:p7env',
76e454
             'cmd/p7sign/p7sign.gyp:p7sign',
76e454
             'cmd/p7verify/p7verify.gyp:p7verify',
76e454
             'cmd/pk11ectest/pk11ectest.gyp:pk11ectest',
76e454
             'cmd/pk11gcmtest/pk11gcmtest.gyp:pk11gcmtest',
76e454
             'cmd/pk11mode/pk11mode.gyp:pk11mode',
76e454
+            'cmd/pk11import/pk11import.gyp:pk11import',
76e454
             'cmd/pk1sign/pk1sign.gyp:pk1sign',
76e454
             'cmd/pp/pp.gyp:pp',
76e454
             'cmd/rsaperf/rsaperf.gyp:rsaperf',
76e454
             'cmd/rsapoptst/rsapoptst.gyp:rsapoptst',
76e454
             'cmd/sdrtest/sdrtest.gyp:sdrtest',
76e454
             'cmd/selfserv/selfserv.gyp:selfserv',
76e454
             'cmd/shlibsign/mangle/mangle.gyp:mangle',
76e454
             'cmd/strsclnt/strsclnt.gyp:strsclnt',
76e454
diff --git a/tests/dbtests/dbtests.sh b/tests/dbtests/dbtests.sh
76e454
--- a/tests/dbtests/dbtests.sh
76e454
+++ b/tests/dbtests/dbtests.sh
76e454
@@ -247,16 +247,35 @@ dbtest_main()
76e454
     # the old one should still be there...
76e454
     ${BINDIR}/certutil -L -n bob -d ${CONFLICT_DIR}
76e454
     ret=$?
76e454
     if [ $ret -ne 0 ]; then
76e454
       html_failed "Nicknane conflict test-setting nickname conflict incorrectly worked"
76e454
     else
76e454
       html_passed "Nicknane conflict test-setting nickname conflict was correctly rejected"
76e454
     fi
76e454
-
76e454
+    # import a token private key and make sure the corresponding public key is
76e454
+    # created
76e454
+    ${BINDIR}/pk11import -d ${CONFLICT_DIR} -f ${R_PWFILE}
76e454
+    echo ${BINDIR}/pk11import -d ${CONFLICT_DIR} -f ${R_PWFILE}
76e454
+    ret=$?
76e454
+    if [ $ret -ne 0 ]; then
76e454
+      html_failed "Importing Token Private Key does not create the corrresponding Public Key"
76e454
+    else
76e454
+      html_passed "Importing Token Private Key correctly creates the corrresponding Public Key"
76e454
+    fi
76e454
+    # import a token private key and make sure the corresponding public key is
76e454
+    # created
76e454
+    ${BINDIR}/pk11import -r -D -h -C Curve25519 -d ${CONFLICT_DIR} -f ${R_PWFILE}
76e454
+    echo ${BINDIR}/pk11import -r -D -h -C Curve25519 -d ${CONFLICT_DIR} -f ${R_PWFILE}
76e454
+    ret=$?
76e454
+    if [ $ret -ne 0 ]; then
76e454
+      html_failed "Importing ECC Curve 25519 Token Private Key does not create the corrresponding Public Key"
76e454
+    else
76e454
+      html_passed "Importing ECC Curve 25519 Token Private Key correctly creates the corrresponding Public Key"
76e454
+    fi
76e454
 }
76e454
 
76e454
 ################## main #################################################
76e454
 
76e454
 dbtest_init 
76e454
 dbtest_main 2>&1
76e454
 dbtest_cleanup