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