Back to index

lightning-sunbird  0.9+nobinonly
cmsdigest.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 digesting.
00039  *
00040  * $Id: cmsdigest.c,v 1.8 2004/04/25 15:03:16 gerv%gerv.net Exp $
00041  */
00042 
00043 #include "cmslocal.h"
00044 
00045 #include "cert.h"
00046 #include "key.h"
00047 #include "secitem.h"
00048 #include "secoid.h"
00049 #include "pk11func.h"
00050 #include "prtime.h"
00051 #include "secerr.h"
00052 
00053 /*  #define CMS_FIND_LEAK_MULTIPLE 1 */
00054 #ifdef CMS_FIND_LEAK_MULTIPLE
00055 static int stop_on_err = 1;
00056 static int global_num_digests = 0;
00057 #endif
00058 
00059 struct digestPairStr { 
00060     const SECHashObject * digobj;
00061     void *                digcx;
00062 };
00063 typedef struct digestPairStr digestPair;
00064 
00065 struct NSSCMSDigestContextStr {
00066     PRBool           saw_contents;
00067     PLArenaPool *       pool;
00068     int                     digcnt;
00069     digestPair  *       digPairs;
00070 };
00071 
00072 
00073 /*
00074  * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
00075  *  digest algorithms in "digestalgs" in parallel.
00076  */
00077 NSSCMSDigestContext *
00078 NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
00079 {
00080     PLArenaPool *        pool;
00081     NSSCMSDigestContext *cmsdigcx;
00082     int digcnt;
00083     int i;
00084 
00085 #ifdef CMS_FIND_LEAK_MULTIPLE
00086     PORT_Assert(global_num_digests == 0 || !stop_on_err);
00087 #endif
00088 
00089     digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
00090     /* It's OK if digcnt is zero.  We have to allow this for "certs only"
00091     ** messages.
00092     */
00093     pool = PORT_NewArena(2048);
00094     if (!pool)
00095        return NULL;
00096 
00097     cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
00098     if (cmsdigcx == NULL)
00099        goto loser;
00100 
00101     cmsdigcx->saw_contents = PR_FALSE;
00102     cmsdigcx->pool   = pool;
00103     cmsdigcx->digcnt = digcnt;
00104 
00105     cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
00106     if (cmsdigcx->digPairs == NULL) {
00107        goto loser;
00108     }
00109 
00110     /*
00111      * Create a digest object context for each algorithm.
00112      */
00113     for (i = 0; i < digcnt; i++) {
00114        const SECHashObject *digobj;
00115        void *digcx;
00116 
00117        digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
00118        /*
00119         * Skip any algorithm we do not even recognize; obviously,
00120         * this could be a problem, but if it is critical then the
00121         * result will just be that the signature does not verify.
00122         * We do not necessarily want to error out here, because
00123         * the particular algorithm may not actually be important,
00124         * but we cannot know that until later.
00125         */
00126        if (digobj == NULL)
00127            continue;
00128 
00129        digcx = (*digobj->create)();
00130        if (digcx != NULL) {
00131            (*digobj->begin) (digcx);
00132            cmsdigcx->digPairs[i].digobj = digobj;
00133            cmsdigcx->digPairs[i].digcx  = digcx;
00134 #ifdef CMS_FIND_LEAK_MULTIPLE
00135            global_num_digests++;
00136 #endif
00137        }
00138     }
00139     return cmsdigcx;
00140 
00141 loser:
00142     /* no digest objects have been created, or need to be destroyed. */
00143     if (pool) {
00144        PORT_FreeArena(pool, PR_FALSE);
00145     }
00146     return NULL;
00147 }
00148 
00149 /*
00150  * NSS_CMSDigestContext_StartSingle - same as 
00151  * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
00152  */
00153 NSSCMSDigestContext *
00154 NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
00155 {
00156     SECAlgorithmID *digestalgs[] = { NULL, NULL };             /* fake array */
00157 
00158     digestalgs[0] = digestalg;
00159     return NSS_CMSDigestContext_StartMultiple(digestalgs);
00160 }
00161 
00162 /*
00163  * NSS_CMSDigestContext_Update - feed more data into the digest machine
00164  */
00165 void
00166 NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx, 
00167                             const unsigned char *data, int len)
00168 {
00169     int i;
00170     digestPair *pair = cmsdigcx->digPairs;
00171 
00172     cmsdigcx->saw_contents = PR_TRUE;
00173 
00174     for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
00175        if (pair->digcx) {
00176            (*pair->digobj->update)(pair->digcx, data, len);
00177        }
00178     }
00179 }
00180 
00181 /*
00182  * NSS_CMSDigestContext_Cancel - cancel digesting operation
00183  */
00184 void
00185 NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
00186 {
00187     int i;
00188     digestPair *pair = cmsdigcx->digPairs;
00189 
00190     for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
00191        if (pair->digcx) {
00192            (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
00193 #ifdef CMS_FIND_LEAK_MULTIPLE
00194            --global_num_digests;
00195 #endif
00196        }
00197     }
00198 #ifdef CMS_FIND_LEAK_MULTIPLE
00199     PORT_Assert(global_num_digests == 0 || !stop_on_err);
00200 #endif
00201     PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
00202 }
00203 
00204 /*
00205  * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
00206  *  into an array of SECItems (allocated on poolp)
00207  */
00208 SECStatus
00209 NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx, 
00210                                     PLArenaPool *poolp,
00211                                  SECItem ***digestsp)
00212 {
00213     SECItem **  digests = NULL;
00214     digestPair *pair;
00215     void *      mark;
00216     int         i;
00217     SECStatus   rv;
00218 
00219     /* no contents? do not finish digests */
00220     if (digestsp == NULL || !cmsdigcx->saw_contents) {
00221        rv = SECSuccess;
00222        goto cleanup;
00223     }
00224 
00225     mark = PORT_ArenaMark (poolp);
00226 
00227     /* allocate digest array & SECItems on arena */
00228     digests = PORT_ArenaNewArray( poolp, SECItem *, cmsdigcx->digcnt + 1);
00229 
00230     rv = ((digests == NULL) ? SECFailure : SECSuccess);
00231     pair = cmsdigcx->digPairs;
00232     for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
00233        SECItem digest;
00234        unsigned char hash[HASH_LENGTH_MAX];
00235 
00236        if (!pair->digcx) {
00237            digests[i] = NULL;
00238            continue;
00239        }
00240 
00241        digest.type = siBuffer;
00242        digest.data = hash;
00243        digest.len  = pair->digobj->length;
00244        (* pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
00245        digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
00246        if (!digests[i]) {
00247            rv = SECFailure;
00248        }
00249     }
00250     digests[i] = NULL;
00251     if (rv == SECSuccess) {
00252        PORT_ArenaUnmark(poolp, mark);
00253     } else
00254        PORT_ArenaRelease(poolp, mark);
00255 
00256 cleanup:
00257     NSS_CMSDigestContext_Cancel(cmsdigcx);
00258     /* Don't change the caller's digests pointer if we have no digests.
00259     **  NSS_CMSSignedData_Encode_AfterData depends on this behavior.
00260     */
00261     if (rv == SECSuccess && digestsp && digests) {
00262        *digestsp = digests;
00263     }
00264     return rv;
00265 }
00266 
00267 /*
00268  * NSS_CMSDigestContext_FinishSingle - same as 
00269  * NSS_CMSDigestContext_FinishMultiple, but for one digest.
00270  */
00271 SECStatus
00272 NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx, 
00273                                   PLArenaPool *poolp,
00274                                SECItem *digest)
00275 {
00276     SECStatus rv = SECFailure;
00277     SECItem **dp;
00278     PLArenaPool *arena = NULL;
00279 
00280     if ((arena = PORT_NewArena(1024)) == NULL)
00281        goto loser;
00282 
00283     /* get the digests into arena, then copy the first digest into poolp */
00284     rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
00285     if (rv == SECSuccess) {
00286        /* now copy it into poolp */
00287        rv = SECITEM_CopyItem(poolp, digest, dp[0]);
00288     }
00289 loser:
00290     if (arena)
00291        PORT_FreeArena(arena, PR_FALSE);
00292 
00293     return rv;
00294 }