summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--security/nss/cmd/pk12util/pk12util.c171
-rw-r--r--security/nss/lib/pkcs12/p12.h16
-rw-r--r--security/nss/lib/pkcs12/p12d.c143
-rw-r--r--security/nss/lib/smime/smime.def7
-rw-r--r--security/nss/tests/tools/tools.sh7
5 files changed, 334 insertions, 10 deletions
diff --git a/security/nss/cmd/pk12util/pk12util.c b/security/nss/cmd/pk12util/pk12util.c
index 2ea30bc46..20bdc1c8f 100644
--- a/security/nss/cmd/pk12util/pk12util.c
+++ b/security/nss/cmd/pk12util/pk12util.c
@@ -59,6 +59,9 @@ Usage(char *progName)
progName);
FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
FPS "\t\t [-v]\n");
+ FPS "Usage: %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
+ progName);
+ FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
FPS "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n", progName);
FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
FPS "\t\t [-v]\n");
@@ -686,6 +689,140 @@ loser:
return;
}
+
+PRIntn
+P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
+ secuPWData *slotPw, secuPWData *p12FilePw)
+{
+ p12uContext *p12cxt = NULL;
+ SEC_PKCS12DecoderContext *p12dcx = NULL;
+ SECItem *pwitem = NULL, uniPwitem = { 0 };
+ SECItem p12file = { 0 };
+ SECStatus rv = SECFailure;
+ PRBool swapUnicode = PR_FALSE;
+ const SEC_PKCS12DecoderItem *dip;
+
+ int error;
+
+#ifdef IS_LITTLE_ENDIAN
+ swapUnicode = PR_TRUE;
+#endif
+
+ p12cxt = p12u_InitContext(PR_TRUE, in_file);
+ if(!p12cxt) {
+ SECU_PrintError(progName,"File Open failed: %s", in_file);
+ pk12uErrno = PK12UERR_INIT_FILE;
+ goto loser;
+ }
+
+ /* get the password */
+ pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
+ if (!pwitem) {
+ pk12uErrno = PK12UERR_USER_CANCELLED;
+ goto loser;
+ }
+
+ if(P12U_UnicodeConversion(NULL, &uniPwitem, pwitem, PR_TRUE,
+ swapUnicode) != SECSuccess) {
+ SECU_PrintError(progName,"Unicode conversion failed");
+ pk12uErrno = PK12UERR_UNICODECONV;
+ goto loser;
+ }
+
+ /* init the decoder context */
+ p12dcx = SEC_PKCS12DecoderStart(&uniPwitem, slot, slotPw,
+ NULL, NULL, NULL, NULL, NULL);
+ if(!p12dcx) {
+ SECU_PrintError(progName,"PKCS12 decoder start failed");
+ pk12uErrno = PK12UERR_PK12DECODESTART;
+ goto loser;
+ }
+
+ /* read the item */
+ rv = SECU_FileToItem(&p12file, p12cxt->file);
+ PR_Close(p12cxt->file);
+ p12cxt->file = NULL;
+
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName,"Failed to read from import file");
+ goto loser;
+ }
+
+ rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
+ if(rv != SECSuccess) {
+ error = PR_GetError();
+ if(error == SEC_ERROR_DECRYPTION_DISALLOWED) {
+ PR_SetError(error, 0);
+ goto loser;
+ }
+ SECU_PrintError(progName,"PKCS12 decoding failed");
+ pk12uErrno = PK12UERR_DECODE;
+ }
+
+ /* does the blob authenticate properly? */
+ if(SEC_PKCS12DecoderVerify(p12dcx) != SECSuccess) {
+ SECU_PrintError(progName,"PKCS12 decode not verified");
+ pk12uErrno = PK12UERR_DECODEVERIFY;
+ rv = SECFailure;
+ }
+ else if (SEC_PKCS12DecoderIterateInit(p12dcx) != SECSuccess) {
+ SECU_PrintError(progName,"PKCS12 decode iterate bags failed");
+ pk12uErrno = PK12UERR_DECODEIMPTBAGS;
+ rv = SECFailure;
+ }
+ else {
+ while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
+ switch (dip->type) {
+ case SEC_OID_PKCS12_V1_CERT_BAG_ID:
+ printf("Certificate");
+ if (SECU_PrintSignedData(stdout, dip->der,
+ (dip->hasKey) ? "(has private key)" : "",
+ 0, SECU_PrintCertificate) != 0) {
+ SECU_PrintError(progName,"PKCS12 print cert bag failed");
+ }
+ if (dip->friendlyName != NULL) {
+ printf(" Friendly Name: %s\n\n",
+ dip->friendlyName->data);
+ }
+ break;
+ case SEC_OID_PKCS12_V1_KEY_BAG_ID:
+ case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
+ printf("Key");
+ if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
+ printf("(shrouded)");
+ printf(":\n");
+ if (dip->friendlyName != NULL) {
+ printf(" Friendly Name: %s\n\n",
+ dip->friendlyName->data);
+ }
+ break;
+ default:
+ printf("unknown bag type(%d): %s\n\n", dip->type,
+ SECOID_FindOIDTagDescription(dip->type));
+ break;
+ }
+ }
+ rv = SECSuccess;
+ }
+
+loser:
+
+ if (p12dcx) {
+ SEC_PKCS12DecoderFinish(p12dcx);
+ }
+ p12u_DestroyContext(&p12cxt, PR_FALSE);
+
+ if (uniPwitem.data) {
+ SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
+ }
+
+ if (pwitem) {
+ SECITEM_ZfreeItem(pwitem, PR_TRUE);
+ }
+
+ return rv;
+}
+
static void
p12u_EnableAllCiphers()
{
@@ -699,13 +836,18 @@ p12u_EnableAllCiphers()
}
static PRUintn
-P12U_Init(char *dir, char *dbprefix)
+P12U_Init(char *dir, char *dbprefix, PRBool listonly)
{
SECStatus rv;
PK11_SetPasswordFunc(SECU_GetModulePassword);
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
- rv = NSS_Initialize(dir,dbprefix,dbprefix,"secmod.db",0);
+ if (listonly && NSS_NoDB_Init("") == SECSuccess) {
+ rv = SECSuccess;
+ }
+ else {
+ rv = NSS_Initialize(dir,dbprefix,dbprefix,"secmod.db",0);
+ }
if (rv != SECSuccess) {
SECU_PrintPRandOSError(progName);
exit(-1);
@@ -726,6 +868,7 @@ enum {
opt_Import,
opt_SlotPWFile,
opt_SlotPW,
+ opt_List,
opt_Nickname,
opt_Export,
opt_P12FilePWFile,
@@ -741,6 +884,7 @@ static secuCommandFlag pk12util_options[] =
{ /* opt_Import */ 'i', PR_TRUE, 0, PR_FALSE },
{ /* opt_SlotPWFile */ 'k', PR_TRUE, 0, PR_FALSE },
{ /* opt_SlotPW */ 'K', PR_TRUE, 0, PR_FALSE },
+ { /* opt_List */ 'l', PR_TRUE, 0, PR_FALSE },
{ /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE },
{ /* opt_Export */ 'o', PR_TRUE, 0, PR_FALSE },
{ /* opt_P12FilePWFile */ 'w', PR_TRUE, 0, PR_FALSE },
@@ -778,8 +922,9 @@ main(int argc, char **argv)
pk12_debugging = pk12util.options[opt_Debug].activated;
- if (pk12util.options[opt_Import].activated +
- pk12util.options[opt_Export].activated != 1) {
+ if ((pk12util.options[opt_Import].activated +
+ pk12util.options[opt_Export].activated +
+ pk12util.options[opt_List].activated) != 1) {
Usage(progName);
}
@@ -789,7 +934,10 @@ main(int argc, char **argv)
}
slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
- import_file = SECU_GetOptionArg(&pk12util, opt_Import);
+
+ import_file = (pk12util.options[opt_List].activated) ?
+ SECU_GetOptionArg(&pk12util, opt_List) :
+ SECU_GetOptionArg(&pk12util, opt_Import);
export_file = SECU_GetOptionArg(&pk12util, opt_Export);
if (pk12util.options[opt_P12FilePWFile].activated) {
@@ -818,7 +966,8 @@ main(int argc, char **argv)
if (pk12util.options[opt_DBPrefix].activated) {
dbprefix = pk12util.options[opt_DBPrefix].arg;
}
- P12U_Init(SECU_ConfigDirectory(NULL),dbprefix);
+ P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
+ pk12util.options[opt_List].activated);
if (!slotname || PL_strcmp(slotname, "internal") == 0)
slot = PK11_GetInternalKeySlot();
@@ -832,14 +981,16 @@ main(int argc, char **argv)
}
if (pk12util.options[opt_Import].activated) {
-
- if ((ret = P12U_ImportPKCS12Object(import_file, slot, &slotPw,
- &p12FilePw)) != 0)
- goto done;
+ P12U_ImportPKCS12Object(import_file, slot, &slotPw,
+ &p12FilePw);
} else if (pk12util.options[opt_Export].activated) {
P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
export_file, slot, &slotPw, &p12FilePw);
+
+ } else if (pk12util.options[opt_List].activated) {
+ P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
+
} else {
Usage(progName);
pk12uErrno = PK12UERR_USAGE;
diff --git a/security/nss/lib/pkcs12/p12.h b/security/nss/lib/pkcs12/p12.h
index 155b171e1..6eb6ecfed 100644
--- a/security/nss/lib/pkcs12/p12.h
+++ b/security/nss/lib/pkcs12/p12.h
@@ -80,6 +80,7 @@ typedef int (PR_CALLBACK *digestIOFn)(void *arg, unsigned char *buf,
typedef struct SEC_PKCS12ExportContextStr SEC_PKCS12ExportContext;
typedef struct SEC_PKCS12SafeInfoStr SEC_PKCS12SafeInfo;
typedef struct SEC_PKCS12DecoderContextStr SEC_PKCS12DecoderContext;
+typedef struct SEC_PKCS12DecoderItemStr SEC_PKCS12DecoderItem;
struct sec_PKCS12PasswordModeInfo {
SECItem *password;
@@ -93,6 +94,14 @@ struct sec_PKCS12PublicKeyModeInfo {
int keySize;
};
+struct SEC_PKCS12DecoderItemStr {
+ SECItem *der;
+ SECOidTag type;
+ PRBool hasKey;
+ SECItem *friendlyName; /* UTF-8 string */
+};
+
+
SEC_BEGIN_PROTOS
SEC_PKCS12SafeInfo *
@@ -187,6 +196,13 @@ SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx);
CERTCertList *
SEC_PKCS12DecoderGetCerts(SEC_PKCS12DecoderContext *p12dcx);
+SECStatus
+SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx);
+
+SECStatus
+SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
+ const SEC_PKCS12DecoderItem **ipp);
+
SEC_END_PROTOS
#endif
diff --git a/security/nss/lib/pkcs12/p12d.c b/security/nss/lib/pkcs12/p12d.c
index c6a1c51ab..67d01ea19 100644
--- a/security/nss/lib/pkcs12/p12d.c
+++ b/security/nss/lib/pkcs12/p12d.c
@@ -146,6 +146,9 @@ struct SEC_PKCS12DecoderContextStr {
PRInt32 allocated; /* total buffer size allocated */
PRInt32 currentpos; /* position counter */
SECPKCS12TargetTokenCAs tokenCAs;
+ sec_PKCS12SafeBag **keyList;/* used by ...IterateNext() */
+ unsigned int iteration;
+ SEC_PKCS12DecoderItem decitem;
};
@@ -1233,6 +1236,13 @@ SEC_PKCS12DecoderStart(SECItem *pwitem, PK11SlotInfo *slot, void *wincx,
p12dcx->dClose = dClose;
p12dcx->dRead = dRead;
p12dcx->dArg = dArg;
+
+ p12dcx->keyList = NULL;
+ p12dcx->decitem.type = 0;
+ p12dcx->decitem.der = NULL;
+ p12dcx->decitem.hasKey = PR_FALSE;
+ p12dcx->decitem.friendlyName = NULL;
+ p12dcx->iteration = 0;
return p12dcx;
@@ -1523,6 +1533,13 @@ SEC_PKCS12DecoderFinish(SEC_PKCS12DecoderContext *p12dcx)
SEC_ASN1DecoderFinish(p12dcx->hmacDcx);
p12dcx->hmacDcx = NULL;
}
+
+ if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
+ SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
+ }
+ if (p12dcx->decitem.friendlyName != NULL) {
+ SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
+ }
if(p12dcx->slot) {
PK11_FreeSlot(p12dcx->slot);
@@ -2908,6 +2925,132 @@ SEC_PKCS12DecoderImportBags(SEC_PKCS12DecoderContext *p12dcx)
return sec_pkcs12_install_bags(p12dcx->safeBags, p12dcx->wincx);
}
+PRBool
+sec_pkcs12_bagHasKey(SEC_PKCS12DecoderContext *p12dcx, sec_PKCS12SafeBag *bag)
+{
+ int i;
+ SECItem *keyId;
+ SECItem *certKeyId;
+
+ certKeyId = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_LOCAL_KEY_ID);
+ if (certKeyId == NULL) {
+ return PR_FALSE;
+ }
+
+ for (i=0; p12dcx->keyList && p12dcx->keyList[i]; i++) {
+ keyId = sec_pkcs12_get_attribute_value(p12dcx->keyList[i],
+ SEC_OID_PKCS9_LOCAL_KEY_ID);
+ if(!keyId) {
+ continue;
+ }
+ if(SECITEM_CompareItem(certKeyId, keyId) == SECEqual) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
+SECItem *
+sec_pkcs12_get_friendlyName(sec_PKCS12SafeBag *bag)
+{
+ SECItem *friendlyName;
+ SECItem *tempnm;
+
+ tempnm = sec_pkcs12_get_attribute_value(bag, SEC_OID_PKCS9_FRIENDLY_NAME);
+ friendlyName = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
+ if (friendlyName) {
+ if (!sec_pkcs12_convert_item_to_unicode(NULL, friendlyName,
+ tempnm, PR_TRUE, PR_FALSE, PR_FALSE)) {
+ SECITEM_FreeItem(friendlyName, PR_TRUE);
+ friendlyName = NULL;
+ }
+ }
+ return friendlyName;
+}
+
+/* Following two functions provide access to selected portions of the safe bags.
+ * Iteration is implemented per decoder context and may be accessed after
+ * SEC_PKCS12DecoderVerify() returns success.
+ * When ...DecoderIterateNext() returns SUCCESS a decoder item has been returned
+ * where item.type is always set; item.friendlyName is set if it is non-null;
+ * item.der, item.hasKey are set only for SEC_OID_PKCS12_V1_CERT_BAG_ID items.
+ * ...DecoderIterateNext() returns FAILURE when the list is exhausted or when
+ * arguments are invalid; PORT_GetError() is 0 at end-of-list.
+ * Caller has read-only access to decoder items. Any SECItems generated are
+ * owned by the decoder context and are freed by ...DecoderFinish().
+ */
+SECStatus
+SEC_PKCS12DecoderIterateInit(SEC_PKCS12DecoderContext *p12dcx)
+{
+ if(!p12dcx || p12dcx->error) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ p12dcx->iteration = 0;
+ return SECSuccess;
+}
+
+SECStatus
+SEC_PKCS12DecoderIterateNext(SEC_PKCS12DecoderContext *p12dcx,
+ const SEC_PKCS12DecoderItem **ipp)
+{
+ sec_PKCS12SafeBag *bag;
+ SECItem *tempnm;
+
+ if(!p12dcx || p12dcx->error) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (p12dcx->decitem.type != 0 && p12dcx->decitem.der != NULL) {
+ SECITEM_FreeItem(p12dcx->decitem.der, PR_TRUE);
+ }
+ if (p12dcx->decitem.friendlyName != NULL) {
+ SECITEM_FreeItem(p12dcx->decitem.friendlyName, PR_TRUE);
+ }
+ p12dcx->decitem.type = 0;
+ p12dcx->decitem.der = NULL;
+ p12dcx->decitem.friendlyName = NULL;
+ p12dcx->decitem.hasKey = PR_FALSE;
+ *ipp = NULL;
+ if (p12dcx->keyList == NULL) {
+ p12dcx->keyList = sec_pkcs12_get_key_bags(p12dcx->safeBags);
+ }
+
+
+ for (; p12dcx->iteration < p12dcx->safeBagCount; p12dcx->iteration++) {
+ bag = p12dcx->safeBags[p12dcx->iteration];
+ if(bag == NULL || bag->problem) {
+ continue;
+ }
+ p12dcx->decitem.type = SECOID_FindOIDTag(&(bag->safeBagType));
+ switch(p12dcx->decitem.type) {
+ case SEC_OID_PKCS12_V1_CERT_BAG_ID:
+ p12dcx->decitem.der = sec_pkcs12_get_der_cert(bag);
+ p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
+ p12dcx->decitem.hasKey = sec_pkcs12_bagHasKey(p12dcx, bag);
+ break;
+ case SEC_OID_PKCS12_V1_KEY_BAG_ID:
+ case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
+ p12dcx->decitem.friendlyName = sec_pkcs12_get_friendlyName(bag);
+ break;
+ default:
+ /* return these even though we don't expect them */
+ break;
+ case SEC_OID_UNKNOWN:
+ /* ignore these */
+ continue;
+ }
+ *ipp = &p12dcx->decitem;
+ p12dcx->iteration++;
+ break; /* end for() */
+ }
+
+ PORT_SetError(0); /* end-of-list is SECFailure with no PORT error */
+ return ((p12dcx->decitem.type == 0) ? SECFailure : SECSuccess);
+}
+
static SECStatus
sec_pkcs12_decoder_append_bag_to_context(SEC_PKCS12DecoderContext *p12dcx,
sec_PKCS12SafeBag *bag)
diff --git a/security/nss/lib/smime/smime.def b/security/nss/lib/smime/smime.def
index 3350cfa3b..ecb2dcff4 100644
--- a/security/nss/lib/smime/smime.def
+++ b/security/nss/lib/smime/smime.def
@@ -260,3 +260,10 @@ SEC_PKCS7EncodeItem;
;+ local:
;+ *;
;+};
+;+NSS_3.10 { # NSS 3.10 release
+;+ global:
+SEC_PKCS12DecoderIterateInit;
+SEC_PKCS12DecoderIterateNext;
+;+ local:
+;+ *;
+;+};
diff --git a/security/nss/tests/tools/tools.sh b/security/nss/tests/tools/tools.sh
index d4a16eec4..73d817366 100644
--- a/security/nss/tests/tools/tools.sh
+++ b/security/nss/tests/tools/tools.sh
@@ -118,6 +118,13 @@ tools_p12()
ret=$?
html_msg $ret 0 "Importing Alice's email cert & key (pk12util -i)"
check_tmpfile
+
+ echo "$SCRIPTNAME: Listing Alice's pk12 file -----------------"
+ echo "pk12util -l Alice.p12 -w ${R_PWFILE}"
+ pk12util -l Alice.p12 -w ${R_PWFILE} 2>&1
+ ret=$?
+ html_msg $ret 0 "Listing Alice's pk12 file (pk12util -l)"
+ check_tmpfile
}
############################## tools_sign ##############################