Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / certdb / certv3.c
blob2dde1136372416cb09dbcc2ae97bd062202879da
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
12 * License.
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.
21 * Contributor(s):
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 $
43 #include "cert.h"
44 #include "secitem.h"
45 #include "secoid.h"
46 #include "secder.h"
47 #include "secasn1.h"
48 #include "certxutl.h"
49 #include "secerr.h"
51 SECStatus
52 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid,
53 SECItem *value)
55 return (cert_FindExtensionByOID (cert->extensions, oid, value));
59 SECStatus
60 CERT_FindCertExtension(CERTCertificate *cert, int tag, SECItem *value)
62 return (cert_FindExtension (cert->extensions, tag, value));
65 static void
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);
74 void *
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' */
81 SECStatus
82 CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value)
84 CERTCertificate *issuercert;
85 SECStatus rv;
87 issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
88 if ( issuercert ) {
89 rv = cert_FindExtension(issuercert->extensions, tag, value);
90 CERT_DestroyCertificate(issuercert);
91 } else {
92 rv = SECFailure;
95 return(rv);
98 /* find a URL extension in the cert or its CA
99 * apply the base URL string if it exists
101 char *
102 CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag)
104 SECStatus rv;
105 SECItem urlitem = {siBuffer,0};
106 SECItem baseitem = {siBuffer,0};
107 SECItem urlstringitem = {siBuffer,0};
108 SECItem basestringitem = {siBuffer,0};
109 PRArenaPool *arena = NULL;
110 PRBool hasbase;
111 char *urlstring;
112 char *str;
113 int len;
114 unsigned int i;
116 urlstring = NULL;
118 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
119 if ( ! arena ) {
120 goto loser;
123 hasbase = PR_FALSE;
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,
128 &baseitem);
129 if ( rv == SECSuccess ) {
130 hasbase = PR_TRUE;
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 ) {
137 goto loser;
139 rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL,
140 &baseitem);
141 if ( rv == SECSuccess ) {
142 hasbase = PR_TRUE;
144 } else {
145 goto loser;
148 rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_IA5StringTemplate,
149 &urlitem);
151 if ( rv != SECSuccess ) {
152 goto loser;
154 if ( hasbase ) {
155 rv = SEC_QuickDERDecodeItem(arena, &basestringitem, SEC_IA5StringTemplate,
156 &baseitem);
158 if ( rv != SECSuccess ) {
159 goto loser;
163 len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1;
165 str = urlstring = (char *)PORT_Alloc(len);
166 if ( urlstring == NULL ) {
167 goto loser;
170 /* copy the URL base first */
171 if ( hasbase ) {
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] == ':' ) {
178 goto nobase;
182 PORT_Memcpy(str, basestringitem.data, basestringitem.len);
183 str += basestringitem.len;
187 nobase:
188 /* copy the rest (or all) of the URL */
189 PORT_Memcpy(str, urlstringitem.data, urlstringitem.len);
190 str += urlstringitem.len;
192 *str = '\0';
193 goto done;
195 loser:
196 if ( urlstring ) {
197 PORT_Free(urlstring);
200 urlstring = NULL;
201 done:
202 if ( arena ) {
203 PORT_FreeArena(arena, PR_FALSE);
205 if ( baseitem.data ) {
206 PORT_Free(baseitem.data);
208 if ( urlitem.data ) {
209 PORT_Free(urlitem.data);
212 return(urlstring);
216 * get the value of the Netscape Certificate Type Extension
218 SECStatus
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
230 char *
231 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
233 SECItem wrapperItem, tmpItem = {siBuffer,0};
234 SECStatus rv;
235 PRArenaPool *arena = NULL;
236 char *retstring = NULL;
238 wrapperItem.data = NULL;
239 tmpItem.data = NULL;
241 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
243 if ( ! arena ) {
244 goto loser;
247 rv = cert_FindExtension(cert->extensions, oidtag,
248 &wrapperItem);
249 if ( rv != SECSuccess ) {
250 goto loser;
253 rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_IA5StringTemplate,
254 &wrapperItem);
256 if ( rv != SECSuccess ) {
257 goto loser;
260 retstring = (char *)PORT_Alloc(tmpItem.len + 1 );
261 if ( retstring == NULL ) {
262 goto loser;
265 PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
266 retstring[tmpItem.len] = '\0';
268 loser:
269 if ( arena ) {
270 PORT_FreeArena(arena, PR_FALSE);
273 if ( wrapperItem.data ) {
274 PORT_Free(wrapperItem.data);
277 return(retstring);
281 * get the value of the X.509 v3 Key Usage Extension
283 SECStatus
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
294 SECStatus
295 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
298 SECStatus rv;
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);
306 if (tmpArena) {
307 rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue,
308 SEC_OctetStringTemplate,
309 &encodedValue);
310 if (rv == SECSuccess) {
311 rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
313 PORT_FreeArena(tmpArena, PR_FALSE);
314 } else {
315 rv = SECFailure;
318 SECITEM_FreeItem(&encodedValue, PR_FALSE);
319 return rv;
322 SECStatus
323 CERT_FindBasicConstraintExten(CERTCertificate *cert,
324 CERTBasicConstraints *value)
326 SECItem encodedExtenValue;
327 SECStatus rv;
329 encodedExtenValue.data = NULL;
330 encodedExtenValue.len = 0;
332 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
333 &encodedExtenValue);
334 if ( rv != SECSuccess ) {
335 return (rv);
338 rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue);
340 /* free the raw extension data */
341 PORT_Free(encodedExtenValue.data);
342 encodedExtenValue.data = NULL;
344 return(rv);
347 CERTAuthKeyID *
348 CERT_FindAuthKeyIDExten (PRArenaPool *arena, CERTCertificate *cert)
350 SECItem encodedExtenValue;
351 SECStatus rv;
352 CERTAuthKeyID *ret;
354 encodedExtenValue.data = NULL;
355 encodedExtenValue.len = 0;
357 rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
358 &encodedExtenValue);
359 if ( rv != SECSuccess ) {
360 return (NULL);
363 ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
365 PORT_Free(encodedExtenValue.data);
366 encodedExtenValue.data = NULL;
368 return(ret);
371 SECStatus
372 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
374 SECItem keyUsage;
375 SECStatus rv;
377 /* There is no extension, v1 or v2 certificate */
378 if (cert->extensions == NULL) {
379 return (SECSuccess);
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);
394 rv = SECFailure;
396 PORT_Free (keyUsage.data);
397 return (rv);