Back to index

lightning-sunbird  0.9+nobinonly
cmsmessage.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  * CMS message methods.
00039  *
00040  * $Id: cmsmessage.c,v 1.6 2004/04/25 15:03:16 gerv%gerv.net Exp $
00041  */
00042 
00043 #include "cmslocal.h"
00044 
00045 #include "cert.h"
00046 #include "secasn1.h"
00047 #include "secitem.h"
00048 #include "secoid.h"
00049 #include "pk11func.h"
00050 #include "secerr.h"
00051 
00052 /*
00053  * NSS_CMSMessage_Create - create a CMS message object
00054  *
00055  * "poolp" - arena to allocate memory from, or NULL if new arena should be created
00056  */
00057 NSSCMSMessage *
00058 NSS_CMSMessage_Create(PLArenaPool *poolp)
00059 {
00060     void *mark = NULL;
00061     NSSCMSMessage *cmsg;
00062     PRBool poolp_is_ours = PR_FALSE;
00063 
00064     if (poolp == NULL) {
00065        poolp = PORT_NewArena (1024);           /* XXX what is right value? */
00066        if (poolp == NULL)
00067            return NULL;
00068        poolp_is_ours = PR_TRUE;
00069     } 
00070 
00071     if (!poolp_is_ours)
00072        mark = PORT_ArenaMark(poolp);
00073 
00074     cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSMessage));
00075     if (cmsg == NULL) {
00076        if (!poolp_is_ours) {
00077            if (mark) {
00078               PORT_ArenaRelease(poolp, mark);
00079            }
00080        } else
00081            PORT_FreeArena(poolp, PR_FALSE);
00082        return NULL;
00083     }
00084 
00085     cmsg->poolp = poolp;
00086     cmsg->poolp_is_ours = poolp_is_ours;
00087     cmsg->refCount = 1;
00088 
00089     if (mark)
00090        PORT_ArenaUnmark(poolp, mark);
00091 
00092     return cmsg;
00093 }
00094 
00095 /*
00096  * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
00097  *
00098  * "cmsg" - message object
00099  * "pwfn", pwfn_arg" - callback function for getting token password
00100  * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
00101  * "detached_digestalgs", "detached_digests" - digests from detached content
00102  */
00103 void
00104 NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
00105                      PK11PasswordFunc pwfn, void *pwfn_arg,
00106                      NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
00107                      SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
00108 {
00109     if (pwfn)
00110        PK11_SetPasswordFunc(pwfn);
00111     cmsg->pwfn_arg = pwfn_arg;
00112     cmsg->decrypt_key_cb = decrypt_key_cb;
00113     cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
00114     cmsg->detached_digestalgs = detached_digestalgs;
00115     cmsg->detached_digests = detached_digests;
00116 }
00117 
00118 /*
00119  * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
00120  */
00121 void
00122 NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
00123 {
00124     PORT_Assert (cmsg->refCount > 0);
00125     if (cmsg->refCount <= 0)       /* oops */
00126        return;
00127 
00128     cmsg->refCount--;              /* thread safety? */
00129     if (cmsg->refCount > 0)
00130        return;
00131 
00132     NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
00133 
00134     /* if poolp is not NULL, cmsg is the owner of its arena */
00135     if (cmsg->poolp_is_ours)
00136        PORT_FreeArena (cmsg->poolp, PR_FALSE);   /* XXX clear it? */
00137 }
00138 
00139 /*
00140  * NSS_CMSMessage_Copy - return a copy of the given message. 
00141  *
00142  * The copy may be virtual or may be real -- either way, the result needs
00143  * to be passed to NSS_CMSMessage_Destroy later (as does the original).
00144  */
00145 NSSCMSMessage *
00146 NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
00147 {
00148     if (cmsg == NULL)
00149        return NULL;
00150 
00151     PORT_Assert (cmsg->refCount > 0);
00152 
00153     cmsg->refCount++; /* XXX chrisk thread safety? */
00154     return cmsg;
00155 }
00156 
00157 /*
00158  * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
00159  */
00160 PLArenaPool *
00161 NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
00162 {
00163     return cmsg->poolp;
00164 }
00165 
00166 /*
00167  * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
00168  */
00169 NSSCMSContentInfo *
00170 NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
00171 {
00172     return &(cmsg->contentInfo);
00173 }
00174 
00175 /*
00176  * Return a pointer to the actual content. 
00177  * In the case of those types which are encrypted, this returns the *plain* content.
00178  * In case of nested contentInfos, this descends and retrieves the innermost content.
00179  */
00180 SECItem *
00181 NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
00182 {
00183     /* this is a shortcut */
00184     NSSCMSContentInfo * cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
00185     SECItem           * pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
00186     return pItem;
00187 }
00188 
00189 /*
00190  * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
00191  *
00192  * CMS data content objects do not count.
00193  */
00194 int
00195 NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
00196 {
00197     int count = 0;
00198     NSSCMSContentInfo *cinfo;
00199 
00200     /* walk down the chain of contentinfos */
00201     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) {
00202        count++;
00203        cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
00204     }
00205     return count;
00206 }
00207 
00208 /*
00209  * NSS_CMSMessage_ContentLevel - find content level #n
00210  *
00211  * CMS data content objects do not count.
00212  */
00213 NSSCMSContentInfo *
00214 NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
00215 {
00216     int count = 0;
00217     NSSCMSContentInfo *cinfo;
00218 
00219     /* walk down the chain of contentinfos */
00220     for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
00221        count++;
00222     }
00223 
00224     return cinfo;
00225 }
00226 
00227 /*
00228  * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
00229  */
00230 PRBool
00231 NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
00232 {
00233     NSSCMSContentInfo *cinfo;
00234 
00235     /* descend into CMS message */
00236     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
00237        if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) != SEC_OID_PKCS7_SIGNED_DATA)
00238            continue; /* next level */
00239        
00240        if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
00241            return PR_TRUE;
00242     }
00243     return PR_FALSE;
00244 }
00245 
00246 /*
00247  * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
00248  */
00249 PRBool
00250 NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
00251 {
00252     NSSCMSContentInfo *cinfo;
00253 
00254     /* walk down the chain of contentinfos */
00255     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
00256     {
00257        switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
00258        case SEC_OID_PKCS7_ENVELOPED_DATA:
00259        case SEC_OID_PKCS7_ENCRYPTED_DATA:
00260            return PR_TRUE;
00261        default:
00262            break;
00263        }
00264     }
00265     return PR_FALSE;
00266 }
00267 
00268 /*
00269  * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
00270  *
00271  * If the CMS message has a SignedData with a signature (not just a SignedData)
00272  * return true; false otherwise.  This can/should be called before calling
00273  * VerifySignature, which will always indicate failure if no signature is
00274  * present, but that does not mean there even was a signature!
00275  * Note that the content itself can be empty (detached content was sent
00276  * another way); it is the presence of the signature that matters.
00277  */
00278 PRBool
00279 NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
00280 {
00281     NSSCMSContentInfo *cinfo;
00282 
00283     /* walk down the chain of contentinfos */
00284     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
00285     {
00286        switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
00287        case SEC_OID_PKCS7_SIGNED_DATA:
00288            if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos))
00289               return PR_TRUE;
00290            break;
00291        default:
00292            break;
00293        }
00294     }
00295     return PR_FALSE;
00296 }
00297 
00298 /*
00299  * NSS_CMSMessage_IsContentEmpty - see if content is empty
00300  *
00301  * returns PR_TRUE is innermost content length is < minLen
00302  * XXX need the encrypted content length (why?)
00303  */
00304 PRBool
00305 NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
00306 {
00307     SECItem *item = NULL;
00308 
00309     if (cmsg == NULL)
00310        return PR_TRUE;
00311 
00312     item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
00313 
00314     if (!item) {
00315        return PR_TRUE;
00316     } else if(item->len <= minLen) {
00317        return PR_TRUE;
00318     }
00319 
00320     return PR_FALSE;
00321 }