/src/nss/lib/certhigh/xcrldist.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | /* |
6 | | * Code for dealing with x.509 v3 CRL Distribution Point extension. |
7 | | */ |
8 | | #include "genname.h" |
9 | | #include "certt.h" |
10 | | #include "secerr.h" |
11 | | |
12 | | SEC_ASN1_MKSUB(SEC_AnyTemplate) |
13 | | SEC_ASN1_MKSUB(SEC_BitStringTemplate) |
14 | | |
15 | | extern void PrepareBitStringForEncoding(SECItem *bitMap, SECItem *value); |
16 | | |
17 | | static const SEC_ASN1Template FullNameTemplate[] = { |
18 | | { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, |
19 | | offsetof(CRLDistributionPoint, derFullName), |
20 | | CERT_GeneralNamesTemplate } |
21 | | }; |
22 | | |
23 | | static const SEC_ASN1Template RelativeNameTemplate[] = { |
24 | | { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, |
25 | | offsetof(CRLDistributionPoint, distPoint.relativeName), |
26 | | CERT_RDNTemplate } |
27 | | }; |
28 | | |
29 | | static const SEC_ASN1Template DistributionPointNameTemplate[] = { |
30 | | { SEC_ASN1_CHOICE, |
31 | | offsetof(CRLDistributionPoint, distPointType), NULL, |
32 | | sizeof(CRLDistributionPoint) }, |
33 | | { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0, |
34 | | offsetof(CRLDistributionPoint, derFullName), |
35 | | CERT_GeneralNamesTemplate, generalName }, |
36 | | { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 1, |
37 | | offsetof(CRLDistributionPoint, distPoint.relativeName), |
38 | | CERT_RDNTemplate, relativeDistinguishedName }, |
39 | | { 0 } |
40 | | }; |
41 | | |
42 | | static const SEC_ASN1Template CRLDistributionPointTemplate[] = { |
43 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CRLDistributionPoint) }, |
44 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | |
45 | | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0, |
46 | | offsetof(CRLDistributionPoint, derDistPoint), |
47 | | SEC_ASN1_SUB(SEC_AnyTemplate) }, |
48 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, |
49 | | offsetof(CRLDistributionPoint, bitsmap), |
50 | | SEC_ASN1_SUB(SEC_BitStringTemplate) }, |
51 | | { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | |
52 | | SEC_ASN1_CONSTRUCTED | 2, |
53 | | offsetof(CRLDistributionPoint, derCrlIssuer), |
54 | | CERT_GeneralNamesTemplate }, |
55 | | { 0 } |
56 | | }; |
57 | | |
58 | | const SEC_ASN1Template CERTCRLDistributionPointsTemplate[] = { |
59 | | { SEC_ASN1_SEQUENCE_OF, 0, CRLDistributionPointTemplate } |
60 | | }; |
61 | | |
62 | | SECStatus |
63 | | CERT_EncodeCRLDistributionPoints(PLArenaPool *arena, |
64 | | CERTCrlDistributionPoints *value, |
65 | | SECItem *derValue) |
66 | 0 | { |
67 | 0 | CRLDistributionPoint **pointList, *point; |
68 | 0 | PLArenaPool *ourPool = NULL; |
69 | 0 | SECStatus rv = SECSuccess; |
70 | |
|
71 | 0 | PORT_Assert(derValue); |
72 | 0 | PORT_Assert(value && value->distPoints); |
73 | |
|
74 | 0 | do { |
75 | 0 | ourPool = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
76 | 0 | if (ourPool == NULL) { |
77 | 0 | rv = SECFailure; |
78 | 0 | break; |
79 | 0 | } |
80 | | |
81 | 0 | pointList = value->distPoints; |
82 | 0 | while (*pointList) { |
83 | 0 | point = *pointList; |
84 | 0 | point->derFullName = NULL; |
85 | 0 | point->derDistPoint.data = NULL; |
86 | |
|
87 | 0 | switch (point->distPointType) { |
88 | 0 | case generalName: |
89 | 0 | point->derFullName = cert_EncodeGeneralNames(ourPool, point->distPoint.fullName); |
90 | |
|
91 | 0 | if (!point->derFullName || |
92 | 0 | !SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, |
93 | 0 | point, FullNameTemplate)) |
94 | 0 | rv = SECFailure; |
95 | 0 | break; |
96 | | |
97 | 0 | case relativeDistinguishedName: |
98 | 0 | if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, |
99 | 0 | point, RelativeNameTemplate)) |
100 | 0 | rv = SECFailure; |
101 | 0 | break; |
102 | | |
103 | 0 | default: |
104 | 0 | PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); |
105 | 0 | rv = SECFailure; |
106 | 0 | break; |
107 | 0 | } |
108 | | |
109 | 0 | if (rv != SECSuccess) |
110 | 0 | break; |
111 | | |
112 | 0 | if (point->reasons.data) |
113 | 0 | PrepareBitStringForEncoding(&point->bitsmap, &point->reasons); |
114 | |
|
115 | 0 | if (point->crlIssuer) { |
116 | 0 | point->derCrlIssuer = cert_EncodeGeneralNames(ourPool, point->crlIssuer); |
117 | 0 | if (!point->derCrlIssuer) { |
118 | 0 | rv = SECFailure; |
119 | 0 | break; |
120 | 0 | } |
121 | 0 | } |
122 | 0 | ++pointList; |
123 | 0 | } |
124 | 0 | if (rv != SECSuccess) |
125 | 0 | break; |
126 | 0 | if (!SEC_ASN1EncodeItem(arena, derValue, value, |
127 | 0 | CERTCRLDistributionPointsTemplate)) { |
128 | 0 | rv = SECFailure; |
129 | 0 | break; |
130 | 0 | } |
131 | 0 | } while (0); |
132 | 0 | PORT_FreeArena(ourPool, PR_FALSE); |
133 | 0 | return rv; |
134 | 0 | } |
135 | | |
136 | | CERTCrlDistributionPoints * |
137 | | CERT_DecodeCRLDistributionPoints(PLArenaPool *arena, SECItem *encodedValue) |
138 | 0 | { |
139 | 0 | CERTCrlDistributionPoints *value = NULL; |
140 | 0 | CRLDistributionPoint **pointList, *point; |
141 | 0 | SECStatus rv = SECSuccess; |
142 | 0 | SECItem newEncodedValue; |
143 | |
|
144 | 0 | PORT_Assert(arena); |
145 | 0 | do { |
146 | 0 | value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); |
147 | 0 | if (value == NULL) { |
148 | 0 | rv = SECFailure; |
149 | 0 | break; |
150 | 0 | } |
151 | | |
152 | | /* copy the DER into the arena, since Quick DER returns data that points |
153 | | into the DER input, which may get freed by the caller */ |
154 | 0 | rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); |
155 | 0 | if (rv != SECSuccess) |
156 | 0 | break; |
157 | | |
158 | 0 | rv = SEC_QuickDERDecodeItem(arena, &value->distPoints, |
159 | 0 | CERTCRLDistributionPointsTemplate, &newEncodedValue); |
160 | 0 | if (rv != SECSuccess) |
161 | 0 | break; |
162 | | |
163 | 0 | pointList = value->distPoints; |
164 | 0 | while (NULL != (point = *pointList)) { |
165 | | |
166 | | /* get the data if the distributionPointName is not omitted */ |
167 | 0 | if (point->derDistPoint.data != NULL) { |
168 | 0 | rv = SEC_QuickDERDecodeItem(arena, point, |
169 | 0 | DistributionPointNameTemplate, &(point->derDistPoint)); |
170 | 0 | if (rv != SECSuccess) |
171 | 0 | break; |
172 | | |
173 | 0 | switch (point->distPointType) { |
174 | 0 | case generalName: |
175 | 0 | point->distPoint.fullName = |
176 | 0 | cert_DecodeGeneralNames(arena, point->derFullName); |
177 | 0 | rv = point->distPoint.fullName ? SECSuccess : SECFailure; |
178 | 0 | break; |
179 | | |
180 | 0 | case relativeDistinguishedName: |
181 | 0 | break; |
182 | | |
183 | 0 | default: |
184 | 0 | PORT_SetError(SEC_ERROR_EXTENSION_VALUE_INVALID); |
185 | 0 | rv = SECFailure; |
186 | 0 | break; |
187 | 0 | } /* end switch */ |
188 | 0 | if (rv != SECSuccess) |
189 | 0 | break; |
190 | 0 | } /* end if */ |
191 | | |
192 | | /* Get the reason code if it's not omitted in the encoding */ |
193 | 0 | if (point->bitsmap.data != NULL) { |
194 | 0 | SECItem bitsmap = point->bitsmap; |
195 | 0 | DER_ConvertBitString(&bitsmap); |
196 | 0 | rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap); |
197 | 0 | if (rv != SECSuccess) |
198 | 0 | break; |
199 | 0 | } |
200 | | |
201 | | /* Get the crl issuer name if it's not omitted in the encoding */ |
202 | 0 | if (point->derCrlIssuer != NULL) { |
203 | 0 | point->crlIssuer = cert_DecodeGeneralNames(arena, |
204 | 0 | point->derCrlIssuer); |
205 | 0 | if (!point->crlIssuer) |
206 | 0 | break; |
207 | 0 | } |
208 | 0 | ++pointList; |
209 | 0 | } /* end while points remain */ |
210 | 0 | } while (0); |
211 | 0 | return (rv == SECSuccess ? value : NULL); |
212 | 0 | } |