Bug 783579 - Add to certutil the ability to specify opFlags and attrFlag, r=rrelya
authorElio Maldonado <emaldona@redhat.com>
Wed, 22 May 2013 09:35:43 -0700
changeset 10786 94a1e80e5f71893dfc34be134ac589558e6e0f73
parent 10785 c499082b9a15f22dc9a4c882ea8769b16ac82234
child 10787 a50886302a4c82917c620c36e5adf823244887f8
push id95
push useremaldona@redhat.com
push dateWed, 22 May 2013 16:35:55 +0000
reviewersrrelya
bugs783579
Bug 783579 - Add to certutil the ability to specify opFlags and attrFlag, r=rrelya
cmd/certutil/certutil.c
cmd/certutil/certutil.h
cmd/certutil/keystuff.c
--- a/cmd/certutil/certutil.c
+++ b/cmd/certutil/certutil.c
@@ -1197,16 +1197,29 @@ static void luG(enum usage_level ul, con
     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
     FPS "%-20s sect131r1, sect131r2\n", "");
 #endif /* NSS_ECC_MORE_THAN_SUITE_B */
 #endif
     FPS "%-20s Key database directory (default is ~/.netscape)\n",
         "   -d keydir");
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
+    FPS "%-20s PKCS #11 key Attributes\n",
+        "   --keyAttrFlags attrflags.");
+    FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
+    FPS "%-20s selected from the following list of choices:\n", "");
+    FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
+    FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
+    FPS "%-20s PKCS #11 key Operation Flags\n",
+        "   --keyOpFlagsOn opflags.");
+    FPS "%-20s PKCS #11 key Operation Flags\n",
+        "   --keyOpFlagsOff opflags.");
+    FPS "%-20s Comma separated list of one or more of the following:\n", "");
+    FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
+    FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
     FPS "\n");
 }
 
 static void luD(enum usage_level ul, const char *command)
 {
     int is_my_command = (command && 0 == strcmp(command, "D"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Delete a certificate from the database\n",
@@ -1428,16 +1441,18 @@ static void luR(enum usage_level ul, con
     FPS "%-20s Cert & Key database prefix\n",
         "   -P dbprefix");
     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
         "   -p phone");
     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
         "   -a");
     FPS "%-20s \n",
         "   See -S for available extension options");
+    FPS "%-20s \n",
+        "   See -G for available key flag  options");
     FPS "\n");
 }
 
 static void luV(enum usage_level ul, const char *command)
 {
     int is_my_command = (command && 0 == strcmp(command, "V"));
     if (ul == usage_all || !command || is_my_command)
     FPS "%-15s Validate a certificate\n",
@@ -1610,16 +1625,18 @@ static void luS(enum usage_level ul, con
     FPS "%-20s Create a Policy Mappings extension\n",
         "   --extPM ");
     FPS "%-20s Create a Policy Constraints extension\n",
         "   --extPC ");
     FPS "%-20s Create an Inhibit Any Policy extension\n",
         "   --extIA ");
     FPS "%-20s Create a subject key ID extension\n",
         "   --extSKID ");
+    FPS "%-20s \n",
+        "   See -G for available key flag  options");
     FPS "%-20s Create a name constraints extension\n",
         "   --extNC ");
     FPS "\n");
 }
 
 static void LongUsage(char *progName, enum usage_level ul, const char *command)
 {
     luA(ul, command);
@@ -1930,16 +1947,113 @@ getObjectClass(CK_ULONG classType)
     }
     if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
 	return objNSSClassArray[classType - CKO_NSS];
     }
     sprintf(buf, "0x%lx", classType);
     return buf;
 }
 
