Back to index

lightning-sunbird  0.9+nobinonly
polcyxtn.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * Support for various policy related extensions
00039  *
00040  * $Id: polcyxtn.c,v 1.6 2004/04/25 15:03:03 gerv%gerv.net Exp $
00041  */
00042 
00043 #include "seccomon.h"
00044 #include "secport.h"
00045 #include "secder.h"
00046 #include "cert.h"
00047 #include "secoid.h"
00048 #include "secasn1.h"
00049 #include "secerr.h"
00050 #include "nspr.h"
00051 
00052 const SEC_ASN1Template CERT_NoticeReferenceTemplate[] = {
00053     { SEC_ASN1_SEQUENCE,
00054          0, NULL, sizeof(CERTNoticeReference) },
00055 /* NOTE: this should be a choice */
00056     { SEC_ASN1_IA5_STRING,
00057          offsetof(CERTNoticeReference, organization) },
00058     { SEC_ASN1_SEQUENCE_OF,
00059          offsetof(CERTNoticeReference, noticeNumbers),
00060          SEC_IntegerTemplate }, 
00061     { 0 }
00062 };
00063 
00064 /* this template can not be encoded because of the option inline */
00065 const SEC_ASN1Template CERT_UserNoticeTemplate[] = {
00066     { SEC_ASN1_SEQUENCE,
00067          0, NULL, sizeof(CERTUserNotice) },
00068     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED,
00069          offsetof(CERTUserNotice, derNoticeReference) }, 
00070     { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
00071          offsetof(CERTUserNotice, displayText) }, 
00072     { 0 }
00073 };
00074 
00075 const SEC_ASN1Template CERT_PolicyQualifierTemplate[] = {
00076     { SEC_ASN1_SEQUENCE,
00077          0, NULL, sizeof(CERTPolicyQualifier) },
00078     { SEC_ASN1_OBJECT_ID,
00079          offsetof(CERTPolicyQualifier, qualifierID) },
00080     { SEC_ASN1_ANY,
00081          offsetof(CERTPolicyQualifier, qualifierValue) },
00082     { 0 }
00083 };
00084 
00085 const SEC_ASN1Template CERT_PolicyInfoTemplate[] = {
00086     { SEC_ASN1_SEQUENCE,
00087          0, NULL, sizeof(CERTPolicyInfo) },
00088     { SEC_ASN1_OBJECT_ID,
00089          offsetof(CERTPolicyInfo, policyID) },
00090     { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_OPTIONAL,
00091          offsetof(CERTPolicyInfo, policyQualifiers),
00092          CERT_PolicyQualifierTemplate },
00093     { 0 }
00094 };
00095 
00096 const SEC_ASN1Template CERT_CertificatePoliciesTemplate[] = {
00097     { SEC_ASN1_SEQUENCE_OF,
00098          offsetof(CERTCertificatePolicies, policyInfos),
00099          CERT_PolicyInfoTemplate, sizeof(CERTCertificatePolicies)  }
00100 };
00101 
00102 static void
00103 breakLines(char *string)
00104 {
00105     char *tmpstr;
00106     char *lastspace = NULL;
00107     int curlen = 0;
00108     int c;
00109     
00110     tmpstr = string;
00111 
00112     while ( ( c = *tmpstr ) != '\0' ) {
00113        switch ( c ) {
00114          case ' ':
00115            lastspace = tmpstr;
00116            break;
00117          case '\n':
00118            lastspace = NULL;
00119            curlen = 0;
00120            break;
00121        }
00122        
00123        if ( ( curlen >= 55 ) && ( lastspace != NULL ) ) {
00124            *lastspace = '\n';
00125            curlen = ( tmpstr - lastspace );
00126            lastspace = NULL;
00127        }
00128        
00129        curlen++;
00130        tmpstr++;
00131     }
00132     
00133     return;
00134 }
00135 
00136 CERTCertificatePolicies *
00137 CERT_DecodeCertificatePoliciesExtension(SECItem *extnValue)
00138 {
00139     PRArenaPool *arena = NULL;
00140     SECStatus rv;
00141     CERTCertificatePolicies *policies;
00142     CERTPolicyInfo **policyInfos, *policyInfo;
00143     CERTPolicyQualifier **policyQualifiers, *policyQualifier;
00144     SECItem newExtnValue;
00145     
00146     /* make a new arena */
00147     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00148     
00149     if ( !arena ) {
00150        goto loser;
00151     }
00152 
00153     /* allocate the certifiate policies structure */
00154     policies = (CERTCertificatePolicies *)
00155        PORT_ArenaZAlloc(arena, sizeof(CERTCertificatePolicies));
00156     
00157     if ( policies == NULL ) {
00158        goto loser;
00159     }
00160     
00161     policies->arena = arena;
00162 
00163     /* copy the DER into the arena, since Quick DER returns data that points
00164        into the DER input, which may get freed by the caller */
00165     rv = SECITEM_CopyItem(arena, &newExtnValue, extnValue);
00166     if ( rv != SECSuccess ) {
00167        goto loser;
00168     }
00169 
00170     /* decode the policy info */
00171     rv = SEC_QuickDERDecodeItem(arena, policies, CERT_CertificatePoliciesTemplate,
00172                          &newExtnValue);
00173 
00174     if ( rv != SECSuccess ) {
00175        goto loser;
00176     }
00177 
00178     /* initialize the oid tags */
00179     policyInfos = policies->policyInfos;
00180     while (*policyInfos != NULL ) {
00181        policyInfo = *policyInfos;
00182        policyInfo->oid = SECOID_FindOIDTag(&policyInfo->policyID);
00183        policyQualifiers = policyInfo->policyQualifiers;
00184        while ( policyQualifiers != NULL && *policyQualifiers != NULL ) {
00185            policyQualifier = *policyQualifiers;
00186            policyQualifier->oid =
00187               SECOID_FindOIDTag(&policyQualifier->qualifierID);
00188            policyQualifiers++;
00189        }
00190        policyInfos++;
00191     }
00192 
00193     return(policies);
00194     
00195 loser:
00196     if ( arena != NULL ) {
00197        PORT_FreeArena(arena, PR_FALSE);
00198     }
00199     
00200     return(NULL);
00201 }
00202 
00203 void
00204 CERT_DestroyCertificatePoliciesExtension(CERTCertificatePolicies *policies)
00205 {
00206     if ( policies != NULL ) {
00207        PORT_FreeArena(policies->arena, PR_FALSE);
00208     }
00209     return;
00210 }
00211 
00212 
00213 CERTUserNotice *
00214 CERT_DecodeUserNotice(SECItem *noticeItem)
00215 {
00216     PRArenaPool *arena = NULL;
00217     SECStatus rv;
00218     CERTUserNotice *userNotice;
00219     SECItem newNoticeItem;
00220     
00221     /* make a new arena */
00222     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00223     
00224     if ( !arena ) {
00225        goto loser;
00226     }
00227 
00228     /* allocate the userNotice structure */
00229     userNotice = (CERTUserNotice *)PORT_ArenaZAlloc(arena,
00230                                               sizeof(CERTUserNotice));
00231     
00232     if ( userNotice == NULL ) {
00233        goto loser;
00234     }
00235     
00236     userNotice->arena = arena;
00237 
00238     /* copy the DER into the arena, since Quick DER returns data that points
00239        into the DER input, which may get freed by the caller */
00240     rv = SECITEM_CopyItem(arena, &newNoticeItem, noticeItem);
00241     if ( rv != SECSuccess ) {
00242        goto loser;
00243     }
00244 
00245     /* decode the user notice */
00246     rv = SEC_QuickDERDecodeItem(arena, userNotice, CERT_UserNoticeTemplate, 
00247                          &newNoticeItem);
00248 
00249     if ( rv != SECSuccess ) {
00250        goto loser;
00251     }
00252 
00253     if (userNotice->derNoticeReference.data != NULL) {
00254        /* sigh, the asn1 parser stripped the sequence encoding, re add it
00255         * before we decode.
00256         */
00257        SECItem tmpbuf;
00258        int    newBytes;
00259 
00260        newBytes = SEC_ASN1LengthLength(userNotice->derNoticeReference.len)+1;
00261        tmpbuf.len = newBytes + userNotice->derNoticeReference.len;
00262        tmpbuf.data = PORT_ArenaZAlloc(arena, tmpbuf.len);
00263        if (tmpbuf.data == NULL) {
00264            goto loser;
00265        }
00266        tmpbuf.data[0] = SEC_ASN1_SEQUENCE | SEC_ASN1_CONSTRUCTED;
00267        SEC_ASN1EncodeLength(&tmpbuf.data[1],userNotice->derNoticeReference.len);
00268        PORT_Memcpy(&tmpbuf.data[newBytes],userNotice->derNoticeReference.data,
00269                             userNotice->derNoticeReference.len);
00270 
00271        /* OK, no decode it */
00272        rv = SEC_QuickDERDecodeItem(arena, &userNotice->noticeReference, 
00273            CERT_NoticeReferenceTemplate, &tmpbuf);
00274 
00275        PORT_Free(tmpbuf.data); tmpbuf.data = NULL;
00276        if ( rv != SECSuccess ) {
00277            goto loser;
00278        }
00279     }
00280 
00281     return(userNotice);
00282     
00283 loser:
00284     if ( arena != NULL ) {
00285        PORT_FreeArena(arena, PR_FALSE);
00286     }
00287     
00288     return(NULL);
00289 }
00290 
00291 void
00292 CERT_DestroyUserNotice(CERTUserNotice *userNotice)
00293 {
00294     if ( userNotice != NULL ) {
00295        PORT_FreeArena(userNotice->arena, PR_FALSE);
00296     }
00297     return;
00298 }
00299 
00300 static CERTPolicyStringCallback policyStringCB = NULL;
00301 static void *policyStringCBArg = NULL;
00302 
00303 void
00304 CERT_SetCAPolicyStringCallback(CERTPolicyStringCallback cb, void *cbarg)
00305 {
00306     policyStringCB = cb;
00307     policyStringCBArg = cbarg;
00308     return;
00309 }
00310 
00311 char *
00312 stringFromUserNotice(SECItem *noticeItem)
00313 {
00314     SECItem *org;
00315     unsigned int len, headerlen;
00316     char *stringbuf;
00317     CERTUserNotice *userNotice;
00318     char *policystr;
00319     char *retstr = NULL;
00320     SECItem *displayText;
00321     SECItem **noticeNumbers;
00322     unsigned int strnum;
00323     
00324     /* decode the user notice */
00325     userNotice = CERT_DecodeUserNotice(noticeItem);
00326     if ( userNotice == NULL ) {
00327        return(NULL);
00328     }
00329     
00330     org = &userNotice->noticeReference.organization;
00331     if ( (org->len != 0 ) && ( policyStringCB != NULL ) ) {
00332        /* has a noticeReference */
00333 
00334        /* extract the org string */
00335        len = org->len;
00336        stringbuf = (char*)PORT_Alloc(len + 1);
00337        if ( stringbuf != NULL ) {
00338            PORT_Memcpy(stringbuf, org->data, len);
00339            stringbuf[len] = '\0';
00340 
00341            noticeNumbers = userNotice->noticeReference.noticeNumbers;
00342            while ( *noticeNumbers != NULL ) {
00343               /* XXX - only one byte integers right now*/
00344               strnum = (*noticeNumbers)->data[0];
00345               policystr = (* policyStringCB)(stringbuf,
00346                                           strnum,
00347                                           policyStringCBArg);
00348               if ( policystr != NULL ) {
00349                   if ( retstr != NULL ) {
00350                      retstr = PR_sprintf_append(retstr, "\n%s", policystr);
00351                   } else {
00352                      retstr = PR_sprintf_append(retstr, "%s", policystr);
00353                   }
00354 
00355                   PORT_Free(policystr);
00356               }
00357               
00358               noticeNumbers++;
00359            }
00360 
00361            PORT_Free(stringbuf);
00362        }
00363     }
00364 
00365     if ( retstr == NULL ) {
00366        if ( userNotice->displayText.len != 0 ) {
00367            displayText = &userNotice->displayText;
00368 
00369            if ( displayText->len > 2 ) {
00370               if ( displayText->data[0] == SEC_ASN1_VISIBLE_STRING ) {
00371                   headerlen = 2;
00372                   if ( displayText->data[1] & 0x80 ) {
00373                      /* multibyte length */
00374                      headerlen += ( displayText->data[1] & 0x7f );
00375                   }
00376 
00377                   len = displayText->len - headerlen;
00378                   retstr = (char*)PORT_Alloc(len + 1);
00379                   if ( retstr != NULL ) {
00380                      PORT_Memcpy(retstr, &displayText->data[headerlen],len);
00381                      retstr[len] = '\0';
00382                   }
00383               }
00384            }
00385        }
00386     }
00387     
00388     CERT_DestroyUserNotice(userNotice);
00389     
00390     return(retstr);
00391 }
00392 
00393 char *
00394 CERT_GetCertCommentString(CERTCertificate *cert)
00395 {
00396     char *retstring = NULL;
00397     SECStatus rv;
00398     SECItem policyItem;
00399     CERTCertificatePolicies *policies = NULL;
00400     CERTPolicyInfo **policyInfos;
00401     CERTPolicyQualifier **policyQualifiers, *qualifier;
00402 
00403     policyItem.data = NULL;
00404     
00405     rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
00406                             &policyItem);
00407     if ( rv != SECSuccess ) {
00408        goto nopolicy;
00409     }
00410 
00411     policies = CERT_DecodeCertificatePoliciesExtension(&policyItem);
00412     if ( policies == NULL ) {
00413        goto nopolicy;
00414     }
00415 
00416     policyInfos = policies->policyInfos;
00417     /* search through policyInfos looking for the verisign policy */
00418     while (*policyInfos != NULL ) {
00419        if ( (*policyInfos)->oid == SEC_OID_VERISIGN_USER_NOTICES ) {
00420            policyQualifiers = (*policyInfos)->policyQualifiers;
00421            /* search through the policy qualifiers looking for user notice */
00422            while ( policyQualifiers != NULL && *policyQualifiers != NULL ) {
00423               qualifier = *policyQualifiers;
00424               if ( qualifier->oid == SEC_OID_PKIX_USER_NOTICE_QUALIFIER ) {
00425                   retstring =
00426                      stringFromUserNotice(&qualifier->qualifierValue);
00427                   break;
00428               }
00429 
00430               policyQualifiers++;
00431            }
00432            break;
00433        }
00434        policyInfos++;
00435     }
00436 
00437 nopolicy:
00438     if ( policyItem.data != NULL ) {
00439        PORT_Free(policyItem.data);
00440     }
00441 
00442     if ( policies != NULL ) {
00443        CERT_DestroyCertificatePoliciesExtension(policies);
00444     }
00445     
00446     if ( retstring == NULL ) {
00447        retstring = CERT_FindNSStringExtension(cert,
00448                                           SEC_OID_NS_CERT_EXT_COMMENT);
00449     }
00450     
00451     if ( retstring != NULL ) {
00452        breakLines(retstring);
00453     }
00454     
00455     return(retstring);
00456 }
00457 
00458 
00459 const SEC_ASN1Template CERT_OidSeqTemplate[] = {
00460     { SEC_ASN1_SEQUENCE_OF,
00461          offsetof(CERTOidSequence, oids),
00462          SEC_ObjectIDTemplate }
00463 };
00464 
00465 CERTOidSequence *
00466 CERT_DecodeOidSequence(SECItem *seqItem)
00467 {
00468     PRArenaPool *arena = NULL;
00469     SECStatus rv;
00470     CERTOidSequence *oidSeq;
00471     SECItem newSeqItem;
00472     
00473     /* make a new arena */
00474     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00475     
00476     if ( !arena ) {
00477        goto loser;
00478     }
00479 
00480     /* allocate the userNotice structure */
00481     oidSeq = (CERTOidSequence *)PORT_ArenaZAlloc(arena,
00482                                            sizeof(CERTOidSequence));
00483     
00484     if ( oidSeq == NULL ) {
00485        goto loser;
00486     }
00487     
00488     oidSeq->arena = arena;
00489 
00490     /* copy the DER into the arena, since Quick DER returns data that points
00491        into the DER input, which may get freed by the caller */
00492     rv = SECITEM_CopyItem(arena, &newSeqItem, seqItem);
00493     if ( rv != SECSuccess ) {
00494        goto loser;
00495     }
00496 
00497     /* decode the user notice */
00498     rv = SEC_QuickDERDecodeItem(arena, oidSeq, CERT_OidSeqTemplate, &newSeqItem);
00499 
00500     if ( rv != SECSuccess ) {
00501        goto loser;
00502     }
00503 
00504     return(oidSeq);
00505     
00506 loser:
00507     return(NULL);
00508 }
00509 
00510 
00511 void
00512 CERT_DestroyOidSequence(CERTOidSequence *oidSeq)
00513 {
00514     if ( oidSeq != NULL ) {
00515        PORT_FreeArena(oidSeq->arena, PR_FALSE);
00516     }
00517     return;
00518 }
00519 
00520 PRBool
00521 CERT_GovtApprovedBitSet(CERTCertificate *cert)
00522 {
00523     SECStatus rv;
00524     SECItem extItem;
00525     CERTOidSequence *oidSeq = NULL;
00526     PRBool ret;
00527     SECItem **oids;
00528     SECItem *oid;
00529     SECOidTag oidTag;
00530     
00531     extItem.data = NULL;
00532     rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, &extItem);
00533     if ( rv != SECSuccess ) {
00534        goto loser;
00535     }
00536 
00537     oidSeq = CERT_DecodeOidSequence(&extItem);
00538     if ( oidSeq == NULL ) {
00539        goto loser;
00540     }
00541 
00542     oids = oidSeq->oids;
00543     while ( oids != NULL && *oids != NULL ) {
00544        oid = *oids;
00545        
00546        oidTag = SECOID_FindOIDTag(oid);
00547        
00548        if ( oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED ) {
00549            goto success;
00550        }
00551        
00552        oids++;
00553     }
00554 
00555 loser:
00556     ret = PR_FALSE;
00557     goto done;
00558 success:
00559     ret = PR_TRUE;
00560 done:
00561     if ( oidSeq != NULL ) {
00562        CERT_DestroyOidSequence(oidSeq);
00563     }
00564     if (extItem.data != NULL) {
00565        PORT_Free(extItem.data);
00566     }
00567     return(ret);
00568 }