security/nss/lib/smime/cmssigdata.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * CMS signedData methods.
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "cert.h"
michael@0 12 /*#include "cdbhdl.h"*/
michael@0 13 #include "secasn1.h"
michael@0 14 #include "secitem.h"
michael@0 15 #include "secoid.h"
michael@0 16 #include "pk11func.h"
michael@0 17 #include "secerr.h"
michael@0 18
michael@0 19 NSSCMSSignedData *
michael@0 20 NSS_CMSSignedData_Create(NSSCMSMessage *cmsg)
michael@0 21 {
michael@0 22 void *mark;
michael@0 23 NSSCMSSignedData *sigd;
michael@0 24 PLArenaPool *poolp;
michael@0 25
michael@0 26 if (!cmsg) {
michael@0 27 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 28 return NULL;
michael@0 29 }
michael@0 30
michael@0 31 poolp = cmsg->poolp;
michael@0 32
michael@0 33 mark = PORT_ArenaMark(poolp);
michael@0 34
michael@0 35 sigd = (NSSCMSSignedData *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSSignedData));
michael@0 36 if (sigd == NULL)
michael@0 37 goto loser;
michael@0 38
michael@0 39 sigd->cmsg = cmsg;
michael@0 40
michael@0 41 /* signerInfos, certs, certlists, crls are all empty */
michael@0 42 /* version is set in NSS_CMSSignedData_Finalize() */
michael@0 43
michael@0 44 PORT_ArenaUnmark(poolp, mark);
michael@0 45 return sigd;
michael@0 46
michael@0 47 loser:
michael@0 48 PORT_ArenaRelease(poolp, mark);
michael@0 49 return NULL;
michael@0 50 }
michael@0 51
michael@0 52 void
michael@0 53 NSS_CMSSignedData_Destroy(NSSCMSSignedData *sigd)
michael@0 54 {
michael@0 55 CERTCertificate **certs, **tempCerts, *cert;
michael@0 56 CERTCertificateList **certlists, *certlist;
michael@0 57 NSSCMSSignerInfo **signerinfos, *si;
michael@0 58
michael@0 59 if (sigd == NULL)
michael@0 60 return;
michael@0 61
michael@0 62 certs = sigd->certs;
michael@0 63 tempCerts = sigd->tempCerts;
michael@0 64 certlists = sigd->certLists;
michael@0 65 signerinfos = sigd->signerInfos;
michael@0 66
michael@0 67 if (certs != NULL) {
michael@0 68 while ((cert = *certs++) != NULL)
michael@0 69 CERT_DestroyCertificate (cert);
michael@0 70 }
michael@0 71
michael@0 72 if (tempCerts != NULL) {
michael@0 73 while ((cert = *tempCerts++) != NULL)
michael@0 74 CERT_DestroyCertificate (cert);
michael@0 75 }
michael@0 76
michael@0 77 if (certlists != NULL) {
michael@0 78 while ((certlist = *certlists++) != NULL)
michael@0 79 CERT_DestroyCertificateList (certlist);
michael@0 80 }
michael@0 81
michael@0 82 if (signerinfos != NULL) {
michael@0 83 while ((si = *signerinfos++) != NULL)
michael@0 84 NSS_CMSSignerInfo_Destroy(si);
michael@0 85 }
michael@0 86
michael@0 87 /* everything's in a pool, so don't worry about the storage */
michael@0 88 NSS_CMSContentInfo_Destroy(&(sigd->contentInfo));
michael@0 89
michael@0 90 }
michael@0 91
michael@0 92 /*
michael@0 93 * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData
michael@0 94 * before start of encoding.
michael@0 95 *
michael@0 96 * In detail:
michael@0 97 * - find out about the right value to put into sigd->version
michael@0 98 * - come up with a list of digestAlgorithms (which should be the union of the algorithms
michael@0 99 * in the signerinfos).
michael@0 100 * If we happen to have a pre-set list of algorithms (and digest values!), we
michael@0 101 * check if we have all the signerinfos' algorithms. If not, this is an error.
michael@0 102 */
michael@0 103 SECStatus
michael@0 104 NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd)
michael@0 105 {
michael@0 106 NSSCMSSignerInfo *signerinfo;
michael@0 107 SECOidTag digestalgtag;
michael@0 108 SECItem *dummy;
michael@0 109 int version;
michael@0 110 SECStatus rv;
michael@0 111 PRBool haveDigests = PR_FALSE;
michael@0 112 int n, i;
michael@0 113 PLArenaPool *poolp;
michael@0 114
michael@0 115 if (!sigd) {
michael@0 116 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 117 return SECFailure;
michael@0 118 }
michael@0 119
michael@0 120 poolp = sigd->cmsg->poolp;
michael@0 121
michael@0 122 /* we assume that we have precomputed digests if there is a list of algorithms, and */
michael@0 123 /* a chunk of data for each of those algorithms */
michael@0 124 if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) {
michael@0 125 for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
michael@0 126 if (sigd->digests[i] == NULL)
michael@0 127 break;
michael@0 128 }
michael@0 129 if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */
michael@0 130 haveDigests = PR_TRUE; /* yes: we must have all the digests */
michael@0 131 }
michael@0 132
michael@0 133 version = NSS_CMS_SIGNED_DATA_VERSION_BASIC;
michael@0 134
michael@0 135 /* RFC2630 5.1 "version is the syntax version number..." */
michael@0 136 if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA)
michael@0 137 version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
michael@0 138
michael@0 139 /* prepare all the SignerInfos (there may be none) */
michael@0 140 for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
michael@0 141 signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
michael@0 142
michael@0 143 /* RFC2630 5.1 "version is the syntax version number..." */
michael@0 144 if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN)
michael@0 145 version = NSS_CMS_SIGNED_DATA_VERSION_EXT;
michael@0 146
michael@0 147 /* collect digestAlgorithms from SignerInfos */
michael@0 148 /* (we need to know which algorithms we have when the content comes in) */
michael@0 149 /* do not overwrite any existing digestAlgorithms (and digest) */
michael@0 150 digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
michael@0 151 n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
michael@0 152 if (n < 0 && haveDigests) {
michael@0 153 /* oops, there is a digestalg we do not have a digest for */
michael@0 154 /* but we were supposed to have all the digests already... */
michael@0 155 goto loser;
michael@0 156 } else if (n < 0) {
michael@0 157 /* add the digestAlgorithm & a NULL digest */
michael@0 158 rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL);
michael@0 159 if (rv != SECSuccess)
michael@0 160 goto loser;
michael@0 161 } else {
michael@0 162 /* found it, nothing to do */
michael@0 163 }
michael@0 164 }
michael@0 165
michael@0 166 dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version);
michael@0 167 if (dummy == NULL)
michael@0 168 return SECFailure;
michael@0 169
michael@0 170 /* this is a SET OF, so we need to sort them guys */
michael@0 171 rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms,
michael@0 172 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
michael@0 173 (void **)sigd->digests);
michael@0 174 if (rv != SECSuccess)
michael@0 175 return SECFailure;
michael@0 176
michael@0 177 return SECSuccess;
michael@0 178
michael@0 179 loser:
michael@0 180 return SECFailure;
michael@0 181 }
michael@0 182
michael@0 183 SECStatus
michael@0 184 NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd)
michael@0 185 {
michael@0 186 SECStatus rv;
michael@0 187 if (!sigd) {
michael@0 188 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 189 return SECFailure;
michael@0 190 }
michael@0 191 rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
michael@0 192 if (rv != SECSuccess) {
michael@0 193 return SECFailure;
michael@0 194 }
michael@0 195 /* set up the digests */
michael@0 196 if (sigd->digests && sigd->digests[0]) {
michael@0 197 sigd->contentInfo.privateInfo->digcx = NULL; /* don't attempt to make new ones. */
michael@0 198 } else if (sigd->digestAlgorithms != NULL) {
michael@0 199 sigd->contentInfo.privateInfo->digcx =
michael@0 200 NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
michael@0 201 if (sigd->contentInfo.privateInfo->digcx == NULL)
michael@0 202 return SECFailure;
michael@0 203 }
michael@0 204 return SECSuccess;
michael@0 205 }
michael@0 206
michael@0 207 /*
michael@0 208 * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData
michael@0 209 * after all the encapsulated data was passed through the encoder.
michael@0 210 *
michael@0 211 * In detail:
michael@0 212 * - create the signatures in all the SignerInfos
michael@0 213 *
michael@0 214 * Please note that nothing is done to the Certificates and CRLs in the message - this
michael@0 215 * is entirely the responsibility of our callers.
michael@0 216 */
michael@0 217 SECStatus
michael@0 218 NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd)
michael@0 219 {
michael@0 220 NSSCMSSignerInfo **signerinfos, *signerinfo;
michael@0 221 NSSCMSContentInfo *cinfo;
michael@0 222 SECOidTag digestalgtag;
michael@0 223 SECStatus ret = SECFailure;
michael@0 224 SECStatus rv;
michael@0 225 SECItem *contentType;
michael@0 226 int certcount;
michael@0 227 int i, ci, cli, n, rci, si;
michael@0 228 PLArenaPool *poolp;
michael@0 229 CERTCertificateList *certlist;
michael@0 230 extern const SEC_ASN1Template NSSCMSSignerInfoTemplate[];
michael@0 231
michael@0 232 if (!sigd) {
michael@0 233 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 234 return SECFailure;
michael@0 235 }
michael@0 236
michael@0 237 poolp = sigd->cmsg->poolp;
michael@0 238 cinfo = &(sigd->contentInfo);
michael@0 239
michael@0 240 /* did we have digest calculation going on? */
michael@0 241 if (cinfo->privateInfo && cinfo->privateInfo->digcx) {
michael@0 242 rv = NSS_CMSDigestContext_FinishMultiple(cinfo->privateInfo->digcx, poolp,
michael@0 243 &(sigd->digests));
michael@0 244 /* error has been set by NSS_CMSDigestContext_FinishMultiple */
michael@0 245 cinfo->privateInfo->digcx = NULL;
michael@0 246 if (rv != SECSuccess)
michael@0 247 goto loser;
michael@0 248 }
michael@0 249
michael@0 250 signerinfos = sigd->signerInfos;
michael@0 251 certcount = 0;
michael@0 252
michael@0 253 /* prepare all the SignerInfos (there may be none) */
michael@0 254 for (i=0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) {
michael@0 255 signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i);
michael@0 256
michael@0 257 /* find correct digest for this signerinfo */
michael@0 258 digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
michael@0 259 n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
michael@0 260 if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) {
michael@0 261 /* oops - digest not found */
michael@0 262 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
michael@0 263 goto loser;
michael@0 264 }
michael@0 265
michael@0 266 /* XXX if our content is anything else but data, we need to force the
michael@0 267 * presence of signed attributes (RFC2630 5.3 "signedAttributes is a
michael@0 268 * collection...") */
michael@0 269
michael@0 270 /* pass contentType here as we want a contentType attribute */
michael@0 271 if ((contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo)) == NULL)
michael@0 272 goto loser;
michael@0 273
michael@0 274 /* sign the thing */
michael@0 275 rv = NSS_CMSSignerInfo_Sign(signerinfo, sigd->digests[n], contentType);
michael@0 276 if (rv != SECSuccess)
michael@0 277 goto loser;
michael@0 278
michael@0 279 /* while we're at it, count number of certs in certLists */
michael@0 280 certlist = NSS_CMSSignerInfo_GetCertList(signerinfo);
michael@0 281 if (certlist)
michael@0 282 certcount += certlist->len;
michael@0 283 }
michael@0 284
michael@0 285 /* this is a SET OF, so we need to sort them guys */
michael@0 286 rv = NSS_CMSArray_SortByDER((void **)signerinfos, NSSCMSSignerInfoTemplate, NULL);
michael@0 287 if (rv != SECSuccess)
michael@0 288 goto loser;
michael@0 289
michael@0 290 /*
michael@0 291 * now prepare certs & crls
michael@0 292 */
michael@0 293
michael@0 294 /* count the rest of the certs */
michael@0 295 if (sigd->certs != NULL) {
michael@0 296 for (ci = 0; sigd->certs[ci] != NULL; ci++)
michael@0 297 certcount++;
michael@0 298 }
michael@0 299
michael@0 300 if (sigd->certLists != NULL) {
michael@0 301 for (cli = 0; sigd->certLists[cli] != NULL; cli++)
michael@0 302 certcount += sigd->certLists[cli]->len;
michael@0 303 }
michael@0 304
michael@0 305 if (certcount == 0) {
michael@0 306 sigd->rawCerts = NULL;
michael@0 307 } else {
michael@0 308 /*
michael@0 309 * Combine all of the certs and cert chains into rawcerts.
michael@0 310 * Note: certcount is an upper bound; we may not need that many slots
michael@0 311 * but we will allocate anyway to avoid having to do another pass.
michael@0 312 * (The temporary space saving is not worth it.)
michael@0 313 *
michael@0 314 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
michael@0 315 * SetOfDERcertficates implementation
michael@0 316 */
michael@0 317 sigd->rawCerts = (SECItem **)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SECItem *));
michael@0 318 if (sigd->rawCerts == NULL)
michael@0 319 return SECFailure;
michael@0 320
michael@0 321 /*
michael@0 322 * XXX Want to check for duplicates and not add *any* cert that is
michael@0 323 * already in the set. This will be more important when we start
michael@0 324 * dealing with larger sets of certs, dual-key certs (signing and
michael@0 325 * encryption), etc. For the time being we can slide by...
michael@0 326 *
michael@0 327 * XXX ARGH - this NEEDS to be fixed. need to come up with a decent
michael@0 328 * SetOfDERcertficates implementation
michael@0 329 */
michael@0 330 rci = 0;
michael@0 331 if (signerinfos != NULL) {
michael@0 332 for (si = 0; signerinfos[si] != NULL; si++) {
michael@0 333 signerinfo = signerinfos[si];
michael@0 334 for (ci = 0; ci < signerinfo->certList->len; ci++)
michael@0 335 sigd->rawCerts[rci++] = &(signerinfo->certList->certs[ci]);
michael@0 336 }
michael@0 337 }
michael@0 338
michael@0 339 if (sigd->certs != NULL) {
michael@0 340 for (ci = 0; sigd->certs[ci] != NULL; ci++)
michael@0 341 sigd->rawCerts[rci++] = &(sigd->certs[ci]->derCert);
michael@0 342 }
michael@0 343
michael@0 344 if (sigd->certLists != NULL) {
michael@0 345 for (cli = 0; sigd->certLists[cli] != NULL; cli++) {
michael@0 346 for (ci = 0; ci < sigd->certLists[cli]->len; ci++)
michael@0 347 sigd->rawCerts[rci++] = &(sigd->certLists[cli]->certs[ci]);
michael@0 348 }
michael@0 349 }
michael@0 350
michael@0 351 sigd->rawCerts[rci] = NULL;
michael@0 352
michael@0 353 /* this is a SET OF, so we need to sort them guys - we have the DER already, though */
michael@0 354 NSS_CMSArray_Sort((void **)sigd->rawCerts, NSS_CMSUtil_DERCompare, NULL, NULL);
michael@0 355 }
michael@0 356
michael@0 357 ret = SECSuccess;
michael@0 358
michael@0 359 loser:
michael@0 360 return ret;
michael@0 361 }
michael@0 362
michael@0 363 SECStatus
michael@0 364 NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd)
michael@0 365 {
michael@0 366 SECStatus rv;
michael@0 367 if (!sigd) {
michael@0 368 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 369 return SECFailure;
michael@0 370 }
michael@0 371 rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo);
michael@0 372 if (rv != SECSuccess) {
michael@0 373 return SECFailure;
michael@0 374 }
michael@0 375 /* handle issue with Windows 2003 servers and kerberos */
michael@0 376 if (sigd->digestAlgorithms != NULL) {
michael@0 377 int i;
michael@0 378 for (i=0; sigd->digestAlgorithms[i] != NULL; i++) {
michael@0 379 SECAlgorithmID *algid = sigd->digestAlgorithms[i];
michael@0 380 SECOidTag senttag= SECOID_FindOIDTag(&algid->algorithm);
michael@0 381 SECOidTag maptag = NSS_CMSUtil_MapSignAlgs(senttag);
michael@0 382
michael@0 383 if (maptag != senttag) {
michael@0 384 SECOidData *hashoid = SECOID_FindOIDByTag(maptag);
michael@0 385 rv = SECITEM_CopyItem(sigd->cmsg->poolp, &algid->algorithm
michael@0 386 ,&hashoid->oid);
michael@0 387 if (rv != SECSuccess) {
michael@0 388 return rv;
michael@0 389 }
michael@0 390 }
michael@0 391 }
michael@0 392 }
michael@0 393
michael@0 394 /* set up the digests */
michael@0 395 if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) {
michael@0 396 /* if digests are already there, do nothing */
michael@0 397 sigd->contentInfo.privateInfo->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms);
michael@0 398 if (sigd->contentInfo.privateInfo->digcx == NULL)
michael@0 399 return SECFailure;
michael@0 400 }
michael@0 401 return SECSuccess;
michael@0 402 }
michael@0 403
michael@0 404 /*
michael@0 405 * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a
michael@0 406 * SignedData after all the encapsulated data was passed through the decoder.
michael@0 407 */
michael@0 408 SECStatus
michael@0 409 NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd)
michael@0 410 {
michael@0 411 SECStatus rv = SECSuccess;
michael@0 412
michael@0 413 if (!sigd) {
michael@0 414 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 415 return SECFailure;
michael@0 416 }
michael@0 417
michael@0 418 /* did we have digest calculation going on? */
michael@0 419 if (sigd->contentInfo.privateInfo && sigd->contentInfo.privateInfo->digcx) {
michael@0 420 rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.privateInfo->digcx,
michael@0 421 sigd->cmsg->poolp, &(sigd->digests));
michael@0 422 /* error set by NSS_CMSDigestContext_FinishMultiple */
michael@0 423 sigd->contentInfo.privateInfo->digcx = NULL;
michael@0 424 }
michael@0 425 return rv;
michael@0 426 }
michael@0 427
michael@0 428 /*
michael@0 429 * NSS_CMSSignedData_Decode_AfterEnd - do all the necessary things to a SignedData
michael@0 430 * after all decoding is finished.
michael@0 431 */
michael@0 432 SECStatus
michael@0 433 NSS_CMSSignedData_Decode_AfterEnd(NSSCMSSignedData *sigd)
michael@0 434 {
michael@0 435 NSSCMSSignerInfo **signerinfos = NULL;
michael@0 436 int i;
michael@0 437
michael@0 438 if (!sigd) {
michael@0 439 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 440 return SECFailure;
michael@0 441 }
michael@0 442
michael@0 443 /* set cmsg for all the signerinfos */
michael@0 444 signerinfos = sigd->signerInfos;
michael@0 445
michael@0 446 /* set cmsg for all the signerinfos */
michael@0 447 if (signerinfos) {
michael@0 448 for (i = 0; signerinfos[i] != NULL; i++)
michael@0 449 signerinfos[i]->cmsg = sigd->cmsg;
michael@0 450 }
michael@0 451
michael@0 452 return SECSuccess;
michael@0 453 }
michael@0 454
michael@0 455 /*
michael@0 456 * NSS_CMSSignedData_GetSignerInfos - retrieve the SignedData's signer list
michael@0 457 */
michael@0 458 NSSCMSSignerInfo **
michael@0 459 NSS_CMSSignedData_GetSignerInfos(NSSCMSSignedData *sigd)
michael@0 460 {
michael@0 461 if (!sigd) {
michael@0 462 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 463 return NULL;
michael@0 464 }
michael@0 465 return sigd->signerInfos;
michael@0 466 }
michael@0 467
michael@0 468 int
michael@0 469 NSS_CMSSignedData_SignerInfoCount(NSSCMSSignedData *sigd)
michael@0 470 {
michael@0 471 if (!sigd) {
michael@0 472 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 473 return 0;
michael@0 474 }
michael@0 475 return NSS_CMSArray_Count((void **)sigd->signerInfos);
michael@0 476 }
michael@0 477
michael@0 478 NSSCMSSignerInfo *
michael@0 479 NSS_CMSSignedData_GetSignerInfo(NSSCMSSignedData *sigd, int i)
michael@0 480 {
michael@0 481 if (!sigd) {
michael@0 482 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 483 return NULL;
michael@0 484 }
michael@0 485 return sigd->signerInfos[i];
michael@0 486 }
michael@0 487
michael@0 488 /*
michael@0 489 * NSS_CMSSignedData_GetDigestAlgs - retrieve the SignedData's digest algorithm list
michael@0 490 */
michael@0 491 SECAlgorithmID **
michael@0 492 NSS_CMSSignedData_GetDigestAlgs(NSSCMSSignedData *sigd)
michael@0 493 {
michael@0 494 if (!sigd) {
michael@0 495 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 496 return NULL;
michael@0 497 }
michael@0 498 return sigd->digestAlgorithms;
michael@0 499 }
michael@0 500
michael@0 501 /*
michael@0 502 * NSS_CMSSignedData_GetContentInfo - return pointer to this signedData's contentinfo
michael@0 503 */
michael@0 504 NSSCMSContentInfo *
michael@0 505 NSS_CMSSignedData_GetContentInfo(NSSCMSSignedData *sigd)
michael@0 506 {
michael@0 507 if (!sigd) {
michael@0 508 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 509 return NULL;
michael@0 510 }
michael@0 511 return &(sigd->contentInfo);
michael@0 512 }
michael@0 513
michael@0 514 /*
michael@0 515 * NSS_CMSSignedData_GetCertificateList - retrieve the SignedData's certificate list
michael@0 516 */
michael@0 517 SECItem **
michael@0 518 NSS_CMSSignedData_GetCertificateList(NSSCMSSignedData *sigd)
michael@0 519 {
michael@0 520 if (!sigd) {
michael@0 521 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 522 return NULL;
michael@0 523 }
michael@0 524 return sigd->rawCerts;
michael@0 525 }
michael@0 526
michael@0 527 SECStatus
michael@0 528 NSS_CMSSignedData_ImportCerts(NSSCMSSignedData *sigd, CERTCertDBHandle *certdb,
michael@0 529 SECCertUsage certusage, PRBool keepcerts)
michael@0 530 {
michael@0 531 int certcount;
michael@0 532 CERTCertificate **certArray = NULL;
michael@0 533 CERTCertList *certList = NULL;
michael@0 534 CERTCertListNode *node;
michael@0 535 SECStatus rv;
michael@0 536 SECItem **rawArray;
michael@0 537 int i;
michael@0 538 PRTime now;
michael@0 539
michael@0 540 if (!sigd) {
michael@0 541 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 542 return SECFailure;
michael@0 543 }
michael@0 544
michael@0 545 certcount = NSS_CMSArray_Count((void **)sigd->rawCerts);
michael@0 546
michael@0 547 /* get the certs in the temp DB */
michael@0 548 rv = CERT_ImportCerts(certdb, certusage, certcount, sigd->rawCerts,
michael@0 549 &certArray, PR_FALSE, PR_FALSE, NULL);
michael@0 550 if (rv != SECSuccess) {
michael@0 551 goto loser;
michael@0 552 }
michael@0 553
michael@0 554 /* save the certs so they don't get destroyed */
michael@0 555 for (i=0; i < certcount; i++) {
michael@0 556 CERTCertificate *cert = certArray[i];
michael@0 557 if (cert)
michael@0 558 NSS_CMSSignedData_AddTempCertificate(sigd, cert);
michael@0 559 }
michael@0 560
michael@0 561 if (!keepcerts) {
michael@0 562 goto done;
michael@0 563 }
michael@0 564
michael@0 565 /* build a CertList for filtering */
michael@0 566 certList = CERT_NewCertList();
michael@0 567 if (certList == NULL) {
michael@0 568 rv = SECFailure;
michael@0 569 goto loser;
michael@0 570 }
michael@0 571 for (i=0; i < certcount; i++) {
michael@0 572 CERTCertificate *cert = certArray[i];
michael@0 573 if (cert)
michael@0 574 cert = CERT_DupCertificate(cert);
michael@0 575 if (cert)
michael@0 576 CERT_AddCertToListTail(certList,cert);
michael@0 577 }
michael@0 578
michael@0 579 /* filter out the certs we don't want */
michael@0 580 rv = CERT_FilterCertListByUsage(certList,certusage, PR_FALSE);
michael@0 581 if (rv != SECSuccess) {
michael@0 582 goto loser;
michael@0 583 }
michael@0 584
michael@0 585 /* go down the remaining list of certs and verify that they have
michael@0 586 * valid chains, then import them.
michael@0 587 */
michael@0 588 now = PR_Now();
michael@0 589 for (node = CERT_LIST_HEAD(certList) ; !CERT_LIST_END(node,certList);
michael@0 590 node= CERT_LIST_NEXT(node)) {
michael@0 591 CERTCertificateList *certChain;
michael@0 592
michael@0 593 if (CERT_VerifyCert(certdb, node->cert,
michael@0 594 PR_TRUE, certusage, now, NULL, NULL) != SECSuccess) {
michael@0 595 continue;
michael@0 596 }
michael@0 597
michael@0 598 certChain = CERT_CertChainFromCert(node->cert, certusage, PR_FALSE);
michael@0 599 if (!certChain) {
michael@0 600 continue;
michael@0 601 }
michael@0 602
michael@0 603 /*
michael@0 604 * CertChain returns an array of SECItems, import expects an array of
michael@0 605 * SECItem pointers. Create the SECItem Pointers from the array of
michael@0 606 * SECItems.
michael@0 607 */
michael@0 608 rawArray = (SECItem **)PORT_Alloc(certChain->len*sizeof (SECItem *));
michael@0 609 if (!rawArray) {
michael@0 610 CERT_DestroyCertificateList(certChain);
michael@0 611 continue;
michael@0 612 }
michael@0 613 for (i=0; i < certChain->len; i++) {
michael@0 614 rawArray[i] = &certChain->certs[i];
michael@0 615 }
michael@0 616 (void )CERT_ImportCerts(certdb, certusage, certChain->len,
michael@0 617 rawArray, NULL, keepcerts, PR_FALSE, NULL);
michael@0 618 PORT_Free(rawArray);
michael@0 619 CERT_DestroyCertificateList(certChain);
michael@0 620 }
michael@0 621
michael@0 622 rv = SECSuccess;
michael@0 623
michael@0 624 /* XXX CRL handling */
michael@0 625
michael@0 626 done:
michael@0 627 if (sigd->signerInfos != NULL) {
michael@0 628 /* fill in all signerinfo's certs */
michael@0 629 for (i = 0; sigd->signerInfos[i] != NULL; i++)
michael@0 630 (void)NSS_CMSSignerInfo_GetSigningCertificate(
michael@0 631 sigd->signerInfos[i], certdb);
michael@0 632 }
michael@0 633
michael@0 634 loser:
michael@0 635 /* now free everything */
michael@0 636 if (certArray) {
michael@0 637 CERT_DestroyCertArray(certArray,certcount);
michael@0 638 }
michael@0 639 if (certList) {
michael@0 640 CERT_DestroyCertList(certList);
michael@0 641 }
michael@0 642
michael@0 643 return rv;
michael@0 644 }
michael@0 645
michael@0 646 /*
michael@0 647 * XXX the digests need to be passed in BETWEEN the decoding and the verification in case
michael@0 648 * of external signatures!
michael@0 649 */
michael@0 650
michael@0 651 /*
michael@0 652 * NSS_CMSSignedData_VerifySignerInfo - check the signatures.
michael@0 653 *
michael@0 654 * The digests were either calculated during decoding (and are stored in the
michael@0 655 * signedData itself) or set after decoding using NSS_CMSSignedData_SetDigests.
michael@0 656 *
michael@0 657 * The verification checks if the signing cert is valid and has a trusted chain
michael@0 658 * for the purpose specified by "certusage".
michael@0 659 */
michael@0 660 SECStatus
michael@0 661 NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedData *sigd, int i,
michael@0 662 CERTCertDBHandle *certdb, SECCertUsage certusage)
michael@0 663 {
michael@0 664 NSSCMSSignerInfo *signerinfo;
michael@0 665 NSSCMSContentInfo *cinfo;
michael@0 666 SECOidData *algiddata;
michael@0 667 SECItem *contentType, *digest;
michael@0 668 SECOidTag oidTag;
michael@0 669 SECStatus rv;
michael@0 670
michael@0 671 if (!sigd) {
michael@0 672 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 673 return SECFailure;
michael@0 674 }
michael@0 675
michael@0 676 cinfo = &(sigd->contentInfo);
michael@0 677
michael@0 678 signerinfo = sigd->signerInfos[i];
michael@0 679
michael@0 680 /* verify certificate */
michael@0 681 rv = NSS_CMSSignerInfo_VerifyCertificate(signerinfo, certdb, certusage);
michael@0 682 if (rv != SECSuccess)
michael@0 683 return rv; /* error is set */
michael@0 684
michael@0 685 /* find digest and contentType for signerinfo */
michael@0 686 algiddata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
michael@0 687 oidTag = algiddata ? algiddata->offset : SEC_OID_UNKNOWN;
michael@0 688 digest = NSS_CMSSignedData_GetDigestValue(sigd, oidTag);
michael@0 689 /* NULL digest is acceptable. */
michael@0 690 contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo);
michael@0 691 /* NULL contentType is acceptable. */
michael@0 692
michael@0 693 /* now verify signature */
michael@0 694 rv = NSS_CMSSignerInfo_Verify(signerinfo, digest, contentType);
michael@0 695 return rv;
michael@0 696 }
michael@0 697
michael@0 698 /*
michael@0 699 * NSS_CMSSignedData_VerifyCertsOnly - verify the certs in a certs-only message
michael@0 700 */
michael@0 701 SECStatus
michael@0 702 NSS_CMSSignedData_VerifyCertsOnly(NSSCMSSignedData *sigd,
michael@0 703 CERTCertDBHandle *certdb,
michael@0 704 SECCertUsage usage)
michael@0 705 {
michael@0 706 CERTCertificate *cert;
michael@0 707 SECStatus rv = SECSuccess;
michael@0 708 int i;
michael@0 709 int count;
michael@0 710 PRTime now;
michael@0 711
michael@0 712 if (!sigd || !certdb || !sigd->rawCerts) {
michael@0 713 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 714 return SECFailure;
michael@0 715 }
michael@0 716
michael@0 717 count = NSS_CMSArray_Count((void**)sigd->rawCerts);
michael@0 718 now = PR_Now();
michael@0 719 for (i=0; i < count; i++) {
michael@0 720 if (sigd->certs && sigd->certs[i]) {
michael@0 721 cert = CERT_DupCertificate(sigd->certs[i]);
michael@0 722 } else {
michael@0 723 cert = CERT_FindCertByDERCert(certdb, sigd->rawCerts[i]);
michael@0 724 if (!cert) {
michael@0 725 rv = SECFailure;
michael@0 726 break;
michael@0 727 }
michael@0 728 }
michael@0 729 rv |= CERT_VerifyCert(certdb, cert, PR_TRUE, usage, now,
michael@0 730 NULL, NULL);
michael@0 731 CERT_DestroyCertificate(cert);
michael@0 732 }
michael@0 733
michael@0 734 return rv;
michael@0 735 }
michael@0 736
michael@0 737 /*
michael@0 738 * NSS_CMSSignedData_HasDigests - see if we have digests in place
michael@0 739 */
michael@0 740 PRBool
michael@0 741 NSS_CMSSignedData_HasDigests(NSSCMSSignedData *sigd)
michael@0 742 {
michael@0 743 if (!sigd) {
michael@0 744 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 745 return PR_FALSE;
michael@0 746 }
michael@0 747 return (sigd->digests != NULL);
michael@0 748 }
michael@0 749
michael@0 750 SECStatus
michael@0 751 NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist)
michael@0 752 {
michael@0 753 SECStatus rv;
michael@0 754
michael@0 755 if (!sigd || !certlist) {
michael@0 756 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 757 return SECFailure;
michael@0 758 }
michael@0 759
michael@0 760 /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */
michael@0 761 rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certLists), (void *)certlist);
michael@0 762
michael@0 763 return rv;
michael@0 764 }
michael@0 765
michael@0 766 /*
michael@0 767 * NSS_CMSSignedData_AddCertChain - add cert and its entire chain to the set of certs
michael@0 768 */
michael@0 769 SECStatus
michael@0 770 NSS_CMSSignedData_AddCertChain(NSSCMSSignedData *sigd, CERTCertificate *cert)
michael@0 771 {
michael@0 772 CERTCertificateList *certlist;
michael@0 773 SECCertUsage usage;
michael@0 774 SECStatus rv;
michael@0 775
michael@0 776 usage = certUsageEmailSigner;
michael@0 777
michael@0 778 if (!sigd || !cert) {
michael@0 779 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 780 return SECFailure;
michael@0 781 }
michael@0 782
michael@0 783 /* do not include root */
michael@0 784 certlist = CERT_CertChainFromCert(cert, usage, PR_FALSE);
michael@0 785 if (certlist == NULL)
michael@0 786 return SECFailure;
michael@0 787
michael@0 788 rv = NSS_CMSSignedData_AddCertList(sigd, certlist);
michael@0 789
michael@0 790 return rv;
michael@0 791 }
michael@0 792
michael@0 793 extern SECStatus
michael@0 794 NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
michael@0 795 {
michael@0 796 CERTCertificate *c;
michael@0 797 SECStatus rv;
michael@0 798
michael@0 799 if (!sigd || !cert) {
michael@0 800 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 801 return SECFailure;
michael@0 802 }
michael@0 803
michael@0 804 c = CERT_DupCertificate(cert);
michael@0 805 rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->tempCerts), (void *)c);
michael@0 806 return rv;
michael@0 807 }
michael@0 808
michael@0 809 SECStatus
michael@0 810 NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert)
michael@0 811 {
michael@0 812 CERTCertificate *c;
michael@0 813 SECStatus rv;
michael@0 814
michael@0 815 if (!sigd || !cert) {
michael@0 816 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 817 return SECFailure;
michael@0 818 }
michael@0 819
michael@0 820 c = CERT_DupCertificate(cert);
michael@0 821 rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certs), (void *)c);
michael@0 822 return rv;
michael@0 823 }
michael@0 824
michael@0 825 PRBool
michael@0 826 NSS_CMSSignedData_ContainsCertsOrCrls(NSSCMSSignedData *sigd)
michael@0 827 {
michael@0 828 if (!sigd) {
michael@0 829 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 830 return PR_FALSE;
michael@0 831 }
michael@0 832 if (sigd->rawCerts != NULL && sigd->rawCerts[0] != NULL)
michael@0 833 return PR_TRUE;
michael@0 834 else if (sigd->crls != NULL && sigd->crls[0] != NULL)
michael@0 835 return PR_TRUE;
michael@0 836 else
michael@0 837 return PR_FALSE;
michael@0 838 }
michael@0 839
michael@0 840 SECStatus
michael@0 841 NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd,
michael@0 842 NSSCMSSignerInfo *signerinfo)
michael@0 843 {
michael@0 844 void *mark;
michael@0 845 SECStatus rv;
michael@0 846 SECOidTag digestalgtag;
michael@0 847 PLArenaPool *poolp;
michael@0 848
michael@0 849 if (!sigd || !signerinfo) {
michael@0 850 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 851 return SECFailure;
michael@0 852 }
michael@0 853
michael@0 854 poolp = sigd->cmsg->poolp;
michael@0 855
michael@0 856 mark = PORT_ArenaMark(poolp);
michael@0 857
michael@0 858 /* add signerinfo */
michael@0 859 rv = NSS_CMSArray_Add(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo);
michael@0 860 if (rv != SECSuccess)
michael@0 861 goto loser;
michael@0 862
michael@0 863 /*
michael@0 864 * add empty digest
michael@0 865 * Empty because we don't have it yet. Either it gets created during encoding
michael@0 866 * (if the data is present) or has to be set externally.
michael@0 867 * XXX maybe pass it in optionally?
michael@0 868 */
michael@0 869 digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
michael@0 870 rv = NSS_CMSSignedData_SetDigestValue(sigd, digestalgtag, NULL);
michael@0 871 if (rv != SECSuccess)
michael@0 872 goto loser;
michael@0 873
michael@0 874 /*
michael@0 875 * The last thing to get consistency would be adding the digest.
michael@0 876 */
michael@0 877
michael@0 878 PORT_ArenaUnmark(poolp, mark);
michael@0 879 return SECSuccess;
michael@0 880
michael@0 881 loser:
michael@0 882 PORT_ArenaRelease (poolp, mark);
michael@0 883 return SECFailure;
michael@0 884 }
michael@0 885
michael@0 886 /*
michael@0 887 * NSS_CMSSignedData_SetDigests - set a signedData's digests member
michael@0 888 *
michael@0 889 * "digestalgs" - array of digest algorithm IDs
michael@0 890 * "digests" - array of digests corresponding to the digest algorithms
michael@0 891 */
michael@0 892 SECStatus
michael@0 893 NSS_CMSSignedData_SetDigests(NSSCMSSignedData *sigd,
michael@0 894 SECAlgorithmID **digestalgs,
michael@0 895 SECItem **digests)
michael@0 896 {
michael@0 897 int cnt, i, idx;
michael@0 898
michael@0 899 if (!sigd || !digestalgs || !digests) {
michael@0 900 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 901 return SECFailure;
michael@0 902 }
michael@0 903
michael@0 904 if (sigd->digestAlgorithms == NULL) {
michael@0 905 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 906 return SECFailure;
michael@0 907 }
michael@0 908
michael@0 909 /* we assume that the digests array is just not there yet */
michael@0 910 PORT_Assert(sigd->digests == NULL);
michael@0 911 if (sigd->digests != NULL) {
michael@0 912 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 913 return SECFailure;
michael@0 914 }
michael@0 915
michael@0 916 /* now allocate one (same size as digestAlgorithms) */
michael@0 917 cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
michael@0 918 sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
michael@0 919 if (sigd->digests == NULL) {
michael@0 920 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 921 return SECFailure;
michael@0 922 }
michael@0 923
michael@0 924 for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) {
michael@0 925 /* try to find the sigd's i'th digest algorithm in the array we passed in */
michael@0 926 idx = NSS_CMSAlgArray_GetIndexByAlgID(digestalgs, sigd->digestAlgorithms[i]);
michael@0 927 if (idx < 0) {
michael@0 928 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
michael@0 929 return SECFailure;
michael@0 930 }
michael@0 931 if (!digests[idx]) {
michael@0 932 /* We have no digest for this algorithm, probably because it is
michael@0 933 ** unrecognized or unsupported. We'll ignore this here. If this
michael@0 934 ** digest is needed later, an error will be be generated then.
michael@0 935 */
michael@0 936 continue;
michael@0 937 }
michael@0 938
michael@0 939 /* found it - now set it */
michael@0 940 if ((sigd->digests[i] = SECITEM_AllocItem(sigd->cmsg->poolp, NULL, 0)) == NULL ||
michael@0 941 SECITEM_CopyItem(sigd->cmsg->poolp, sigd->digests[i], digests[idx]) != SECSuccess)
michael@0 942 {
michael@0 943 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 944 return SECFailure;
michael@0 945 }
michael@0 946 }
michael@0 947 return SECSuccess;
michael@0 948 }
michael@0 949
michael@0 950 SECStatus
michael@0 951 NSS_CMSSignedData_SetDigestValue(NSSCMSSignedData *sigd,
michael@0 952 SECOidTag digestalgtag,
michael@0 953 SECItem *digestdata)
michael@0 954 {
michael@0 955 SECItem *digest = NULL;
michael@0 956 PLArenaPool *poolp;
michael@0 957 void *mark;
michael@0 958 int n, cnt;
michael@0 959
michael@0 960 if (!sigd) {
michael@0 961 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 962 return SECFailure;
michael@0 963 }
michael@0 964
michael@0 965 poolp = sigd->cmsg->poolp;
michael@0 966
michael@0 967 mark = PORT_ArenaMark(poolp);
michael@0 968
michael@0 969
michael@0 970 if (digestdata) {
michael@0 971 digest = (SECItem *) PORT_ArenaZAlloc(poolp,sizeof(SECItem));
michael@0 972
michael@0 973 /* copy digestdata item to arena (in case we have it and are not only making room) */
michael@0 974 if (SECITEM_CopyItem(poolp, digest, digestdata) != SECSuccess)
michael@0 975 goto loser;
michael@0 976 }
michael@0 977
michael@0 978 /* now allocate one (same size as digestAlgorithms) */
michael@0 979 if (sigd->digests == NULL) {
michael@0 980 cnt = NSS_CMSArray_Count((void **)sigd->digestAlgorithms);
michael@0 981 sigd->digests = PORT_ArenaZAlloc(sigd->cmsg->poolp, (cnt + 1) * sizeof(SECItem *));
michael@0 982 if (sigd->digests == NULL) {
michael@0 983 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 984 return SECFailure;
michael@0 985 }
michael@0 986 }
michael@0 987
michael@0 988 n = -1;
michael@0 989 if (sigd->digestAlgorithms != NULL)
michael@0 990 n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
michael@0 991
michael@0 992 /* if not found, add a digest */
michael@0 993 if (n < 0) {
michael@0 994 if (NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, digest) != SECSuccess)
michael@0 995 goto loser;
michael@0 996 } else {
michael@0 997 /* replace NULL pointer with digest item (and leak previous value) */
michael@0 998 sigd->digests[n] = digest;
michael@0 999 }
michael@0 1000
michael@0 1001 PORT_ArenaUnmark(poolp, mark);
michael@0 1002 return SECSuccess;
michael@0 1003
michael@0 1004 loser:
michael@0 1005 PORT_ArenaRelease(poolp, mark);
michael@0 1006 return SECFailure;
michael@0 1007 }
michael@0 1008
michael@0 1009 SECStatus
michael@0 1010 NSS_CMSSignedData_AddDigest(PLArenaPool *poolp,
michael@0 1011 NSSCMSSignedData *sigd,
michael@0 1012 SECOidTag digestalgtag,
michael@0 1013 SECItem *digest)
michael@0 1014 {
michael@0 1015 SECAlgorithmID *digestalg;
michael@0 1016 void *mark;
michael@0 1017
michael@0 1018 if (!sigd || !poolp) {
michael@0 1019 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1020 return SECFailure;
michael@0 1021 }
michael@0 1022
michael@0 1023 mark = PORT_ArenaMark(poolp);
michael@0 1024
michael@0 1025 digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
michael@0 1026 if (digestalg == NULL)
michael@0 1027 goto loser;
michael@0 1028
michael@0 1029 if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */
michael@0 1030 goto loser;
michael@0 1031
michael@0 1032 if (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess ||
michael@0 1033 /* even if digest is NULL, add dummy to have same-size array */
michael@0 1034 NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess)
michael@0 1035 {
michael@0 1036 goto loser;
michael@0 1037 }
michael@0 1038
michael@0 1039 PORT_ArenaUnmark(poolp, mark);
michael@0 1040 return SECSuccess;
michael@0 1041
michael@0 1042 loser:
michael@0 1043 PORT_ArenaRelease(poolp, mark);
michael@0 1044 return SECFailure;
michael@0 1045 }
michael@0 1046
michael@0 1047 /* XXX This function doesn't set the error code on failure. */
michael@0 1048 SECItem *
michael@0 1049 NSS_CMSSignedData_GetDigestValue(NSSCMSSignedData *sigd, SECOidTag digestalgtag)
michael@0 1050 {
michael@0 1051 int n;
michael@0 1052
michael@0 1053 if (!sigd) {
michael@0 1054 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1055 return NULL;
michael@0 1056 }
michael@0 1057
michael@0 1058 if (sigd->digestAlgorithms == NULL || sigd->digests == NULL) {
michael@0 1059 PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND);
michael@0 1060 return NULL;
michael@0 1061 }
michael@0 1062
michael@0 1063 n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag);
michael@0 1064
michael@0 1065 return (n < 0) ? NULL : sigd->digests[n];
michael@0 1066 }
michael@0 1067
michael@0 1068 /* =============================================================================
michael@0 1069 * Misc. utility functions
michael@0 1070 */
michael@0 1071
michael@0 1072 /*
michael@0 1073 * NSS_CMSSignedData_CreateCertsOnly - create a certs-only SignedData.
michael@0 1074 *
michael@0 1075 * cert - base certificates that will be included
michael@0 1076 * include_chain - if true, include the complete cert chain for cert
michael@0 1077 *
michael@0 1078 * More certs and chains can be added via AddCertificate and AddCertChain.
michael@0 1079 *
michael@0 1080 * An error results in a return value of NULL and an error set.
michael@0 1081 *
michael@0 1082 * XXXX CRLs
michael@0 1083 */
michael@0 1084 NSSCMSSignedData *
michael@0 1085 NSS_CMSSignedData_CreateCertsOnly(NSSCMSMessage *cmsg, CERTCertificate *cert, PRBool include_chain)
michael@0 1086 {
michael@0 1087 NSSCMSSignedData *sigd;
michael@0 1088 void *mark;
michael@0 1089 PLArenaPool *poolp;
michael@0 1090 SECStatus rv;
michael@0 1091
michael@0 1092 if (!cmsg || !cert) {
michael@0 1093 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 1094 return NULL;
michael@0 1095 }
michael@0 1096
michael@0 1097 poolp = cmsg->poolp;
michael@0 1098 mark = PORT_ArenaMark(poolp);
michael@0 1099
michael@0 1100 sigd = NSS_CMSSignedData_Create(cmsg);
michael@0 1101 if (sigd == NULL)
michael@0 1102 goto loser;
michael@0 1103
michael@0 1104 /* no signerinfos, thus no digestAlgorithms */
michael@0 1105
michael@0 1106 /* but certs */
michael@0 1107 if (include_chain) {
michael@0 1108 rv = NSS_CMSSignedData_AddCertChain(sigd, cert);
michael@0 1109 } else {
michael@0 1110 rv = NSS_CMSSignedData_AddCertificate(sigd, cert);
michael@0 1111 }
michael@0 1112 if (rv != SECSuccess)
michael@0 1113 goto loser;
michael@0 1114
michael@0 1115 /* RFC2630 5.2 sez:
michael@0 1116 * In the degenerate case where there are no signers, the
michael@0 1117 * EncapsulatedContentInfo value being "signed" is irrelevant. In this
michael@0 1118 * case, the content type within the EncapsulatedContentInfo value being
michael@0 1119 * "signed" should be id-data (as defined in section 4), and the content
michael@0 1120 * field of the EncapsulatedContentInfo value should be omitted.
michael@0 1121 */
michael@0 1122 rv = NSS_CMSContentInfo_SetContent_Data(cmsg, &(sigd->contentInfo), NULL, PR_TRUE);
michael@0 1123 if (rv != SECSuccess)
michael@0 1124 goto loser;
michael@0 1125
michael@0 1126 PORT_ArenaUnmark(poolp, mark);
michael@0 1127 return sigd;
michael@0 1128
michael@0 1129 loser:
michael@0 1130 if (sigd)
michael@0 1131 NSS_CMSSignedData_Destroy(sigd);
michael@0 1132 PORT_ArenaRelease(poolp, mark);
michael@0 1133 return NULL;
michael@0 1134 }
michael@0 1135
michael@0 1136 /* TODO:
michael@0 1137 * NSS_CMSSignerInfo_GetReceiptRequest()
michael@0 1138 * NSS_CMSSignedData_HasReceiptRequest()
michael@0 1139 * easy way to iterate over signers
michael@0 1140 */
michael@0 1141

mercurial