rpms/crypto-utils/devel keyutil.c,1.1,1.2

Elio Maldonado (emaldonado) fedora-extras-commits at redhat.com
Fri May 2 23:42:59 UTC 2008


Author: emaldonado

Update of /cvs/extras/rpms/crypto-utils/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv21916

Modified Files:
	keyutil.c 
Log Message:
Added support for exporting unencrypted keys for openssl (#346731)


Index: keyutil.c
===================================================================
RCS file: /cvs/extras/rpms/crypto-utils/devel/keyutil.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- keyutil.c	1 May 2008 01:06:25 -0000	1.1
+++ keyutil.c	2 May 2008 23:42:20 -0000	1.2
@@ -88,7 +88,7 @@
 #include <prio.h>
 #include <prlong.h>
 #include <prtime.h>
-#include <pk11func.h>
+#include <pkcs11.h>
 #include <pk11pub.h>
 #include <pkcs11t.h>
 #include <assert.h>
@@ -103,6 +103,10 @@
 #include <plarenas.h>
 #include <secasn1.h>
 
+#include <secpkcs5.h>
+#include <keythi.h>
+#include <secmodt.h>
+
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -173,7 +177,8 @@
 	fprintf(stderr, "-g keysize in bits");
 	fprintf(stderr, "-v validity in months");
 	fprintf(stderr, "-z noise file");
-	fprintf(stderr, "-f password file");
+	fprintf(stderr, "-f key encryption password file");
+	fprintf(stderr, "-f module access password file");
 	fprintf(stderr, "-d digest algorithm");
 	fprintf(stderr, "-i input (key to encrypt)");
 	fprintf(stderr, "-k key out, when csr or cert generation");
@@ -760,7 +765,7 @@
     int publicExponent,
 	char *noise, 
     SECKEYPublicKey **pubkeyp,
-    secuPWData *pwdata)
+    secuPWData *accessPassword)
 {
     CK_MECHANISM_TYPE  mechanism;
     PK11RSAGenParams   rsaparams;
@@ -769,7 +774,7 @@
     if (slot == NULL) 
     	return NULL;
 
-    if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess)
+    if (PK11_Authenticate(slot, PR_TRUE, accessPassword) != SECSuccess)
     	return NULL;
 
     /*
@@ -801,7 +806,7 @@
     		mechanism, &rsaparams, pubkeyp,
             PR_FALSE /* isPerm */, 
             PR_TRUE  /* isSensitive*/, 
-            pwdata   /* wincx */
+            accessPassword   /* wincx */
             );
     
     assert(privKey);
@@ -811,7 +816,7 @@
 
 static SECStatus
 ValidateCert(CERTCertDBHandle *handle, CERTCertificate  *cert, char *name, char *date,
-	    char *certUsage, PRBool checkSig, PRBool logit, secuPWData *pwdata)
+	    char *certUsage, PRBool checkSig, PRBool logit, secuPWData *accessPassword)
 {
     SECStatus rv;
     int64 timeBoundary;
@@ -872,7 +877,7 @@
 		}
 		fprintf(stdout, "%s: CERT_VerifyCertificate called\n", progName);
 		rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
