|
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 { |
|
67 CRLDistributionPoint **pointList, *point; |
|
68 PLArenaPool *ourPool = NULL; |
|
69 SECStatus rv = SECSuccess; |
|
70 |
|
71 PORT_Assert (derValue); |
|
72 PORT_Assert (value && value->distPoints); |
|
73 |
|
74 do { |
|
75 ourPool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
76 if (ourPool == NULL) { |
|
77 rv = SECFailure; |
|
78 break; |
|
79 } |
|
80 |
|
81 pointList = value->distPoints; |
|
82 while (*pointList) { |
|
83 point = *pointList; |
|
84 point->derFullName = NULL; |
|
85 point->derDistPoint.data = NULL; |
|
86 |
|
87 switch (point->distPointType) { |
|
88 case generalName: |
|
89 point->derFullName = cert_EncodeGeneralNames |
|
90 (ourPool, point->distPoint.fullName); |
|
91 |
|
92 if (!point->derFullName || |
|
93 !SEC_ASN1EncodeItem (ourPool, &point->derDistPoint, |
|
94 point, FullNameTemplate)) |
|
95 rv = SECFailure; |
|
96 break; |
|
97 |
|
98 case relativeDistinguishedName: |
|
99 if (!SEC_ASN1EncodeItem(ourPool, &point->derDistPoint, |
|
100 point, RelativeNameTemplate)) |
|
101 rv = SECFailure; |
|
102 break; |
|
103 |
|
104 /* distributionPointName is omitted */ |
|
105 case 0: break; |
|
106 |
|
107 default: |
|
108 PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
109 rv = SECFailure; |
|
110 break; |
|
111 } |
|
112 |
|
113 if (rv != SECSuccess) |
|
114 break; |
|
115 |
|
116 if (point->reasons.data) |
|
117 PrepareBitStringForEncoding (&point->bitsmap, &point->reasons); |
|
118 |
|
119 if (point->crlIssuer) { |
|
120 point->derCrlIssuer = cert_EncodeGeneralNames |
|
121 (ourPool, point->crlIssuer); |
|
122 if (!point->derCrlIssuer) { |
|
123 rv = SECFailure; |
|
124 break; |
|
125 } |
|
126 } |
|
127 ++pointList; |
|
128 } |
|
129 if (rv != SECSuccess) |
|
130 break; |
|
131 if (!SEC_ASN1EncodeItem(arena, derValue, value, |
|
132 CERTCRLDistributionPointsTemplate)) { |
|
133 rv = SECFailure; |
|
134 break; |
|
135 } |
|
136 } while (0); |
|
137 PORT_FreeArena (ourPool, PR_FALSE); |
|
138 return rv; |
|
139 } |
|
140 |
|
141 CERTCrlDistributionPoints * |
|
142 CERT_DecodeCRLDistributionPoints (PLArenaPool *arena, SECItem *encodedValue) |
|
143 { |
|
144 CERTCrlDistributionPoints *value = NULL; |
|
145 CRLDistributionPoint **pointList, *point; |
|
146 SECStatus rv = SECSuccess; |
|
147 SECItem newEncodedValue; |
|
148 |
|
149 PORT_Assert (arena); |
|
150 do { |
|
151 value = PORT_ArenaZNew(arena, CERTCrlDistributionPoints); |
|
152 if (value == NULL) { |
|
153 rv = SECFailure; |
|
154 break; |
|
155 } |
|
156 |
|
157 /* copy the DER into the arena, since Quick DER returns data that points |
|
158 into the DER input, which may get freed by the caller */ |
|
159 rv = SECITEM_CopyItem(arena, &newEncodedValue, encodedValue); |
|
160 if (rv != SECSuccess) |
|
161 break; |
|
162 |
|
163 rv = SEC_QuickDERDecodeItem(arena, &value->distPoints, |
|
164 CERTCRLDistributionPointsTemplate, &newEncodedValue); |
|
165 if (rv != SECSuccess) |
|
166 break; |
|
167 |
|
168 pointList = value->distPoints; |
|
169 while (NULL != (point = *pointList)) { |
|
170 |
|
171 /* get the data if the distributionPointName is not omitted */ |
|
172 if (point->derDistPoint.data != NULL) { |
|
173 rv = SEC_QuickDERDecodeItem(arena, point, |
|
174 DistributionPointNameTemplate, &(point->derDistPoint)); |
|
175 if (rv != SECSuccess) |
|
176 break; |
|
177 |
|
178 switch (point->distPointType) { |
|
179 case generalName: |
|
180 point->distPoint.fullName = |
|
181 cert_DecodeGeneralNames(arena, point->derFullName); |
|
182 rv = point->distPoint.fullName ? SECSuccess : SECFailure; |
|
183 break; |
|
184 |
|
185 case relativeDistinguishedName: |
|
186 break; |
|
187 |
|
188 default: |
|
189 PORT_SetError (SEC_ERROR_EXTENSION_VALUE_INVALID); |
|
190 rv = SECFailure; |
|
191 break; |
|
192 } /* end switch */ |
|
193 if (rv != SECSuccess) |
|
194 break; |
|
195 } /* end if */ |
|
196 |
|
197 /* Get the reason code if it's not omitted in the encoding */ |
|
198 if (point->bitsmap.data != NULL) { |
|
199 SECItem bitsmap = point->bitsmap; |
|
200 DER_ConvertBitString(&bitsmap); |
|
201 rv = SECITEM_CopyItem(arena, &point->reasons, &bitsmap); |
|
202 if (rv != SECSuccess) |
|
203 break; |
|
204 } |
|
205 |
|
206 /* Get the crl issuer name if it's not omitted in the encoding */ |
|
207 if (point->derCrlIssuer != NULL) { |
|
208 point->crlIssuer = cert_DecodeGeneralNames(arena, |
|
209 point->derCrlIssuer); |
|
210 if (!point->crlIssuer) |
|
211 break; |
|
212 } |
|
213 ++pointList; |
|
214 } /* end while points remain */ |
|
215 } while (0); |
|
216 return (rv == SECSuccess ? value : NULL); |
|
217 } |