security/nss/lib/smime/cmssigdata.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial