security/nss/lib/smime/cmsmessage.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/smime/cmsmessage.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,291 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * CMS message methods.
    1.10 + */
    1.11 +
    1.12 +#include "cmslocal.h"
    1.13 +
    1.14 +#include "cert.h"
    1.15 +#include "secasn1.h"
    1.16 +#include "secitem.h"
    1.17 +#include "secoid.h"
    1.18 +#include "pk11func.h"
    1.19 +#include "secerr.h"
    1.20 +
    1.21 +/*
    1.22 + * NSS_CMSMessage_Create - create a CMS message object
    1.23 + *
    1.24 + * "poolp" - arena to allocate memory from, or NULL if new arena should be created
    1.25 + */
    1.26 +NSSCMSMessage *
    1.27 +NSS_CMSMessage_Create(PLArenaPool *poolp)
    1.28 +{
    1.29 +    void *mark = NULL;
    1.30 +    NSSCMSMessage *cmsg;
    1.31 +    PRBool poolp_is_ours = PR_FALSE;
    1.32 +
    1.33 +    if (poolp == NULL) {
    1.34 +	poolp = PORT_NewArena (1024);           /* XXX what is right value? */
    1.35 +	if (poolp == NULL)
    1.36 +	    return NULL;
    1.37 +	poolp_is_ours = PR_TRUE;
    1.38 +    } 
    1.39 +
    1.40 +    if (!poolp_is_ours)
    1.41 +	mark = PORT_ArenaMark(poolp);
    1.42 +
    1.43 +    cmsg = (NSSCMSMessage *)PORT_ArenaZAlloc (poolp, sizeof(NSSCMSMessage));
    1.44 +    if (cmsg == NULL) {
    1.45 +	if (!poolp_is_ours) {
    1.46 +	    if (mark) {
    1.47 +		PORT_ArenaRelease(poolp, mark);
    1.48 +	    }
    1.49 +	} else
    1.50 +	    PORT_FreeArena(poolp, PR_FALSE);
    1.51 +	return NULL;
    1.52 +    }
    1.53 +    NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo));
    1.54 +
    1.55 +    cmsg->poolp = poolp;
    1.56 +    cmsg->poolp_is_ours = poolp_is_ours;
    1.57 +    cmsg->refCount = 1;
    1.58 +
    1.59 +    if (mark)
    1.60 +	PORT_ArenaUnmark(poolp, mark);
    1.61 +
    1.62 +    return cmsg;
    1.63 +}
    1.64 +
    1.65 +/*
    1.66 + * NSS_CMSMessage_SetEncodingParams - set up a CMS message object for encoding or decoding
    1.67 + *
    1.68 + * "cmsg" - message object
    1.69 + * "pwfn", pwfn_arg" - callback function for getting token password
    1.70 + * "decrypt_key_cb", "decrypt_key_cb_arg" - callback function for getting bulk key for encryptedData
    1.71 + * "detached_digestalgs", "detached_digests" - digests from detached content
    1.72 + */
    1.73 +void
    1.74 +NSS_CMSMessage_SetEncodingParams(NSSCMSMessage *cmsg,
    1.75 +			PK11PasswordFunc pwfn, void *pwfn_arg,
    1.76 +			NSSCMSGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
    1.77 +			SECAlgorithmID **detached_digestalgs, SECItem **detached_digests)
    1.78 +{
    1.79 +    if (pwfn)
    1.80 +	PK11_SetPasswordFunc(pwfn);
    1.81 +    cmsg->pwfn_arg = pwfn_arg;
    1.82 +    cmsg->decrypt_key_cb = decrypt_key_cb;
    1.83 +    cmsg->decrypt_key_cb_arg = decrypt_key_cb_arg;
    1.84 +    cmsg->detached_digestalgs = detached_digestalgs;
    1.85 +    cmsg->detached_digests = detached_digests;
    1.86 +}
    1.87 +
    1.88 +/*
    1.89 + * NSS_CMSMessage_Destroy - destroy a CMS message and all of its sub-pieces.
    1.90 + */
    1.91 +void
    1.92 +NSS_CMSMessage_Destroy(NSSCMSMessage *cmsg)
    1.93 +{
    1.94 +    PORT_Assert (cmsg->refCount > 0);
    1.95 +    if (cmsg->refCount <= 0)	/* oops */
    1.96 +	return;
    1.97 +
    1.98 +    cmsg->refCount--;		/* thread safety? */
    1.99 +    if (cmsg->refCount > 0)
   1.100 +	return;
   1.101 +
   1.102 +    NSS_CMSContentInfo_Destroy(&(cmsg->contentInfo));
   1.103 +
   1.104 +    /* if poolp is not NULL, cmsg is the owner of its arena */
   1.105 +    if (cmsg->poolp_is_ours)
   1.106 +	PORT_FreeArena (cmsg->poolp, PR_FALSE);	/* XXX clear it? */
   1.107 +}
   1.108 +
   1.109 +/*
   1.110 + * NSS_CMSMessage_Copy - return a copy of the given message. 
   1.111 + *
   1.112 + * The copy may be virtual or may be real -- either way, the result needs
   1.113 + * to be passed to NSS_CMSMessage_Destroy later (as does the original).
   1.114 + */
   1.115 +NSSCMSMessage *
   1.116 +NSS_CMSMessage_Copy(NSSCMSMessage *cmsg)
   1.117 +{
   1.118 +    if (cmsg == NULL)
   1.119 +	return NULL;
   1.120 +
   1.121 +    PORT_Assert (cmsg->refCount > 0);
   1.122 +
   1.123 +    cmsg->refCount++; /* XXX chrisk thread safety? */
   1.124 +    return cmsg;
   1.125 +}
   1.126 +
   1.127 +/*
   1.128 + * NSS_CMSMessage_GetArena - return a pointer to the message's arena pool
   1.129 + */
   1.130 +PLArenaPool *
   1.131 +NSS_CMSMessage_GetArena(NSSCMSMessage *cmsg)
   1.132 +{
   1.133 +    return cmsg->poolp;
   1.134 +}
   1.135 +
   1.136 +/*
   1.137 + * NSS_CMSMessage_GetContentInfo - return a pointer to the top level contentInfo
   1.138 + */
   1.139 +NSSCMSContentInfo *
   1.140 +NSS_CMSMessage_GetContentInfo(NSSCMSMessage *cmsg)
   1.141 +{
   1.142 +    return &(cmsg->contentInfo);
   1.143 +}
   1.144 +
   1.145 +/*
   1.146 + * Return a pointer to the actual content. 
   1.147 + * In the case of those types which are encrypted, this returns the *plain* content.
   1.148 + * In case of nested contentInfos, this descends and retrieves the innermost content.
   1.149 + */
   1.150 +SECItem *
   1.151 +NSS_CMSMessage_GetContent(NSSCMSMessage *cmsg)
   1.152 +{
   1.153 +    /* this is a shortcut */
   1.154 +    NSSCMSContentInfo * cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
   1.155 +    SECItem           * pItem = NSS_CMSContentInfo_GetInnerContent(cinfo);
   1.156 +    return pItem;
   1.157 +}
   1.158 +
   1.159 +/*
   1.160 + * NSS_CMSMessage_ContentLevelCount - count number of levels of CMS content objects in this message
   1.161 + *
   1.162 + * CMS data content objects do not count.
   1.163 + */
   1.164 +int
   1.165 +NSS_CMSMessage_ContentLevelCount(NSSCMSMessage *cmsg)
   1.166 +{
   1.167 +    int count = 0;
   1.168 +    NSSCMSContentInfo *cinfo;
   1.169 +
   1.170 +    /* walk down the chain of contentinfos */
   1.171 +    for (cinfo = &(cmsg->contentInfo); cinfo != NULL; ) {
   1.172 +	count++;
   1.173 +	cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo);
   1.174 +    }
   1.175 +    return count;
   1.176 +}
   1.177 +
   1.178 +/*
   1.179 + * NSS_CMSMessage_ContentLevel - find content level #n
   1.180 + *
   1.181 + * CMS data content objects do not count.
   1.182 + */
   1.183 +NSSCMSContentInfo *
   1.184 +NSS_CMSMessage_ContentLevel(NSSCMSMessage *cmsg, int n)
   1.185 +{
   1.186 +    int count = 0;
   1.187 +    NSSCMSContentInfo *cinfo;
   1.188 +
   1.189 +    /* walk down the chain of contentinfos */
   1.190 +    for (cinfo = &(cmsg->contentInfo); cinfo != NULL && count < n; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
   1.191 +	count++;
   1.192 +    }
   1.193 +
   1.194 +    return cinfo;
   1.195 +}
   1.196 +
   1.197 +/*
   1.198 + * NSS_CMSMessage_ContainsCertsOrCrls - see if message contains certs along the way
   1.199 + */
   1.200 +PRBool
   1.201 +NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg)
   1.202 +{
   1.203 +    NSSCMSContentInfo *cinfo;
   1.204 +
   1.205 +    /* descend into CMS message */
   1.206 +    for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) {
   1.207 +	if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag(cinfo)))
   1.208 +	    continue;	/* next level */
   1.209 +	
   1.210 +	if (NSS_CMSSignedData_ContainsCertsOrCrls(cinfo->content.signedData))
   1.211 +	    return PR_TRUE;
   1.212 +	/* callback here for generic wrappers? */
   1.213 +    }
   1.214 +    return PR_FALSE;
   1.215 +}
   1.216 +
   1.217 +/*
   1.218 + * NSS_CMSMessage_IsEncrypted - see if message contains a encrypted submessage
   1.219 + */
   1.220 +PRBool
   1.221 +NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg)
   1.222 +{
   1.223 +    NSSCMSContentInfo *cinfo;
   1.224 +
   1.225 +    /* walk down the chain of contentinfos */
   1.226 +    for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
   1.227 +    {
   1.228 +	switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
   1.229 +	case SEC_OID_PKCS7_ENVELOPED_DATA:
   1.230 +	case SEC_OID_PKCS7_ENCRYPTED_DATA:
   1.231 +	    return PR_TRUE;
   1.232 +	default:
   1.233 +	    /* callback here for generic wrappers? */
   1.234 +	    break;
   1.235 +	}
   1.236 +    }
   1.237 +    return PR_FALSE;
   1.238 +}
   1.239 +
   1.240 +/*
   1.241 + * NSS_CMSMessage_IsSigned - see if message contains a signed submessage
   1.242 + *
   1.243 + * If the CMS message has a SignedData with a signature (not just a SignedData)
   1.244 + * return true; false otherwise.  This can/should be called before calling
   1.245 + * VerifySignature, which will always indicate failure if no signature is
   1.246 + * present, but that does not mean there even was a signature!
   1.247 + * Note that the content itself can be empty (detached content was sent
   1.248 + * another way); it is the presence of the signature that matters.
   1.249 + */
   1.250 +PRBool
   1.251 +NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg)
   1.252 +{
   1.253 +    NSSCMSContentInfo *cinfo;
   1.254 +
   1.255 +    /* walk down the chain of contentinfos */
   1.256 +    for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo))
   1.257 +    {
   1.258 +	switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) {
   1.259 +	case SEC_OID_PKCS7_SIGNED_DATA:
   1.260 +	    if (!NSS_CMSArray_IsEmpty((void **)cinfo->content.signedData->signerInfos))
   1.261 +		return PR_TRUE;
   1.262 +	    break;
   1.263 +	default:
   1.264 +	    /* callback here for generic wrappers? */
   1.265 +	    break;
   1.266 +	}
   1.267 +    }
   1.268 +    return PR_FALSE;
   1.269 +}
   1.270 +
   1.271 +/*
   1.272 + * NSS_CMSMessage_IsContentEmpty - see if content is empty
   1.273 + *
   1.274 + * returns PR_TRUE is innermost content length is < minLen
   1.275 + * XXX need the encrypted content length (why?)
   1.276 + */
   1.277 +PRBool
   1.278 +NSS_CMSMessage_IsContentEmpty(NSSCMSMessage *cmsg, unsigned int minLen)
   1.279 +{
   1.280 +    SECItem *item = NULL;
   1.281 +
   1.282 +    if (cmsg == NULL)
   1.283 +	return PR_TRUE;
   1.284 +
   1.285 +    item = NSS_CMSContentInfo_GetContent(NSS_CMSMessage_GetContentInfo(cmsg));
   1.286 +
   1.287 +    if (!item) {
   1.288 +	return PR_TRUE;
   1.289 +    } else if(item->len <= minLen) {
   1.290 +	return PR_TRUE;
   1.291 +    }
   1.292 +
   1.293 +    return PR_FALSE;
   1.294 +}

mercurial