~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

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
 * Support for various policy related extensions
 
39
 *
 
40
 * $Id: polcyxtn.c,v 1.6 2004/04/25 15:03:03 gerv%gerv.net Exp $
 
41
 */
 
42
 
 
43
#include "seccomon.h"
 
44
#include "secport.h"
 
45
#include "secder.h"
 
46
#include "cert.h"
 
47
#include "secoid.h"
 
48
#include "secasn1.h"
 
49
#include "secerr.h"
 
50
#include "nspr.h"
 
51
 
 
52
const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
 
53
    { SEC_ASN1_SEQUENCE,
 
54
          0, NULL, sizeof(CERTNoticeReference) },
 
55
/* NOTE: this should be a choice */
 
56
    { SEC_ASN1_IA5_STRING,
 
57
          offsetof(CERTNoticeReference, organization) },
 
58
    { SEC_ASN1_SEQUENCE_OF,
 
59
          offsetof(CERTNoticeReference, noticeNumbers),
 
60
          SEC_IntegerTemplate }, 
 
61
    { 0 }
 
62
};
 
63
 
 
64
/* this template can not be encoded because of the option inline */
 
65
const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
 
66
    { SEC_ASN1_SEQUENCE,
 
67
          0, NULL, sizeof(CERTUserNotice) },
 
68
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED,
 
69
          offsetof(CERTUserNotice, derNoticeReference) }, 
 
70
    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
 
71
          offsetof(CERTUserNotice, displayText) }, 
 
72
    { 0 }
 
73
};
 
74
 
 
75
const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
 
76
    { SEC_ASN1_SEQUENCE,
 
77
          0, NULL, sizeof(CERTPolicyQualifier) },
 
78
    { SEC_ASN1_OBJECT_ID,
 
79
          offsetof(CERTPolicyQualifier, qualifierID) },
 
80
    { SEC_ASN1_ANY,
 
81
          offsetof(CERTPolicyQualifier, qualifierValue) },
 
82
    { 0 }
 
83
};
 
84
 
 
85
const SEC_ASN1Template CERT_PolicyInfoTemplate[] = {
 
86
    { SEC_ASN1_SEQUENCE,
 
87
          0, NULL, sizeof(CERTPolicyInfo) },
 
88
    { SEC_ASN1_OBJECT_ID,
 
89
          offsetof(CERTPolicyInfo, policyID) },
 
90
    { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL,
 
91
          offsetof(CERTPolicyInfo, policyQualifiers),
 
92
          CERT_PolicyQualifierTemplate },
 
93
    { 0 }
 
94
};
 
95
 
 
96
const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
 
97
    { SEC_ASN1_SEQUENCE_OF,
 
98
          offsetof(CERTCertificatePolicies, policyInfos),
 
99
          CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies)  }
 
100
};
 
101
 
 
102
static void
 
103
breakLines(char *string)
 
104
{
 
105
    char *tmpstr;
 
106
    char *lastspace = NULL;
 
107
    int curlen = 0;
 
108
    int c;
 
109
    
 
110
    tmpstr = string;
 
111
 
 
112
    while ( ( c = *tmpstr ) != '\0' ) {
 
113
        switch ( c ) {
 
114
          case ' ':
 
115
            lastspace = tmpstr;
 
116
            break;
 
117
          case '\n':
 
118
            lastspace = NULL;
 
119
            curlen = 0;
 
120
            break;
 
121
        }
 
122
        
 
123
        if ( ( curlen >= 55 ) && ( lastspace != NULL ) ) {
 
124
            *lastspace = '\n';
 
125
            curlen = ( tmpstr - lastspace );
 
126
            lastspace = NULL;
 
127
        }
 
128
        
 
129
        curlen++;
 
130
        tmpstr++;
 
131
    }
 
132
    
 
133
    return;
 
134
}
 
135
 
 
136
CERTCertificatePolicies *
 
137
CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue)
 
