Fix numerous errors (mostly off-by-1 errors) in the code that formats

and prints certs and CRLs.  This code is common to certutil and pp.
Bug 222568  r=nicholson (for this portion).
This commit is contained in:
nelsonb%netscape.com 2003-11-04 02:16:42 +00:00
Родитель 0fc82ad629
Коммит 0feb5dfd5f
1 изменённых файлов: 287 добавлений и 188 удалений

Просмотреть файл

@ -84,6 +84,7 @@ static char consoleName[] = {
#endif
};
char *
SECU_GetString(int16 error_number)
{
@ -645,6 +646,7 @@ SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
*trailer = '\0';
} else {
fprintf(stderr, "input has header but no trailer\n");
PORT_Free(filedata.data);
return SECFailure;
}
} else {
@ -656,9 +658,11 @@ SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
if (rv) {
fprintf(stderr, "error converting ascii to binary (%s)\n",
SECU_Strerror(PORT_GetError()));
PORT_Free(filedata.data);
return SECFailure;
}
PORT_Free(asc);
PORT_Free(filedata.data);
} else {
/* Read in binary der */
rv = SECU_FileToItem(der, inFile);
@ -692,6 +696,7 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
unsigned i;
int column;
PRBool isString = PR_TRUE;
unsigned int limit = 15;
if ( m ) {
SECU_Indent(out, level); fprintf(out, "%s:\n", m);
@ -699,12 +704,19 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
}
SECU_Indent(out, level); column = level*INDENT_MULT;
/* take a pass to see if it's all printable. */
for (i = 0; i < data->len; i++) {
unsigned char val = data->data[i];
if (!val || !isprint(val)) {
isString = PR_FALSE;
break;
}
}
if (!isString)
for (i = 0; i < data->len; i++) {
unsigned char val = data->data[i];
if (isString && val && !isprint(val)) {
isString = PR_FALSE;
}
if (i != data->len - 1) {
fprintf(out, "%02x:", data->data[i]);
column += 3;
@ -713,14 +725,13 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
column += 2;
break;
}
if (column > 76 || (i % 16 == 15)) {
if (column > 76 || (i % 16 == limit)) {
secu_Newline(out);
SECU_Indent(out, level); column = level*INDENT_MULT;
SECU_Indent(out, level);
column = level*INDENT_MULT;
limit = i % 16;
}
}
if (isString) {
secu_Newline(out);
SECU_Indent(out, level); column = level*INDENT_MULT;
} else {
for (i = 0; i < data->len; i++) {
unsigned char val = data->data[i];
@ -737,7 +748,6 @@ SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level)
}
}
level--;
if (column != level*INDENT_MULT) {
secu_Newline(out);
}
@ -796,6 +806,28 @@ SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len)
}
}
SECStatus
SECU_StripTagAndLength(SECItem *i)
{
unsigned int start;
if (!i || !i->data || i->len < 2) { /* must be at least tag and length */
return SECFailure;
}
start = ((i->data[1] & 0x80) ? (i->data[1] & 0x7f) + 2 : 2);
if (i->len < start) {
return SECFailure;
}
i->data += start;
i->len -= start;
return SECSuccess;
}
/* This expents i->data[0] to be the MSB of the integer.
** if you want to print a DER-encoded integer (with the tag and length)
** call SECU_PrintEncodedInteger();
*/
void
SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level)
{
@ -821,53 +853,61 @@ SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level)
}
}
void
SECU_PrintString(FILE *out, SECItem *i, char *m, int level)
static void
secu_PrintRawString(FILE *out, SECItem *si, char *m, int level)
{
char *string;
unsigned char *data = i->data;
int len = i->len;
int lenlen;
int tag;
int column;
unsigned int i;
string = PORT_ZAlloc(i->len+1);
tag = *data++; len--;
if (data[1] & 0x80) {
lenlen = data[1] & 0x1f;
} else {
lenlen = 1;
if ( m ) {
SECU_Indent(out, level); fprintf(out, "%s:\n", m);
level++;
}
data += lenlen; len -= lenlen;
if (len <= 0) return;
PORT_Memcpy(string,data,len);
/* should check the validity of tag, and convert the string as necessary */
SECU_Indent(out, level);
if (m) {
fprintf(out, "%s: \"%s\"\n", m, string);
} else {
fprintf(out, "\"%s\"\n", string);
SECU_Indent(out, level); column = level*INDENT_MULT;
fprintf(out, "\""); column++;
for (i = 0; i < si->len; i++) {
unsigned char val = si->data[i];
if (column > 76) {
secu_Newline(out);
SECU_Indent(out, level); column = level*INDENT_MULT;
}
fprintf(out,"%c", printable[val]); column++;
}
fprintf(out, "\""); column++;
if (column != level*INDENT_MULT || column > 76) {
secu_Newline(out);
}
}
void
SECU_PrintString(FILE *out, SECItem *si, char *m, int level)
{
SECItem my = *si;
if (SECSuccess != SECU_StripTagAndLength(&my) || !my.len)
return;
secu_PrintRawString(out, &my, m, level);
}
/* print an unencoded boolean */
static void
secu_PrintBoolean(FILE *out, SECItem *i, char *m, int level)
secu_PrintBoolean(FILE *out, SECItem *i, const char *m, int level)
{
int val = 0;
if ( i->data ) {
if ( i->data && i->len ) {
val = i->data[0];
}
if (m) {
SECU_Indent(out, level); fprintf(out, "%s:\n", m); level++;
}
if ( val ) {
SECU_Indent(out, level); fprintf(out, "%s\n", "True");
} else {
SECU_Indent(out, level); fprintf(out, "%s\n", "False");
if (!m) {
m = "Boolean";
}
SECU_Indent(out, level);
fprintf(out, "%s: %s\n", m, (val ? "True" : "False"));
}
/*
@ -964,100 +1004,112 @@ 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
SECU_PrintSet(FILE *out, SECItem *t, char *m, int level)
{
int type= t->data[0] & SEC_ASN1_TAGNUM_MASK;
int start;
unsigned char *bp;
int type = t->data[0] & SEC_ASN1_TAGNUM_MASK;
int constructed = t->data[0] & SEC_ASN1_CONSTRUCTED;
const char * label;
SECItem my = *t;
if (!constructed) {
SECU_PrintAsHex(out, t, m, level);
return;
}
if (SECSuccess != SECU_StripTagAndLength(&my))
return;
SECU_Indent(out, level);
if (m) {
fprintf(out, "%s: ", m);
}
fprintf(out,"%s {\n", type == SEC_ASN1_SET ? "Set" : "Sequence"); /* } */
if (type == SEC_ASN1_SET)
label = "Set ";
else if (type = SEC_ASN1_SEQUENCE)
label = "Sequence ";
else
label = "";
fprintf(out,"%s{\n", label); /* } */
start = 2;
if (t->data[1] & 0x80) {
start += (t->data[1] & 0x7f);
}
for (bp=&t->data[start]; bp < &t->data[t->len]; ) {
SECItem tmp;
unsigned int i,len,lenlen;
while (my.len >= 2) {
SECItem tmp = my;
if (bp[1] & 0x80) {
lenlen = bp[1] & 0x1f;
len = 0;
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++) {
len = len * 255 + bp[2+i];
tmp.len = (tmp.len << 8) | tmp.data[2+i];
}
tmp.len += lenlen + 2;
} else {
lenlen = 1;
len = bp[1];
tmp.len = tmp.data[1] + 2;
}
tmp.len = len+lenlen+1;
if (tmp.len > &t->data[t->len] - bp) {
tmp.len = &t->data[t->len] - bp;
if (tmp.len > my.len) {
tmp.len = my.len;
}
tmp.data = bp;
bp += tmp.len;
secu_PrintAny(out,&tmp,NULL,level+1);
my.data += tmp.len;
my.len -= tmp.len;
secu_PrintAny(out, &tmp, NULL, level + 1);
}
/* { */SECU_Indent(out, level); fprintf(out, "}\n");
SECU_Indent(out, level); fprintf(out, /* { */ "}\n");
}
static void
secu_PrintContextSpecific(FILE *out, SECItem *i, char *m, int level)
{
int type= i->data[0] & SEC_ASN1_TAGNUM_MASK;
int type = i->data[0] & SEC_ASN1_TAGNUM_MASK;
int constructed = i->data[0] & SEC_ASN1_CONSTRUCTED;
SECItem tmp;
int start;
if (constructed) {
char * m2;
if (!m)
m2 = PR_smprintf("[%d]", type);
else
m2 = PR_smprintf("%s: [%d]", m, type);
if (m2) {
SECU_PrintSet(out, i, m2, level);
PR_smprintf_free(m2);
}
return;
}
SECU_Indent(out, level);
if (m) {
fprintf(out, "%s: ", m);
}
fprintf(out,"[%d]\n", type);
start = 2;
if (i->data[1] & 0x80) {
start = (i->data[1] & 0x7f) +1;
}
tmp.data = &i->data[start];
tmp.len = i->len -start;
tmp = *i;
if (SECSuccess == SECU_StripTagAndLength(&tmp))
SECU_PrintAsHex(out, &tmp, m, level+1);
}
static void
secu_PrintOctetString(FILE *out, SECItem *i, char *m, int level)
{
SECItem tmp;
int start;
start = 2;
if (i->data[1] & 0x80) {
start = (i->data[1] & 0x7f) +1;
}
tmp.data = &i->data[start];
tmp.len = i->len - start;
SECItem tmp = *i;
if (SECSuccess == SECU_StripTagAndLength(&tmp))
SECU_PrintAsHex(out, &tmp, m, level);
}
static void
secu_PrintBitString(FILE *out, SECItem *i, char *m, int level)
{
SECItem tmp;
int start;
int unused_bits;
SECItem tmp = *i;
if (SECSuccess != SECU_StripTagAndLength(&tmp) || tmp.len < 2)
return;
unused_bits = *tmp.data++;
tmp.len--;
start = 2;
if (i->data[1] & 0x80) {
start = (i->data[1] & 0x7f) + 1;
}
unused_bits = i->data[start++];
tmp.data = &i->data[start];
tmp.len = i->len - start;
SECU_PrintAsHex(out, &tmp, m, level);
if (unused_bits) {
SECU_Indent(out, level + 1);
@ -1065,26 +1117,52 @@ secu_PrintBitString(FILE *out, SECItem *i, char *m, int level)
}
}
/* Print a DER encoded Boolean */
void
SECU_PrintEncodedBoolean(FILE *out, SECItem *i, char *m, int level)
{
SECItem my = *i;
if (SECSuccess == SECU_StripTagAndLength(&my))
secu_PrintBoolean(out, &my, m, level);
}
/* Print a DER encoded integer */
void
SECU_PrintEncodedInteger(FILE *out, SECItem *i, char *m, int level)
{
SECItem my = *i;
if (SECSuccess == SECU_StripTagAndLength(&my))
SECU_PrintInteger(out, &my, m, level);
}
/* Print a DER encoded OID */
void
SECU_PrintEncodedObjectID(FILE *out, SECItem *i, char *m, int level)
{
SECItem my = *i;
if (SECSuccess == SECU_StripTagAndLength(&my))
SECU_PrintObjectID(out, &my, m, level);
}
static void
secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level)
{
switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) {
case SEC_ASN1_ENUMERATED:
case SEC_ASN1_INTEGER:
SECU_PrintInteger(out, i, m, level);
SECU_PrintEncodedInteger(out, i, m, level);
break;
case SEC_ASN1_OBJECT_ID:
SECU_PrintObjectID(out, i, m, level);
SECU_PrintEncodedObjectID(out, i, m, level);
break;
case SEC_ASN1_BOOLEAN:
secu_PrintBoolean(out, i, m, level);
SECU_PrintEncodedBoolean(out, i, m, level);
break;
case SEC_ASN1_UTF8_STRING:
case SEC_ASN1_PRINTABLE_STRING:
case SEC_ASN1_VISIBLE_STRING:
case SEC_ASN1_BMP_STRING:
case SEC_ASN1_IA5_STRING:
case SEC_ASN1_T61_STRING:
case SEC_ASN1_UNIVERSAL_STRING:
SECU_PrintString(out, i, m, level);
break;
case SEC_ASN1_GENERALIZED_TIME:
@ -1106,6 +1184,8 @@ secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level)
case SEC_ASN1_BIT_STRING:
secu_PrintBitString(out, i, m, level);
break;
case SEC_ASN1_BMP_STRING:
case SEC_ASN1_UNIVERSAL_STRING:
default:
SECU_PrintAsHex(out, i, m, level);
break;
@ -1134,30 +1214,41 @@ static int
secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level)
{
SECU_Indent(out, level); fprintf(out, "%s:\n", m);
SECU_PrintUTCTime(out, &v->notBefore, "Not Before", level+1);
SECU_PrintUTCTime(out, &v->notAfter, "Not After", level+1);
SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level+1);
SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level+1);
return 0;
}
/* This function does NOT expect a DER type and length. */
void
SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level)
{
const char *name;
SECOidData *oiddata;
char * oidString = NULL;
oiddata = SECOID_FindOID(oid);
if (oiddata == NULL) {
SECU_PrintAsHex(out, oid, m, level);
return;
}
name = oiddata->desc;
if (oiddata != NULL) {
const char *name = oiddata->desc;
SECU_Indent(out, level);
if (m != NULL)
fprintf(out, "%s: ", m);
fprintf(out, "%s\n", name);
return;
}
oidString = CERT_GetOidString(oid);
if (oidString) {
SECU_Indent(out, level);
if (m != NULL)
fprintf(out, "%s: ", m);
fprintf(out, "%s\n", oidString);
PR_smprintf_free(oidString);
return;
}
SECU_PrintAsHex(out, oid, m, level);
}
/* This function does NOT expect a DER type and length. */
void
SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level)
{
@ -1204,7 +1295,7 @@ secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level)
SECU_PrintObjectID(out, value, om, level+1);
break;
case SEC_OID_PKCS9_SIGNING_TIME:
SECU_PrintUTCTime(out, value, om, level+1);
SECU_PrintTimeChoice(out, value, om, level+1);
break;
}
}
@ -1342,22 +1433,9 @@ PrintExtKeyUsageExten (FILE *out, SECItem *value, char *msg, int level)
}
for( op = os->oids; *op; op++ ) {
SECOidData *od = SECOID_FindOID(*op);
if( (SECOidData *)NULL == od ) {
SECU_Indent(out, level+1);
SECU_PrintAsHex(out, *op, "Unknown:", level+2);
secu_Newline(out);
continue;
SECU_PrintObjectID(out, *op, msg, level + 1);
}
SECU_Indent(out, level+1);
if( od->desc ) fprintf(out, "%s", od->desc);
else SECU_PrintAsHex(out, &od->oid, "", level+2);
secu_Newline(out);
}
CERT_DestroyOidSequence(os);
return SECSuccess;
}
@ -1405,7 +1483,8 @@ secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier,char *m
/* fall through on error */
case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
default:
secu_PrintAny(out, &policyQualifier->qualifierValue, "Policy Qualifier Data", level+1);
secu_PrintAny(out, &policyQualifier->qualifierValue,
"Policy Qualifier Data", level+1);
break;
}
@ -1478,37 +1557,39 @@ secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) {
return SECSuccess;
}
/* NSCertType is merely a bit string whose bits are displayed symbolically */
static SECStatus
secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) {
char NS_Type=0;
int len, i, found=0;
secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level)
{
int unused;
int NS_Type;
int i;
int found = 0;
SECItem my = *value;
if (value->data[1] & 0x80) {
len = 3;
} else {
len = value->data[1];
}
if ((value->data[0] != SEC_ASN1_BIT_STRING) || (len < 2)) {
if ((my.data[0] != SEC_ASN1_BIT_STRING) ||
SECSuccess != SECU_StripTagAndLength(&my)) {
secu_PrintAny(out, value, "Data", level);
return SECSuccess;
}
NS_Type=value->data[3];
unused = (my.len == 2) ? (my.data[0] & 0x0f) : 0;
NS_Type = my.data[1] & (0xff << unused);
if (msg) {
SECU_Indent(out, level);
if (msg) {
fprintf(out,"%s: ",msg);
} else {
SECU_Indent(out, level);
fprintf(out,"Netscape Certificate Type: ");
}
for (i=0; i < 8; i++) {
if ( (0x80 >> i) & NS_Type) {
fprintf(out,"%c%s",found?',':'<',nsTypeBits[i]);
fprintf(out, "%c%s", (found ? ',' : '<'), nsTypeBits[i]);
found = 1;
}
}
if (found) { fprintf(out,">\n"); } else { fprintf(out,"none\n"); }
fprintf(out, (found ? ">\n" : "none\n"));
return SECSuccess;
}
@ -1523,10 +1604,9 @@ SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
while ( *extensions ) {
SECItem *tmpitem;
SECU_Indent(out, level+1); fprintf(out, "Name:\n");
tmpitem = &(*extensions)->id;
SECU_PrintObjectID(out, tmpitem, NULL, level+2);
SECU_PrintObjectID(out, tmpitem, "Name", level+1);
tmpitem = &(*extensions)->critical;
if ( tmpitem->len ) {
@ -1570,7 +1650,7 @@ SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
break;
case SEC_OID_X509_EXT_KEY_USAGE:
PrintExtKeyUsageExten(out, tmpitem, "", level+1);
PrintExtKeyUsageExten(out, tmpitem, NULL, level+1);
break;
case SEC_OID_X509_AUTH_INFO_ACCESS:
@ -1640,15 +1720,21 @@ void
SECU_PrintName(FILE *out, CERTName *name, char *msg, int level)
{
char *str;
SECU_Indent(out, level); fprintf(out, "%s: ", msg);
SECItem my;
str = CERT_NameToAscii(name);
if (!str)
str = "!Invalid AVA!";
my.data = (unsigned char *)str;
my.len = PORT_Strlen(str);
#if 1
secu_PrintRawString(out, &my, msg, level);
#else
SECU_Indent(out, level); fprintf(out, "%s: ", msg);
fprintf(out, str);
secu_Newline(out);
#endif
PORT_Free(str);
}
void
@ -1694,13 +1780,13 @@ SECU_PrintCertNickname(CERTCertListNode *node, void *data)
out = (FILE *)data;
name = node->appData;
if ( name == NULL) {
if (!name || !name[0]) {
name = cert->nickname;
}
if ( name == NULL ) {
if (!name || !name[0]) {
name = cert->emailAddr;
}
if ( name == NULL ) {
if (!name || !name[0]) {
name = "(NULL)";
}
@ -1851,10 +1937,13 @@ SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
{
unsigned char fingerprint[20];
char *fpStr = NULL;
int err = PORT_GetError();
SECStatus rv;
SECItem fpItem;
/* print MD5 fingerprint */
memset(fingerprint, 0, sizeof fingerprint);
PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len);
rv = PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len);
fpItem.data = fingerprint;
fpItem.len = MD5_LENGTH;
fpStr = CERT_Hexify(&fpItem, 1);
@ -1862,9 +1951,12 @@ SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
PORT_Free(fpStr);
fpStr = NULL;
if (rv != SECSuccess && !err)
err = PORT_GetError();
/* print SHA1 fingerprint */
memset(fingerprint, 0, sizeof fingerprint);
PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
rv = PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len);
fpItem.data = fingerprint;
fpItem.len = SHA1_LENGTH;
fpStr = CERT_Hexify(&fpItem, 1);
@ -1872,6 +1964,12 @@ SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level)
SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr);
PORT_Free(fpStr);
fprintf(out, "\n");
if (err)
PORT_SetError(err);
if (err || rv != SECSuccess)
return SECFailure;
return 0;
}
@ -1989,11 +2087,15 @@ SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
char om[100];
SECU_Indent(out, level); fprintf(out, "%s:\n", m);
/* version is optional */
iv = crl->version.len ? DER_GetInteger(&crl->version) : 0;
SECU_Indent(out, level+1);
fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv);
SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm",
level + 1);
SECU_PrintName(out, &(crl->name), "Name", level + 1);
SECU_PrintUTCTime(out, &(crl->lastUpdate), "Last Update", level + 1);
SECU_PrintUTCTime(out, &(crl->nextUpdate), "Next Update", level + 1);
SECU_PrintName(out, &(crl->name), "Issuer", level + 1);
SECU_PrintTimeChoice(out, &(crl->lastUpdate), "This Update", level + 1);
SECU_PrintTimeChoice(out, &(crl->nextUpdate), "Next Update", level + 1);
if (crl->entries != NULL) {
iv = 0;
@ -2002,14 +2104,13 @@ SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level)
SECU_Indent(out, level + 1); fprintf(out, om);
SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number",
level + 2);
SECU_PrintUTCTime(out, &(entry->revocationDate), "Revocation Date",
level + 2);
SECU_PrintExtensions
(out, entry->extensions, "Signed CRL Entries Extensions", level + 1);
SECU_PrintTimeChoice(out, &(entry->revocationDate),
"Revocation Date", level + 2);
SECU_PrintExtensions(out, entry->extensions,
"Entry Extensions", level + 2);
}
}
SECU_PrintExtensions
(out, crl->extensions, "Signed CRL Extension", level + 1);
SECU_PrintExtensions(out, crl->extensions, "CRL Extensions", level + 1);
}
/*
@ -2428,16 +2529,14 @@ int SECU_PrintSignedData(FILE *out, SECItem *der, char *m,
SECU_Indent(out, level); fprintf(out, "%s:\n", m);
rv = (*inner)(out, &sd->data, "Data", level+1);
if (rv)
goto loser;
SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm",
level+1);
DER_ConvertBitString(&sd->signature);
SECU_PrintAsHex(out, &sd->signature, "Signature", level+1);
SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
loser:
PORT_FreeArena(arena, PR_FALSE);
SECU_PrintFingerprints(out, der, "Fingerprint", level+1);
return rv;
}
@ -2682,7 +2781,7 @@ bestCertName(CERTCertificate *cert) {
if (cert->nickname) {
return cert->nickname;
}
if (cert->emailAddr) {
if (cert->emailAddr && cert->emailAddr[0]) {
return cert->emailAddr;
}
return cert->subjectName;