1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
38 * Code for dealing with X509.V3 extensions.
40 * $Id: certv3.c,v 1.9 2006/09/29 20:20:21 alexei.volkov.bugs%sun.com Exp $
52 CERT_FindCertExtensionByOID(CERTCertificate
*cert
, SECItem
*oid
,
55 return (cert_FindExtensionByOID (cert
->extensions
, oid
, value
));
60 CERT_FindCertExtension(CERTCertificate
*cert
, int tag
, SECItem
*value
)
62 return (cert_FindExtension (cert
->extensions
, tag
, value
));
66 SetExts(void *object
, CERTCertExtension
**exts
)
68 CERTCertificate
*cert
= (CERTCertificate
*)object
;
70 cert
->extensions
= exts
;
71 DER_SetUInteger (cert
->arena
, &(cert
->version
), SEC_CERTIFICATE_VERSION_3
);
75 CERT_StartCertExtensions(CERTCertificate
*cert
)
77 return (cert_StartExtensions ((void *)cert
, cert
->arena
, SetExts
));
80 /* find the given extension in the certificate of the Issuer of 'cert' */
82 CERT_FindIssuerCertExtension(CERTCertificate
*cert
, int tag
, SECItem
*value
)
84 CERTCertificate
*issuercert
;
87 issuercert
= CERT_FindCertByName(cert
->dbhandle
, &cert
->derIssuer
);
89 rv
= cert_FindExtension(issuercert
->extensions
, tag
, value
);
90 CERT_DestroyCertificate(issuercert
);
98 /* find a URL extension in the cert or its CA
99 * apply the base URL string if it exists
102 CERT_FindCertURLExtension(CERTCertificate
*cert
, int tag
, int catag
)
105 SECItem urlitem
= {siBuffer
,0};
106 SECItem baseitem
= {siBuffer
,0};
107 SECItem urlstringitem
= {siBuffer
,0};
108 SECItem basestringitem
= {siBuffer
,0};
109 PRArenaPool
*arena
= NULL
;
118 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
125 rv
= cert_FindExtension(cert
->extensions
, tag
, &urlitem
);
126 if ( rv
== SECSuccess
) {
127 rv
= cert_FindExtension(cert
->extensions
, SEC_OID_NS_CERT_EXT_BASE_URL
,
129 if ( rv
== SECSuccess
) {
133 } else if ( catag
) {
134 /* if the cert doesn't have the extensions, see if the issuer does */
135 rv
= CERT_FindIssuerCertExtension(cert
, catag
, &urlitem
);
136 if ( rv
!= SECSuccess
) {
139 rv
= CERT_FindIssuerCertExtension(cert
, SEC_OID_NS_CERT_EXT_BASE_URL
,
141 if ( rv
== SECSuccess
) {
148 rv
= SEC_QuickDERDecodeItem(arena
, &urlstringitem
, SEC_IA5StringTemplate
,
151 if ( rv
!= SECSuccess
) {
155 rv
= SEC_QuickDERDecodeItem(arena
, &basestringitem
, SEC_IA5StringTemplate
,
158 if ( rv
!= SECSuccess
) {
163 len
= urlstringitem
.len
+ ( hasbase
? basestringitem
.len
: 0 ) + 1;
165 str
= urlstring
= (char *)PORT_Alloc(len
);
166 if ( urlstring
== NULL
) {
170 /* copy the URL base first */
173 /* if the urlstring has a : in it, then we assume it is an absolute
174 * URL, and will not get the base string pre-pended
176 for ( i
= 0; i
< urlstringitem
.len
; i
++ ) {
177 if ( urlstringitem
.data
[i
] == ':' ) {
182 PORT_Memcpy(str
, basestringitem
.data
, basestringitem
.len
);
183 str
+= basestringitem
.len
;
188 /* copy the rest (or all) of the URL */
189 PORT_Memcpy(str
, urlstringitem
.data
, urlstringitem
.len
);
190 str
+= urlstringitem
.len
;
197 PORT_Free(urlstring
);
203 PORT_FreeArena(arena
, PR_FALSE
);
205 if ( baseitem
.data
) {
206 PORT_Free(baseitem
.data
);
208 if ( urlitem
.data
) {
209 PORT_Free(urlitem
.data
);
216 * get the value of the Netscape Certificate Type Extension
219 CERT_FindNSCertTypeExtension(CERTCertificate
*cert
, SECItem
*retItem
)
222 return (CERT_FindBitStringExtension
223 (cert
->extensions
, SEC_OID_NS_CERT_EXT_CERT_TYPE
, retItem
));
228 * get the value of a string type extension
231 CERT_FindNSStringExtension(CERTCertificate
*cert
, int oidtag
)
233 SECItem wrapperItem
, tmpItem
= {siBuffer
,0};
235 PRArenaPool
*arena
= NULL
;
236 char *retstring
= NULL
;
238 wrapperItem
.data
= NULL
;
241 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
247 rv
= cert_FindExtension(cert
->extensions
, oidtag
,
249 if ( rv
!= SECSuccess
) {
253 rv
= SEC_QuickDERDecodeItem(arena
, &tmpItem
, SEC_IA5StringTemplate
,
256 if ( rv
!= SECSuccess
) {
260 retstring
= (char *)PORT_Alloc(tmpItem
.len
+ 1 );
261 if ( retstring
== NULL
) {
265 PORT_Memcpy(retstring
, tmpItem
.data
, tmpItem
.len
);
266 retstring
[tmpItem
.len
] = '\0';
270 PORT_FreeArena(arena
, PR_FALSE
);
273 if ( wrapperItem
.data
) {
274 PORT_Free(wrapperItem
.data
);
281 * get the value of the X.509 v3 Key Usage Extension
284 CERT_FindKeyUsageExtension(CERTCertificate
*cert
, SECItem
*retItem
)
287 return (CERT_FindBitStringExtension(cert
->extensions
,
288 SEC_OID_X509_KEY_USAGE
, retItem
));
292 * get the value of the X.509 v3 Key Usage Extension
295 CERT_FindSubjectKeyIDExtension(CERTCertificate
*cert
, SECItem
*retItem
)
299 SECItem encodedValue
= {siBuffer
, NULL
, 0 };
300 SECItem decodedValue
= {siBuffer
, NULL
, 0 };
302 rv
= cert_FindExtension
303 (cert
->extensions
, SEC_OID_X509_SUBJECT_KEY_ID
, &encodedValue
);
304 if (rv
== SECSuccess
) {
305 PLArenaPool
* tmpArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
307 rv
= SEC_QuickDERDecodeItem(tmpArena
, &decodedValue
,
308 SEC_OctetStringTemplate
,
310 if (rv
== SECSuccess
) {
311 rv
= SECITEM_CopyItem(NULL
, retItem
, &decodedValue
);
313 PORT_FreeArena(tmpArena
, PR_FALSE
);
318 SECITEM_FreeItem(&encodedValue
, PR_FALSE
);
323 CERT_FindBasicConstraintExten(CERTCertificate
*cert
,
324 CERTBasicConstraints
*value
)
326 SECItem encodedExtenValue
;
329 encodedExtenValue
.data
= NULL
;
330 encodedExtenValue
.len
= 0;
332 rv
= cert_FindExtension(cert
->extensions
, SEC_OID_X509_BASIC_CONSTRAINTS
,
334 if ( rv
!= SECSuccess
) {
338 rv
= CERT_DecodeBasicConstraintValue (value
, &encodedExtenValue
);
340 /* free the raw extension data */
341 PORT_Free(encodedExtenValue
.data
);
342 encodedExtenValue
.data
= NULL
;
348 CERT_FindAuthKeyIDExten (PRArenaPool
*arena
, CERTCertificate
*cert
)
350 SECItem encodedExtenValue
;
354 encodedExtenValue
.data
= NULL
;
355 encodedExtenValue
.len
= 0;
357 rv
= cert_FindExtension(cert
->extensions
, SEC_OID_X509_AUTH_KEY_ID
,
359 if ( rv
!= SECSuccess
) {
363 ret
= CERT_DecodeAuthKeyID (arena
, &encodedExtenValue
);
365 PORT_Free(encodedExtenValue
.data
);
366 encodedExtenValue
.data
= NULL
;
372 CERT_CheckCertUsage(CERTCertificate
*cert
, unsigned char usage
)
377 /* There is no extension, v1 or v2 certificate */
378 if (cert
->extensions
== NULL
) {
382 keyUsage
.data
= NULL
;
384 /* This code formerly ignored the Key Usage extension if it was
385 ** marked non-critical. That was wrong. Since we do understand it,
386 ** we are obligated to honor it, whether or not it is critical.
388 rv
= CERT_FindKeyUsageExtension(cert
, &keyUsage
);
389 if (rv
== SECFailure
) {
390 rv
= (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND
) ?
391 SECSuccess
: SECFailure
;
392 } else if (!(keyUsage
.data
[0] & usage
)) {
393 PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID
);
396 PORT_Free (keyUsage
.data
);