~ubuntu-branches/ubuntu/feisty/firefox/feisty-updates

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/certdb/certv3.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack, Alexander Sack
  • Date: 2008-06-23 15:08:12 UTC
  • mfrom: (1.1.24 upstream)
  • Revision ID: james.westby@ubuntu.com-20080623150812-sxdwhn3dz9pmapvf
Tags: 2.0.0.15+0nobinonly-0ubuntu0.7.4
[ Alexander Sack ]
* New security/stability upstream release (v2.0.0.15)
  - see USN-619-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
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/
 
8
 *
 
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.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
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.
 
20
 *
 
21
 * Contributor(s):
 
22
 *
 
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.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
/*
 
38
 * Code for dealing with X509.V3 extensions.
 
39
 *
 
40
 * $Id: certv3.c,v 1.8 2004/04/25 15:03:03 gerv%gerv.net Exp $
 
41
 */
 
42
 
 
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"
 
50
 
 
51
SECStatus
 
52
CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid,
 
53
                            SECItem *value)
 
54
{
 
55
    return (cert_FindExtensionByOID (cert->extensions, oid, value));
 
56
}
 
57
    
 
58
 
 
59
SECStatus
 
60
CERT_FindCertExtension(CERTCertificate *cert, int tag, SECItem *value)
 
61
{
 
62
    return (cert_FindExtension (cert->extensions, tag, value));
 
63
}
 
64
 
 
65
static void
 
66
SetExts(void *object, CERTCertExtension **exts)
 
67
{
 
68
    CERTCertificate *cert = (CERTCertificate *)object;
 
69
 
 
70
    cert->extensions = exts;
 
71
    DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
 
72
}
 
73
 
 
74
void *
 
75
CERT_StartCertExtensions(CERTCertificate *cert)
 
76
{
 
77
    return (cert_StartExtensions ((void *)cert, cert->arena, SetExts));
 
78
}
 
79
 
 
80
/* find the given extension in the certificate of the Issuer of 'cert' */
 
81
SECStatus
 
82
CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value)
 
83
{
 
84
    CERTCertificate *issuercert;
 
85
    SECStatus rv;
 
86
 
 
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;
 
93
    }
 
94
    
 
95
    return(rv);
 
96
}
 
97
 
 
98
/* find a URL extension in the cert or its CA
 
99
 * apply the base URL string if it exists
 
100
 */
 
101
char *
 
102
CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag)
 
103
{
 
104
    SECStatus rv;
 
105
    SECItem urlitem;
 
106
    SECItem baseitem;
 
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;
 
115
    
 
116
    urlstring = NULL;
 
117
 
 
118
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
119
    if ( ! arena ) {
 
120
        goto loser;
 
121
    }
 
122
    
 
123
    hasbase = PR_FALSE;
 
124
    urlitem.data = NULL;
 
125
    baseitem.data = NULL;
 
126
    
 
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,
 
130
                                   &baseitem);
 
131
        if ( rv == SECSuccess ) {
 
132
            hasbase = PR_TRUE;
 
133
        }
 
134
        
 
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 ) {
 
139
            goto loser;
 
140
        }           
 
141
        rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL,
 
142
                                         &baseitem);
 
143
        if ( rv == SECSuccess ) {
 
144
            hasbase = PR_TRUE;
 
145
        }
 
146
    } else {
 
147
        goto loser;
 
148
    }
 
149
 
 
150
    rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, SEC_IA5StringTemplate, 
 
151
                            &urlitem);
 
152
 
 
153
    if ( rv != SECSuccess ) {
 
154
        goto loser;
 
155
    }
 
156
    if ( hasbase ) {
 
157
        rv = SEC_QuickDERDecodeItem(arena, &basestringitem, SEC_IA5StringTemplate,
 
158
                                &baseitem);
 
159
 
 
160
        if ( rv != SECSuccess ) {
 
161
            goto loser;
 
162
        }
 
163
    }
 
164
    
 
165
    len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1;
 
166
    
 
167
    str = urlstring = (char *)PORT_Alloc(len);
 
168
    if ( urlstring == NULL ) {
 
169
        goto loser;
 
170
    }
 
171
    
 
172
    /* copy the URL base first */
 
173
    if ( hasbase ) {
 
174
 
 
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
 
177
         */
 
178
        for ( i = 0; i < urlstringitem.len; i++ ) {
 
179
            if ( urlstringitem.data[i] == ':' ) {
 
180
                goto nobase;
 
181
            }
 
182
        }
 
183
        
 
184
        PORT_Memcpy(str, basestringitem.data, basestringitem.len);
 
185
        str += basestringitem.len;
 
186
        
 
187
    }
 
188
 
 
189
nobase:
 
190
    /* copy the rest (or all) of the URL */
 
191
    PORT_Memcpy(str, urlstringitem.data, urlstringitem.len);
 
192
    str += urlstringitem.len;
 
193
    
 
194
    *str = '\0';
 
195
    goto done;
 
196
    
 
197
loser:
 
198
    if ( urlstring ) {
 
199
        PORT_Free(urlstring);
 
200
    }
 
201
    
 
202
    urlstring = NULL;
 
203
done:
 
204
    if ( arena ) {
 
205
        PORT_FreeArena(arena, PR_FALSE);
 
206
    }
 
207
    if ( baseitem.data ) {
 
208
        PORT_Free(baseitem.data);
 
209
    }
 
210
    if ( urlitem.data ) {
 
211
        PORT_Free(urlitem.data);
 
212
    }
 
213
 
 
214
    return(urlstring);
 
215
}
 
