Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / certdb / polcyxtn.c
blob601e43241a8594ba55cf3e97e2d0dd9170a28404
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
12 * License.
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.
21 * Contributor(s):
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 $
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"
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 }
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 }
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 }
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 }
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[] = {
103 { SEC_ASN1_SEQUENCE,
104 0, NULL, sizeof(CERTPolicyMap) },
105 { SEC_ASN1_OBJECT_ID,
106 offsetof(CERTPolicyMap, issuerDomainPolicy) },
107 { SEC_ASN1_OBJECT_ID,
108 offsetof(CERTPolicyMap, subjectDomainPolicy) },
109 { 0 }
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 },
126 { 0 }
129 const SEC_ASN1Template CERT_InhibitAnyTemplate[] = {
130 { SEC_ASN1_INTEGER,
131 offsetof(CERTCertificateInhibitAny, inhibitAnySkipCerts),
132 NULL, sizeof(CERTCertificateInhibitAny) }
135 static void
136 breakLines(char *string)
138 char *tmpstr;
139 char *lastspace = NULL;
140 int curlen = 0;
141 int c;
143 tmpstr = string;
145 while ( ( c = *tmpstr ) != '\0' ) {
146 switch ( c ) {
147 case ' ':
148 lastspace = tmpstr;
149 break;
150 case '\n':
151 lastspace = NULL;
152 curlen = 0;
153 break;
156 if ( ( curlen >= 55 ) && ( lastspace != NULL ) ) {
157 *lastspace = '\n';
158 curlen = ( tmpstr - lastspace );
159 lastspace = NULL;
162 curlen++;
163 tmpstr++;
166 return;
169 CERTCertificatePolicies *
170 CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue)
172 PRArenaPool *arena = NULL;
173 SECStatus rv;
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);
182 if ( !arena ) {
183 goto loser;
186 /* allocate the certificate policies structure */
187 policies = (CERTCertificatePolicies *)
188 PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicies));
190 if ( policies == NULL ) {
191 goto loser;
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 ) {
200 goto loser;
203 /* decode the policy info */
204 rv = SEC_QuickDERDecodeItem(arena, policies, CERT_CertificatePoliciesTemplate,
205 &newExtnValue);
207 if ( rv != SECSuccess ) {
208 goto loser;
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);
221 policyQualifiers++;
223 policyInfos++;
226 return(policies);
228 loser:
229 if ( arena != NULL ) {
230 PORT_FreeArena(arena, PR_FALSE);
233 return(NULL);
236 void
237 CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
239 if ( policies != NULL ) {
240 PORT_FreeArena(policies->arena, PR_FALSE);
242 return;
245 CERTCertificatePolicyMappings *
246 CERT_DecodePolicyMappingsExtension(SECItem *extnValue)
248 PRArenaPool *arena = NULL;
249 SECStatus rv;
250 CERTCertificatePolicyMappings *mappings;
251 SECItem newExtnValue;
253 /* make a new arena */
254 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
255 if ( !arena ) {
256 goto loser;
259 /* allocate the policy mappings structure */
260 mappings = (CERTCertificatePolicyMappings *)
261 PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicyMappings));
262 if ( mappings == NULL ) {
263 goto loser;
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 ) {
271 goto loser;
274 /* decode the policy mappings */
275 rv = SEC_QuickDERDecodeItem
276 (arena, mappings, CERT_PolicyMappingsTemplate, &newExtnValue);
277 if ( rv != SECSuccess ) {
278 goto loser;
281 return(mappings);
283 loser:
284 if ( arena != NULL ) {
285 PORT_FreeArena(arena, PR_FALSE);
288 return(NULL);
291 SECStatus
292 CERT_DestroyPolicyMappingsExtension(CERTCertificatePolicyMappings *mappings)
294 if ( mappings != NULL ) {
295 PORT_FreeArena(mappings->arena, PR_FALSE);
297 return SECSuccess;
300 SECStatus
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);
314 if (!arena) {
315 return SECFailure;
318 do {
319 /* decode the policy constraints */
320 rv = SEC_QuickDERDecodeItem(arena,
321 &decodeContext, CERT_PolicyConstraintsTemplate, encodedValue);
323 if ( rv != SECSuccess ) {
324 break;
327 if (decodeContext.explicitPolicySkipCerts.len == 0) {
328 *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data = -1;
329 } else {
330 *(PRInt32 *)decodedValue->explicitPolicySkipCerts.data =
331 DER_GetInteger(&decodeContext.explicitPolicySkipCerts);
334 if (decodeContext.inhibitMappingSkipCerts.len == 0) {
335 *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data = -1;
336 } else {
337 *(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data =
338 DER_GetInteger(&decodeContext.inhibitMappingSkipCerts);
341 if ((*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
342 PR_INT32_MIN) ||
343 (*(PRInt32 *)decodedValue->explicitPolicySkipCerts.data ==
344 PR_INT32_MAX) ||
345 (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
346 PR_INT32_MIN) ||
347 (*(PRInt32 *)decodedValue->inhibitMappingSkipCerts.data ==
348 PR_INT32_MAX)) {
349 rv = SECFailure;
352 } while (0);
354 PORT_FreeArena(arena, PR_FALSE);
355 return(rv);
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);
367 if ( !arena ) {
368 return SECFailure;
371 do {
373 /* decode the policy mappings */
374 decodeContext.inhibitAnySkipCerts.type = siUnsignedInteger;
375 rv = SEC_QuickDERDecodeItem(arena,
376 &decodeContext, CERT_InhibitAnyTemplate, encodedValue);
378 if ( rv != SECSuccess ) {
379 break;
382 *(PRInt32 *)decodedValue->inhibitAnySkipCerts.data =
383 DER_GetInteger(&decodeContext.inhibitAnySkipCerts);
385 } while (0);
387 PORT_FreeArena(arena, PR_FALSE);
388 return(rv);
391 CERTUserNotice *
392 CERT_DecodeUserNotice(SECItem *noticeItem)
394 PRArenaPool *arena = NULL;
395 SECStatus rv;
396 CERTUserNotice *userNotice;
397 SECItem newNoticeItem;
399 /* make a new arena */
400 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
402 if ( !arena ) {
403 goto loser;
406 /* allocate the userNotice structure */
407 userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena,
408 sizeof(CERTUserNotice));
410 if ( userNotice == NULL ) {
411 goto loser;
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 ) {
420 goto loser;
423 /* decode the user notice */
424 rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate,
425 &newNoticeItem);
427 if ( rv != SECSuccess ) {
428 goto loser;
431 if (userNotice->derNoticeReference.data != NULL) {
432 /* sigh, the asn1 parser stripped the sequence encoding, re add it
433 * before we decode.
435 SECItem tmpbuf;
436 int newBytes;
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) {
442 goto loser;
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 ) {
455 goto loser;
459 return(userNotice);
461 loser:
462 if ( arena != NULL ) {
463 PORT_FreeArena(arena, PR_FALSE);
466 return(NULL);
469 void
470 CERT_DestroyUserNotice(CERTUserNotice *userNotice)
472 if ( userNotice != NULL ) {
473 PORT_FreeArena(userNotice->arena, PR_FALSE);
475 return;
478 static CERTPolicyStringCallback policyStringCB = NULL;
479 static void *policyStringCBArg = NULL;
481 void
482 CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
484 policyStringCB = cb;
485 policyStringCBArg = cbarg;
486 return;
489 char *
490 stringFromUserNotice(SECItem *noticeItem)
492 SECItem *org;
493 unsigned int len, headerlen;
494 char *stringbuf;
495 CERTUserNotice *userNotice;
496 char *policystr;
497 char *retstr = NULL;
498 SECItem *displayText;
499 SECItem **noticeNumbers;
500 unsigned int strnum;
502 /* decode the user notice */
503 userNotice = CERT_DecodeUserNotice(noticeItem);
504 if ( userNotice == NULL ) {
505 return(NULL);
508 org = &userNotice->noticeReference.organization;
509 if ( (org->len != 0 ) && ( policyStringCB != NULL ) ) {
510 /* has a noticeReference */
512 /* extract the org string */
513 len = org->len;
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,
524 strnum,
525 policyStringCBArg);
526 if ( policystr != NULL ) {
527 if ( retstr != NULL ) {
528 retstr = PR_sprintf_append(retstr, "\n%s", policystr);
529 } else {
530 retstr = PR_sprintf_append(retstr, "%s", policystr);
533 PORT_Free(policystr);
536 noticeNumbers++;
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 ) {
549 headerlen = 2;
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);
559 retstr[len] = '\0';
566 CERT_DestroyUserNotice(userNotice);
568 return(retstr);
571 char *
572 CERT_GetCertCommentString(CERTCertificate *cert)
574 char *retstring = NULL;
575 SECStatus rv;
576 SECItem policyItem;
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,
584 &policyItem);
585 if ( rv != SECSuccess ) {
586 goto nopolicy;
589 policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
590 if ( policies == NULL ) {
591 goto nopolicy;
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 ) {
603 retstring =
604 stringFromUserNotice(&qualifier->qualifierValue);
605 break;
608 policyQualifiers++;
610 break;
612 policyInfos++;
615 nopolicy:
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);
633 return(retstring);
637 const SEC_ASN1Template CERT_OidSeqTemplate[] = {
638 { SEC_ASN1_SEQUENCE_OF,
639 offsetof(CERTOidSequence, oids),
640 SEC_ObjectIDTemplate }
643 CERTOidSequence *
644 CERT_DecodeOidSequence(SECItem *seqItem)
646 PRArenaPool *arena = NULL;
647 SECStatus rv;
648 CERTOidSequence *oidSeq;
649 SECItem newSeqItem;
651 /* make a new arena */
652 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
654 if ( !arena ) {
655 goto loser;
658 /* allocate the userNotice structure */
659 oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena,
660 sizeof(CERTOidSequence));
662 if ( oidSeq == NULL ) {
663 goto loser;
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 ) {
672 goto loser;
675 /* decode the user notice */
676 rv = SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
678 if ( rv != SECSuccess ) {
679 goto loser;
682 return(oidSeq);
684 loser:
685 return(NULL);
689 void
690 CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
692 if ( oidSeq != NULL ) {
693 PORT_FreeArena(oidSeq->arena, PR_FALSE);
695 return;
698 PRBool
699 CERT_GovtApprovedBitSet(CERTCertificate *cert)
701 SECStatus rv;
702 SECItem extItem;
703 CERTOidSequence *oidSeq = NULL;
704 PRBool ret;
705 SECItem **oids;
706 SECItem *oid;
707 SECOidTag oidTag;
709 extItem.data = NULL;
710 rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
711 if ( rv != SECSuccess ) {
712 goto loser;
715 oidSeq = CERT_DecodeOidSequence(&extItem);
716 if ( oidSeq == NULL ) {
717 goto loser;
720 oids = oidSeq->oids;
721 while ( oids != NULL && *oids != NULL ) {
722 oid = *oids;
724 oidTag = SECOID_FindOIDTag(oid);
726 if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) {
727 goto success;
730 oids++;
733 loser:
734 ret = PR_FALSE;
735 goto done;
736 success:
737 ret = PR_TRUE;
738 done:
739 if ( oidSeq != NULL ) {
740 CERT_DestroyOidSequence(oidSeq);
742 if (extItem.data != NULL) {
743 PORT_Free(extItem.data);
745 return(ret);