-			     timeBoundary, pwdata, log, &usage);
+			     timeBoundary, accessPassword, log, &usage);
 		fprintf(stdout, "%s: CERT_VerifyCertificate returned %d\n", progName, rv);
 		
 		if ( log ) {
@@ -934,7 +939,7 @@
 	SECKEYEncryptedPrivateKeyInfo epki;
 	PRArenaPool *arena = NULL;
 	SECItem pwitem = { 0, NULL, 0 };
-	secuPWData pwdata = { 0, NULL };
+	secuPWData accessPassword = { 0, NULL };
 	
 	do {
 		if (passwordfile) {
@@ -973,7 +978,7 @@
 				&epki, &pwitem, &nickname, &dummy, 
 				PR_FALSE, PR_TRUE, /* not permanent, private */
 				rsaKey, 0,         /* signing */
-				&pwdata
+				&accessPassword
 	           );
 		if (rv) {
 			SECU_PrintError(progName, 
@@ -992,35 +997,149 @@
 	return rv;
 }
 
+/* Decrypt the private key */
+SECStatus DecryptKey(
+	SECKEYEncryptedPrivateKeyInfo *epki,    
+    SECOidTag algTag,
+    SECItem *pwitem, 
+    secuPWData *accessPassword,
+    SECItem **derPKI
+    )
+{
+	PLArenaPool *arena = NULL;
+	SECItem  *cryptoParam = NULL;
+	PK11SymKey *symKey = NULL;
+	PK11Context *ctx = NULL;
+	SECItem *dest = NULL;
+	SECStatus rv = SECSuccess;
+
+    if (!pwitem) {
+		return SEC_ERROR_INVALID_ARGS;
+    }
+	
+	do {	
+		SECAlgorithmID algid = epki->algorithm;
+		CK_MECHANISM_TYPE cryptoMechType;
+		CK_MECHANISM cryptoMech;
+		CK_ATTRIBUTE_TYPE operation = CKA_DECRYPT;
+		
+		/* don't know if this will work */
+		symKey = PK11_PBEKeyGen(PK11_GetInternalSlot(), 
+				&algid, pwitem, PR_FALSE, accessPassword);
+	    if (symKey == NULL) {
+	    	ERROR_BREAK;
+	    }
+	    
+	    cryptoMechType = PK11_GetPBECryptoMechanism(&algid, &cryptoParam, pwitem);
+	    if (cryptoMechType == CKM_INVALID_MECHANISM)  {
+	    	ERROR_BREAK;
+	    }
+	    
+	    cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType);
+	    cryptoMech.pParameter = cryptoParam ? cryptoParam->data : NULL;
+	    cryptoMech.ulParameterLen = cryptoParam ? cryptoParam->len : 0;
+
+	    ctx = PK11_CreateContextBySymKey(cryptoMechType, operation, symKey, cryptoParam);
+	    if (ctx == NULL) {
+	    	 ERROR_BREAK;    	
+	    }
+
+	    arena = PORT_NewArena(2048);
+	    if (!arena) {
+	    	GEN_BREAK(PR_OUT_OF_MEMORY_ERROR);
+	    }
+
+	    dest = malloc(sizeof(SECItem));
+	    assert(dest);
+	    dest->data = PORT_ArenaAlloc(arena, epki->encryptedData.len);
+	    dest->len = 0;
+	    dest->type = siBuffer; /* siClearDataBuffer? */
+	    
+	    rv = PK11_CipherOp(ctx, 
+	    		dest->data,                    /* out */
+	    		(int *)(&dest->len),           /* out len */
+	    		(int)epki->encryptedData.len,    /* max out */
+	    		epki->encryptedData.data,        /* in */
+			    (int)epki->encryptedData.len);   /* in len */
+	    
+	    assert(dest->len == epki->encryptedData.len);
+	    assert(rv == SECSuccess);
+	    rv = PK11_Finalize(ctx);
+	    assert(rv == SECSuccess);
+	    
+    } while (0);
+ 
+	/* cleanup */
+	if (symKey) {
+		PK11_FreeSymKey(symKey);
+	}
+    if (cryptoParam) {
+    	SECITEM_ZfreeItem(cryptoParam, PR_TRUE);
+    	cryptoParam = NULL;
+    }
+	if (ctx) {
+		PK11_DestroyContext(ctx, PR_TRUE);
+	}
+
+	if (rv != SECSuccess) {
+		if (dest) {
+			if (arena) {
+				PORT_FreeArena(arena, PR_TRUE);
+			}
+		}
+		*derPKI = NULL;
+	} else {
+		*derPKI = dest;		
+	}
+	
+	return rv;
+
+}
+
 /* Output the private key to a file */
 static SECStatus
 KeyOut(const char *keyoutfile,
-	   const char *passwordfile,
+	   const char *key_pwd_file,
        SECKEYPrivateKey *privkey,
        SECKEYPublicKey *pubkey,
        SECOidTag algTag,
-       secuPWData *pwdata,
+       secuPWData *accessPassword,
        PRBool ascii)
 {
+	
+#define PRAND_PASS_LEN 6
+	
 	PRFileDesc *keyOutFile = NULL;
-	PRUint32 total = 0, numBytes = 0;
+	PRUint32 total = 0;
+	PRUint32 numBytes = 0;
 	SECItem *derEPKI = NULL;
+	SECItem *derPKI = NULL;
 	char *b64 = NULL;
 	SECItem pwitem = { 0, NULL, 0 };
 	PRArenaPool *arena = NULL;
 	SECKEYEncryptedPrivateKeyInfo *epki = NULL;
+	unsigned char randomPassword[PRAND_PASS_LEN];
+	
 	int rv = SECSuccess;
 
 	do {
-        
-		if (passwordfile) {
-			if (!GetKeyPassword(passwordfile, &pwitem))
+		/* get the password from the file */
+		if (key_pwd_file) {
+			if (!GetKeyPassword(key_pwd_file, &pwitem)) {
 				return 255;
+			}
 		} else {
-			PR_fprintf(PR_STDERR, 
-					"%s export of clear keys not impemented yet\n",
-					progName);
+			/* No password file indicates the caller wants clear keys. 
+			 * Make up a dummy password to get NSS to export an encrypted 
+			 * key and then decrypt it 
+			 */
+			rv = PK11_GenerateRandom(randomPassword, PRAND_PASS_LEN);
+			if (rv != SECSuccess) GEN_BREAK(rv);	
+			pwitem.data = randomPassword;
+			pwitem.len = PRAND_PASS_LEN;
+			pwitem.type = siBuffer;
 		}
+		
     	keyOutFile = PR_Open(keyoutfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
     	if (!keyOutFile) {
     	    PR_fprintf(PR_STDERR,
@@ -1030,7 +1149,7 @@
     	}
 
 	    epki = PK11_ExportEncryptedPrivKeyInfo(NULL,
-	    		algTag, &pwitem, privkey, 1000, pwdata);
+	    		algTag, &pwitem, privkey, 1000, accessPassword);
 		if (!epki) {
 			rv = PORT_GetError();
 			SECU_PrintError(progName, 
@@ -1040,55 +1159,59 @@
 		
 		arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 		assert(arena);
-
-        /* NULL dest to let it allocate memory for us */
-		derEPKI = SEC_ASN1EncodeItem(arena, NULL, epki,
-		            SECKEY_EncryptedPrivateKeyInfoTemplate);
 		
-        if (derEPKI == NULL) {
-        	PR_fprintf(PR_STDERR, "%s ASN1 Encode failed (%dl)\n",
-        		    progName, PR_GetError());
-        	GEN_BREAK(255);
-        }
-	    
-	    assert(derEPKI);      
-	    assert(derEPKI->len);
-		assert(derEPKI->data);
-    	   
-		if (!passwordfile) {
-			/* Make a decrypted key the one to write out. 
-			 * Can't use SECKEYPrivateKeyInfo *
-			 * *PK11_ExportPrivateKeyInfo(
-		     * CERTCertificate *cert, void *wincx);
-		     * as it always returns NULL.
-			 * We exported the key encrypted, decrypt it
-			 * and write that one out.
-			 */
-		}
+    	if (key_pwd_file) {
+	        /* NULL dest to let it allocate memory for us */
+			derEPKI = SEC_ASN1EncodeItem(arena, NULL, epki,
+			            SECKEY_EncryptedPrivateKeyInfoTemplate);
+	        if (rv != SECSuccess) {
+	        	PR_fprintf(PR_STDERR, "%s ASN1 Encode failed (%dl)\n",
+	        		    progName, rv);
+	        	GEN_BREAK(rv);
+	        }
+   		
+    	} else {
+			/* Make a decrypted key the one to write out. */
+			rv = DecryptKey(epki, algTag, &pwitem, accessPassword, &derPKI);
+			if (rv) {
+				GEN_BREAK(rv);
+			}
+    	}
  
         if (ascii) {
-        	char *header = passwordfile 
-                ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
-        	char *trailer = passwordfile 
-                ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
-        	
-    		b64 = BTOA_ConvertItemToAscii(derEPKI);
+        	/* we could be exporting a clear or encrypted key */
+        	SECItem *src  = key_pwd_file ? derEPKI : derPKI;
+        	char *header  = key_pwd_file ? ENCRYPTED_KEY_HEADER : KEY_HEADER;
+        	char *trailer = key_pwd_file ? ENCRYPTED_KEY_TRAILER : KEY_TRAILER;
+        	        	
+    		b64 = BTOA_ConvertItemToAscii(src);
     	    assert(b64);
     	    total = PL_strlen(b64);
        	
             PR_fprintf(keyOutFile, "%s\n", header);
             
         	numBytes = PR_Write(keyOutFile, b64, total);
-        	assert(numBytes == total);
+        	
+            if (numBytes != total) {
+            	printf("Wrote  %d bytes, instead of %d\n", numBytes, total);
+            }
+
         	
         	PR_fprintf(keyOutFile, "\n%s\n", trailer);
         } else {
-            numBytes = PR_Write(keyOutFile, derEPKI, derEPKI->len);
-            assert(numBytes == derEPKI->len);
+        	if (key_pwd_file) {
+        		numBytes = PR_Write(keyOutFile, derEPKI, derEPKI->len);
+        	} else {
+        		numBytes = PR_Write(keyOutFile, derPKI, derPKI->len);
+                if (numBytes != derEPKI->len) {
+                	printf("Wrote  %d bytes, instead of %d\n", numBytes, derPKI->len);
+                }
+
+        	}
+            
         }
     	
-		printf("Wrote %d bytes of encoded data to %s \n", 
-				numBytes, keyoutfile);
+		printf("Wrote %d bytes of encoded data to %s \n", numBytes, keyoutfile);
 		/* can we read it and reverse operations */
 		
     } while (0);
@@ -1101,6 +1224,13 @@
    	    PORT_FreeArena(arena, PR_FALSE);
     }
 	
+  	if (!key_pwd_file) {
+  		/* paranoia, this is stack-based object but we clear it anyway */
+  		int i;
+  		for (i = 0; i< PRAND_PASS_LEN; i++) {
+  			randomPassword[i]='\0';
+  		}
+  	}
 	return rv;
 }
 
@@ -1110,7 +1240,8 @@
 static int keyutil_main(
 		CERTCertDBHandle *certHandle,
 		const char       *noisefile, 
-        const char       *passwordfile, 
+        const char       *access_pwd_file,
+        const char       *key_pwd_file,
         const char       *subjectstr,
         int              keysize, 
     	int              warpmonths,
@@ -1130,7 +1261,7 @@
 	SECKEYPublicKey *pubkey     = NULL;
                                /* PK11_GetInternalSlot() ? */
 	PK11SlotInfo *slot          = PK11_GetInternalKeySlot();
-    secuPWData  pwdata          = { PW_NONE, 0 };
+    secuPWData  accessPassword  = { PW_NONE, 0 };
     KeyType     keytype         = rsaKey;
     SECOidTag   hashAlgTag      = SEC_OID_UNKNOWN;
     PRBool      doCert          = certfile != NULL;
@@ -1145,16 +1276,13 @@
 	    return 255;
 	}
     printf("Opened %s for writing\n", certreqfile);
-	if (passwordfile) {
-	    pwdata.source = PW_FROMFILE;
-	    pwdata.data = (char *)passwordfile;
-    } else {
-        pwdata.source = PW_PLAINTEXT;
-        pwdata.data = (char *)"badpassword";
+	if (access_pwd_file) {
+	    accessPassword.source = PW_FROMFILE;
+	    accessPassword.data = (char *)access_pwd_file;
     }
 
 	privkey = GenerateRSAPrivateKey(keytype, slot, 
-			keysize, 65537L, (char *)noisefile, &pubkey, &pwdata);
+			keysize, 65537L, (char *)noisefile, &pubkey, &accessPassword);
 	
 	if (!privkey) {
 	    PR_fprintf(PR_STDERR,
@@ -1209,7 +1337,7 @@
 	    LL_USHR(now, now, 19);
 	    LL_L2UI(serialNumber, now);
 		
-	    privkey->wincx = &pwdata;
+	    privkey->wincx = &accessPassword;
 	    PR_Close(outFile);
 	   
 	    inFile  = PR_Open(certreqfile, PR_RDONLY, 0);
@@ -1235,7 +1363,7 @@
 	    /* issuerName == subject */
 	    rv = CreateCert(certHandle, 
 	        "tempnickname", inFile, outFile,
-			privkey, &pwdata, hashAlgTag,
+			privkey, &accessPassword, hashAlgTag,
 	        serialNumber, warpmonths, validityMonths,
 	        NULL, NULL, ascii, PR_TRUE, NULL,
 	        &cert);
@@ -1255,7 +1383,7 @@
 	
 	     /* XXX temporary hack for fips - must log in to get priv key */
 	    if (slot && PK11_NeedLogin(slot)) {
-	        SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
+	        SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &accessPassword);
 	        if (newrv != SECSuccess) {
 	            SECU_PrintError(progName, "could not authenticate to token %s.",
 	                        PK11_GetTokenName(slot));
@@ -1272,7 +1400,7 @@
 	    		NULL,     // Usage.arg,    --> certificateUsageSSLServer
 	    		PR_TRUE, // VerifySig,
 	    		PR_TRUE, // DetailedInfo,
-	            &pwdata);
+	            &accessPassword);
 	        if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS) {
 	        	SECU_PrintError(progName, "validation failed");
 	            goto shutdown;
@@ -1285,11 +1413,9 @@
     	/* Two candidate tags to use: SEC_OID_DES_EDE3_CBC and
     	 * SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
     	 */
-	    rv = KeyOut(keyoutfile,
-                passwordfile,
-                privkey, pubkey,
-	    		SEC_OID_DES_EDE3_CBC, 
-	    		&pwdata, ascii);
+	    rv = KeyOut(keyoutfile, key_pwd_file,
+                privkey, pubkey, SEC_OID_DES_EDE3_CBC, 
+	    		&accessPassword, ascii);
 	    if (rv != SECSuccess) {
 	    	SECU_PrintError(progName, "Failed to write the key");
 	    } else {
@@ -1337,7 +1463,8 @@
     	{ "subject",    required_argument, NULL, 's'},
     	{ "gkeysize",   required_argument, NULL, 'g'},
     	{ "validity",   required_argument, NULL, 'v'},
-        { "filepwd",    required_argument, NULL, 'f' },
+        { "encpwdfile", required_argument, NULL, 'e' },
+        { "filepwdnss", required_argument, NULL, 'f' },
         { "digest",     required_argument, NULL, 'd' },
         { "znoisefile", required_argument, NULL, 'z' },
         { "input",      required_argument, NULL, 'i' }, /* key in */
@@ -1355,7 +1482,8 @@
     char *keyfile = NULL;
     char *outfile = NULL;
     char *subject = NULL;
-    char *passwordfile = NULL;
+    char *access_pwd_file = NULL;
+    char *key_pwd_file = NULL;
     char *digestAlgorithm = "md5";
     char *keyoutfile = 0;
     PRBool ascii = PR_FALSE;
@@ -1366,7 +1494,7 @@
     
     progName = argv[0];
     
-    while ((optc = getopt_long(argc, argv, "ac:s:g:v:f:d:z:i:p:o:k:", options, NULL)) != -1) {
+    while ((optc = getopt_long(argc, argv, "ac:s:g:v:e:f:d:z:i:p:o:k:", options, NULL)) != -1) {
         switch (optc) {
         case 'a':
         	ascii = PR_TRUE;
@@ -1401,9 +1529,13 @@
         	validity_months = atoi(optarg);
         	printf("valid for %d months\n", validity_months);
         	break;
+        case 'e':
+        	key_pwd_file = strdup(optarg);
+        	printf("key encryption password from = %s\n", key_pwd_file);
+        	break;
         case 'f':
-        	passwordfile = strdup(optarg);
-        	printf("password from = %s\n", passwordfile);
+        	access_pwd_file = strdup(optarg);
+        	printf("module access password from = %s\n", access_pwd_file);
         	break;
         case 'd':
             digestAlgorithm = strdup(optarg);
@@ -1453,19 +1585,19 @@
     	printf("\ncmd_CertReq\n");
         /* certfile NULL signals only the request is needed */
         rv = keyutil_main(certHandle,
-                noisefile, passwordfile, subject,
-                keysize, warpmonths, validity_months,
+                noisefile, access_pwd_file, key_pwd_file,
+                subject, keysize, warpmonths, validity_months,
                 ascii, outfile, NULL, keyoutfile);
         break;
     case cmd_CreateNewCert:
     	printf("\ncmd_CreateNewCert\n");
 	    rv = keyutil_main(certHandle,
-                noisefile, passwordfile, subject,
-                keysize, warpmonths, validity_months,
+                noisefile, access_pwd_file, key_pwd_file,
+                subject, keysize, warpmonths, validity_months,
                 ascii, "tmprequest", outfile, keyoutfile);
         break;
     case cmd_ImportKey:
-    	rv = ImportKey(certHandle, passwordfile, keyfile, PR_TRUE);
+    	rv = ImportKey(certHandle, key_pwd_file, keyfile, PR_TRUE);
     	break;
     default:
     	printf("\nEntered an inconsistent state, bailing out\n");




More information about the fedora-extras-commits mailing list