security/nss/lib/smime/cmsmessage.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 message methods.
     7  */
     9 #include "cmslocal.h"
    11 #include "cert.h"
    12 #include "secasn1.h"
    13 #include "secitem.h"
    14 #include "secoid.h"
    15 #include "pk11func.h"
    16 #include "secerr.h"
    18 /*
    19  * NSS_CMSMessage_Create - create a CMS message object
    20  *
    21  * "poolp" - arena to allocate memory from, or NULL if new arena should be created
    22  */
    23 NSSCMSMessage *
    24 NSS_CMSMessage_Create(PLArenaPool *poolp)
    25 {
    26     void *mark = NULL;
    27     NSSCMSMessage *cmsg;
    28     PRBool poolp_is_ours = PR_FALSE;
    30     if (poolp == NULL) {
    31 	poolp = PORT_NewArena (1024);           /* XXX what is right value? */
    32 	if (poolp == NULL)
    33 	    return NULL;
    34 	poolp_is_ours = PR_TRUE;
    35     } 
    37     if (!poolp_is_ours)
    38 	mark = PORT_ArenaMark(poolp);
    40     cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSMessage));
    41     if (cmsg == NULL) {
    42 	if (!poolp_is_ours) {
    43 	    if (mark) {
    44 		PORT_ArenaRelease(poolp, mark);
    45 	    }
    46 	} else
    47 	    PORT_FreeArena(poolp, PR_FALSE);
    48 	return NULL;
    49     }
    50     NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo));
    52     cmsg->poolp = poolp;
    53     cmsg->poolp_is_ours = poolp_is_ours;
    54     cmsg->refCount = 1;
    56     if (mark)
    57 	PORT_ArenaUnmark(poolp, mark);
    59     return cmsg;
    60 }
    62 /*
    63  * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
    64  *
    65  * "cmsg" - message object
    66  * "pwfn", pwfn_arg" - callback function for getting token password
    67  * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
    68  * "detached_digestalgs", "detached_digests" - digests from detached content
    69  */
    70 void
    71 NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
    72 			PK11PasswordFunc pwfn, void *pwfn_arg,
    73 			NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
    74 			SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
    75 {
    76     if (pwfn)
    77 	PK11_SetPasswordFunc(pwfn);
    78     cmsg->pwfn_arg = pwfn_arg;
    79     cmsg->decrypt_key_cb = decrypt_key_cb;
    80     cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
    81     cmsg->detached_digestalgs = detached_digestalgs;
    82     cmsg->detached_digests = detached_digests;
    83 }
    85 /*
    86  * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
    87  */
    88 void
    89 NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
    90 {
    91     PORT_Assert (cmsg->refCount > 0);
    92     if (cmsg->refCount <= 0)	/* oops */
    93 	return;
    95     cmsg->refCount--;		/* thread safety? */
    96     if (cmsg->refCount > 0)
    97 	return;
    99     NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
   101     /* if poolp is not NULL, cmsg is the owner of its arena */
   102     if (cmsg->poolp_is_ours)
   103 	PORT_FreeArena (cmsg->poolp, PR_FALSE);	/* XXX clear it? */
   104 }
   106 /*
   107  * NSS_CMSMessage_Copy - return a copy of the given message. 
   108  *
   109  * The copy may be virtual or may be real -- either way, the result needs
   110  * to be passed to NSS_CMSMessage_Destroy later (as does the original).
   111  */
   112 NSSCMSMessage *
   113 NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
   114 {
   115     if (cmsg == NULL)
   116 	return NULL;
   118     PORT_Assert (cmsg->refCount > 0);
   120     cmsg->refCount++; /* XXX chrisk thread safety? */
   121     return cmsg;
   122 }
   124 /*
   125  * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
   126  */
   127 PLArenaPool *
   128 NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
   129 {
   130     return cmsg->poolp;
   131 }
   133 /*
   134  * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
   135  */
   136 NSSCMSContentInfo *
   137 NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
   138 {
   139     return &(cmsg->contentInfo);
   140 }
   142 /*
   143  * Return a pointer to the actual content. 
   144  * In the case of those types which are encrypted, this returns the *plain* content.
   145  * In case of nested contentInfos, this descends and retrieves the innermost content.
   146  */
   147 SECItem *
   148 NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
   149 {
   150     /* this is a shortcut */
   151     NSSCMSContentInfo * cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   152     SECItem           * pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
   153     return pItem;
   154 }
   156 /*
   157  * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
   158  *
   159  * CMS data content objects do not count.
   160  */
   161 int
   162 NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
   163 {
   164     int count = 0;
   165     NSSCMSContentInfo *cinfo;
   167     /* walk down the chain of contentinfos */
   168     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) {
   169 	count++;
   170 	cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
   171     }
   172     return count;
   173 }
   175 /*
   176  * NSS_CMSMessage_ContentLevel - find content level #n
   177  *
   178  * CMS data content objects do not count.
   179  */
   180 NSSCMSContentInfo *
   181 NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
   182 {
   183     int count = 0;
   184     NSSCMSContentInfo *cinfo;
   186     /* walk down the chain of contentinfos */
   187     for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
   188 	count++;
   189     }
   191     return cinfo;
   192 }
   194 /*
   195  * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
   196  */
   197 PRBool
   198 NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
   199 {
   200     NSSCMSContentInfo *cinfo;
   202     /* descend into CMS message */
   203     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
   204 	if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo)))
   205 	    continue;	/* next level */
   207 	if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
   208 	    return PR_TRUE;
   209 	/* callback here for generic wrappers? */
   210     }
   211     return PR_FALSE;
   212 }
   214 /*
   215  * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
   216  */
   217 PRBool
   218 NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
   219 {
   220     NSSCMSContentInfo *cinfo;
   222     /* walk down the chain of contentinfos */
   223     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
   224     {
   225 	switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
   226 	case SEC_OID_PKCS7_ENVELOPED_DATA:
   227 	case SEC_OID_PKCS7_ENCRYPTED_DATA:
   228 	    return PR_TRUE;
   229 	default:
   230 	    /* callback here for generic wrappers? */
   231 	    break;
   232 	}
   233     }
   234     return PR_FALSE;
   235 }
   237 /*
   238  * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
   239  *
   240  * If the CMS message has a SignedData with a signature (not just a SignedData)
   241  * return true; false otherwise.  This can/should be called before calling
   242  * VerifySignature, which will always indicate failure if no signature is
   243  * present, but that does not mean there even was a signature!
   244  * Note that the content itself can be empty (detached content was sent
   245  * another way); it is the presence of the signature that matters.
   246  */
   247 PRBool
   248 NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
   249 {
   250     NSSCMSContentInfo *cinfo;
   252     /* walk down the chain of contentinfos */
   253     for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
   254     {
   255 	switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
   256 	case SEC_OID_PKCS7_SIGNED_DATA:
   257 	    if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos))
   258 		return PR_TRUE;
   259 	    break;
   260 	default:
   261 	    /* callback here for generic wrappers? */
   262 	    break;
   263 	}
   264     }
   265     return PR_FALSE;
   266 }
   268 /*
   269  * NSS_CMSMessage_IsContentEmpty - see if content is empty
   270  *
   271  * returns PR_TRUE is innermost content length is < minLen
   272  * XXX need the encrypted content length (why?)
   273  */
   274 PRBool
   275 NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
   276 {
   277     SECItem *item = NULL;
   279     if (cmsg == NULL)
   280 	return PR_TRUE;
   282     item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
   284     if (!item) {
   285 	return PR_TRUE;
   286     } else if(item->len <= minLen) {
   287 	return PR_TRUE;
   288     }
   290     return PR_FALSE;
   291 }

mercurial