diff --git a/automation/abi-check/expected-report-libnss3.so.txt b/automation/abi-check/expected-report-libnss3.so.txt
index 9e127aee6d..a6dbb05bff 100644
--- a/automation/abi-check/expected-report-libnss3.so.txt
+++ b/automation/abi-check/expected-report-libnss3.so.txt
@@ -1,8 +1,11 @@
-2 Added functions:
+5 Added functions:
+ 'function SECOidTag HASH_GetHMACOidTagByHashOidTag(SECOidTag)' {HASH_GetHMACOidTagByHashOidTag@@NSS_3.65}
'function PK11Context* PK11_CreateContextByPrivKey(CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, SECKEYPrivateKey*, const SECItem*)' {PK11_CreateContextByPrivKey@@NSS_3.65}
'function PK11Context* PK11_CreateContextByPubKey(CK_MECHANISM_TYPE, CK_ATTRIBUTE_TYPE, SECKEYPublicKey*, const SECItem*, void*)' {PK11_CreateContextByPubKey@@NSS_3.65}
+ 'function SECKEYEncryptedPrivateKeyInfo* PK11_ExportEncryptedPrivKeyInfoV2(PK11SlotInfo*, SECOidTag, SECOidTag, SECOidTag, SECItem*, SECKEYPrivateKey*, int, void*)' {PK11_ExportEncryptedPrivKeyInfoV2@@NSS_3.65}
+ 'function SECKEYEncryptedPrivateKeyInfo* PK11_ExportEncryptedPrivateKeyInfoV2(PK11SlotInfo*, SECOidTag, SECOidTag, SECOidTag, SECItem*, CERTCertificate*, int, void*)' {PK11_ExportEncryptedPrivateKeyInfoV2@@NSS_3.65}
1 function with some indirect sub-type change:
diff --git a/cmd/lib/basicutil.h b/cmd/lib/basicutil.h
index de8c1b01e8..ba76b1798f 100644
--- a/cmd/lib/basicutil.h
+++ b/cmd/lib/basicutil.h
@@ -54,10 +54,8 @@ extern void SECU_PrintAsHex(FILE *out, const SECItem *i, const char *m,
/* dump a buffer in hex and ASCII */
extern void SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len);
-#ifdef HAVE_EPV_TEMPLATE
/* Dump contents of private key */
extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level);
-#endif
/* Init PKCS11 stuff */
extern SECStatus SECU_PKCS11Init(PRBool readOnly);
diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
index 7fb041ec7d..d9270ed927 100644
--- a/cmd/lib/secutil.c
+++ b/cmd/lib/secutil.c
@@ -562,20 +562,110 @@ SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii,
#define INDENT_MULT 4
+/*
+ * remove the tag and length and just leave the bare BER data
+ */
SECStatus
SECU_StripTagAndLength(SECItem *i)
{
unsigned int start;
+ PRBool isIndefinite;
if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
+ PORT_SetError(SEC_ERROR_BAD_DER);
return SECFailure;
}
+ isIndefinite = (i->data[1] == 0x80);
start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
if (i->len < start) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
return SECFailure;
}
i->data += start;
i->len -= start;
+ /* we are using indefinite encoding, drop the trailing zero */
+ if (isIndefinite) {
+ if (i->len <= 1) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ /* verify tags are zero */
+ if ((i->data[i->len - 1] != 0) || (i->data[i->len - 2] != 0)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ i->len -= 2;
+ }
+
+ return SECSuccess;
+}
+
+/*
+ * Create a new SECItem which points to the current BER tag and length with
+ * all it's data. For indefinite encoding, this will also include the trailing
+ * indefinite markers
+ * The 'in' item is advanced to point to the next BER tag.
+ * You don't want to use this in an actual BER/DER parser as NSS already
+ * has 3 to choose from)
+ */
+SECStatus
+SECU_ExtractBERAndStep(SECItem *in, SECItem *out)
+{
+ if (!in || !in->data || in->len < 2) { /* must be at least tag and length */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ *out = *in;
+
+ /* first handle indefinite encoding */
+ if (out->data[1] == 0x80) {
+ SECItem this = *out;
+ SECItem next;
+ this.data += 2;
+ this.len -= 2;
+ out->len = 2;
+ /* walk through all the entries until we find the '0' */
+ while ((this.len >= 2) && (this.data[0] != 0)) {
+ SECStatus rv = SECU_ExtractBERAndStep(&this, &next);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ out->len += next.len;
+ }
+ if ((this.len < 2) || ((this.data[0] != 0) && (this.data[1] != 0))) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ out->len += 2; /* include the trailing zeros */
+ in->data += out->len;
+ in->len -= out->len;
+ return SECSuccess;
+ }
+
+ /* now handle normal DER encoding */
+ if (out->data[1] & 0x80) {
+ unsigned int i;
+ unsigned int lenlen = out->data[1] & 0x7f;
+ unsigned int len = 0;
+ if (lenlen > sizeof out->len) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ for (i = 0; i < lenlen; i++) {
+ len = (len << 8) | out->data[2 + i];
+ }
+ out->len = len + lenlen + 2;
+ } else {
+ out->len = out->data[1] + 2;
+ }
+ if (out->len > in->len) {
+ /* we've ran into a truncated file */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ in->data += out->len;
+ in->len -= out->len;
return SECSuccess;
}
@@ -786,26 +876,10 @@ SECU_PrintSet(FILE *out, const SECItem *t, const char *m, int level)
fprintf(out, "%s{\n", label); /* } */
while (my.len >= 2) {
- SECItem tmp = my;
-
- if (tmp.data[1] & 0x80) {
- unsigned int i;
- unsigned int lenlen = tmp.data[1] & 0x7f;
- if (lenlen > sizeof tmp.len)
- break;
- tmp.len = 0;
- for (i = 0; i < lenlen; i++) {
- tmp.len = (tmp.len << 8) | tmp.data[2 + i];
- }
- tmp.len += lenlen + 2;
- } else {
- tmp.len = tmp.data[1] + 2;
- }
- if (tmp.len > my.len) {
- tmp.len = my.len;
+ SECItem tmp;
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &tmp)) {
+ break;
}
- my.data += tmp.len;
- my.len -= tmp.len;
SECU_PrintAny(out, &tmp, NULL, level + 1);
}
SECU_Indent(out, level);
@@ -906,12 +980,14 @@ SECU_PrintEncodedInteger(FILE *out, const SECItem *i, const char *m, int level)
}
/* Print a DER encoded OID */
-void
+SECOidTag
SECU_PrintEncodedObjectID(FILE *out, const SECItem *i, const char *m, int level)
{
SECItem my = *i;
+ SECOidTag tag = SEC_OID_UNKNOWN;
if (SECSuccess == SECU_StripTagAndLength(&my))
- SECU_PrintObjectID(out, &my, m, level);
+ tag = SECU_PrintObjectID(out, &my, m, level);
+ return tag;
}
static void
@@ -2455,7 +2531,6 @@ SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m, int level)
return rv;
}
-#ifdef HAVE_EPV_TEMPLATE
int
SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
{
@@ -2482,7 +2557,6 @@ SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level)
PORT_FreeArena(arena, PR_TRUE);
return rv;
}
-#endif
int
SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
@@ -2545,16 +2619,26 @@ SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
*/
/* forward declaration */
+typedef enum {
+ secuPKCS7Unknown = 0,
+ secuPKCS7PKCS12AuthSafe,
+ secuPKCS7PKCS12Safe
+} secuPKCS7State;
+
static int
-secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int);
+secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, secuPKCS7State,
+ const char *, int);
+static int
+secu_PrintDERPKCS7ContentInfo(FILE *, SECItem *, secuPKCS7State,
+ const char *, int);
/*
** secu_PrintPKCS7EncContent
** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it)
*/
-static void
+static int
secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src,
- char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
if (src->contentTypeTag == NULL)
src->contentTypeTag = SECOID_FindOID(&(src->contentType));
@@ -2569,6 +2653,7 @@ secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src,
"Content Encryption Algorithm", level + 1);
SECU_PrintAsHex(out, &(src->encContent),
"Encrypted Content", level + 1);
+ return 0;
}
/*
@@ -2576,8 +2661,8 @@ secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src,
** Prints a PKCS7RecipientInfo type
*/
static void
-secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m,
- int level)
+secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info,
+ const char *m, int level)
{
SECU_Indent(out, level);
fprintf(out, "%s:\n", m);
@@ -2599,7 +2684,8 @@ secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m,
** Prints a PKCS7SingerInfo type
*/
static void
-secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level)
+secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info,
+ const char *m, int level)
{
SEC_PKCS7Attribute *attr;
int iv;
@@ -2691,7 +2777,7 @@ SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
*/
static int
secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
- const char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
SECAlgorithmID *digAlg; /* digest algorithms */
SECItem *aCert; /* certificate */
@@ -2717,7 +2803,7 @@ secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
/* Now for the content */
rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo),
- "Content Information", level + 1);
+ state, "Content Information", level + 1);
if (rv != 0)
return rv;
@@ -2772,9 +2858,9 @@ secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src,
** secu_PrintPKCS7Enveloped
** Pretty print a PKCS7 enveloped data type (up to version 1).
*/
-static void
+static int
secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
- const char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */
int iv;
@@ -2795,8 +2881,8 @@ secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
}
}
- secu_PrintPKCS7EncContent(out, &src->encContentInfo,
- "Encrypted Content Information", level + 1);
+ return secu_PrintPKCS7EncContent(out, &src->encContentInfo, state,
+ "Encrypted Content Information", level + 1);
}
/*
@@ -2806,7 +2892,8 @@ secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src,
static int
secu_PrintPKCS7SignedAndEnveloped(FILE *out,
SEC_PKCS7SignedAndEnvelopedData *src,
- const char *m, int level)
+ secuPKCS7State state, const char *m,
+ int level)
{
SECAlgorithmID *digAlg; /* pointer for digest algorithms */
SECItem *aCert; /* pointer for certificate */
@@ -2842,8 +2929,10 @@ secu_PrintPKCS7SignedAndEnveloped(FILE *out,
}
}
- secu_PrintPKCS7EncContent(out, &src->encContentInfo,
- "Encrypted Content Information", level + 1);
+ rv = secu_PrintPKCS7EncContent(out, &src->encContentInfo, state,
+ "Encrypted Content Information", level + 1);
+ if (rv)
+ return rv;
/* Parse and list certificates (if any) */
if (src->rawCerts != NULL) {
@@ -2920,25 +3009,25 @@ SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level)
** secu_PrintPKCS7Encrypted
** Pretty print a PKCS7 encrypted data type (up to version 1).
*/
-static void
+static int
secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src,
- const char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
SECU_Indent(out, level);
fprintf(out, "%s:\n", m);
SECU_PrintInteger(out, &(src->version), "Version", level + 1);
- secu_PrintPKCS7EncContent(out, &src->encContentInfo,
- "Encrypted Content Information", level + 1);
+ return secu_PrintPKCS7EncContent(out, &src->encContentInfo, state,
+ "Encrypted Content Information", level + 1);
}
/*
** secu_PrintPKCS7Digested
** Pretty print a PKCS7 digested data type (up to version 1).
*/
-static void
+static int
secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
- const char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
SECU_Indent(out, level);
fprintf(out, "%s:\n", m);
@@ -2946,9 +3035,257 @@ secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm",
level + 1);
- secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information",
- level + 1);
+ secu_PrintPKCS7ContentInfo(out, &src->contentInfo, state,
+ "Content Information", level + 1);
SECU_PrintAsHex(out, &src->digest, "Digest", level + 1);
+ return 0;
+}
+
+static int
+secu_PrintPKCS12Attributes(FILE *out, SECItem *item, const char *m, int level)
+{
+ SECItem my = *item;
+ SECItem attribute;
+ SECItem attributeID;
+ SECItem attributeValues;
+
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SET)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ SECU_Indent(out, level);
+ fprintf(out, "%s:\n", m);
+ level++;
+
+ while (my.len) {
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &attribute)) {
+ return SECFailure;
+ }
+ if ((attribute.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&attribute)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ /* attribute ID */
+ if (SECSuccess != SECU_ExtractBERAndStep(&attribute, &attributeID)) {
+ return SECFailure;
+ }
+ if ((attributeID.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OBJECT_ID) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ SECU_PrintEncodedObjectID(out, &attributeID, "Attribute ID", level);
+
+ /* attribute values */
+ if (!attribute.len) { /* skip if there aren't any */
+ continue;
+ }
+ if (SECSuccess != SECU_ExtractBERAndStep(&attribute, &attributeValues)) {
+ return SECFailure;
+ }
+ if (SECSuccess != SECU_StripTagAndLength(&attributeValues)) {
+ return SECFailure;
+ }
+ while (attributeValues.len) {
+ SECItem tmp;
+ if (SECSuccess != SECU_ExtractBERAndStep(&attributeValues, &tmp)) {
+ return SECFailure;
+ }
+ SECU_PrintAny(out, &tmp, NULL, level + 1);
+ }
+ }
+ return SECSuccess;
+}
+
+static int
+secu_PrintPKCS12Bag(FILE *out, SECItem *item, const char *desc, int level)
+{
+ SECItem my = *item;
+ SECItem bagID;
+ SECItem bagValue;
+ SECItem bagAttributes;
+ SECOidTag bagTag;
+ SECStatus rv;
+ int i;
+ char *m;
+
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ /* bagId BAG-TYPE.&id ({PKCS12BagSet}) */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagID)) {
+ return SECFailure;
+ }
+ if ((bagID.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OBJECT_ID) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ m = PR_smprintf("%s ID", desc);
+ bagTag = SECU_PrintEncodedObjectID(out, &bagID, m ? m : "Bag ID", level);
+ if (m)
+ PR_smprintf_free(m);
+
+ /* bagValue [0] EXPLICIT BAG-TYPE.&type({PKCS12BagSet}{@bagID}) */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagValue)) {
+ return SECFailure;
+ }
+ if ((bagValue.data[0] & (SEC_ASN1_CLASS_MASK | SEC_ASN1_TAGNUM_MASK)) !=
+ (SEC_ASN1_CONTEXT_SPECIFIC | 0)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ if (SECSuccess != SECU_StripTagAndLength(&bagValue)) {
+ return SECFailure;
+ }
+
+ rv = SECSuccess;
+ switch (bagTag) {
+ case SEC_OID_PKCS12_V1_KEY_BAG_ID:
+ /* Future we need to print out raw private keys. Not a priority since
+ * p12util can't create files with unencrypted private keys, but
+ * some tools can and do */
+ SECU_PrintAny(out, &bagValue, "Private Key", level);
+ break;
+ case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
+ rv = SECU_PrintPrivateKey(out, &bagValue,
+ "Encrypted Private Key", level);
+ break;
+ case SEC_OID_PKCS12_V1_CERT_BAG_ID:
+ rv = secu_PrintPKCS12Bag(out, &bagValue, "Certificate Bag", level + 1);
+ break;
+ case SEC_OID_PKCS12_V1_CRL_BAG_ID:
+ rv = secu_PrintPKCS12Bag(out, &bagValue, "Crl Bag", level + 1);
+ break;
+ case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
+ rv = secu_PrintPKCS12Bag(out, &bagValue, "Secret Bag", level + 1);
+ break;
+ /* from recursive call from CRL and certificate Bag */
+ case SEC_OID_PKCS9_X509_CRL:
+ case SEC_OID_PKCS9_X509_CERT:
+ case SEC_OID_PKCS9_SDSI_CERT:
+ /* unwrap the octect string */
+ rv = SECU_StripTagAndLength(&bagValue);
+ if (rv != SECSuccess) {
+ break;
+ }
+ /* fall through */
+ case SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID:
+ case SEC_OID_PKCS12_X509_CERT_CRL_BAG:
+ case SEC_OID_PKCS12_SDSI_CERT_BAG:
+ if (strcmp(desc, "Crl Bag") == 0) {
+ rv = SECU_PrintSignedData(out, &bagValue, NULL, level + 1,
+ (SECU_PPFunc)SECU_PrintCrl);
+ } else {
+ rv = SECU_PrintSignedData(out, &bagValue, NULL, level + 1,
+ (SECU_PPFunc)SECU_PrintCertificate);
+ }
+ break;
+ case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
+ for (i = 1; my.len; i++) {
+ SECItem nextBag;
+ rv = SECU_ExtractBERAndStep(&bagValue, &nextBag);
+ if (rv != SECSuccess) {
+ break;
+ }
+ m = PR_smprintf("Nested Bag %d", i);
+ rv = secu_PrintPKCS12Bag(out, &nextBag,
+ m ? m : "Nested Bag", level + 1);
+ if (m)
+ PR_smprintf_free(m);
+ if (rv != SECSuccess) {
+ break;
+ }
+ }
+ break;
+ default:
+ m = PR_smprintf("%s Value", desc);
+ SECU_PrintAny(out, &bagValue, m ? m : "Bag Value", level);
+ if (m)
+ PR_smprintf_free(m);
+ }
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ /* bagAttributes SET OF PKCS12Attributes OPTIONAL */
+ if (my.len &&
+ (my.data[0] == (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SET))) {
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &bagAttributes)) {
+ return SECFailure;
+ }
+ m = PR_smprintf("%s Attributes", desc);
+ rv = secu_PrintPKCS12Attributes(out, &bagAttributes,
+ m ? m : "Bag Attributes", level);
+ if (m)
+ PR_smprintf_free(m);
+ }
+ return rv;
+}
+
+static int
+secu_PrintPKCS7Data(FILE *out, SECItem *item, secuPKCS7State state,
+ const char *desc, int level)
+{
+ SECItem my = *item;
+ SECItem nextbag;
+ int i;
+ SECStatus rv;
+
+ /* walk down each safe */
+ switch (state) {
+ case secuPKCS7PKCS12AuthSafe:
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ for (i = 1; my.len; i++) {
+ char *m;
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &nextbag)) {
+ return SECFailure;
+ }
+ m = PR_smprintf("Safe %d", i);
+ rv = secu_PrintDERPKCS7ContentInfo(out, &nextbag,
+ secuPKCS7PKCS12Safe,
+ m ? m : "Safe", level);
+ if (m)
+ PR_smprintf_free(m);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+ case secuPKCS7PKCS12Safe:
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ for (i = 1; my.len; i++) {
+ char *m;
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &nextbag)) {
+ return SECFailure;
+ }
+ m = PR_smprintf("Bag %d", i);
+ rv = secu_PrintPKCS12Bag(out, &nextbag,
+ m ? m : "Bag", level);
+ if (m)
+ PR_smprintf_free(m);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+ case secuPKCS7Unknown:
+ SECU_PrintAsHex(out, item, desc, level);
+ break;
+ }
+ return SECSuccess;
}
/*
@@ -2958,7 +3295,7 @@ secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src,
*/
static int
secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
- char *m, int level)
+ secuPKCS7State state, const char *m, int level)
{
const char *desc;
SECOidTag kind;
@@ -2973,7 +3310,7 @@ secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
if (src->contentTypeTag == NULL) {
desc = "Unknown";
- kind = SEC_OID_PKCS7_DATA;
+ kind = SEC_OID_UNKNOWN;
} else {
desc = src->contentTypeTag->desc;
kind = src->contentTypeTag->offset;
@@ -2991,25 +3328,33 @@ secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
rv = 0;
switch (kind) {
case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */
- rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level);
+ rv = secu_PrintPKCS7Signed(out, src->content.signedData,
+ state, desc, level);
break;
case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */
- secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level);
+ rv = secu_PrintPKCS7Enveloped(out, src->content.envelopedData,
+ state, desc, level);
break;
case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */
rv = secu_PrintPKCS7SignedAndEnveloped(out,
src->content.signedAndEnvelopedData,
- desc, level);
+ state, desc, level);
break;
case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */
- secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level);
+ rv = secu_PrintPKCS7Digested(out, src->content.digestedData,
+ state, desc, level);
break;
case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */
- secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level);
+ rv = secu_PrintPKCS7Encrypted(out, src->content.encryptedData,
+ state, desc, level);
+ break;
+
+ case SEC_OID_PKCS7_DATA:
+ rv = secu_PrintPKCS7Data(out, src->content.data, state, desc, level);
break;
default:
@@ -3024,8 +3369,9 @@ secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src,
** SECU_PrintPKCS7ContentInfo
** Decode and print any major PKCS7 data type (up to version 1).
*/
-int
-SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
+static int
+secu_PrintDERPKCS7ContentInfo(FILE *out, SECItem *der, secuPKCS7State state,
+ const char *m, int level)
{
SEC_PKCS7ContentInfo *cinfo;
int rv;
@@ -3033,7 +3379,7 @@ SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (cinfo != NULL) {
/* Send it to recursive parsing and printing module */
- rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level);
+ rv = secu_PrintPKCS7ContentInfo(out, cinfo, state, m, level);
SEC_PKCS7DestroyContentInfo(cinfo);
} else {
rv = -1;
@@ -3042,6 +3388,12 @@ SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
return rv;
}
+int
+SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level)
+{
+ return secu_PrintDERPKCS7ContentInfo(out, der, secuPKCS7Unknown, m, level);
+}
+
/*
** End of PKCS7 functions
*/
@@ -4214,3 +4566,169 @@ readPSK(const char *arg, SECItem *psk, SECItem *label)
PORT_Free(str);
return rv;
}
+
+static SECStatus
+secu_PrintPKCS12DigestInfo(FILE *out, const SECItem *t, char *m, int level)
+{
+ SECItem my = *t;
+ SECItem rawDigestAlgID;
+ SECItem digestData;
+ SECStatus rv;
+ PLArenaPool *arena;
+ SECAlgorithmID digestAlgID;
+ char *mAlgID = NULL;
+ char *mDigest = NULL;
+
+ /* strip the outer sequence */
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ /* get the algorithm ID */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &rawDigestAlgID)) {
+ return SECFailure;
+ }
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ return SECFailure;
+ }
+#define DIGEST_ALGID_STRING "Digest Algorithm ID"
+ if (m)
+ mAlgID = PR_smprintf("%s " DIGEST_ALGID_STRING, m);
+ rv = SEC_QuickDERDecodeItem(arena, &digestAlgID,
+ SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
+ &rawDigestAlgID);
+ if (rv == SECSuccess) {
+ SECU_PrintAlgorithmID(out, &digestAlgID,
+ mAlgID ? mAlgID : DIGEST_ALGID_STRING, level);
+ }
+ if (mAlgID)
+ PR_smprintf_free(mAlgID);
+ PORT_FreeArena(arena, PR_FALSE);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+
+ /* get the mac data */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &digestData)) {
+ return SECFailure;
+ }
+ if ((digestData.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OCTET_STRING) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+#define DIGEST_STRING "Digest"
+ if (m)
+ mDigest = PR_smprintf("%s " DIGEST_STRING, m);
+ secu_PrintOctetString(out, &digestData,
+ mDigest ? mDigest : DIGEST_STRING, level);
+ if (mDigest)
+ PR_smprintf_free(mDigest);
+ return SECSuccess;
+}
+
+static SECStatus
+secu_PrintPKCS12MacData(FILE *out, const SECItem *t, char *m, int level)
+{
+ SECItem my = *t;
+ SECItem hash;
+ SECItem salt;
+
+ if (m) {
+ SECU_Indent(out, level);
+ fprintf(out, "%s: \n", m);
+ level++;
+ }
+
+ /* strip the outer sequence */
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &hash)) {
+ return SECFailure;
+ }
+ if (SECSuccess != secu_PrintPKCS12DigestInfo(out, &hash, "Mac", level)) {
+ return SECFailure;
+ }
+
+ /* handle the salt */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &salt)) {
+ return SECFailure;
+ ;
+ }
+ if ((salt.data[0] & SEC_ASN1_TAGNUM_MASK) != SEC_ASN1_OCTET_STRING) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ secu_PrintOctetString(out, &salt, "Mac Salt", level);
+
+ if (my.len &&
+ ((my.data[0] & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_INTEGER)) {
+ SECItem iterator;
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &iterator)) {
+ return SECFailure;
+ }
+ SECU_PrintEncodedInteger(out, &iterator, "Iterations", level);
+ }
+ return SECSuccess;
+}
+
+SECStatus
+SECU_PrintPKCS12(FILE *out, const SECItem *t, char *m, int level)
+{
+ SECItem my = *t;
+ SECItem authSafe;
+ SECItem macData;
+
+ SECU_Indent(out, level);
+ fprintf(out, "%s:\n", m);
+ level++;
+
+ /* strip the outer sequence */
+ if ((my.data[0] != (SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE)) ||
+ SECSuccess != SECU_StripTagAndLength(&my)) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ /* print and remove the optional version number */
+ if (my.len && ((my.data[0] & SEC_ASN1_TAGNUM_MASK) == SEC_ASN1_INTEGER)) {
+ SECItem version;
+
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &version)) {
+ return SECFailure;
+ }
+ SECU_PrintEncodedInteger(out, &version, "Version", level);
+ }
+
+ /* print the authSafe */
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &authSafe)) {
+ return SECFailure;
+ }
+ if (SECSuccess != secu_PrintDERPKCS7ContentInfo(out, &authSafe,
+ secuPKCS7PKCS12AuthSafe,
+ "AuthSafe", level)) {
+ return SECFailure;
+ }
+
+ /* print the mac data (optional) */
+ if (!my.len) {
+ return SECSuccess;
+ }
+ if (SECSuccess != SECU_ExtractBERAndStep(&my, &macData)) {
+ return SECFailure;
+ }
+ if (SECSuccess != secu_PrintPKCS12MacData(out, &macData,
+ "Mac Data", level)) {
+ return SECFailure;
+ }
+
+ if (my.len) {
+ fprintf(out, "Unknown extra data found \n");
+ }
+ return SECSuccess;
+}
diff --git a/cmd/lib/secutil.h b/cmd/lib/secutil.h
index 0bdfa95089..b5f86ad061 100644
--- a/cmd/lib/secutil.h
+++ b/cmd/lib/secutil.h
@@ -26,6 +26,7 @@
#define SEC_CT_CERTIFICATE_REQUEST "certificate-request"
#define SEC_CT_CERTIFICATE_ID "certificate-identity"
#define SEC_CT_PKCS7 "pkcs7"
+#define SEC_CT_PKCS12 "pkcs12"
#define SEC_CT_CRL "crl"
#define SEC_CT_NAME "name"
@@ -235,10 +236,8 @@ extern void SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m,
extern int SECU_PrintSubjectPublicKeyInfo(FILE *out, SECItem *der, char *m,
int level);
-#ifdef HAVE_EPV_TEMPLATE
/* Dump contents of private key */
extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level);
-#endif
/* Dump contents of an RSA public key */
extern void SECU_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level);
@@ -253,7 +252,8 @@ extern int SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m,
/* Pretty-print any PKCS7 thing */
extern int SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m,
int level);
-
+/* Pretty-print a pkcs12 file */
+extern SECStatus SECU_PrintPKCS12(FILE *out, const SECItem *der, char *m, int level);
/* Init PKCS11 stuff */
extern SECStatus SECU_PKCS11Init(PRBool readOnly);
diff --git a/cmd/pk12util/pk12util.c b/cmd/pk12util/pk12util.c
index 794f17b39c..b0c4ffd7bf 100644
--- a/cmd/pk12util/pk12util.c
+++ b/cmd/pk12util/pk12util.c
@@ -16,6 +16,7 @@
#include "nss.h"
#include "secport.h"
#include "secpkcs5.h"
+#include "sechash.h"
#include "certdb.h"
#define PKCS12_IN_BUFFER_SIZE 200
@@ -43,7 +44,7 @@ Usage()
FPS "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n",
progName);
- FPS "\t\t [-c key_cipher] [-C cert_cipher]\n"
+ FPS "\t\t [-c key_cipher] [-C cert_cipher] [-M mac_alg]\n"
"\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n");
FPS "\t\t [-k slotpwfile | -K slotpw]\n"
"\t\t [-w p12filepwfile | -W p12filepw]\n");
@@ -625,7 +626,7 @@ p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
void
P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
- SECOidTag cipher, SECOidTag certCipher,
+ SECOidTag cipher, SECOidTag certCipher, SECOidTag hash,
secuPWData *slotPw, secuPWData *p12FilePw)
{
SEC_PKCS12ExportContext *p12ecx = NULL;
@@ -690,7 +691,7 @@ P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
goto loser;
}
- if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, SEC_OID_SHA1) !=
+ if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, hash) !=
SECSuccess) {
SECU_PrintError(progName, "PKCS12 add password integrity failed");
pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
@@ -722,8 +723,8 @@ P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
}
if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
- CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, cipher) !=
- SECSuccess) {
+ CERT_GetDefaultCertDB(), keySafe, NULL,
+ PR_TRUE, pwitem, cipher) != SECSuccess) {
SECU_PrintError(progName, "add cert and key failed");
pk12uErrno = PK12UERR_ADDCERTKEY;
goto loser;
@@ -857,6 +858,27 @@ P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
return rv;
}
+SECOidTag
+PKCS12U_FindTagFromString(char *cipherString)
+{
+ SECOidTag tag;
+ SECOidData *oid;
+
+ /* future enhancement: accept dotted oid spec? */
+
+ for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
+ /* only interested in oids that we actually understand */
+ if (oid->mechanism == CKM_INVALID_MECHANISM) {
+ continue;
+ }
+ if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
+ continue;
+ }
+ return tag;
+ }
+ return SEC_OID_UNKNOWN;
+}
+
/*
* use the oid table description to map a user input string to a particular
* oid.
@@ -865,46 +887,55 @@ SECOidTag
PKCS12U_MapCipherFromString(char *cipherString, int keyLen)
{
SECOidTag tag;
- SECOidData *oid;
SECOidTag cipher;
- /* future enhancement: accept dotted oid spec? */
-
/* future enhancement: provide 'friendlier' typed in names for
* pbe mechanisms.
*/
/* look for the oid tag by Description */
+ tag = PKCS12U_FindTagFromString(cipherString);
+ if (tag == SEC_OID_UNKNOWN) {
+ return tag;
+ }
+
cipher = SEC_OID_UNKNOWN;
- for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
- /* only interested in oids that we actually understand */
- if (oid->mechanism == CKM_INVALID_MECHANISM) {
- continue;
- }
- if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
- continue;
- }
- /* we found a match... get the PBE version of this
- * cipher... */
- if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
- cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
- /* no eqivalent PKCS5/PKCS12 cipher, use the raw
- * encryption tag we got and pass it directly in,
- * pkcs12 will use the pkcsv5 mechanism */
- if (cipher == SEC_OID_PKCS5_PBES2) {
- cipher = tag;
- } else if (cipher == SEC_OID_PKCS5_PBMAC1) {
- /* make sure we have not macing ciphers here */
- cipher = SEC_OID_UNKNOWN;
- }
- } else {
+ /* we found a match... get the PBE version of this
+ * cipher... */
+ if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
+ cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
+ /* no eqivalent PKCS5/PKCS12 cipher, use the raw
+ * encryption tag we got and pass it directly in,
+ * pkcs12 will use the pkcsv5 mechanism */
+ if (cipher == SEC_OID_PKCS5_PBES2) {
cipher = tag;
+ } else if (cipher == SEC_OID_PKCS5_PBMAC1) {
+ /* make sure we have not macing ciphers here */
+ cipher = SEC_OID_UNKNOWN;
}
- break;
+ } else {
+ cipher = tag;
}
return cipher;
}
+SECOidTag
+PKCS12U_MapHashFromString(char *hashString)
+{
+ SECOidTag hashAlg;
+
+ /* look for the oid tag by Description */
+ hashAlg = PKCS12U_FindTagFromString(hashString);
+ if (hashAlg == SEC_OID_UNKNOWN) {
+ return hashAlg;
+ }
+ /* make sure it's a hashing oid */
+ if (HASH_GetHashTypeByOidTag(hashAlg) == HASH_AlgNULL) {
+ return SEC_OID_UNKNOWN;
+ }
+ return hashAlg;
+}
+
static void
p12u_EnableAllCiphers()
{
@@ -917,7 +948,7 @@ p12u_EnableAllCiphers()
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128, 1);
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192, 1);
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256, 1);
- SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
+ SEC_PKCS12SetPreferredCipher(PKCS12_AES_CBC_256, 1);
}
static PRUintn
@@ -963,7 +994,8 @@ enum {
opt_Cipher,
opt_CertCipher,
opt_KeyLength,
- opt_CertKeyLength
+ opt_CertKeyLength,
+ opt_Mac
};
static secuCommandFlag pk12util_options[] =
@@ -984,7 +1016,8 @@ static secuCommandFlag pk12util_options[] =
{ /* opt_Cipher */ 'c', PR_TRUE, 0, PR_FALSE },
{ /* opt_CertCipher */ 'C', PR_TRUE, 0, PR_FALSE },
{ /* opt_KeyLength */ 'm', PR_TRUE, 0, PR_FALSE, "key_len" },
- { /* opt_CertKeyLength */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" }
+ { /* opt_CertKeyLength */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" },
+ { /* opt_Mac */ 'M', PR_TRUE, 0, PR_FALSE, PR_FALSE }
};
int
@@ -998,9 +1031,9 @@ main(int argc, char **argv)
char *export_file = NULL;
char *dbprefix = "";
SECStatus rv;
- SECOidTag cipher =
- SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
- SECOidTag certCipher;
+ SECOidTag cipher = SEC_OID_AES_256_CBC;
+ SECOidTag hash = SEC_OID_SHA256;
+ SECOidTag certCipher = SEC_OID_AES_128_CBC;
int keyLen = 0;
int certKeyLen = 0;
secuCommand pk12util;
@@ -1114,7 +1147,6 @@ main(int argc, char **argv)
}
}
- certCipher = PK11_IsFIPS() ? SEC_OID_UNKNOWN : SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
if (pk12util.options[opt_CertCipher].activated) {
char *cipherString = pk12util.options[opt_CertCipher].arg;
@@ -1132,6 +1164,18 @@ main(int argc, char **argv)
}
}
}
+ if (pk12util.options[opt_Mac].activated) {
+ char *hashString = pk12util.options[opt_Mac].arg;
+
+ hash = PKCS12U_MapHashFromString(hashString);
+ /* We don't support creating Mac-less pkcs 12 files */
+ if (hash == SEC_OID_UNKNOWN) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ SECU_PrintError(progName, "Algorithm: \"%s\"", hashString);
+ pk12uErrno = PK12UERR_INVALIDALGORITHM;
+ goto done;
+ }
+ }
if (pk12util.options[opt_Import].activated) {
P12U_ImportPKCS12Object(import_file, slot, &slotPw, &p12FilePw);
@@ -1139,7 +1183,7 @@ main(int argc, char **argv)
} else if (pk12util.options[opt_Export].activated) {
P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
export_file, slot, cipher, certCipher,
- &slotPw, &p12FilePw);
+ hash, &slotPw, &p12FilePw);
} else if (pk12util.options[opt_List].activated) {
P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
diff --git a/cmd/pp/pp.c b/cmd/pp/pp.c
index d6e276834c..b89b9ad0d9 100644
--- a/cmd/pp/pp.c
+++ b/cmd/pp/pp.c
@@ -27,14 +27,13 @@ Usage(char *progName)
progName);
fprintf(stderr, "Pretty prints a file containing ASN.1 data in DER or ascii format.\n");
fprintf(stderr, "%-14s Specify input and display type:", "-t type");
-#ifdef HAVE_EPV_TEMPLATE
fprintf(stderr, " %s (sk),", SEC_CT_PRIVATE_KEY);
-#endif
fprintf(stderr, "\n");
fprintf(stderr, "%-14s %s (pk), %s (c), %s (cr),\n", "", SEC_CT_PUBLIC_KEY,
SEC_CT_CERTIFICATE, SEC_CT_CERTIFICATE_REQUEST);
- fprintf(stderr, "%-14s %s (ci), %s (p7), %s or %s (n).\n", "", SEC_CT_CERTIFICATE_ID,
- SEC_CT_PKCS7, SEC_CT_CRL, SEC_CT_NAME);
+ fprintf(stderr, "%-14s %s (ci), %s (p7), %s (p12), %s or %s (n).\n", "",
+ SEC_CT_CERTIFICATE_ID, SEC_CT_PKCS7, SEC_CT_PKCS12,
+ SEC_CT_CRL, SEC_CT_NAME);
fprintf(stderr, "%-14s (Use either the long type name or the shortcut.)\n", "");
fprintf(stderr, "%-14s Input is in ascii encoded form (RFC1113)\n",
"-a");
@@ -159,11 +158,9 @@ main(int argc, char **argv)
SECU_PrintCertificateRequest);
} else if (PORT_Strcmp(typeTag, SEC_CT_CRL) == 0) {
rv = SECU_PrintSignedData(outFile, &data, "CRL", 0, SECU_PrintCrl);
-#ifdef HAVE_EPV_TEMPLATE
} else if (PORT_Strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0 ||
PORT_Strcmp(typeTag, "sk") == 0) {
rv = SECU_PrintPrivateKey(outFile, &data, "Private Key", 0);
-#endif
} else if (PORT_Strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0 ||
PORT_Strcmp(typeTag, "pk") == 0) {
rv = SECU_PrintSubjectPublicKeyInfo(outFile, &data, "Public Key", 0);
@@ -174,6 +171,9 @@ main(int argc, char **argv)
} else if (PORT_Strcmp(typeTag, SEC_CT_NAME) == 0 ||
PORT_Strcmp(typeTag, "n") == 0) {
rv = SECU_PrintDERName(outFile, &data, "Name", 0);
+ } else if (PORT_Strcmp(typeTag, SEC_CT_PKCS12) == 0 ||
+ PORT_Strcmp(typeTag, "p12") == 0) {
+ rv = SECU_PrintPKCS12(outFile, &data, "PKCS #12 File", 0);
} else {
fprintf(stderr, "%s: don't know how to print out '%s' files\n",
progName, typeTag);
diff --git a/doc/pk12util.xml b/doc/pk12util.xml
index 1bd218d147..0b68beb7ff 100644
--- a/doc/pk12util.xml
+++ b/doc/pk12util.xml
@@ -28,11 +28,17 @@
pk12util
-i p12File|-l p12File|-o p12File
+ -c keyCipher
+ -C certCipher
-d [sql:]directory
-h tokenname
+ -m | --key-len keyLength
+ -M hashAlg
+ -n certname
-P dbprefix
-r
-v
+ --cert-key-len certKeyLength
-k slotPasswordFile|-K slotPassword
-w p12filePasswordFile|-W p12filePassword
@@ -107,6 +113,12 @@
Specify the desired length of the symmetric key to be used to encrypt the private key.
+
+ -M hashAlg
+ Specify the hash algorithm used in the pkcs #12 mac. This algorithm also specifies the HMAC used in the prf when using pkcs #5 v2.
+
+
+
--cert-key-len certKeyLength
Specify the desired length of the symmetric key to be used to encrypt the certificates and other meta-data.
diff --git a/doc/pp.xml b/doc/pp.xml
index 24efdf876b..8b42367218 100644
--- a/doc/pp.xml
+++ b/doc/pp.xml
@@ -40,7 +40,7 @@
Description
pp pretty-prints private and public key, certificate, certificate-request,
- pkcs7 or crl files
+ pkcs7, pkcs12 or crl files
@@ -53,7 +53,7 @@
type
- specify the input, one of {private-key | public-key | certificate | certificate-request | pkcs7 | crl}
+ specify the input, one of {private-key | public-key | certificate | certificate-request | pkcs7 | pkcs12 | crl | name}
diff --git a/lib/nss/nss.def b/lib/nss/nss.def
index a79e56c714..46bd41a60f 100644
--- a/lib/nss/nss.def
+++ b/lib/nss/nss.def
@@ -1224,6 +1224,9 @@ PK11_HPKE_ImportContext;
;+ global:
PK11_CreateContextByPubKey;
PK11_CreateContextByPrivKey;
+PK11_ExportEncryptedPrivKeyInfoV2;
+PK11_ExportEncryptedPrivateKeyInfoV2;
+HASH_GetHMACOidTagByHashOidTag;
;+ local:
;+ *;
;+};
diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c
index cada965c61..310d656627 100644
--- a/lib/pk11wrap/pk11akey.c
+++ b/lib/pk11wrap/pk11akey.c
@@ -1969,14 +1969,20 @@ PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx)
return pki;
}
+/* V2 refers to PKCS #5 V2 here. If a PKCS #5 v1 or PKCS #12 pbe is passed
+ * for pbeTag, then encTag and hashTag are ignored. If pbe is an encryption
+ * algorithm, then PKCS #5 V2 is used with prfTag for the prf. If prfTag isn't
+ * supplied prf will be SEC_OID_HMAC_SHA1 */
SECKEYEncryptedPrivateKeyInfo *
-PK11_ExportEncryptedPrivKeyInfo(
+PK11_ExportEncryptedPrivKeyInfoV2(
PK11SlotInfo *slot, /* optional, encrypt key in this slot */
- SECOidTag algTag, /* encrypt key with this algorithm */
+ SECOidTag pbeAlg, /* PBE algorithm to encrypt the with key */
+ SECOidTag encAlg, /* Encryption algorithm to Encrypt the key with */
+ SECOidTag prfAlg, /* Hash algorithm for PRF */
SECItem *pwitem, /* password for PBE encryption */
SECKEYPrivateKey *pk, /* encrypt this private key */
int iteration, /* interations for PBE alg */
- void *wincx) /* context for password callback ? */
+ void *pwArg) /* context for password callback */
{
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
PLArenaPool *arena = NULL;
@@ -1997,7 +2003,7 @@ PK11_ExportEncryptedPrivKeyInfo(
return NULL;
}
- algid = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, SEC_OID_UNKNOWN,
+ algid = sec_pkcs5CreateAlgorithmID(pbeAlg, encAlg, prfAlg,
&pbeAlgTag, 0, NULL, iteration);
if (algid == NULL) {
return NULL;
@@ -2026,7 +2032,7 @@ PK11_ExportEncryptedPrivKeyInfo(
slot = pk->pkcs11Slot;
}
}
- key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, wincx);
+ key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, pwArg);
if (key == NULL) {
rv = SECFailure;
goto loser;
@@ -2121,24 +2127,59 @@ PK11_ExportEncryptedPrivKeyInfo(
}
SECKEYEncryptedPrivateKeyInfo *
-PK11_ExportEncryptedPrivateKeyInfo(
+PK11_ExportEncryptedPrivKeyInfo(
+ PK11SlotInfo *slot, /* optional, encrypt key in this slot */
+ SECOidTag algTag, /* PBE algorithm to encrypt the with key */
+ SECItem *pwitem, /* password for PBE encryption */
+ SECKEYPrivateKey *pk, /* encrypt this private key */
+ int iteration, /* interations for PBE alg */
+ void *pwArg) /* context for password callback */
+{
+ return PK11_ExportEncryptedPrivKeyInfoV2(slot, algTag, SEC_OID_UNKNOWN,
+ SEC_OID_UNKNOWN, pwitem, pk,
+ iteration, pwArg);
+}
+
+/* V2 refers to PKCS #5 V2 here. If a PKCS #5 v1 or PKCS #12 pbe is passed
+ * for pbeTag, then encTag and hashTag are ignored. If pbe is an encryption
+ * algorithm, then PKCS #5 V2 is used with prfTag for the prf. If prfTag isn't
+ * supplied prf will be SEC_OID_HMAC_SHA1 */
+SECKEYEncryptedPrivateKeyInfo *
+PK11_ExportEncryptedPrivateKeyInfoV2(
PK11SlotInfo *slot, /* optional, encrypt key in this slot */
- SECOidTag algTag, /* encrypt key with this algorithm */
+ SECOidTag pbeAlg, /* PBE algorithm to encrypt the with key */
+ SECOidTag encAlg, /* Encryption algorithm to Encrypt the key with */
+ SECOidTag prfAlg, /* HMAC algorithm for PRF*/
SECItem *pwitem, /* password for PBE encryption */
CERTCertificate *cert, /* wrap priv key for this user cert */
int iteration, /* interations for PBE alg */
- void *wincx) /* context for password callback ? */
+ void *pwArg) /* context for password callback */
{
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
- SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx);
+ SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, pwArg);
if (pk != NULL) {
- epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk,
- iteration, wincx);
+ epki = PK11_ExportEncryptedPrivKeyInfoV2(slot, pbeAlg, encAlg, prfAlg,
+ pwitem, pk, iteration,
+ pwArg);
SECKEY_DestroyPrivateKey(pk);
}
return epki;
}
+SECKEYEncryptedPrivateKeyInfo *
+PK11_ExportEncryptedPrivateKeyInfo(
+ PK11SlotInfo *slot, /* optional, encrypt key in this slot */
+ SECOidTag algTag, /* encrypt key with this algorithm */
+ SECItem *pwitem, /* password for PBE encryption */
+ CERTCertificate *cert, /* wrap priv key for this user cert */
+ int iteration, /* interations for PBE alg */
+ void *pwArg) /* context for password callback */
+{
+ return PK11_ExportEncryptedPrivateKeyInfoV2(slot, algTag, SEC_OID_UNKNOWN,
+ SEC_OID_UNKNOWN, pwitem, cert,
+ iteration, pwArg);
+}
+
SECItem *
PK11_DEREncodePublicKey(const SECKEYPublicKey *pubk)
{
diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h
index 559fc3c661..0fe0876404 100644
--- a/lib/pk11wrap/pk11pub.h
+++ b/lib/pk11wrap/pk11pub.h
@@ -627,10 +627,20 @@ SECKEYPrivateKeyInfo *PK11_ExportPrivateKeyInfo(
CERTCertificate *cert, void *wincx);
SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivKeyInfo(
PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem,
- SECKEYPrivateKey *pk, int iteration, void *wincx);
+ SECKEYPrivateKey *pk, int iteration, void *pwArg);
SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivateKeyInfo(
PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem,
- CERTCertificate *cert, int iteration, void *wincx);
+ CERTCertificate *cert, int iteration, void *pwArg);
+/* V2 refers to PKCS #5 V2 here. If a PKCS #5 v1 or PKCS #12 pbe is passed
+ * for pbeTag, then encTag and hashTag are ignored. If pbe is an encryption
+ * algorithm, then PKCS #5 V2 is used with prfTag for the prf. If prfTag isn't
+ * supplied prf will be SEC_OID_HMAC_SHA1 */
+SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivKeyInfoV2(
+ PK11SlotInfo *slot, SECOidTag pbeTag, SECOidTag encTag, SECOidTag prfTag,
+ SECItem *pwitem, SECKEYPrivateKey *pk, int iteration, void *pwArg);
+SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivateKeyInfoV2(
+ PK11SlotInfo *slot, SECOidTag pbeTag, SECOidTag encTag, SECOidTag prfTag,
+ SECItem *pwitem, CERTCertificate *cert, int iteration, void *pwArg);
SECKEYPrivateKey *PK11_FindKeyByDERCert(PK11SlotInfo *slot,
CERTCertificate *cert, void *wincx);
SECKEYPublicKey *PK11_MakeKEAPubKey(unsigned char *data, int length);
diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c
index fae1626576..676f33b319 100644
--- a/lib/pkcs12/p12d.c
+++ b/lib/pkcs12/p12d.c
@@ -1353,32 +1353,10 @@ sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx)
iteration);
algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm);
- switch (algtag) {
- case SEC_OID_SHA1:
- integrityMech = CKM_NSS_PBE_SHA1_HMAC_KEY_GEN;
- break;
- case SEC_OID_MD5:
- integrityMech = CKM_NSS_PBE_MD5_HMAC_KEY_GEN;
- break;
- case SEC_OID_MD2:
- integrityMech = CKM_NSS_PBE_MD2_HMAC_KEY_GEN;
- break;
- case SEC_OID_SHA224:
- integrityMech = CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN;
- break;
- case SEC_OID_SHA256:
- integrityMech = CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN;
- break;
- case SEC_OID_SHA384:
- integrityMech = CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN;
- break;
- case SEC_OID_SHA512:
- integrityMech = CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN;
- break;
- default:
- goto loser;
+ integrityMech = sec_pkcs12_algtag_to_keygen_mech(algtag);
+ if (integrityMech == CKM_INVALID_MECHANISM) {
+ goto loser;
}
-
symKey = PK11_KeyGen(NULL, integrityMech, params, 0, NULL);
PK11_DestroyPBEParams(params);
params = NULL;
diff --git a/lib/pkcs12/p12e.c b/lib/pkcs12/p12e.c
index 7e476e95fd..2b8654698b 100644
--- a/lib/pkcs12/p12e.c
+++ b/lib/pkcs12/p12e.c
@@ -14,6 +14,7 @@
#include "secpkcs7.h"
#include "secasn1.h"
#include "secerr.h"
+#include "sechash.h"
#include "pk11func.h"
#include "p12plcy.h"
#include "p12local.h"
@@ -379,11 +380,18 @@ SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
safeInfo->itemCount = 0;
/* create the encrypted safe */
- if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg) &&
- PK11_AlgtagToMechanism(privAlg) == CKM_AES_CBC) {
+ if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg)) {
+ SECOidTag prfAlg = SEC_OID_UNKNOWN;
+ /* if we have password integrity set, use that to set the integrity
+ * hash algorithm to set our password PRF. If we haven't set it, just
+ * let the low level code pick it */
+ if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
+ prfAlg = HASH_GetHMACOidTagByHashOidTag(
+ p12ctxt->integrityInfo.pwdInfo.algorithm);
+ }
safeInfo->cinfo = SEC_PKCS7CreateEncryptedDataWithPBEV2(SEC_OID_PKCS5_PBES2,
privAlg,
- SEC_OID_UNKNOWN,
+ prfAlg,
0,
p12ctxt->pwfn,
p12ctxt->pwfnarg);
@@ -1213,6 +1221,7 @@ SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *sa
/* extract the key encrypted */
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
PK11SlotInfo *slot = NULL;
+ SECOidTag prfAlg = SEC_OID_UNKNOWN;
if (!sec_pkcs12_encode_password(p12ctxt->arena, &uniPwitem, algorithm,
pwitem)) {
@@ -1220,6 +1229,14 @@ SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *sa
goto loser;
}
+ /* if we have password integrity set, use that to set the integrity
+ * hash algorithm to set our password PRF. If we haven't set it, just
+ * let the low level code pick it */
+ if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
+ prfAlg = HASH_GetHMACOidTagByHashOidTag(
+ p12ctxt->integrityInfo.pwdInfo.algorithm);
+ }
+
/* we want to make sure to take the key out of the key slot */
if (PK11_IsInternal(p12ctxt->slot)) {
slot = PK11_GetInternalKeySlot();
@@ -1227,10 +1244,15 @@ SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *sa
slot = PK11_ReferenceSlot(p12ctxt->slot);
}
- epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
- &uniPwitem, cert,
- NSS_PBE_DEFAULT_ITERATION_COUNT,
- p12ctxt->wincx);
+ /* passing algorithm as the pbe will force the PBE code to
+ * automatically handle the selection between using the algorithm
+ * as a the pbe algorithm, or using the algorithm as a cipher
+ * and building a pkcs5 pbe */
+ epki = PK11_ExportEncryptedPrivateKeyInfoV2(slot, algorithm,
+ SEC_OID_UNKNOWN, prfAlg,
+ &uniPwitem, cert,
+ NSS_PBE_DEFAULT_ITERATION_COUNT,
+ p12ctxt->wincx);
PK11_FreeSlot(slot);
if (!epki) {
PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
@@ -1595,18 +1617,10 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
SECITEM_ZfreeItem(&pwd, PR_FALSE);
/* get the PBA Mechanism to generate the key */
- switch (p12exp->integrityInfo.pwdInfo.algorithm) {
- case SEC_OID_SHA1:
- integrityMechType = CKM_PBA_SHA1_WITH_SHA1_HMAC;
- break;
- case SEC_OID_MD5:
- integrityMechType = CKM_NSS_PBE_MD5_HMAC_KEY_GEN;
- break;
- case SEC_OID_MD2:
- integrityMechType = CKM_NSS_PBE_MD2_HMAC_KEY_GEN;
- break;
- default:
- goto loser;
+ integrityMechType = sec_pkcs12_algtag_to_keygen_mech(
+ p12exp->integrityInfo.pwdInfo.algorithm);
+ if (integrityMechType == CKM_INVALID_MECHANISM) {
+ goto loser;
}
/* generate the key */
@@ -1837,7 +1851,8 @@ sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
static SECStatus
sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
{
- SECItem hmac = { siBuffer, NULL, 0 };
+ unsigned char hmacData[HASH_LENGTH_MAX];
+ unsigned int hmacLen;
SECStatus rv;
SGNDigestInfo *di = NULL;
void *dummy;
@@ -1856,13 +1871,8 @@ sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
}
/* finish the hmac */
- hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
- if (!hmac.data) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
+ rv = PK11_DigestFinal(p12ecx->hmacCx, hmacData, &hmacLen, HASH_LENGTH_MAX);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
@@ -1871,7 +1881,7 @@ sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
/* create the digest info */
di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
- hmac.data, hmac.len);
+ hmacData, hmacLen);
if (!di) {
PORT_SetError(SEC_ERROR_NO_MEMORY);
rv = SECFailure;
@@ -1896,11 +1906,9 @@ sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
if (di) {
SGN_DestroyDigestInfo(di);
}
- if (hmac.data) {
- SECITEM_ZfreeItem(&hmac, PR_FALSE);
- }
PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
p12ecx->hmacCx = NULL;
+ PORT_Memset(hmacData, 0, hmacLen);
return rv;
}
diff --git a/lib/pkcs12/p12local.c b/lib/pkcs12/p12local.c
index 53e3aa6bb6..900a0dbce7 100644
--- a/lib/pkcs12/p12local.c
+++ b/lib/pkcs12/p12local.c
@@ -44,6 +44,37 @@ sec_pkcs12_algtag_to_mech(SECOidTag algtag)
return CKM_INVALID_MECHANISM;
}
+CK_MECHANISM_TYPE
+sec_pkcs12_algtag_to_keygen_mech(SECOidTag algtag)
+{
+ switch (algtag) {
+ case SEC_OID_SHA1:
+ return CKM_NSS_PBE_SHA1_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_MD5:
+ return CKM_NSS_PBE_MD5_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_MD2:
+ return CKM_NSS_PBE_MD2_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_SHA224:
+ return CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_SHA256:
+ return CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_SHA384:
+ return CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN;
+ break;
+ case SEC_OID_SHA512:
+ return CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN;
+ break;
+ default:
+ break;
+ }
+ return CKM_INVALID_MECHANISM;
+}
+
/* helper functions */
/* returns proper bag type template based upon object type tag */
const SEC_ASN1Template *
diff --git a/lib/pkcs12/p12local.h b/lib/pkcs12/p12local.h
index 06a56d13b9..99068e21ef 100644
--- a/lib/pkcs12/p12local.h
+++ b/lib/pkcs12/p12local.h
@@ -38,6 +38,7 @@ extern PRBool sec_pkcs12_convert_item_to_unicode(PLArenaPool *arena, SECItem *de
SECItem *src, PRBool zeroTerm,
PRBool asciiConvert, PRBool toUnicode);
extern CK_MECHANISM_TYPE sec_pkcs12_algtag_to_mech(SECOidTag algtag);
+extern CK_MECHANISM_TYPE sec_pkcs12_algtag_to_keygen_mech(SECOidTag algtag);
/* create functions */
extern SEC_PKCS12PFXItem *sec_pkcs12_new_pfx(void);
diff --git a/lib/pkcs12/p12plcy.c b/lib/pkcs12/p12plcy.c
index 97970abc4d..394e07be50 100644
--- a/lib/pkcs12/p12plcy.c
+++ b/lib/pkcs12/p12plcy.c
@@ -6,6 +6,7 @@
#include "secoid.h"
#include "secport.h"
#include "secpkcs5.h"
+#include "secerr.h"
#define PKCS12_NULL 0x0000
@@ -32,31 +33,32 @@ static pkcs12SuiteMap pkcs12SuiteMaps[] = {
};
/* determine if algid is an algorithm which is allowed */
+static PRBool
+sec_PKCS12Allowed(SECOidTag alg)
+{
+ PRUint32 policy;
+ SECStatus rv;
+
+ rv = NSS_GetAlgorithmPolicy(alg, &policy);
+ if (rv != SECSuccess) {
+ return PR_FALSE;
+ }
+ if (policy & NSS_USE_ALG_IN_PKCS12) {
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
PRBool
SEC_PKCS12DecryptionAllowed(SECAlgorithmID *algid)
{
- unsigned int keyLengthBits;
SECOidTag algId;
- int i;
algId = SEC_PKCS5GetCryptoAlgorithm(algid);
if (algId == SEC_OID_UNKNOWN) {
return PR_FALSE;
}
-
- keyLengthBits = (unsigned int)(SEC_PKCS5GetKeyLength(algid) * 8);
-
- i = 0;
- while (pkcs12SuiteMaps[i].algTag != SEC_OID_UNKNOWN) {
- if ((pkcs12SuiteMaps[i].algTag == algId) &&
- (pkcs12SuiteMaps[i].keyLengthBits == keyLengthBits)) {
-
- return pkcs12SuiteMaps[i].allowed;
- }
- i++;
- }
-
- return PR_FALSE;
+ return sec_PKCS12Allowed(algId);
}
/* is any encryption allowed? */
@@ -65,61 +67,45 @@ SEC_PKCS12IsEncryptionAllowed(void)
{
int i;
- i = 0;
- while (pkcs12SuiteMaps[i].algTag != SEC_OID_UNKNOWN) {
- if (pkcs12SuiteMaps[i].allowed == PR_TRUE) {
+ for (i = 0; pkcs12SuiteMaps[i].algTag != SEC_OID_UNKNOWN; i++) {
+ /* we're going to return true here if any of the traditional
+ * algorithms are enabled */
+ if (sec_PKCS12Allowed(pkcs12SuiteMaps[i].algTag)) {
return PR_TRUE;
}
- i++;
}
return PR_FALSE;
}
+/* keep the traditional enable/disable for old ciphers so old applications
+ * continue to work. This only works for the traditional pkcs12 values,
+ * you need to use NSS_SetAlgorithmPolicy directly for other ciphers. */
SECStatus
SEC_PKCS12EnableCipher(long which, int on)
{
int i;
+ SECStatus rv;
+ PRUint32 set = on ? NSS_USE_ALG_IN_PKCS12 : 0;
+ PRUint32 clear = on ? 0 : NSS_USE_ALG_IN_PKCS12;
- i = 0;
- while (pkcs12SuiteMaps[i].suite != 0L) {
+ for (i = 0; pkcs12SuiteMaps[i].suite != 0L; i++) {
if (pkcs12SuiteMaps[i].suite == (unsigned long)which) {
- if (on) {
- pkcs12SuiteMaps[i].allowed = PR_TRUE;
- } else {
- pkcs12SuiteMaps[i].allowed = PR_FALSE;
+ rv = NSS_SetAlgorithmPolicy(pkcs12SuiteMaps[i].algTag, set, clear);
+ /* could fail if the policy has been locked */
+ if (rv != SECSuccess) {
+ return rv;
}
- return SECSuccess;
}
- i++;
}
-
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
SEC_PKCS12SetPreferredCipher(long which, int on)
{
- int i;
- PRBool turnedOff = PR_FALSE;
- PRBool turnedOn = PR_FALSE;
-
- i = 0;
- while (pkcs12SuiteMaps[i].suite != 0L) {
- if (pkcs12SuiteMaps[i].preferred == PR_TRUE) {
- pkcs12SuiteMaps[i].preferred = PR_FALSE;
- turnedOff = PR_TRUE;
- }
- if (pkcs12SuiteMaps[i].suite == (unsigned long)which) {
- pkcs12SuiteMaps[i].preferred = PR_TRUE;
- turnedOn = PR_TRUE;
- }
- i++;
- }
-
- if ((turnedOn) && (turnedOff)) {
- return SECSuccess;
- }
-
- return SECFailure;
+ /* nothing looked at the preferences in the suite maps, so this function
+ * has always been a noop */
+ return SECSuccess;
}
diff --git a/lib/util/secoidt.h b/lib/util/secoidt.h
index c73829ef86..2b7eb2139e 100644
--- a/lib/util/secoidt.h
+++ b/lib/util/secoidt.h
@@ -538,7 +538,8 @@ struct SECOidDataStr {
#define NSS_USE_ALG_IN_SSL_KX 0x00000004 /* used in SSL key exchange */
#define NSS_USE_ALG_IN_SSL 0x00000008 /* used in SSL record protocol */
#define NSS_USE_POLICY_IN_SSL 0x00000010 /* enable policy in SSL protocol */
-#define NSS_USE_ALG_IN_ANY_SIGNATURE 0x00000020 /* used in S/MIME */
+#define NSS_USE_ALG_IN_ANY_SIGNATURE 0x00000020 /* used in any signature */
+#define NSS_USE_ALG_IN_PKCS12 0x00000040 /* used in pkcs12 */
#define NSS_USE_DEFAULT_NOT_VALID 0x80000000 /* clear to make the default flag valid */
#define NSS_USE_DEFAULT_SSL_ENABLE 0x40000000 /* default cipher suite setting 1=enable */
diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh
old mode 100644
new mode 100755
index 7cf1ef73f8..19d8b1903f
--- a/tests/tools/tools.sh
+++ b/tests/tools/tools.sh
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/bash
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -8,7 +8,7 @@
#
# mozilla/security/nss/tests/tools/tools.sh
#
-# Script to test basic functionality of NSS tools
+# Script to test basic functionality of NSS tools
#
# needs to work on all Unix and Windows platforms
#
@@ -23,29 +23,20 @@
########################################################################
export pkcs12v2pbeWithSha1And128BitRc4=\
-"PKCS #12 V2 PBE With SHA-1 and 128 Bit RC4"
+"PKCS #12 V2 PBE With SHA-1 And 128 Bit RC4"
export pkcs12v2pbeWithSha1And40BitRc4=\
-"PKCS #12 V2 PBE With SHA-1 and 40 Bit RC4"
+"PKCS #12 V2 PBE With SHA-1 And 40 Bit RC4"
export pkcs12v2pbeWithSha1AndTripleDESCBC=\
-"PKCS #12 V2 PBE With SHA-1 and 3KEY Triple DES-CBC"
+"PKCS #12 V2 PBE With SHA-1 And 3KEY Triple DES-CBC"
export pkcs12v2pbeWithSha1And128BitRc2Cbc=\
-"PKCS #12 V2 PBE With SHA-1 and 128 Bit RC2 CBC"
+"PKCS #12 V2 PBE With SHA-1 And 128 Bit RC2 CBC"
export pkcs12v2pbeWithSha1And40BitRc2Cbc=\
-"PKCS #12 V2 PBE With SHA-1 and 40 Bit RC2 CBC"
+"PKCS #12 V2 PBE With SHA-1 And 40 Bit RC2 CBC"
- export pkcs12v2pbeWithMd2AndDESCBC=\
-"PKCS #5 Password Based Encryption with MD2 and DES-CBC"
-
- export pkcs12v2pbeWithMd5AndDESCBC=\
-"PKCS #5 Password Based Encryption with MD5 and DES-CBC"
-
- export pkcs12v2pbeWithSha1AndDESCBC=\
-"PKCS #5 Password Based Encryption with SHA-1 and DES-CBC"
-
export pkcs5pbeWithMD2AndDEScbc=\
"PKCS #5 Password Based Encryption with MD2 and DES-CBC"
@@ -55,8 +46,28 @@
export pkcs5pbeWithSha1AndDEScbc=\
"PKCS #5 Password Based Encryption with SHA-1 and DES-CBC"
+ # if we change the defaults in pk12util, update these variables
+ export CERT_ENCRYPTION_DEFAULT="AES-128-CBC"
+ export KEY_ENCRYPTION_DEFAULT="AES-256-CBC"
+ export HASH_DEFAULT="SHA-256"
+
+ export PKCS5v1_PBE_CIPHERS="${pkcs5pbeWithMD2AndDEScbc},\
+${pkcs5pbeWithMD5AndDEScbc},\
+${pkcs5pbeWithSha1AndDEScbc}"
+ export PKCS12_PBE_CIPHERS="${pkcs12v2pbeWithSha1And128BitRc4},\
+${pkcs12v2pbeWithSha1And40BitRc4},\
+${pkcs12v2pbeWithSha1AndTripleDESCBC},\
+${pkcs12v2pbeWithSha1And128BitRc2Cbc},\
+${pkcs12v2pbeWithSha1And40BitRc2Cbc}"
+ export PKCS5v2_PBE_CIPHERS="RC2-CBC,DES-EDE3-CBC,AES-128-CBC,AES-192-CBC,\
+AES-256-CBC,CAMELLIA-128-CBC,CAMELLIA-192-CBC,CAMELLIA-256-CBC"
+ export PBE_CIPHERS="${PKCS5v1_PBE_CIPHERS},${PKCS12_PBE_CIPHERS},${PKCS5v2_PBE_CIPHERS}"
+ export PBE_CIPHERS_CLASSES="${pkcs5pbeWithSha1AndDEScbc},\
+${pkcs12v2pbeWithSha1AndTripleDESCBC},AES-256-CBC,default"
+ export PBE_HASH="SHA-1,SHA-224,SHA-256,SHA-384,SHA-512,default"
+
############################## tools_init ##############################
-# local shell function to initialize this script
+# local shell function to initialize this script
########################################################################
tools_init()
{
@@ -117,7 +128,7 @@ list_p12_file()
{
echo "$SCRIPTNAME: Listing Alice's pk12 file"
echo "pk12util -l ${1} -w ${R_PWFILE}"
-
+
${BINDIR}/pk12util -l ${1} -w ${R_PWFILE} 2>&1
ret=$?
html_msg $ret 0 "Listing ${1} (pk12util -l)"
@@ -131,105 +142,70 @@ import_p12_file()
{
echo "$SCRIPTNAME: Importing Alice's pk12 ${1} file"
echo "pk12util -i ${1} -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE}"
-
+
${BINDIR}/pk12util -i ${1} -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE} 2>&1
ret=$?
html_msg $ret 0 "Importing ${1} (pk12util -i)"
check_tmpfile
}
-########################################################################
-# Export the key and cert to a p12 file using default ciphers
-########################################################################
-export_with_default_ciphers()
-{
- echo "$SCRIPTNAME: Exporting Alice's key & cert with [default:default] (pk12util -o)"
- echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE}"
- ${BINDIR}/pk12util -o Alice.p12 -n "Alice" -d ${P_R_ALICEDIR} \
- -k ${R_PWFILE} -w ${R_PWFILE} 2>&1
- ret=$?
- html_msg $ret 0 "Exporting Alices's key & cert with [default:default] (pk12util -o)"
- check_tmpfile
- return $ret
-}
########################################################################
-# Exports key/cert to a p12 file, the key encryption cipher is specified
-# and the cert encryption cipher is blank for default.
+# Export the key and cert from the specified p12 file
########################################################################
-export_with_key_cipher()
+export_p12_file()
{
- # $1 key encryption cipher
- echo "$SCRIPTNAME: Exporting with [${1}:default]"
- echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE} -c ${1}"
- ${BINDIR}/pk12util -o Alice.p12 -n "Alice" -d ${P_R_ALICEDIR} \
- -k ${R_PWFILE} -w ${R_PWFILE} -c "${1}" 2>&1
- ret=$?
- html_msg $ret 0 "Exporting with [${1}:default] (pk12util -o)"
- check_tmpfile
- return $ret
-}
-
-########################################################################
-# Exports key/cert to a p12 file, the key encryption cipher is left
-# empty for default and the cert encryption cipher is specified.
-########################################################################
-export_with_cert_cipher()
-{
- # $1 certificate encryption cipher
- echo "$SCRIPTNAME: Exporting with [default:${1}]"
- echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE} -C ${1}"
- ${BINDIR}/pk12util -o Alice.p12 -n "Alice" -d ${P_R_ALICEDIR} \
- -k ${R_PWFILE} -w ${R_PWFILE} -C "${1}" 2>&1
- ret=$?
- html_msg $ret 0 "Exporting with [default:${1}] (pk12util -o)"
- check_tmpfile
- return $ret
-}
+ # $1 p12 file
+ # $2 cert to export
+ # $3 certdb
+ # $4 key encryption cipher or "default"
+ # $5 certificate encryption cipher or "default"
+ # $6 hash algorithm or "default"
+ KEY_CIPHER_OPT="-c"
+ KEY_CIPHER="${4}"
+ CERT_CIPHER_OPT="-C"
+ CERT_CIPHER="${5}"
+ HASH_ALG_OPT="-M"
+ HASH_ALG="${6}"
+
+ if [ "${KEY_CIPHER}" = "default" ]; then
+ KEY_CIPHER_OPT=""
+ KEY_CIPHER=""
+ fi
+ if [ "${CERT_CIPHER}" = "default" ]; then
+ CERT_CIPHER_OPT=""
+ CERT_CIPHER=""
+ fi
+ if [ "${HASH_ALG}" = "default" ]; then
+ HASH_ALG_OPT=""
+ HASH_ALG=""
+ fi
-########################################################################
-# Exports key/cert to a p12 file, both the key encryption cipher and
-# the cert encryption cipher are specified.
-########################################################################
-export_with_both_key_and_cert_cipher()
-{
- # $1 key encryption cipher or ""
- # $2 certificate encryption cipher or ""
-
- echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE} -c ${1} -C ${2}"
- ${BINDIR}/pk12util -o Alice.p12 -n Alice -d ${P_R_ALICEDIR} \
+ echo "pk12util -o \"${1}\" -n \"${2}\" -d \"${3}\" \\"
+ echo " -k ${R_PWFILE} -w ${R_PWFILE} \\"
+ echo " ${KEY_CIPHER_OPT} \"${KEY_CIPHER}\" \\"
+ echo " ${CERT_CIPHER_OPT} \"${CERT_CIPHER}\" \\"
+ echo " ${HASH_ALG_OPT} \"${HASH_ALG}\""
+ ${BINDIR}/pk12util -o "${1}" -n "${2}" -d "${3}" \
-k ${R_PWFILE} -w ${R_PWFILE} \
- -c "${1}" -C "${2}" 2>&1
- ret=$?
- html_msg $ret 0 "Exporting with [${1}:${2}] (pk12util -o)"
+ ${KEY_CIPHER_OPT} "${KEY_CIPHER}" \
+ ${CERT_CIPHER_OPT} "${CERT_CIPHER}" \
+ ${HASH_ALG_OPT} "${HASH_ALG}" 2>&1
+ ret=$?
+ html_msg $ret 0 "Exporting with [${4}:${5}:${6}] (pk12util -o)"
check_tmpfile
+ verify_p12 "${1}" "${4}" "${5}" "${6}"
return $ret
}
########################################################################
-# Exports key and cert to a p12 file, both the key encryption cipher
-# and the cert encryption cipher are specified. The key and cert are
-# imported and the p12 file is listed
+# Exports key and cert to a p12 file, the key encryption cipher,
+# the cert encryption cipher, and/or the hash algorithm are specified.
+# The key and cert are imported and the p12 file is listed
########################################################################
export_list_import()
{
- # $1 key encryption cipher
- # $2 certificate encryption cipher
-
- if [ "${1}" != "DEFAULT" -a "${2}" != "DEFAULT" ]; then
- export_with_both_key_and_cert_cipher "${1}" "${2}"
- elif [ "${1}" != "DEFAULT" -a "${2}" = "DEFAULT" ]; then
- export_with_key_cipher "${1}"
- elif [ "${1}" = "DEFAULT" -a "${2}" != "DEFAULT" ]; then
- export_with_cert_cipher "${2}"
- else
- export_with_default_ciphers
- fi
-
+ export_p12_file Alice.p12 Alice "${P_R_ALICEDIR}" "${@}"
list_p12_file Alice.p12
import_p12_file Alice.p12
}
@@ -239,20 +215,17 @@ export_list_import()
# List the contents of and import from the p12 file.
########################################################################
tools_p12_export_list_import_all_pkcs5pbe_ciphers()
-{
- # specify each on key and cert cipher
- for key_cipher in "${pkcs5pbeWithMD2AndDEScbc}" \
- "${pkcs5pbeWithMD5AndDEScbc}" \
- "${pkcs5pbeWithSha1AndDEScbc}"\
- "DEFAULT"; do
- for cert_cipher in "${pkcs5pbeWithMD2AndDEScbc}" \
- "${pkcs5pbeWithMD5AndDEScbc}" \
- "${pkcs5pbeWithSha1AndDEScbc}" \
- "DEFAULT"\
- "none"; do
- export_list_import "${key_cipher}" "${cert_cipher}"
- done
+{
+ local saveIFS="${IFS}"
+ IFS=,
+ for key_cipher in ${PKCS5v1_PBE_CIPHERS} default; do
+ for cert_cipher in ${PKCS5v1_PBE_CIPHERS} default none; do
+ for hash in ${PBE_HASH}; do
+ export_list_import "${key_cipher}" "${cert_cipher}" "${hash}"
+ done
+ done
done
+ IFS="${saveIFS}"
}
########################################################################
@@ -261,36 +234,16 @@ tools_p12_export_list_import_all_pkcs5pbe_ciphers()
########################################################################
tools_p12_export_list_import_all_pkcs5v2_ciphers()
{
- # These should pass
- for key_cipher in\
- RC2-CBC \
- DES-EDE3-CBC \
- AES-128-CBC \
- AES-192-CBC \
- AES-256-CBC \
- CAMELLIA-128-CBC \
- CAMELLIA-192-CBC \
- CAMELLIA-256-CBC; do
-
-#---------------------------------------------------------------
-# Bug 452464 - pk12util -o fails when -C option specifies
-# Camellia ciphers
-# FIXME Restore these to the list
-# CAMELLIA-128-CBC, \
-# CAMELLIA-192-CBC, \
-# CAMELLIA-256-CBC, \
-# when 452464 is fixed
-#---------------------------------------------------------------
- for cert_cipher in \
- RC2-CBC \
- DES-EDE3-CBC \
- AES-128-CBC \
- AES-192-CBC \
- AES-256-CBC \
- none; do
- export_list_import ${key_cipher} ${cert_cipher}
- done
+ local saveIFS="${IFS}"
+ IFS=,
+ for key_cipher in ${PKCS5v2_PBE_CIPHERS} default; do
+ for cert_cipher in ${PKCS5v2_PBE_CIPHERS} default none; do
+ for hash in ${PBE_HASH}; do
+ export_list_import "${key_cipher}" "${cert_cipher}" "${hash}"
+ done
+ done
done
+ IFS="${saveIFS}"
}
########################################################################
@@ -298,36 +251,50 @@ tools_p12_export_list_import_all_pkcs5v2_ciphers()
# List the contents of and import from the p12 file.
########################################################################
tools_p12_export_list_import_all_pkcs12v2pbe_ciphers()
-{
-#---------------------------------------------------------------
-# Bug 452471 - pk12util -o fails when -c option specifies pkcs12v2 PBE ciphers
-# FIXME - Restore these to the list
-# "${pkcs12v2pbeWithSha1And128BitRc4}" \
-# "${pkcs12v2pbeWithSha1And40BitRc4}" \
-# "${pkcs12v2pbeWithSha1AndTripleDESCBC}" \
-# "${pkcs12v2pbeWithSha1And128BitRc2Cbc}" \
-# "${pkcs12v2pbeWithSha1And40BitRc2Cbc}" \
-# "${pkcs12v2pbeWithMd2AndDESCBC}" \
-# "${pkcs12v2pbeWithMd5AndDESCBC}" \
-# "${pkcs12v2pbeWithSha1AndDESCBC}" \
-# "DEFAULT"; do
-# when 452471 is fixed
-#---------------------------------------------------------------
-# for key_cipher in \
- key_cipher="DEFAULT"
- for cert_cipher in "${pkcs12v2pbeWithSha1And128BitRc4}" \
- "${pkcs12v2pbeWithSha1And40BitRc4}" \
- "${pkcs12v2pbeWithSha1AndTripleDESCBC}" \
- "${pkcs12v2pbeWithSha1And128BitRc2Cbc}" \
- "${pkcs12v2pbeWithSha1And40BitRc2Cbc}" \
- "${pkcs12v2pbeWithMd2AndDESCBC}" \
- "${pkcs12v2pbeWithMd5AndDESCBC}" \
- "${pkcs12v2pbeWithSha1AndDESCBC}" \
- "DEFAULT"\
- "none"; do
- export_list_import "${key_cipher}" "${cert_cipher}"
- done
- #done
+{
+ local saveIFS="${IFS}"
+ IFS=,
+ for key_cipher in ${PKCS12_PBE_CIPHERS} ${PKCS5v1_PBE_CIPHERS} default; do
+ for cert_cipher in ${PKCS12_PBE_CIPHERS} ${PKCS5v1_PBE_CIPHERS} default none; do
+ for hash in ${PBE_HASH}; do
+ export_list_import "${key_cipher}" "${cert_cipher}" "${hash}"
+ done
+ done
+ done
+ IFS="${saveIFS}"
+}
+
+########################################################################
+# Spot check all ciphers.
+# using the traditional tests, we wind up running almost 1300 tests.
+# This isn't too bad for debug builds in which the interator is set to 1000.
+# for optimized builds, the iterator is set to 60000, which means a 30
+# minute test will now take more than 2 hours. This tests most combinations
+# and results in only about 300 tests. We are stil testing all ciphers
+# for both key and cert encryption, and we are testing them against
+# one of each class of cipher (pkcs5v1, pkcs5v2, pkcs12).
+########################################################################
+tools_p12_export_list_import_most_ciphers()
+{
+ local saveIFS="${IFS}"
+ IFS=,
+ for cipher in ${PBE_CIPHERS}; do
+ for class in ${PBE_CIPHERS_CLASSES}; do
+ # we'll test the case of cipher == class below the for loop
+ if [ "${cipher}" != "${class}" ]; then
+ export_list_import "${class}" "${cipher}" "SHA-1"
+ export_list_import "${cipher}" "${class}" "SHA-256"
+ fi
+ done
+ export_list_import "${cipher}" "none" "SHA-224"
+ export_list_import "${cipher}" "${cipher}" "SHA-384"
+ done
+ for class in ${PBE_CIPHERS_CLASSES}; do
+ for hash in ${PBE_HASH}; do
+ export_list_import "${class}" "${class}" "${hash}"
+ done
+ done
+ IFS="${saveIFS}"
}
#########################################################################
@@ -337,28 +304,28 @@ tools_p12_export_with_none_ciphers()
{
# use none as the key encryption algorithm default for the cert one
# should fail
-
+
echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE} -c none"
+ echo " -k ${R_PWFILE} -w ${R_PWFILE} -c none"
${BINDIR}/pk12util -o Alice.p12 -n Alice -d ${P_R_ALICEDIR} \
-k ${R_PWFILE} -w ${R_PWFILE} \
- -c none 2>&1
+ -c none 2>&1
ret=$?
- html_msg $ret 30 "Exporting with [none:default] (pk12util -o)"
+ html_msg $ret 30 "Exporting with [none:default:default] (pk12util -o)"
check_tmpfile
# use default as the key encryption algorithm none for the cert one
# should pass
-
+
echo "pk12util -o Alice.p12 -n \"Alice\" -d ${P_R_ALICEDIR} \\"
- echo " -k ${R_PWFILE} -w ${R_PWFILE} -C none"
+ echo " -k ${R_PWFILE} -w ${R_PWFILE} -C none"
${BINDIR}/pk12util -o Alice.p12 -n Alice -d ${P_R_ALICEDIR} \
-k ${R_PWFILE} -w ${R_PWFILE} \
- -C none 2>&1
+ -C none 2>&1
ret=$?
- html_msg $ret 0 "Exporting with [default:none] (pk12util -o)"
+ html_msg $ret 0 "Exporting with [default:none:default] (pk12util -o)"
check_tmpfile
-
+ verify_p12 Alice.p12 "default" "none" "default"
}
#########################################################################
@@ -394,17 +361,18 @@ tools_p12_export_with_invalid_ciphers()
tools_p12_export_list_import_with_default_ciphers()
{
echo "$SCRIPTNAME: Exporting Alice's email cert & key - default ciphers"
-
- export_list_import "DEFAULT" "DEFAULT"
+
+ export_list_import "default" "default" "default"
echo "$SCRIPTNAME: Exporting Alice's email EC cert & key---------------"
echo "pk12util -o Alice-ec.p12 -n \"Alice-ec\" -d ${P_R_ALICEDIR} -k ${R_PWFILE} \\"
echo " -w ${R_PWFILE}"
${BINDIR}/pk12util -o Alice-ec.p12 -n "Alice-ec" -d ${P_R_ALICEDIR} -k ${R_PWFILE} \
- -w ${R_PWFILE} 2>&1
+ -w ${R_PWFILE} 2>&1
ret=$?
html_msg $ret 0 "Exporting Alice's email EC cert & key (pk12util -o)"
check_tmpfile
+ verify_p12 Alice-ec.p12 "default" "default" "default"
echo "$SCRIPTNAME: Importing Alice's email EC cert & key --------------"
echo "pk12util -i Alice-ec.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE}"
@@ -460,9 +428,18 @@ tools_p12_import_rsa_pss_private_key()
tools_p12()
{
tools_p12_export_list_import_with_default_ciphers
- tools_p12_export_list_import_all_pkcs5v2_ciphers
- tools_p12_export_list_import_all_pkcs5pbe_ciphers
- tools_p12_export_list_import_all_pkcs12v2pbe_ciphers
+ # optimized builds have a larger iterator, so they can't run as many
+ # pkcs12 tests and complete in a reasonable time. Use the iterateration
+ # count from the previous tests to determine how many tests
+ # we can run.
+ iteration_count=$(pp -t p12 -i Alice-ec.p12 | grep "Iterations: " | sed -e 's;.*Iterations: ;;' -e 's;(.*).*;;')
+ echo "Iteration count=${iteration_count}"
+ if [ -n "${iteration_count}" -a ${iteration_count} -le 10000 ]; then
+ tools_p12_export_list_import_all_pkcs5v2_ciphers
+ tools_p12_export_list_import_all_pkcs12v2pbe_ciphers
+ else
+ tools_p12_export_list_import_most_ciphers
+ fi
tools_p12_export_with_none_ciphers
tools_p12_export_with_invalid_ciphers
tools_p12_import_old_files
@@ -473,7 +450,7 @@ tools_p12()
############################## tools_sign ##############################
# local shell function pk12util uses a hardcoded tmp file, if this exists
-# and is owned by another user we don't get reasonable errormessages
+# and is owned by another user we don't get reasonable errormessages
########################################################################
check_tmpfile()
{
@@ -483,6 +460,163 @@ check_tmpfile()
fi
}
+############################## tools_sign ##############################
+# make sure the generated p12 file has the characteristics we expected
+########################################################################
+verify_p12()
+{
+ KEY_ENCRYPTION=$(map_cipher "${2}" "${KEY_ENCRYPTION_DEFAULT}")
+ CERT_ENCRYPTION=$(map_cipher "${3}" "${CERT_ENCRYPTION_DEFAULT}")
+ HASH=$(map_cipher "${4}" "${HASH_DEFAULT}")
+
+ STATE="NOBAGS" # state records if we are in the key or cert bag
+ CERT_ENCRYPTION_NOT_FOUND=1
+ KEY_ENCRYPTION_NOT_FOUND=1
+ CERT_ENCRYPTION_FAIL=0
+ KEY_ENCRYPTION_FAIL=0
+ HASH_FAIL=0
+ TMP=$(mktemp /tmp/p12Verify.XXXXXX)
+ which pk12util
+ local saveIFS="${IFS}"
+ IFS=" \
+"
+ # use pp to dump the pkcs12 file, only the unencrypted portions are visible
+ # if there are multiple entries, we fail if any of those entries have the
+ # wrong encryption. We also fail if we can't find any encryption info.
+ # Use a file rather than a pipe so that while do can modify our variables.
+ # We're only interested in extracting the encryption algorithms are here,
+ # p12util -l will verify that decryption works properly.
+ pp -t pkcs12 -i ${1} -o ${TMP}
+ while read line ; do
+ # first up: if we see an unencrypted key bag, then we know that the key
+ # was unencrypted (NOTE: pk12util currently can't generate these kinds of
+ # files).
+ if [[ "${line}" =~ "Bag "[0-9]+" ID: PKCS #12 V1 Key Bag" ]]; then
+ KEY_ENCRYPTION_NOT_FOUND=0
+ if [ "${KEY_ENCRYPTION}" != "none" ]; then
+ KEY_ENCRYPTION_FAIL=1
+ echo "--Key encryption mismatch: expected \"${KEY_ENCRYPTION}\" found \"none\""
+ fi
+ continue
+ fi
+ # if we find the the Cert Bag, then we know that the certificate was not
+ # encrypted
+ if [[ "${line}" =~ "Bag "[0-9]+" ID: PKCS #12 V1 Cert Bag" ]]; then
+ CERT_ENCRYPTION_NOT_FOUND=0
+ if [ "${CERT_ENCRYPTION}" != "none" ]; then
+ CERT_ENCRYPTION_FAIL=1
+ echo "--Cert encryption mismatch: expected \"${CERT_ENCRYPTION}\" found \"none\""
+ fi
+ continue
+ fi
+ # we found the shrouded key bag, the next encryption informtion should be
+ # for the key.
+ if [[ "${line}" =~ "Bag "[0-9]+" ID: PKCS #12 V1 PKCS8 Shrouded Key Bag" ]]; then
+ STATE="KEY"
+ continue
+ fi
+ # If we found PKCS #7 Encrypted Data, it must be the encrypted certificate
+ # (well it could be any encrypted certificate, or a crl, but in p12util
+ # they will all have the same encryption value
+ if [[ "${line}" = "PKCS #7 Encrypted Data:" ]]; then
+ STATE="CERT"
+ continue
+ fi
+ # check the Mac
+ if [[ "${line}" =~ "Mac Digest Algorithm ID: ".* ]]; then
+ MAC="${line##Mac Digest Algorithm ID: }"
+ if [ "${MAC}" != "${HASH}" ]; then
+ HASH_FAIL=1
+ echo "--Mac Hash mismatch: expected \"${HASH}\" found \"${MAC}\""
+ fi
+ fi
+ # check the KDF
+ if [[ "${line}" =~ "KDF algorithm: ".* ]]; then
+ KDF="${line##KDF algorithm: }"
+ if [ "${KDF}" != "HMAC ${HASH}" ]; then
+ HASH_FAIL=1
+ echo "--KDF Hash mismatch: expected \"HMAC ${HASH}\" found \"${KDF}\""
+ fi
+ fi
+ # Content Encryption Algorithm is the PKCS #5 algorithm ID.
+ if [[ "${line}" =~ .*"Encryption Algorithm: ".* ]]; then
+ # Strip the [Content ]EncryptionAlgorithm
+ ENCRYPTION="${line##Content }"
+ ENCRYPTION="${ENCRYPTION##Encryption Algorithm: }"
+ # If that algorithm id is PKCS #5 V2, then skip forward looking
+ # for the Cipher: field.
+ if [[ "${ENCRYPTION}" =~ "PKCS #5 Password Based Encryption v2"\ * ]]; then
+ continue;
+ fi
+ case ${STATE} in
+ "KEY")
+ KEY_ENCRYPTION_NOT_FOUND=0
+ if [ "${KEY_ENCRYPTION}" != "${ENCRYPTION}" ]; then
+ KEY_ENCRYPTION_FAIL=1
+ echo "--Key encryption mismatch: expected \"${KEY_ENCRYPTION}\" found \"${ENCRYPTION}\""
+ fi
+ ;;
+ "CERT")
+ CERT_ENCRYPTION_NOT_FOUND=0
+ if [ "${CERT_ENCRYPTION}" != "${ENCRYPTION}" ]; then
+ CERT_ENCRYPTION_FAIL=1
+ echo "--Cert encryption mismatch: expected \"${CERT_ENCRYPTION}\" found \"${ENCRYPTION}\""
+ fi
+ ;;
+ esac
+ fi
+ # handle the PKCS 5 case
+ if [[ "${line}" =~ "Cipher: ".* ]]; then
+ ENCRYPTION="${line#Cipher: }"
+ case ${STATE} in
+ "KEY")
+ KEY_ENCRYPTION_NOT_FOUND=0
+ if [ "${KEY_ENCRYPTION}" != "${ENCRYPTION}" ]; then
+ KEY_ENCRYPTION_FAIL=1
+ echo "--Key encryption mismatch: expected \"${KEY_ENCRYPTION}\" found \"${ENCRYPTION}\""
+ fi
+ ;;
+ "CERT")
+ CERT_ENCRYPTION_NOT_FOUND=0
+ if [ "${CERT_ENCRYPTION}" != "${ENCRYPTION}" ]; then
+ CERT_ENCRYPTION_FAIL=1
+ echo "--Cert encryption mismatch: expected \"${CERT_ENCRYPTION}\" found \"${ENCRYPTION}\""
+ fi
+ ;;
+ esac
+ fi
+ done < ${TMP}
+ IFS="${saveIFS}"
+ # we've scanned the file, set the return value to a combination of
+ # KEY and CERT state variables. If everything is as expected, they should
+ # add up to 0.
+ ret=$((${HASH_FAIL} * 10000 + ${KEY_ENCRYPTION_FAIL} * 1000 + ${KEY_ENCRYPTION_NOT_FOUND} * 100 + ${CERT_ENCRYPTION_FAIL} * 10 + ${CERT_ENCRYPTION_NOT_FOUND}))
+ rm -r ${TMP}
+ html_msg $ret 0 "Verifying p12 file generated with [${2}:${3}:${4}]"
+}
+
+#
+# this handles any mapping we need from requested cipher to
+# actual cipher. For instance ciphers which already have
+# PKCS 5 v1 PBE will be mapped to those pbes by pk12util.
+map_cipher()
+{
+ if [ "${1}" = "default" ]; then
+ echo "${2}"
+ return
+ fi
+ case "${1}" in
+ # these get mapped to the PKCS5 v1 or PKCS 12 attributes, not PKCS 5v2
+ RC2-CBC)
+ echo "${pkcs12v2pbeWithSha1And128BitRc2Cbc}"
+ return ;;
+ DES-EDE3-CBC)
+ echo "${pkcs12v2pbeWithSha1AndTripleDESCBC}"
+ return;;
+ esac
+ echo "${1}"
+}
+
############################## tools_sign ##############################
# local shell function to test basic functionality of signtool
########################################################################
@@ -554,7 +688,7 @@ tools_modutil()
}
############################## tools_cleanup ###########################
-# local shell function to finish this script (no exit since it might be
+# local shell function to finish this script (no exit since it might be
# sourced)
########################################################################
tools_cleanup()