1/* 2 * The contents of this file are subject to the Mozilla Public 3 * License Version 1.1 (the "License"); you may not use this file 4 * except in compliance with the License. You may obtain a copy of 5 * the License at http://www.mozilla.org/MPL/ 6 * 7 * Software distributed under the License is distributed on an "AS 8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 9 * implied. See the License for the specific language governing 10 * rights and limitations under the License. 11 * 12 * The Original Code is the Netscape security libraries. 13 * 14 * The Initial Developer of the Original Code is Netscape 15 * Communications Corporation. Portions created by Netscape are 16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All 17 * Rights Reserved. 18 * 19 * Contributor(s): 20 * 21 * Alternatively, the contents of this file may be used under the 22 * terms of the GNU General Public License Version 2 or later (the 23 * "GPL"), in which case the provisions of the GPL are applicable 24 * instead of those above. If you wish to allow use of your 25 * version of this file only under the terms of the GPL and not to 26 * allow others to use your version of this file under the MPL, 27 * indicate your decision by deleting the provisions above and 28 * replace them with the notice and other provisions required by 29 * the GPL. If you do not delete the provisions above, a recipient 30 * may use your version of this file under either the MPL or the 31 * GPL. 32 */ 33 34/* 35 * CMS digesting. 36 */ 37 38#include "cmslocal.h" 39 40#include "secitem.h" 41#include "secoid.h" 42 43#include <security_asn1/secerr.h> 44#include <Security/cssmapi.h> 45 46#include <Security/SecCmsDigestContext.h> 47 48 49struct SecCmsDigestContextStr { 50 Boolean saw_contents; 51 int digcnt; 52 CSSM_CC_HANDLE * digobjs; 53}; 54 55/* 56 * SecCmsDigestContextStartMultiple - start digest calculation using all the 57 * digest algorithms in "digestalgs" in parallel. 58 */ 59SecCmsDigestContextRef 60SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs) 61{ 62 SecCmsDigestContextRef cmsdigcx; 63 CSSM_CC_HANDLE digobj; 64 int digcnt; 65 int i; 66 67 digcnt = (digestalgs == NULL) ? 0 : SecCmsArrayCount((void **)digestalgs); 68 69 cmsdigcx = (SecCmsDigestContextRef)PORT_Alloc(sizeof(struct SecCmsDigestContextStr)); 70 if (cmsdigcx == NULL) 71 return NULL; 72 73 if (digcnt > 0) { 74 cmsdigcx->digobjs = (CSSM_CC_HANDLE *)PORT_Alloc(digcnt * sizeof(CSSM_CC_HANDLE)); 75 if (cmsdigcx->digobjs == NULL) 76 goto loser; 77 } 78 79 cmsdigcx->digcnt = 0; 80 81 /* 82 * Create a digest object context for each algorithm. 83 */ 84 for (i = 0; i < digcnt; i++) { 85 digobj = SecCmsUtilGetHashObjByAlgID(digestalgs[i]); 86 /* 87 * Skip any algorithm we do not even recognize; obviously, 88 * this could be a problem, but if it is critical then the 89 * result will just be that the signature does not verify. 90 * We do not necessarily want to error out here, because 91 * the particular algorithm may not actually be important, 92 * but we cannot know that until later. 93 */ 94 if (digobj) 95 { 96 CSSM_RETURN result; 97 result = CSSM_DigestDataInit(digobj); 98 if (result != CSSM_OK) 99 { 100 goto loser; 101 } 102 } 103 104 cmsdigcx->digobjs[cmsdigcx->digcnt] = digobj; 105 cmsdigcx->digcnt++; 106 } 107 108 cmsdigcx->saw_contents = PR_FALSE; 109 110 return cmsdigcx; 111 112loser: 113 if (cmsdigcx) { 114 if (cmsdigcx->digobjs) 115 PORT_Free(cmsdigcx->digobjs); 116 } 117 return NULL; 118} 119 120/* 121 * SecCmsDigestContextStartSingle - same as SecCmsDigestContextStartMultiple, but 122 * only one algorithm. 123 */ 124SecCmsDigestContextRef 125SecCmsDigestContextStartSingle(SECAlgorithmID *digestalg) 126{ 127 SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */ 128 129 digestalgs[0] = digestalg; 130 return SecCmsDigestContextStartMultiple(digestalgs); 131} 132 133/* 134 * SecCmsDigestContextUpdate - feed more data into the digest machine 135 */ 136void 137SecCmsDigestContextUpdate(SecCmsDigestContextRef cmsdigcx, const unsigned char *data, size_t len) 138{ 139 CSSM_DATA dataBuf; 140 int i; 141 142 dataBuf.Length = len; 143 dataBuf.Data = (uint8 *)data; 144 cmsdigcx->saw_contents = PR_TRUE; 145 for (i = 0; i < cmsdigcx->digcnt; i++) 146 if (cmsdigcx->digobjs[i]) 147 CSSM_DigestDataUpdate(cmsdigcx->digobjs[i], &dataBuf, 1); 148} 149 150/* 151 * SecCmsDigestContextCancel - cancel digesting operation 152 */ 153void 154SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx) 155{ 156 int i; 157 158 for (i = 0; i < cmsdigcx->digcnt; i++) 159 if (cmsdigcx->digobjs[i]) 160 CSSM_DeleteContext(cmsdigcx->digobjs[i]); 161} 162 163/* 164 * SecCmsDigestContextFinishMultiple - finish the digests and put them 165 * into an array of CSSM_DATAs (allocated on poolp) 166 */ 167OSStatus 168SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp, 169 CSSM_DATA_PTR **digestsp) 170{ 171 CSSM_CC_HANDLE digobj; 172 CSSM_DATA_PTR *digests, digest; 173 int i; 174 void *mark; 175 OSStatus rv = SECFailure; 176 177 /* no contents? do not update digests */ 178 if (digestsp == NULL || !cmsdigcx->saw_contents) { 179 for (i = 0; i < cmsdigcx->digcnt; i++) 180 if (cmsdigcx->digobjs[i]) 181 CSSM_DeleteContext(cmsdigcx->digobjs[i]); 182 rv = SECSuccess; 183 if (digestsp) 184 *digestsp = NULL; 185 goto cleanup; 186 } 187 188 mark = PORT_ArenaMark ((PLArenaPool *)poolp); 189 190 /* allocate digest array & CSSM_DATAs on arena */ 191 digests = (CSSM_DATA_PTR *)PORT_ArenaAlloc((PLArenaPool *)poolp, (cmsdigcx->digcnt+1) * sizeof(CSSM_DATA_PTR)); 192 digest = (CSSM_DATA_PTR)PORT_ArenaZAlloc((PLArenaPool *)poolp, cmsdigcx->digcnt * sizeof(CSSM_DATA)); 193 if (digests == NULL || digest == NULL) { 194 goto loser; 195 } 196 197 for (i = 0; i < cmsdigcx->digcnt; i++, digest++) { 198 digobj = cmsdigcx->digobjs[i]; 199 CSSM_QUERY_SIZE_DATA dataSize; 200 rv = CSSM_QuerySize(digobj, CSSM_FALSE, 1, &dataSize); 201 if (rv != CSSM_OK) 202 { 203 goto loser; 204 } 205 206 int diglength = dataSize.SizeOutputBlock; 207 208 if (digobj) 209 { 210 digest->Data = (unsigned char*)PORT_ArenaAlloc((PLArenaPool *)poolp, diglength); 211 if (digest->Data == NULL) 212 goto loser; 213 digest->Length = diglength; 214 rv = CSSM_DigestDataFinal(digobj, digest); 215 if (rv != CSSM_OK) 216 { 217 goto loser; 218 } 219 220 CSSM_DeleteContext(digobj); 221 } 222 else 223 { 224 digest->Data = NULL; 225 digest->Length = 0; 226 } 227 228 digests[i] = digest; 229 } 230 digests[i] = NULL; 231 *digestsp = digests; 232 233 rv = SECSuccess; 234 235loser: 236 if (rv == SECSuccess) 237 PORT_ArenaUnmark((PLArenaPool *)poolp, mark); 238 else 239 PORT_ArenaRelease((PLArenaPool *)poolp, mark); 240 241cleanup: 242 if (cmsdigcx->digcnt > 0) { 243 PORT_Free(cmsdigcx->digobjs); 244 } 245 PORT_Free(cmsdigcx); 246 247 return rv; 248} 249 250/* 251 * SecCmsDigestContextFinishSingle - same as SecCmsDigestContextFinishMultiple, 252 * but for one digest. 253 */ 254OSStatus 255SecCmsDigestContextFinishSingle(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp, 256 CSSM_DATA_PTR digest) 257{ 258 OSStatus rv = SECFailure; 259 CSSM_DATA_PTR *dp; 260 PLArenaPool *arena = NULL; 261 262 if ((arena = PORT_NewArena(1024)) == NULL) 263 goto loser; 264 265 /* get the digests into arena, then copy the first digest into poolp */ 266 if (SecCmsDigestContextFinishMultiple(cmsdigcx, (SecArenaPoolRef)arena, &dp) != SECSuccess) 267 goto loser; 268 269 /* now copy it into poolp */ 270 if (SECITEM_CopyItem((PLArenaPool *)poolp, digest, dp[0]) != SECSuccess) 271 goto loser; 272 273 rv = SECSuccess; 274 275loser: 276 if (arena) 277 PORT_FreeArena(arena, PR_FALSE); 278 279 return rv; 280} 281