138
{
 
139
    PRArenaPool *arena = NULL;
 
140
    SECStatus rv;
 
141
    CERTCertificatePolicies *policies;
 
142
    CERTPolicyInfo **policyInfos, *policyInfo;
 
143
    CERTPolicyQualifier **policyQualifiers, *policyQualifier;
 
144
    SECItem newExtnValue;
 
145
    
 
146
    /* make a new arena */
 
147
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
148
    
 
149
    if ( !arena ) {
 
150
        goto loser;
 
151
    }
 
152
 
 
153
    /* allocate the certifiate policies structure */
 
154
    policies = (CERTCertificatePolicies *)
 
155
        PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicies));
 
156
    
 
157
    if ( policies == NULL ) {
 
158
        goto loser;
 
159
    }
 
160
    
 
161
    policies->arena = arena;
 
162
 
 
163
    /* copy the DER into the arena, since Quick DER returns data that points
 
164
       into the DER input, which may get freed by the caller */
 
165
    rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
 
166
    if ( rv != SECSuccess ) {
 
167
        goto loser;
 
168
    }
 
169
 
 
170
    /* decode the policy info */
 
171
    rv = SEC_QuickDERDecodeItem(arena, policies, CERT_CertificatePoliciesTemplate,
 
172
                            &newExtnValue);
 
173
 
 
174
    if ( rv != SECSuccess ) {
 
175
        goto loser;
 
176
    }
 
177
 
 
178
    /* initialize the oid tags */
 
179
    policyInfos = policies->policyInfos;
 
180
    while (*policyInfos != NULL ) {
 
181
        policyInfo = *policyInfos;
 
182
        policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
 
183
        policyQualifiers = policyInfo->policyQualifiers;
 
184
        while ( policyQualifiers != NULL && *policyQualifiers != NULL ) {
 
185
            policyQualifier = *policyQualifiers;
 
186
            policyQualifier->oid =
 
187
                SECOID_FindOIDTag(&policyQualifier->qualifierID);
 
188
            policyQualifiers++;
 
189
        }
 
190
        policyInfos++;
 
191
    }
 
192
 
 
193
    return(policies);
 
194
    
 
195
loser:
 
196
    if ( arena != NULL ) {
 
197
        PORT_FreeArena(arena, PR_FALSE);
 
198
    }
 
199
    
 
200
    return(NULL);
 
201
}
 
202
 
 
203
void
 
204
CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
 
205
{
 
206
    if ( policies != NULL ) {
 
207
        PORT_FreeArena(policies->arena, PR_FALSE);
 
208
    }
 
209
    return;
 
210
}
 
211
 
 
212
 
 
213
CERTUserNotice *
 
214
CERT_DecodeUserNotice(SECItem *noticeItem)
 
215
{
 
216
    PRArenaPool *arena = NULL;
 
217
    SECStatus rv;
 
218
    CERTUserNotice *userNotice;
 
219
    SECItem newNoticeItem;
 
220
    
 
221
    /* make a new arena */
 
222
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
223
    
 
224
    if ( !arena ) {
 
225
        goto loser;
 
226
    }
 
227
 
 
228
    /* allocate the userNotice structure */
 
229
    userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena,
 
230
                                                    sizeof(CERTUserNotice));
 
231
    
 
232
    if ( userNotice == NULL ) {
 
233
        goto loser;
 
234
    }
 
235
    
 
236
    userNotice->arena = arena;
 
237
 
 
238
    /* copy the DER into the arena, since Quick DER returns data that points
 
239
       into the DER input, which may get freed by the caller */
 
240
    rv = SECITEM_CopyItem(arena, &newNoticeItem, noticeItem);
 
241
    if ( rv != SECSuccess ) {
 
242
        goto loser;
 
243
    }
 
244
 
 
245
    /* decode the user notice */
 
246
    rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate, 
 
247
                            &newNoticeItem);
 
248
 
 
249
    if ( rv != SECSuccess ) {
 
250
        goto loser;
 
251
    }
 
