diff options
author | nelsonb%netscape.com <devnull@localhost> | 2004-01-29 22:45:20 +0000 |
---|---|---|
committer | nelsonb%netscape.com <devnull@localhost> | 2004-01-29 22:45:20 +0000 |
commit | a6874a4fb746bab5589456b2e5a117efb065d108 (patch) | |
tree | 4c94ed3df288abf3f2cb2baded69ac730c069013 | |
parent | 3992fc052de8e693a8f00bbb49fdcdaf063aa663 (diff) | |
download | nss-hg-a6874a4fb746bab5589456b2e5a117efb065d108.tar.gz |
Bug 132942. r=wtc
Make the following enhancements to NSS's ASN.1 printing code:
- Print warning messages that are properly indendented.
- PrintAsHex notices when the buffer contains entirely printable characters, and is larger than an int, and prints it as text in that case.
- PrintRawString now indents the string, rather than always printing it on
a separate line.
- now prints decoded bit strings
- now prints BMP (UCS2) strings as strings (not as hex) when they contain only printable ASCII characters.
- now prints Universal (UCS4) Strings as strings (not hex) when they contain only printable ASCII characters.
- Decodes certain encoded data that was previously printed as hex.
- Generically decodes ASN.1 data, rather than merely printing an error, when the ASN.1 data doesn't fit a known template.
- properly handles all optional components of basic constraints extensions.
- Prints the names of the bits in the X509 Key Usage extension.
- Prints General Names.
- Print Auth Key ID extensions
- Print subject and issuer alt name extensions
- Print CRL distribution points extensions
- format and print name constraints extensions
- print Authority Information Access extensions
- Print optional X509v2 subject and issuer Unique ID bit strings
-rw-r--r-- | security/nss/cmd/lib/manifest.mn | 2 | ||||
-rw-r--r-- | security/nss/cmd/lib/moreoids.c | 177 | ||||
-rw-r--r-- | security/nss/cmd/lib/pppolicy.c | 295 | ||||
-rw-r--r-- | security/nss/cmd/lib/secutil.c | 714 | ||||
-rw-r--r-- | security/nss/cmd/lib/secutil.h | 9 |
5 files changed, 1030 insertions, 167 deletions
diff --git a/security/nss/cmd/lib/manifest.mn b/security/nss/cmd/lib/manifest.mn index 9df34a5df..a45e42c2d 100644 --- a/security/nss/cmd/lib/manifest.mn +++ b/security/nss/cmd/lib/manifest.mn @@ -45,6 +45,8 @@ EXPORTS = secutil.h \ CSRCS = secutil.c \ secpwd.c \ derprint.c \ + moreoids.c \ + pppolicy.c \ secerror.c \ ffs.c \ $(NULL) diff --git a/security/nss/cmd/lib/moreoids.c b/security/nss/cmd/lib/moreoids.c new file mode 100644 index 000000000..a7a78e8d3 --- /dev/null +++ b/security/nss/cmd/lib/moreoids.c @@ -0,0 +1,177 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2004 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secoid.h" +#include "secmodt.h" /* for CKM_INVALID_MECHANISM */ + +#define OI(x) { siDEROID, (unsigned char *)x, sizeof x } +#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext } +#define ODN(oid,desc) \ + { OI(oid), 0, desc, CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION } + +#define OIDT static const unsigned char + +/* OIW Security Special Interest Group defined algorithms. */ +#define OIWSSIG 0x2B, 13, 3, 2 + +OIDT oiwMD5RSA[] = { OIWSSIG, 3 }; +OIDT oiwDESCBC[] = { OIWSSIG, 7 }; +OIDT oiwRSAsig[] = { OIWSSIG, 11 }; +OIDT oiwDSA [] = { OIWSSIG, 12 }; +OIDT oiwMD5RSAsig[] = { OIWSSIG, 25 }; +OIDT oiwSHA1 [] = { OIWSSIG, 26 }; +OIDT oiwDSASHA1[] = { OIWSSIG, 27 }; +OIDT oiwDSASHA1param[] = { OIWSSIG, 28 }; +OIDT oiwSHA1RSA[] = { OIWSSIG, 29 }; + + +/* Microsoft OIDs. (1 3 6 1 4 1 311 ... ) */ +#define MICROSOFT 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37 + +OIDT mCTL[] = { MICROSOFT, 10, 3, 1 }; /* Cert Trust List signing */ +OIDT mTSS[] = { MICROSOFT, 10, 3, 2 }; /* Time Stamp Signing */ +OIDT mSGC[] = { MICROSOFT, 10, 3, 3 }; /* Server gated cryptography */ +OIDT mEFS[] = { MICROSOFT, 10, 3, 4 }; /* Encrypted File System */ +OIDT mSMIME[] = { MICROSOFT, 16, 4 }; /* SMIME encryption key prefs */ + +OIDT mECRTT[] = { MICROSOFT, 20, 2 }; /* Enrollment cert type xtn */ +OIDT mEAGNT[] = { MICROSOFT, 20, 2, 1 }; /* Enrollment Agent */ +OIDT mKPSCL[] = { MICROSOFT, 20, 2, 2 }; /* KP SmartCard Logon */ +OIDT mNTPN [] = { MICROSOFT, 20, 2, 3 }; /* NT Principal Name */ +OIDT mCASRV[] = { MICROSOFT, 21, 1 }; /* CertServ CA version */ + +/* AOL OIDs (1 3 6 1 4 1 1066 ... ) */ +#define AOL 0x2B, 0x06, 0x01, 0x04, 0x01, 0x88, 0x2A + +/* PKIX IDs (1 3 6 1 5 5 7 ...) */ +#define ID_PKIX 0x2B, 6, 1, 5, 5, 7 +/* PKIX Access Descriptors (methods for Authority Info Access Extns) */ +#define ID_AD ID_PKIX, 48 + +OIDT padOCSP[] = { ID_AD, 1 }; /* OCSP method */ +OIDT padCAissuer[] = { ID_AD, 2 }; /* URI (for CRL ?) */ +OIDT padTimeStamp[] = { ID_AD, 3 }; /* time stamping */ + +/* ISO Cert Extension type OIDs (id-ce) (2 5 29 ...) */ +#define X500 0x55 +#define X520_ATTRIBUTE_TYPE X500, 0x04 +#define X500_ALG X500, 0x08 +#define X500_ALG_ENCRYPTION X500_ALG, 0x01 +#define ID_CE X500, 29 + +OIDT cePlcyObs[] = { ID_CE, 3 }; /* Cert policies, obsolete. */ +OIDT cePlcyCns[] = { ID_CE, 36 }; /* Cert policy constraints. */ + +/* US Company arc (2 16 840 1 ...) */ +#define USCOM 0x60, 0x86, 0x48, 0x01 +#define USGOV USCOM, 0x65 +#define USDOD USGOV, 2 +#define ID_INFOSEC USDOD, 1 + +/* Verisign PKI OIDs (2 16 840 1 113733 1 ...) */ +#define VERISIGN_PKI USCOM, 0x86, 0xf8, 0x45, 1 +#define VERISIGN_XTN VERISIGN_PKI, 6 +#define VERISIGN_POL VERISIGN_PKI, 7 /* Cert policies */ +#define VERISIGN_TNET VERISIGN_POL, 23 /* Verisign Trust Network */ + +OIDT vcx7[] = { VERISIGN_XTN, 7 }; /* Cert Extension 7 (?) */ +OIDT vcp1[] = { VERISIGN_TNET, 1 }; /* class 1 cert policy */ +OIDT vcp2[] = { VERISIGN_TNET, 2 }; /* class 2 cert policy */ +OIDT vcp3[] = { VERISIGN_TNET, 3 }; /* class 3 cert policy */ +OIDT vcp4[] = { VERISIGN_TNET, 4 }; /* class 4 cert policy */ + + +/* ------------------------------------------------------------------- */ +static const SECOidData oids[] = { +/* OIW Security Special Interest Group OIDs */ + ODN( oiwMD5RSA, "OIWSecSIG MD5 with RSA"), + ODN( oiwDESCBC, "OIWSecSIG DES CBC"), + ODN( oiwRSAsig, "OIWSecSIG RSA signature"), + ODN( oiwDSA , "OIWSecSIG DSA"), + ODN( oiwMD5RSAsig, "OIWSecSIG MD5 with RSA signature"), + ODN( oiwSHA1 , "OIWSecSIG SHA1"), + ODN( oiwDSASHA1, "OIWSecSIG DSA with SHA1"), + ODN( oiwDSASHA1param, "OIWSecSIG DSA with SHA1 with params"), + ODN( oiwSHA1RSA, "OIWSecSIG MD5 with RSA"), + +/* Microsoft OIDs */ + ODN( mCTL, "Microsoft Cert Trust List signing"), + ODN( mTSS, "Microsoft Time Stamp signing"), + ODN( mSGC, "Microsoft SGC SSL server"), + ODN( mEFS, "Microsoft Encrypted File System"), + ODN( mSMIME, "Microsoft SMIME preferences"), + ODN( mECRTT, "Microsoft Enrollment Cert Type Extension"), + ODN( mEAGNT, "Microsoft Enrollment Agent"), + ODN( mKPSCL, "Microsoft KP SmartCard Logon"), + ODN( mNTPN, "Microsoft NT Principal Name"), + ODN( mCASRV, "Microsoft CertServ CA version"), + +/* PKIX OIDs */ + ODN( padOCSP, "PKIX OCSP method"), + ODN( padCAissuer, "PKIX CA Issuer method"), + ODN( padTimeStamp, "PKIX Time Stamping method"), + +/* ID_CE OIDs. */ + ODN( cePlcyObs, "Certificate Policies (Obsolete)"), + ODN( cePlcyCns, "Certificate Policy Constraints"), + +/* Verisign OIDs. */ + ODN( vcx7, "Verisign Cert Extension 7 (?)"), + ODN( vcp1, "Verisign Class 1 Certificate Policy"), + ODN( vcp2, "Verisign Class 2 Certificate Policy"), + ODN( vcp3, "Verisign Class 3 Certificate Policy"), + ODN( vcp4, "Verisign Class 4 Certificate Policy"), + +}; + +static const unsigned int numOids = (sizeof oids) / (sizeof oids[0]); + +SECStatus +SECU_RegisterDynamicOids(void) +{ + unsigned int i; + SECStatus rv = SECSuccess; + + for (i = 0; i < numOids; ++i) { + SECOidTag tag = SECOID_AddEntry(&oids[i]); + if (tag == SEC_OID_UNKNOWN) { + rv = SECFailure; +#ifdef DEBUG_DYN_OIDS + fprintf(stderr, "Add OID[%d] failed\n", i); + } else { + fprintf(stderr, "Add OID[%d] returned tag %d\n", i, tag); +#endif + } + } + return rv; +} diff --git a/security/nss/cmd/lib/pppolicy.c b/security/nss/cmd/lib/pppolicy.c new file mode 100644 index 000000000..71a036d8d --- /dev/null +++ b/security/nss/cmd/lib/pppolicy.c @@ -0,0 +1,295 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2004 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * Support for various policy related extensions + * + * $Id$ + */ + +#include "seccomon.h" +#include "secport.h" +#include "secder.h" +#include "cert.h" +#include "secoid.h" +#include "secasn1.h" +#include "secerr.h" +#include "nspr.h" +#include "secutil.h" + +/* This implementation is derived from the one in nss/lib/certdb/policyxtn.c . +** The chief difference is the addition of the OPTIONAL flag to many +** parts. The idea is to be able to parse and print as much of the +** policy extension as possible, even if some parts are invalid. +** +** If this approach still is unable to decode policy extensions that +** contain invalid parts, then the next approach will be to parse +** the PolicyInfos as a SEQUENCE of ANYs, and then parse each of them +** as PolicyInfos, with the PolicyQualifiers being ANYs, and finally +** parse each of the PolicyQualifiers. +*/ + +static const SEC_ASN1Template secu_PolicyQualifierTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyQualifier) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyQualifier, qualifierID) }, + { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyQualifier, qualifierValue) }, + { 0 } +}; + +static const SEC_ASN1Template secu_PolicyInfoTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTPolicyInfo) }, + { SEC_ASN1_OBJECT_ID, + offsetof(CERTPolicyInfo, policyID) }, + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL, + offsetof(CERTPolicyInfo, policyQualifiers), + secu_PolicyQualifierTemplate }, + { 0 } +}; + +static const SEC_ASN1Template secu_CertificatePoliciesTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, + offsetof(CERTCertificatePolicies, policyInfos), + secu_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) } +}; + + +static CERTCertificatePolicies * +secu_DecodeCertificatePoliciesExtension(SECItem *extnValue) +{ + PRArenaPool *arena = NULL; + SECStatus rv; + CERTCertificatePolicies *policies; + CERTPolicyInfo **policyInfos, *policyInfo; + CERTPolicyQualifier **policyQualifiers, *policyQualifier; + SECItem newExtnValue; + + /* make a new arena */ + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + + /* allocate the certifiate policies structure */ + policies = PORT_ArenaZNew(arena, CERTCertificatePolicies); + if ( policies == NULL ) { + goto loser; + } + + policies->arena = arena; + + /* copy the DER into the arena, since Quick DER returns data that points + into the DER input, which may get freed by the caller */ + rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue); + if ( rv != SECSuccess ) { + goto loser; + } + + /* decode the policy info */ + rv = SEC_QuickDERDecodeItem(arena, policies, + secu_CertificatePoliciesTemplate, + &newExtnValue); + + if ( rv != SECSuccess ) { + goto loser; + } + + /* initialize the oid tags */ + policyInfos = policies->policyInfos; + while (policyInfos != NULL && *policyInfos != NULL ) { + policyInfo = *policyInfos; + policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID); + policyQualifiers = policyInfo->policyQualifiers; + while ( policyQualifiers && *policyQualifiers != NULL ) { + policyQualifier = *policyQualifiers; + policyQualifier->oid = + SECOID_FindOIDTag(&policyQualifier->qualifierID); + policyQualifiers++; + } + policyInfos++; + } + + return(policies); + +loser: + if ( arena != NULL ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return(NULL); +} + + +static char * +itemToString(SECItem *item) +{ + char *string; + + string = PORT_ZAlloc(item->len+1); + if (string == NULL) return NULL; + PORT_Memcpy(string,item->data,item->len); + string[item->len] = 0; + return string; +} + +static SECStatus +secu_PrintUserNoticeQualifier(FILE *out, SECItem * qualifierValue, + char *msg, int level) +{ + CERTUserNotice *userNotice = NULL; + if (qualifierValue) + userNotice = CERT_DecodeUserNotice(qualifierValue); + if (userNotice) { + if (userNotice->noticeReference.organization.len != 0) { + char *string = + itemToString(&userNotice->noticeReference.organization); + SECItem **itemList = userNotice->noticeReference.noticeNumbers; + + while (itemList && *itemList) { + SECU_PrintInteger(out,*itemList,string,level+1); + itemList++; + } + PORT_Free(string); + } + if (userNotice->displayText.len != 0) { + SECU_PrintString(out,&userNotice->displayText, + "Display Text", level+1); + } + return SECSuccess; + } + return SECFailure; /* caller will print this value */ +} + +static SECStatus +secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier, + char *msg,int level) +{ + SECStatus rv; + SECItem * qualifierValue = &policyQualifier->qualifierValue; + + SECU_PrintObjectID(out, &policyQualifier->qualifierID , + "Policy Qualifier Name", level); + if (!qualifierValue->data) { + SECU_Indent(out, level); + fprintf(out,"Error: missing qualifier\n"); + } else + switch (policyQualifier->oid) { + case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: + rv = secu_PrintUserNoticeQualifier(out, qualifierValue, msg, level); + if (SECSuccess == rv) + break; + /* fall through on error */ + case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: + default: + SECU_PrintAny(out, qualifierValue, "Policy Qualifier Data", level); + break; + } + return SECSuccess; +} + +static SECStatus +secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level) +{ + CERTPolicyQualifier **policyQualifiers; + + policyQualifiers = policyInfo->policyQualifiers; + SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); + + while (policyQualifiers && *policyQualifiers != NULL) { + secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); + policyQualifiers++; + } + return SECSuccess; +} + +void +SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCertificatePolicies *policies = NULL; + CERTPolicyInfo **policyInfos; + + if (msg) { + SECU_Indent(out, level); + fprintf(out,"%s: \n",msg); + level++; + } + policies = secu_DecodeCertificatePoliciesExtension(value); + if (policies == NULL) { + SECU_PrintAny(out, value, "Invalid Policy Data", level); + return; + } + + policyInfos = policies->policyInfos; + while (policyInfos && *policyInfos != NULL) { + secu_PrintPolicyInfo(out,*policyInfos,"",level); + policyInfos++; + } + + CERT_DestroyCertificatePoliciesExtension(policies); +} + + +void +SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + char *msg, int level) +{ + CERTPrivKeyUsagePeriod * prd; + PLArenaPool * arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + goto loser; + } + prd = CERT_DecodePrivKeyUsagePeriodExtension(arena, value); + if (!prd) { + goto loser; + } + if (prd->notBefore.data) { + SECU_PrintGeneralizedTime(out, &prd->notBefore, "Not Before", level); + } + if (prd->notAfter.data) { + SECU_PrintGeneralizedTime(out, &prd->notAfter, "Not After ", level); + } + if (!prd->notBefore.data && !prd->notAfter.data) { + SECU_Indent(out, level); + fprintf(out, "Error: notBefore or notAfter MUST be present.\n"); +loser: + SECU_PrintAny(out, value, msg, level); + } + if (arena) { + PORT_FreeArena(arena, PR_FALSE); + } +} diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c index c21e8f56e..c76ce1894 100644 --- a/security/nss/cmd/lib/secutil.c +++ b/security/nss/cmd/lib/secutil.c @@ -46,6 +46,7 @@ #include "prprf.h" #include "plgetopt.h" #include "prenv.h" +#include "prnetdb.h" #include "secutil.h" #include "secpkcs7.h" @@ -84,6 +85,8 @@ static char consoleName[] = { #endif }; +static int OIDsAdded; + char * SECU_GetString(int16 error_number) @@ -95,6 +98,26 @@ SECU_GetString(int16 error_number) } void +SECU_PrintErrMsg(FILE *out, int level, char *progName, char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + SECU_Indent(out, level); + fprintf(out, "%s: ", progName); + vfprintf(out, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(out, ": %s\n", errString); + else + fprintf(out, ": error %d\n", (int)err); + + va_end(args); +} + +void SECU_PrintError(char *progName, char *msg, ...) { va_list args; @@ -531,9 +554,11 @@ secu_StdinToItem(SECItem *dst) break; if (dst->data) { - /* XXX if PORT_Realloc fails, the old buffer is leaked. */ - dst->data = (unsigned char*)PORT_Realloc(dst->data, - dst->len + numBytes); + unsigned char * p = dst->data; + dst->data = (unsigned char*)PORT_Realloc(p, dst->len + numBytes); + if (!dst->data) { + PORT_Free(p); + } } else { dst->data = (unsigned char*)PORT_Alloc(numBytes); } @@ -687,6 +712,7 @@ void SECU_Indent(FILE *out, int level) { int i; + for (i = 0; i < level; i++) { fprintf(out, " "); } @@ -702,7 +728,9 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) { unsigned i; int column; - PRBool isString = PR_TRUE; + PRBool isString = PR_TRUE; + PRBool isWhiteSpace = PR_TRUE; + PRBool printedHex = PR_FALSE; unsigned int limit = 15; if ( m ) { @@ -711,6 +739,10 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) } SECU_Indent(out, level); column = level*INDENT_MULT; + if (!data->len) { + fprintf(out, "(empty)\n"); + return; + } /* take a pass to see if it's all printable. */ for (i = 0; i < data->len; i++) { unsigned char val = data->data[i]; @@ -718,9 +750,18 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) isString = PR_FALSE; break; } + if (isWhiteSpace && !isspace(val)) { + isWhiteSpace = PR_FALSE; + } } - if (!isString) + /* Short values, such as bit strings (which are printed with this + ** function) often look like strings, but we want to see the bits. + ** so this test assures that short values will be printed in hex, + ** perhaps in addition to being printed as strings. + ** The threshold size (4 bytes) is arbitrary. + */ + if (!isString || data->len <= 4) { for (i = 0; i < data->len; i++) { if (i != data->len - 1) { fprintf(out, "%02x:", data->data[i]); @@ -736,7 +777,14 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) column = level*INDENT_MULT; limit = i % 16; } - } else { + } + printedHex = PR_TRUE; + } + if (isString && !isWhiteSpace) { + if (printedHex != PR_FALSE) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } for (i = 0; i < data->len; i++) { unsigned char val = data->data[i]; @@ -865,11 +913,13 @@ secu_PrintRawString(FILE *out, SECItem *si, char *m, int level) unsigned int i; if ( m ) { - SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_Indent(out, level); fprintf(out, "%s: ", m); + column = (level * INDENT_MULT) + strlen(m) + 2; level++; + } else { + SECU_Indent(out, level); + column = level*INDENT_MULT; } - - SECU_Indent(out, level); column = level*INDENT_MULT; fprintf(out, "\""); column++; for (i = 0; i < si->len; i++) { @@ -1007,7 +1057,6 @@ SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level) } } -static void secu_PrintAny(FILE *out, SECItem *i, char *m, int level); /* This prints a SET or SEQUENCE */ void @@ -1059,7 +1108,7 @@ SECU_PrintSet(FILE *out, SECItem *t, char *m, int level) } my.data += tmp.len; my.len -= tmp.len; - secu_PrintAny(out, &tmp, NULL, level + 1); + SECU_PrintAny(out, &tmp, NULL, level + 1); } SECU_Indent(out, level); fprintf(out, /* { */ "}\n"); } @@ -1122,6 +1171,25 @@ secu_PrintBitString(FILE *out, SECItem *i, char *m, int level) } } +/* in a decoded bit string, the len member is a bit length. */ +static void +secu_PrintDecodedBitString(FILE *out, SECItem *i, char *m, int level) +{ + int unused_bits; + SECItem tmp = *i; + + + unused_bits = (tmp.len & 0x7) ? 8 - (tmp.len & 7) : 0; + DER_ConvertBitString(&tmp); /* convert length to byte length */ + + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + + /* Print a DER encoded Boolean */ void SECU_PrintEncodedBoolean(FILE *out, SECItem *i, char *m, int level) @@ -1150,6 +1218,75 @@ SECU_PrintEncodedObjectID(FILE *out, SECItem *i, char *m, int level) } static void +secu_PrintBMPString(FILE *out, SECItem *i, char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 2) + goto loser; + len = (int)(my.len / 2); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 8) | s[1]; s += 2; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void +secu_PrintUniversalString(FILE *out, SECItem *i, char *m, int level) +{ + unsigned char * s; + unsigned char * d; + int len; + SECItem tmp = {0, 0, 0}; + SECItem my = *i; + + if (SECSuccess != SECU_StripTagAndLength(&my)) + goto loser; + if (my.len % 4) + goto loser; + len = (int)(my.len / 4); + tmp.data = (unsigned char *)PORT_Alloc(len); + if (!tmp.data) + goto loser; + tmp.len = len; + for (s = my.data, d = tmp.data ; len > 0; len--) { + PRUint32 bmpChar = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; + s += 4; + if (!isprint(bmpChar)) + goto loser; + *d++ = (unsigned char)bmpChar; + } + secu_PrintRawString(out, &tmp, m, level); + PORT_Free(tmp.data); + return; + +loser: + SECU_PrintAsHex(out, i, m, level); + if (tmp.data) + PORT_Free(tmp.data); +} + +static void secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level) { switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { @@ -1190,15 +1327,19 @@ secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level) secu_PrintBitString(out, i, m, level); break; case SEC_ASN1_BMP_STRING: + secu_PrintBMPString(out, i, m, level); + break; case SEC_ASN1_UNIVERSAL_STRING: + secu_PrintUniversalString(out, i, m, level); + break; default: SECU_PrintAsHex(out, i, m, level); break; } } -static void -secu_PrintAny(FILE *out, SECItem *i, char *m, int level) +void +SECU_PrintAny(FILE *out, SECItem *i, char *m, int level) { if ( i && i->len && i->data ) { switch (i->data[0] & SEC_ASN1_CLASS_MASK) { @@ -1290,7 +1431,7 @@ secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) while ((value = attr->values[i++]) != NULL) { sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); if (attr->encoded || attr->typeTag == NULL) { - SECU_PrintAsHex(out, value, om, level+1); + SECU_PrintAny(out, value, om, level+1); } else { switch (attr->typeTag->offset) { default: @@ -1311,18 +1452,14 @@ secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) static void secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) { -#if 0 /* - * um, yeah, that might be nice, but if you look at the callers - * you will see that they do not *set* this, so this will not work! - * Instead, somebody needs to fix the callers to be smarter about - * public key stuff, if that is important. - */ - PORT_Assert(pk->keyType == rsaKey); -#endif SECU_Indent(out, level); fprintf(out, "%s:\n", m); SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); + if (pk->u.rsa.publicExponent.len == 1 && + pk->u.rsa.publicExponent.data[0] == 1) { + SECU_Indent(out, level +1); fprintf(out, "Error: INVALID RSA KEY!\n"); + } } static void @@ -1355,7 +1492,7 @@ secu_PrintECPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) } #endif /* NSS_ENABLE_ECC */ -static int +static void secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, CERTSubjectPublicKeyInfo *i, char *msg, int level) { @@ -1384,18 +1521,22 @@ secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, case dhKey: case fortezzaKey: case keaKey: + SECU_Indent(out, level); fprintf(out, "unable to format this SPKI algorithm type\n"); - break; + goto loser; default: + SECU_Indent(out, level); fprintf(out, "unknown SPKI algorithm type\n"); - break; + goto loser; } PORT_FreeArena(pk->arena, PR_FALSE); } else { - SECU_PrintError("Error", "Parsing public key"); + SECU_PrintErrMsg(out, level, "Error", "Parsing public key"); +loser: + if (i->subjectPublicKey.data) { + SECU_PrintAny(out, &i->subjectPublicKey, "Raw", level); + } } - - return 0; } static SECStatus @@ -1425,13 +1566,11 @@ secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) } static SECStatus -PrintExtKeyUsageExten (FILE *out, SECItem *value, char *msg, int level) +PrintExtKeyUsageExtension (FILE *out, SECItem *value, char *msg, int level) { CERTOidSequence *os; SECItem **op; - SECU_Indent(out, level); fprintf(out, "Extended Key Usage Extension:\n"); - os = CERT_DecodeOidSequence(value); if( (CERTOidSequence *)NULL == os ) { return SECFailure; @@ -1444,105 +1583,6 @@ PrintExtKeyUsageExten (FILE *out, SECItem *value, char *msg, int level) return SECSuccess; } -char * -itemToString(SECItem *item) -{ - char *string; - - string = PORT_ZAlloc(item->len+1); - if (string == NULL) return NULL; - PORT_Memcpy(string,item->data,item->len); - string[item->len] = 0; - return string; -} - -static SECStatus -secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier,char *msg,int level) -{ - CERTUserNotice *userNotice; - SECItem **itemList = NULL; - char *string; - - SECU_PrintObjectID(out, &policyQualifier->qualifierID , - "Policy Qualifier Name", level); - - switch (policyQualifier->oid) { - case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: - userNotice = CERT_DecodeUserNotice(&policyQualifier->qualifierValue); - if (userNotice) { - if (userNotice->noticeReference.organization.len != 0) { - string=itemToString(&userNotice->noticeReference.organization); - itemList = userNotice->noticeReference.noticeNumbers; - while (*itemList) { - SECU_PrintInteger(out,*itemList,string,level+1); - itemList++; - } - PORT_Free(string); - } - if (userNotice->displayText.len != 0) { - SECU_PrintString(out,&userNotice->displayText, - "Display Text", level+1); - } - break; - } - /* fall through on error */ - case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: - default: - secu_PrintAny(out, &policyQualifier->qualifierValue, - "Policy Qualifier Data", level+1); - break; - } - - return SECSuccess; - -} - -static SECStatus -secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level) -{ - CERTPolicyQualifier **policyQualifiers; - - policyQualifiers = policyInfo->policyQualifiers; - SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); - - while (*policyQualifiers != NULL) { - secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); - policyQualifiers++; - } - return SECSuccess; - -} - -static SECStatus -secu_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) -{ - CERTCertificatePolicies *policies = NULL; - CERTPolicyInfo **policyInfos; - - if (msg) { - SECU_Indent(out, level); - fprintf(out,"%s: \n",msg); - level++; - } - policies = CERT_DecodeCertificatePoliciesExtension(value); - if (policies == NULL) { - SECU_PrintAsHex(out, value, "Invalid Policy Data", level); - return SECFailure; - } - - policyInfos = policies->policyInfos; - while (*policyInfos != NULL) { - secu_PrintPolicyInfo(out,*policyInfos,"",level); - policyInfos++; - } - - CERT_DestroyCertificatePoliciesExtension(policies); - return SECSuccess; -} - -char *nsTypeBits[] = { -"SSL Client","SSL Server","S/MIME","Object Signing","Reserved","SSL CA","S/MIME CA","ObjectSigning CA" }; - static SECStatus secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { CERTBasicConstraints constraints; @@ -1554,14 +1594,29 @@ secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { } rv = CERT_DecodeBasicConstraintValue(&constraints,value); if (rv == SECSuccess && constraints.isCA) { - fprintf(out,"Is a CA with a maximum path length of %d.\n", - constraints.pathLenConstraint); + if (constraints.pathLenConstraint >= 0) { + fprintf(out,"Is a CA with a maximum path length of %d.\n", + constraints.pathLenConstraint); + } else { + fprintf(out,"Is a CA with no maximum path length.\n"); + } } else { fprintf(out,"Is not a CA.\n"); } return SECSuccess; } +static const char * const nsTypeBits[] = { + "SSL Client", + "SSL Server", + "S/MIME", + "Object Signing", + "Reserved", + "SSL CA", + "S/MIME CA", + "ObjectSigning CA" +}; + /* NSCertType is merely a bit string whose bits are displayed symbolically */ static SECStatus secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) @@ -1574,7 +1629,7 @@ secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) if ((my.data[0] != SEC_ASN1_BIT_STRING) || SECSuccess != SECU_StripTagAndLength(&my)) { - secu_PrintAny(out, value, "Data", level); + SECU_PrintAny(out, value, "Data", level); return SECSuccess; } @@ -1598,6 +1653,321 @@ secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) return SECSuccess; } +static const char * const usageBits[] = { + "Digital Signature", /* 0x80 */ + "Non-Repudiation", /* 0x40 */ + "Key Encipherment", /* 0x20 */ + "Data Encipherment", /* 0x10 */ + "Key Agreement", /* 0x08 */ + "Certificate Signing", /* 0x04 */ + "CRL Signing", /* 0x02 */ + "Encipher Only", /* 0x01 */ + "Decipher Only", /* 0x0080 */ + NULL +}; + +/* X509KeyUsage is merely a bit string whose bits are displayed symbolically */ +static void +secu_PrintX509KeyUsage(FILE *out, SECItem *value, char *msg, int level) +{ + int unused; + int usage; + int i; + int found = 0; + SECItem my = *value; + + if ((my.data[0] != SEC_ASN1_BIT_STRING) || + SECSuccess != SECU_StripTagAndLength(&my)) { + SECU_PrintAny(out, value, "Data", level); + return; + } + + unused = (my.len >= 2) ? (my.data[0] & 0x0f) : 0; + usage = (my.len == 2) ? (my.data[1] & (0xff << unused)) << 8 + : (my.data[1] << 8) | + (my.data[2] & (0xff << unused)); + + SECU_Indent(out, level); + fprintf(out, "Usages: "); + for (i=0; usageBits[i]; i++) { + if ( (0x8000 >> i) & usage) { + if (found) + SECU_Indent(out, level + 2); + fprintf(out, "%s\n", usageBits[i]); + found = 1; + } + } + if (!found) { + fprintf(out, "(none)\n"); + } +} + +static void +secu_PrintIPAddress(FILE *out, SECItem *value, char *msg, int level) +{ + PRStatus st; + PRNetAddr addr; + char addrBuf[80]; + + memset(&addr, 0, sizeof addr); + if (value->len == 4) { + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, value->data, value->len); + } else if (value->len == 16) { + addr.ipv6.family = PR_AF_INET6; + memcpy(addr.ipv6.ip.pr_s6_addr, value->data, value->len); + if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) { + /* convert to IPv4. */ + addr.inet.family = PR_AF_INET; + memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4); + memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad); + } + } else { + goto loser; + } + + st = PR_NetAddrToString(&addr, addrBuf, sizeof addrBuf); + if (st == PR_SUCCESS) { + SECU_Indent(out, level); + fprintf(out, "%s: %s\n", msg, addrBuf); + } else { +loser: + SECU_PrintAsHex(out, value, msg, level); + } +} + + +static void +secu_PrintGeneralName(FILE *out, CERTGeneralName *gname, char *msg, int level) +{ + char label[40]; + if (msg && msg[0]) { + SECU_Indent(out, level++); fprintf(out, "%s: \n", msg); + } + switch (gname->type) { + case certOtherName : + SECU_PrintAny( out, &gname->name.OthName.name, "Other Name", level); + SECU_PrintObjectID(out, &gname->name.OthName.oid, "OID", level+1); + break; + case certDirectoryName : + SECU_PrintName(out, &gname->name.directoryName, "Directory Name", level); + break; + case certRFC822Name : + secu_PrintRawString( out, &gname->name.other, "RFC822 Name", level); + break; + case certDNSName : + secu_PrintRawString( out, &gname->name.other, "DNS name", level); + break; + case certURI : + secu_PrintRawString( out, &gname->name.other, "URI", level); + break; + case certIPAddress : + secu_PrintIPAddress(out, &gname->name.other, "IP Address", level); + break; + case certRegisterID : + SECU_PrintObjectID( out, &gname->name.other, "Registered ID", level); + break; + case certX400Address : + SECU_PrintAny( out, &gname->name.other, "X400 Address", level); + break; + case certEDIPartyName : + SECU_PrintAny( out, &gname->name.other, "EDI Party", level); + break; + default: + PR_snprintf(label, sizeof label, "unknown type [%d]", + (int)gname->type - 1); + SECU_PrintAsHex(out, &gname->name.other, label, level); + break; + } +} + +static void +secu_PrintAuthKeyIDExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthKeyID *kid = NULL; + PLArenaPool *pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + kid = CERT_DecodeAuthKeyID(pool, value); + if (!kid) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + int keyIDPresent = (kid->keyID.data && kid->keyID.len); + int issuerPresent = kid->authCertIssuer != NULL; + int snPresent = (kid->authCertSerialNumber.data && + kid->authCertSerialNumber.len); + + if ((keyIDPresent && !issuerPresent && !snPresent) || + (!keyIDPresent && issuerPresent && snPresent)) { + /* all is well */ + } else { + SECU_Indent(out, level); + fprintf(out, + "Error: KeyID OR (Issuer AND Serial) must be present, not both.\n"); + } + if (keyIDPresent) + SECU_PrintAsHex(out, &kid->keyID, "Key ID", level); + if (issuerPresent) + secu_PrintGeneralName(out, kid->authCertIssuer, "Issuer", level); + if (snPresent) + SECU_PrintInteger(out, &kid->authCertSerialNumber, + "Serial Number", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAltNameExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTGeneralName * nameList; + CERTGeneralName * current; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + nameList = current = CERT_DecodeAltNameExtension(pool, value); + if (!current) { + if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { + /* Decoder found empty sequence, which is invalid. */ + PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); + } + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } else { + do { + secu_PrintGeneralName(out, current, msg, level); + current = CERT_GetNextGeneralName(current); + } while (current != nameList); + } + PORT_FreeArena(pool, PR_FALSE); +} + +static void +secu_PrintCRLDistPtsExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCrlDistributionPoints * dPoints; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + dPoints = CERT_DecodeCRLDistributionPoints(pool, value); + if (dPoints && dPoints->distPoints && dPoints->distPoints[0]) { + CRLDistributionPoint ** pPoints = dPoints->distPoints; + CRLDistributionPoint * pPoint; + while (NULL != (pPoint = *pPoints++)) { + if (pPoint->distPointType == generalName && + pPoint->distPoint.fullName != NULL) { + secu_PrintGeneralName(out, pPoint->distPoint.fullName, NULL, + level); +#if defined(LATER) + } else if (pPoint->distPointType == relativeDistinguishedName) { + /* print the relative name */ +#endif + } else if (pPoint->derDistPoint.data) { + SECU_PrintAny(out, &pPoint->derDistPoint, "Point", level); + } + if (pPoint->reasons.data) { + secu_PrintDecodedBitString(out, &pPoint->reasons, "Reasons", + level); + } + if (pPoint->crlIssuer) { + secu_PrintGeneralName(out, pPoint->crlIssuer, "Issuer", level); + } + } + } else { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Data", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintNameConstraintSubtree(FILE *out, CERTNameConstraint *value, + char *msg, int level) +{ + CERTNameConstraint *head = value; + SECU_Indent(out, level); fprintf(out, "%s Subtree:\n", msg); + level++; + do { + secu_PrintGeneralName(out, &value->name, NULL, level); + if (value->min.data) + SECU_PrintInteger(out, &value->min, "Minimum", level+1); + if (value->max.data) + SECU_PrintInteger(out, &value->max, "Maximum", level+1); + value = CERT_GetNextNameConstraint(value); + } while (value != head); +} + +static void +secu_PrintNameConstraintsExtension(FILE *out, SECItem *value, char *msg, int level) +{ + CERTNameConstraints * cnstrnts; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + cnstrnts = CERT_DecodeNameConstraintsExtension(pool, value); + if (!cnstrnts) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + if (cnstrnts->permited) + secu_PrintNameConstraintSubtree(out, cnstrnts->permited, + "Permitted", level); + if (cnstrnts->excluded) + secu_PrintNameConstraintSubtree(out, cnstrnts->excluded, + "Excluded", level); + } + PORT_FreeArena(pool, PR_FALSE); +} + + +static void +secu_PrintAuthorityInfoAcess(FILE *out, SECItem *value, char *msg, int level) +{ + CERTAuthInfoAccess **infos = NULL; + PLArenaPool * pool = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if (!pool) { + SECU_PrintError("Error", "Allocating new ArenaPool"); + return; + } + infos = CERT_DecodeAuthInfoAccessExtension(pool, value); + if (!infos) { + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, value, "Raw", level); + } else { + CERTAuthInfoAccess *info; + while (NULL != (info = *infos++)) { + if (info->method.data) { + SECU_PrintObjectID(out, &info->method, "Method", level); + } else { + SECU_Indent(out,level); + fprintf(out, "Error: missing method\n"); + } + if (info->location) { + secu_PrintGeneralName(out, info->location, "Location", level); + } else { + SECU_PrintAny(out, &info->derLocation, "Location", level); + } + } + } + PORT_FreeArena(pool, PR_FALSE); +} + + void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, char *msg, int level) @@ -1627,7 +1997,7 @@ SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, secu_PrintX509InvalidDate(out, tmpitem, "Date", level + 1); break; case SEC_OID_X509_CERTIFICATE_POLICIES: - secu_PrintPolicy(out, tmpitem, "Data", level +1); + SECU_PrintPolicy(out, tmpitem, "Data", level +1); break; case SEC_OID_NS_CERT_EXT_BASE_URL: case SEC_OID_NS_CERT_EXT_REVOCATION_URL: @@ -1653,12 +2023,33 @@ SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, case SEC_OID_X509_BASIC_CONSTRAINTS: secu_PrintBasicConstraints(out,tmpitem,"Data",level+1); break; - case SEC_OID_X509_EXT_KEY_USAGE: - PrintExtKeyUsageExten(out, tmpitem, NULL, level+1); + PrintExtKeyUsageExtension(out, tmpitem, NULL, level+1); + break; + case SEC_OID_X509_KEY_USAGE: + secu_PrintX509KeyUsage(out, tmpitem, NULL, level + 1); + break; + case SEC_OID_X509_AUTH_KEY_ID: + secu_PrintAuthKeyIDExtension(out, tmpitem, NULL, level + 1); + break; + case SEC_OID_X509_SUBJECT_ALT_NAME: + case SEC_OID_X509_ISSUER_ALT_NAME: + secu_PrintAltNameExtension(out, tmpitem, NULL, level + 1); + break; + case SEC_OID_X509_CRL_DIST_POINTS: + secu_PrintCRLDistPtsExtension(out, tmpitem, NULL, level + 1); + break; + case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: + SECU_PrintPrivKeyUsagePeriodExtension(out, tmpitem, NULL, + level +1); + break; + case SEC_OID_X509_NAME_CONSTRAINTS: + secu_PrintNameConstraintsExtension(out, tmpitem, NULL, level+1); break; - case SEC_OID_X509_AUTH_INFO_ACCESS: + secu_PrintAuthorityInfoAcess(out, tmpitem, NULL, level+1); + break; + case SEC_OID_X509_CRL_NUMBER: case SEC_OID_X509_REASON_CODE: @@ -1679,38 +2070,23 @@ SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: case SEC_OID_PKIX_REGINFO_CERT_REQUEST: - case SEC_OID_EXT_KEY_USAGE_SERVER_AUTH: - case SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH: - case SEC_OID_EXT_KEY_USAGE_CODE_SIGN: - case SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT: - case SEC_OID_EXT_KEY_USAGE_TIME_STAMP: - case SEC_OID_X509_SUBJECT_ALT_NAME: - case SEC_OID_X509_ISSUER_ALT_NAME: - /* - * We should add at least some of the more interesting cases - * here, but need to have subroutines to back them up. - */ + + /* Netscape extension OIDs. */ case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: case SEC_OID_NS_CERT_EXT_USER_PICTURE: - case SEC_OID_NS_KEY_USAGE_GOVT_APPROVED: /* x.509 v3 Extensions */ case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: case SEC_OID_X509_SUBJECT_KEY_ID: - case SEC_OID_X509_KEY_USAGE: - case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: - case SEC_OID_X509_NAME_CONSTRAINTS: - case SEC_OID_X509_CRL_DIST_POINTS: case SEC_OID_X509_POLICY_MAPPINGS: case SEC_OID_X509_POLICY_CONSTRAINTS: - case SEC_OID_X509_AUTH_KEY_ID: default: - secu_PrintAny(out, tmpitem, "Data", level+1); + SECU_PrintAny(out, tmpitem, "Data", level+1); break; } @@ -1729,8 +2105,9 @@ SECU_PrintName(FILE *out, CERTName *name, char *msg, int level) SECItem my; str = nameStr = CERT_NameToAscii(name); - if (!str) + if (!str) { str = "!Invalid AVA!"; + } my.data = (unsigned char *)str; my.len = PORT_Strlen(str); #if 1 @@ -1835,13 +2212,11 @@ SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level) SECU_Indent(out, level); fprintf(out, "%s:\n", m); SECU_PrintInteger(out, &cr->version, "Version", level+1); SECU_PrintName(out, &cr->subject, "Subject", level+1); - rv = secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, + secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, "Subject Public Key Info", level+1); - if (rv) - goto loser; if (cr->attributes) - secu_PrintAny(out, cr->attributes[0], "Attributes", level+1); - + SECU_PrintAny(out, cr->attributes[0], "Attributes", level+1); + rv = 0; loser: PORT_FreeArena(arena, PR_FALSE); return rv; @@ -1865,9 +2240,12 @@ SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level) c->arena = arena; rv = SEC_ASN1DecodeItem(arena, c, SEC_ASN1_GET(CERT_CertificateTemplate), der); - if (rv) + if (rv) { + SECU_Indent(out, level); + SECU_PrintErrMsg(out, level, "Error", "Parsing extension"); + SECU_PrintAny(out, der, "Raw", level); goto loser; - + } /* Pretty print it out */ SECU_Indent(out, level); fprintf(out, "%s:\n", m); iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ @@ -1878,10 +2256,12 @@ SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level) SECU_PrintName(out, &c->issuer, "Issuer", level+1); secu_PrintValidity(out, &c->validity, "Validity", level+1); SECU_PrintName(out, &c->subject, "Subject", level+1); - rv = secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, + secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, "Subject Public Key Info", level+1); - if (rv) - goto loser; + if (c->issuerID.data) + secu_PrintDecodedBitString(out, &c->issuerID, "Issuer Unique ID", level+1); + if (c->subjectID.data) + secu_PrintDecodedBitString(out, &c->subjectID, "Subject Unique ID", level+1); SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); loser: PORT_FreeArena(arena, PR_FALSE); @@ -2775,7 +3155,7 @@ SECU_PrintPRandOSError(char *progName) if (errLen > 0 && errLen < sizeof buffer) { PR_GetErrorText(buffer); } - SECU_PrintError(progName, "NSS_Initialize failed"); + SECU_PrintError(progName, "function failed"); if (errLen > 0 && errLen < sizeof buffer) { PR_fprintf(PR_STDERR, "\t%s\n", buffer); } diff --git a/security/nss/cmd/lib/secutil.h b/security/nss/cmd/lib/secutil.h index 2cc7f289e..de7876f1b 100644 --- a/security/nss/cmd/lib/secutil.h +++ b/security/nss/cmd/lib/secutil.h @@ -266,6 +266,13 @@ extern int SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level); extern void SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level); +extern void SECU_PrintString(FILE *out, SECItem *si, char *m, int level); +extern void SECU_PrintAny(FILE *out, SECItem *i, char *m, int level); + +extern void SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level); +extern void SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value, + char *msg, int level); + extern void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, char *msg, int level); @@ -287,6 +294,8 @@ extern char *SECU_SECModDBName(void); extern void SECU_PrintPRandOSError(char *progName); +extern SECStatus SECU_RegisterDynamicOids(void); + /* * * Utilities for parsing security tools command lines |