michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Code for dealing with x.509 v3 CRL Distribution Point extension. michael@0: */ michael@0: #include "genname.h" michael@0: #include "certt.h" michael@0: #include "secerr.h" michael@0: michael@0: SEC_ASN1_MKSUB(SEC_AnyTemplate) michael@0: SEC_ASN1_MKSUB(SEC_BitStringTemplate) michael@0: michael@0: extern void PrepareBitStringForEncoding (SECItem *bitMap, SECItem *value); michael@0: michael@0: static const SEC_ASN1Template FullNameTemplate[] = { michael@0: {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, michael@0: offsetof (CRLDistributionPoint,derFullName), michael@0: CERT_GeneralNamesTemplate} michael@0: }; michael@0: michael@0: static const SEC_ASN1Template RelativeNameTemplate[] = { michael@0: {SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, michael@0: offsetof (CRLDistributionPoint,distPoint.relativeName), michael@0: CERT_RDNTemplate} michael@0: }; michael@0: michael@0: static const SEC_ASN1Template DistributionPointNameTemplate[] = { michael@0: { SEC_ASN1_CHOICE, michael@0: offsetof(CRLDistributionPoint, distPointType), NULL, michael@0: sizeof(CRLDistributionPoint) }, michael@0: { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, michael@0: offsetof (CRLDistributionPoint, derFullName), michael@0: CERT_GeneralNamesTemplate, generalName }, michael@0: { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, michael@0: offsetof (CRLDistributionPoint, distPoint.relativeName), michael@0: CERT_RDNTemplate, relativeDistinguishedName }, michael@0: { 0 } michael@0: }; michael@0: michael@0: static const SEC_ASN1Template CRLDistributionPointTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | michael@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0, michael@0: offsetof(CRLDistributionPoint,derDistPoint), michael@0: SEC_ASN1_SUB(SEC_AnyTemplate)}, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, michael@0: offsetof(CRLDistributionPoint,bitsmap), michael@0: SEC_ASN1_SUB(SEC_BitStringTemplate) }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | michael@0: SEC_ASN1_CONSTRUCTED | 2, michael@0: offsetof(CRLDistributionPoint, derCrlIssuer), michael@0: CERT_GeneralNamesTemplate}, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = { michael@0: {SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate} michael@0: }; michael@0: michael@0: SECStatus michael@0: CERT_EncodeCRLDistributionPoints (PLArenaPool *arena, michael@0: CERTCrlDistributionPoints *value, michael@0: SECItem *derValue) michael@0: { michael@0: CRLDistributionPoint **pointList, *point; michael@0: PLArenaPool *ourPool = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: PORT_Assert (derValue); michael@0: PORT_Assert (value && value->distPoints); michael@0: michael@0: do { michael@0: ourPool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); michael@0: if (ourPool == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: michael@0: pointList = value->distPoints; michael@0: while (*pointList) { michael@0: point = *pointList; michael@0: point->derFullName = NULL; michael@0: point->derDistPoint.data = NULL; michael@0: michael@0: switch (point->distPointType) { michael@0: case generalName: michael@0: point->derFullName = cert_EncodeGeneralNames michael@0: (ourPool, point->distPoint.fullName); michael@0: michael@0: if (!point->derFullName || michael@0: !SEC_ASN1EncodeItem (ourPool, &point->derDistPoint, michael@0: point, FullNameTemplate)) michael@0: rv = SECFailure; michael@0: break; michael@0: michael@0: case relativeDistinguishedName: michael@0: if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, michael@0: point, RelativeNameTemplate)) michael@0: rv = SECFailure; michael@0: break; michael@0: michael@0: /* distributionPointName is omitted */ michael@0: case 0: break; michael@0: michael@0: default: michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: if (point->reasons.data) michael@0: PrepareBitStringForEncoding (&point->bitsmap, &point->reasons); michael@0: michael@0: if (point->crlIssuer) { michael@0: point->derCrlIssuer = cert_EncodeGeneralNames michael@0: (ourPool, point->crlIssuer); michael@0: if (!point->derCrlIssuer) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: } michael@0: ++pointList; michael@0: } michael@0: if (rv != SECSuccess) michael@0: break; michael@0: if (!SEC_ASN1EncodeItem(arena, derValue, value, michael@0: CERTCRLDistributionPointsTemplate)) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: } while (0); michael@0: PORT_FreeArena (ourPool, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: CERTCrlDistributionPoints * michael@0: CERT_DecodeCRLDistributionPoints (PLArenaPool *arena, SECItem *encodedValue) michael@0: { michael@0: CERTCrlDistributionPoints *value = NULL; michael@0: CRLDistributionPoint **pointList, *point; michael@0: SECStatus rv = SECSuccess; michael@0: SECItem newEncodedValue; michael@0: michael@0: PORT_Assert (arena); michael@0: do { michael@0: value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); michael@0: if (value == NULL) { michael@0: rv = SECFailure; michael@0: break; michael@0: } michael@0: michael@0: /* copy the DER into the arena, since Quick DER returns data that points michael@0: into the DER input, which may get freed by the caller */ michael@0: rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: rv = SEC_QuickDERDecodeItem(arena, &value->distPoints, michael@0: CERTCRLDistributionPointsTemplate, &newEncodedValue); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: pointList = value->distPoints; michael@0: while (NULL != (point = *pointList)) { michael@0: michael@0: /* get the data if the distributionPointName is not omitted */ michael@0: if (point->derDistPoint.data != NULL) { michael@0: rv = SEC_QuickDERDecodeItem(arena, point, michael@0: DistributionPointNameTemplate, &(point->derDistPoint)); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: michael@0: switch (point->distPointType) { michael@0: case generalName: michael@0: point->distPoint.fullName = michael@0: cert_DecodeGeneralNames(arena, point->derFullName); michael@0: rv = point->distPoint.fullName ? SECSuccess : SECFailure; michael@0: break; michael@0: michael@0: case relativeDistinguishedName: michael@0: break; michael@0: michael@0: default: michael@0: PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); michael@0: rv = SECFailure; michael@0: break; michael@0: } /* end switch */ michael@0: if (rv != SECSuccess) michael@0: break; michael@0: } /* end if */ michael@0: michael@0: /* Get the reason code if it's not omitted in the encoding */ michael@0: if (point->bitsmap.data != NULL) { michael@0: SECItem bitsmap = point->bitsmap; michael@0: DER_ConvertBitString(&bitsmap); michael@0: rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap); michael@0: if (rv != SECSuccess) michael@0: break; michael@0: } michael@0: michael@0: /* Get the crl issuer name if it's not omitted in the encoding */ michael@0: if (point->derCrlIssuer != NULL) { michael@0: point->crlIssuer = cert_DecodeGeneralNames(arena, michael@0: point->derCrlIssuer); michael@0: if (!point->crlIssuer) michael@0: break; michael@0: } michael@0: ++pointList; michael@0: } /* end while points remain */ michael@0: } while (0); michael@0: return (rv == SECSuccess ? value : NULL); michael@0: }