252
 
 
253
    if (userNotice->derNoticeReference.data != NULL) {
 
254
        /* sigh, the asn1 parser stripped the sequence encoding, re add it
 
255
         * before we decode.
 
256
         */
 
257
        SECItem tmpbuf;
 
258
        int     newBytes;
 
259
 
 
260
        newBytes = SEC_ASN1LengthLength(userNotice->derNoticeReference.len)+1;
 
261
        tmpbuf.len = newBytes + userNotice->derNoticeReference.len;
 
262
        tmpbuf.data = PORT_ArenaZAlloc(arena, tmpbuf.len);
 
263
        if (tmpbuf.data == NULL) {
 
264
            goto loser;
 
265
        }
 
266
        tmpbuf.data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
 
267
        SEC_ASN1EncodeLength(&tmpbuf.data[1],userNotice->derNoticeReference.len);
 
268
        PORT_Memcpy(&tmpbuf.data[newBytes],userNotice->derNoticeReference.data,
 
269
                                userNotice->derNoticeReference.len);
 
270
 
 
271
        /* OK, no decode it */
 
272
        rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference, 
 
273
            CERT_NoticeReferenceTemplate, &tmpbuf);
 
274
 
 
275
        PORT_Free(tmpbuf.data); tmpbuf.data = NULL;
 
276
        if ( rv != SECSuccess ) {
 
277
            goto loser;
 
278
        }
 
279
    }
 
280
 
 
281
    return(userNotice);
 
282
    
 
283
loser:
 
284
    if ( arena != NULL ) {
 
285
        PORT_FreeArena(arena, PR_FALSE);
 
286
    }
 
287
    
 
288
    return(NULL);
 
289
}
 
290
 
 
291
void
 
292
CERT_DestroyUserNotice(CERTUserNotice *userNotice)
 
293
{
 
294
    if ( userNotice != NULL ) {
 
295
        PORT_FreeArena(userNotice->arena, PR_FALSE);
 
296
    }
 
297
    return;
 
298
}
 
299
 
 
300
static CERTPolicyStringCallback policyStringCB = NULL;
 
301
static void *policyStringCBArg = NULL;
 
302
 
 
303
void
 
304
CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
 
305
{
 
306
    policyStringCB = cb;
 
307
    policyStringCBArg = cbarg;
 
308
    return;
 
309
}
 
310
 
 
311
char *
 
312
stringFromUserNotice(SECItem *noticeItem)
 
