123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /*
- * CMS message methods.
- */
- #include "cmslocal.h"
- #include "cert.h"
- #include "secasn1.h"
- #include "secitem.h"
- #include "secoid.h"
- #include "pk11func.h"
- #include "secerr.h"
- /*
- * NSS_CMSMessage_Create - create a CMS message object
- *
- * "poolp" - arena to allocate memory from, or NULL if new arena should be created
- */
- NSSCMSMessage *
- NSS_CMSMessage_Create(PLArenaPool *poolp)
- {
- void *mark = NULL;
- NSSCMSMessage *cmsg;
- PRBool poolp_is_ours = PR_FALSE;
- if (poolp == NULL) {
- poolp = PORT_NewArena(1024); /* XXX what is right value? */
- if (poolp == NULL) {
- return NULL;
- }
- poolp_is_ours = PR_TRUE;
- }
- if (!poolp_is_ours)
- mark = PORT_ArenaMark(poolp);
- cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSMessage));
- if (cmsg == NULL ||
- NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)) != SECSuccess) {
- if (!poolp_is_ours) {
- if (mark) {
- PORT_ArenaRelease(poolp, mark);
- }
- } else {
- PORT_FreeArena(poolp, PR_FALSE);
- }
- return NULL;
- }
- cmsg->poolp = poolp;
- cmsg->poolp_is_ours = poolp_is_ours;
- cmsg->refCount = 1;
- if (mark) {
- PORT_ArenaUnmark(poolp, mark);
- }
- return cmsg;
- }
- /*
- * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
- *
- * "cmsg" - message object
- * "pwfn", pwfn_arg" - callback function for getting token password
- * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
- * "detached_digestalgs", "detached_digests" - digests from detached content
- */
- void
- NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
- PK11PasswordFunc pwfn, void *pwfn_arg,
- NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
- SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
- {
- if (cmsg == NULL) {
- return;
- }
- if (pwfn) {
- PK11_SetPasswordFunc(pwfn);
- }
- cmsg->pwfn_arg = pwfn_arg;
- cmsg->decrypt_key_cb = decrypt_key_cb;
- cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
- cmsg->detached_digestalgs = detached_digestalgs;
- cmsg->detached_digests = detached_digests;
- }
- /*
- * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
- */
- void
- NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
- {
- if (cmsg == NULL)
- return;
- PORT_Assert(cmsg->refCount > 0);
- if (cmsg->refCount <= 0) { /* oops */
- return;
- }
- cmsg->refCount--; /* thread safety? */
- if (cmsg->refCount > 0) {
- return;
- }
- NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
- /* if poolp is not NULL, cmsg is the owner of its arena */
- if (cmsg->poolp_is_ours) {
- PORT_FreeArena(cmsg->poolp, PR_FALSE); /* XXX clear it? */
- }
- }
- /*
- * NSS_CMSMessage_Copy - return a copy of the given message.
- *
- * The copy may be virtual or may be real -- either way, the result needs
- * to be passed to NSS_CMSMessage_Destroy later (as does the original).
- */
- NSSCMSMessage *
- NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
- {
- if (cmsg == NULL) {
- return NULL;
- }
- PORT_Assert(cmsg->refCount > 0);
- cmsg->refCount++; /* XXX chrisk thread safety? */
- return cmsg;
- }
- /*
- * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
- */
- PLArenaPool *
- NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
- {
- if (cmsg == NULL) {
- return NULL;
- }
- return cmsg->poolp;
- }
- /*
- * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
- */
- NSSCMSContentInfo *
- NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
- {
- if (cmsg == NULL) {
- return NULL;
- }
- return &(cmsg->contentInfo);
- }
- /*
- * Return a pointer to the actual content.
- * In the case of those types which are encrypted, this returns the *plain* content.
- * In case of nested contentInfos, this descends and retrieves the innermost content.
- */
- SECItem *
- NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
- {
- if (cmsg == NULL) {
- return NULL;
- }
- /* this is a shortcut */
- NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
- SECItem *pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
- return pItem;
- }
- /*
- * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
- *
- * CMS data content objects do not count.
- */
- int
- NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
- {
- int count = 0;
- NSSCMSContentInfo *cinfo;
- if (cmsg == NULL) {
- return 0;
- }
- /* walk down the chain of contentinfos */
- for (cinfo = &(cmsg->contentInfo); cinfo != NULL;) {
- count++;
- cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
- }
- return count;
- }
- /*
- * NSS_CMSMessage_ContentLevel - find content level #n
- *
- * CMS data content objects do not count.
- */
- NSSCMSContentInfo *
- NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
- {
- int count = 0;
- NSSCMSContentInfo *cinfo;
- if (cmsg == NULL) {
- return NULL;
- }
- /* walk down the chain of contentinfos */
- for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n;
- cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
- count++;
- }
- return cinfo;
- }
- /*
- * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
- */
- PRBool
- NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
- {
- NSSCMSContentInfo *cinfo;
- if (cmsg == NULL) {
- return PR_FALSE;
- }
- /* descend into CMS message */
- for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
- cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
- if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo)))
- continue; /* next level */
- if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
- return PR_TRUE;
- /* callback here for generic wrappers? */
- }
- return PR_FALSE;
- }
- /*
- * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
- */
- PRBool
- NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
- {
- NSSCMSContentInfo *cinfo;
- if (cmsg == NULL) {
- return PR_FALSE;
- }
- /* walk down the chain of contentinfos */
- for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
- cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
- switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
- case SEC_OID_PKCS7_ENVELOPED_DATA:
- case SEC_OID_PKCS7_ENCRYPTED_DATA:
- return PR_TRUE;
- default:
- /* callback here for generic wrappers? */
- break;
- }
- }
- return PR_FALSE;
- }
- /*
- * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
- *
- * If the CMS message has a SignedData with a signature (not just a SignedData)
- * return true; false otherwise. This can/should be called before calling
- * VerifySignature, which will always indicate failure if no signature is
- * present, but that does not mean there even was a signature!
- * Note that the content itself can be empty (detached content was sent
- * another way); it is the presence of the signature that matters.
- */
- PRBool
- NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
- {
- NSSCMSContentInfo *cinfo;
- if (cmsg == NULL) {
- return PR_FALSE;
- }
- /* walk down the chain of contentinfos */
- for (cinfo = &(cmsg->contentInfo); cinfo != NULL;
- cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
- switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
- case SEC_OID_PKCS7_SIGNED_DATA:
- if (cinfo->content.signedData == NULL) {
- return PR_FALSE;
- }
- if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos)) {
- return PR_TRUE;
- }
- break;
- default:
- /* callback here for generic wrappers? */
- break;
- }
- }
- return PR_FALSE;
- }
- /*
- * NSS_CMSMessage_IsContentEmpty - see if content is empty
- *
- * returns PR_TRUE is innermost content length is < minLen
- * XXX need the encrypted content length (why?)
- */
- PRBool
- NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
- {
- SECItem *item = NULL;
- if (cmsg == NULL) {
- return PR_TRUE;
- }
- item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
- if (!item) {
- return PR_TRUE;
- } else if (item->len <= minLen) {
- return PR_TRUE;
- }
- return PR_FALSE;
- }
|