Bug#:280602 Added list option to pk12uti, test for it.

r=nelson@bolyard.com
This commit is contained in:
neil.williams%sun.com 2005-02-08 01:04:50 +00:00
parent e042c2f571
commit a7dcc795a8
5 changed files with 334 additions and 10 deletions

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -260,3 +260,10 @@ SEC_PKCS7EncodeItem;
;+ local:
;+ *;
;+};
;+NSS_3.10 { # NSS 3.10 release
;+ global:
SEC_PKCS12DecoderIterateInit;
SEC_PKCS12DecoderIterateNext;
;+ local:
;+ *;
;+};

View File

@ -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 ##############################