Bug 259031, Add support for displaying certificate extensions

Patch provided by Martin v. Loewis
r=rrelyea r=kengert sr=shaver
This commit is contained in:
kaie%kuix.de 2005-12-02 22:29:14 +00:00
Родитель e6c12ea90c
Коммит abe3f8e6c5
2 изменённых файлов: 899 добавлений и 32 удалений

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

@ -175,6 +175,46 @@ CertDumpNonCritical=Not Critical
CertDumpSigAlg=Certificate Signature Algorithm
CertDumpCertSig=Certificate Signature Value
CertDumpExtensionFailure=Error: Unable to process extension
CertDumpIsCA=Is a Certificate Authority
CertDumpIsNotCA=Is not a Certificate Authority
CertDumpPathLen=Maximum number of intermediate CAs: %S
CertDumpEKU_1_3_6_1_5_5_7_3_1=TLS Web Server Authentication
CertDumpEKU_1_3_6_1_5_5_7_3_2=TLS Web Client Authentication
CertDumpEKU_1_3_6_1_5_5_7_3_3=Signing of downloadable executable code
CertDumpEKU_1_3_6_1_5_5_7_3_4=E-mail protection
CertDumpEKU_1_3_6_1_5_5_7_3_8=Time Stamping
CertDumpEKU_1_3_6_1_4_1_311_2_1_21=Microsoft Individual Code Signing (authenticode)
CertDumpEKU_1_3_6_1_4_1_311_2_1_22=Microsoft Commercial Code Signing (authenticode)
CertDumpEKU_1_3_6_1_4_1_311_10_3_1=Microsoft Trust List Signing
CertDumpEKU_1_3_6_1_4_1_311_10_3_2=Microsoft Timestamp Signing
CertDumpEKU_1_3_6_1_4_1_311_10_3_3=Microsoft Strong Crypto Approved
CertDumpMSCerttype=Microsoft CA Certificate Type
CertDumpEKU_1_3_6_1_4_1_311_10_3_4=Microsoft Encrypting Filesystem
CertDumpEKU_1_3_6_1_4_1_311_10_3_4_1=Microsoft Encrypting Filesystem Recovery Agent
CertDumpMSNTPrincipal=Microsoft NT User Principal Name
CertDumpMSCAVersion=Microsoft CA Version
CertDumpMSDomainGUID=Microsoft Domain GUID
CertDumpEKU_2_16_840_1_113730_4_1=Netscape Strong Crypto Approved
CertDumpRFC822Name=E-Mail Address
CertDumpDNSName=DNS Name
CertDumpX400Address=X.400 Address
CertDumpDirectoryName=X.500 Name
CertDumpEDIPartyName=EDI Party Name
CertDumpURI=URI
CertDumpIPAddress=IP Address
CertDumpRegisterID=Registered OID
CertDumpKeyID=Key ID
CertDumpVerisignNotices=Verisign User Notices
CertDumpUnused=Unused
CertDumpKeyCompromise=Key Compromise
CertDumpCACompromise=CA Compromise
CertDumpAffiliationChanged=Affiliation Changed
CertDumpSuperseded=Superseded
CertDumpCessation=Cessation of Operation
CertDumpHold=Certificate Hold
CertDumpCAIssuers=Authority Issuer Path
CertDumpCPSPointer=Certification Practice Statement pointer
CertDumpUserNotice=User Notice
VerifySSLClient_p=Client
VerifySSLServer_p=Server
VerifySSLStepUp_p=Step-up

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

