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