if (nss_cms_before_data(p7dcx) != SECSuccess) {
SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); /* stop all processing */
p7dcx->error = PORT_GetError();
+ PORT_SetError(0); // Clean the thread error since we've returned the error
}
}
if (after && dest == &(cinfo->rawContent)) {
/* we're right after of the data */
- if (nss_cms_after_data(p7dcx) != SECSuccess)
+ if (nss_cms_after_data(p7dcx) != SECSuccess) {
p7dcx->error = PORT_GetError();
+ PORT_SetError(0); // Clean the thread error since we've returned the error
+ }
/* we don't need to see the contents anymore */
SEC_ASN1DecoderClearFilterProc(p7dcx->dcx);
nss_cms_after_end(SecCmsDecoderRef p7dcx)
{
OSStatus rv;
- PLArenaPool *poolp;
-
- poolp = p7dcx->cmsg->poolp;
switch (p7dcx->type) {
case SEC_OID_PKCS7_SIGNED_DATA:
if (!p7dcx->content.pointer) // might be ExContent??
return;
-
+
cinfo = SecCmsContentGetContentInfo(p7dcx->content.pointer, p7dcx->type);
if (cinfo->ciphcx != NULL) {
- /*
- * we are decrypting.
- *
- * XXX If we get an error, we do not want to do the digest or callback,
- * but we want to keep decoding. Or maybe we want to stop decoding
- * altogether if there is a callback, because obviously we are not
- * sending the data back and they want to know that.
- */
-
- CSSM_SIZE outlen = 0; /* length of decrypted data */
- CSSM_SIZE buflen; /* length available for decrypted data */
-
- /* find out about the length of decrypted data */
- buflen = SecCmsCipherContextDecryptLength(cinfo->ciphcx, len, final);
-
- /*
- * it might happen that we did not provide enough data for a full
- * block (decryption unit), and that there is no output available
- */
-
- /* no output available, AND no input? */
- if (buflen == 0 && len == 0)
- goto loser; /* bail out */
-
- /*
- * have inner decoder: pass the data on (means inner content type is NOT data)
- * no inner decoder: we have DATA in here: either call callback or store
- */
- if (buflen != 0) {
- /* there will be some output - need to make room for it */
- /* allocate buffer from the heap */
- buf = (unsigned char *)PORT_Alloc(buflen);
- if (buf == NULL) {
- p7dcx->error = SEC_ERROR_NO_MEMORY;
- goto loser;
- }
- }
-
- /*
- * decrypt incoming data
- * buf can still be NULL here (and buflen == 0) here if we don't expect
- * any output (see above), but we still need to call SecCmsCipherContextDecrypt to
- * keep track of incoming data
- */
- rv = SecCmsCipherContextDecrypt(cinfo->ciphcx, buf, &outlen, buflen,
- data, len, final);
- if (rv != SECSuccess) {
- p7dcx->error = PORT_GetError();
- goto loser;
- }
-
- PORT_Assert (final || outlen == buflen);
-
- /* swap decrypted data in */
- data = buf;
- len = outlen;
+ /*
+ * we are decrypting.
+ *
+ * XXX If we get an error, we do not want to do the digest or callback,
+ * but we want to keep decoding. Or maybe we want to stop decoding
+ * altogether if there is a callback, because obviously we are not
+ * sending the data back and they want to know that.
+ */
+
+ CSSM_SIZE outlen = 0; /* length of decrypted data */
+ CSSM_SIZE buflen; /* length available for decrypted data */
+
+ /* find out about the length of decrypted data */
+ buflen = SecCmsCipherContextDecryptLength(cinfo->ciphcx, len, final);
+
+ /*
+ * it might happen that we did not provide enough data for a full
+ * block (decryption unit), and that there is no output available
+ */
+
+ /* no output available, AND no input? */
+ if (buflen == 0 && len == 0)
+ goto loser; /* bail out */
+
+ /*
+ * have inner decoder: pass the data on (means inner content type is NOT data)
+ * no inner decoder: we have DATA in here: either call callback or store
+ */
+ if (buflen != 0) {
+ /* there will be some output - need to make room for it */
+ /* allocate buffer from the heap */
+ buf = (unsigned char *)PORT_Alloc(buflen);
+ if (buf == NULL) {
+ p7dcx->error = SEC_ERROR_NO_MEMORY;
+ goto loser;
+ }
+ }
+
+ /*
+ * decrypt incoming data
+ * buf can still be NULL here (and buflen == 0) here if we don't expect
+ * any output (see above), but we still need to call SecCmsCipherContextDecrypt to
+ * keep track of incoming data
+ */
+ rv = SecCmsCipherContextDecrypt(cinfo->ciphcx, buf, &outlen, buflen,
+ data, len, final);
+ if (rv != SECSuccess) {
+ p7dcx->error = PORT_GetError();
+ PORT_SetError(0); // Clean the thread error since we've returned the error
+ goto loser;
+ }
+
+ PORT_Assert (final || outlen == buflen);
+
+ /* swap decrypted data in */
+ data = buf;
+ len = outlen;
}
if (len == 0)
- goto done; /* nothing more to do */
+ goto done; /* nothing more to do */
/*
* Update the running digests with plaintext bytes (if we need to).
*/
if (cinfo->digcx)
- SecCmsDigestContextUpdate(cinfo->digcx, data, len);
+ SecCmsDigestContextUpdate(cinfo->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 decoder */
/* pass the content back to our caller or */
/* feed our freshly decrypted and decoded data into child decoder */
if (p7dcx->cb != NULL) {
- (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);
+ (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len);
}
#if 1
else
#endif
- switch(SecCmsContentInfoGetContentTypeTag(cinfo)) {
- default:
- break;
- case SEC_OID_PKCS7_DATA:
- case SEC_OID_OTHER:
- /* store it in "inner" data item as well */
- /* find the DATA item in the encapsulated cinfo and store it there */
- storage = cinfo->content.data;
-
- offset = storage->Length;
-
- /* check for potential overflow */
- if (len >= (size_t)(INT_MAX - storage->Length)) {
- p7dcx->error = SEC_ERROR_NO_MEMORY;
- goto loser;
- }
-
- if (storage->Length == 0) {
- dest = (unsigned char *)PORT_ArenaAlloc(p7dcx->cmsg->poolp, len);
- } else {
- dest = (unsigned char *)PORT_ArenaGrow(p7dcx->cmsg->poolp,
- storage->Data,
- storage->Length,
- storage->Length + len);
- }
- if (dest == NULL) {
- p7dcx->error = SEC_ERROR_NO_MEMORY;
- goto loser;
- }
-
- storage->Data = dest;
- storage->Length += len;
-
- /* copy it in */
- PORT_Memcpy(storage->Data + offset, data, len);
- }
+ switch(SecCmsContentInfoGetContentTypeTag(cinfo)) {
+ default:
+ break;
+ case SEC_OID_PKCS7_DATA:
+ case SEC_OID_OTHER:
+ /* store it in "inner" data item as well */
+ /* find the DATA item in the encapsulated cinfo and store it there */
+ storage = cinfo->content.data;
+
+ offset = storage->Length;
+
+ /* check for potential overflow */
+ if (len >= (size_t)(INT_MAX - storage->Length)) {
+ p7dcx->error = SEC_ERROR_NO_MEMORY;
+ goto loser;
+ }
+
+ if (storage->Length == 0) {
+ dest = (unsigned char *)PORT_ArenaAlloc(p7dcx->cmsg->poolp, len);
+ } else {
+ dest = (unsigned char *)PORT_ArenaGrow(p7dcx->cmsg->poolp,
+ storage->Data,
+ storage->Length,
+ storage->Length + len);
+ }
+ if (dest == NULL) {
+ p7dcx->error = SEC_ERROR_NO_MEMORY;
+ goto loser;
+ }
+
+ storage->Data = dest;
+ storage->Length += len;
+
+ /* copy it in */
+ if (data != NULL) {
+ PORT_Memcpy(storage->Data + offset, data, len);
+ }
+ }
done:
loser:
if (buf)
- PORT_Free (buf);
+ PORT_Free (buf);
}
/*
SecCmsMessageRef cmsg;
OSStatus result;
+ /* Clear the thread error to clean up dirty threads */
+ PORT_SetError(0);
+
cmsg = SecCmsMessageCreate(pool);
if (cmsg == NULL)
goto loser;
loser:
result = PORT_GetError();
+ PORT_SetError(0); // Clean the thread error since we've returned the error
return result;
}
OSStatus
SecCmsDecoderUpdate(SecCmsDecoderRef p7dcx, const void *buf, CFIndex len)
{
+ if (!p7dcx) {
+ return errSecParam;
+ }
+
if (p7dcx->dcx != NULL && p7dcx->error == 0) { /* if error is set already, don't bother */
if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) {
p7dcx->error = PORT_GetError();
(void) SEC_ASN1DecoderFinish (p7dcx->dcx);
p7dcx->dcx = NULL;
}
- PORT_SetError (p7dcx->error);
+ PORT_SetError (0); // Clean the thread error since we've returned the error
return p7dcx->error;
}
void
SecCmsDecoderDestroy(SecCmsDecoderRef p7dcx)
{
- /* XXXX what about inner decoders? running digests? decryption? */
- /* XXXX there's a leak here! */
- SecCmsMessageDestroy(p7dcx->cmsg);
- if (p7dcx->dcx)
+ /* SecCmsMessageDestroy frees inner decoders and digests. */
+ if (p7dcx->cmsg) {
+ SecCmsMessageDestroy(p7dcx->cmsg);
+ }
+ if (p7dcx->dcx) {
(void)SEC_ASN1DecoderFinish(p7dcx->dcx);
+ }
+ /* Clear out references */
+ p7dcx->cmsg = NULL;
+ p7dcx->dcx = NULL;
+ p7dcx->childp7dcx = NULL;
PORT_Free(p7dcx);
}
if (p7dcx->dcx == NULL || SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess ||
nss_cms_after_end(p7dcx) != SECSuccess)
{
- SecCmsMessageDestroy(cmsg); /* needs to get rid of pool if it's ours */
+ if (p7dcx->cmsg) {
+ SecCmsMessageDestroy(cmsg); /* needs to get rid of pool if it's ours */
+ }
result = PORT_GetError();
goto loser;
}
result = noErr;
loser:
+ /* Clear out references */
+ p7dcx->cmsg = NULL;
+ p7dcx->dcx = NULL;
+ p7dcx->childp7dcx = NULL;
PORT_Free(p7dcx);
+ PORT_SetError(0); // Clean the thread error since we've returned the error
return result;
}