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 + -
显示快捷键?