diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/certhigh/xcrldist.c | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/security/nss/lib/certhigh/xcrldist.c b/security/nss/lib/certhigh/xcrldist.c new file mode 100644 index 0000000000..4f74cdb259 --- /dev/null +++ b/security/nss/lib/certhigh/xcrldist.c @@ -0,0 +1,212 @@ +/* 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/. */ + +/* + * Code for dealing with x.509 v3 CRL Distribution Point extension. + */ +#include "genname.h" +#include "certt.h" +#include "secerr.h" + +SEC_ASN1_MKSUB(SEC_AnyTemplate) +SEC_ASN1_MKSUB(SEC_BitStringTemplate) + +extern void PrepareBitStringForEncoding(SECItem *bitMap, SECItem *value); + +static const SEC_ASN1Template FullNameTemplate[] = { + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, + offsetof(CRLDistributionPoint, derFullName), + CERT_GeneralNamesTemplate } +}; + +static const SEC_ASN1Template RelativeNameTemplate[] = { + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, + offsetof(CRLDistributionPoint, distPoint.relativeName), + CERT_RDNTemplate } +}; + +static const SEC_ASN1Template DistributionPointNameTemplate[] = { + { SEC_ASN1_CHOICE, + offsetof(CRLDistributionPoint, distPointType), NULL, + sizeof(CRLDistributionPoint) }, + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, + offsetof(CRLDistributionPoint, derFullName), + CERT_GeneralNamesTemplate, generalName }, + { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, + offsetof(CRLDistributionPoint, distPoint.relativeName), + CERT_RDNTemplate, relativeDistinguishedName }, + { 0 } +}; + +static const SEC_ASN1Template CRLDistributionPointTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | + SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0, + offsetof(CRLDistributionPoint, derDistPoint), + SEC_ASN1_SUB(SEC_AnyTemplate) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, + offsetof(CRLDistributionPoint, bitsmap), + SEC_ASN1_SUB(SEC_BitStringTemplate) }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | + SEC_ASN1_CONSTRUCTED | 2, + offsetof(CRLDistributionPoint, derCrlIssuer), + CERT_GeneralNamesTemplate }, + { 0 } +}; + +const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate } +}; + +SECStatus +CERT_EncodeCRLDistributionPoints(PLArenaPool *arena, + CERTCrlDistributionPoints *value, + SECItem *derValue) +{ + CRLDistributionPoint **pointList, *point; + PLArenaPool *ourPool = NULL; + SECStatus rv = SECSuccess; + + PORT_Assert(derValue); + PORT_Assert(value && value->distPoints); + + do { + ourPool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (ourPool == NULL) { + rv = SECFailure; + break; + } + + pointList = value->distPoints; + while (*pointList) { + point = *pointList; + point->derFullName = NULL; + point->derDistPoint.data = NULL; + + switch (point->distPointType) { + case generalName: + point->derFullName = cert_EncodeGeneralNames(ourPool, point->distPoint.fullName); + + if (!point->derFullName || + !SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, + point, FullNameTemplate)) + rv = SECFailure; + break; + + case relativeDistinguishedName: + if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, + point, RelativeNameTemplate)) + rv = SECFailure; + break; + + default: + PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); + rv = SECFailure; + break; + } + + if (rv != SECSuccess) + break; + + if (point->reasons.data) + PrepareBitStringForEncoding(&point->bitsmap, &point->reasons); + + if (point->crlIssuer) { + point->derCrlIssuer = cert_EncodeGeneralNames(ourPool, point->crlIssuer); + if (!point->derCrlIssuer) { + rv = SECFailure; + break; + } + } + ++pointList; + } + if (rv != SECSuccess) + break; + if (!SEC_ASN1EncodeItem(arena, derValue, value, + CERTCRLDistributionPointsTemplate)) { + rv = SECFailure; + break; + } + } while (0); + PORT_FreeArena(ourPool, PR_FALSE); + return rv; +} + +CERTCrlDistributionPoints * +CERT_DecodeCRLDistributionPoints(PLArenaPool *arena, SECItem *encodedValue) +{ + CERTCrlDistributionPoints *value = NULL; + CRLDistributionPoint **pointList, *point; + SECStatus rv = SECSuccess; + SECItem newEncodedValue; + + PORT_Assert(arena); + do { + value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); + if (value == NULL) { + rv = SECFailure; + break; + } + + /* 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, &newEncodedValue, encodedValue); + if (rv != SECSuccess) + break; + + rv = SEC_QuickDERDecodeItem(arena, &value->distPoints, + CERTCRLDistributionPointsTemplate, &newEncodedValue); + if (rv != SECSuccess) + break; + + pointList = value->distPoints; + while (NULL != (point = *pointList)) { + + /* get the data if the distributionPointName is not omitted */ + if (point->derDistPoint.data != NULL) { + rv = SEC_QuickDERDecodeItem(arena, point, + DistributionPointNameTemplate, &(point->derDistPoint)); + if (rv != SECSuccess) + break; + + switch (point->distPointType) { + case generalName: + point->distPoint.fullName = + cert_DecodeGeneralNames(arena, point->derFullName); + rv = point->distPoint.fullName ? SECSuccess : SECFailure; + break; + + case relativeDistinguishedName: + break; + + default: + PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); + rv = SECFailure; + break; + } /* end switch */ + if (rv != SECSuccess) + break; + } /* end if */ + + /* Get the reason code if it's not omitted in the encoding */ + if (point->bitsmap.data != NULL) { + SECItem bitsmap = point->bitsmap; + DER_ConvertBitString(&bitsmap); + rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap); + if (rv != SECSuccess) + break; + } + + /* Get the crl issuer name if it's not omitted in the encoding */ + if (point->derCrlIssuer != NULL) { + point->crlIssuer = cert_DecodeGeneralNames(arena, + point->derCrlIssuer); + if (!point->crlIssuer) + break; + } + ++pointList; + } /* end while points remain */ + } while (0); + return (rv == SECSuccess ? value : NULL); +} |