diff options
Diffstat (limited to 'cmd/lib/secutil.c')
-rw-r--r-- | cmd/lib/secutil.c | 630 |
1 files changed, 574 insertions, 56 deletions
diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c index 7fb041ec7..d9270ed92 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 @@ loser: 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 @@ cleanup: 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; +} |