diff options
author | rrelyea%redhat.com <devnull@localhost> | 2011-01-28 23:08:27 +0000 |
---|---|---|
committer | rrelyea%redhat.com <devnull@localhost> | 2011-01-28 23:08:27 +0000 |
commit | ee7a00d669c3d01a5c4ab2f74c3b74f42142d289 (patch) | |
tree | ccea67d6192c53d5c7601e3e6590b8f119a4cc13 /security/nss | |
parent | 7e8bc4b5ed3d4c311681fd2d839c63578463123a (diff) | |
download | nss-hg-ee7a00d669c3d01a5c4ab2f74c3b74f42142d289.tar.gz |
Bug 584224 - CMS does not allow content types other than S/MIME
Part 1
Patch by rrelyea
r=emaldona
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/lib/smime/cms.h | 53 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsasn1.c | 14 | ||||
-rw-r--r-- | security/nss/lib/smime/cmscinfo.c | 113 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsdecode.c | 136 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsdigdata.c | 35 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsencdata.c | 31 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsencode.c | 105 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsenvdata.c | 30 | ||||
-rw-r--r-- | security/nss/lib/smime/cmslocal.h | 43 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsmessage.c | 6 | ||||
-rw-r--r-- | security/nss/lib/smime/cmssigdata.c | 32 | ||||
-rw-r--r-- | security/nss/lib/smime/cmst.h | 26 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsutil.c | 9 | ||||
-rw-r--r-- | security/nss/lib/smime/manifest.mn | 1 | ||||
-rw-r--r-- | security/nss/lib/smime/smime.def | 8 |
15 files changed, 412 insertions, 230 deletions
diff --git a/security/nss/lib/smime/cms.h b/security/nss/lib/smime/cms.h index b7f60fb58..d71d0bcb0 100644 --- a/security/nss/lib/smime/cms.h +++ b/security/nss/lib/smime/cms.h @@ -303,6 +303,14 @@ extern SECStatus NSS_CMSContentInfo_SetContent_EncryptedData(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, NSSCMSEncryptedData *encd); /* + * turn off streaming for this content type. + * This could fail with SEC_ERROR_NO_MEMORY in memory constrained conditions. + */ +extern SECStatus +NSS_CMSContentInfo_SetDontStream(NSSCMSContentInfo *cinfo, PRBool dontStream); + + +/* * NSS_CMSContentInfo_GetContent - get pointer to inner content * * needs to be casted... @@ -1128,6 +1136,51 @@ NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut, PLArenaPool *arena); +/************************************************************************ + * + ************************************************************************/ + +/* + * define new S/MIME content type entries + * + * S/MIME uses the builtin PKCS7 oid types for encoding and decoding the + * various S/MIME content. Some applications have their own content type + * which is different from the standard content type defined by S/MIME. + * + * This function allows you to register new content types. There are basically + * Two different types of content, Wrappping content, and Data. + * + * For data types, All the functions below can be zero or NULL excext + * type and is isData, which should be your oid tag and PR_FALSE respectively + * + * For wrapping types, everything must be provided, or you will get encoder + * failures. + * + * If NSS doesn't already define the OID that you need, you can register + * your own with SECOID_AddEntry. + * + * Once you have defined your new content type, you can pass your new content + * type to NSS_CMSContentInfo_SetContent(). + * + * If you are using a wrapping type you can pass your own data structure in + * the ptr field, but it must contain and embedded NSSCMSGenericWrappingData + * structure as the first element. The size you pass to + * NSS_CMSType_RegisterContentType is the total size of your self defined + * data structure. NSS_CMSContentInfo_GetContent will return that data + * structure from the content info. Your ASN1Template will be evaluated + * against that data structure. + */ +SECStatus NSS_CMSType_RegisterContentType(SECOidTag type, + SEC_ASN1Template *template, size_t size, + NSSCMSGenericWrapperDataDestroy *destroy, + NSSCMSGenericWrapperDataCallback * decode_before, + NSSCMSGenericWrapperDataCallback * decode_after, + NSSCMSGenericWrapperDataCallback * decode_end, + NSSCMSGenericWrapperDataCallback * encode_start, + NSSCMSGenericWrapperDataCallback * encode_before, + NSSCMSGenericWrapperDataCallback * encode_after, + PRBool isData); + /************************************************************************/ SEC_END_PROTOS diff --git a/security/nss/lib/smime/cmsasn1.c b/security/nss/lib/smime/cmsasn1.c index 31f9be4d7..b1c1577f8 100644 --- a/security/nss/lib/smime/cmsasn1.c +++ b/security/nss/lib/smime/cmsasn1.c @@ -547,18 +547,22 @@ nss_cms_choose_content_template(void *src_or_dest, PRBool encoding) { const SEC_ASN1Template *theTemplate; NSSCMSContentInfo *cinfo; + SECOidTag type; PORT_Assert (src_or_dest != NULL); if (src_or_dest == NULL) return NULL; cinfo = (NSSCMSContentInfo *)src_or_dest; - switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) { - default: - theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); - break; - case SEC_OID_PKCS7_DATA: + type = NSS_CMSContentInfo_GetContentTypeTag(cinfo); + if (NSS_CMSType_IsData(type)) { theTemplate = SEC_ASN1_GET(SEC_PointerToOctetStringTemplate); + } else switch (type) { + default: + theTemplate = NSS_CMSType_GetTemplate(type); + if (theTemplate == NULL) { + theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); + } break; case SEC_OID_PKCS7_SIGNED_DATA: theTemplate = NSS_PointerToCMSSignedDataTemplate; diff --git a/security/nss/lib/smime/cmscinfo.c b/security/nss/lib/smime/cmscinfo.c index 1129ea33e..73e4eda87 100644 --- a/security/nss/lib/smime/cmscinfo.c +++ b/security/nss/lib/smime/cmscinfo.c @@ -47,11 +47,37 @@ #include "secoid.h" #include "secerr.h" + /* * NSS_CMSContentInfo_Create - create a content info * * version is set in the _Finalize procedures for each content type */ +SECStatus +NSS_CMSContentInfo_Private_Init(NSSCMSContentInfo *cinfo) +{ + if (cinfo->private) { + return SECSuccess; + } + cinfo->private = PORT_ZNew(NSSCMSContentInfoPrivate); + return (cinfo->private) ? SECSuccess: SECFailure; +} + + +static void +nss_cmsContentInfo_private_destroy(NSSCMSContentInfoPrivate *private) +{ + if (private->digcx) { + /* must destroy digest objects */ + NSS_CMSDigestContext_Cancel(private->digcx); + private->digcx = NULL; + } + if (private->ciphcx) { + NSS_CMSCipherContext_Destroy(private->ciphcx); + private->ciphcx = NULL; + } + PORT_Free(private); +} /* * NSS_CMSContentInfo_Destroy - destroy a CMS contentInfo and all of its sub-pieces. @@ -76,23 +102,17 @@ NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo) NSS_CMSDigestedData_Destroy(cinfo->content.digestedData); break; default: + NSS_CMSGenericWrapperData_Destroy(kind, cinfo->content.genericData); /* XXX Anything else that needs to be "manually" freed/destroyed? */ break; } - if (cinfo->digcx) { - /* must destroy digest objects */ - NSS_CMSDigestContext_Cancel(cinfo->digcx); - cinfo->digcx = NULL; + if (cinfo->private) { + nss_cmsContentInfo_private_destroy(cinfo->private); + cinfo->private = NULL; } - if (cinfo->bulkkey) + if (cinfo->bulkkey) { PK11_FreeSymKey(cinfo->bulkkey); - - if (cinfo->ciphcx) { - NSS_CMSCipherContext_Destroy(cinfo->ciphcx); - cinfo->ciphcx = NULL; } - - /* we live in a pool, so no need to worry about storage */ } /* @@ -101,31 +121,46 @@ NSS_CMSContentInfo_Destroy(NSSCMSContentInfo *cinfo) NSSCMSContentInfo * NSS_CMSContentInfo_GetChildContentInfo(NSSCMSContentInfo *cinfo) { - void * ptr = NULL; NSSCMSContentInfo * ccinfo = NULL; SECOidTag tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); switch (tag) { case SEC_OID_PKCS7_SIGNED_DATA: - ptr = (void *)cinfo->content.signedData; ccinfo = &(cinfo->content.signedData->contentInfo); break; case SEC_OID_PKCS7_ENVELOPED_DATA: - ptr = (void *)cinfo->content.envelopedData; ccinfo = &(cinfo->content.envelopedData->contentInfo); break; case SEC_OID_PKCS7_DIGESTED_DATA: - ptr = (void *)cinfo->content.digestedData; ccinfo = &(cinfo->content.digestedData->contentInfo); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: - ptr = (void *)cinfo->content.encryptedData; ccinfo = &(cinfo->content.encryptedData->contentInfo); break; case SEC_OID_PKCS7_DATA: default: + if (NSS_CMSType_IsWrapper(tag)) { + ccinfo = &(cinfo->content.genericData->contentInfo); + } break; } - return (ptr ? ccinfo : NULL); + if (ccinfo && !ccinfo->private) { + NSS_CMSContentInfo_Private_Init(ccinfo); + } + return ccinfo; +} + +SECStatus +NSS_CMSContentInfo_SetDontStream(NSSCMSContentInfo *cinfo, PRBool dontStream) +{ + SECStatus rv; + + rv = NSS_CMSContentInfo_Private_Init(cinfo); + if (rv != SECSuccess) { + /* default is streaming, failure to get ccinfo will not effect this */ + return dontStream ? SECFailure : SECSuccess ; + } + cinfo->private->dontStream = dontStream; + return SECSuccess; } /* @@ -147,7 +182,9 @@ NSS_CMSContentInfo_SetContent(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo, SEC cinfo->content.pointer = ptr; - if (type != SEC_OID_PKCS7_DATA) { + if (NSS_CMSType_IsData(type) && ptr) { + cinfo->rawContent = ptr; + } else { /* as we always have some inner data, * we need to set it to something, just to fool the encoder enough to work on it * and get us into nss_cms_encoder_notify at that point */ @@ -174,9 +211,10 @@ NSS_CMSContentInfo_SetContent_Data(NSSCMSMessage *cmsg, NSSCMSContentInfo *cinfo { if (NSS_CMSContentInfo_SetContent(cmsg, cinfo, SEC_OID_PKCS7_DATA, (void *)data) != SECSuccess) return SECFailure; - cinfo->rawContent = (detached) ? - NULL : (data) ? - data : SECITEM_AllocItem(cmsg->poolp, NULL, 1); + if (detached) { + cinfo->rawContent = NULL; + } + return SECSuccess; } @@ -204,6 +242,7 @@ NSS_CMSContentInfo_SetContent_EncryptedData(NSSCMSMessage *cmsg, NSSCMSContentIn return NSS_CMSContentInfo_SetContent(cmsg, cinfo, SEC_OID_PKCS7_ENCRYPTED_DATA, (void *)encd); } + /* * NSS_CMSContentInfo_GetContent - get pointer to inner content * @@ -215,16 +254,8 @@ NSS_CMSContentInfo_GetContent(NSSCMSContentInfo *cinfo) SECOidTag tag = (cinfo && cinfo->contentTypeTag) ? cinfo->contentTypeTag->offset : SEC_OID_UNKNOWN; - switch (tag) { - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_SIGNED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - return cinfo->content.pointer; - default: - return NULL; - } + return NSS_CMSType_IsWrapper(tag)||NSS_CMSType_IsData(tag) ? + cinfo->content.pointer : NULL; } /* @@ -232,6 +263,7 @@ NSS_CMSContentInfo_GetContent(NSSCMSContentInfo *cinfo) * * this is typically only called by NSS_CMSMessage_GetContent() */ + SECItem * NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo) { @@ -240,26 +272,21 @@ NSS_CMSContentInfo_GetInnerContent(NSSCMSContentInfo *cinfo) SECItem *pItem = NULL; tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); - switch (tag) { - case SEC_OID_PKCS7_DATA: - /* end of recursion - every message has to have a data cinfo */ + if (NSS_CMSType_IsData(tag)) { pItem = cinfo->content.data; - break; - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_SIGNED_DATA: + } else if (NSS_CMSType_IsWrapper(tag)) { ccinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo); - if (ccinfo != NULL) + if (ccinfo != NULL) { pItem = NSS_CMSContentInfo_GetContent(ccinfo); - break; - default: + } + } else { PORT_Assert(0); - break; } + return pItem; } + /* * NSS_CMSContentInfo_GetContentType{Tag,OID} - find out (saving pointer to lookup result * for future reference) and return the inner content type. diff --git a/security/nss/lib/smime/cmsdecode.c b/security/nss/lib/smime/cmsdecode.c index b050b9dc7..e75281d48 100644 --- a/security/nss/lib/smime/cmsdecode.c +++ b/security/nss/lib/smime/cmsdecode.c @@ -120,8 +120,7 @@ nss_cms_decoder_notify(void *arg, PRBool before, void *dest, int depth) #endif /* so what are we working on right now? */ - switch (p7dcx->type) { - case SEC_OID_UNKNOWN: + if (p7dcx->type == SEC_OID_UNKNOWN) { /* * right now, we are still decoding the OUTER (root) cinfo * As soon as we know the inner content type, set up the info, @@ -136,8 +135,7 @@ nss_cms_decoder_notify(void *arg, PRBool before, void *dest, int depth) /* is this ready already ? need to alloc? */ /* XXX yes we need to alloc -- continue here */ } - break; - case SEC_OID_PKCS7_DATA: + } else if (NSS_CMSType_IsData(p7dcx->type)) { /* this can only happen if the outermost cinfo has DATA in it */ /* otherwise, we handle this type implicitely in the inner decoders */ @@ -150,86 +148,71 @@ nss_cms_decoder_notify(void *arg, PRBool before, void *dest, int depth) nss_cms_decoder_update_filter, p7dcx, (PRBool)(p7dcx->cb != NULL)); - break; - } - - if (after && dest == &(rootcinfo->content.data)) { + } else if (after && dest == &(rootcinfo->content.data)) { /* remove the filter */ SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); } - break; - - case SEC_OID_PKCS7_SIGNED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - - if (before && dest == &(rootcinfo->content)) - break; /* we're not there yet */ + } else if (NSS_CMSType_IsWrapper(p7dcx->type)) { + if (!before || dest != &(rootcinfo->content)) { - if (p7dcx->content.pointer == NULL) - p7dcx->content = rootcinfo->content; + if (p7dcx->content.pointer == NULL) + p7dcx->content = rootcinfo->content; - /* get this data type's inner contentInfo */ - cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, + /* get this data type's inner contentInfo */ + cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type); - if (before && dest == &(cinfo->contentType)) { - /* at this point, set up the &%$&$ back pointer */ - /* we cannot do it later, because the content itself is optional! */ - /* please give me C++ */ - switch (p7dcx->type) { - case SEC_OID_PKCS7_SIGNED_DATA: - p7dcx->content.signedData->cmsg = p7dcx->cmsg; - break; - case SEC_OID_PKCS7_DIGESTED_DATA: - p7dcx->content.digestedData->cmsg = p7dcx->cmsg; - break; - case SEC_OID_PKCS7_ENVELOPED_DATA: - p7dcx->content.envelopedData->cmsg = p7dcx->cmsg; - break; - case SEC_OID_PKCS7_ENCRYPTED_DATA: - p7dcx->content.encryptedData->cmsg = p7dcx->cmsg; - break; - default: - PORT_Assert(0); - break; + if (before && dest == &(cinfo->contentType)) { + /* at this point, set up the &%$&$ back pointer */ + /* we cannot do it later, because the content itself + * is optional! */ + switch (p7dcx->type) { + case SEC_OID_PKCS7_SIGNED_DATA: + p7dcx->content.signedData->cmsg = p7dcx->cmsg; + break; + case SEC_OID_PKCS7_DIGESTED_DATA: + p7dcx->content.digestedData->cmsg = p7dcx->cmsg; + break; + case SEC_OID_PKCS7_ENVELOPED_DATA: + p7dcx->content.envelopedData->cmsg = p7dcx->cmsg; + break; + case SEC_OID_PKCS7_ENCRYPTED_DATA: + p7dcx->content.encryptedData->cmsg = p7dcx->cmsg; + break; + default: + p7dcx->content.genericData->cmsg = p7dcx->cmsg; + break; + } } - } - if (before && dest == &(cinfo->rawContent)) { - /* we want the ASN.1 decoder to deliver the decoded bytes to us - ** from now on - */ - SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, + if (before && dest == &(cinfo->rawContent)) { + /* we want the ASN.1 decoder to deliver the decoded bytes to us + ** from now on + */ + SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, nss_cms_decoder_update_filter, p7dcx, (PRBool)(p7dcx->cb != NULL)); - /* we're right in front of the data */ - if (nss_cms_before_data(p7dcx) != SECSuccess) { - SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); - /* stop all processing */ - p7dcx->error = PORT_GetError(); + /* we're right in front of the data */ + if (nss_cms_before_data(p7dcx) != SECSuccess) { + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); + /* stop all processing */ + p7dcx->error = PORT_GetError(); + } } - } - if (after && dest == &(cinfo->rawContent)) { - /* we're right after of the data */ - if (nss_cms_after_data(p7dcx) != SECSuccess) - p7dcx->error = PORT_GetError(); + if (after && dest == &(cinfo->rawContent)) { + /* we're right after of the data */ + if (nss_cms_after_data(p7dcx) != SECSuccess) + p7dcx->error = PORT_GetError(); - /* we don't need to see the contents anymore */ - SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); + /* we don't need to see the contents anymore */ + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); + } } - break; - -#if 0 /* NIH */ - case SEC_OID_PKCS7_AUTHENTICATED_DATA: -#endif - default: + } else { /* unsupported or unknown message type - fail gracefully */ p7dcx->error = SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE; - break; } } @@ -269,7 +252,8 @@ nss_cms_before_data(NSSCMSDecoderContext *p7dcx) p7dcx->content.encryptedData); break; default: - return SECFailure; + rv = NSS_CMSGenericWrapperData_Decode_BeforeData(p7dcx->type, + p7dcx->content.genericData); } if (rv != SECSuccess) return SECFailure; @@ -280,7 +264,7 @@ nss_cms_before_data(NSSCMSDecoderContext *p7dcx) cinfo = NSS_CMSContent_GetContentInfo(p7dcx->content.pointer, p7dcx->type); childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); - if (childtype == SEC_OID_PKCS7_DATA) { + if (NSS_CMSType_IsData(childtype)) { cinfo->content.pointer = (void *) nss_cms_create_decoder_data(poolp); if (cinfo->content.pointer == NULL) /* set memory error */ @@ -395,7 +379,8 @@ nss_cms_after_data(NSSCMSDecoderContext *p7dcx) /* do nothing */ break; default: - rv = SECFailure; + rv = NSS_CMSGenericWrapperData_Decode_AfterData(p7dcx->type, + p7dcx->content.genericData); break; } done: @@ -430,7 +415,8 @@ nss_cms_after_end(NSSCMSDecoderContext *p7dcx) case SEC_OID_PKCS7_DATA: break; default: - rv = SECFailure; /* we should not have got that far... */ + rv = NSS_CMSGenericWrapperData_Decode_AfterEnd(p7dcx->type, + p7dcx->content.genericData); break; } return rv; @@ -469,7 +455,7 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, goto loser; } - if (cinfo->ciphcx != NULL) { + if (cinfo->private && cinfo->private->ciphcx != NULL) { /* * we are decrypting. * @@ -483,7 +469,7 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, unsigned int buflen; /* length available for decrypted data */ /* find out about the length of decrypted data */ - buflen = NSS_CMSCipherContext_DecryptLength(cinfo->ciphcx, len, final); + buflen = NSS_CMSCipherContext_DecryptLength(cinfo->private->ciphcx, len, final); /* * it might happen that we did not provide enough data for a full @@ -514,7 +500,7 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, * any output (see above), but we still need to call NSS_CMSCipherContext_Decrypt to * keep track of incoming data */ - rv = NSS_CMSCipherContext_Decrypt(cinfo->ciphcx, buf, &outlen, buflen, + rv = NSS_CMSCipherContext_Decrypt(cinfo->private->ciphcx, buf, &outlen, buflen, data, len, final); if (rv != SECSuccess) { p7dcx->error = PORT_GetError(); @@ -534,8 +520,8 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx, /* * Update the running digests with plaintext bytes (if we need to). */ - if (cinfo->digcx) - NSS_CMSDigestContext_Update(cinfo->digcx, data, len); + if (cinfo->private && cinfo->private->digcx) + NSS_CMSDigestContext_Update(cinfo->private->digcx, data, len); /* at this point, we have the plain decoded & decrypted data ** which is either more encoded DER (which we need to hand to the child diff --git a/security/nss/lib/smime/cmsdigdata.c b/security/nss/lib/smime/cmsdigdata.c index e3eb4159d..ba061d57c 100644 --- a/security/nss/lib/smime/cmsdigdata.c +++ b/security/nss/lib/smime/cmsdigdata.c @@ -117,7 +117,8 @@ NSS_CMSDigestedData_Encode_BeforeStart(NSSCMSDigestedData *digd) SECItem *dummy; version = NSS_CMS_DIGESTED_DATA_VERSION_DATA; - if (NSS_CMSContentInfo_GetContentTypeTag(&(digd->contentInfo)) != SEC_OID_PKCS7_DATA) + if (!NSS_CMSType_IsData(NSS_CMSContentInfo_GetContentTypeTag( + &(digd->contentInfo)))) version = NSS_CMS_DIGESTED_DATA_VERSION_ENCAP; dummy = SEC_ASN1EncodeInteger(digd->cmsg->poolp, &(digd->version), version); @@ -134,11 +135,16 @@ NSS_CMSDigestedData_Encode_BeforeStart(NSSCMSDigestedData *digd) SECStatus NSS_CMSDigestedData_Encode_BeforeData(NSSCMSDigestedData *digd) { + SECStatus rv =NSS_CMSContentInfo_Private_Init(&digd->contentInfo); + if (rv != SECSuccess) { + return SECFailure; + } + /* set up the digests */ if (digd->digestAlg.algorithm.len != 0 && digd->digest.len == 0) { /* if digest is already there, do nothing */ - digd->contentInfo.digcx = NSS_CMSDigestContext_StartSingle(&(digd->digestAlg)); - if (digd->contentInfo.digcx == NULL) + digd->contentInfo.private->digcx = NSS_CMSDigestContext_StartSingle(&(digd->digestAlg)); + if (digd->contentInfo.private->digcx == NULL) return SECFailure; } return SECSuccess; @@ -156,12 +162,12 @@ NSS_CMSDigestedData_Encode_AfterData(NSSCMSDigestedData *digd) { SECStatus rv = SECSuccess; /* did we have digest calculation going on? */ - if (digd->contentInfo.digcx) { - rv = NSS_CMSDigestContext_FinishSingle(digd->contentInfo.digcx, + if (digd->contentInfo.private && digd->contentInfo.private->digcx) { + rv = NSS_CMSDigestContext_FinishSingle(digd->contentInfo.private->digcx, digd->cmsg->poolp, &(digd->digest)); /* error has been set by NSS_CMSDigestContext_FinishSingle */ - digd->contentInfo.digcx = NULL; + digd->contentInfo.private->digcx = NULL; } return rv; @@ -177,12 +183,19 @@ NSS_CMSDigestedData_Encode_AfterData(NSSCMSDigestedData *digd) SECStatus NSS_CMSDigestedData_Decode_BeforeData(NSSCMSDigestedData *digd) { + SECStatus rv; + /* is there a digest algorithm yet? */ if (digd->digestAlg.algorithm.len == 0) return SECFailure; - digd->contentInfo.digcx = NSS_CMSDigestContext_StartSingle(&(digd->digestAlg)); - if (digd->contentInfo.digcx == NULL) + rv = NSS_CMSContentInfo_Private_Init(&digd->contentInfo); + if (rv != SECSuccess) { + return SECFailure; + } + + digd->contentInfo.private->digcx = NSS_CMSDigestContext_StartSingle(&(digd->digestAlg)); + if (digd->contentInfo.private->digcx == NULL) return SECFailure; return SECSuccess; @@ -200,12 +213,12 @@ NSS_CMSDigestedData_Decode_AfterData(NSSCMSDigestedData *digd) { SECStatus rv = SECSuccess; /* did we have digest calculation going on? */ - if (digd->contentInfo.digcx) { - rv = NSS_CMSDigestContext_FinishSingle(digd->contentInfo.digcx, + if (digd->contentInfo.private && digd->contentInfo.private->digcx) { + rv = NSS_CMSDigestContext_FinishSingle(digd->contentInfo.private->digcx, digd->cmsg->poolp, &(digd->cdigest)); /* error has been set by NSS_CMSDigestContext_FinishSingle */ - digd->contentInfo.digcx = NULL; + digd->contentInfo.private->digcx = NULL; } return rv; diff --git a/security/nss/lib/smime/cmsencdata.c b/security/nss/lib/smime/cmsencdata.c index a14a3b7c7..caa892e5b 100644 --- a/security/nss/lib/smime/cmsencdata.c +++ b/security/nss/lib/smime/cmsencdata.c @@ -181,6 +181,7 @@ NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd) NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey; SECAlgorithmID *algid; + SECStatus rv; cinfo = &(encd->contentInfo); @@ -192,12 +193,16 @@ NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd) if (algid == NULL) return SECFailure; + rv = NSS_CMSContentInfo_Private_Init(cinfo); + if (rv != SECSuccess) { + return SECFailure; + } /* this may modify algid (with IVs generated in a token). * it is therefore essential that algid is a pointer to the "real" contentEncAlg, * not just to a copy */ - cinfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid); + cinfo->private->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp, bulkkey, algid); PK11_FreeSymKey(bulkkey); - if (cinfo->ciphcx == NULL) + if (cinfo->private->ciphcx == NULL) return SECFailure; return SECSuccess; @@ -209,9 +214,9 @@ NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd) SECStatus NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd) { - if (encd->contentInfo.ciphcx) { - NSS_CMSCipherContext_Destroy(encd->contentInfo.ciphcx); - encd->contentInfo.ciphcx = NULL; + if (encd->contentInfo.private && encd->contentInfo.private->ciphcx) { + NSS_CMSCipherContext_Destroy(encd->contentInfo.private->ciphcx); + encd->contentInfo.private->ciphcx = NULL; } /* nothing to do after data */ @@ -244,8 +249,14 @@ NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd) NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); - cinfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); - if (cinfo->ciphcx == NULL) + rv = NSS_CMSContentInfo_Private_Init(cinfo); + if (rv != SECSuccess) { + goto loser; + } + rv = SECFailure; + + cinfo->private->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); + if (cinfo->private->ciphcx == NULL) goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */ @@ -264,9 +275,9 @@ loser: SECStatus NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd) { - if (encd->contentInfo.ciphcx) { - NSS_CMSCipherContext_Destroy(encd->contentInfo.ciphcx); - encd->contentInfo.ciphcx = NULL; + if (encd->contentInfo.private && encd->contentInfo.private->ciphcx) { + NSS_CMSCipherContext_Destroy(encd->contentInfo.private->ciphcx); + encd->contentInfo.private->ciphcx = NULL; } return SECSuccess; diff --git a/security/nss/lib/smime/cmsencode.c b/security/nss/lib/smime/cmsencode.c index 419b5d707..221d5c7d3 100644 --- a/security/nss/lib/smime/cmsencode.c +++ b/security/nss/lib/smime/cmsencode.c @@ -159,19 +159,7 @@ nss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth) * Watch for the content field, at which point we want to instruct * the ASN.1 encoder to start taking bytes from the buffer. */ - switch (p7ecx->type) { - default: - case SEC_OID_UNKNOWN: - /* we're still in the root message */ - if (after && dest == &(rootcinfo->contentType)) { - /* got the content type OID now - so find out the type tag */ - p7ecx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo); - /* set up a pointer to our current content */ - p7ecx->content = rootcinfo->content; - } - break; - - case SEC_OID_PKCS7_DATA: + if (NSS_CMSType_IsData(p7ecx->type)) { if (before && dest == &(rootcinfo->rawContent)) { /* just set up encoder to grab from user - no encryption or digesting */ if ((item = rootcinfo->content.data) != NULL) @@ -180,13 +168,7 @@ nss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth) SEC_ASN1EncoderSetTakeFromBuf(p7ecx->ecx); SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */ } - break; - - case SEC_OID_PKCS7_SIGNED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - + } else if (NSS_CMSType_IsWrapper(p7ecx->type)) { /* when we know what the content is, we encode happily until we reach the inner content */ cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type); childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); @@ -199,7 +181,7 @@ nss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth) p7ecx->error = PORT_GetError(); } if (before && dest == &(cinfo->rawContent)) { - if (childtype == SEC_OID_PKCS7_DATA && (item = cinfo->content.data) != NULL) + if (NSS_CMSType_IsData(childtype) && (item = cinfo->content.data) != NULL) /* we have data - feed it in */ (void)nss_cms_encoder_work_data(p7ecx, NULL, item->data, item->len, PR_TRUE, PR_TRUE); else @@ -211,7 +193,14 @@ nss_cms_encoder_notify(void *arg, PRBool before, void *dest, int depth) p7ecx->error = PORT_GetError(); SEC_ASN1EncoderClearNotifyProc(p7ecx->ecx); /* no need to get notified anymore */ } - break; + } else { + /* we're still in the root message */ + if (after && dest == &(rootcinfo->contentType)) { + /* got the content type OID now - so find out the type tag */ + p7ecx->type = NSS_CMSContentInfo_GetContentTypeTag(rootcinfo); + /* set up a pointer to our current content */ + p7ecx->content = rootcinfo->content; + } } } @@ -247,7 +236,11 @@ nss_cms_before_data(NSSCMSEncoderContext *p7ecx) rv = NSS_CMSEncryptedData_Encode_BeforeData(p7ecx->content.encryptedData); break; default: - rv = SECFailure; + if (NSS_CMSType_IsWrapper(p7ecx->type)) { + rv = NSS_CMSGenericWrapperData_Encode_BeforeData(p7ecx->type, p7ecx->content.genericData); + } else { + rv = SECFailure; + } } if (rv != SECSuccess) return SECFailure; @@ -258,14 +251,7 @@ nss_cms_before_data(NSSCMSEncoderContext *p7ecx) cinfo = NSS_CMSContent_GetContentInfo(p7ecx->content.pointer, p7ecx->type); childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); - switch (childtype) { - case SEC_OID_PKCS7_SIGNED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: -#if 0 - case SEC_OID_PKCS7_DATA: /* XXX here also??? maybe yes! */ -#endif + if (NSS_CMSType_IsWrapper(childtype)) { /* in these cases, we need to set up a child encoder! */ /* create new encoder context */ childp7ecx = PORT_ZAlloc(sizeof(NSSCMSEncoderContext)); @@ -303,11 +289,8 @@ nss_cms_before_data(NSSCMSEncoderContext *p7ecx) case SEC_OID_PKCS7_ENCRYPTED_DATA: rv = NSS_CMSEncryptedData_Encode_BeforeStart(cinfo->content.encryptedData); break; - case SEC_OID_PKCS7_DATA: - rv = SECSuccess; - break; default: - PORT_Assert(0); + rv = NSS_CMSGenericWrapperData_Encode_BeforeStart(childp7ecx->type, cinfo->content.genericData); break; } if (rv != SECSuccess) @@ -327,7 +310,8 @@ nss_cms_before_data(NSSCMSEncoderContext *p7ecx) * Indicate that we are streaming. We will be streaming until we * get past the contents bytes. */ - SEC_ASN1EncoderSetStreaming(childp7ecx->ecx); + if (!cinfo->private || !cinfo->private->dontStream) + SEC_ASN1EncoderSetStreaming(childp7ecx->ecx); /* * The notify function will watch for the contents field. @@ -346,15 +330,11 @@ nss_cms_before_data(NSSCMSEncoderContext *p7ecx) goto loser; p7ecx->childp7ecx = childp7ecx; - break; - - case SEC_OID_PKCS7_DATA: + } else if (NSS_CMSType_IsData(childtype)) { p7ecx->childp7ecx = NULL; - break; - default: + } else { /* we do not know this type */ p7ecx->error = SEC_ERROR_BAD_DER; - break; } return SECSuccess; @@ -387,11 +367,12 @@ nss_cms_after_data(NSSCMSEncoderContext *p7ecx) case SEC_OID_PKCS7_ENCRYPTED_DATA: rv = NSS_CMSEncryptedData_Encode_AfterData(p7ecx->content.encryptedData); break; - case SEC_OID_PKCS7_DATA: - /* do nothing */ - break; default: - rv = SECFailure; + if (NSS_CMSType_IsWrapper(p7ecx->type)) { + rv = NSS_CMSGenericWrapperData_Encode_AfterData(p7ecx->type, p7ecx->content.genericData); + } else { + rv = SECFailure; + } break; } return rv; @@ -432,23 +413,23 @@ nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest, } /* Update the running digest. */ - if (len && cinfo->digcx != NULL) - NSS_CMSDigestContext_Update(cinfo->digcx, data, len); + if (len && cinfo->private && cinfo->private->digcx != NULL) + NSS_CMSDigestContext_Update(cinfo->private->digcx, data, len); /* Encrypt this chunk. */ - if (cinfo->ciphcx != NULL) { + if (cinfo->private && cinfo->private->ciphcx != NULL) { unsigned int inlen; /* length of data being encrypted */ unsigned int outlen; /* length of encrypted data */ unsigned int buflen; /* length available for encrypted data */ inlen = len; - buflen = NSS_CMSCipherContext_EncryptLength(cinfo->ciphcx, inlen, final); + buflen = NSS_CMSCipherContext_EncryptLength(cinfo->private->ciphcx, inlen, final); if (buflen == 0) { /* * No output is expected, but the input data may be buffered * so we still have to call Encrypt. */ - rv = NSS_CMSCipherContext_Encrypt(cinfo->ciphcx, NULL, NULL, 0, + rv = NSS_CMSCipherContext_Encrypt(cinfo->private->ciphcx, NULL, NULL, 0, data, inlen, final); if (final) { len = 0; @@ -465,7 +446,7 @@ nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest, if (buf == NULL) { rv = SECFailure; } else { - rv = NSS_CMSCipherContext_Encrypt(cinfo->ciphcx, buf, &outlen, buflen, + rv = NSS_CMSCipherContext_Encrypt(cinfo->private->ciphcx, buf, &outlen, buflen, data, inlen, final); data = buf; len = outlen; @@ -486,7 +467,7 @@ nss_cms_encoder_work_data(NSSCMSEncoderContext *p7ecx, SECItem *dest, done: - if (cinfo->ciphcx != NULL) { + if (cinfo->private && cinfo->private->ciphcx != NULL) { if (dest != NULL) { dest->data = buf; dest->len = len; @@ -532,6 +513,7 @@ NSS_CMSEncoder_Start(NSSCMSMessage *cmsg, NSSCMSEncoderContext *p7ecx; SECStatus rv; NSSCMSContentInfo *cinfo; + SECOidTag tag; NSS_CMSMessage_SetEncodingParams(cmsg, pwfn, pwfn_arg, decrypt_key_cb, decrypt_key_cb_arg, detached_digestalgs, detached_digests); @@ -551,7 +533,8 @@ NSS_CMSEncoder_Start(NSSCMSMessage *cmsg, cinfo = NSS_CMSMessage_GetContentInfo(cmsg); - switch (NSS_CMSContentInfo_GetContentTypeTag(cinfo)) { + tag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); + switch (tag) { case SEC_OID_PKCS7_SIGNED_DATA: rv = NSS_CMSSignedData_Encode_BeforeStart(cinfo->content.signedData); break; @@ -565,7 +548,12 @@ NSS_CMSEncoder_Start(NSSCMSMessage *cmsg, rv = NSS_CMSEncryptedData_Encode_BeforeStart(cinfo->content.encryptedData); break; default: - rv = SECFailure; + if (NSS_CMSType_IsWrapper(tag)) { + rv = NSS_CMSGenericWrapperData_Encode_AfterData(tag, + p7ecx->content.genericData); + } else { + rv = SECFailure; + } break; } if (rv != SECSuccess) { @@ -587,7 +575,8 @@ NSS_CMSEncoder_Start(NSSCMSMessage *cmsg, * Indicate that we are streaming. We will be streaming until we * get past the contents bytes. */ - SEC_ASN1EncoderSetStreaming(p7ecx->ecx); + if (!cinfo->private || !cinfo->private->dontStream) + SEC_ASN1EncoderSetStreaming(p7ecx->ecx); /* * The notify function will watch for the contents field. @@ -640,7 +629,7 @@ NSS_CMSEncoder_Update(NSSCMSEncoderContext *p7ecx, const char *data, unsigned lo } childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); - if (childtype != SEC_OID_PKCS7_DATA) + if (!NSS_CMSType_IsData(childtype)) return SECFailure; /* and we must not have preset data */ if (cinfo->content.data != NULL) @@ -746,7 +735,7 @@ NSS_CMSEncoder_Finish(NSSCMSEncoderContext *p7ecx) goto loser; } childtype = NSS_CMSContentInfo_GetContentTypeTag(cinfo); - if (childtype == SEC_OID_PKCS7_DATA && cinfo->content.data == NULL) { + if (NSS_CMSType_IsData(childtype) && cinfo->content.data == NULL) { SEC_ASN1EncoderClearTakeFromBuf(p7ecx->ecx); /* now that TakeFromBuf is off, this will kick this encoder to finish encoding */ rv = SEC_ASN1EncoderUpdate(p7ecx->ecx, NULL, 0); diff --git a/security/nss/lib/smime/cmsenvdata.c b/security/nss/lib/smime/cmsenvdata.c index c575a995e..73cafabcb 100644 --- a/security/nss/lib/smime/cmsenvdata.c +++ b/security/nss/lib/smime/cmsenvdata.c @@ -270,6 +270,7 @@ NSS_CMSEnvelopedData_Encode_BeforeData(NSSCMSEnvelopedData *envd) NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey; SECAlgorithmID *algid; + SECStatus rv; cinfo = &(envd->contentInfo); @@ -281,12 +282,16 @@ NSS_CMSEnvelopedData_Encode_BeforeData(NSSCMSEnvelopedData *envd) if (algid == NULL) return SECFailure; + rv = NSS_CMSContentInfo_Private_Init(cinfo); + if (rv != SECSuccess) { + return SECFailure; + } /* this may modify algid (with IVs generated in a token). * it is essential that algid is a pointer to the contentEncAlg data, not a * pointer to a copy! */ - cinfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(envd->cmsg->poolp, bulkkey, algid); + cinfo->private->ciphcx = NSS_CMSCipherContext_StartEncrypt(envd->cmsg->poolp, bulkkey, algid); PK11_FreeSymKey(bulkkey); - if (cinfo->ciphcx == NULL) + if (cinfo->private->ciphcx == NULL) return SECFailure; return SECSuccess; @@ -298,9 +303,9 @@ NSS_CMSEnvelopedData_Encode_BeforeData(NSSCMSEnvelopedData *envd) SECStatus NSS_CMSEnvelopedData_Encode_AfterData(NSSCMSEnvelopedData *envd) { - if (envd->contentInfo.ciphcx) { - NSS_CMSCipherContext_Destroy(envd->contentInfo.ciphcx); - envd->contentInfo.ciphcx = NULL; + if (envd->contentInfo.private && envd->contentInfo.private->ciphcx) { + NSS_CMSCipherContext_Destroy(envd->contentInfo.private->ciphcx); + envd->contentInfo.private->ciphcx = NULL; } /* nothing else to do after data */ @@ -380,8 +385,13 @@ NSS_CMSEnvelopedData_Decode_BeforeData(NSSCMSEnvelopedData *envd) bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo); - cinfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); - if (cinfo->ciphcx == NULL) + rv = NSS_CMSContentInfo_Private_Init(cinfo); + if (rv != SECSuccess) { + goto loser; + } + rv = SECFailure; + cinfo->private->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg); + if (cinfo->private->ciphcx == NULL) goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */ @@ -401,9 +411,9 @@ loser: SECStatus NSS_CMSEnvelopedData_Decode_AfterData(NSSCMSEnvelopedData *envd) { - if (envd && envd->contentInfo.ciphcx) { - NSS_CMSCipherContext_Destroy(envd->contentInfo.ciphcx); - envd->contentInfo.ciphcx = NULL; + if (envd && envd->contentInfo.private && envd->contentInfo.private->ciphcx) { + NSS_CMSCipherContext_Destroy(envd->contentInfo.private->ciphcx); + envd->contentInfo.private->ciphcx = NULL; } return SECSuccess; diff --git a/security/nss/lib/smime/cmslocal.h b/security/nss/lib/smime/cmslocal.h index 666eeb033..8aafec8ff 100644 --- a/security/nss/lib/smime/cmslocal.h +++ b/security/nss/lib/smime/cmslocal.h @@ -54,9 +54,25 @@ extern const SEC_ASN1Template NSSCMSContentInfoTemplate[]; +struct NSSCMSContentInfoPrivateStr { + NSSCMSCipherContext *ciphcx; + NSSCMSDigestContext *digcx; + PRBool dontStream; +}; + /************************************************************************/ SEC_BEGIN_PROTOS +/* + * private content Info stuff + */ + +/* initialize the private content info field. If this returns + * SECSuccess, the cinfo->private field is safe to dereference. + */ +SECStatus NSS_CMSContentInfo_Private_Init(NSSCMSContentInfo *cinfo); + + /*********************************************************************** * cmscipher.c - en/decryption routines ***********************************************************************/ @@ -340,7 +356,34 @@ NSS_CMSAttributeArray_SetAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, SECO extern SECStatus NSS_CMSSignedData_AddTempCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert); + /************************************************************************/ + +/* + * local functions to handle user defined S/MIME content types + */ + + +PRBool NSS_CMSType_IsWrapper(SECOidTag type); +PRBool NSS_CMSType_IsData(SECOidTag type); +size_t NSS_CMSType_GetContentSize(SECOidTag type); +const SEC_ASN1Template * NSS_CMSType_GetTemplate(SECOidTag type); + +void NSS_CMSGenericWrapperData_Destroy(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type, + NSSCMSGenericWrapperData *gd); +SECStatus NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type, + NSSCMSGenericWrapperData *gd); + SEC_END_PROTOS #endif /* _CMSLOCAL_H_ */ diff --git a/security/nss/lib/smime/cmsmessage.c b/security/nss/lib/smime/cmsmessage.c index 1b3d69c74..787a287bf 100644 --- a/security/nss/lib/smime/cmsmessage.c +++ b/security/nss/lib/smime/cmsmessage.c @@ -81,6 +81,7 @@ NSS_CMSMessage_Create(PLArenaPool *poolp) PORT_FreeArena(poolp, PR_FALSE); return NULL; } + NSS_CMSContentInfo_Private_Init(&(cmsg->contentInfo)); cmsg->poolp = poolp; cmsg->poolp_is_ours = poolp_is_ours; @@ -234,11 +235,12 @@ NSS_CMSMessage_ContainsCertsOrCrls(NSSCMSMessage *cmsg) /* descend into CMS message */ for (cinfo = &(cmsg->contentInfo); cinfo != NULL; cinfo = NSS_CMSContentInfo_GetChildContentInfo(cinfo)) { - if (NSS_CMSContentInfo_GetContentTypeTag(cinfo) != SEC_OID_PKCS7_SIGNED_DATA) + 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; } @@ -259,6 +261,7 @@ NSS_CMSMessage_IsEncrypted(NSSCMSMessage *cmsg) case SEC_OID_PKCS7_ENCRYPTED_DATA: return PR_TRUE; default: + /* callback here for generic wrappers? */ break; } } @@ -289,6 +292,7 @@ NSS_CMSMessage_IsSigned(NSSCMSMessage *cmsg) return PR_TRUE; break; default: + /* callback here for generic wrappers? */ break; } } diff --git a/security/nss/lib/smime/cmssigdata.c b/security/nss/lib/smime/cmssigdata.c index 0ba771d65..f396ec77f 100644 --- a/security/nss/lib/smime/cmssigdata.c +++ b/security/nss/lib/smime/cmssigdata.c @@ -217,17 +217,22 @@ loser: SECStatus NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd) { + SECStatus rv; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } + rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo); + if (rv != SECSuccess) { + return SECFailure; + } /* set up the digests */ if (sigd->digests && sigd->digests[0]) { - sigd->contentInfo.digcx = NULL; /* don't attempt to make new ones. */ + sigd->contentInfo.private->digcx = NULL; /* don't attempt to make new ones. */ } else if (sigd->digestAlgorithms != NULL) { - sigd->contentInfo.digcx = + sigd->contentInfo.private->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); - if (sigd->contentInfo.digcx == NULL) + if (sigd->contentInfo.private->digcx == NULL) return SECFailure; } return SECSuccess; @@ -267,11 +272,11 @@ NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd) cinfo = &(sigd->contentInfo); /* did we have digest calculation going on? */ - if (cinfo->digcx) { - rv = NSS_CMSDigestContext_FinishMultiple(cinfo->digcx, poolp, + if (cinfo->private && cinfo->private->digcx) { + rv = NSS_CMSDigestContext_FinishMultiple(cinfo->private->digcx, poolp, &(sigd->digests)); /* error has been set by NSS_CMSDigestContext_FinishMultiple */ - cinfo->digcx = NULL; + cinfo->private->digcx = NULL; if (rv != SECSuccess) goto loser; } @@ -392,15 +397,20 @@ loser: SECStatus NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd) { + SECStatus rv; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } + rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo); + if (rv != SECSuccess) { + return SECFailure; + } /* set up the digests */ if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) { /* if digests are already there, do nothing */ - sigd->contentInfo.digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); - if (sigd->contentInfo.digcx == NULL) + sigd->contentInfo.private->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); + if (sigd->contentInfo.private->digcx == NULL) return SECFailure; } return SECSuccess; @@ -421,11 +431,11 @@ NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd) } /* did we have digest calculation going on? */ - if (sigd->contentInfo.digcx) { - rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.digcx, + if (sigd->contentInfo.private && sigd->contentInfo.private->digcx) { + rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.private->digcx, sigd->cmsg->poolp, &(sigd->digests)); /* error set by NSS_CMSDigestContext_FinishMultiple */ - sigd->contentInfo.digcx = NULL; + sigd->contentInfo.private->digcx = NULL; } return rv; } diff --git a/security/nss/lib/smime/cmst.h b/security/nss/lib/smime/cmst.h index 82f24da14..f894dd122 100644 --- a/security/nss/lib/smime/cmst.h +++ b/security/nss/lib/smime/cmst.h @@ -98,6 +98,8 @@ typedef struct NSSCMSRecipientInfoStr NSSCMSRecipientInfo; typedef struct NSSCMSDigestedDataStr NSSCMSDigestedData; typedef struct NSSCMSEncryptedDataStr NSSCMSEncryptedData; +typedef struct NSSCMSGenericWrapperDataStr NSSCMSGenericWrapperData; + typedef struct NSSCMSSMIMEKEAParametersStr NSSCMSSMIMEKEAParameters; typedef struct NSSCMSAttributeStr NSSCMSAttribute; @@ -108,6 +110,13 @@ typedef struct NSSCMSEncoderContextStr NSSCMSEncoderContext; typedef struct NSSCMSCipherContextStr NSSCMSCipherContext; typedef struct NSSCMSDigestContextStr NSSCMSDigestContext; +typedef struct NSSCMSContentInfoPrivateStr NSSCMSContentInfoPrivate; + +typedef SECStatus (*NSSCMSGenericWrapperDataCallback) + (NSSCMSGenericWrapperData *); +typedef void (*NSSCMSGenericWrapperDataDestroy) + (NSSCMSGenericWrapperData *); + /* * Type of function passed to NSSCMSDecode or NSSCMSDecoderStart. * If specified, this is where the content bytes (only) will be "sent" @@ -142,6 +151,7 @@ union NSSCMSContentUnion { NSSCMSEncryptedData * encryptedData; NSSCMSEnvelopedData * envelopedData; NSSCMSSignedData * signedData; + NSSCMSGenericWrapperData * genericData; /* or anonymous pointer to something */ void * pointer; }; @@ -164,8 +174,8 @@ struct NSSCMSContentInfoStr { * (only used by creation code) */ SECOidTag contentEncAlgTag; /* oid tag of encryption algorithm * (only used by creation code) */ - NSSCMSCipherContext *ciphcx; /* context for en/decryption going on */ - NSSCMSDigestContext *digcx; /* context for digesting going on */ + NSSCMSContentInfoPrivate *private; /* place for NSS private info */ + void *reserved; /* keep binary compatibility */ }; /* ============================================================================= @@ -186,6 +196,18 @@ struct NSSCMSMessageStr { void * decrypt_key_cb_arg; }; +/* ============================================================================ + * GENERIC WRAPPER + * + * used for user defined types. + */ +struct NSSCMSGenericWrapperDataStr { + NSSCMSContentInfo contentInfo; + /* ---- local; not part of encoding ------ */ + NSSCMSMessage * cmsg; + /* wrapperspecific data starts here */ +}; + /* ============================================================================= * SIGNEDDATA */ diff --git a/security/nss/lib/smime/cmsutil.c b/security/nss/lib/smime/cmsutil.c index ddd87870a..b4839d3bf 100644 --- a/security/nss/lib/smime/cmsutil.c +++ b/security/nss/lib/smime/cmsutil.c @@ -243,8 +243,7 @@ NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type) template = NSSCMSDigestedDataTemplate; break; default: - case SEC_OID_PKCS7_DATA: - template = NULL; + template = NSS_CMSType_GetTemplate(type); break; } return template; @@ -269,8 +268,7 @@ NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type) size = sizeof(NSSCMSDigestedData); break; default: - case SEC_OID_PKCS7_DATA: - size = 0; + size = NSS_CMSType_GetContentSize(type); break; } return size; @@ -300,6 +298,9 @@ NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type) break; default: cinfo = NULL; + if (NSS_CMSType_IsWrapper(type)) { + cinfo = &(c.genericData->contentInfo); + } } return cinfo; } diff --git a/security/nss/lib/smime/manifest.mn b/security/nss/lib/smime/manifest.mn index a72b41377..1f5421f35 100644 --- a/security/nss/lib/smime/manifest.mn +++ b/security/nss/lib/smime/manifest.mn @@ -69,6 +69,7 @@ CSRCS = \ cmsreclist.c \ cmssigdata.c \ cmssiginfo.c \ + cmsudf.c \ cmsutil.c \ smimemessage.c \ smimeutil.c \ diff --git a/security/nss/lib/smime/smime.def b/security/nss/lib/smime/smime.def index 39ccc45bb..bddf03f4e 100644 --- a/security/nss/lib/smime/smime.def +++ b/security/nss/lib/smime/smime.def @@ -273,3 +273,11 @@ SEC_PKCS12AddCertOrChainAndKey; ;+ local: ;+ *; ;+}; +;+NSS_3.12.10 { # NSS 3.12.10 release +;+ global: +NSS_CMSType_RegisterContentType; +NSS_CMSContentInfo_SetDontStream; +NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs; +;+ local: +;+ *; +;+}; |