+typedef struct {
+    char *name;
+    int  nameSize;
+    CK_ULONG value;
+} flagArray;
+
+#define NAME_SIZE(x) #x,sizeof(#x)-1
+
+flagArray opFlagsArray[] =
+{
+    {NAME_SIZE(encrypt), CKF_ENCRYPT},
+    {NAME_SIZE(decrypt), CKF_DECRYPT},
+    {NAME_SIZE(sign), CKF_SIGN},
+    {NAME_SIZE(sign_recover), CKF_SIGN_RECOVER},
+    {NAME_SIZE(verify), CKF_VERIFY},
+    {NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER},
+    {NAME_SIZE(wrap), CKF_WRAP},
+    {NAME_SIZE(unwrap), CKF_UNWRAP},
+    {NAME_SIZE(derive), CKF_DERIVE},
+};
+
+int opFlagsCount = sizeof(opFlagsArray)/sizeof(flagArray);
+
+flagArray attrFlagsArray[] =
+{
+    {NAME_SIZE(token), PK11_ATTR_TOKEN},
+    {NAME_SIZE(session), PK11_ATTR_SESSION},
+    {NAME_SIZE(private), PK11_ATTR_PRIVATE},
+    {NAME_SIZE(public), PK11_ATTR_PUBLIC},
+    {NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE},
+    {NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE},
+    {NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE},
+    {NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE},
+    {NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE},
+    {NAME_SIZE(unextractable), PK11_ATTR_EXTRACTABLE}
+
+};
+
+int attrFlagsCount = sizeof(attrFlagsArray)/sizeof(flagArray);
+
+#define MAX_STRING 30
+CK_ULONG
+GetFlags(char *flagsString, flagArray *flagArray, int count)
+{
+   CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
+   int i;
+
+fprintf(stderr, "parsing flags <%s>\n", flagsString);
+
+   if ((flagsValue != 0) || (*flagsString == 0)) {
+	return flagsValue;
+   }
+   while (*flagsString) {
+	for (i=0; i < count; i++) {
+	    if (strncmp(flagsString, flagArray[i].name, flagArray[i].nameSize) 
+								== 0) {
+		flagsValue |= flagArray[i].value;
+		flagsString += flagArray[i].nameSize;
+		if (*flagsString != 0) {
+		    flagsString++;
+		}
+		break;
+	    }
+	}
+	if (i == count) {
+	    char name[MAX_STRING];
+	    char *tok;
+
+	    strncpy(name,flagsString, MAX_STRING);
+	    name[MAX_STRING-1] = 0;
+	    tok = strchr(name, ',');
+	    if (tok) {
+		*tok = 0;
+	    }
+	    fprintf(stderr,"Unknown flag (%s)\n",name);
+	    tok = strchr(flagsString, ',');
+	    if (tok == NULL)  {
+		break;
+	    }
+	    flagsString = tok+1;
+	}
+    }
+    return flagsValue;
+}
+
+CK_FLAGS
+GetOpFlags(char *flags)
+{
+    return GetFlags(flags, opFlagsArray, opFlagsCount);
+}
+
+PK11AttrFlags
+GetAttrFlags(char *flags)
+{
+    return GetFlags(flags, attrFlagsArray, attrFlagsCount);
+}
+
 char *mkNickname(unsigned char *data, int len)
 {
    char *nick = PORT_Alloc(len+1);
    if (!nick) {
 	return nick;
    }
    PORT_Memcpy(nick, data, len);
    nick[len] = 0;
@@ -2069,16 +2183,19 @@ enum certutilOpts {
     opt_AddSubjectKeyIDExt,
     opt_AddCmdKeyUsageExt,
     opt_AddCmdNSCertTypeExt,
     opt_AddCmdExtKeyUsageExt,
     opt_SourceDir,
     opt_SourcePrefix,
     opt_UpgradeID,
     opt_UpgradeTokenName,
+    opt_KeyOpFlagsOn,
+    opt_KeyOpFlagsOff,
+    opt_KeyAttrFlags,
     opt_Help
 };
 
 static const
 secuCommandFlag commands_init[] =
 {
 	{ /* cmd_AddCert             */  'A', PR_FALSE, 0, PR_FALSE },
 	{ /* cmd_CreateNewCert       */  'C', PR_FALSE, 0, PR_FALSE },
@@ -2170,16 +2287,22 @@ secuCommandFlag options_init[] =
 	{ /* opt_SourceDir           */  0,   PR_TRUE,  0, PR_FALSE,
                                                    "source-dir"},
 	{ /* opt_SourcePrefix        */  0,   PR_TRUE,  0, PR_FALSE, 
 						   "source-prefix"},
 	{ /* opt_UpgradeID           */  0,   PR_TRUE,  0, PR_FALSE, 
                                                    "upgrade-id"},
 	{ /* opt_UpgradeTokenName    */  0,   PR_TRUE,  0, PR_FALSE, 
                                                    "upgrade-token-name"},
+	{ /* opt_KeyOpFlagsOn        */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyOpFlagsOn"},
+	{ /* opt_KeyOpFlagsOff       */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyOpFlagsOff"},
+	{ /* opt_KeyAttrFlags        */  0,   PR_TRUE, 0, PR_FALSE, 
+                                                   "keyAttrFlags"},
 };
 #define NUM_OPTIONS ((sizeof options_init)  / (sizeof options_init[0]))
 
 static secuCommandFlag certutil_commands[NUM_COMMANDS];
 static secuCommandFlag certutil_options [NUM_OPTIONS ];
 
 static const secuCommand certutil = {
     NUM_COMMANDS, 
@@ -2217,16 +2340,20 @@ certutil_main(int argc, char **argv, PRB
     int         warpmonths      = 0;
     int         validityMonths  = 3;
     int         commandsEntered = 0;
     char        commandToRun    = '\0';
     secuPWData  pwdata          = { PW_NONE, 0 };
     secuPWData  pwdata2         = { PW_NONE, 0 };
     PRBool      readOnly        = PR_FALSE;
     PRBool      initialized     = PR_FALSE;
+    CK_FLAGS    keyOpFlagsOn = 0;
+    CK_FLAGS    keyOpFlagsOff = 0;
+    PK11AttrFlags    keyAttrFlags = 
+		PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
 
     SECKEYPrivateKey *privkey = NULL;
     SECKEYPublicKey *pubkey = NULL;
 
     int i;
     SECStatus rv;
 
     progName = PORT_Strrchr(argv[0], '/');
@@ -2339,16 +2466,27 @@ certutil_main(int argc, char **argv, PRB
 	} else {
 	    /* use an existing private/public key pair */
 	    keysource = arg;
 	}
     } else if (certutil.commands[cmd_ListKeys].activated) {
 	keytype = nullKey;
     }
 
+    if (certutil.options[opt_KeyOpFlagsOn].activated) {
+	keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
+    }
+    if (certutil.options[opt_KeyOpFlagsOff].activated) {
+	keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
+	keyOpFlagsOn &=~keyOpFlagsOff; /* make off override on */
+    }
+    if (certutil.options[opt_KeyAttrFlags].activated) {
+	keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
+    }
+
     /*  -m serial number */
     if (certutil.options[opt_SerialNumber].activated) {
 	int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
 	if (sn < 0) {
 	    PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
 	               progName, certutil.options[opt_SerialNumber].arg);
 	    return 255;
 	}
@@ -2932,16 +3070,19 @@ merge_fail:
 	    CERT_DestroyCertificate(keycert);
 	} else {
 	    privkey = 
 		CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
 					    publicExponent, 
 					    certutil.options[opt_NoiseFile].arg,
 					    &pubkey, 
 					    certutil.options[opt_PQGFile].arg,
+					    keyAttrFlags,
+					    keyOpFlagsOn,
+					    keyOpFlagsOff,
 					    &pwdata);
 	    if (privkey == NULL) {
 		SECU_PrintError(progName, "unable to generate key(s)\n");
 		rv = SECFailure;
 		goto shutdown;
 	    }
 	}
 	privkey->wincx = &pwdata;
--- a/cmd/certutil/certutil.h
+++ b/cmd/certutil/certutil.h
@@ -8,16 +8,19 @@
 extern SECKEYPrivateKey *
 CERTUTIL_GeneratePrivateKey(KeyType keytype,
                             PK11SlotInfo *slot, 
                             int rsasize,
                             int publicExponent,
                             char *noise,
                             SECKEYPublicKey **pubkeyp,
                             char *pqgFile,
+                            PK11AttrFlags attrFlags,
+                            CK_FLAGS opFlagsOn,
+                            CK_FLAGS opFlagsOff,
                             secuPWData *pwdata);
 
 extern char *progName;
 
 enum certutilExtns {
     ext_keyUsage = 0,
     ext_basicConstraint,
     ext_authorityKeyID,
--- a/cmd/certutil/keystuff.c
+++ b/cmd/certutil/keystuff.c
@@ -485,17 +485,18 @@ getECParams(const char *curve)
     return ecparams;
 }
 #endif /* NSS_ENABLE_ECC */
 
 SECKEYPrivateKey *
 CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size,
 			    int publicExponent, const char *noise, 
 			    SECKEYPublicKey **pubkeyp, const char *pqgFile,
-                            secuPWData *pwdata)
+			    PK11AttrFlags attrFlags, CK_FLAGS opFlagsOn,
+			    CK_FLAGS opFlagsOff, secuPWData *pwdata)
 {
     CK_MECHANISM_TYPE  mechanism;
     SECOidTag          algtag;
     PK11RSAGenParams   rsaparams;
     SECKEYPQGParams  * dsaparams = NULL;
     void             * params;
     SECKEYPrivateKey * privKey = NULL;
 
@@ -554,18 +555,18 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
 #endif /* NSS_ENABLE_ECC */
     default:
 	return NULL;
     }
 
     fprintf(stderr, "\n\n");
     fprintf(stderr, "Generating key.  This may take a few moments...\n\n");
 
-    privKey = PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp,
-				PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, 
+    privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism, params, pubkeyp,
+				attrFlags, opFlagsOn, opFlagsOn|opFlagsOff,
 				pwdata /*wincx*/);
     /* free up the params */
     switch (keytype) {
     case dsaKey: if (dsaparams) CERTUTIL_DestroyParamsPQG(dsaparams); 
 	                                                      break;
 #ifdef NSS_ENABLE_ECC
     case ecKey: SECITEM_FreeItem((SECItem *)params, PR_TRUE); break;
 #endif