Files
Mozilla/mozilla/security/nss/cmd/lib/pppolicy.c
nelsonb%netscape.com 14340b9719 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


git-svn-id: svn://10.0.0.236/trunk@152050 18797224-902f-48f8-a5cc-f745e15eee43
2004-01-29 22:45:20 +00:00

296 lines
8.6 KiB
C

/*
* 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: pppolicy.c,v 1.1 2004-01-29 22:45:20 nelsonb%netscape.com Exp $
*/
#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);
}
}