OLD | NEW |
| (Empty) |
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 X509.V3 extensions. | |
7 * | |
8 * $Id: certv3.c,v 1.13 2012/04/25 14:49:26 gerv%gerv.net Exp $ | |
9 */ | |
10 | |
11 #include "cert.h" | |
12 #include "secitem.h" | |
13 #include "secoid.h" | |
14 #include "secder.h" | |
15 #include "secasn1.h" | |
16 #include "certxutl.h" | |
17 #include "secerr.h" | |
18 | |
19 SECStatus | |
20 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, | |
21 SECItem *value) | |
22 { | |
23 return (cert_FindExtensionByOID (cert->extensions, oid, value)); | |
24 } | |
25 | |
26 | |
27 SECStatus | |
28 CERT_FindCertExtension(CERTCertificate *cert, int tag, SECItem *value) | |
29 { | |
30 return (cert_FindExtension (cert->extensions, tag, value)); | |
31 } | |
32 | |
33 static void | |
34 SetExts(void *object, CERTCertExtension **exts) | |
35 { | |
36 CERTCertificate *cert = (CERTCertificate *)object; | |
37 | |
38 cert->extensions = exts; | |
39 DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3); | |
40 } | |
41 | |
42 void * | |
43 CERT_StartCertExtensions(CERTCertificate *cert) | |
44 { | |
45 return (cert_StartExtensions ((void *)cert, cert->arena, SetExts)); | |
46 } | |
47 | |
48 /* find the given extension in the certificate of the Issuer of 'cert' */ | |
49 SECStatus | |
50 CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value) | |
51 { | |
52 CERTCertificate *issuercert; | |
53 SECStatus rv; | |
54 | |
55 issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer); | |
56 if ( issuercert ) { | |
57 rv = cert_FindExtension(issuercert->extensions, tag, value); | |
58 CERT_DestroyCertificate(issuercert); | |
59 } else { | |
60 rv = SECFailure; | |
61 } | |
62 | |
63 return(rv); | |
64 } | |
65 | |
66 /* find a URL extension in the cert or its CA | |
67 * apply the base URL string if it exists | |
68 */ | |
69 char * | |
70 CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag) | |
71 { | |
72 SECStatus rv; | |
73 SECItem urlitem = {siBuffer,0}; | |
74 SECItem baseitem = {siBuffer,0}; | |
75 SECItem urlstringitem = {siBuffer,0}; | |
76 SECItem basestringitem = {siBuffer,0}; | |
77 PRArenaPool *arena = NULL; | |
78 PRBool hasbase; | |
79 char *urlstring; | |
80 char *str; | |
81 int len; | |
82 unsigned int i; | |
83 | |
84 urlstring = NULL; | |
85 | |
86 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
87 if ( ! arena ) { | |
88 goto loser; | |
89 } | |
90 | |
91 hasbase = PR_FALSE; | |
92 | |
93 rv = cert_FindExtension(cert->extensions, tag, &urlitem); | |
94 if ( rv == SECSuccess ) { | |
95 rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL, | |
96 &baseitem); | |
97 if ( rv == SECSuccess ) { | |
98 hasbase = PR_TRUE; | |
99 } | |
100 | |
101 } else if ( catag ) { | |
102 /* if the cert doesn't have the extensions, see if the issuer does */ | |
103 rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem); | |
104 if ( rv != SECSuccess ) { | |
105 goto loser; | |
106 } | |
107 rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL, | |
108 &baseitem); | |
109 if ( rv == SECSuccess ) { | |
110 hasbase = PR_TRUE; | |
111 } | |
112 } else { | |
113 goto loser; | |
114 } | |
115 | |
116 rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, | |
117 SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem); | |
118 | |
119 if ( rv != SECSuccess ) { | |
120 goto loser; | |
121 } | |
122 if ( hasbase ) { | |
123 rv = SEC_QuickDERDecodeItem(arena, &basestringitem, | |
124 SEC_ASN1_GET(SEC_IA5StringTemplate), | |
125 &baseitem); | |
126 | |
127 if ( rv != SECSuccess ) { | |
128 goto loser; | |
129 } | |
130 } | |
131 | |
132 len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1; | |
133 | |
134 str = urlstring = (char *)PORT_Alloc(len); | |
135 if ( urlstring == NULL ) { | |
136 goto loser; | |
137 } | |
138 | |
139 /* copy the URL base first */ | |
140 if ( hasbase ) { | |
141 | |
142 /* if the urlstring has a : in it, then we assume it is an absolute | |
143 * URL, and will not get the base string pre-pended | |
144 */ | |
145 for ( i = 0; i < urlstringitem.len; i++ ) { | |
146 if ( urlstringitem.data[i] == ':' ) { | |
147 goto nobase; | |
148 } | |
149 } | |
150 | |
151 PORT_Memcpy(str, basestringitem.data, basestringitem.len); | |
152 str += basestringitem.len; | |
153 | |
154 } | |
155 | |
156 nobase: | |
157 /* copy the rest (or all) of the URL */ | |
158 PORT_Memcpy(str, urlstringitem.data, urlstringitem.len); | |
159 str += urlstringitem.len; | |
160 | |
161 *str = '\0'; | |
162 goto done; | |
163 | |
164 loser: | |
165 if ( urlstring ) { | |
166 PORT_Free(urlstring); | |
167 } | |
168 | |
169 urlstring = NULL; | |
170 done: | |
171 if ( arena ) { | |
172 PORT_FreeArena(arena, PR_FALSE); | |
173 } | |
174 if ( baseitem.data ) { | |
175 PORT_Free(baseitem.data); | |
176 } | |
177 if ( urlitem.data ) { | |
178 PORT_Free(urlitem.data); | |
179 } | |
180 | |
181 return(urlstring); | |
182 } | |
183 | |
184 /* | |
185 * get the value of the Netscape Certificate Type Extension | |
186 */ | |
187 SECStatus | |
188 CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem) | |
189 { | |
190 | |
191 return (CERT_FindBitStringExtension | |
192 (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem)); | |
193 } | |
194 | |
195 | |
196 /* | |
197 * get the value of a string type extension | |
198 */ | |
199 char * | |
200 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag) | |
201 { | |
202 SECItem wrapperItem, tmpItem = {siBuffer,0}; | |
203 SECStatus rv; | |
204 PRArenaPool *arena = NULL; | |
205 char *retstring = NULL; | |
206 | |
207 wrapperItem.data = NULL; | |
208 tmpItem.data = NULL; | |
209 | |
210 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
211 | |
212 if ( ! arena ) { | |
213 goto loser; | |
214 } | |
215 | |
216 rv = cert_FindExtension(cert->extensions, oidtag, | |
217 &wrapperItem); | |
218 if ( rv != SECSuccess ) { | |
219 goto loser; | |
220 } | |
221 | |
222 rv = SEC_QuickDERDecodeItem(arena, &tmpItem, | |
223 SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem); | |
224 | |
225 if ( rv != SECSuccess ) { | |
226 goto loser; | |
227 } | |
228 | |
229 retstring = (char *)PORT_Alloc(tmpItem.len + 1 ); | |
230 if ( retstring == NULL ) { | |
231 goto loser; | |
232 } | |
233 | |
234 PORT_Memcpy(retstring, tmpItem.data, tmpItem.len); | |
235 retstring[tmpItem.len] = '\0'; | |
236 | |
237 loser: | |
238 if ( arena ) { | |
239 PORT_FreeArena(arena, PR_FALSE); | |
240 } | |
241 | |
242 if ( wrapperItem.data ) { | |
243 PORT_Free(wrapperItem.data); | |
244 } | |
245 | |
246 return(retstring); | |
247 } | |
248 | |
249 /* | |
250 * get the value of the X.509 v3 Key Usage Extension | |
251 */ | |
252 SECStatus | |
253 CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem) | |
254 { | |
255 | |
256 return (CERT_FindBitStringExtension(cert->extensions, | |
257 SEC_OID_X509_KEY_USAGE, retItem)); | |
258 } | |
259 | |
260 /* | |
261 * get the value of the X.509 v3 Key Usage Extension | |
262 */ | |
263 SECStatus | |
264 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem) | |
265 { | |
266 | |
267 SECStatus rv; | |
268 SECItem encodedValue = {siBuffer, NULL, 0 }; | |
269 SECItem decodedValue = {siBuffer, NULL, 0 }; | |
270 | |
271 rv = cert_FindExtension | |
272 (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue); | |
273 if (rv == SECSuccess) { | |
274 PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
275 if (tmpArena) { | |
276 rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, | |
277 SEC_ASN1_GET(SEC_OctetStringTemplate), | |
278 &encodedValue); | |
279 if (rv == SECSuccess) { | |
280 rv = SECITEM_CopyItem(NULL, retItem, &decodedValue); | |
281 } | |
282 PORT_FreeArena(tmpArena, PR_FALSE); | |
283 } else { | |
284 rv = SECFailure; | |
285 } | |
286 } | |
287 SECITEM_FreeItem(&encodedValue, PR_FALSE); | |
288 return rv; | |
289 } | |
290 | |
291 SECStatus | |
292 CERT_FindBasicConstraintExten(CERTCertificate *cert, | |
293 CERTBasicConstraints *value) | |
294 { | |
295 SECItem encodedExtenValue; | |
296 SECStatus rv; | |
297 | |
298 encodedExtenValue.data = NULL; | |
299 encodedExtenValue.len = 0; | |
300 | |
301 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS, | |
302 &encodedExtenValue); | |
303 if ( rv != SECSuccess ) { | |
304 return (rv); | |
305 } | |
306 | |
307 rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue); | |
308 | |
309 /* free the raw extension data */ | |
310 PORT_Free(encodedExtenValue.data); | |
311 encodedExtenValue.data = NULL; | |
312 | |
313 return(rv); | |
314 } | |
315 | |
316 CERTAuthKeyID * | |
317 CERT_FindAuthKeyIDExten (PRArenaPool *arena, CERTCertificate *cert) | |
318 { | |
319 SECItem encodedExtenValue; | |
320 SECStatus rv; | |
321 CERTAuthKeyID *ret; | |
322 | |
323 encodedExtenValue.data = NULL; | |
324 encodedExtenValue.len = 0; | |
325 | |
326 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID, | |
327 &encodedExtenValue); | |
328 if ( rv != SECSuccess ) { | |
329 return (NULL); | |
330 } | |
331 | |
332 ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); | |
333 | |
334 PORT_Free(encodedExtenValue.data); | |
335 encodedExtenValue.data = NULL; | |
336 | |
337 return(ret); | |
338 } | |
339 | |
340 SECStatus | |
341 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage) | |
342 { | |
343 SECItem keyUsage; | |
344 SECStatus rv; | |
345 | |
346 /* There is no extension, v1 or v2 certificate */ | |
347 if (cert->extensions == NULL) { | |
348 return (SECSuccess); | |
349 } | |
350 | |
351 keyUsage.data = NULL; | |
352 | |
353 /* This code formerly ignored the Key Usage extension if it was | |
354 ** marked non-critical. That was wrong. Since we do understand it, | |
355 ** we are obligated to honor it, whether or not it is critical. | |
356 */ | |
357 rv = CERT_FindKeyUsageExtension(cert, &keyUsage); | |
358 if (rv == SECFailure) { | |
359 rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ? | |
360 SECSuccess : SECFailure; | |
361 } else if (!(keyUsage.data[0] & usage)) { | |
362 PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID); | |
363 rv = SECFailure; | |
364 } | |
365 PORT_Free (keyUsage.data); | |
366 return (rv); | |
367 } | |
OLD | NEW |