313
{
 
314
    SECItem *org;
 
315
    unsigned int len, headerlen;
 
316
    char *stringbuf;
 
317
    CERTUserNotice *userNotice;
 
318
    char *policystr;
 
319
    char *retstr = NULL;
 
320
    SECItem *displayText;
 
321
    SECItem **noticeNumbers;
 
322
    unsigned int strnum;
 
323
    
 
324
    /* decode the user notice */
 
325
    userNotice = CERT_DecodeUserNotice(noticeItem);
 
326
    if ( userNotice == NULL ) {
 
327
        return(NULL);
 
328
    }
 
329
    
 
330
    org = &userNotice->noticeReference.organization;
 
331
    if ( (org->len != 0 ) && ( policyStringCB != NULL ) ) {
 
332
        /* has a noticeReference */
 
333
 
 
334
        /* extract the org string */
 
335
        len = org->len;
 
336
        stringbuf = (char*)PORT_Alloc(len + 1);
 
337
        if ( stringbuf != NULL ) {
 
338
            PORT_Memcpy(stringbuf, org->data, len);
 
339
            stringbuf[len] = '\0';
 
340
 
 
341
            noticeNumbers = userNotice->noticeReference.noticeNumbers;
 
342
            while ( *noticeNumbers != NULL ) {
 
343
                /* XXX - only one byte integers right now*/
 
344
                strnum = (*noticeNumbers)->data[0];
 
345
                policystr = (* policyStringCB)(stringbuf,
 
346
                                               strnum,
 
347
                                               policyStringCBArg);
 
348
                if ( policystr != NULL ) {
 
349
                    if ( retstr != NULL ) {
 
350
                        retstr = PR_sprintf_append(retstr, "\n%s", policystr);
 
351
                    } else {
 
352
                        retstr = PR_sprintf_append(retstr, "%s", policystr);
 
353
                    }
 
354
 
 
355
                    PORT_Free(policystr);
 
356
                }
 
357
                
 
358
                noticeNumbers++;
 
359
            }
 
360
 
 
361
            PORT_Free(stringbuf);
 
362
        }
 
363
    }
 
364
 
 
365
    if ( retstr == NULL ) {
 
366
        if ( userNotice->displayText.len != 0 ) {
 
367
            displayText = &userNotice->displayText;
 
368
 
 
369
            if ( displayText->len > 2 ) {
 
370
                if ( displayText->data[0] == SEC_ASN1_VISIBLE_STRING ) {
 
371
                    headerlen = 2;
 
372
                    if ( displayText->data[1] & 0x80 ) {
 
373
                        /* multibyte length */
 
374
                        headerlen += ( displayText->data[1] & 0x7f );
 
375
                    }
 
376
 
 
377
                    len = displayText->len - headerlen;
 
378
                    retstr = (char*)PORT_Alloc(len + 1);
 
379
                    if ( retstr != NULL ) {
 
380
                        PORT_Memcpy(retstr, &displayText->data[headerlen],len);
 
381
                        retstr[len] = '\0';
 
382
                    }
 
383
                }
 
384
            }
 
385
        }
 
386
    }
 
387
    
 
388
    CERT_DestroyUserNotice(userNotice);
 
389
    
 
390
    return(retstr);
 
391
}
 
392
 
 
393
char *
 
394
CERT_GetCertCommentString(CERTCertificate *cert)
 
395
{
 
396
    char *retstring = NULL;
 
397
    SECStatus rv;
 
398
    SECItem policyItem;
 
399
    CERTCertificatePolicies *policies = NULL;
 
400
    CERTPolicyInfo **policyInfos;
 
401
    CERTPolicyQualifier **policyQualifiers, *qualifier;
 
402
 
 
403
    policyItem.data = NULL;
 
404
    
 
405
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
 
406
                                &policyItem);
 
407
    if ( rv != SECSuccess ) {
 
408
        goto nopolicy;
 
409
    }
 
410
 
 
411
    policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
 
412
    if ( policies == NULL ) {
 
413
        goto nopolicy;
 
414
    }
 
415
 
 
416
    policyInfos = policies->policyInfos;
 
417
    /* search through policyInfos looking for the verisign policy */
 
418
    while (*policyInfos != NULL ) {
 
419
        if ( (*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES ) {
 
420
            policyQualifiers = (*policyInfos)->policyQualifiers;
 
421
            /* search through the policy qualifiers looking for user notice */
 
422
            while ( policyQualifiers != NULL && *policyQualifiers != NULL ) {
 
423
                qualifier = *policyQualifiers;
 
424
                if ( qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER ) {
 
425
                    retstring =
 
426
                        stringFromUserNotice(&qualifier->qualifierValue);
 
427
                    break;
 
428
                }
 
429
 
 
430
                policyQualifiers++;
 
431
            }
 
432
            break;
 
433
        }
 
434
        policyInfos++;
 
435
    }
 
436
 
 
437
nopolicy:
 
438
    if ( policyItem.data != NULL ) {
 
439
        PORT_Free(policyItem.data);
 
440
    }
 
441
 
 
442
    if ( policies != NULL ) {
 
443
        CERT_DestroyCertificatePoliciesExtension(policies);
 
444
    }
 
445
    
 
446
    if ( retstring == NULL ) {
 
447
        retstring = CERT_FindNSStringExtension(cert,
 
448
                                               SEC_OID_NS_CERT_EXT_COMMENT);
 
449
    }
 
450
    
 
451
    if ( retstring != NULL ) {
 
452
        breakLines(retstring);
 
453
    }
 
454
    
 
455
    return(retstring);
 
456
}
 
