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.7 2007/05/25 07:28:32 alexei.volkov.bugs%sun.com Exp $
52 const SEC_ASN1Template CERT_NoticeReferenceTemplate
[] = {
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
},
64 /* this template can not be encoded because of the option inline */
65 const SEC_ASN1Template CERT_UserNoticeTemplate
[] = {
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
) },
75 const SEC_ASN1Template CERT_PolicyQualifierTemplate
[] = {
77 0, NULL
, sizeof(CERTPolicyQualifier
) },
79 offsetof(CERTPolicyQualifier
, qualifierID
) },
81 offsetof(CERTPolicyQualifier
, qualifierValue
) },
85 const SEC_ASN1Template CERT_PolicyInfoTemplate
[] = {
87 0, NULL
, sizeof(CERTPolicyInfo
) },
89 offsetof(CERTPolicyInfo
, policyID
) },
90 { SEC_ASN1_SEQUENCE_OF
| SEC_ASN1_OPTIONAL
,
91 offsetof(CERTPolicyInfo
, policyQualifiers
),
92 CERT_PolicyQualifierTemplate
},
96 const SEC_ASN1Template CERT_CertificatePoliciesTemplate
[] = {
97 { SEC_ASN1_SEQUENCE_OF
,
98 offsetof(CERTCertificatePolicies
, policyInfos
),
99 CERT_PolicyInfoTemplate
, sizeof(CERTCertificatePolicies
) }
102 const SEC_ASN1Template CERT_PolicyMapTemplate
[] = {
104 0, NULL
, sizeof(CERTPolicyMap
) },
105 { SEC_ASN1_OBJECT_ID
,
106 offsetof(CERTPolicyMap
, issuerDomainPolicy
) },
107 { SEC_ASN1_OBJECT_ID
,
108 offsetof(CERTPolicyMap
, subjectDomainPolicy
) },
112 const SEC_ASN1Template CERT_PolicyMappingsTemplate
[] = {
113 { SEC_ASN1_SEQUENCE_OF
,
114 offsetof(CERTCertificatePolicyMappings
, policyMaps
),
115 CERT_PolicyMapTemplate
, sizeof(CERTPolicyMap
) }
118 const SEC_ASN1Template CERT_PolicyConstraintsTemplate
[] = {
119 { SEC_ASN1_SEQUENCE
, 0, NULL
, sizeof(CERTCertificatePolicyConstraints
) },
120 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONTEXT_SPECIFIC
| 0,
121 offsetof(CERTCertificatePolicyConstraints
, explicitPolicySkipCerts
),
122 SEC_IntegerTemplate
},
123 { SEC_ASN1_OPTIONAL
| SEC_ASN1_CONTEXT_SPECIFIC
| 1,
124 offsetof(CERTCertificatePolicyConstraints
, inhibitMappingSkipCerts
),
125 SEC_IntegerTemplate
},
129 const SEC_ASN1Template CERT_InhibitAnyTemplate
[] = {
131 offsetof(CERTCertificateInhibitAny
, inhibitAnySkipCerts
),
132 NULL
, sizeof(CERTCertificateInhibitAny
) }
136 breakLines(char *string
)
139 char *lastspace
= NULL
;
145 while ( ( c
= *tmpstr
) != '\0' ) {
156 if ( ( curlen
>= 55 ) && ( lastspace
!= NULL
) ) {
158 curlen
= ( tmpstr
- lastspace
);
169 CERTCertificatePolicies
*
170 CERT_DecodeCertificatePoliciesExtension(SECItem
*extnValue
)
172 PRArenaPool
*arena
= NULL
;
174 CERTCertificatePolicies
*policies
;
175 CERTPolicyInfo
**policyInfos
, *policyInfo
;
176 CERTPolicyQualifier
**policyQualifiers
, *policyQualifier
;
177 SECItem newExtnValue
;
179 /* make a new arena */
180 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
186 /* allocate the certificate policies structure */
187 policies
= (CERTCertificatePolicies
*)
188 PORT_ArenaZAlloc(arena
, sizeof(CERTCertificatePolicies
));
190 if ( policies
== NULL
) {
194 policies
->arena
= arena
;
196 /* copy the DER into the arena, since Quick DER returns data that points
197 into the DER input, which may get freed by the caller */
198 rv
= SECITEM_CopyItem(arena
, &newExtnValue
, extnValue
);
199 if ( rv
!= SECSuccess
) {
203 /* decode the policy info */
204 rv
= SEC_QuickDERDecodeItem(arena
, policies
, CERT_CertificatePoliciesTemplate
,
207 if ( rv
!= SECSuccess
) {
211 /* initialize the oid tags */
212 policyInfos
= policies
->policyInfos
;
213 while (*policyInfos
!= NULL
) {
214 policyInfo
= *policyInfos
;
215 policyInfo
->oid
= SECOID_FindOIDTag(&policyInfo
->policyID
);
216 policyQualifiers
= policyInfo
->policyQualifiers
;
217 while ( policyQualifiers
!= NULL
&& *policyQualifiers
!= NULL
) {
218 policyQualifier
= *policyQualifiers
;
219 policyQualifier
->oid
=
220 SECOID_FindOIDTag(&policyQualifier
->qualifierID
);
229 if ( arena
!= NULL
) {
230 PORT_FreeArena(arena
, PR_FALSE
);
237 CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies
*policies
)
239 if ( policies
!= NULL
) {
240 PORT_FreeArena(policies
->arena
, PR_FALSE
);
245 CERTCertificatePolicyMappings
*
246 CERT_DecodePolicyMappingsExtension(SECItem
*extnValue
)
248 PRArenaPool
*arena
= NULL
;
250 CERTCertificatePolicyMappings
*mappings
;
251 SECItem newExtnValue
;
253 /* make a new arena */
254 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
259 /* allocate the policy mappings structure */
260 mappings
= (CERTCertificatePolicyMappings
*)
261 PORT_ArenaZAlloc(arena
, sizeof(CERTCertificatePolicyMappings
));
262 if ( mappings
== NULL
) {
265 mappings
->arena
= arena
;
267 /* copy the DER into the arena, since Quick DER returns data that points
268 into the DER input, which may get freed by the caller */
269 rv
= SECITEM_CopyItem(arena
, &newExtnValue
, extnValue
);
270 if ( rv
!= SECSuccess
) {
274 /* decode the policy mappings */
275 rv
= SEC_QuickDERDecodeItem
276 (arena
, mappings
, CERT_PolicyMappingsTemplate
, &newExtnValue
);
277 if ( rv
!= SECSuccess
) {
284 if ( arena
!= NULL
) {
285 PORT_FreeArena(arena
, PR_FALSE
);
292 CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings
*mappings
)
294 if ( mappings
!= NULL
) {
295 PORT_FreeArena(mappings
->arena
, PR_FALSE
);
301 CERT_DecodePolicyConstraintsExtension
302 (CERTCertificatePolicyConstraints
*decodedValue
,
303 SECItem
*encodedValue
)
305 CERTCertificatePolicyConstraints decodeContext
;
306 PRArenaPool
*arena
= NULL
;
307 SECStatus rv
= SECSuccess
;
309 /* initialize so we can tell when an optional component is omitted */
310 PORT_Memset(&decodeContext
, 0, sizeof(decodeContext
));
312 /* make a new arena */
313 arena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
319 /* decode the policy constraints */
320 rv
= SEC_QuickDERDecodeItem(arena
,
321 &decodeContext
, CERT_PolicyConstraintsTemplate
, encodedValue
);
323 if ( rv
!= SECSuccess
) {
327 if (decodeContext
.explicitPolicySkipCerts
.len
== 0) {
328 *(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
= -1;
330 *(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
=
331 DER_GetInteger(&decodeContext
.explicitPolicySkipCerts
);
334 if (decodeContext
.inhibitMappingSkipCerts
.len
== 0) {
335 *(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
= -1;
337 *(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
=
338 DER_GetInteger(&decodeContext
.inhibitMappingSkipCerts
);
341 if ((*(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
==
343 (*(PRInt32
*)decodedValue
->explicitPolicySkipCerts
.data
==
345 (*(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
==
347 (*(PRInt32
*)decodedValue
->inhibitMappingSkipCerts
.data
==
354 PORT_FreeArena(arena
, PR_FALSE
);
358 SECStatus CERT_DecodeInhibitAnyExtension
359 (CERTCertificateInhibitAny
*decodedValue
, SECItem
*encodedValue
)
361 CERTCertificateInhibitAny decodeContext
;
362 PRArenaPool
*arena
= NULL
;
363 SECStatus rv
= SECSuccess
;
365 /* make a new arena */
366 arena
= PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE
);
373 /* decode the policy mappings */
374 decodeContext
.inhibitAnySkipCerts
.type
= siUnsignedInteger
;
375 rv
= SEC_QuickDERDecodeItem(arena
,
376 &decodeContext
, CERT_InhibitAnyTemplate
, encodedValue
);
378 if ( rv
!= SECSuccess
) {
382 *(PRInt32
*)decodedValue
->inhibitAnySkipCerts
.data
=
383 DER_GetInteger(&decodeContext
.inhibitAnySkipCerts
);
387 PORT_FreeArena(arena
, PR_FALSE
);
392 CERT_DecodeUserNotice(SECItem
*noticeItem
)
394 PRArenaPool
*arena
= NULL
;
396 CERTUserNotice
*userNotice
;
397 SECItem newNoticeItem
;
399 /* make a new arena */
400 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
406 /* allocate the userNotice structure */
407 userNotice
= (CERTUserNotice
*)PORT_ArenaZAlloc(arena
,
408 sizeof(CERTUserNotice
));
410 if ( userNotice
== NULL
) {
414 userNotice
->arena
= arena
;
416 /* copy the DER into the arena, since Quick DER returns data that points
417 into the DER input, which may get freed by the caller */
418 rv
= SECITEM_CopyItem(arena
, &newNoticeItem
, noticeItem
);
419 if ( rv
!= SECSuccess
) {
423 /* decode the user notice */
424 rv
= SEC_QuickDERDecodeItem(arena
, userNotice
, CERT_UserNoticeTemplate
,
427 if ( rv
!= SECSuccess
) {
431 if (userNotice
->derNoticeReference
.data
!= NULL
) {
432 /* sigh, the asn1 parser stripped the sequence encoding, re add it
438 newBytes
= SEC_ASN1LengthLength(userNotice
->derNoticeReference
.len
)+1;
439 tmpbuf
.len
= newBytes
+ userNotice
->derNoticeReference
.len
;
440 tmpbuf
.data
= PORT_ArenaZAlloc(arena
, tmpbuf
.len
);
441 if (tmpbuf
.data
== NULL
) {
444 tmpbuf
.data
[0] = SEC_ASN1_SEQUENCE
| SEC_ASN1_CONSTRUCTED
;
445 SEC_ASN1EncodeLength(&tmpbuf
.data
[1],userNotice
->derNoticeReference
.len
);
446 PORT_Memcpy(&tmpbuf
.data
[newBytes
],userNotice
->derNoticeReference
.data
,
447 userNotice
->derNoticeReference
.len
);
449 /* OK, no decode it */
450 rv
= SEC_QuickDERDecodeItem(arena
, &userNotice
->noticeReference
,
451 CERT_NoticeReferenceTemplate
, &tmpbuf
);
453 PORT_Free(tmpbuf
.data
); tmpbuf
.data
= NULL
;
454 if ( rv
!= SECSuccess
) {
462 if ( arena
!= NULL
) {
463 PORT_FreeArena(arena
, PR_FALSE
);
470 CERT_DestroyUserNotice(CERTUserNotice
*userNotice
)
472 if ( userNotice
!= NULL
) {
473 PORT_FreeArena(userNotice
->arena
, PR_FALSE
);
478 static CERTPolicyStringCallback policyStringCB
= NULL
;
479 static void *policyStringCBArg
= NULL
;
482 CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb
, void *cbarg
)
485 policyStringCBArg
= cbarg
;
490 stringFromUserNotice(SECItem
*noticeItem
)
493 unsigned int len
, headerlen
;
495 CERTUserNotice
*userNotice
;
498 SECItem
*displayText
;
499 SECItem
**noticeNumbers
;
502 /* decode the user notice */
503 userNotice
= CERT_DecodeUserNotice(noticeItem
);
504 if ( userNotice
== NULL
) {
508 org
= &userNotice
->noticeReference
.organization
;
509 if ( (org
->len
!= 0 ) && ( policyStringCB
!= NULL
) ) {
510 /* has a noticeReference */
512 /* extract the org string */
514 stringbuf
= (char*)PORT_Alloc(len
+ 1);
515 if ( stringbuf
!= NULL
) {
516 PORT_Memcpy(stringbuf
, org
->data
, len
);
517 stringbuf
[len
] = '\0';
519 noticeNumbers
= userNotice
->noticeReference
.noticeNumbers
;
520 while ( *noticeNumbers
!= NULL
) {
521 /* XXX - only one byte integers right now*/
522 strnum
= (*noticeNumbers
)->data
[0];
523 policystr
= (* policyStringCB
)(stringbuf
,
526 if ( policystr
!= NULL
) {
527 if ( retstr
!= NULL
) {
528 retstr
= PR_sprintf_append(retstr
, "\n%s", policystr
);
530 retstr
= PR_sprintf_append(retstr
, "%s", policystr
);
533 PORT_Free(policystr
);
539 PORT_Free(stringbuf
);
543 if ( retstr
== NULL
) {
544 if ( userNotice
->displayText
.len
!= 0 ) {
545 displayText
= &userNotice
->displayText
;
547 if ( displayText
->len
> 2 ) {
548 if ( displayText
->data
[0] == SEC_ASN1_VISIBLE_STRING
) {
550 if ( displayText
->data
[1] & 0x80 ) {
551 /* multibyte length */
552 headerlen
+= ( displayText
->data
[1] & 0x7f );
555 len
= displayText
->len
- headerlen
;
556 retstr
= (char*)PORT_Alloc(len
+ 1);
557 if ( retstr
!= NULL
) {
558 PORT_Memcpy(retstr
, &displayText
->data
[headerlen
],len
);
566 CERT_DestroyUserNotice(userNotice
);
572 CERT_GetCertCommentString(CERTCertificate
*cert
)
574 char *retstring
= NULL
;
577 CERTCertificatePolicies
*policies
= NULL
;
578 CERTPolicyInfo
**policyInfos
;
579 CERTPolicyQualifier
**policyQualifiers
, *qualifier
;
581 policyItem
.data
= NULL
;
583 rv
= CERT_FindCertExtension(cert
, SEC_OID_X509_CERTIFICATE_POLICIES
,
585 if ( rv
!= SECSuccess
) {
589 policies
= CERT_DecodeCertificatePoliciesExtension(&policyItem
);
590 if ( policies
== NULL
) {
594 policyInfos
= policies
->policyInfos
;
595 /* search through policyInfos looking for the verisign policy */
596 while (*policyInfos
!= NULL
) {
597 if ( (*policyInfos
)->oid
== SEC_OID_VERISIGN_USER_NOTICES
) {
598 policyQualifiers
= (*policyInfos
)->policyQualifiers
;
599 /* search through the policy qualifiers looking for user notice */
600 while ( policyQualifiers
!= NULL
&& *policyQualifiers
!= NULL
) {
601 qualifier
= *policyQualifiers
;
602 if ( qualifier
->oid
== SEC_OID_PKIX_USER_NOTICE_QUALIFIER
) {
604 stringFromUserNotice(&qualifier
->qualifierValue
);
616 if ( policyItem
.data
!= NULL
) {
617 PORT_Free(policyItem
.data
);
620 if ( policies
!= NULL
) {
621 CERT_DestroyCertificatePoliciesExtension(policies
);
624 if ( retstring
== NULL
) {
625 retstring
= CERT_FindNSStringExtension(cert
,
626 SEC_OID_NS_CERT_EXT_COMMENT
);
629 if ( retstring
!= NULL
) {
630 breakLines(retstring
);
637 const SEC_ASN1Template CERT_OidSeqTemplate
[] = {
638 { SEC_ASN1_SEQUENCE_OF
,
639 offsetof(CERTOidSequence
, oids
),
640 SEC_ObjectIDTemplate
}
644 CERT_DecodeOidSequence(SECItem
*seqItem
)
646 PRArenaPool
*arena
= NULL
;
648 CERTOidSequence
*oidSeq
;
651 /* make a new arena */
652 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
658 /* allocate the userNotice structure */
659 oidSeq
= (CERTOidSequence
*)PORT_ArenaZAlloc(arena
,
660 sizeof(CERTOidSequence
));
662 if ( oidSeq
== NULL
) {
666 oidSeq
->arena
= arena
;
668 /* copy the DER into the arena, since Quick DER returns data that points
669 into the DER input, which may get freed by the caller */
670 rv
= SECITEM_CopyItem(arena
, &newSeqItem
, seqItem
);
671 if ( rv
!= SECSuccess
) {
675 /* decode the user notice */
676 rv
= SEC_QuickDERDecodeItem(arena
, oidSeq
, CERT_OidSeqTemplate
, &newSeqItem
);
678 if ( rv
!= SECSuccess
) {
690 CERT_DestroyOidSequence(CERTOidSequence
*oidSeq
)
692 if ( oidSeq
!= NULL
) {
693 PORT_FreeArena(oidSeq
->arena
, PR_FALSE
);
699 CERT_GovtApprovedBitSet(CERTCertificate
*cert
)
703 CERTOidSequence
*oidSeq
= NULL
;
710 rv
= CERT_FindCertExtension(cert
, SEC_OID_X509_EXT_KEY_USAGE
, &extItem
);
711 if ( rv
!= SECSuccess
) {
715 oidSeq
= CERT_DecodeOidSequence(&extItem
);
716 if ( oidSeq
== NULL
) {
721 while ( oids
!= NULL
&& *oids
!= NULL
) {
724 oidTag
= SECOID_FindOIDTag(oid
);
726 if ( oidTag
== SEC_OID_NS_KEY_USAGE_GOVT_APPROVED
) {
739 if ( oidSeq
!= NULL
) {
740 CERT_DestroyOidSequence(oidSeq
);
742 if (extItem
.data
!= NULL
) {
743 PORT_Free(extItem
.data
);