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 * Support for various policy related extensions
40 * $Id: polcyxtn.c,v 1.11 2008/02/13 04:03:19 julien.pierre.boogz%sun.com Exp $
52 SEC_ASN1_MKSUB(SEC_IntegerTemplate
)
53 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate
)
55 const SEC_ASN1Template CERT_DisplayTextTypeTemplate
[] = {
56 { SEC_ASN1_CHOICE
, offsetof(SECItem
, type
), 0, sizeof(SECItem
) },
57 { SEC_ASN1_IA5_STRING
, 0, 0, siAsciiString
},
58 { SEC_ASN1_VISIBLE_STRING
, 0, 0, siVisibleString
},
59 { SEC_ASN1_BMP_STRING
, 0, 0, siBMPString
},
60 { SEC_ASN1_UTF8_STRING
, 0, 0, siUTF8String
},
64 const SEC_ASN1Template CERT_NoticeReferenceTemplate
[] = {
66 0, NULL
, sizeof(CERTNoticeReference
) },
68 offsetof(CERTNoticeReference
, organization
),
69 CERT_DisplayTextTypeTemplate
, 0 },
70 { SEC_ASN1_SEQUENCE_OF
| SEC_ASN1_XTRN
,
71 offsetof(CERTNoticeReference
, noticeNumbers
),
72 SEC_ASN1_SUB(SEC_IntegerTemplate
) },
76 const SEC_ASN1Template CERT_UserNoticeTemplate
[] = {
78 0, NULL
, sizeof(CERTUserNotice
) },
79 { SEC_ASN1_INLINE
| SEC_ASN1_OPTIONAL
,
80 offsetof(CERTUserNotice
, noticeReference
),
81 CERT_NoticeReferenceTemplate
, 0 },
82 { SEC_ASN1_INLINE
| SEC_ASN1_OPTIONAL
,
83 offsetof(CERTUserNotice
, displayText
),
84 CERT_DisplayTextTypeTemplate
, 0 },
88 const SEC_ASN1Template CERT_PolicyQualifierTemplate
[] = {
90 0, NULL
, sizeof(CERTPolicyQualifier
) },
92 offsetof(CERTPolicyQualifier
, qualifierID
) },
94 offsetof(CERTPolicyQualifier
, qualifierValue
) },
98 const SEC_ASN1Template CERT_PolicyInfoTemplate
[] = {
100 0, NULL
, sizeof(CERTPolicyInfo
) },
101 { SEC_ASN1_OBJECT_ID
,
102 offsetof(CERTPolicyInfo
, policyID
) },
103 { SEC_ASN1_SEQUENCE_OF
| SEC_ASN1_OPTIONAL
,
104 offsetof(CERTPolicyInfo
, policyQualifiers
),
105 CERT_PolicyQualifierTemplate
},
109 const SEC_ASN1Template CERT_CertificatePoliciesTemplate
[] = {
110 { SEC_ASN1_SEQUENCE_OF
,
111 offsetof(CERTCertificatePolicies
, policyInfos
),
112 CERT_PolicyInfoTemplate
, sizeof(CERTCertificatePolicies
) }
115 const SEC_ASN1Template CERT_PolicyMapTemplate
[] = {
117 0, NULL
, sizeof(CERTPolicyMap
) },
118 { SEC_ASN1_OBJECT_ID
,
119 offsetof(CERTPolicyMap
, issuerDomainPolicy
) },
120 { SEC_ASN1_OBJECT_ID
,
121 offsetof(CERTPolicyMap
, subjectDomainPolicy
) },
125 const SEC_ASN1Template CERT_PolicyMappingsTemplate
[] = {
126 { SEC_ASN1_SEQUENCE_OF
,
127 offsetof(CERTCertificatePolicyMappings
, policyMaps
),
128 CERT_PolicyMapTemplate
, sizeof(CERTPolicyMap
) }
131 const SEC_ASN1Template CERT_PolicyConstraintsTemplate
[] = {
132 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(CERTCertificatePolicyConstraints
) },
133 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_XTRN
| 0,
134 offsetof(CERTCertificatePolicyConstraints
, explicitPolicySkipCerts
),
135 SEC_ASN1_SUB(SEC_IntegerTemplate
) },
136 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_XTRN
| 1,
137 offsetof(CERTCertificatePolicyConstraints
, inhibitMappingSkipCerts
),
138 SEC_ASN1_SUB(SEC_IntegerTemplate
) },
142 const SEC_ASN1Template CERT_InhibitAnyTemplate
[] = {
144 offsetof(CERTCertificateInhibitAny
, inhibitAnySkipCerts
),
145 NULL
, sizeof(CERTCertificateInhibitAny
) }
149 breakLines(char *string
)
152 char *lastspace
= NULL
;
158 while ( ( c
= *tmpstr
) != '\0' ) {
169 if ( ( curlen
>= 55 ) && ( lastspace
!= NULL
) ) {
171 curlen
= ( tmpstr
- lastspace
);
182 CERTCertificatePolicies
*
183 CERT_DecodeCertificatePoliciesExtension(SECItem
*extnValue
)
185 PRArenaPool
*arena
= NULL
;
187 CERTCertificatePolicies
*policies
;
188 CERTPolicyInfo
**policyInfos
, *policyInfo
;
189 CERTPolicyQualifier
**policyQualifiers
, *policyQualifier
;
190 SECItem newExtnValue
;
192 /* make a new arena */
193 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
199 /* allocate the certificate policies structure */
200 policies
= (CERTCertificatePolicies
*)
201 PORT_ArenaZAlloc(arena
, sizeof(CERTCertificatePolicies
));
203 if ( policies
== NULL
) {
207 policies
->arena
= arena
;
209 /* copy the DER into the arena, since Quick DER returns data that points
210 into the DER input, which may get freed by the caller */
211 rv
= SECITEM_CopyItem(arena
, &newExtnValue
, extnValue
);
212 if ( rv
!= SECSuccess
) {
216 /* decode the policy info */
217 rv
= SEC_QuickDERDecodeItem(arena
, policies
, CERT_CertificatePoliciesTemplate
,
220 if ( rv
!= SECSuccess
) {
224 /* initialize the oid tags */
225 policyInfos
= policies
->policyInfos
;
226 while (*policyInfos
!= NULL
) {
227 policyInfo
= *policyInfos
;
228 policyInfo
->oid
= SECOID_FindOIDTag(&policyInfo
->policyID
);
229 policyQualifiers
= policyInfo
->policyQualifiers
;
230 while ( policyQualifiers
!= NULL
&& *policyQualifiers
!= NULL
) {
231 policyQualifier
= *policyQualifiers
;
232 policyQualifier
->oid
=
233 SECOID_FindOIDTag(&policyQualifier
->qualifierID
);
242 if ( arena
!= NULL
) {
243 PORT_FreeArena(arena
, PR_FALSE
);
250 CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies
*policies
)
252 if ( policies
!= NULL
) {
253 PORT_FreeArena(policies
->arena
, PR_FALSE
);
258 CERTCertificatePolicyMappings
*
259 CERT_DecodePolicyMappingsExtension(SECItem
*extnValue
)
261 PRArenaPool
*arena
= NULL
;
263 CERTCertificatePolicyMappings
*mappings
;
264 SECItem newExtnValue
;
266 /* make a new arena */
267 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
272 /* allocate the policy mappings structure */
273 mappings
= (CERTCertificatePolicyMappings
*)
274 PORT_ArenaZAlloc(arena
, sizeof(CERTCertificatePolicyMappings
));
275 if ( mappings
== NULL
) {
278 mappings
->arena
= arena
;
280 /* copy the DER into the arena, since Quick DER returns data that points
281 into the DER input, which may get freed by the caller */
282 rv
= SECITEM_CopyItem(arena
, &newExtnValue
, extnValue
);
283 if ( rv
!= SECSuccess
) {
287 /* decode the policy mappings */
288 rv
= SEC_QuickDERDecodeItem
289 (arena
, mappings
, CERT_PolicyMappingsTemplate
, &newExtnValue
);
290 if ( rv
!= SECSuccess
) {
297 if ( arena
!= NULL
) {
298 PORT_FreeArena(arena
, PR_FALSE
);
305 CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings
*mappings
)
307 if ( mappings
!= NULL
) {
308 PORT_FreeArena(mappings
->arena
, PR_FALSE
);
314 CERT_DecodePolicyConstraintsExtension
315 (CERTCertificatePolicyConstraints
*decodedValue
,
316 SECItem
*encodedValue
)
318 CERTCertificatePolicyConstraints decodeContext
;
319 PRArenaPool
*arena
= NULL
;
320 SECStatus rv
= SECSuccess
;
322 /* initialize so we can tell when an optional component is omitted */
323 PORT_Memset(&decodeContext
, 0, sizeof(decodeContext
));
325 /* make a new arena */
326 arena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
332 /* decode the policy constraints */
333 rv
= SEC_QuickDERDecodeItem(arena
,
334 &decodeContext
, CERT_PolicyConstraintsTemplate
, encodedValue
);
336 if ( rv
!= SECSuccess
) {
340 if (decodeContext
.explicitPolicySkipCerts
.len
== 0) {
341 *(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
= -1;
343 *(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
=
344 DER_GetInteger(&decodeContext
.explicitPolicySkipCerts
);
347 if (decodeContext
.inhibitMappingSkipCerts
.len
== 0) {
348 *(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
= -1;
350 *(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
=
351 DER_GetInteger(&decodeContext
.inhibitMappingSkipCerts
);
354 if ((*(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
==
356 (*(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
==
358 (*(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
==
360 (*(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
==
367 PORT_FreeArena(arena
, PR_FALSE
);
371 SECStatus CERT_DecodeInhibitAnyExtension
372 (CERTCertificateInhibitAny
*decodedValue
, SECItem
*encodedValue
)
374 CERTCertificateInhibitAny decodeContext
;
375 PRArenaPool
*arena
= NULL
;
376 SECStatus rv
= SECSuccess
;
378 /* make a new arena */
379 arena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
386 /* decode the policy mappings */
387 decodeContext
.inhibitAnySkipCerts
.type
= siUnsignedInteger
;
388 rv
= SEC_QuickDERDecodeItem(arena
,
389 &decodeContext
, CERT_InhibitAnyTemplate
, encodedValue
);
391 if ( rv
!= SECSuccess
) {
395 *(PRInt32
*)decodedValue
->inhibitAnySkipCerts
.data
=
396 DER_GetInteger(&decodeContext
.inhibitAnySkipCerts
);
400 PORT_FreeArena(arena
, PR_FALSE
);
405 CERT_DecodeUserNotice(SECItem
*noticeItem
)
407 PRArenaPool
*arena
= NULL
;
409 CERTUserNotice
*userNotice
;
410 SECItem newNoticeItem
;
412 /* make a new arena */
413 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
419 /* allocate the userNotice structure */
420 userNotice
= (CERTUserNotice
*)PORT_ArenaZAlloc(arena
,
421 sizeof(CERTUserNotice
));
423 if ( userNotice
== NULL
) {
427 userNotice
->arena
= arena
;
429 /* copy the DER into the arena, since Quick DER returns data that points
430 into the DER input, which may get freed by the caller */
431 rv
= SECITEM_CopyItem(arena
, &newNoticeItem
, noticeItem
);
432 if ( rv
!= SECSuccess
) {
436 /* decode the user notice */
437 rv
= SEC_QuickDERDecodeItem(arena
, userNotice
, CERT_UserNoticeTemplate
,
440 if ( rv
!= SECSuccess
) {
444 if (userNotice
->derNoticeReference
.data
!= NULL
) {
446 rv
= SEC_QuickDERDecodeItem(arena
, &userNotice
->noticeReference
,
447 CERT_NoticeReferenceTemplate
,
448 &userNotice
->derNoticeReference
);
449 if (rv
== SECFailure
) {
457 if ( arena
!= NULL
) {
458 PORT_FreeArena(arena
, PR_FALSE
);
465 CERT_DestroyUserNotice(CERTUserNotice
*userNotice
)
467 if ( userNotice
!= NULL
) {
468 PORT_FreeArena(userNotice
->arena
, PR_FALSE
);
473 static CERTPolicyStringCallback policyStringCB
= NULL
;
474 static void *policyStringCBArg
= NULL
;
477 CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb
, void *cbarg
)
480 policyStringCBArg
= cbarg
;
485 stringFromUserNotice(SECItem
*noticeItem
)
488 unsigned int len
, headerlen
;
490 CERTUserNotice
*userNotice
;
493 SECItem
*displayText
;
494 SECItem
**noticeNumbers
;
497 /* decode the user notice */
498 userNotice
= CERT_DecodeUserNotice(noticeItem
);
499 if ( userNotice
== NULL
) {
503 org
= &userNotice
->noticeReference
.organization
;
504 if ( (org
->len
!= 0 ) && ( policyStringCB
!= NULL
) ) {
505 /* has a noticeReference */
507 /* extract the org string */
509 stringbuf
= (char*)PORT_Alloc(len
+ 1);
510 if ( stringbuf
!= NULL
) {
511 PORT_Memcpy(stringbuf
, org
->data
, len
);
512 stringbuf
[len
] = '\0';
514 noticeNumbers
= userNotice
->noticeReference
.noticeNumbers
;
515 while ( *noticeNumbers
!= NULL
) {
516 /* XXX - only one byte integers right now*/
517 strnum
= (*noticeNumbers
)->data
[0];
518 policystr
= (* policyStringCB
)(stringbuf
,
521 if ( policystr
!= NULL
) {
522 if ( retstr
!= NULL
) {
523 retstr
= PR_sprintf_append(retstr
, "\n%s", policystr
);
525 retstr
= PR_sprintf_append(retstr
, "%s", policystr
);
528 PORT_Free(policystr
);
534 PORT_Free(stringbuf
);
538 if ( retstr
== NULL
) {
539 if ( userNotice
->displayText
.len
!= 0 ) {
540 displayText
= &userNotice
->displayText
;
542 if ( displayText
->len
> 2 ) {
543 if ( displayText
->data
[0] == SEC_ASN1_VISIBLE_STRING
) {
545 if ( displayText
->data
[1] & 0x80 ) {
546 /* multibyte length */
547 headerlen
+= ( displayText
->data
[1] & 0x7f );
550 len
= displayText
->len
- headerlen
;
551 retstr
= (char*)PORT_Alloc(len
+ 1);
552 if ( retstr
!= NULL
) {
553 PORT_Memcpy(retstr
, &displayText
->data
[headerlen
],len
);
561 CERT_DestroyUserNotice(userNotice
);
567 CERT_GetCertCommentString(CERTCertificate
*cert
)
569 char *retstring
= NULL
;
572 CERTCertificatePolicies
*policies
= NULL
;
573 CERTPolicyInfo
**policyInfos
;
574 CERTPolicyQualifier
**policyQualifiers
, *qualifier
;
576 policyItem
.data
= NULL
;
578 rv
= CERT_FindCertExtension(cert
, SEC_OID_X509_CERTIFICATE_POLICIES
,
580 if ( rv
!= SECSuccess
) {
584 policies
= CERT_DecodeCertificatePoliciesExtension(&policyItem
);
585 if ( policies
== NULL
) {
589 policyInfos
= policies
->policyInfos
;
590 /* search through policyInfos looking for the verisign policy */
591 while (*policyInfos
!= NULL
) {
592 if ( (*policyInfos
)->oid
== SEC_OID_VERISIGN_USER_NOTICES
) {
593 policyQualifiers
= (*policyInfos
)->policyQualifiers
;
594 /* search through the policy qualifiers looking for user notice */
595 while ( policyQualifiers
!= NULL
&& *policyQualifiers
!= NULL
) {
596 qualifier
= *policyQualifiers
;
597 if ( qualifier
->oid
== SEC_OID_PKIX_USER_NOTICE_QUALIFIER
) {
599 stringFromUserNotice(&qualifier
->qualifierValue
);
611 if ( policyItem
.data
!= NULL
) {
612 PORT_Free(policyItem
.data
);
615 if ( policies
!= NULL
) {
616 CERT_DestroyCertificatePoliciesExtension(policies
);
619 if ( retstring
== NULL
) {
620 retstring
= CERT_FindNSStringExtension(cert
,
621 SEC_OID_NS_CERT_EXT_COMMENT
);
624 if ( retstring
!= NULL
) {
625 breakLines(retstring
);
632 const SEC_ASN1Template CERT_OidSeqTemplate
[] = {
633 { SEC_ASN1_SEQUENCE_OF
| SEC_ASN1_XTRN
,
634 offsetof(CERTOidSequence
, oids
),
635 SEC_ASN1_SUB(SEC_ObjectIDTemplate
) }
639 CERT_DecodeOidSequence(SECItem
*seqItem
)
641 PRArenaPool
*arena
= NULL
;
643 CERTOidSequence
*oidSeq
;
646 /* make a new arena */
647 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
653 /* allocate the userNotice structure */
654 oidSeq
= (CERTOidSequence
*)PORT_ArenaZAlloc(arena
,
655 sizeof(CERTOidSequence
));
657 if ( oidSeq
== NULL
) {
661 oidSeq
->arena
= arena
;
663 /* copy the DER into the arena, since Quick DER returns data that points
664 into the DER input, which may get freed by the caller */
665 rv
= SECITEM_CopyItem(arena
, &newSeqItem
, seqItem
);
666 if ( rv
!= SECSuccess
) {
670 /* decode the user notice */
671 rv
= SEC_QuickDERDecodeItem(arena
, oidSeq
, CERT_OidSeqTemplate
, &newSeqItem
);
673 if ( rv
!= SECSuccess
) {
685 CERT_DestroyOidSequence(CERTOidSequence
*oidSeq
)
687 if ( oidSeq
!= NULL
) {
688 PORT_FreeArena(oidSeq
->arena
, PR_FALSE
);
694 CERT_GovtApprovedBitSet(CERTCertificate
*cert
)
698 CERTOidSequence
*oidSeq
= NULL
;
705 rv
= CERT_FindCertExtension(cert
, SEC_OID_X509_EXT_KEY_USAGE
, &extItem
);
706 if ( rv
!= SECSuccess
) {
710 oidSeq
= CERT_DecodeOidSequence(&extItem
);
711 if ( oidSeq
== NULL
) {
716 while ( oids
!= NULL
&& *oids
!= NULL
) {
719 oidTag
= SECOID_FindOIDTag(oid
);
721 if ( oidTag
== SEC_OID_NS_KEY_USAGE_GOVT_APPROVED
) {
734 if ( oidSeq
!= NULL
) {
735 CERT_DestroyOidSequence(oidSeq
);
737 if (extItem
.data
!= NULL
) {
738 PORT_Free(extItem
.data
);
745 CERT_EncodePolicyConstraintsExtension(PRArenaPool
*arena
,
746 CERTCertificatePolicyConstraints
*constr
,
749 SECStatus rv
= SECSuccess
;
751 PORT_Assert(constr
!= NULL
&& dest
!= NULL
);
752 if (constr
== NULL
|| dest
== NULL
) {
756 if (SEC_ASN1EncodeItem (arena
, dest
, constr
,
757 CERT_PolicyConstraintsTemplate
) == NULL
) {
764 CERT_EncodePolicyMappingExtension(PRArenaPool
*arena
,
765 CERTCertificatePolicyMappings
*mapping
,
768 SECStatus rv
= SECSuccess
;
770 PORT_Assert(mapping
!= NULL
&& dest
!= NULL
);
771 if (mapping
== NULL
|| dest
== NULL
) {
775 if (SEC_ASN1EncodeItem (arena
, dest
, mapping
,
776 CERT_PolicyMappingsTemplate
) == NULL
) {
785 CERT_EncodeCertPoliciesExtension(PRArenaPool
*arena
,
786 CERTPolicyInfo
**info
,
789 SECStatus rv
= SECSuccess
;
791 PORT_Assert(info
!= NULL
&& dest
!= NULL
);
792 if (info
== NULL
|| dest
== NULL
) {
796 if (SEC_ASN1EncodeItem (arena
, dest
, info
,
797 CERT_CertificatePoliciesTemplate
) == NULL
) {
804 CERT_EncodeUserNotice(PRArenaPool
*arena
,
805 CERTUserNotice
*notice
,
808 SECStatus rv
= SECSuccess
;
810 PORT_Assert(notice
!= NULL
&& dest
!= NULL
);
811 if (notice
== NULL
|| dest
== NULL
) {
815 if (SEC_ASN1EncodeItem(arena
, dest
,
816 notice
, CERT_UserNoticeTemplate
) == NULL
) {
824 CERT_EncodeNoticeReference(PRArenaPool
*arena
,
825 CERTNoticeReference
*reference
,
828 SECStatus rv
= SECSuccess
;
830 PORT_Assert(reference
!= NULL
&& dest
!= NULL
);
831 if (reference
== NULL
|| dest
== NULL
) {
835 if (SEC_ASN1EncodeItem (arena
, dest
, reference
,
836 CERT_NoticeReferenceTemplate
) == NULL
) {
844 CERT_EncodeInhibitAnyExtension(PRArenaPool
*arena
,
845 CERTCertificateInhibitAny
*certInhibitAny
,
848 SECStatus rv
= SECSuccess
;
850 PORT_Assert(certInhibitAny
!= NULL
&& dest
!= NULL
);
851 if (certInhibitAny
== NULL
|| dest
== NULL
) {
855 if (SEC_ASN1EncodeItem (arena
, dest
, certInhibitAny
,
856 CERT_InhibitAnyTemplate
) == NULL
) {