457
 
 
458
 
 
459
const SEC_ASN1Template CERT_OidSeqTemplate[] = {
 
460
    { SEC_ASN1_SEQUENCE_OF,
 
461
          offsetof(CERTOidSequence, oids),
 
462
          SEC_ObjectIDTemplate }
 
463
};
 
464
 
 
465
CERTOidSequence *
 
466
CERT_DecodeOidSequence(SECItem *seqItem)
 
467
{
 
468
    PRArenaPool *arena = NULL;
 
469
    SECStatus rv;
 
470
    CERTOidSequence *oidSeq;
 
471
    SECItem newSeqItem;
 
472
    
 
473
    /* make a new arena */
 
474
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
 
475
    
 
476
    if ( !arena ) {
 
477
        goto loser;
 
478
    }
 
479
 
 
480
    /* allocate the userNotice structure */
 
481
    oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena,
 
482
                                                 sizeof(CERTOidSequence));
 
483
    
 
484
    if ( oidSeq == NULL ) {
 
485
        goto loser;
 
486
    }
 
487
    
 
488
    oidSeq->arena = arena;
 
489
 
 
490
    /* copy the DER into the arena, since Quick DER returns data that points
 
491
       into the DER input, which may get freed by the caller */
 
492
    rv = SECITEM_CopyItem(arena, &newSeqItem, seqItem);
 
493
    if ( rv != SECSuccess ) {
 
494
        goto loser;
 
495
    }
 
496
 
 
497
    /* decode the user notice */
 
498
    rv = SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
 
499
 
 
500
    if ( rv != SECSuccess ) {
 
501
        goto loser;
 
502
    }
 
503
 
 
504
    return(oidSeq);
 
505
    
 
506
loser:
 
507
    return(NULL);
 
508
}
 
509
 
 
510
 
 
511
void
 
512
CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
 
513
{
 
514
    if ( oidSeq != NULL ) {
 
515
        PORT_FreeArena(oidSeq->arena, PR_FALSE);
 
516
    }
 
517
    return;
 
518
}
 
519
 
 
520
PRBool
 
521
CERT_GovtApprovedBitSet(CERTCertificate *cert)
 
522
{
 
523
    SECStatus rv;
 
524
    SECItem extItem;
 
525
    CERTOidSequence *oidSeq = NULL;
 
526
    PRBool ret;
 
527
    SECItem **oids;
 
528
    SECItem *oid;
 
529
    SECOidTag oidTag;
 
530
    
 
531
    extItem.data = NULL;
 
532
    rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
 
533
    if ( rv != SECSuccess ) {
 
534
        goto loser;
 
535
    }
 
536
 
 
537
    oidSeq = CERT_DecodeOidSequence(&extItem);
 
538
    if ( oidSeq == NULL ) {
 
539
        goto loser;
 
540
    }
 
541
 
 
542
    oids = oidSeq->oids;
 
543
    while ( oids != NULL && *oids != NULL ) {
 
544
        oid = *oids;
 
545
        
 
546
        oidTag = SECOID_FindOIDTag(oid);
 
547
        
 
548
        if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) {
 
549
            goto success;
 
550
        }
 
551
        
 
552
        oids++;
 
553
    }
 
554
 
 
555
loser:
 
556
    ret = PR_FALSE;
 
557
    goto done;
 
558
success:
 
559
    ret = PR_TRUE;
 
560
done:
 
561
    if ( oidSeq != NULL ) {
 
562
        CERT_DestroyOidSequence(oidSeq);
 
563
    }
 
564
    if (extItem.data != NULL) {
 
565
        PORT_Free(extItem.data);
 
566
    }
 
567
    return(ret);
 
568
}