diff options
Diffstat (limited to 'nss/lib/pkcs7/p7decode.c')
-rw-r--r-- | nss/lib/pkcs7/p7decode.c | 2119 |
1 files changed, 1052 insertions, 1067 deletions
diff --git a/nss/lib/pkcs7/p7decode.c b/nss/lib/pkcs7/p7decode.c index 7a52d82..658c61e 100644 --- a/nss/lib/pkcs7/p7decode.c +++ b/nss/lib/pkcs7/p7decode.c @@ -9,11 +9,11 @@ #include "p7local.h" #include "cert.h" - /* XXX do not want to have to include */ -#include "certdb.h" /* certdb.h -- the trust stuff needed by */ - /* the add certificate code needs to get */ - /* rewritten/abstracted and then this */ - /* include should be removed! */ +/* XXX do not want to have to include */ +#include "certdb.h" /* certdb.h -- the trust stuff needed by */ + /* the add certificate code needs to get */ + /* rewritten/abstracted and then this */ + /* include should be removed! */ /*#include "cdbhdl.h" */ #include "cryptohi.h" #include "key.h" @@ -23,7 +23,7 @@ #include "pk11func.h" #include "prtime.h" #include "secerr.h" -#include "sechash.h" /* for HASH_GetHashObject() */ +#include "sechash.h" /* for HASH_GetHashObject() */ #include "secder.h" #include "secpkcs5.h" @@ -60,10 +60,10 @@ struct SEC_PKCS7DecoderContextStr { * corresponding to the given worker. */ static void -sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx, - struct sec_pkcs7_decoder_worker *worker, - const unsigned char *data, unsigned long len, - PRBool final) +sec_pkcs7_decoder_work_data(SEC_PKCS7DecoderContext *p7dcx, + struct sec_pkcs7_decoder_worker *worker, + const unsigned char *data, unsigned long len, + PRBool final) { unsigned char *buf = NULL; SECStatus rv; @@ -76,7 +76,7 @@ sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx, * proves they do it right. But it could find a bug in future * modifications/development, that is why it is here.) */ - PORT_Assert ((data != NULL && len) || final); + PORT_Assert((data != NULL && len) || final); /* * Decrypt this chunk. @@ -87,100 +87,99 @@ sec_pkcs7_decoder_work_data (SEC_PKCS7DecoderContext *p7dcx, * sending the data back and they want to know that. */ if (worker->decryptobj != NULL) { - /* XXX the following lengths should all be longs? */ - unsigned int inlen; /* length of data being decrypted */ - unsigned int outlen; /* length of decrypted data */ - unsigned int buflen; /* length available for decrypted data */ - SECItem *plain; - - inlen = len; - buflen = sec_PKCS7DecryptLength (worker->decryptobj, inlen, final); - if (buflen == 0) { - if (inlen == 0) /* no input and no output */ - return; - /* - * No output is expected, but the input data may be buffered - * so we still have to call Decrypt. - */ - rv = sec_PKCS7Decrypt (worker->decryptobj, NULL, NULL, 0, - data, inlen, final); - if (rv != SECSuccess) { - p7dcx->error = PORT_GetError(); - return; /* XXX indicate error? */ - } - return; - } - - if (p7dcx->cb != NULL) { - buf = (unsigned char *) PORT_Alloc (buflen); - plain = NULL; - } else { - unsigned long oldlen; - - /* - * XXX This assumes one level of content only. - * See comment above about nested content types. - * XXX Also, it should work for signedAndEnvelopedData, too! - */ - plain = &(p7dcx->cinfo-> - content.envelopedData->encContentInfo.plainContent); - - oldlen = plain->len; - if (oldlen == 0) { - buf = (unsigned char*)PORT_ArenaAlloc (p7dcx->cinfo->poolp, - buflen); - } else { - buf = (unsigned char*)PORT_ArenaGrow (p7dcx->cinfo->poolp, - plain->data, - oldlen, oldlen + buflen); - if (buf != NULL) - buf += oldlen; - } - plain->data = buf; - } - if (buf == NULL) { - p7dcx->error = SEC_ERROR_NO_MEMORY; - return; /* XXX indicate error? */ - } - rv = sec_PKCS7Decrypt (worker->decryptobj, buf, &outlen, buflen, - data, inlen, final); - if (rv != SECSuccess) { - p7dcx->error = PORT_GetError(); - return; /* XXX indicate error? */ - } - if (plain != NULL) { - PORT_Assert (final || outlen == buflen); - plain->len += outlen; - } - data = buf; - len = outlen; + /* XXX the following lengths should all be longs? */ + unsigned int inlen; /* length of data being decrypted */ + unsigned int outlen; /* length of decrypted data */ + unsigned int buflen; /* length available for decrypted data */ + SECItem *plain; + + inlen = len; + buflen = sec_PKCS7DecryptLength(worker->decryptobj, inlen, final); + if (buflen == 0) { + if (inlen == 0) /* no input and no output */ + return; + /* + * No output is expected, but the input data may be buffered + * so we still have to call Decrypt. + */ + rv = sec_PKCS7Decrypt(worker->decryptobj, NULL, NULL, 0, + data, inlen, final); + if (rv != SECSuccess) { + p7dcx->error = PORT_GetError(); + return; /* XXX indicate error? */ + } + return; + } + + if (p7dcx->cb != NULL) { + buf = (unsigned char *)PORT_Alloc(buflen); + plain = NULL; + } else { + unsigned long oldlen; + + /* + * XXX This assumes one level of content only. + * See comment above about nested content types. + * XXX Also, it should work for signedAndEnvelopedData, too! + */ + plain = &(p7dcx->cinfo->content.envelopedData->encContentInfo.plainContent); + + oldlen = plain->len; + if (oldlen == 0) { + buf = (unsigned char *)PORT_ArenaAlloc(p7dcx->cinfo->poolp, + buflen); + } else { + buf = (unsigned char *)PORT_ArenaGrow(p7dcx->cinfo->poolp, + plain->data, + oldlen, oldlen + buflen); + if (buf != NULL) + buf += oldlen; + } + plain->data = buf; + } + if (buf == NULL) { + p7dcx->error = SEC_ERROR_NO_MEMORY; + return; /* XXX indicate error? */ + } + rv = sec_PKCS7Decrypt(worker->decryptobj, buf, &outlen, buflen, + data, inlen, final); + if (rv != SECSuccess) { + p7dcx->error = PORT_GetError(); + return; /* XXX indicate error? */ + } + if (plain != NULL) { + PORT_Assert(final || outlen == buflen); + plain->len += outlen; + } + data = buf; + len = outlen; } /* * Update the running digests. */ if (len) { - for (i = 0; i < worker->digcnt; i++) { - (* worker->digobjs[i]->update) (worker->digcxs[i], data, len); - } + for (i = 0; i < worker->digcnt; i++) { + (*worker->digobjs[i]->update)(worker->digcxs[i], data, len); + } } /* * Pass back the contents bytes, and free the temporary buffer. */ if (p7dcx->cb != NULL) { - if (len) - (* p7dcx->cb) (p7dcx->cb_arg, (const char *)data, len); - if (worker->decryptobj != NULL) { - PORT_Assert (buf != NULL); - PORT_Free (buf); - } + if (len) + (*p7dcx->cb)(p7dcx->cb_arg, (const char *)data, len); + if (worker->decryptobj != NULL) { + PORT_Assert(buf != NULL); + PORT_Free(buf); + } } } static void -sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, - int depth, SEC_ASN1EncodingPart data_kind) +sec_pkcs7_decoder_filter(void *arg, const char *data, unsigned long len, + int depth, SEC_ASN1EncodingPart data_kind) { SEC_PKCS7DecoderContext *p7dcx; struct sec_pkcs7_decoder_worker *worker; @@ -193,17 +192,17 @@ sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, * smarter based on depth and data_kind. */ if (data_kind != SEC_ASN1_Contents) - return; + return; /* * The ASN.1 decoder should not even call us with a length of 0. * Just being paranoid. */ - PORT_Assert (len); + PORT_Assert(len); if (len == 0) - return; + return; - p7dcx = (SEC_PKCS7DecoderContext*)arg; + p7dcx = (SEC_PKCS7DecoderContext *)arg; /* * Handling nested contents would mean that there is a chain @@ -214,11 +213,10 @@ sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, worker->saw_contents = PR_TRUE; - sec_pkcs7_decoder_work_data (p7dcx, worker, - (const unsigned char *) data, len, PR_FALSE); + sec_pkcs7_decoder_work_data(p7dcx, worker, + (const unsigned char *)data, len, PR_FALSE); } - /* * Create digest contexts for each algorithm in "digestalgs". * No algorithms is not an error, we just do not do anything. @@ -227,35 +225,35 @@ sec_pkcs7_decoder_filter (void *arg, const char *data, unsigned long len, * should just give up altogether. */ static SECStatus -sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth, - SECAlgorithmID **digestalgs) +sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth, + SECAlgorithmID **digestalgs) { int i, digcnt; if (digestalgs == NULL) - return SECSuccess; + return SECSuccess; /* * Count the algorithms. */ digcnt = 0; while (digestalgs[digcnt] != NULL) - digcnt++; + digcnt++; /* * No algorithms means no work to do. * Just act as if there were no algorithms specified. */ if (digcnt == 0) - return SECSuccess; + return SECSuccess; - p7dcx->worker.digcxs = (void**)PORT_ArenaAlloc (p7dcx->tmp_poolp, - digcnt * sizeof (void *)); - p7dcx->worker.digobjs = (const SECHashObject**)PORT_ArenaAlloc (p7dcx->tmp_poolp, - digcnt * sizeof (SECHashObject *)); + p7dcx->worker.digcxs = (void **)PORT_ArenaAlloc(p7dcx->tmp_poolp, + digcnt * sizeof(void *)); + p7dcx->worker.digobjs = (const SECHashObject **)PORT_ArenaAlloc(p7dcx->tmp_poolp, + digcnt * sizeof(SECHashObject *)); if (p7dcx->worker.digcxs == NULL || p7dcx->worker.digobjs == NULL) { - p7dcx->error = SEC_ERROR_NO_MEMORY; - return SECFailure; + p7dcx->error = SEC_ERROR_NO_MEMORY; + return SECFailure; } p7dcx->worker.depth = depth; @@ -265,49 +263,48 @@ sec_pkcs7_decoder_start_digests (SEC_PKCS7DecoderContext *p7dcx, int depth, * Create a digest context for each algorithm. */ for (i = 0; i < digcnt; i++) { - SECAlgorithmID * algid = digestalgs[i]; - SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); - const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); - void *digcx; - - /* - * Skip any algorithm we do not even recognize; obviously, - * this could be a problem, but if it is critical then the - * result will just be that the signature does not verify. - * We do not necessarily want to error out here, because - * the particular algorithm may not actually be important, - * but we cannot know that until later. - */ - if (digobj == NULL) { - p7dcx->worker.digcnt--; - continue; - } - - digcx = (* digobj->create)(); - if (digcx != NULL) { - (* digobj->begin) (digcx); - p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj; - p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx; - p7dcx->worker.digcnt++; - } + SECAlgorithmID *algid = digestalgs[i]; + SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm)); + const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag); + void *digcx; + + /* + * Skip any algorithm we do not even recognize; obviously, + * this could be a problem, but if it is critical then the + * result will just be that the signature does not verify. + * We do not necessarily want to error out here, because + * the particular algorithm may not actually be important, + * but we cannot know that until later. + */ + if (digobj == NULL) { + p7dcx->worker.digcnt--; + continue; + } + + digcx = (*digobj->create)(); + if (digcx != NULL) { + (*digobj->begin)(digcx); + p7dcx->worker.digobjs[p7dcx->worker.digcnt] = digobj; + p7dcx->worker.digcxs[p7dcx->worker.digcnt] = digcx; + p7dcx->worker.digcnt++; + } } if (p7dcx->worker.digcnt != 0) - SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, - sec_pkcs7_decoder_filter, - p7dcx, - (PRBool)(p7dcx->cb != NULL)); + SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, + sec_pkcs7_decoder_filter, + p7dcx, + (PRBool)(p7dcx->cb != NULL)); return SECSuccess; } - /* * Close out all of the digest contexts, storing the results in "digestsp". */ static SECStatus -sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, - PLArenaPool *poolp, - SECItem ***digestsp) +sec_pkcs7_decoder_finish_digests(SEC_PKCS7DecoderContext *p7dcx, + PLArenaPool *poolp, + SECItem ***digestsp) { struct sec_pkcs7_decoder_worker *worker; const SECHashObject *digobj; @@ -327,14 +324,14 @@ sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, * If no digests, then we have nothing to do. */ if (worker->digcnt == 0) - return SECSuccess; + return SECSuccess; /* * No matter what happens after this, we want to stop filtering. * XXX If we handle nested contents, we only want to stop filtering * if we are finishing off the *last* worker. */ - SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); /* * If we ended up with no contents, just destroy each @@ -342,50 +339,50 @@ sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, * confusing, because their presence would imply some content * was digested. */ - if (! worker->saw_contents) { - for (i = 0; i < worker->digcnt; i++) { - digcx = worker->digcxs[i]; - digobj = worker->digobjs[i]; - (* digobj->destroy) (digcx, PR_TRUE); - } - return SECSuccess; + if (!worker->saw_contents) { + for (i = 0; i < worker->digcnt; i++) { + digcx = worker->digcxs[i]; + digobj = worker->digobjs[i]; + (*digobj->destroy)(digcx, PR_TRUE); + } + return SECSuccess; } - mark = PORT_ArenaMark (poolp); + mark = PORT_ArenaMark(poolp); /* * Close out each digest context, saving digest away. */ - digests = - (SECItem**)PORT_ArenaAlloc (poolp,(worker->digcnt+1)*sizeof(SECItem *)); - digest = (SECItem*)PORT_ArenaAlloc (poolp, worker->digcnt*sizeof(SECItem)); + digests = + (SECItem **)PORT_ArenaAlloc(poolp, (worker->digcnt + 1) * sizeof(SECItem *)); + digest = (SECItem *)PORT_ArenaAlloc(poolp, worker->digcnt * sizeof(SECItem)); if (digests == NULL || digest == NULL) { - p7dcx->error = PORT_GetError(); - PORT_ArenaRelease (poolp, mark); - return SECFailure; + p7dcx->error = PORT_GetError(); + PORT_ArenaRelease(poolp, mark); + return SECFailure; } for (i = 0; i < worker->digcnt; i++, digest++) { - digcx = worker->digcxs[i]; - digobj = worker->digobjs[i]; + digcx = worker->digcxs[i]; + digobj = worker->digobjs[i]; - digest->data = (unsigned char*)PORT_ArenaAlloc (poolp, digobj->length); - if (digest->data == NULL) { - p7dcx->error = PORT_GetError(); - PORT_ArenaRelease (poolp, mark); - return SECFailure; - } + digest->data = (unsigned char *)PORT_ArenaAlloc(poolp, digobj->length); + if (digest->data == NULL) { + p7dcx->error = PORT_GetError(); + PORT_ArenaRelease(poolp, mark); + return SECFailure; + } - digest->len = digobj->length; - (* digobj->end) (digcx, digest->data, &(digest->len), digest->len); - (* digobj->destroy) (digcx, PR_TRUE); + digest->len = digobj->length; + (*digobj->end)(digcx, digest->data, &(digest->len), digest->len); + (*digobj->destroy)(digcx, PR_TRUE); - digests[i] = digest; + digests[i] = digest; } digests[i] = NULL; *digestsp = digests; - PORT_ArenaUnmark (poolp, mark); + PORT_ArenaUnmark(poolp, mark); return SECSuccess; } @@ -395,9 +392,9 @@ sec_pkcs7_decoder_finish_digests (SEC_PKCS7DecoderContext *p7dcx, */ static PK11SymKey * -sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx, - SEC_PKCS7RecipientInfo **recipientinfos, - SEC_PKCS7EncryptedContentInfo *enccinfo) +sec_pkcs7_decoder_get_recipient_key(SEC_PKCS7DecoderContext *p7dcx, + SEC_PKCS7RecipientInfo **recipientinfos, + SEC_PKCS7EncryptedContentInfo *enccinfo) { SEC_PKCS7RecipientInfo *ri; CERTCertificate *cert = NULL; @@ -407,53 +404,53 @@ sec_pkcs7_decoder_get_recipient_key (SEC_PKCS7DecoderContext *p7dcx, PK11SlotInfo *slot = NULL; if (recipientinfos == NULL || recipientinfos[0] == NULL) { - p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; - goto no_key_found; + p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; + goto no_key_found; } - cert = PK11_FindCertAndKeyByRecipientList(&slot,recipientinfos,&ri, - &privkey, p7dcx->pwfn_arg); + cert = PK11_FindCertAndKeyByRecipientList(&slot, recipientinfos, &ri, + &privkey, p7dcx->pwfn_arg); if (cert == NULL) { - p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; - goto no_key_found; + p7dcx->error = SEC_ERROR_NOT_A_RECIPIENT; + goto no_key_found; } - ri->cert = cert; /* so we can find it later */ + ri->cert = cert; /* so we can find it later */ PORT_Assert(privkey != NULL); keyalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); - encalgtag = SECOID_GetAlgorithmTag (&(ri->keyEncAlg)); + encalgtag = SECOID_GetAlgorithmTag(&(ri->keyEncAlg)); if (keyalgtag != encalgtag) { - p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH; - goto no_key_found; + p7dcx->error = SEC_ERROR_PKCS7_KEYALG_MISMATCH; + goto no_key_found; } - bulkalgtag = SECOID_GetAlgorithmTag (&(enccinfo->contentEncAlg)); + bulkalgtag = SECOID_GetAlgorithmTag(&(enccinfo->contentEncAlg)); switch (encalgtag) { - case SEC_OID_PKCS1_RSA_ENCRYPTION: - bulkkey = PK11_PubUnwrapSymKey (privkey, &ri->encKey, - PK11_AlgtagToMechanism (bulkalgtag), - CKA_DECRYPT, 0); - if (bulkkey == NULL) { - p7dcx->error = PORT_GetError(); - PORT_SetError(0); - goto no_key_found; - } - break; - default: - p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG; - break; + case SEC_OID_PKCS1_RSA_ENCRYPTION: + bulkkey = PK11_PubUnwrapSymKey(privkey, &ri->encKey, + PK11_AlgtagToMechanism(bulkalgtag), + CKA_DECRYPT, 0); + if (bulkkey == NULL) { + p7dcx->error = PORT_GetError(); + PORT_SetError(0); + goto no_key_found; + } + break; + default: + p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG; + break; } no_key_found: if (privkey != NULL) - SECKEY_DestroyPrivateKey (privkey); + SECKEY_DestroyPrivateKey(privkey); if (slot != NULL) - PK11_FreeSlot(slot); + PK11_FreeSlot(slot); return bulkkey; } - + /* * XXX The following comment is old -- the function used to only handle * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData @@ -469,16 +466,16 @@ no_key_found: * The encryption key and related information can be found in "enccinfo". */ static SECStatus -sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth, - SEC_PKCS7RecipientInfo **recipientinfos, - SEC_PKCS7EncryptedContentInfo *enccinfo, - PK11SymKey **copy_key_for_signature) +sec_pkcs7_decoder_start_decrypt(SEC_PKCS7DecoderContext *p7dcx, int depth, + SEC_PKCS7RecipientInfo **recipientinfos, + SEC_PKCS7EncryptedContentInfo *enccinfo, + PK11SymKey **copy_key_for_signature) { PK11SymKey *bulkkey = NULL; sec_PKCS7CipherObject *decryptobj; /* - * If a callback is supplied to retrieve the encryption key, + * If a callback is supplied to retrieve the encryption key, * for instance, for Encrypted Content infos, then retrieve * the bulkkey from the callback. Otherwise, assume that * we are processing Enveloped or SignedAndEnveloped data @@ -487,41 +484,41 @@ sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth, * XXX Put an assert here? */ if (SEC_PKCS7ContentType(p7dcx->cinfo) == SEC_OID_PKCS7_ENCRYPTED_DATA) { - if (p7dcx->dkcb != NULL) { - bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, - &(enccinfo->contentEncAlg)); - } - enccinfo->keysize = 0; + if (p7dcx->dkcb != NULL) { + bulkkey = (*p7dcx->dkcb)(p7dcx->dkcb_arg, + &(enccinfo->contentEncAlg)); + } + enccinfo->keysize = 0; } else { - bulkkey = sec_pkcs7_decoder_get_recipient_key (p7dcx, recipientinfos, - enccinfo); - if (bulkkey == NULL) goto no_decryption; - enccinfo->keysize = PK11_GetKeyStrength(bulkkey, - &(enccinfo->contentEncAlg)); - + bulkkey = sec_pkcs7_decoder_get_recipient_key(p7dcx, recipientinfos, + enccinfo); + if (bulkkey == NULL) + goto no_decryption; + enccinfo->keysize = PK11_GetKeyStrength(bulkkey, + &(enccinfo->contentEncAlg)); } /* * XXX I think following should set error in p7dcx and clear set error * (as used to be done here, or as is done in get_receipient_key above. */ - if(bulkkey == NULL) { - goto no_decryption; + if (bulkkey == NULL) { + goto no_decryption; } - - /* + + /* * We want to make sure decryption is allowed. This is done via * a callback specified in SEC_PKCS7DecoderStart(). */ if (p7dcx->decrypt_allowed_cb) { - if ((*p7dcx->decrypt_allowed_cb) (&(enccinfo->contentEncAlg), - bulkkey) == PR_FALSE) { - p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; - goto no_decryption; - } + if ((*p7dcx->decrypt_allowed_cb)(&(enccinfo->contentEncAlg), + bulkkey) == PR_FALSE) { + p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; + goto no_decryption; + } } else { - p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; - goto no_decryption; + p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED; + goto no_decryption; } /* @@ -531,31 +528,31 @@ sec_pkcs7_decoder_start_decrypt (SEC_PKCS7DecoderContext *p7dcx, int depth, * RSA operation), copy it for later signature verification to use. */ if (copy_key_for_signature != NULL) - *copy_key_for_signature = PK11_ReferenceSymKey (bulkkey); + *copy_key_for_signature = PK11_ReferenceSymKey(bulkkey); /* * Now we have the bulk encryption key (in bulkkey) and the * the algorithm (in enccinfo->contentEncAlg). Using those, * create a decryption context. */ - decryptobj = sec_PKCS7CreateDecryptObject (bulkkey, - &(enccinfo->contentEncAlg)); + decryptobj = sec_PKCS7CreateDecryptObject(bulkkey, + &(enccinfo->contentEncAlg)); /* * We are done with (this) bulkkey now. */ - PK11_FreeSymKey (bulkkey); + PK11_FreeSymKey(bulkkey); if (decryptobj == NULL) { - p7dcx->error = PORT_GetError(); - PORT_SetError(0); - goto no_decryption; + p7dcx->error = PORT_GetError(); + PORT_SetError(0); + goto no_decryption; } - SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, - sec_pkcs7_decoder_filter, - p7dcx, - (PRBool)(p7dcx->cb != NULL)); + SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, + sec_pkcs7_decoder_filter, + p7dcx, + (PRBool)(p7dcx->cb != NULL)); p7dcx->worker.depth = depth; p7dcx->worker.decryptobj = decryptobj; @@ -575,16 +572,15 @@ no_decryption: * maybe it is not important that the decryption failed. */ if (p7dcx->cb != NULL) - return SECFailure; + return SECFailure; else - return SECSuccess; /* Let the decoding continue. */ + return SECSuccess; /* Let the decoding continue. */ } - static SECStatus -sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx, - PLArenaPool *poolp, - SEC_PKCS7EncryptedContentInfo *enccinfo) +sec_pkcs7_decoder_finish_decrypt(SEC_PKCS7DecoderContext *p7dcx, + PLArenaPool *poolp, + SEC_PKCS7EncryptedContentInfo *enccinfo) { struct sec_pkcs7_decoder_worker *worker; @@ -599,32 +595,31 @@ sec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx, * If no decryption context, then we have nothing to do. */ if (worker->decryptobj == NULL) - return SECSuccess; + return SECSuccess; /* * No matter what happens after this, we want to stop filtering. * XXX If we handle nested contents, we only want to stop filtering * if we are finishing off the *last* worker. */ - SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); /* * Handle the last block. */ - sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE); + sec_pkcs7_decoder_work_data(p7dcx, worker, NULL, 0, PR_TRUE); /* * All done, destroy it. */ - sec_PKCS7DestroyDecryptObject (worker->decryptobj); + sec_PKCS7DestroyDecryptObject(worker->decryptobj); worker->decryptobj = NULL; return SECSuccess; } - static void -sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth) +sec_pkcs7_decoder_notify(void *arg, PRBool before, void *dest, int depth) { SEC_PKCS7DecoderContext *p7dcx; SEC_PKCS7ContentInfo *cinfo; @@ -643,331 +638,342 @@ sec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth) * causes a warning on the mac; to avoid that, we do it the long way.) */ if (before) - after = PR_FALSE; + after = PR_FALSE; else - after = PR_TRUE; + after = PR_TRUE; + + p7dcx = (SEC_PKCS7DecoderContext *)arg; + if (!p7dcx) { + return; + } - p7dcx = (SEC_PKCS7DecoderContext*)arg; cinfo = p7dcx->cinfo; + if (!cinfo) { + return; + } + if (cinfo->contentTypeTag == NULL) { - if (after && dest == &(cinfo->contentType)) - cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); - return; + if (after && dest == &(cinfo->contentType)) + cinfo->contentTypeTag = SECOID_FindOID(&(cinfo->contentType)); + return; } switch (cinfo->contentTypeTag->offset) { - case SEC_OID_PKCS7_SIGNED_DATA: - sigd = cinfo->content.signedData; - if (sigd == NULL) - break; - - if (sigd->contentInfo.contentTypeTag == NULL) { - if (after && dest == &(sigd->contentInfo.contentType)) - sigd->contentInfo.contentTypeTag = - SECOID_FindOID(&(sigd->contentInfo.contentType)); - break; - } - - /* - * We only set up a filtering digest if the content is - * plain DATA; anything else needs more work because a - * second pass is required to produce a DER encoding from - * an input that can be BER encoded. (This is a requirement - * of PKCS7 that is unfortunate, but there you have it.) - * - * XXX Also, since we stop here if this is not DATA, the - * inner content is not getting processed at all. Someday - * we may want to fix that. - */ - if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) { - /* XXX Set an error in p7dcx->error */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - break; - } - - /* - * Just before the content, we want to set up a digest context - * for each digest algorithm listed, and start a filter which - * will run all of the contents bytes through that digest. - */ - if (before && dest == &(sigd->contentInfo.content)) { - rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, - sigd->digestAlgorithms); - if (rv != SECSuccess) - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - - break; - } - - /* - * XXX To handle nested types, here is where we would want - * to check for inner boundaries that need handling. - */ - - /* - * Are we done? - */ - if (after && dest == &(sigd->contentInfo.content)) { - /* - * Close out the digest contexts. We ignore any error - * because we are stopping anyway; the error status left - * behind in p7dcx will be seen by outer functions. - */ - (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, - &(sigd->digests)); - - /* - * XXX To handle nested contents, we would need to remove - * the worker from the chain (and free it). - */ - - /* - * Stop notify. - */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - } - break; - - case SEC_OID_PKCS7_ENVELOPED_DATA: - envd = cinfo->content.envelopedData; - if (envd == NULL) - break; - - if (envd->encContentInfo.contentTypeTag == NULL) { - if (after && dest == &(envd->encContentInfo.contentType)) - envd->encContentInfo.contentTypeTag = - SECOID_FindOID(&(envd->encContentInfo.contentType)); - break; - } - - /* - * Just before the content, we want to set up a decryption - * context, and start a filter which will run all of the - * contents bytes through it to determine the plain content. - */ - if (before && dest == &(envd->encContentInfo.encContent)) { - rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, - envd->recipientInfos, - &(envd->encContentInfo), - NULL); - if (rv != SECSuccess) - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - - break; - } - - /* - * Are we done? - */ - if (after && dest == &(envd->encContentInfo.encContent)) { - /* - * Close out the decryption context. We ignore any error - * because we are stopping anyway; the error status left - * behind in p7dcx will be seen by outer functions. - */ - (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, - &(envd->encContentInfo)); - - /* - * XXX To handle nested contents, we would need to remove - * the worker from the chain (and free it). - */ - - /* - * Stop notify. - */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - } - break; - - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - saed = cinfo->content.signedAndEnvelopedData; - if (saed == NULL) - break; - - if (saed->encContentInfo.contentTypeTag == NULL) { - if (after && dest == &(saed->encContentInfo.contentType)) - saed->encContentInfo.contentTypeTag = - SECOID_FindOID(&(saed->encContentInfo.contentType)); - break; - } - - /* - * Just before the content, we want to set up a decryption - * context *and* digest contexts, and start a filter which - * will run all of the contents bytes through both. - */ - if (before && dest == &(saed->encContentInfo.encContent)) { - rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, - saed->recipientInfos, - &(saed->encContentInfo), - &(saed->sigKey)); - if (rv == SECSuccess) - rv = sec_pkcs7_decoder_start_digests (p7dcx, depth, - saed->digestAlgorithms); - if (rv != SECSuccess) - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - - break; - } - - /* - * Are we done? - */ - if (after && dest == &(saed->encContentInfo.encContent)) { - /* - * Close out the decryption and digests contexts. - * We ignore any errors because we are stopping anyway; - * the error status left behind in p7dcx will be seen by - * outer functions. - * - * Note that the decrypt stuff must be called first; - * it may have a last buffer to do which in turn has - * to be added to the digest. - */ - (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, - &(saed->encContentInfo)); - (void) sec_pkcs7_decoder_finish_digests (p7dcx, cinfo->poolp, - &(saed->digests)); - - /* - * XXX To handle nested contents, we would need to remove - * the worker from the chain (and free it). - */ - - /* - * Stop notify. - */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - } - break; - - case SEC_OID_PKCS7_DIGESTED_DATA: - digd = cinfo->content.digestedData; - - /* - * XXX Want to do the digest or not? Maybe future enhancement... - */ - if (before && dest == &(digd->contentInfo.content.data)) { - SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, sec_pkcs7_decoder_filter, - p7dcx, - (PRBool)(p7dcx->cb != NULL)); - break; - } - - /* - * Are we done? - */ - if (after && dest == &(digd->contentInfo.content.data)) { - SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); - } - break; - - case SEC_OID_PKCS7_ENCRYPTED_DATA: - encd = cinfo->content.encryptedData; - - /* - * XXX If the decryption key callback is set, we want to start - * the decryption. If the callback is not set, we will treat the - * content as plain data, since we do not have the key. - * - * Is this the proper thing to do? - */ - if (before && dest == &(encd->encContentInfo.encContent)) { - /* - * Start the encryption process if the decryption key callback - * is present. Otherwise, treat the content like plain data. - */ - rv = SECSuccess; - if (p7dcx->dkcb != NULL) { - rv = sec_pkcs7_decoder_start_decrypt (p7dcx, depth, NULL, - &(encd->encContentInfo), - NULL); - } - - if (rv != SECSuccess) - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - - break; - } - - /* - * Are we done? - */ - if (after && dest == &(encd->encContentInfo.encContent)) { - /* - * Close out the decryption context. We ignore any error - * because we are stopping anyway; the error status left - * behind in p7dcx will be seen by outer functions. - */ - (void) sec_pkcs7_decoder_finish_decrypt (p7dcx, cinfo->poolp, - &(encd->encContentInfo)); - - /* - * Stop notify. - */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - } - break; - - case SEC_OID_PKCS7_DATA: - /* - * If a output callback has been specified, we want to set the filter - * to call the callback. This is taken care of in - * sec_pkcs7_decoder_start_decrypt() or - * sec_pkcs7_decoder_start_digests() for the other content types. - */ - - if (before && dest == &(cinfo->content.data)) { - - /* - * Set the filter proc up. - */ - SEC_ASN1DecoderSetFilterProc (p7dcx->dcx, - sec_pkcs7_decoder_filter, - p7dcx, - (PRBool)(p7dcx->cb != NULL)); - break; - } - - if (after && dest == &(cinfo->content.data)) { - /* - * Time to clean up after ourself, stop the Notify and Filter - * procedures. - */ - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - SEC_ASN1DecoderClearFilterProc (p7dcx->dcx); - } - break; - - default: - SEC_ASN1DecoderClearNotifyProc (p7dcx->dcx); - break; + case SEC_OID_PKCS7_SIGNED_DATA: + sigd = cinfo->content.signedData; + if (sigd == NULL) + break; + + if (sigd->contentInfo.contentTypeTag == NULL) { + if (after && dest == &(sigd->contentInfo.contentType)) + sigd->contentInfo.contentTypeTag = + SECOID_FindOID(&(sigd->contentInfo.contentType)); + break; + } + + /* + * We only set up a filtering digest if the content is + * plain DATA; anything else needs more work because a + * second pass is required to produce a DER encoding from + * an input that can be BER encoded. (This is a requirement + * of PKCS7 that is unfortunate, but there you have it.) + * + * XXX Also, since we stop here if this is not DATA, the + * inner content is not getting processed at all. Someday + * we may want to fix that. + */ + if (sigd->contentInfo.contentTypeTag->offset != SEC_OID_PKCS7_DATA) { + /* XXX Set an error in p7dcx->error */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + break; + } + + /* + * Just before the content, we want to set up a digest context + * for each digest algorithm listed, and start a filter which + * will run all of the contents bytes through that digest. + */ + if (before && dest == &(sigd->contentInfo.content)) { + rv = sec_pkcs7_decoder_start_digests(p7dcx, depth, + sigd->digestAlgorithms); + if (rv != SECSuccess) + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + + break; + } + + /* + * XXX To handle nested types, here is where we would want + * to check for inner boundaries that need handling. + */ + + /* + * Are we done? + */ + if (after && dest == &(sigd->contentInfo.content)) { + /* + * Close out the digest contexts. We ignore any error + * because we are stopping anyway; the error status left + * behind in p7dcx will be seen by outer functions. + */ + (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp, + &(sigd->digests)); + + /* + * XXX To handle nested contents, we would need to remove + * the worker from the chain (and free it). + */ + + /* + * Stop notify. + */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + } + break; + + case SEC_OID_PKCS7_ENVELOPED_DATA: + envd = cinfo->content.envelopedData; + if (envd == NULL) + break; + + if (envd->encContentInfo.contentTypeTag == NULL) { + if (after && dest == &(envd->encContentInfo.contentType)) + envd->encContentInfo.contentTypeTag = + SECOID_FindOID(&(envd->encContentInfo.contentType)); + break; + } + + /* + * Just before the content, we want to set up a decryption + * context, and start a filter which will run all of the + * contents bytes through it to determine the plain content. + */ + if (before && dest == &(envd->encContentInfo.encContent)) { + rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, + envd->recipientInfos, + &(envd->encContentInfo), + NULL); + if (rv != SECSuccess) + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + + break; + } + + /* + * Are we done? + */ + if (after && dest == &(envd->encContentInfo.encContent)) { + /* + * Close out the decryption context. We ignore any error + * because we are stopping anyway; the error status left + * behind in p7dcx will be seen by outer functions. + */ + (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, + &(envd->encContentInfo)); + + /* + * XXX To handle nested contents, we would need to remove + * the worker from the chain (and free it). + */ + + /* + * Stop notify. + */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + } + break; + + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: + saed = cinfo->content.signedAndEnvelopedData; + if (saed == NULL) + break; + + if (saed->encContentInfo.contentTypeTag == NULL) { + if (after && dest == &(saed->encContentInfo.contentType)) + saed->encContentInfo.contentTypeTag = + SECOID_FindOID(&(saed->encContentInfo.contentType)); + break; + } + + /* + * Just before the content, we want to set up a decryption + * context *and* digest contexts, and start a filter which + * will run all of the contents bytes through both. + */ + if (before && dest == &(saed->encContentInfo.encContent)) { + rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, + saed->recipientInfos, + &(saed->encContentInfo), + &(saed->sigKey)); + if (rv == SECSuccess) + rv = sec_pkcs7_decoder_start_digests(p7dcx, depth, + saed->digestAlgorithms); + if (rv != SECSuccess) + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + + break; + } + + /* + * Are we done? + */ + if (after && dest == &(saed->encContentInfo.encContent)) { + /* + * Close out the decryption and digests contexts. + * We ignore any errors because we are stopping anyway; + * the error status left behind in p7dcx will be seen by + * outer functions. + * + * Note that the decrypt stuff must be called first; + * it may have a last buffer to do which in turn has + * to be added to the digest. + */ + (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, + &(saed->encContentInfo)); + (void)sec_pkcs7_decoder_finish_digests(p7dcx, cinfo->poolp, + &(saed->digests)); + + /* + * XXX To handle nested contents, we would need to remove + * the worker from the chain (and free it). + */ + + /* + * Stop notify. + */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + } + break; + + case SEC_OID_PKCS7_DIGESTED_DATA: + digd = cinfo->content.digestedData; + + /* + * XXX Want to do the digest or not? Maybe future enhancement... + */ + if (before && dest == &(digd->contentInfo.content.data)) { + SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, sec_pkcs7_decoder_filter, + p7dcx, + (PRBool)(p7dcx->cb != NULL)); + break; + } + + /* + * Are we done? + */ + if (after && dest == &(digd->contentInfo.content.data)) { + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); + } + break; + + case SEC_OID_PKCS7_ENCRYPTED_DATA: + encd = cinfo->content.encryptedData; + + if (!encd) { + break; + } + + /* + * XXX If the decryption key callback is set, we want to start + * the decryption. If the callback is not set, we will treat the + * content as plain data, since we do not have the key. + * + * Is this the proper thing to do? + */ + if (before && dest == &(encd->encContentInfo.encContent)) { + /* + * Start the encryption process if the decryption key callback + * is present. Otherwise, treat the content like plain data. + */ + rv = SECSuccess; + if (p7dcx->dkcb != NULL) { + rv = sec_pkcs7_decoder_start_decrypt(p7dcx, depth, NULL, + &(encd->encContentInfo), + NULL); + } + + if (rv != SECSuccess) + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + + break; + } + + /* + * Are we done? + */ + if (after && dest == &(encd->encContentInfo.encContent)) { + /* + * Close out the decryption context. We ignore any error + * because we are stopping anyway; the error status left + * behind in p7dcx will be seen by outer functions. + */ + (void)sec_pkcs7_decoder_finish_decrypt(p7dcx, cinfo->poolp, + &(encd->encContentInfo)); + + /* + * Stop notify. + */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + } + break; + + case SEC_OID_PKCS7_DATA: + /* + * If a output callback has been specified, we want to set the filter + * to call the callback. This is taken care of in + * sec_pkcs7_decoder_start_decrypt() or + * sec_pkcs7_decoder_start_digests() for the other content types. + */ + + if (before && dest == &(cinfo->content.data)) { + + /* + * Set the filter proc up. + */ + SEC_ASN1DecoderSetFilterProc(p7dcx->dcx, + sec_pkcs7_decoder_filter, + p7dcx, + (PRBool)(p7dcx->cb != NULL)); + break; + } + + if (after && dest == &(cinfo->content.data)) { + /* + * Time to clean up after ourself, stop the Notify and Filter + * procedures. + */ + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + SEC_ASN1DecoderClearFilterProc(p7dcx->dcx); + } + break; + + default: + SEC_ASN1DecoderClearNotifyProc(p7dcx->dcx); + break; } } - SEC_PKCS7DecoderContext * SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, - SECKEYGetPasswordKey pwfn, void *pwfn_arg, - SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, - void *decrypt_key_cb_arg, - SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) + SECKEYGetPasswordKey pwfn, void *pwfn_arg, + SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, + void *decrypt_key_cb_arg, + SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) { SEC_PKCS7DecoderContext *p7dcx; SEC_ASN1DecoderContext *dcx; SEC_PKCS7ContentInfo *cinfo; PLArenaPool *poolp; - poolp = PORT_NewArena (1024); /* XXX what is right value? */ + poolp = PORT_NewArena(1024); /* XXX what is right value? */ if (poolp == NULL) - return NULL; + return NULL; - cinfo = (SEC_PKCS7ContentInfo*)PORT_ArenaZAlloc (poolp, sizeof(*cinfo)); + cinfo = (SEC_PKCS7ContentInfo *)PORT_ArenaZAlloc(poolp, sizeof(*cinfo)); if (cinfo == NULL) { - PORT_FreeArena (poolp, PR_FALSE); - return NULL; + PORT_FreeArena(poolp, PR_FALSE); + return NULL; } cinfo->poolp = poolp; @@ -976,29 +982,29 @@ SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, cinfo->created = PR_FALSE; cinfo->refCount = 1; - p7dcx = - (SEC_PKCS7DecoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7DecoderContext)); + p7dcx = + (SEC_PKCS7DecoderContext *)PORT_ZAlloc(sizeof(SEC_PKCS7DecoderContext)); if (p7dcx == NULL) { - PORT_FreeArena (poolp, PR_FALSE); - return NULL; + PORT_FreeArena(poolp, PR_FALSE); + return NULL; } - p7dcx->tmp_poolp = PORT_NewArena (1024); /* XXX what is right value? */ + p7dcx->tmp_poolp = PORT_NewArena(1024); /* XXX what is right value? */ if (p7dcx->tmp_poolp == NULL) { - PORT_Free (p7dcx); - PORT_FreeArena (poolp, PR_FALSE); - return NULL; + PORT_Free(p7dcx); + PORT_FreeArena(poolp, PR_FALSE); + return NULL; } - dcx = SEC_ASN1DecoderStart (poolp, cinfo, sec_PKCS7ContentInfoTemplate); + dcx = SEC_ASN1DecoderStart(poolp, cinfo, sec_PKCS7ContentInfoTemplate); if (dcx == NULL) { - PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); - PORT_Free (p7dcx); - PORT_FreeArena (poolp, PR_FALSE); - return NULL; + PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE); + PORT_Free(p7dcx); + PORT_FreeArena(poolp, PR_FALSE); + return NULL; } - SEC_ASN1DecoderSetNotifyProc (dcx, sec_pkcs7_decoder_notify, p7dcx); + SEC_ASN1DecoderSetNotifyProc(dcx, sec_pkcs7_decoder_notify, p7dcx); p7dcx->dcx = dcx; p7dcx->cinfo = cinfo; @@ -1013,7 +1019,6 @@ SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, return p7dcx; } - /* * Do the next chunk of PKCS7 decoding. If there is a problem, set * an error and return a failure status. Note that in the case of @@ -1024,37 +1029,36 @@ SEC_PKCS7DecoderStart(SEC_PKCS7DecoderContentCallback cb, void *cb_arg, */ SECStatus SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx, - const char *buf, unsigned long len) + const char *buf, unsigned long len) { - if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { - PORT_Assert (p7dcx->error == 0); - if (p7dcx->error == 0) { - if (SEC_ASN1DecoderUpdate (p7dcx->dcx, buf, len) != SECSuccess) { - p7dcx->error = PORT_GetError(); - PORT_Assert (p7dcx->error); - if (p7dcx->error == 0) - p7dcx->error = -1; - } - } + if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) { + PORT_Assert(p7dcx->error == 0); + if (p7dcx->error == 0) { + if (SEC_ASN1DecoderUpdate(p7dcx->dcx, buf, len) != SECSuccess) { + p7dcx->error = PORT_GetError(); + PORT_Assert(p7dcx->error); + if (p7dcx->error == 0) + p7dcx->error = -1; + } + } } if (p7dcx->error) { - if (p7dcx->dcx != NULL) { - (void) SEC_ASN1DecoderFinish (p7dcx->dcx); - p7dcx->dcx = NULL; - } - if (p7dcx->cinfo != NULL) { - SEC_PKCS7DestroyContentInfo (p7dcx->cinfo); - p7dcx->cinfo = NULL; - } - PORT_SetError (p7dcx->error); - return SECFailure; + if (p7dcx->dcx != NULL) { + (void)SEC_ASN1DecoderFinish(p7dcx->dcx); + p7dcx->dcx = NULL; + } + if (p7dcx->cinfo != NULL) { + SEC_PKCS7DestroyContentInfo(p7dcx->cinfo); + p7dcx->cinfo = NULL; + } + PORT_SetError(p7dcx->error); + return SECFailure; } return SECSuccess; } - SEC_PKCS7ContentInfo * SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx) { @@ -1062,38 +1066,37 @@ SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx) cinfo = p7dcx->cinfo; if (p7dcx->dcx != NULL) { - if (SEC_ASN1DecoderFinish (p7dcx->dcx) != SECSuccess) { - SEC_PKCS7DestroyContentInfo (cinfo); - cinfo = NULL; - } + if (SEC_ASN1DecoderFinish(p7dcx->dcx) != SECSuccess) { + SEC_PKCS7DestroyContentInfo(cinfo); + cinfo = NULL; + } } /* free any NSS data structures */ if (p7dcx->worker.decryptobj) { - sec_PKCS7DestroyDecryptObject (p7dcx->worker.decryptobj); + sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj); } - PORT_FreeArena (p7dcx->tmp_poolp, PR_FALSE); - PORT_Free (p7dcx); + PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE); + PORT_Free(p7dcx); return cinfo; } - SEC_PKCS7ContentInfo * SEC_PKCS7DecodeItem(SECItem *p7item, - SEC_PKCS7DecoderContentCallback cb, void *cb_arg, - SECKEYGetPasswordKey pwfn, void *pwfn_arg, - SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, - void *decrypt_key_cb_arg, - SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) + SEC_PKCS7DecoderContentCallback cb, void *cb_arg, + SECKEYGetPasswordKey pwfn, void *pwfn_arg, + SEC_PKCS7GetDecryptKeyCallback decrypt_key_cb, + void *decrypt_key_cb_arg, + SEC_PKCS7DecryptionAllowedCallback decrypt_allowed_cb) { SEC_PKCS7DecoderContext *p7dcx; p7dcx = SEC_PKCS7DecoderStart(cb, cb_arg, pwfn, pwfn_arg, decrypt_key_cb, - decrypt_key_cb_arg, decrypt_allowed_cb); + decrypt_key_cb_arg, decrypt_allowed_cb); if (!p7dcx) { /* error code is set */ return NULL; } - (void) SEC_PKCS7DecoderUpdate(p7dcx, (char *) p7item->data, p7item->len); + (void)SEC_PKCS7DecoderUpdate(p7dcx, (char *)p7item->data, p7item->len); return SEC_PKCS7DecoderFinish(p7dcx); } @@ -1107,7 +1110,6 @@ SEC_PKCS7DecoderAbort(SEC_PKCS7DecoderContext *p7dcx, int error) SEC_ASN1DecoderAbort(p7dcx->dcx, error); } - /* * If the thing contains any certs or crls return true; false otherwise. */ @@ -1118,90 +1120,87 @@ SEC_PKCS7ContainsCertsOrCrls(SEC_PKCS7ContentInfo *cinfo) SECItem **certs; CERTSignedCrl **crls; - kind = SEC_PKCS7ContentType (cinfo); + kind = SEC_PKCS7ContentType(cinfo); switch (kind) { - default: - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - return PR_FALSE; - case SEC_OID_PKCS7_SIGNED_DATA: - certs = cinfo->content.signedData->rawCerts; - crls = cinfo->content.signedData->crls; - break; - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - certs = cinfo->content.signedAndEnvelopedData->rawCerts; - crls = cinfo->content.signedAndEnvelopedData->crls; - break; + default: + case SEC_OID_PKCS7_DATA: + case SEC_OID_PKCS7_DIGESTED_DATA: + case SEC_OID_PKCS7_ENVELOPED_DATA: + case SEC_OID_PKCS7_ENCRYPTED_DATA: + return PR_FALSE; + case SEC_OID_PKCS7_SIGNED_DATA: + certs = cinfo->content.signedData->rawCerts; + crls = cinfo->content.signedData->crls; + break; + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: + certs = cinfo->content.signedAndEnvelopedData->rawCerts; + crls = cinfo->content.signedAndEnvelopedData->crls; + break; } /* * I know this could be collapsed, but I was in a mood to be explicit. */ if (certs != NULL && certs[0] != NULL) - return PR_TRUE; + return PR_TRUE; else if (crls != NULL && crls[0] != NULL) - return PR_TRUE; + return PR_TRUE; else - return PR_FALSE; + return PR_FALSE; } /* return the content length...could use GetContent, however we - * need the encrypted content length + * need the encrypted content length */ PRBool SEC_PKCS7IsContentEmpty(SEC_PKCS7ContentInfo *cinfo, unsigned int minLen) { SECItem *item = NULL; - if(cinfo == NULL) { - return PR_TRUE; + if (cinfo == NULL) { + return PR_TRUE; } - switch(SEC_PKCS7ContentType(cinfo)) - { - case SEC_OID_PKCS7_DATA: - item = cinfo->content.data; - break; - case SEC_OID_PKCS7_ENCRYPTED_DATA: - item = &cinfo->content.encryptedData->encContentInfo.encContent; - break; - default: - /* add other types */ - return PR_FALSE; + switch (SEC_PKCS7ContentType(cinfo)) { + case SEC_OID_PKCS7_DATA: + item = cinfo->content.data; + break; + case SEC_OID_PKCS7_ENCRYPTED_DATA: + item = &cinfo->content.encryptedData->encContentInfo.encContent; + break; + default: + /* add other types */ + return PR_FALSE; } - if(!item) { - return PR_TRUE; - } else if(item->len <= minLen) { - return PR_TRUE; + if (!item) { + return PR_TRUE; + } else if (item->len <= minLen) { + return PR_TRUE; } return PR_FALSE; } - PRBool SEC_PKCS7ContentIsEncrypted(SEC_PKCS7ContentInfo *cinfo) { SECOidTag kind; - kind = SEC_PKCS7ContentType (cinfo); + kind = SEC_PKCS7ContentType(cinfo); switch (kind) { - default: - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_SIGNED_DATA: - return PR_FALSE; - case SEC_OID_PKCS7_ENCRYPTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - return PR_TRUE; + default: + case SEC_OID_PKCS7_DATA: + case SEC_OID_PKCS7_DIGESTED_DATA: + case SEC_OID_PKCS7_SIGNED_DATA: + return PR_FALSE; + case SEC_OID_PKCS7_ENCRYPTED_DATA: + case SEC_OID_PKCS7_ENVELOPED_DATA: + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: + return PR_TRUE; } } - /* * If the PKCS7 content has a signature (not just *could* have a signature) * return true; false otherwise. This can/should be called before calling @@ -1216,20 +1215,20 @@ SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) SECOidTag kind; SEC_PKCS7SignerInfo **signerinfos; - kind = SEC_PKCS7ContentType (cinfo); + kind = SEC_PKCS7ContentType(cinfo); switch (kind) { - default: - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - return PR_FALSE; - case SEC_OID_PKCS7_SIGNED_DATA: - signerinfos = cinfo->content.signedData->signerInfos; - break; - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; - break; + default: + case SEC_OID_PKCS7_DATA: + case SEC_OID_PKCS7_DIGESTED_DATA: + case SEC_OID_PKCS7_ENVELOPED_DATA: + case SEC_OID_PKCS7_ENCRYPTED_DATA: + return PR_FALSE; + case SEC_OID_PKCS7_SIGNED_DATA: + signerinfos = cinfo->content.signedData->signerInfos; + break; + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: + signerinfos = cinfo->content.signedAndEnvelopedData->signerInfos; + break; } /* @@ -1237,27 +1236,26 @@ SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) * more complicated before I am finished, so... */ if (signerinfos != NULL && signerinfos[0] != NULL) - return PR_TRUE; + return PR_TRUE; else - return PR_FALSE; + return PR_FALSE; } - /* * sec_pkcs7_verify_signature * - * Look at a PKCS7 contentInfo and check if the signature is good. - * The digest was either calculated earlier (and is stored in the - * contentInfo itself) or is passed in via "detached_digest". + * Look at a PKCS7 contentInfo and check if the signature is good. + * The digest was either calculated earlier (and is stored in the + * contentInfo itself) or is passed in via "detached_digest". * - * The verification checks that the signing cert is valid and trusted - * for the purpose specified by "certusage" at - * - "*atTime" if "atTime" is not null, or - * - the signing time if the signing time is available in "cinfo", or - * - the current time (as returned by PR_Now). + * The verification checks that the signing cert is valid and trusted + * for the purpose specified by "certusage" at + * - "*atTime" if "atTime" is not null, or + * - the signing time if the signing time is available in "cinfo", or + * - the current time (as returned by PR_Now). * - * In addition, if "keepcerts" is true, add any new certificates found - * into our local database. + * In addition, if "keepcerts" is true, add any new certificates found + * into our local database. * * XXX Each place which returns PR_FALSE should be sure to have a good * error set for inspection by the caller. Alternatively, we could create @@ -1280,11 +1278,11 @@ SEC_PKCS7ContentIsSigned(SEC_PKCS7ContentInfo *cinfo) */ static PRBool sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, - SECCertUsage certusage, - const SECItem *detached_digest, - HASH_HashType digest_type, - PRBool keepcerts, - const PRTime *atTime) + SECCertUsage certusage, + const SECItem *detached_digest, + HASH_HashType digest_type, + PRBool keepcerts, + const PRTime *atTime) { SECAlgorithmID **digestalgs, *bulkid; const SECItem *digest; @@ -1293,8 +1291,8 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, SEC_PKCS7SignerInfo **signerinfos, *signerinfo; CERTCertificate *cert, **certs; PRBool goodsig; - CERTCertDBHandle *certdb, *defaultdb; - SECOidTag encTag,digestTag; + CERTCertDBHandle *certdb, *defaultdb; + SECOidTag encTag, digestTag; HASH_HashType found_type; int i, certcount; SECKEYPublicKey *publickey; @@ -1316,54 +1314,50 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, defaultdb = CERT_GetDefaultCertDB(); publickey = NULL; - if (! SEC_PKCS7ContentIsSigned(cinfo)) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; + if (!SEC_PKCS7ContentIsSigned(cinfo)) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; } - PORT_Assert (cinfo->contentTypeTag != NULL); + PORT_Assert(cinfo->contentTypeTag != NULL); switch (cinfo->contentTypeTag->offset) { - default: - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */ - PORT_Assert (0); - case SEC_OID_PKCS7_SIGNED_DATA: - { - SEC_PKCS7SignedData *sdp; - - sdp = cinfo->content.signedData; - digestalgs = sdp->digestAlgorithms; - digests = sdp->digests; - rawcerts = sdp->rawCerts; - signerinfos = sdp->signerInfos; - content_type = &(sdp->contentInfo.contentType); - sigkey = NULL; - bulkid = NULL; - } - break; - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - { - SEC_PKCS7SignedAndEnvelopedData *saedp; - - saedp = cinfo->content.signedAndEnvelopedData; - digestalgs = saedp->digestAlgorithms; - digests = saedp->digests; - rawcerts = saedp->rawCerts; - signerinfos = saedp->signerInfos; - content_type = &(saedp->encContentInfo.contentType); - sigkey = saedp->sigKey; - bulkid = &(saedp->encContentInfo.contentEncAlg); - } - break; + default: + case SEC_OID_PKCS7_DATA: + case SEC_OID_PKCS7_DIGESTED_DATA: + case SEC_OID_PKCS7_ENVELOPED_DATA: + case SEC_OID_PKCS7_ENCRYPTED_DATA: + /* Could only get here if SEC_PKCS7ContentIsSigned is broken. */ + PORT_Assert(0); + case SEC_OID_PKCS7_SIGNED_DATA: { + SEC_PKCS7SignedData *sdp; + + sdp = cinfo->content.signedData; + digestalgs = sdp->digestAlgorithms; + digests = sdp->digests; + rawcerts = sdp->rawCerts; + signerinfos = sdp->signerInfos; + content_type = &(sdp->contentInfo.contentType); + sigkey = NULL; + bulkid = NULL; + } break; + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { + SEC_PKCS7SignedAndEnvelopedData *saedp; + + saedp = cinfo->content.signedAndEnvelopedData; + digestalgs = saedp->digestAlgorithms; + digests = saedp->digests; + rawcerts = saedp->rawCerts; + signerinfos = saedp->signerInfos; + content_type = &(saedp->encContentInfo.contentType); + sigkey = saedp->sigKey; + bulkid = &(saedp->encContentInfo.contentEncAlg); + } break; } if ((signerinfos == NULL) || (signerinfos[0] == NULL)) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; } /* @@ -1371,8 +1365,8 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, * but what should be the semantics here (like, return value)? */ if (signerinfos[1] != NULL) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; } signerinfo = signerinfos[0]; @@ -1385,14 +1379,14 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, */ certdb = defaultdb; if (certdb == NULL) { - goto done; + goto done; } certcount = 0; if (rawcerts != NULL) { - for (; rawcerts[certcount] != NULL; certcount++) { - /* just counting */ - } + for (; rawcerts[certcount] != NULL; certcount++) { + /* just counting */ + } } /* @@ -1400,9 +1394,9 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, * needs to be destroyed. */ rv = CERT_ImportCerts(certdb, certusage, certcount, rawcerts, &certs, - keepcerts, PR_FALSE, NULL); - if ( rv != SECSuccess ) { - goto done; + keepcerts, PR_FALSE, NULL); + if (rv != SECSuccess) { + goto done; } /* @@ -1413,7 +1407,7 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, */ cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->issuerAndSN); if (cert == NULL) { - goto done; + goto done; } signerinfo->cert = cert; @@ -1423,10 +1417,10 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, * both on the cert verification and for importing the sender * email profile. */ - encoded_stime = SEC_PKCS7GetSigningTime (cinfo); + encoded_stime = SEC_PKCS7GetSigningTime(cinfo); if (encoded_stime != NULL) { - if (DER_DecodeTimeChoice (&stime, encoded_stime) != SECSuccess) - encoded_stime = NULL; /* conversion failed, so pretend none */ + if (DER_DecodeTimeChoice(&stime, encoded_stime) != SECSuccess) + encoded_stime = NULL; /* conversion failed, so pretend none */ } /* @@ -1438,29 +1432,28 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, * maybe make them pass in the current time, always?). */ if (atTime) { - verificationTime = *atTime; + verificationTime = *atTime; } else if (encoded_stime != NULL) { - verificationTime = stime; + verificationTime = stime; } else { - verificationTime = PR_Now(); + verificationTime = PR_Now(); } - if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, verificationTime, - cinfo->pwfn_arg, NULL) != SECSuccess) - { - /* - * XXX Give the user an option to check the signature anyway? - * If we want to do this, need to give a way to leave and display - * some dialog and get the answer and come back through (or do - * the rest of what we do below elsewhere, maybe by putting it - * in a function that we call below and could call from a dialog - * finish handler). - */ - goto savecert; + if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, verificationTime, + cinfo->pwfn_arg, NULL) != SECSuccess) { + /* + * XXX Give the user an option to check the signature anyway? + * If we want to do this, need to give a way to leave and display + * some dialog and get the answer and come back through (or do + * the rest of what we do below elsewhere, maybe by putting it + * in a function that we call below and could call from a dialog + * finish handler). + */ + goto savecert; } - publickey = CERT_ExtractPublicKey (cert); + publickey = CERT_ExtractPublicKey(cert); if (publickey == NULL) - goto done; + goto done; /* * XXX No! If digests is empty, see if we can create it now by @@ -1472,9 +1465,8 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, * stashed in the struct itself or passed in explicitly (as would * be done for detached contents). */ - if ((digests == NULL || digests[0] == NULL) - && (detached_digest == NULL || detached_digest->data == NULL)) - goto done; + if ((digests == NULL || digests[0] == NULL) && (detached_digest == NULL || detached_digest->data == NULL)) + goto done; /* * Find and confirm digest algorithm. @@ -1484,198 +1476,197 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, /* make sure we understand the digest type first */ found_type = HASH_GetHashTypeByOidTag(digestTag); if ((digestTag == SEC_OID_UNKNOWN) || (found_type == HASH_AlgNULL)) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; } if (detached_digest != NULL) { - unsigned int hashLen = HASH_ResultLen(found_type); - - if (digest_type != found_type || - detached_digest->len != hashLen) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - digest = detached_digest; + unsigned int hashLen = HASH_ResultLen(found_type); + + if (digest_type != found_type || + detached_digest->len != hashLen) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + digest = detached_digest; } else { - PORT_Assert (digestalgs != NULL && digestalgs[0] != NULL); - if (digestalgs == NULL || digestalgs[0] == NULL) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - /* - * pick digest matching signerinfo->digestAlg from digests - */ - for (i = 0; digestalgs[i] != NULL; i++) { - if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag) - break; - } - if (digestalgs[i] == NULL) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - digest = digests[i]; + PORT_Assert(digestalgs != NULL && digestalgs[0] != NULL); + if (digestalgs == NULL || digestalgs[0] == NULL) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + /* + * pick digest matching signerinfo->digestAlg from digests + */ + for (i = 0; digestalgs[i] != NULL; i++) { + if (SECOID_FindOIDTag(&(digestalgs[i]->algorithm)) == digestTag) + break; + } + if (digestalgs[i] == NULL) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + digest = digests[i]; } encTag = SECOID_FindOIDTag(&(signerinfo->digestEncAlg.algorithm)); if (encTag == SEC_OID_UNKNOWN) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; } if (signerinfo->authAttr != NULL) { - SEC_PKCS7Attribute *attr; - SECItem *value; - SECItem encoded_attrs; - - /* - * We have a sigkey only for signedAndEnvelopedData, which is - * not supposed to have any authenticated attributes. - */ - if (sigkey != NULL) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - /* - * PKCS #7 says that if there are any authenticated attributes, - * then there must be one for content type which matches the - * content type of the content being signed, and there must - * be one for message digest which matches our message digest. - * So check these things first. - * XXX Might be nice to have a compare-attribute-value function - * which could collapse the following nicely. - */ - attr = sec_PKCS7FindAttribute (signerinfo->authAttr, - SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE); - value = sec_PKCS7AttributeValue (attr); - if (value == NULL || value->len != content_type->len) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - if (PORT_Memcmp (value->data, content_type->data, value->len) != 0) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - attr = sec_PKCS7FindAttribute (signerinfo->authAttr, - SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE); - value = sec_PKCS7AttributeValue (attr); - if (value == NULL || value->len != digest->len) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - if (PORT_Memcmp (value->data, digest->data, value->len) != 0) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - /* - * Okay, we met the constraints of the basic attributes. - * Now check the signature, which is based on a digest of - * the DER-encoded authenticated attributes. So, first we - * encode and then we digest/verify. - */ - encoded_attrs.data = NULL; - encoded_attrs.len = 0; - if (sec_PKCS7EncodeAttributes (NULL, &encoded_attrs, - &(signerinfo->authAttr)) == NULL) - goto done; - - if (encoded_attrs.data == NULL || encoded_attrs.len == 0) { - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data, - encoded_attrs.len, - publickey, &(signerinfo->encDigest), - encTag, digestTag, NULL, - cinfo->pwfn_arg) == SECSuccess); - PORT_Free (encoded_attrs.data); + SEC_PKCS7Attribute *attr; + SECItem *value; + SECItem encoded_attrs; + + /* + * We have a sigkey only for signedAndEnvelopedData, which is + * not supposed to have any authenticated attributes. + */ + if (sigkey != NULL) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + /* + * PKCS #7 says that if there are any authenticated attributes, + * then there must be one for content type which matches the + * content type of the content being signed, and there must + * be one for message digest which matches our message digest. + * So check these things first. + * XXX Might be nice to have a compare-attribute-value function + * which could collapse the following nicely. + */ + attr = sec_PKCS7FindAttribute(signerinfo->authAttr, + SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE); + value = sec_PKCS7AttributeValue(attr); + if (value == NULL || value->len != content_type->len) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + if (PORT_Memcmp(value->data, content_type->data, value->len) != 0) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + attr = sec_PKCS7FindAttribute(signerinfo->authAttr, + SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE); + value = sec_PKCS7AttributeValue(attr); + if (value == NULL || value->len != digest->len) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + if (PORT_Memcmp(value->data, digest->data, value->len) != 0) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + /* + * Okay, we met the constraints of the basic attributes. + * Now check the signature, which is based on a digest of + * the DER-encoded authenticated attributes. So, first we + * encode and then we digest/verify. + */ + encoded_attrs.data = NULL; + encoded_attrs.len = 0; + if (sec_PKCS7EncodeAttributes(NULL, &encoded_attrs, + &(signerinfo->authAttr)) == NULL) + goto done; + + if (encoded_attrs.data == NULL || encoded_attrs.len == 0) { + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + goodsig = (PRBool)(VFY_VerifyDataDirect(encoded_attrs.data, + encoded_attrs.len, + publickey, &(signerinfo->encDigest), + encTag, digestTag, NULL, + cinfo->pwfn_arg) == SECSuccess); + PORT_Free(encoded_attrs.data); } else { - SECItem *sig; - SECItem holder; - SECStatus rv; - - /* - * No authenticated attributes. - * The signature is based on the plain message digest. - */ - - sig = &(signerinfo->encDigest); - if (sig->len == 0) { /* bad signature */ - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); - goto done; - } - - if (sigkey != NULL) { - sec_PKCS7CipherObject *decryptobj; - unsigned int buflen; - - /* - * For signedAndEnvelopedData, we first must decrypt the encrypted - * digest with the bulk encryption key. The result is the normal - * encrypted digest (aka the signature). - */ - decryptobj = sec_PKCS7CreateDecryptObject (sigkey, bulkid); - if (decryptobj == NULL) - goto done; - - buflen = sec_PKCS7DecryptLength (decryptobj, sig->len, PR_TRUE); - PORT_Assert (buflen); - if (buflen == 0) { /* something is wrong */ - sec_PKCS7DestroyDecryptObject (decryptobj); - goto done; - } - - holder.data = (unsigned char*)PORT_Alloc (buflen); - if (holder.data == NULL) { - sec_PKCS7DestroyDecryptObject (decryptobj); - goto done; - } - - rv = sec_PKCS7Decrypt (decryptobj, holder.data, &holder.len, buflen, - sig->data, sig->len, PR_TRUE); - sec_PKCS7DestroyDecryptObject (decryptobj); - if (rv != SECSuccess) { - goto done; - } - - sig = &holder; - } - - goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig, - encTag, digestTag, cinfo->pwfn_arg) - == SECSuccess); - - if (sigkey != NULL) { - PORT_Assert (sig == &holder); - PORT_ZFree (holder.data, holder.len); - } + SECItem *sig; + SECItem holder; + SECStatus rv; + + /* + * No authenticated attributes. + * The signature is based on the plain message digest. + */ + + sig = &(signerinfo->encDigest); + if (sig->len == 0) { /* bad signature */ + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); + goto done; + } + + if (sigkey != NULL) { + sec_PKCS7CipherObject *decryptobj; + unsigned int buflen; + + /* + * For signedAndEnvelopedData, we first must decrypt the encrypted + * digest with the bulk encryption key. The result is the normal + * encrypted digest (aka the signature). + */ + decryptobj = sec_PKCS7CreateDecryptObject(sigkey, bulkid); + if (decryptobj == NULL) + goto done; + + buflen = sec_PKCS7DecryptLength(decryptobj, sig->len, PR_TRUE); + PORT_Assert(buflen); + if (buflen == 0) { /* something is wrong */ + sec_PKCS7DestroyDecryptObject(decryptobj); + goto done; + } + + holder.data = (unsigned char *)PORT_Alloc(buflen); + if (holder.data == NULL) { + sec_PKCS7DestroyDecryptObject(decryptobj); + goto done; + } + + rv = sec_PKCS7Decrypt(decryptobj, holder.data, &holder.len, buflen, + sig->data, sig->len, PR_TRUE); + sec_PKCS7DestroyDecryptObject(decryptobj); + if (rv != SECSuccess) { + goto done; + } + + sig = &holder; + } + + goodsig = (PRBool)(VFY_VerifyDigestDirect(digest, publickey, sig, + encTag, digestTag, cinfo->pwfn_arg) == SECSuccess); + + if (sigkey != NULL) { + PORT_Assert(sig == &holder); + PORT_ZFree(holder.data, holder.len); + } } - if (! goodsig) { - /* - * XXX Change the generic error into our specific one, because - * in that case we get a better explanation out of the Security - * Advisor. This is really a bug in our error strings (the - * "generic" error has a lousy/wrong message associated with it - * which assumes the signature verification was done for the - * purposes of checking the issuer signature on a certificate) - * but this is at least an easy workaround and/or in the - * Security Advisor, which specifically checks for the error - * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation - * in that case but does not similarly check for - * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would - * probably say the wrong thing in the case that it *was* the - * certificate signature check that failed during the cert - * verification done above. Our error handling is really a mess. - */ - if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) - PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); + if (!goodsig) { + /* + * XXX Change the generic error into our specific one, because + * in that case we get a better explanation out of the Security + * Advisor. This is really a bug in our error strings (the + * "generic" error has a lousy/wrong message associated with it + * which assumes the signature verification was done for the + * purposes of checking the issuer signature on a certificate) + * but this is at least an easy workaround and/or in the + * Security Advisor, which specifically checks for the error + * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation + * in that case but does not similarly check for + * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would + * probably say the wrong thing in the case that it *was* the + * certificate signature check that failed during the cert + * verification done above. Our error handling is really a mess. + */ + if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE) + PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE); } savecert: @@ -1683,46 +1674,45 @@ savecert: * Only save the smime profile if we are checking an email message and * the cert has an email address in it. */ - if ( cert->emailAddr && cert->emailAddr[0] && - ( ( certusage == certUsageEmailSigner ) || - ( certusage == certUsageEmailRecipient ) ) ) { - SECItem *profile = NULL; - int save_error; - - /* - * Remember the current error set because we do not care about - * anything set by the functions we are about to call. - */ - save_error = PORT_GetError(); - - if (goodsig && (signerinfo->authAttr != NULL)) { - /* - * If the signature is good, then we can save the S/MIME profile, - * if we have one. - */ - SEC_PKCS7Attribute *attr; - - attr = sec_PKCS7FindAttribute (signerinfo->authAttr, - SEC_OID_PKCS9_SMIME_CAPABILITIES, - PR_TRUE); - profile = sec_PKCS7AttributeValue (attr); - } - - rv = CERT_SaveSMimeProfile (cert, profile, encoded_stime); - - /* - * Restore the saved error in case the calls above set a new - * one that we do not actually care about. - */ - PORT_SetError (save_error); - - /* - * XXX Failure is not indicated anywhere -- the signature - * verification itself is unaffected by whether or not the - * profile was successfully saved. - */ + if (cert->emailAddr && cert->emailAddr[0] && + ((certusage == certUsageEmailSigner) || + (certusage == certUsageEmailRecipient))) { + SECItem *profile = NULL; + int save_error; + + /* + * Remember the current error set because we do not care about + * anything set by the functions we are about to call. + */ + save_error = PORT_GetError(); + + if (goodsig && (signerinfo->authAttr != NULL)) { + /* + * If the signature is good, then we can save the S/MIME profile, + * if we have one. + */ + SEC_PKCS7Attribute *attr; + + attr = sec_PKCS7FindAttribute(signerinfo->authAttr, + SEC_OID_PKCS9_SMIME_CAPABILITIES, + PR_TRUE); + profile = sec_PKCS7AttributeValue(attr); + } + + rv = CERT_SaveSMimeProfile(cert, profile, encoded_stime); + + /* + * Restore the saved error in case the calls above set a new + * one that we do not actually care about. + */ + PORT_SetError(save_error); + + /* + * XXX Failure is not indicated anywhere -- the signature + * verification itself is unaffected by whether or not the + * profile was successfully saved. + */ } - done: @@ -1732,52 +1722,52 @@ done: */ if (certs != NULL) - CERT_DestroyCertArray (certs, certcount); + CERT_DestroyCertArray(certs, certcount); if (publickey != NULL) - SECKEY_DestroyPublicKey (publickey); + SECKEY_DestroyPublicKey(publickey); return goodsig; } /* * SEC_PKCS7VerifySignature - * Look at a PKCS7 contentInfo and check if the signature is good. - * The verification checks that the signing cert is valid and trusted - * for the purpose specified by "certusage". + * Look at a PKCS7 contentInfo and check if the signature is good. + * The verification checks that the signing cert is valid and trusted + * for the purpose specified by "certusage". * - * In addition, if "keepcerts" is true, add any new certificates found - * into our local database. + * In addition, if "keepcerts" is true, add any new certificates found + * into our local database. */ PRBool SEC_PKCS7VerifySignature(SEC_PKCS7ContentInfo *cinfo, - SECCertUsage certusage, - PRBool keepcerts) + SECCertUsage certusage, + PRBool keepcerts) { - return sec_pkcs7_verify_signature (cinfo, certusage, - NULL, HASH_AlgNULL, keepcerts, NULL); + return sec_pkcs7_verify_signature(cinfo, certusage, + NULL, HASH_AlgNULL, keepcerts, NULL); } /* * SEC_PKCS7VerifyDetachedSignature - * Look at a PKCS7 contentInfo and check if the signature matches - * a passed-in digest (calculated, supposedly, from detached contents). - * The verification checks that the signing cert is valid and trusted - * for the purpose specified by "certusage". + * Look at a PKCS7 contentInfo and check if the signature matches + * a passed-in digest (calculated, supposedly, from detached contents). + * The verification checks that the signing cert is valid and trusted + * for the purpose specified by "certusage". * - * In addition, if "keepcerts" is true, add any new certificates found - * into our local database. + * In addition, if "keepcerts" is true, add any new certificates found + * into our local database. */ PRBool SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo, - SECCertUsage certusage, - const SECItem *detached_digest, - HASH_HashType digest_type, - PRBool keepcerts) + SECCertUsage certusage, + const SECItem *detached_digest, + HASH_HashType digest_type, + PRBool keepcerts) { - return sec_pkcs7_verify_signature (cinfo, certusage, - detached_digest, digest_type, - keepcerts, NULL); + return sec_pkcs7_verify_signature(cinfo, certusage, + detached_digest, digest_type, + keepcerts, NULL); } /* @@ -1787,20 +1777,20 @@ SEC_PKCS7VerifyDetachedSignature(SEC_PKCS7ContentInfo *cinfo, * The verification checks that the signing cert is valid and trusted * for the purpose specified by "certusage" at time "atTime". * - * In addition, if "keepcerts" is true, add any new certificates found - * into our local database. + * In addition, if "keepcerts" is true, add any new certificates found + * into our local database. */ PRBool SEC_PKCS7VerifyDetachedSignatureAtTime(SEC_PKCS7ContentInfo *cinfo, - SECCertUsage certusage, - const SECItem *detached_digest, - HASH_HashType digest_type, - PRBool keepcerts, - PRTime atTime) + SECCertUsage certusage, + const SECItem *detached_digest, + HASH_HashType digest_type, + PRBool keepcerts, + PRTime atTime) { - return sec_pkcs7_verify_signature (cinfo, certusage, - detached_digest, digest_type, - keepcerts, &atTime); + return sec_pkcs7_verify_signature(cinfo, certusage, + detached_digest, digest_type, + keepcerts, &atTime); } /* @@ -1822,35 +1812,31 @@ sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector) CERTCertificate *signercert; char *container; - kind = SEC_PKCS7ContentType (cinfo); + kind = SEC_PKCS7ContentType(cinfo); switch (kind) { - default: - case SEC_OID_PKCS7_DATA: - case SEC_OID_PKCS7_DIGESTED_DATA: - case SEC_OID_PKCS7_ENVELOPED_DATA: - case SEC_OID_PKCS7_ENCRYPTED_DATA: - PORT_Assert (0); - return NULL; - case SEC_OID_PKCS7_SIGNED_DATA: - { - SEC_PKCS7SignedData *sdp; - - sdp = cinfo->content.signedData; - signerinfos = sdp->signerInfos; - } - break; - case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: - { - SEC_PKCS7SignedAndEnvelopedData *saedp; - - saedp = cinfo->content.signedAndEnvelopedData; - signerinfos = saedp->signerInfos; - } - break; + default: + case SEC_OID_PKCS7_DATA: + case SEC_OID_PKCS7_DIGESTED_DATA: + case SEC_OID_PKCS7_ENVELOPED_DATA: + case SEC_OID_PKCS7_ENCRYPTED_DATA: + PORT_Assert(0); + return NULL; + case SEC_OID_PKCS7_SIGNED_DATA: { + SEC_PKCS7SignedData *sdp; + + sdp = cinfo->content.signedData; + signerinfos = sdp->signerInfos; + } break; + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { + SEC_PKCS7SignedAndEnvelopedData *saedp; + + saedp = cinfo->content.signedAndEnvelopedData; + signerinfos = saedp->signerInfos; + } break; } if (signerinfos == NULL || signerinfos[0] == NULL) - return NULL; + return NULL; signercert = signerinfos[0]->cert; @@ -1858,33 +1844,33 @@ sec_pkcs7_get_signer_cert_info(SEC_PKCS7ContentInfo *cinfo, int selector) * No cert there; see if we can find one by calling verify ourselves. */ if (signercert == NULL) { - /* - * The cert usage does not matter in this case, because we do not - * actually care about the verification itself, but we have to pick - * some valid usage to pass in. - */ - (void) sec_pkcs7_verify_signature (cinfo, certUsageEmailSigner, - NULL, HASH_AlgNULL, PR_FALSE, NULL); - signercert = signerinfos[0]->cert; - if (signercert == NULL) - return NULL; + /* + * The cert usage does not matter in this case, because we do not + * actually care about the verification itself, but we have to pick + * some valid usage to pass in. + */ + (void)sec_pkcs7_verify_signature(cinfo, certUsageEmailSigner, + NULL, HASH_AlgNULL, PR_FALSE, NULL); + signercert = signerinfos[0]->cert; + if (signercert == NULL) + return NULL; } switch (selector) { - case sec_common_name: - container = CERT_GetCommonName (&signercert->subject); - break; - case sec_email_address: - if(signercert->emailAddr && signercert->emailAddr[0]) { - container = PORT_Strdup(signercert->emailAddr); - } else { - container = NULL; - } - break; - default: - PORT_Assert (0); - container = NULL; - break; + case sec_common_name: + container = CERT_GetCommonName(&signercert->subject); + break; + case sec_email_address: + if (signercert->emailAddr && signercert->emailAddr[0]) { + container = PORT_Strdup(signercert->emailAddr); + } else { + container = NULL; + } + break; + default: + PORT_Assert(0); + container = NULL; + break; } return container; @@ -1902,7 +1888,6 @@ SEC_PKCS7GetSignerEmailAddress(SEC_PKCS7ContentInfo *cinfo) return sec_pkcs7_get_signer_cert_info(cinfo, sec_email_address); } - /* * Return the signing time, in UTCTime format, of a PKCS7 contentInfo. */ @@ -1912,8 +1897,8 @@ SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo) SEC_PKCS7SignerInfo **signerinfos; SEC_PKCS7Attribute *attr; - if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA) - return NULL; + if (SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_SIGNED_DATA) + return NULL; signerinfos = cinfo->content.signedData->signerInfos; @@ -1921,9 +1906,9 @@ SEC_PKCS7GetSigningTime(SEC_PKCS7ContentInfo *cinfo) * No signature, or more than one, means no deal. */ if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL) - return NULL; + return NULL; - attr = sec_PKCS7FindAttribute (signerinfos[0]->authAttr, - SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); - return sec_PKCS7AttributeValue (attr); + attr = sec_PKCS7FindAttribute(signerinfos[0]->authAttr, + SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE); + return sec_PKCS7AttributeValue(attr); } |