summaryrefslogtreecommitdiff
path: root/security/nss/lib/certdb/polcyxtn.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/certdb/polcyxtn.c')
-rw-r--r--security/nss/lib/certdb/polcyxtn.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/security/nss/lib/certdb/polcyxtn.c b/security/nss/lib/certdb/polcyxtn.c
new file mode 100644
index 000000000..7f3dd3a78
--- /dev/null
+++ b/security/nss/lib/certdb/polcyxtn.c
@@ -0,0 +1,541 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1994-2000 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/*
+ * Support for various policy related extensions
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "secport.h"
+#include "secder.h"
+#include "cert.h"
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+#include "nspr.h"
+
+const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTNoticeReference) },
+/* NOTE: this should be a choice */
+ { SEC_ASN1_IA5_STRING,
+ offsetof(CERTNoticeReference, organization) },
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTNoticeReference, noticeNumbers),
+ SEC_IntegerTemplate },
+ { 0 }
+};
+
+/* this template can not be encoded because of the option inline */
+const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTUserNotice) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED,
+ offsetof(CERTUserNotice, derNoticeReference) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+ offsetof(CERTUserNotice, displayText) },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTPolicyQualifier) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTPolicyQualifier, qualifierID) },
+ { SEC_ASN1_ANY,
+ offsetof(CERTPolicyQualifier, qualifierValue) },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_PolicyInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CERTPolicyInfo) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CERTPolicyInfo, policyID) },
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTPolicyInfo, policyQualifiers),
+ CERT_PolicyQualifierTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTCertificatePolicies, policyInfos),
+ CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies) }
+};
+
+static void
+breakLines(char *string)
+{
+ char *tmpstr;
+ char *lastspace = NULL;
+ int curlen = 0;
+ int c;
+
+ tmpstr = string;
+
+ while ( ( c = *tmpstr ) != '\0' ) {
+ switch ( c ) {
+ case ' ':
+ lastspace = tmpstr;
+ break;
+ case '\n':
+ lastspace = NULL;
+ curlen = 0;
+ break;
+ }
+
+ if ( ( curlen >= 55 ) && ( lastspace != NULL ) ) {
+ *lastspace = '\n';
+ curlen = ( tmpstr - lastspace );
+ lastspace = NULL;
+ }
+
+ curlen++;
+ tmpstr++;
+ }
+
+ return;
+}
+
+CERTCertificatePolicies *
+CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTCertificatePolicies *policies;
+ CERTPolicyInfo **policyInfos, *policyInfo;
+ CERTPolicyQualifier **policyQualifiers, *policyQualifier;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the certifiate policies structure */
+ policies = (CERTCertificatePolicies *)
+ PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicies));
+
+ if ( policies == NULL ) {
+ goto loser;
+ }
+
+ policies->arena = arena;
+
+ /* decode the policy info */
+ rv = SEC_ASN1DecodeItem(arena, policies, CERT_CertificatePoliciesTemplate,
+ extnValue);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ /* initialize the oid tags */
+ policyInfos = policies->policyInfos;
+ while (*policyInfos != NULL ) {
+ policyInfo = *policyInfos;
+ policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
+ policyQualifiers = policyInfo->policyQualifiers;
+ while ( *policyQualifiers != NULL ) {
+ policyQualifier = *policyQualifiers;
+ policyQualifier->oid =
+ SECOID_FindOIDTag(&policyQualifier->qualifierID);
+ policyQualifiers++;
+ }
+ policyInfos++;
+ }
+
+ return(policies);
+
+loser:
+ if ( arena != NULL ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(NULL);
+}
+
+void
+CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
+{
+ if ( policies != NULL ) {
+ PORT_FreeArena(policies->arena, PR_FALSE);
+ }
+ return;
+}
+
+
+CERTUserNotice *
+CERT_DecodeUserNotice(SECItem *noticeItem)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTUserNotice *userNotice;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the userNotice structure */
+ userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena,
+ sizeof(CERTUserNotice));
+
+ if ( userNotice == NULL ) {
+ goto loser;
+ }
+
+ userNotice->arena = arena;
+
+ /* decode the user notice */
+ rv = SEC_ASN1DecodeItem(arena, userNotice, CERT_UserNoticeTemplate,
+ noticeItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ if (userNotice->derNoticeReference.data != NULL) {
+ /* sigh, the asn1 parser stripped the sequence encoding, re add it
+ * before we decode.
+ */
+ SECItem tmpbuf;
+ int newBytes;
+
+ newBytes = SEC_ASN1LengthLength(userNotice->derNoticeReference.len)+1;
+ tmpbuf.len = newBytes + userNotice->derNoticeReference.len;
+ tmpbuf.data = PORT_ZAlloc(tmpbuf.len);
+ if (tmpbuf.data == NULL) {
+ goto loser;
+ }
+ tmpbuf.data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
+ SEC_ASN1EncodeLength(&tmpbuf.data[1],userNotice->derNoticeReference.len);
+ PORT_Memcpy(&tmpbuf.data[newBytes],userNotice->derNoticeReference.data,
+ userNotice->derNoticeReference.len);
+
+ /* OK, no decode it */
+ rv = SEC_ASN1DecodeItem(arena, &userNotice->noticeReference,
+ CERT_NoticeReferenceTemplate, &tmpbuf);
+
+ PORT_Free(tmpbuf.data); tmpbuf.data = NULL;
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+ }
+
+ return(userNotice);
+
+loser:
+ if ( arena != NULL ) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ return(NULL);
+}
+
+void
+CERT_DestroyUserNotice(CERTUserNotice *userNotice)
+{
+ if ( userNotice != NULL ) {
+ PORT_FreeArena(userNotice->arena, PR_FALSE);
+ }
+ return;
+}
+
+static CERTPolicyStringCallback policyStringCB = NULL;
+static void *policyStringCBArg = NULL;
+
+void
+CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
+{
+ policyStringCB = cb;
+ policyStringCBArg = cbarg;
+ return;
+}
+
+char *
+stringFromUserNotice(SECItem *noticeItem)
+{
+ SECItem *org;
+ unsigned int len, headerlen;
+ char *stringbuf;
+ CERTUserNotice *userNotice;
+ char *policystr;
+ char *retstr = NULL;
+ SECItem *displayText;
+ SECItem **noticeNumbers;
+ unsigned int strnum;
+
+ /* decode the user notice */
+ userNotice = CERT_DecodeUserNotice(noticeItem);
+ if ( userNotice == NULL ) {
+ return(NULL);
+ }
+
+ org = &userNotice->noticeReference.organization;
+ if ( (org->len != 0 ) && ( policyStringCB != NULL ) ) {
+ /* has a noticeReference */
+
+ /* extract the org string */
+ len = org->len;
+ stringbuf = (char*)PORT_Alloc(len + 1);
+ if ( stringbuf != NULL ) {
+ PORT_Memcpy(stringbuf, org->data, len);
+ stringbuf[len] = '\0';
+
+ noticeNumbers = userNotice->noticeReference.noticeNumbers;
+ while ( *noticeNumbers != NULL ) {
+ /* XXX - only one byte integers right now*/
+ strnum = (*noticeNumbers)->data[0];
+ policystr = (* policyStringCB)(stringbuf,
+ strnum,
+ policyStringCBArg);
+ if ( policystr != NULL ) {
+ if ( retstr != NULL ) {
+ retstr = PR_sprintf_append(retstr, "\n%s", policystr);
+ } else {
+ retstr = PR_sprintf_append(retstr, "%s", policystr);
+ }
+
+ PORT_Free(policystr);
+ }
+
+ noticeNumbers++;
+ }
+
+ PORT_Free(stringbuf);
+ }
+ }
+
+ if ( retstr == NULL ) {
+ if ( userNotice->displayText.len != 0 ) {
+ displayText = &userNotice->displayText;
+
+ if ( displayText->len > 2 ) {
+ if ( displayText->data[0] == SEC_ASN1_VISIBLE_STRING ) {
+ headerlen = 2;
+ if ( displayText->data[1] & 0x80 ) {
+ /* multibyte length */
+ headerlen += ( displayText->data[1] & 0x7f );
+ }
+
+ len = displayText->len - headerlen;
+ retstr = (char*)PORT_Alloc(len + 1);
+ if ( retstr != NULL ) {
+ PORT_Memcpy(retstr, &displayText->data[headerlen],len);
+ retstr[len] = '\0';
+ }
+ }
+ }
+ }
+ }
+
+ CERT_DestroyUserNotice(userNotice);
+
+ return(retstr);
+}
+
+char *
+CERT_GetCertCommentString(CERTCertificate *cert)
+{
+ char *retstring = NULL;
+ SECStatus rv;
+ SECItem policyItem;
+ CERTCertificatePolicies *policies = NULL;
+ CERTPolicyInfo **policyInfos;
+ CERTPolicyQualifier **policyQualifiers, *qualifier;
+
+ policyItem.data = NULL;
+
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
+ &policyItem);
+ if ( rv != SECSuccess ) {
+ goto nopolicy;
+ }
+
+ policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
+ if ( policies == NULL ) {
+ goto nopolicy;
+ }
+
+ policyInfos = policies->policyInfos;
+ /* search through policyInfos looking for the verisign policy */
+ while (*policyInfos != NULL ) {
+ if ( (*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES ) {
+ policyQualifiers = (*policyInfos)->policyQualifiers;
+ /* search through the policy qualifiers looking for user notice */
+ while ( *policyQualifiers != NULL ) {
+ qualifier = *policyQualifiers;
+ if ( qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER ) {
+ retstring =
+ stringFromUserNotice(&qualifier->qualifierValue);
+ break;
+ }
+
+ policyQualifiers++;
+ }
+ break;
+ }
+ policyInfos++;
+ }
+
+nopolicy:
+ if ( policyItem.data != NULL ) {
+ PORT_Free(policyItem.data);
+ }
+
+ if ( policies != NULL ) {
+ CERT_DestroyCertificatePoliciesExtension(policies);
+ }
+
+ if ( retstring == NULL ) {
+ retstring = CERT_FindNSStringExtension(cert,
+ SEC_OID_NS_CERT_EXT_COMMENT);
+ }
+
+ if ( retstring != NULL ) {
+ breakLines(retstring);
+ }
+
+ return(retstring);
+}
+
+
+const SEC_ASN1Template CERT_OidSeqTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF,
+ offsetof(CERTOidSequence, oids),
+ SEC_ObjectIDTemplate }
+};
+
+CERTOidSequence *
+CERT_DecodeOidSequence(SECItem *seqItem)
+{
+ PRArenaPool *arena = NULL;
+ SECStatus rv;
+ CERTOidSequence *oidSeq;
+
+ /* make a new arena */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+
+ if ( !arena ) {
+ goto loser;
+ }
+
+ /* allocate the userNotice structure */
+ oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena,
+ sizeof(CERTOidSequence));
+
+ if ( oidSeq == NULL ) {
+ goto loser;
+ }
+
+ oidSeq->arena = arena;
+
+ /* decode the user notice */
+ rv = SEC_ASN1DecodeItem(arena, oidSeq, CERT_OidSeqTemplate, seqItem);
+
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ return(oidSeq);
+
+loser:
+ return(NULL);
+}
+
+
+void
+CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
+{
+ if ( oidSeq != NULL ) {
+ PORT_FreeArena(oidSeq->arena, PR_FALSE);
+ }
+ return;
+}
+
+PRBool
+CERT_GovtApprovedBitSet(CERTCertificate *cert)
+{
+ SECStatus rv;
+ SECItem extItem;
+ CERTOidSequence *oidSeq = NULL;
+ PRBool ret;
+ SECItem **oids;
+ SECItem *oid;
+ SECOidTag oidTag;
+
+ extItem.data = NULL;
+ rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
+ if ( rv != SECSuccess ) {
+ goto loser;
+ }
+
+ oidSeq = CERT_DecodeOidSequence(&extItem);
+ if ( oidSeq == NULL ) {
+ goto loser;
+ }
+
+ oids = oidSeq->oids;
+ while ( oids != NULL && *oids != NULL ) {
+ oid = *oids;
+
+ oidTag = SECOID_FindOIDTag(oid);
+
+ if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) {
+ goto success;
+ }
+
+ oids++;
+ }
+
+loser:
+ ret = PR_FALSE;
+ goto done;
+success:
+ ret = PR_TRUE;
+done:
+ if ( oidSeq != NULL ) {
+ CERT_DestroyOidSequence(oidSeq);
+ }
+ if (extItem.data != NULL) {
+ PORT_Free(extItem.data);
+ }
+ return(ret);
+}