@ -22,6 +22,7 @@
* Ian McGreer <mcgreer@netscape.com>
* Javier Delgadillo <javi@netscape.com>
* John Gardiner Myers <jgmyers@speakeasy.net>
* Martin v. Loewis <martin@v.loewis.de>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -55,6 +56,43 @@
static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
/* Object Identifier constants */
#define CONST_OID static const unsigned char
#define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37
CONST_OID msCertExtCerttype[] = { MICROSOFT_OID, 20, 2};
CONST_OID msNTPrincipalName[] = { MICROSOFT_OID, 20, 2, 3 };
CONST_OID msCertsrvCAVersion[] = { MICROSOFT_OID, 21, 1 };
CONST_OID msNTDSReplication[] = { MICROSOFT_OID, 25, 1 };
#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
#define OD(oid,desc,mech,ext) {OI(oid), SEC_OID_UNKNOWN, desc, mech, ext}
#define SEC_OID(tag) more_oids[tag].offset
static SECOidData more_oids[] = {
/* Microsoft OIDs */
#define MS_CERT_EXT_CERTTYPE 0
OD( msCertExtCerttype,
"Microsoft Certificate Type",
CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
#define MS_NT_PRINCIPAL_NAME 1
OD( msNTPrincipalName,
"Microsoft NT User Principal Name",
CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
#define MS_CERTSERV_CA_VERSION 2
OD( msCertsrvCAVersion,
"Microsoft CA Version",
CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
#define MS_NTDS_REPLICATION 3
OD( msNTDSReplication,
"Microsoft Domain GUID",
CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
};
static const unsigned int numOids = (sizeof more_oids) / (sizeof more_oids[0]);
static nsresult
GetIntValue(SECItem *versionItem,
unsigned long *version)
@ -158,7 +196,8 @@ ProcessSerialNumberDER(SECItem *serialItem,
static nsresult
GetDefaultOIDFormat(SECItem *oid,
nsAString &outString)
nsAString &outString,
char separator)
{
char buf[300];
unsigned int len;
@ -167,7 +206,7 @@ GetDefaultOIDFormat(SECItem *oid,
unsigned long val = oid->data[0];
unsigned int i = val % 40;
val /= 40;
written = PR_snprintf(buf, 300, "%lu %u ", val, i);
written = PR_snprintf(buf, 300, "%lu%c%u", val, separator, i);
if (written < 0)
return NS_ERROR_FAILURE;
len = written;
@ -186,7 +225,8 @@ GetDefaultOIDFormat(SECItem *oid,
val = (val << 7) | (j & 0x7f);
if (j & 0x80)
continue;
written = PR_snprintf(&buf[len], sizeof(buf)-len, "%lu ", val);
written = PR_snprintf(&buf[len], sizeof(buf)-len, "%c%lu",
separator, val);
if (written < 0)
return NS_ERROR_FAILURE;
@ -342,14 +382,23 @@ GetOIDText(SECItem *oid, nsINSSComponent *nssComponent, nsAString &text)
case SEC_OID_PKCS9_EMAIL_ADDRESS:
bundlekey = "CertDumpPK9Email";
break;
default: ;
default:
if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) {
bundlekey = "CertDumpMSCerttype";
break;
}
if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) {
bundlekey = "CertDumpMSCAVersion";
break;
}
/* fallthrough */
}
if (bundlekey) {
rv = nssComponent->GetPIPNSSBundleString(bundlekey, text);
} else {
nsAutoString text2;
rv = GetDefaultOIDFormat(oid, text2);
rv = GetDefaultOIDFormat(oid, text2, ' ');
if (NS_FAILED(rv))
return rv;
@ -493,23 +542,130 @@ ProcessKeyUsageExtension(SECItem *extData, nsAString &text,
return NS_OK;
}
static nsresult
ProcessBasicConstraints(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
nsAutoString local;
CERTBasicConstraints value;
SECStatus rv;
nsresult rv2;
rv = CERT_DecodeBasicConstraintValue (&value, extData);
if (rv != SECSuccess) {
NS_ASSERTION(0,"Could not decode basic constraints");
return NS_ERROR_FAILURE;
}
if (value.isCA)
rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsCA", local);
else
rv2 = nssComponent->GetPIPNSSBundleString("CertDumpIsNotCA", local);
if (NS_FAILED(rv2))
return rv2;
text.Append(local.get());
if (value.pathLenConstraint >= 0) {
nsAutoString depth;
depth.AppendInt(value.pathLenConstraint);
const PRUnichar *params[1] = {depth.get()};
rv2 = nssComponent->PIPBundleFormatStringFromName("CertDumpPathLen",
params, 1, local);
if (NS_FAILED(rv2))
return rv2;
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
text.Append(local.get());
}
return NS_OK;
}
static nsresult
ProcessExtKeyUsage(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
nsAutoString local;
CERTOidSequence *extKeyUsage = NULL;
SECItem **oids;
SECItem *oid;
nsresult rv;
extKeyUsage = CERT_DecodeOidSequence(extData);
if (extKeyUsage == NULL)
return NS_ERROR_FAILURE;
oids = extKeyUsage->oids;
while (oids != NULL && *oids != NULL) {
// For each OID, try to find a bundle string
// of the form CertDumpEKU_<underlined-OID>
nsAutoString oidname;
oid = *oids;
rv = GetDefaultOIDFormat(oid, oidname, '_');
if (NS_FAILED(rv))
return rv;
nsAutoString bundlekey = NS_LITERAL_STRING("CertDumpEKU_")+ oidname;
NS_ConvertUTF16toUTF8 bk_ascii(bundlekey);
rv = nssComponent->GetPIPNSSBundleString(bk_ascii.get(), local);
if (NS_FAILED(rv))
// If there is no bundle string, just display the OID itself
rv = GetDefaultOIDFormat(oid, local, ' ');
if (NS_FAILED(rv))
return rv;
text.Append(local.get());
text.Append(NS_LITERAL_STRING(SEPARATOR).get());
oids++;
}
CERT_DestroyOidSequence(extKeyUsage);
return NS_OK;
}
static nsresult
ProcessRDN(CERTRDN* rdn, nsAString &finalString, nsINSSComponent *nssComponent)
{
nsresult rv;
CERTAVA** avas;
CERTAVA* ava;
SECItem *decodeItem = nsnull;
nsString avavalue;
nsString type;
nsAutoString temp;
const PRUnichar *params[2];
avas = rdn->avas;
while ((ava = *avas++) != 0) {
rv = GetOIDText(&ava->type, nssComponent, type);
if (NS_FAILED(rv))
return rv;
//This function returns a string in UTF8 format.
decodeItem = CERT_DecodeAVAValue(&ava->value);
if(!decodeItem) {
return NS_ERROR_FAILURE;
}
avavalue = NS_ConvertUTF8toUTF16((char*)decodeItem->data, decodeItem->len);
SECITEM_FreeItem(decodeItem, PR_TRUE);
params[0] = type.get();
params[1] = avavalue.get();
nssComponent->PIPBundleFormatStringFromName("AVATemplate",
params, 2, temp);
finalString += temp + NS_LITERAL_STRING("\n");
}
return NS_OK;
}
static nsresult
ProcessName(CERTName *name, nsINSSComponent *nssComponent, PRUnichar **value)
{
CERTRDN** rdns;
CERTRDN** rdn;
CERTAVA** avas;
CERTAVA* ava;
SECItem *decodeItem = nsnull;
nsString finalString;
rdns = name->rdns;
nsString type;
nsresult rv;
const PRUnichar *params[2];
nsString avavalue;
nsAutoString temp;
CERTRDN **lastRdn;
lastRdn = rdns;
@ -534,31 +690,633 @@ ProcessName(CERTName *name, nsINSSComponent *nssComponent, PRUnichar **value)
* value portion of the AVA and could cause trouble when parsing.
*/
for (rdn = lastRdn; rdn >= rdns; rdn--) {
avas = (*rdn)->avas;
while ((ava = *avas++) != 0) {
rv = GetOIDText(&ava->type, nssComponent, type);
if (NS_FAILED(rv))
return rv;
//This function returns a string in UTF8 format.
decodeItem = CERT_DecodeAVAValue(&ava->value);
if(!decodeItem) {
return NS_ERROR_FAILURE;
}
avavalue = NS_ConvertUTF8toUTF16((char*)decodeItem->data, decodeItem->len);
SECITEM_FreeItem(decodeItem, PR_TRUE);
params[0] = type.get();
params[1] = avavalue.get();
nssComponent->PIPBundleFormatStringFromName("AVATemplate",
params, 2, temp);
finalString += temp + NS_LITERAL_STRING("\n");
}
rv = ProcessRDN(*rdn, finalString, nssComponent);
if (NS_FAILED(rv))
return rv;
}
*value = ToNewUnicode(finalString);
return NS_OK;
}
static nsresult
ProcessIA5String(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
SECItem item;
nsAutoString local;
if (SECSuccess != SEC_ASN1DecodeItem(nsnull, &item,
SEC_IA5StringTemplate,
extData))
return NS_ERROR_FAILURE;
local.AssignASCII((char*)item.data, item.len);
nsMemory::Free(item.data);
text.Append(local);
return NS_OK;
}
static nsresult
AppendBMPtoUTF16(PRArenaPool *arena,
unsigned char* data, unsigned int len,
nsAString& text)
{
unsigned int utf8ValLen;
unsigned char *utf8Val;
if (len % 2 != 0)
return NS_ERROR_FAILURE;
/* XXX instead of converting to and from UTF-8, it would
be sufficient to just swap bytes, or do nothing */
utf8ValLen = len * 3 + 1;
utf8Val = (unsigned char*)PORT_ArenaZAlloc(arena, utf8ValLen);
if (!PORT_UCS2_UTF8Conversion(PR_FALSE, data, len,
utf8Val, utf8ValLen, &utf8ValLen))
return NS_ERROR_FAILURE;
AppendUTF8toUTF16((char*)utf8Val, text);
return NS_OK;
}
static nsresult
ProcessBMPString(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
SECItem item;
PRArenaPool *arena;
nsresult rv = NS_ERROR_FAILURE;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
if (SECSuccess == SEC_ASN1DecodeItem(arena, &item,
SEC_BMPStringTemplate,
extData))
rv = AppendBMPtoUTF16(arena, item.data, item.len, text);
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
static nsresult
ProcessGeneralName(PRArenaPool *arena,
CERTGeneralName *current,
nsAString &text,
nsINSSComponent *nssComponent)
{
nsAutoString key;
nsXPIDLString value;
nsresult rv = NS_OK;
switch (current->type) {
case certOtherName: {
SECOidTag oidTag = SECOID_FindOIDTag(&current->name.OthName.oid);
if (oidTag == SEC_OID(MS_NT_PRINCIPAL_NAME)) {
/* The type of this name is apparently nowhere explicitly
documented. However, in the generated templates, it is always
UTF-8. So try to decode this as UTF-8; if that fails, dump the
raw data. */
SECItem decoded;
nssComponent->GetPIPNSSBundleString("CertDumpMSNTPrincipal", key);
if (SEC_ASN1DecodeItem(arena, &decoded,
SEC_ASN1_GET(SEC_UTF8StringTemplate),
&current->name.OthName.name) == SECSuccess) {
AppendUTF8toUTF16(nsCAutoString((char*)decoded.data, decoded.len),
value);
} else {
ProcessRawBytes(&current->name.OthName.name, value);
}
break;
} else if (oidTag == SEC_OID(MS_NTDS_REPLICATION)) {
/* This should be a 16-byte GUID */
SECItem guid;
nssComponent->GetPIPNSSBundleString("CertDumpMSDomainGUID", key);
if (SEC_ASN1DecodeItem(arena, &guid,
SEC_ASN1_GET(SEC_OctetStringTemplate),
&current->name.OthName.name) == SECSuccess
&& guid.len == 16) {
char buf[40];
unsigned char *d = guid.data;
PR_snprintf(buf, sizeof(buf),
"{%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x}",
d[3], d[2], d[1], d[0], d[5], d[4], d[7], d[6],
d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
value.AssignASCII(buf);
} else {
ProcessRawBytes(&current->name.OthName.name, value);
}
} else {
rv = GetDefaultOIDFormat(&current->name.OthName.oid, key, ' ');
if (NS_FAILED(rv))
goto finish;
ProcessRawBytes(&current->name.OthName.name, value);
}
break;
}
case certRFC822Name:
nssComponent->GetPIPNSSBundleString("CertDumpRFC822Name", key);
value.AssignASCII((char*)current->name.other.data, current->name.other.len);
break;
case certDNSName:
nssComponent->GetPIPNSSBundleString("CertDumpDNSName", key);
value.AssignASCII((char*)current->name.other.data, current->name.other.len);
break;
case certX400Address:
nssComponent->GetPIPNSSBundleString("CertDumpX400Address", key);
ProcessRawBytes(&current->name.other, value);
break;
case certDirectoryName:
nssComponent->GetPIPNSSBundleString("CertDumpDirectoryName", key);
rv = ProcessName(&current->name.directoryName, nssComponent,
getter_Copies(value));
if (NS_FAILED(rv))
goto finish;
break;
case certEDIPartyName:
nssComponent->GetPIPNSSBundleString("CertDumpEDIPartyName", key);
ProcessRawBytes(&current->name.other, value);
break;
case certURI:
nssComponent->GetPIPNSSBundleString("CertDumpURI", key);
value.AssignASCII((char*)current->name.other.data, current->name.other.len);
break;
case certIPAddress:
{
char buf[INET6_ADDRSTRLEN];
nssComponent->GetPIPNSSBundleString("CertDumpIPAddress", key);
if (current->name.other.len == 4)
inet_ntop(AF_INET, current->name.other.data, buf, sizeof(buf));
else if (current->name.other.len == 16)
inet_ntop(AF_INET6, current->name.other.data, buf, sizeof(buf));
else
strcpy(buf, "Invalid IP address");
value.AssignASCII(buf);
break;
}
case certRegisterID:
nssComponent->GetPIPNSSBundleString("CertDumpRegisterID", key);
rv = GetDefaultOIDFormat(&current->name.other, value, '.');
if (NS_FAILED(rv))
goto finish;
break;
}
text.Append(key);
text.Append(NS_LITERAL_STRING(": "));
text.Append(value);
text.Append(NS_LITERAL_STRING(SEPARATOR));
finish:
return rv;
}
static nsresult
ProcessGeneralNames(PRArenaPool *arena,
CERTGeneralName *nameList,
nsAString &text,
nsINSSComponent *nssComponent)
{
CERTGeneralName *current = nameList;
nsresult rv;
do {
rv = ProcessGeneralName(arena, current, text, nssComponent);
if (NS_FAILED(rv))
break;
current = CERT_GetNextGeneralName(current);
} while (current != nameList);
return rv;
}
static nsresult
ProcessAltName(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
nsresult rv = NS_OK;
PRArenaPool *arena;
CERTGeneralName *nameList;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
nameList = CERT_DecodeAltNameExtension(arena, extData);
if (!nameList)
goto finish;
rv = ProcessGeneralNames(arena, nameList, text, nssComponent);
finish:
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
static nsresult
ProcessSubjectKeyId(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
PRArenaPool *arena;
nsresult rv = NS_OK;
SECItem decoded;
nsAutoString local;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
if (SEC_QuickDERDecodeItem(arena, &decoded,
SEC_OctetStringTemplate,
extData) != SECSuccess) {
rv = NS_ERROR_FAILURE;
goto finish;
}
nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
ProcessRawBytes(&decoded, text);
finish:
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
static nsresult
ProcessAuthKeyId(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
CERTAuthKeyID *ret;
PRArenaPool *arena;
nsresult rv = NS_OK;
nsAutoString local;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
ret = CERT_DecodeAuthKeyID (arena, extData);
if (ret->keyID.len > 0) {
nssComponent->GetPIPNSSBundleString("CertDumpKeyID", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
ProcessRawBytes(&ret->keyID, text);
text.Append(NS_LITERAL_STRING(SEPARATOR));
}
if (ret->authCertIssuer) {
nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
rv = ProcessGeneralNames(arena, ret->authCertIssuer, text, nssComponent);
if (NS_FAILED(rv))
goto finish;
}
if (ret->authCertSerialNumber.len > 0) {
nssComponent->GetPIPNSSBundleString("CertDumpSerialNo", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
ProcessRawBytes(&ret->authCertSerialNumber, text);
}
finish:
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
enum DisplayTextForm { VisibleForm, BMPForm, UTF8Form };
struct DisplayText {
DisplayTextForm variant;
SECItem value;
};
const SEC_ASN1Template DisplayTextTemplate[] = {
{ SEC_ASN1_CHOICE,
offsetof(DisplayText, variant), NULL,
sizeof(DisplayText) },
{ SEC_ASN1_VISIBLE_STRING,
offsetof(DisplayText, value), NULL, VisibleForm },
{ SEC_ASN1_BMP_STRING,
offsetof(DisplayText, value), NULL, BMPForm },
{ SEC_ASN1_UTF8_STRING,
offsetof(DisplayText, value), NULL, UTF8Form },
{ 0 }
};
static nsresult
ProcessUserNotice(SECItem *der_notice,
nsAString &text,
nsINSSComponent *nssComponent)
{
nsresult rv = NS_OK;
CERTUserNotice *notice = NULL;
SECItem **itemList;
DisplayText display;
PRArenaPool *arena;
char *buf;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
notice = CERT_DecodeUserNotice(der_notice);
/* XXX: currently, polcyxtn.c assumes that organization
is an IA5String, whereas it really ought to be a
choice of VisibleString, BMPString, and UTF8String.
So if decoding of the user notice fails, it is most likely
that the organization was encoded in an unexpected way.
Make this function return "something" in this case,
instead letting the decode for the entire certificate
fail.
*/
if (notice == NULL) {
text.Append(NS_LITERAL_STRING("<implementation limitation>"));
goto finish;
}
if (notice->noticeReference.organization.len != 0) {
rv = ProcessIA5String(&notice->noticeReference.organization,
text, nssComponent);
if (NS_FAILED(rv))
goto finish;
itemList = notice->noticeReference.noticeNumbers;
while (*itemList) {
unsigned long number;
char buffer[60];
if (SEC_ASN1DecodeInteger(*itemList, &number) != SECSuccess) {
rv = NS_ERROR_FAILURE;
goto finish;
}
PR_snprintf(buffer, sizeof(buffer), "%d ", number);
AppendASCIItoUTF16(buffer, text);
itemList++;
}
}
if (notice->displayText.len != 0) {
if (SEC_QuickDERDecodeItem(arena, &display,
DisplayTextTemplate,
&notice->displayText) != SECSuccess) {
rv = NS_ERROR_FAILURE;
goto finish;
}
switch (display.variant) {
case VisibleForm:
/* Need to null-terminate string before appending it. */
buf = (char*)PORT_ArenaAlloc(arena, display.value.len+1);
PORT_Memcpy(buf, display.value.data, display.value.len);
buf[display.value.len] = '\0';
text.AppendASCII(buf);
break;
case BMPForm:
AppendBMPtoUTF16(arena, display.value.data, display.value.len,
text);
break;
case UTF8Form:
buf = (char*)PORT_ArenaAlloc(arena, display.value.len+1);
PORT_Memcpy(buf, display.value.data, display.value.len);
buf[display.value.len] = '\0';
AppendUTF8toUTF16(buf, text);
break;
}
}
finish:
if (notice)
CERT_DestroyUserNotice(notice);
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
static nsresult
ProcessCertificatePolicies(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
CERTCertificatePolicies *policies;
CERTPolicyInfo **policyInfos, *policyInfo;
CERTPolicyQualifier **policyQualifiers, *policyQualifier;
nsAutoString local;
nsresult rv = NS_OK;
policies = CERT_DecodeCertificatePoliciesExtension(extData);
if ( policies == NULL )
return NS_ERROR_FAILURE;
policyInfos = policies->policyInfos;
while (*policyInfos != NULL ) {
policyInfo = *policyInfos++;
switch (policyInfo->oid) {
case SEC_OID_VERISIGN_USER_NOTICES:
nssComponent->GetPIPNSSBundleString("CertDumpVerisignNotices", local);
text.Append(local);
break;
default:
GetDefaultOIDFormat(&policyInfo->policyID, local, '.');
text.Append(local);
}
if (policyInfo->policyQualifiers) {
/* Add all qualifiers on separate lines, indented */
policyQualifiers = policyInfo->policyQualifiers;
text.Append(NS_LITERAL_STRING(":"));
text.Append(NS_LITERAL_STRING(SEPARATOR));
while (*policyQualifiers != NULL) {
text.Append(NS_LITERAL_STRING(" "));
policyQualifier = *policyQualifiers++;
switch(policyQualifier->oid) {
case SEC_OID_PKIX_CPS_POINTER_QUALIFIER:
nssComponent->GetPIPNSSBundleString("CertDumpCPSPointer", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(":"));
text.Append(NS_LITERAL_STRING(SEPARATOR));
text.Append(NS_LITERAL_STRING(" "));
/* The CPS pointer ought to be the cPSuri alternative
of the Qualifier choice. */
rv = ProcessIA5String(&policyQualifier->qualifierValue,
text, nssComponent);
if (NS_FAILED(rv))
goto finish;
break;
case SEC_OID_PKIX_USER_NOTICE_QUALIFIER:
nssComponent->GetPIPNSSBundleString("CertDumpUserNotice", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
rv = ProcessUserNotice(&policyQualifier->qualifierValue,
text, nssComponent);
break;
default:
GetDefaultOIDFormat(&policyQualifier->qualifierID, local, '.');
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
ProcessRawBytes(&policyQualifier->qualifierValue, text);
}
text.Append(NS_LITERAL_STRING(SEPARATOR));
} /* while policyQualifiers */
} /* if policyQualifiers */
text.Append(NS_LITERAL_STRING(SEPARATOR));
}
finish:
CERT_DestroyCertificatePoliciesExtension(policies);
return rv;
}
static nsresult
ProcessCrlDistPoints(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
CERTCrlDistributionPoints *crldp;
CRLDistributionPoint **points, *point;
PRArenaPool *arena;
nsresult rv = NS_OK;
nsAutoString local;
int reasons, comma;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
crldp = CERT_DecodeCRLDistributionPoints(arena, extData);
if (!crldp || !crldp->distPoints) {
rv = NS_ERROR_FAILURE;
goto finish;
}
for(points = crldp->distPoints; *points; points++) {
point = *points;
switch (point->distPointType) {
case generalName:
rv = ProcessGeneralName(arena, point->distPoint.fullName,
text, nssComponent);
if (NS_FAILED(rv))
goto finish;
break;
case relativeDistinguishedName:
rv = ProcessRDN(&point->distPoint.relativeName,
text, nssComponent);
if (NS_FAILED(rv))
goto finish;
break;
}
if (point->reasons.len) {
reasons = point->reasons.data[0];
text.Append(NS_LITERAL_STRING(" "));
comma = 0;
if (reasons & RF_UNUSED) {
nssComponent->GetPIPNSSBundleString("CertDumpUnused", local);
text.Append(local); comma = 1;
}
if (reasons & RF_KEY_COMPROMISE) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpKeyCompromise", local);
text.Append(local); comma = 1;
}
if (reasons & RF_CA_COMPROMISE) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpCACompromise", local);
text.Append(local); comma = 1;
}
if (reasons & RF_AFFILIATION_CHANGED) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpAffiliationChanged", local);
text.Append(local); comma = 1;
}
if (reasons & RF_SUPERSEDED) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpSuperseded", local);
text.Append(local); comma = 1;
}
if (reasons & RF_CESSATION_OF_OPERATION) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpCessation", local);
text.Append(local); comma = 1;
}
if (reasons & RF_CERTIFICATE_HOLD) {
if (comma) text.Append(NS_LITERAL_STRING(", "));
nssComponent->GetPIPNSSBundleString("CertDumpHold", local);
text.Append(local); comma = 1;
}
}
if (point->crlIssuer) {
nssComponent->GetPIPNSSBundleString("CertDumpIssuer", local);
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
rv = ProcessGeneralNames(arena, point->crlIssuer,
text, nssComponent);
if (NS_FAILED(rv))
goto finish;
}
text.Append(NS_LITERAL_STRING(SEPARATOR));
}
finish:
PORT_FreeArena(arena, PR_FALSE);
return NS_OK;
}
static nsresult
ProcessAuthInfoAccess(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
CERTAuthInfoAccess **aia, *desc;
PRArenaPool *arena;
nsresult rv = NS_OK;
nsAutoString local;
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena)
return NS_ERROR_FAILURE;
aia = CERT_DecodeAuthInfoAccessExtension(arena, extData);
if (aia == NULL)
goto finish;
while (*aia != NULL) {
desc = *aia++;
switch (SECOID_FindOIDTag(&desc->method)) {
case SEC_OID_PKIX_CA_ISSUERS:
nssComponent->GetPIPNSSBundleString("CertDumpCAIssuers", text);
break;
default:
rv = GetDefaultOIDFormat(&desc->method, text, '.');
if (NS_FAILED(rv))
goto finish;
}
text.Append(local);
text.Append(NS_LITERAL_STRING(": "));
rv = ProcessGeneralName(arena, desc->location, text, nssComponent);
if (NS_FAILED(rv))
goto finish;
text.Append(NS_LITERAL_STRING(SEPARATOR));
}
finish:
PORT_FreeArena(arena, PR_FALSE);
return rv;
}
static nsresult
ProcessMSCAVersion(SECItem *extData,
nsAString &text,
nsINSSComponent *nssComponent)
{
unsigned long version;
nsresult rv;
char buf[50];
rv = GetIntValue(extData, &version);
if (NS_FAILED(rv))
return rv;
PR_snprintf(buf, sizeof(buf), "0x%x", version);
text.AppendASCII(buf);
return NS_OK;
}
static nsresult
ProcessExtensionData(SECOidTag oidTag, SECItem *extData,
nsAString &text, nsINSSComponent *nssComponent)
@ -571,7 +1329,52 @@ ProcessExtensionData(SECOidTag oidTag, SECItem *extData,
case SEC_OID_X509_KEY_USAGE:
rv = ProcessKeyUsageExtension(extData, text, nssComponent);
break;
case SEC_OID_X509_BASIC_CONSTRAINTS:
rv = ProcessBasicConstraints(extData, text, nssComponent);
break;
case SEC_OID_X509_EXT_KEY_USAGE:
rv = ProcessExtKeyUsage(extData, text, nssComponent);
break;
case SEC_OID_X509_ISSUER_ALT_NAME:
case SEC_OID_X509_SUBJECT_ALT_NAME:
rv = ProcessAltName(extData, text, nssComponent);
break;
case SEC_OID_X509_SUBJECT_KEY_ID:
rv = ProcessSubjectKeyId(extData, text, nssComponent);
break;
case SEC_OID_X509_AUTH_KEY_ID:
rv = ProcessAuthKeyId(extData, text, nssComponent);
break;
case SEC_OID_X509_CERTIFICATE_POLICIES:
rv = ProcessCertificatePolicies(extData, text, nssComponent);
break;
case SEC_OID_X509_CRL_DIST_POINTS:
rv = ProcessCrlDistPoints(extData, text, nssComponent);
break;
case SEC_OID_X509_AUTH_INFO_ACCESS:
rv = ProcessAuthInfoAccess(extData, text, nssComponent);
break;
case SEC_OID_NS_CERT_EXT_BASE_URL:
case SEC_OID_NS_CERT_EXT_REVOCATION_URL:
case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL:
case SEC_OID_NS_CERT_EXT_CA_CERT_URL:
case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL:
case SEC_OID_NS_CERT_EXT_CA_POLICY_URL:
case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL:
case SEC_OID_NS_CERT_EXT_COMMENT:
case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME:
case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL:
rv = ProcessIA5String(extData, text, nssComponent);
break;
default:
if (oidTag == SEC_OID(MS_CERT_EXT_CERTTYPE)) {
rv = ProcessBMPString(extData, text, nssComponent);
break;
}
if (oidTag == SEC_OID(MS_CERTSERV_CA_VERSION)) {
rv = ProcessMSCAVersion(extData, text, nssComponent);
break;
}
rv = ProcessRawBytes(extData, text);
break;
}
@ -768,6 +1571,27 @@ ProcessExtensions(CERTCertExtension **extensions,
return NS_OK;
}
static bool registered;
static SECStatus RegisterDynamicOids()
{
unsigned int i;
SECStatus rv = SECSuccess;
if (registered)
return rv;
for (i = 0; i < numOids; i++) {
SECOidTag tag = SECOID_AddEntry(&more_oids[i]);
if (tag == SEC_OID_UNKNOWN) {
rv = SECFailure;
continue;
}
more_oids[i].offset = tag;
}
registered = true;
return rv;
}
nsresult
nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence,
nsINSSComponent *nssComponent)
@ -776,6 +1600,9 @@ nsNSSCertificate::CreateTBSCertificateASN1Struct(nsIASN1Sequence **retSequence,
if (isAlreadyShutDown())
return NS_ERROR_NOT_AVAILABLE;
if (RegisterDynamicOids() != SECSuccess)
return NS_ERROR_FAILURE;
//
// TBSCertificate ::= SEQUENCE {
// version [0] EXPLICIT Version DEFAULT v1,