216
 
 
217
/*
 
218
 * get the value of the Netscape Certificate Type Extension
 
219
 */
 
220
SECStatus
 
221
CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
 
222
{
 
223
 
 
224
    return (CERT_FindBitStringExtension
 
225
            (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));    
 
226
}
 
227
 
 
228
 
 
229
/*
 
230
 * get the value of a string type extension
 
231
 */
 
232
char *
 
233
CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
 
234
{
 
235
    SECItem wrapperItem, tmpItem = {siBuffer,0};
 
236
    SECStatus rv;
 
237
    PRArenaPool *arena = NULL;
 
238
    char *retstring = NULL;
 
239
    
 
240
    wrapperItem.data = NULL;
 
241
    tmpItem.data = NULL;
 
242
    
 
243
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
244
    
 
245
    if ( ! arena ) {
 
246
        goto loser;
 
247
    }
 
248
    
 
249
    rv = cert_FindExtension(cert->extensions, oidtag,
 
250
                               &wrapperItem);
 
251
    if ( rv != SECSuccess ) {
 
252
        goto loser;
 
253
    }
 
254
 
 
255
    rv = SEC_QuickDERDecodeItem(arena, &tmpItem, SEC_IA5StringTemplate, 
 
256
                            &wrapperItem);
 
257
 
 
258
    if ( rv != SECSuccess ) {
 
259
        goto loser;
 
260
    }
 
261
 
 
262
    retstring = (char *)PORT_Alloc(tmpItem.len + 1 );
 
263
    if ( retstring == NULL ) {
 
264
        goto loser;
 
265
    }
 
266
    
 
267
    PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
 
268
    retstring[tmpItem.len] = '\0';
 
269
 
 
270
loser:
 
271
    if ( arena ) {
 
272
        PORT_FreeArena(arena, PR_FALSE);
 
273
    }
 
274
    
 
275
    if ( wrapperItem.data ) {
 
276
        PORT_Free(wrapperItem.data);
 
277
    }
 
278
 
 
279
    return(retstring);
 
280
}
 
281
 
 
282
/*
 
283
 * get the value of the X.509 v3 Key Usage Extension
 
284
 */
 
285
SECStatus
 
286
CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
 
287
{
 
288
 
 
289
    return (CERT_FindBitStringExtension(cert->extensions,
 
290
                                        SEC_OID_X509_KEY_USAGE, retItem));    
 
291
}
 
292
 
 
293
/*
 
294
 * get the value of the X.509 v3 Key Usage Extension
 
295
 */
 
296
SECStatus
 
297
CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
 
298
{
 
299
 
 
300
    SECStatus rv;
 
301
    SECItem encodedValue = {siBuffer, NULL, 0 };
 
302
    SECItem decodedValue = {siBuffer, NULL, 0 };
 
303
 
 
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);
 
308
        if (tmpArena) {
 
309
            rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, 
 
310
                                        SEC_OctetStringTemplate, 
 
311
                                        &encodedValue);
 
312
            if (rv == SECSuccess) {
 
313
                rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
 
314
            }
 
315
            PORT_FreeArena(tmpArena, PR_FALSE);
 
316
        } else {
 
317
            rv = SECFailure;
 
318
        }
 
319
    }
 
320
    SECITEM_FreeItem(&encodedValue, PR_FALSE);
 
321
    return rv;
 
322
}
 
323
 
 
324
SECStatus
 
325
CERT_FindBasicConstraintExten(CERTCertificate *cert,
 
326
                              CERTBasicConstraints *value)
 
327
{
 
328
    SECItem encodedExtenValue;
 
329
    SECStatus rv;
 
330
 
 
331
    encodedExtenValue.data = NULL;
 
332
    encodedExtenValue.len = 0;
 
333
 
 
334
    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
 
335
                            &encodedExtenValue);
 
336
    if ( rv != SECSuccess ) {
 
337
        return (rv);
 
338
    }
 
339
 
 
340
    rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue);
 
341
    
 
342
    /* free the raw extension data */
 
343
    PORT_Free(encodedExtenValue.data);
 
344
    encodedExtenValue.data = NULL;
 
345
    
 
346
    return(rv);
 
347
}
 
348
 
 
349
CERTAuthKeyID *
 
350
CERT_FindAuthKeyIDExten (PRArenaPool *arena, CERTCertificate *cert)
 
351
{
 
352
    SECItem encodedExtenValue;
 
353
    SECStatus rv;
 
354
    CERTAuthKeyID *ret;
 
355
    
 
356
    encodedExtenValue.data = NULL;
 
357
    encodedExtenValue.len = 0;
 
358
 
 
359
    rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
 
360
                            &encodedExtenValue);
 
361
    if ( rv != SECSuccess ) {
 
362
        return (NULL);
 
363
    }
 
364
 
 
365
    ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
 
366
 
 
367
    PORT_Free(encodedExtenValue.data);
 
368
    encodedExtenValue.data = NULL;
 
369
    
 
370
    return(ret);
 
371
}
 
372
 
 
373
SECStatus
 
374
CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
 
375
{
 
376
    SECItem keyUsage;
 
377
    SECStatus rv;
 
378
 
 
379
    /* There is no extension, v1 or v2 certificate */
 
380
    if (cert->extensions == NULL) {
 
381
        return (SECSuccess);
 
382
    }
 
383
    
 
384
    keyUsage.data = NULL;
 
385
 
 
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.
 
389
    */
 
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);
 
396
        rv = SECFailure;
 
397
    }
 
398
    PORT_Free (keyUsage.data);
 
399
    return (rv);
 
400
}