p7encode.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,330 行 · 第 1/3 页
C
1,330 行
digd = cinfo->content.digestedData; if (digd == NULL) break; if (dest == &(digd->contentInfo.content)) before_content = PR_TRUE; } break; case SEC_OID_PKCS7_ENCRYPTED_DATA: { SEC_PKCS7EncryptedData *encd; encd = cinfo->content.encryptedData; if (encd == NULL) break; if (dest == &(encd->encContentInfo.encContent)) before_content = PR_TRUE; } break; case SEC_OID_PKCS7_ENVELOPED_DATA: { SEC_PKCS7EnvelopedData *envd; envd = cinfo->content.envelopedData; if (envd == NULL) break; if (dest == &(envd->encContentInfo.encContent)) before_content = PR_TRUE; } break; case SEC_OID_PKCS7_SIGNED_DATA: { SEC_PKCS7SignedData *sigd; sigd = cinfo->content.signedData; if (sigd == NULL) break; if (dest == &(sigd->contentInfo.content)) before_content = PR_TRUE; } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saed; saed = cinfo->content.signedAndEnvelopedData; if (saed == NULL) break; if (dest == &(saed->encContentInfo.encContent)) before_content = PR_TRUE; } break; } if (before_content) { /* * This will cause the next SEC_ASN1EncoderUpdate to take the * contents bytes from the passed-in buffer. */ SEC_ASN1EncoderSetTakeFromBuf (p7ecx->ecx); /* * And that is all we needed this notify function for. */ SEC_ASN1EncoderClearNotifyProc (p7ecx->ecx); }}static SEC_PKCS7EncoderContext *sec_pkcs7_encoder_start_contexts (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *bulkkey){ SEC_PKCS7EncoderContext *p7ecx; SECOidTag kind; PRBool encrypt; SECItem **digests; SECAlgorithmID *digestalg, **digestalgs; p7ecx = (SEC_PKCS7EncoderContext*)PORT_ZAlloc (sizeof(SEC_PKCS7EncoderContext)); if (p7ecx == NULL) return NULL; digests = NULL; digestalg = NULL; digestalgs = NULL; encrypt = PR_FALSE; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { default: case SEC_OID_PKCS7_DATA: break; case SEC_OID_PKCS7_DIGESTED_DATA: digestalg = &(cinfo->content.digestedData->digestAlg); break; case SEC_OID_PKCS7_SIGNED_DATA: digests = cinfo->content.signedData->digests; digestalgs = cinfo->content.signedData->digestAlgorithms; break; case SEC_OID_PKCS7_ENCRYPTED_DATA: case SEC_OID_PKCS7_ENVELOPED_DATA: encrypt = PR_TRUE; break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: digests = cinfo->content.signedAndEnvelopedData->digests; digestalgs = cinfo->content.signedAndEnvelopedData->digestAlgorithms; encrypt = PR_TRUE; break; } if (encrypt) { p7ecx->encryptobj = sec_pkcs7_encoder_start_encrypt (cinfo, bulkkey); if (p7ecx->encryptobj == NULL) { PORT_Free (p7ecx); return NULL; } } if (digestalgs != NULL) { if (digests != NULL) { /* digests already created (probably for detached data) */ digestalg = NULL; } else { /* * XXX Some day we should handle multiple digests; for now, * assume only one will be done. */ PORT_Assert (digestalgs[0] != NULL && digestalgs[1] == NULL); digestalg = digestalgs[0]; } } if (digestalg != NULL) { SECOidData *oiddata; oiddata = SECOID_FindOID (&(digestalg->algorithm)); if (oiddata != NULL) { switch (oiddata->offset) { case SEC_OID_MD2: p7ecx->digestobj = &SECHashObjects[HASH_AlgMD2]; break; case SEC_OID_MD5: p7ecx->digestobj = &SECHashObjects[HASH_AlgMD5]; break; case SEC_OID_SHA1: p7ecx->digestobj = &SECHashObjects[HASH_AlgSHA1]; break; default: /* XXX right error? */ PORT_SetError (SEC_ERROR_INVALID_ALGORITHM); break; } } if (p7ecx->digestobj != NULL) { p7ecx->digestcx = (* p7ecx->digestobj->create) (); if (p7ecx->digestcx == NULL) p7ecx->digestobj = NULL; else (* p7ecx->digestobj->begin) (p7ecx->digestcx); } if (p7ecx->digestobj == NULL) { if (p7ecx->encryptobj != NULL) sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj); PORT_Free (p7ecx); return NULL; } } p7ecx->cinfo = cinfo; return p7ecx;}SEC_PKCS7EncoderContext *SEC_PKCS7EncoderStart (SEC_PKCS7ContentInfo *cinfo, SEC_PKCS7EncoderOutputCallback outputfn, void *outputarg, PK11SymKey *bulkkey){ SEC_PKCS7EncoderContext *p7ecx; SECStatus rv; p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey); if (p7ecx == NULL) return NULL; p7ecx->output.outputfn = outputfn; p7ecx->output.outputarg = outputarg; /* * Initialize the BER encoder. */ p7ecx->ecx = SEC_ASN1EncoderStart (cinfo, sec_PKCS7ContentInfoTemplate, sec_pkcs7_encoder_out, &(p7ecx->output)); if (p7ecx->ecx == NULL) { PORT_Free (p7ecx); return NULL; } /* * Indicate that we are streaming. We will be streaming until we * get past the contents bytes. */ SEC_ASN1EncoderSetStreaming (p7ecx->ecx); /* * The notify function will watch for the contents field. */ SEC_ASN1EncoderSetNotifyProc (p7ecx->ecx, sec_pkcs7_encoder_notify, p7ecx); /* * This will encode everything up to the content bytes. (The notify * function will then cause the encoding to stop there.) Then our * caller can start passing contents bytes to our Update, which we * will pass along. */ rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0); if (rv != SECSuccess) { PORT_Free (p7ecx); return NULL; } return p7ecx;}/* * XXX If/when we support nested contents, this needs to be revised. */static SECStatussec_pkcs7_encoder_work_data (SEC_PKCS7EncoderContext *p7ecx, SECItem *dest, const unsigned char *data, unsigned long len, PRBool final){ unsigned char *buf = NULL; SECStatus rv; rv = SECSuccess; /* may as well be optimistic */ /* * We should really have data to process, or we should be trying * to finish/flush the last block. (This is an overly paranoid * check since all callers are in this file and simple inspection * 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); /* * Update the running digest. * XXX This needs modification if/when we handle multiple digests. */ if (len && p7ecx->digestobj != NULL) { (* p7ecx->digestobj->update) (p7ecx->digestcx, data, len); } /* * Encrypt this chunk. */ if (p7ecx->encryptobj != NULL) { /* XXX the following lengths should all be longs? */ 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 = sec_PKCS7EncryptLength (p7ecx->encryptobj, inlen, final); if (buflen == 0) { /* * No output is expected, but the input data may be buffered * so we still have to call Encrypt. */ rv = sec_PKCS7Encrypt (p7ecx->encryptobj, NULL, NULL, 0, data, inlen, final); if (final) { len = 0; goto done; } return rv; } if (dest != NULL) buf = (unsigned char*)PORT_ArenaAlloc(p7ecx->cinfo->poolp, buflen); else buf = (unsigned char*)PORT_Alloc (buflen); if (buf == NULL) { rv = SECFailure; } else { rv = sec_PKCS7Encrypt (p7ecx->encryptobj, buf, &outlen, buflen, data, inlen, final); data = buf; len = outlen; } if (rv != SECSuccess) { if (final) goto done; return rv; } } if (p7ecx->ecx != NULL) { /* * Encode the contents bytes. */ if(len) { rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, (const char *)data, len); } }done: if (p7ecx->encryptobj != NULL) { if (final) sec_PKCS7DestroyEncryptObject (p7ecx->encryptobj); if (dest != NULL) { dest->data = buf; dest->len = len; } else if (buf != NULL) { PORT_Free (buf); } } if (final && p7ecx->digestobj != NULL) { SECItem *digest, **digests, ***digestsp; unsigned char *digdata; SECOidTag kind; kind = SEC_PKCS7ContentType (p7ecx->cinfo); switch (kind) { default: PORT_Assert (0); return SECFailure; case SEC_OID_PKCS7_DIGESTED_DATA: digest = &(p7ecx->cinfo->content.digestedData->digest); digestsp = NULL; break; case SEC_OID_PKCS7_SIGNED_DATA: digest = NULL; digestsp = &(p7ecx->cinfo->content.signedData->digests); break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: digest = NULL; digestsp = &(p7ecx->cinfo->content.signedAndEnvelopedData->digests); break; } digdata = (unsigned char*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, p7ecx->digestobj->length); if (digdata == NULL) return SECFailure; if (digestsp != NULL) { PORT_Assert (digest == NULL); digest = (SECItem*)PORT_ArenaAlloc (p7ecx->cinfo->poolp, sizeof(SECItem)); digests = (SECItem**)PORT_ArenaAlloc (p7ecx->cinfo->poolp, 2 * sizeof(SECItem *)); if (digests == NULL || digest == NULL) return SECFailure; digests[0] = digest; digests[1] = NULL; *digestsp = digests; } PORT_Assert (digest != NULL); digest->data = digdata; digest->len = p7ecx->digestobj->length; (* p7ecx->digestobj->end) (p7ecx->digestcx, digest->data, &(digest->len), digest->len); (* p7ecx->digestobj->destroy) (p7ecx->digestcx, PR_TRUE); } return rv;}SECStatusSEC_PKCS7EncoderUpdate (SEC_PKCS7EncoderContext *p7ecx, const char *data, unsigned long len){ /* XXX Error handling needs help. Return what? Do "Finish" on failure? */ return sec_pkcs7_encoder_work_data (p7ecx, NULL, (const unsigned char *)data, len, PR_FALSE);}/* * XXX I would *really* like to not have to do this, but the current * signing interface gives me little choice. */static SECOidTagsec_pkcs7_pick_sign_alg (SECOidTag hashalg, SECOidTag encalg){ switch (encalg) { case SEC_OID_PKCS1_RSA_ENCRYPTION: switch (hashalg) { case SEC_OID_MD2: return SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; case SEC_OID_MD5: return SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; case SEC_OID_SHA1: return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; default: return SEC_OID_UNKNOWN; } case SEC_OID_ANSIX9_DSA_SIGNATURE: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_DSS: switch (hashalg) { case SEC_OID_SHA1: return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; default: return SEC_OID_UNKNOWN; } default: break; } return encalg; /* maybe it is already the right algid */}static SECStatussec_pkcs7_encoder_sig_and_certs (SEC_PKCS7ContentInfo *cinfo, SECKEYGetPasswordKey pwfn, void *pwfnarg){ SECOidTag kind;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?