зеркало из https://github.com/mozilla/gecko-dev.git
807 строки
21 KiB
C
807 строки
21 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* Support for various policy related extensions
|
|
*/
|
|
|
|
#include "seccomon.h"
|
|
#include "secport.h"
|
|
#include "secder.h"
|
|
#include "cert.h"
|
|
#include "secoid.h"
|
|
#include "secasn1.h"
|
|
#include "secerr.h"
|
|
#include "nspr.h"
|
|
|
|
SEC_ASN1_MKSUB(SEC_IntegerTemplate)
|
|
SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
|
|
|
|
const SEC_ASN1Template CERT_DisplayTextTypeTemplate[] = {
|
|
{ SEC_ASN1_CHOICE, offsetof(SECItem, type), 0, sizeof(SECItem) },
|
|
{ SEC_ASN1_IA5_STRING, 0, 0, siAsciiString },
|
|
{ SEC_ASN1_VISIBLE_STRING, 0, 0, siVisibleString },
|
|
{ SEC_ASN1_BMP_STRING, 0, 0, siBMPString },
|
|
{ SEC_ASN1_UTF8_STRING, 0, 0, siUTF8String },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNoticeReference) },
|
|
{ SEC_ASN1_INLINE, offsetof(CERTNoticeReference, organization),
|
|
CERT_DisplayTextTypeTemplate, 0 },
|
|
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
|
|
offsetof(CERTNoticeReference, noticeNumbers),
|
|
SEC_ASN1_SUB(SEC_IntegerTemplate) },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTUserNotice) },
|
|
{ SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
|
|
offsetof(CERTUserNotice, noticeReference), CERT_NoticeReferenceTemplate,
|
|
0 },
|
|
{ SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
|
|
offsetof(CERTUserNotice, displayText), CERT_DisplayTextTypeTemplate, 0 },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPolicyQualifier) },
|
|
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyQualifier, qualifierID) },
|
|
{ SEC_ASN1_ANY, offsetof(CERTPolicyQualifier, qualifierValue) },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_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),
|
|
CERT_PolicyQualifierTemplate },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE_OF, offsetof(CERTCertificatePolicies, policyInfos),
|
|
CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_PolicyMapTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTPolicyMap) },
|
|
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyMap, issuerDomainPolicy) },
|
|
{ SEC_ASN1_OBJECT_ID, offsetof(CERTPolicyMap, subjectDomainPolicy) },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_PolicyMappingsTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE_OF, offsetof(CERTCertificatePolicyMappings, policyMaps),
|
|
CERT_PolicyMapTemplate, sizeof(CERTPolicyMap) }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_PolicyConstraintsTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertificatePolicyConstraints) },
|
|
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
|
|
offsetof(CERTCertificatePolicyConstraints, explicitPolicySkipCerts),
|
|
SEC_ASN1_SUB(SEC_IntegerTemplate) },
|
|
{ SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
|
|
offsetof(CERTCertificatePolicyConstraints, inhibitMappingSkipCerts),
|
|
SEC_ASN1_SUB(SEC_IntegerTemplate) },
|
|
{ 0 }
|
|
};
|
|
|
|
const SEC_ASN1Template CERT_InhibitAnyTemplate[] = {
|
|
{ SEC_ASN1_INTEGER,
|
|
offsetof(CERTCertificateInhibitAny, inhibitAnySkipCerts), NULL,
|
|
sizeof(CERTCertificateInhibitAny) }
|
|
};
|
|
|
|
static void
|
|
breakLines(char *string)
|
|
{
|
|
char *tmpstr;
|
|
char *lastspace = NULL;
|
|
int curlen = 0;
|
|
int c;
|
|
|
|
tmpstr = string;
|
|
|
|
while ((c = *tmpstr) != '\0') {
|
|
switch (c) {
|
|
case ' ':
|
|
lastspace = tmpstr;
|
|
break;
|
|
case '\n':
|
|
lastspace = NULL;
|
|
curlen = 0;
|
|
break;
|
|
}
|
|
|
|
if ((curlen >= 55) && (lastspace != NULL)) {
|
|
*lastspace = '\n';
|
|
curlen = (tmpstr - lastspace);
|
|
lastspace = NULL;
|
|
}
|
|
|
|
curlen++;
|
|
tmpstr++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
CERTCertificatePolicies *
|
|
CERT_DecodeCertificatePoliciesExtension(const SECItem *extnValue)
|
|
{
|
|
PLArenaPool *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 certificate policies structure */
|
|
policies = (CERTCertificatePolicies *)PORT_ArenaZAlloc(
|
|
arena, sizeof(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, CERT_CertificatePoliciesTemplate, &newExtnValue);
|
|
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* initialize the oid tags */
|
|
policyInfos = policies->policyInfos;
|
|
while (*policyInfos != NULL) {
|
|
policyInfo = *policyInfos;
|
|
policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
|
|
policyQualifiers = policyInfo->policyQualifiers;
|
|
while (policyQualifiers != NULL && *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);
|
|
}
|
|
|
|
void
|
|
CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
|
|
{
|
|
if (policies != NULL) {
|
|
PORT_FreeArena(policies->arena, PR_FALSE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
CERTCertificatePolicyMappings *
|
|
CERT_DecodePolicyMappingsExtension(SECItem *extnValue)
|
|
{
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv;
|
|
CERTCertificatePolicyMappings *mappings;
|
|
SECItem newExtnValue;
|
|
|
|
/* make a new arena */
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (!arena) {
|
|
goto loser;
|
|
}
|
|
|
|
/* allocate the policy mappings structure */
|
|
mappings = (CERTCertificatePolicyMappings *)PORT_ArenaZAlloc(
|
|
arena, sizeof(CERTCertificatePolicyMappings));
|
|
if (mappings == NULL) {
|
|
goto loser;
|
|
}
|
|
mappings->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 mappings */
|
|
rv = SEC_QuickDERDecodeItem(arena, mappings, CERT_PolicyMappingsTemplate,
|
|
&newExtnValue);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
return (mappings);
|
|
|
|
loser:
|
|
if (arena != NULL) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings *mappings)
|
|
{
|
|
if (mappings != NULL) {
|
|
PORT_FreeArena(mappings->arena, PR_FALSE);
|
|
}
|
|
return SECSuccess;
|
|
}
|
|
|
|
SECStatus
|
|
CERT_DecodePolicyConstraintsExtension(
|
|
CERTCertificatePolicyConstraints *decodedValue, const SECItem *encodedValue)
|
|
{
|
|
CERTCertificatePolicyConstraints decodeContext;
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv = SECSuccess;
|
|
|
|
/* initialize so we can tell when an optional component is omitted */
|
|
PORT_Memset(&decodeContext, 0, sizeof(decodeContext));
|
|
|
|
/* make a new arena */
|
|
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
|
if (!arena) {
|
|
return SECFailure;
|
|
}
|
|
|
|
do {
|
|
/* decode the policy constraints */
|
|
rv = SEC_QuickDERDecodeItem(arena, &decodeContext,
|
|
CERT_PolicyConstraintsTemplate,
|
|
encodedValue);
|
|
|
|
if (rv != SECSuccess) {
|
|
break;
|
|
}
|
|
|
|
if (decodeContext.explicitPolicySkipCerts.len == 0) {
|
|
*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = -1;
|
|
} else {
|
|
*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data =
|
|
DER_GetInteger(&decodeContext.explicitPolicySkipCerts);
|
|
}
|
|
|
|
if (decodeContext.inhibitMappingSkipCerts.len == 0) {
|
|
*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = -1;
|
|
} else {
|
|
*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data =
|
|
DER_GetInteger(&decodeContext.inhibitMappingSkipCerts);
|
|
}
|
|
|
|
if ((*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
|
|
PR_INT32_MIN) ||
|
|
(*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
|
|
PR_INT32_MAX) ||
|
|
(*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
|
|
PR_INT32_MIN) ||
|
|
(*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
|
|
PR_INT32_MAX)) {
|
|
rv = SECFailure;
|
|
}
|
|
|
|
} while (0);
|
|
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_DecodeInhibitAnyExtension(CERTCertificateInhibitAny *decodedValue,
|
|
SECItem *encodedValue)
|
|
{
|
|
CERTCertificateInhibitAny decodeContext;
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv = SECSuccess;
|
|
|
|
/* make a new arena */
|
|
arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
|
if (!arena) {
|
|
return SECFailure;
|
|
}
|
|
|
|
do {
|
|
|
|
/* decode the policy mappings */
|
|
decodeContext.inhibitAnySkipCerts.type = siUnsignedInteger;
|
|
rv = SEC_QuickDERDecodeItem(arena, &decodeContext,
|
|
CERT_InhibitAnyTemplate, encodedValue);
|
|
|
|
if (rv != SECSuccess) {
|
|
break;
|
|
}
|
|
|
|
*(PRInt32 *)decodedValue->inhibitAnySkipCerts.data =
|
|
DER_GetInteger(&decodeContext.inhibitAnySkipCerts);
|
|
|
|
} while (0);
|
|
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return (rv);
|
|
}
|
|
|
|
CERTUserNotice *
|
|
CERT_DecodeUserNotice(SECItem *noticeItem)
|
|
{
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv;
|
|
CERTUserNotice *userNotice;
|
|
SECItem newNoticeItem;
|
|
|
|
/* make a new arena */
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if (!arena) {
|
|
goto loser;
|
|
}
|
|
|
|
/* allocate the userNotice structure */
|
|
userNotice =
|
|
(CERTUserNotice *)PORT_ArenaZAlloc(arena, sizeof(CERTUserNotice));
|
|
|
|
if (userNotice == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
userNotice->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, &newNoticeItem, noticeItem);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* decode the user notice */
|
|
rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate,
|
|
&newNoticeItem);
|
|
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
if (userNotice->derNoticeReference.data != NULL) {
|
|
|
|
rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference,
|
|
CERT_NoticeReferenceTemplate,
|
|
&userNotice->derNoticeReference);
|
|
if (rv == SECFailure) {
|
|
goto loser;
|
|
}
|
|
}
|
|
|
|
return (userNotice);
|
|
|
|
loser:
|
|
if (arena != NULL) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
void
|
|
CERT_DestroyUserNotice(CERTUserNotice *userNotice)
|
|
{
|
|
if (userNotice != NULL) {
|
|
PORT_FreeArena(userNotice->arena, PR_FALSE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static CERTPolicyStringCallback policyStringCB = NULL;
|
|
static void *policyStringCBArg = NULL;
|
|
|
|
void
|
|
CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
|
|
{
|
|
policyStringCB = cb;
|
|
policyStringCBArg = cbarg;
|
|
return;
|
|
}
|
|
|
|
char *
|
|
stringFromUserNotice(SECItem *noticeItem)
|
|
{
|
|
SECItem *org;
|
|
unsigned int len, headerlen;
|
|
char *stringbuf;
|
|
CERTUserNotice *userNotice;
|
|
char *policystr;
|
|
char *retstr = NULL;
|
|
SECItem *displayText;
|
|
SECItem **noticeNumbers;
|
|
unsigned int strnum;
|
|
|
|
/* decode the user notice */
|
|
userNotice = CERT_DecodeUserNotice(noticeItem);
|
|
if (userNotice == NULL) {
|
|
return (NULL);
|
|
}
|
|
|
|
org = &userNotice->noticeReference.organization;
|
|
if ((org->len != 0) && (policyStringCB != NULL)) {
|
|
/* has a noticeReference */
|
|
|
|
/* extract the org string */
|
|
len = org->len;
|
|
stringbuf = (char *)PORT_Alloc(len + 1);
|
|
if (stringbuf != NULL) {
|
|
PORT_Memcpy(stringbuf, org->data, len);
|
|
stringbuf[len] = '\0';
|
|
|
|
noticeNumbers = userNotice->noticeReference.noticeNumbers;
|
|
while (*noticeNumbers != NULL) {
|
|
/* XXX - only one byte integers right now*/
|
|
strnum = (*noticeNumbers)->data[0];
|
|
policystr =
|
|
(*policyStringCB)(stringbuf, strnum, policyStringCBArg);
|
|
if (policystr != NULL) {
|
|
if (retstr != NULL) {
|
|
retstr = PR_sprintf_append(retstr, "\n%s", policystr);
|
|
} else {
|
|
retstr = PR_sprintf_append(retstr, "%s", policystr);
|
|
}
|
|
|
|
PORT_Free(policystr);
|
|
}
|
|
|
|
noticeNumbers++;
|
|
}
|
|
|
|
PORT_Free(stringbuf);
|
|
}
|
|
}
|
|
|
|
if (retstr == NULL) {
|
|
if (userNotice->displayText.len != 0) {
|
|
displayText = &userNotice->displayText;
|
|
|
|
if (displayText->len > 2) {
|
|
if (displayText->data[0] == SEC_ASN1_VISIBLE_STRING) {
|
|
headerlen = 2;
|
|
if (displayText->data[1] & 0x80) {
|
|
/* multibyte length */
|
|
headerlen += (displayText->data[1] & 0x7f);
|
|
}
|
|
|
|
len = displayText->len - headerlen;
|
|
retstr = (char *)PORT_Alloc(len + 1);
|
|
if (retstr != NULL) {
|
|
PORT_Memcpy(retstr, &displayText->data[headerlen], len);
|
|
retstr[len] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CERT_DestroyUserNotice(userNotice);
|
|
|
|
return (retstr);
|
|
}
|
|
|
|
char *
|
|
CERT_GetCertCommentString(CERTCertificate *cert)
|
|
{
|
|
char *retstring = NULL;
|
|
SECStatus rv;
|
|
SECItem policyItem;
|
|
CERTCertificatePolicies *policies = NULL;
|
|
CERTPolicyInfo **policyInfos;
|
|
CERTPolicyQualifier **policyQualifiers, *qualifier;
|
|
|
|
policyItem.data = NULL;
|
|
|
|
rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
|
|
&policyItem);
|
|
if (rv != SECSuccess) {
|
|
goto nopolicy;
|
|
}
|
|
|
|
policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
|
|
if (policies == NULL) {
|
|
goto nopolicy;
|
|
}
|
|
|
|
policyInfos = policies->policyInfos;
|
|
/* search through policyInfos looking for the verisign policy */
|
|
while (*policyInfos != NULL) {
|
|
if ((*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES) {
|
|
policyQualifiers = (*policyInfos)->policyQualifiers;
|
|
/* search through the policy qualifiers looking for user notice */
|
|
while (policyQualifiers != NULL && *policyQualifiers != NULL) {
|
|
qualifier = *policyQualifiers;
|
|
if (qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER) {
|
|
retstring =
|
|
stringFromUserNotice(&qualifier->qualifierValue);
|
|
break;
|
|
}
|
|
|
|
policyQualifiers++;
|
|
}
|
|
break;
|
|
}
|
|
policyInfos++;
|
|
}
|
|
|
|
nopolicy:
|
|
if (policyItem.data != NULL) {
|
|
PORT_Free(policyItem.data);
|
|
}
|
|
|
|
if (policies != NULL) {
|
|
CERT_DestroyCertificatePoliciesExtension(policies);
|
|
}
|
|
|
|
if (retstring == NULL) {
|
|
retstring =
|
|
CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_COMMENT);
|
|
}
|
|
|
|
if (retstring != NULL) {
|
|
breakLines(retstring);
|
|
}
|
|
|
|
return (retstring);
|
|
}
|
|
|
|
const SEC_ASN1Template CERT_OidSeqTemplate[] = {
|
|
{ SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, offsetof(CERTOidSequence, oids),
|
|
SEC_ASN1_SUB(SEC_ObjectIDTemplate) }
|
|
};
|
|
|
|
CERTOidSequence *
|
|
CERT_DecodeOidSequence(const SECItem *seqItem)
|
|
{
|
|
PLArenaPool *arena = NULL;
|
|
SECStatus rv;
|
|
CERTOidSequence *oidSeq;
|
|
SECItem newSeqItem;
|
|
|
|
/* make a new arena */
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
|
|
if (!arena) {
|
|
goto loser;
|
|
}
|
|
|
|
/* allocate the userNotice structure */
|
|
oidSeq =
|
|
(CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
|
|
|
|
if (oidSeq == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
oidSeq->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, &newSeqItem, seqItem);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
/* decode the user notice */
|
|
rv =
|
|
SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
|
|
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
return (oidSeq);
|
|
|
|
loser:
|
|
if (arena) {
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
void
|
|
CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
|
|
{
|
|
if (oidSeq != NULL) {
|
|
PORT_FreeArena(oidSeq->arena, PR_FALSE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
PRBool
|
|
CERT_GovtApprovedBitSet(CERTCertificate *cert)
|
|
{
|
|
SECStatus rv;
|
|
SECItem extItem;
|
|
CERTOidSequence *oidSeq = NULL;
|
|
PRBool ret;
|
|
SECItem **oids;
|
|
SECItem *oid;
|
|
SECOidTag oidTag;
|
|
|
|
extItem.data = NULL;
|
|
rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
|
|
if (rv != SECSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
oidSeq = CERT_DecodeOidSequence(&extItem);
|
|
if (oidSeq == NULL) {
|
|
goto loser;
|
|
}
|
|
|
|
oids = oidSeq->oids;
|
|
while (oids != NULL && *oids != NULL) {
|
|
oid = *oids;
|
|
|
|
oidTag = SECOID_FindOIDTag(oid);
|
|
|
|
if (oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) {
|
|
goto success;
|
|
}
|
|
|
|
oids++;
|
|
}
|
|
|
|
loser:
|
|
ret = PR_FALSE;
|
|
goto done;
|
|
success:
|
|
ret = PR_TRUE;
|
|
done:
|
|
if (oidSeq != NULL) {
|
|
CERT_DestroyOidSequence(oidSeq);
|
|
}
|
|
if (extItem.data != NULL) {
|
|
PORT_Free(extItem.data);
|
|
}
|
|
return (ret);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodePolicyConstraintsExtension(PLArenaPool *arena,
|
|
CERTCertificatePolicyConstraints *constr,
|
|
SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(constr != NULL && dest != NULL);
|
|
if (constr == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, constr,
|
|
CERT_PolicyConstraintsTemplate) == NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodePolicyMappingExtension(PLArenaPool *arena,
|
|
CERTCertificatePolicyMappings *mapping,
|
|
SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(mapping != NULL && dest != NULL);
|
|
if (mapping == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, mapping, CERT_PolicyMappingsTemplate) ==
|
|
NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodeCertPoliciesExtension(PLArenaPool *arena, CERTPolicyInfo **info,
|
|
SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(info != NULL && dest != NULL);
|
|
if (info == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, info,
|
|
CERT_CertificatePoliciesTemplate) == NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodeUserNotice(PLArenaPool *arena, CERTUserNotice *notice, SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(notice != NULL && dest != NULL);
|
|
if (notice == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, notice, CERT_UserNoticeTemplate) ==
|
|
NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodeNoticeReference(PLArenaPool *arena, CERTNoticeReference *reference,
|
|
SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(reference != NULL && dest != NULL);
|
|
if (reference == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, reference,
|
|
CERT_NoticeReferenceTemplate) == NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
SECStatus
|
|
CERT_EncodeInhibitAnyExtension(PLArenaPool *arena,
|
|
CERTCertificateInhibitAny *certInhibitAny,
|
|
SECItem *dest)
|
|
{
|
|
SECStatus rv = SECSuccess;
|
|
|
|
PORT_Assert(certInhibitAny != NULL && dest != NULL);
|
|
if (certInhibitAny == NULL || dest == NULL) {
|
|
return SECFailure;
|
|
}
|
|
|
|
if (SEC_ASN1EncodeItem(arena, dest, certInhibitAny,
|
|
CERT_InhibitAnyTemplate) == NULL) {
|
|
rv = SECFailure;
|
|
}
|
|
return (rv);
|
|
}
|