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.8 2004/04/25 15:03:03 gerv%gerv.net 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)
107
SECItem urlstringitem = {siBuffer,0};
108
SECItem basestringitem = {siBuffer,0};
109
PRArenaPool *arena = NULL;
118
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
125
baseitem.data = NULL;
127
rv = cert_FindExtension(cert->extensions, tag, &urlitem);
128
if ( rv == SECSuccess ) {
129
rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL,
131
if ( rv == SECSuccess ) {
135
} else if ( catag ) {
136
/* if the cert doesn't have the extensions, see if the issuer does */
137
rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem);
138
if ( rv != SECSuccess ) {
141
rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL,
143
if ( rv == SECSuccess ) {
150
rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_IA5StringTemplate,
153
if ( rv != SECSuccess ) {
157
rv = SEC_QuickDERDecodeItem(arena, &basestringitem, SEC_IA5StringTemplate,
160
if ( rv != SECSuccess ) {
165
len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1;
167
str = urlstring = (char *)PORT_Alloc(len);
168
if ( urlstring == NULL ) {
172
/* copy the URL base first */
175
/* if the urlstring has a : in it, then we assume it is an absolute
176
* URL, and will not get the base string pre-pended
178
for ( i = 0; i < urlstringitem.len; i++ ) {
179
if ( urlstringitem.data[i] == ':' ) {
184
PORT_Memcpy(str, basestringitem.data, basestringitem.len);
185
str += basestringitem.len;
190
/* copy the rest (or all) of the URL */
191
PORT_Memcpy(str, urlstringitem.data, urlstringitem.len);
192
str += urlstringitem.len;
199
PORT_Free(urlstring);
205
PORT_FreeArena(arena, PR_FALSE);
207
if ( baseitem.data ) {
208
PORT_Free(baseitem.data);
210
if ( urlitem.data ) {
211
PORT_Free(urlitem.data);
218
* get the value of the Netscape Certificate Type Extension
221
CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
224
return (CERT_FindBitStringExtension
225
(cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));
230
* get the value of a string type extension
233
CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
235
SECItem wrapperItem, tmpItem = {siBuffer,0};
237
PRArenaPool *arena = NULL;
238
char *retstring = NULL;
240
wrapperItem.data = NULL;
243
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
249
rv = cert_FindExtension(cert->extensions, oidtag,
251
if ( rv != SECSuccess ) {
255
rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_IA5StringTemplate,
258
if ( rv != SECSuccess ) {
262
retstring = (char *)PORT_Alloc(tmpItem.len + 1 );
263
if ( retstring == NULL ) {
267
PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
268
retstring[tmpItem.len] = '\0';
272
PORT_FreeArena(arena, PR_FALSE);
275
if ( wrapperItem.data ) {
276
PORT_Free(wrapperItem.data);
283
* get the value of the X.509 v3 Key Usage Extension
286
CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
289
return (CERT_FindBitStringExtension(cert->extensions,
290
SEC_OID_X509_KEY_USAGE, retItem));
294
* get the value of the X.509 v3 Key Usage Extension
297
CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
301
SECItem encodedValue = {siBuffer, NULL, 0 };
302
SECItem decodedValue = {siBuffer, NULL, 0 };
304
rv = cert_FindExtension
305
(cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue);
306
if (rv == SECSuccess) {
307
PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
309
rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue,
310
SEC_OctetStringTemplate,
312
if (rv == SECSuccess) {
313
rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
315
PORT_FreeArena(tmpArena, PR_FALSE);
320
SECITEM_FreeItem(&encodedValue, PR_FALSE);
325
CERT_FindBasicConstraintExten(CERTCertificate *cert,
326
CERTBasicConstraints *value)
328
SECItem encodedExtenValue;
331
encodedExtenValue.data = NULL;
332
encodedExtenValue.len = 0;
334
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
336
if ( rv != SECSuccess ) {
340
rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue);
342
/* free the raw extension data */
343
PORT_Free(encodedExtenValue.data);
344
encodedExtenValue.data = NULL;
350
CERT_FindAuthKeyIDExten (PRArenaPool *arena, CERTCertificate *cert)
352
SECItem encodedExtenValue;
356
encodedExtenValue.data = NULL;
357
encodedExtenValue.len = 0;
359
rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
361
if ( rv != SECSuccess ) {
365
ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
367
PORT_Free(encodedExtenValue.data);
368
encodedExtenValue.data = NULL;
374
CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
379
/* There is no extension, v1 or v2 certificate */
380
if (cert->extensions == NULL) {
384
keyUsage.data = NULL;
386
/* This code formerly ignored the Key Usage extension if it was
387
** marked non-critical. That was wrong. Since we do understand it,
388
** we are obligated to honor it, whether or not it is critical.
390
rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
391
if (rv == SECFailure) {
392
rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ?
393
SECSuccess : SECFailure;
394
} else if (!(keyUsage.data[0] & usage)) {
395
PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID);
398
PORT_Free (keyUsage.data);