p7encode.c

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

C
1,330
字号
    CERTCertificate **certs;    CERTCertificateList **certlists;    SECAlgorithmID **digestalgs;    SECItem **digests;    SEC_PKCS7SignerInfo *signerinfo, **signerinfos;    SECItem **rawcerts, ***rawcertsp;    PRArenaPool *poolp;    int certcount;    int ci, cli, rci, si;    kind = SEC_PKCS7ContentType (cinfo);    switch (kind) {      default:      case SEC_OID_PKCS7_DATA:      case SEC_OID_PKCS7_DIGESTED_DATA:      case SEC_OID_PKCS7_ENCRYPTED_DATA:      case SEC_OID_PKCS7_ENVELOPED_DATA:	certs = NULL;	certlists = NULL;	digestalgs = NULL;	digests = NULL;	signerinfos = NULL;	rawcertsp = NULL;	break;      case SEC_OID_PKCS7_SIGNED_DATA:	{	    SEC_PKCS7SignedData *sdp;	    sdp = cinfo->content.signedData;	    certs = sdp->certs;	    certlists = sdp->certLists;	    digestalgs = sdp->digestAlgorithms;	    digests = sdp->digests;	    signerinfos = sdp->signerInfos;	    rawcertsp = &(sdp->rawCerts);	}	break;      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:	{	    SEC_PKCS7SignedAndEnvelopedData *saedp;	    saedp = cinfo->content.signedAndEnvelopedData;	    certs = saedp->certs;	    certlists = saedp->certLists;	    digestalgs = saedp->digestAlgorithms;	    digests = saedp->digests;	    signerinfos = saedp->signerInfos;	    rawcertsp = &(saedp->rawCerts);	}	break;    }    if (certs == NULL && certlists == NULL && signerinfos == NULL)	return SECSuccess;		/* nothing for us to do! */    poolp = cinfo->poolp;    certcount = 0;    if (signerinfos != NULL) {	SECOidTag digestalgtag;	int di;	SECStatus rv;	CERTCertificate *cert;	SECKEYPrivateKey *privkey;	SECItem signature;	SECOidTag signalgtag;	PORT_Assert (digestalgs != NULL && digests != NULL);	/*	 * If one fails, we bail right then.  If we want to continue and	 * try to do subsequent signatures, this loop, and the departures	 * from it, will need to be reworked.	 */	for (si = 0; signerinfos[si] != NULL; si++) {	    signerinfo = signerinfos[si];	    /* find right digest */	    digestalgtag = SECOID_GetAlgorithmTag (&(signerinfo->digestAlg));	    for (di = 0; digestalgs[di] != NULL; di++) {		/* XXX Should I be comparing more than the tag? */		if (digestalgtag == SECOID_GetAlgorithmTag (digestalgs[di]))		    break;	    }	    if (digestalgs[di] == NULL) {		/* XXX oops; do what? set an error? */		return SECFailure;	    }	    PORT_Assert (digests[di] != NULL);	    cert = signerinfo->cert;	    privkey = PK11_FindKeyByAnyCert (cert, pwfnarg);	    if (privkey == NULL)		return SECFailure;	    /*	     * XXX I think there should be a cert-level interface for this,	     * so that I do not have to know about subjectPublicKeyInfo...	     */	    signalgtag = SECOID_GetAlgorithmTag (&(cert->subjectPublicKeyInfo.algorithm));	    /* Fortezza MISSI have weird signature formats.  Map them	     * to standard DSA formats */	    signalgtag = PK11_FortezzaMapSig(signalgtag);	    if (signerinfo->authAttr != NULL) {		SEC_PKCS7Attribute *attr;		SECItem encoded_attrs;		SECItem *dummy;		/*		 * First, find and fill in the message digest attribute.		 */		attr = sec_PKCS7FindAttribute (signerinfo->authAttr,					       SEC_OID_PKCS9_MESSAGE_DIGEST,					       PR_TRUE);		PORT_Assert (attr != NULL);		if (attr == NULL) {		    SECKEY_DestroyPrivateKey (privkey);		    return SECFailure;		}		/*		 * XXX The second half of the following assertion prevents		 * the encoder from being called twice on the same content.		 * Either just remove the second half the assertion, or		 * change the code to check if the value already there is		 * the same as digests[di], whichever seems more right.		 */		PORT_Assert (attr->values != NULL && attr->values[0] == NULL);		attr->values[0] = digests[di];		/*		 * Before encoding, reorder the attributes so that when they		 * are encoded, they will be conforming DER, which is required		 * to have a specific order and that is what must be used for		 * the hash/signature.  We do this here, rather than building		 * it into EncodeAttributes, because we do not want to do		 * such reordering on incoming messages (which also uses		 * EncodeAttributes) or our old signatures (and other "broken"		 * implementations) will not verify.  So, we want to guarantee		 * that we send out good DER encodings of attributes, but not		 * to expect to receive them.		 */		rv = sec_PKCS7ReorderAttributes (signerinfo->authAttr);		if (rv != SECSuccess) {		    SECKEY_DestroyPrivateKey (privkey);		    return SECFailure;		}		encoded_attrs.data = NULL;		encoded_attrs.len = 0;		dummy = sec_PKCS7EncodeAttributes (NULL, &encoded_attrs,						   &(signerinfo->authAttr));		if (dummy == NULL) {		    SECKEY_DestroyPrivateKey (privkey);		    return SECFailure;		}		rv = SEC_SignData (&signature,				   encoded_attrs.data, encoded_attrs.len,				   privkey,				   sec_pkcs7_pick_sign_alg (digestalgtag,							    signalgtag));		SECITEM_FreeItem (&encoded_attrs, PR_FALSE);	    } else {		rv = SGN_Digest (privkey, digestalgtag, &signature,				 digests[di]);	    }	    SECKEY_DestroyPrivateKey (privkey);	    if (rv != SECSuccess)		return rv;	    rv = SECITEM_CopyItem (poolp, &(signerinfo->encDigest), &signature);	    if (rv != SECSuccess)		return rv;	    SECITEM_FreeItem (&signature, PR_FALSE);	    rv = SECOID_SetAlgorithmID (poolp, &(signerinfo->digestEncAlg),					signalgtag, NULL);	    if (rv != SECSuccess)		return SECFailure;	    /*	     * Count the cert chain for this signer.	     */	    if (signerinfo->certList != NULL)		certcount += signerinfo->certList->len;	}    }    if (certs != NULL) {	for (ci = 0; certs[ci] != NULL; ci++)	    certcount++;    }    if (certlists != NULL) {	for (cli = 0; certlists[cli] != NULL; cli++)	    certcount += certlists[cli]->len;    }    if (certcount == 0)	return SECSuccess;		/* signing done; no certs */    /*     * Combine all of the certs and cert chains into rawcerts.     * Note: certcount is an upper bound; we may not need that many slots     * but we will allocate anyway to avoid having to do another pass.     * (The temporary space saving is not worth it.)     */    rawcerts = (SECItem**)PORT_ArenaAlloc (poolp, 					(certcount + 1) * sizeof(SECItem *));    if (rawcerts == NULL)	return SECFailure;    /*     * XXX Want to check for duplicates and not add *any* cert that is     * already in the set.  This will be more important when we start     * dealing with larger sets of certs, dual-key certs (signing and     * encryption), etc.  For the time being we can slide by...     */    rci = 0;    if (signerinfos != NULL) {	for (si = 0; signerinfos[si] != NULL; si++) {	    signerinfo = signerinfos[si];	    for (ci = 0; ci < signerinfo->certList->len; ci++)		rawcerts[rci++] = &(signerinfo->certList->certs[ci]);	}    }    if (certs != NULL) {	for (ci = 0; certs[ci] != NULL; ci++)	    rawcerts[rci++] = &(certs[ci]->derCert);    }    if (certlists != NULL) {	for (cli = 0; certlists[cli] != NULL; cli++) {	    for (ci = 0; ci < certlists[cli]->len; ci++)		rawcerts[rci++] = &(certlists[cli]->certs[ci]);	}    }    rawcerts[rci] = NULL;    *rawcertsp = rawcerts;    return SECSuccess;}SECStatusSEC_PKCS7EncoderFinish (SEC_PKCS7EncoderContext *p7ecx,			SECKEYGetPasswordKey pwfn, void *pwfnarg){    SECStatus rv;    /*     * Flush out any remaining data.     */    rv = sec_pkcs7_encoder_work_data (p7ecx, NULL, NULL, 0, PR_TRUE);    /*     * Turn off streaming stuff.     */    SEC_ASN1EncoderClearTakeFromBuf (p7ecx->ecx);    SEC_ASN1EncoderClearStreaming (p7ecx->ecx);    if (rv != SECSuccess)	goto loser;    rv = sec_pkcs7_encoder_sig_and_certs (p7ecx->cinfo, pwfn, pwfnarg);    if (rv != SECSuccess)	goto loser;    rv = SEC_ASN1EncoderUpdate (p7ecx->ecx, NULL, 0);loser:    SEC_ASN1EncoderFinish (p7ecx->ecx);    PORT_Free (p7ecx);    return rv;}/* * After this routine is called, the entire PKCS7 contentInfo is ready * to be encoded.  This is used internally, but can also be called from * elsewhere for those who want to be able to just have pointers to * the ASN1 template for pkcs7 contentInfo built into their own encodings. */SECStatusSEC_PKCS7PrepareForEncode (SEC_PKCS7ContentInfo *cinfo,			   PK11SymKey *bulkkey,			   SECKEYGetPasswordKey pwfn,			   void *pwfnarg){    SEC_PKCS7EncoderContext *p7ecx;    SECItem *content, *enc_content;    SECStatus rv;    p7ecx = sec_pkcs7_encoder_start_contexts (cinfo, bulkkey);    if (p7ecx == NULL)	return SECFailure;    content = SEC_PKCS7GetContent (cinfo);    if (p7ecx->encryptobj != NULL) {	SECOidTag kind;	SEC_PKCS7EncryptedContentInfo *enccinfo;	kind = SEC_PKCS7ContentType (p7ecx->cinfo);	switch (kind) {	  default:	    PORT_Assert (0);	    rv = SECFailure;	    goto loser;	  case SEC_OID_PKCS7_ENCRYPTED_DATA:	    enccinfo = &(p7ecx->cinfo->content.encryptedData->encContentInfo);	    break;	  case SEC_OID_PKCS7_ENVELOPED_DATA:	    enccinfo = &(p7ecx->cinfo->content.envelopedData->encContentInfo);	    break;	  case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:	    enccinfo = &(p7ecx->cinfo->content.signedAndEnvelopedData->encContentInfo);	    break;	}	enc_content = &(enccinfo->encContent);    } else {	enc_content = NULL;    }    if (content != NULL && content->data != NULL && content->len) {	rv = sec_pkcs7_encoder_work_data (p7ecx, enc_content,					  content->data, content->len, PR_TRUE);	if (rv != SECSuccess)	    goto loser;    }    rv = sec_pkcs7_encoder_sig_and_certs (cinfo, pwfn, pwfnarg);loser:    PORT_Free (p7ecx);    return rv;}/* * Encode a PKCS7 object, in one shot.  All necessary components * of the object must already be specified.  Either the data has * already been included (via SetContent), or the data is detached, * or there is no data at all (certs-only). * * "cinfo" specifies the object to be encoded. * * "outputfn" is where the encoded bytes will be passed. * * "outputarg" is an opaque argument to the above callback. * * "bulkkey" specifies the bulk encryption key to use.   This argument * can be NULL if no encryption is being done, or if the bulk key should * be generated internally (usually the case for EnvelopedData but never * for EncryptedData, which *must* provide a bulk encryption key). * * "pwfn" is a callback for getting the password which protects the * private key of the signer.  This argument can be NULL if it is known * that no signing is going to be done. * * "pwfnarg" is an opaque argument to the above callback. */SECStatusSEC_PKCS7Encode (SEC_PKCS7ContentInfo *cinfo,		 SEC_PKCS7EncoderOutputCallback outputfn,		 void *outputarg,		 PK11SymKey *bulkkey,		 SECKEYGetPasswordKey pwfn,		 void *pwfnarg){    SECStatus rv;    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);    if (rv == SECSuccess) {	struct sec_pkcs7_encoder_output outputcx;	outputcx.outputfn = outputfn;	outputcx.outputarg = outputarg;	rv = SEC_ASN1Encode (cinfo, sec_PKCS7ContentInfoTemplate,			     sec_pkcs7_encoder_out, &outputcx);    }    return rv;}/* * Encode a PKCS7 object, in one shot.  All necessary components * of the object must already be specified.  Either the data has * already been included (via SetContent), or the data is detached, * or there is no data at all (certs-only).  The output, rather than * being passed to an output function as is done above, is all put * into a SECItem. * * "pool" specifies a pool from which to allocate the result. * It can be NULL, in which case memory is allocated generically. * * "dest" specifies a SECItem in which to put the result data. * It can be NULL, in which case the entire item is allocated, too. * * "cinfo" specifies the object to be encoded. * * "bulkkey" specifies the bulk encryption key to use.   This argument * can be NULL if no encryption is being done, or if the bulk key should * be generated internally (usually the case for EnvelopedData but never * for EncryptedData, which *must* provide a bulk encryption key). * * "pwfn" is a callback for getting the password which protects the * private key of the signer.  This argument can be NULL if it is known * that no signing is going to be done. * * "pwfnarg" is an opaque argument to the above callback. */SECItem *SEC_PKCS7EncodeItem (PRArenaPool *pool,		     SECItem *dest,		     SEC_PKCS7ContentInfo *cinfo,		     PK11SymKey *bulkkey,		     SECKEYGetPasswordKey pwfn,		     void *pwfnarg){    SECStatus rv;    rv = SEC_PKCS7PrepareForEncode (cinfo, bulkkey, pwfn, pwfnarg);    if (rv != SECSuccess)	return NULL;    return SEC_ASN1EncodeItem (pool, dest, cinfo, sec_PKCS7ContentInfoTemplate);}

⌨️ 快捷键说明

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