p7decode.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,088 行 · 第 1/4 页

C
2,088
字号
	     senderPubKey = 		  PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,				     keaParams.originatorKEAKey.len);	     if (senderPubKey == NULL)	     {		    p7dcx->error = PORT_GetError();		    PORT_SetError(0);		    goto no_key_found;	     }	      	     /* Generate the TEK (token exchange key) which we use	         to unwrap the bulk encryption key. */	     tek = PK11_PubDerive(privkey, senderPubKey, 				   PR_FALSE,				   &keaParams.originatorRA,				   NULL,				   CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,				   CKA_WRAP, 0, p7dcx->pwfn_arg);	     SECKEY_DestroyPublicKey(senderPubKey);	      	     if (tek == NULL)	     {		  p7dcx->error = PORT_GetError();		  PORT_SetError(0);		  goto no_key_found;	     }	      	      /* Now that we have the TEK, unwrap the bulk key	         with which to decrypt the message. We have to		 do one of two different things depending on 		 whether Skipjack was used for bulk encryption 		 of the message. */	      bulkType = PK11_AlgtagToMechanism (bulkalgtag);	      switch(bulkType)	      {	      case CKM_SKIPJACK_CBC64:	      case CKM_SKIPJACK_ECB64:	      case CKM_SKIPJACK_OFB64:	      case CKM_SKIPJACK_CFB64:	      case CKM_SKIPJACK_CFB32:	      case CKM_SKIPJACK_CFB16:	      case CKM_SKIPJACK_CFB8:		  /* Skipjack is being used as the bulk encryption algorithm.*/		  /* Unwrap the bulk key. */		  bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP,					      NULL, &ri->encKey, 					      CKM_SKIPJACK_CBC64, 					      CKA_DECRYPT, 0);		  break;	      default:		  /* Skipjack was not used for bulk encryption of this		     message. Use Skipjack CBC64, with the nonSkipjackIV		     part of the KEA key parameters, to decrypt 		     the bulk key. If we got a parameter indicating that the		     bulk key size is different than the encrypted key size,		     pass in the real key size. */		  		  /* Check for specified bulk key length (unspecified implies		     that the bulk key length is the same as encrypted length) */		  if (keaParams.bulkKeySize.len > 0)		  {		      p7dcx->error = SEC_ASN1DecodeItem(NULL, &bulkLength,							SEC_IntegerTemplate,							&keaParams.bulkKeySize);		  }		  		  if (p7dcx->error != SECSuccess)		      goto no_key_found;		  		  bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_CBC64,					      &keaParams.nonSkipjackIV, 					      &ri->encKey,					      bulkType,					      CKA_DECRYPT, bulkLength);	      }	      	      	      if (bulkkey == NULL)	      {		  p7dcx->error = PORT_GetError();		  PORT_SetError(0);		  goto no_key_found;	      }	      break;	  }      default:	p7dcx->error = SEC_ERROR_UNSUPPORTED_KEYALG;	goto no_key_found;    }    return bulkkey;no_key_found:    if (privkey != NULL)	SECKEY_DestroyPrivateKey (privkey);    return NULL;} /* * XXX The following comment is old -- the function used to only handle * EnvelopedData or SignedAndEnvelopedData but now handles EncryptedData * as well (and it had all of the code of the helper function above * built into it), though the comment was left as is.  Fix it... * * We are just about to decode the content of an EnvelopedData. * Set up a decryption context so we can decrypt as we go. * Presumably we are one of the recipients listed in "recipientinfos". * (XXX And if we are not, or if we have trouble, what should we do? *  It would be nice to let the decoding still work.  Maybe it should *  be an error if there is a content callback, but not an error otherwise?) * The encryption key and related information can be found in "enccinfo". */static SECStatussec_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,      * for instance, for Encrypted Content infos, then retrieve     * the bulkkey from the callback.  Otherwise, assume that     * we are processing Enveloped or SignedAndEnveloped data     * content infos.     *     * 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;    } else {	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;    }        /*      * 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;	}    } else {	    p7dcx->error = SEC_ERROR_DECRYPTION_DISALLOWED;	    goto no_decryption;    }    /*     * When decrypting a signedAndEnvelopedData, the signature also has     * to be decrypted with the bulk encryption key; to avoid having to     * get it all over again later (and do another potentially expensive     * RSA operation), copy it for later signature verification to use.     */    if (copy_key_for_signature != NULL)	*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));    /*      * For PKCS5 Encryption Algorithms, the bulkkey is actually a different     * structure.  Therefore, we need to set the bulkkey to the actual key      * prior to freeing it.     */    if ( SEC_PKCS5IsAlgorithmPBEAlg(&(enccinfo->contentEncAlg)) && bulkkey ) {	SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;	bulkkey = keyPwd->key;    }    /*     * We are done with (this) bulkkey now.     */    PK11_FreeSymKey (bulkkey);    if (decryptobj == NULL) {	p7dcx->error = PORT_GetError();	PORT_SetError(0);	goto no_decryption;    }    SEC_ASN1DecoderSetFilterProc (p7dcx->dcx,				  sec_pkcs7_decoder_filter,				  p7dcx,				  (PRBool)(p7dcx->cb != NULL));    p7dcx->worker.depth = depth;    p7dcx->worker.decryptobj = decryptobj;    return SECSuccess;no_decryption:    /*     * For some reason (error set already, if appropriate), we cannot     * decrypt the content.  I am not sure what exactly is the right     * thing to do here; in some cases we want to just stop, and in     * others we want to let the decoding finish even though we cannot     * decrypt the content.  My current thinking is that if the caller     * set up a content callback, then they are really interested in     * getting (decrypted) content, and if they cannot they will want     * to know about it.  However, if no callback was specified, then     * maybe it is not important that the decryption failed.     */    if (p7dcx->cb != NULL)	return SECFailure;    else	return SECSuccess;	/* Let the decoding continue. */}static SECStatussec_pkcs7_decoder_finish_decrypt (SEC_PKCS7DecoderContext *p7dcx,				  PRArenaPool *poolp,				  SEC_PKCS7EncryptedContentInfo *enccinfo){    struct sec_pkcs7_decoder_worker *worker;    /*     * XXX Handling nested contents would mean that there is a chain     * of workers -- one per each level of content.  The following     * would want to find the last worker in the chain.     */    worker = &(p7dcx->worker);    /*     * If no decryption context, then we have nothing to do.     */    if (worker->decryptobj == NULL)	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);    /*     * Handle the last block.     */    sec_pkcs7_decoder_work_data (p7dcx, worker, NULL, 0, PR_TRUE);    /*     * All done, destroy it.     */    sec_PKCS7DestroyDecryptObject (worker->decryptobj);    return SECSuccess;}static voidsec_pkcs7_decoder_notify (void *arg, PRBool before, void *dest, int depth){    SEC_PKCS7DecoderContext *p7dcx;    SEC_PKCS7ContentInfo *cinfo;    SEC_PKCS7SignedData *sigd;    SEC_PKCS7EnvelopedData *envd;    SEC_PKCS7SignedAndEnvelopedData *saed;    SEC_PKCS7EncryptedData *encd;    SEC_PKCS7DigestedData *digd;    PRBool after;    SECStatus rv;    /*     * Just to make the code easier to read, create an "after" variable     * that is equivalent to "not before".     * (This used to be just the statement "after = !before", but that     * causes a warning on the mac; to avoid that, we do it the long way.)     */    if (before)	after = PR_FALSE;    else	after = PR_TRUE;    p7dcx = (SEC_PKCS7DecoderContext*)arg;    cinfo = p7dcx->cinfo;    if (cinfo->contentTypeTag == NULL) {	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;	/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?