p7create.c

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

C
1,321
字号
    PORT_Assert (poolp != NULL);    mark = PORT_ArenaMark (poolp);    attr = (SEC_PKCS7Attribute*)PORT_ArenaAlloc (poolp, 						 sizeof(SEC_PKCS7Attribute));    if (attr == NULL)	goto loser;    attr->typeTag = SECOID_FindOIDByTag (oidtag);    if (attr->typeTag == NULL)	goto loser;    if (SECITEM_CopyItem (poolp, &(attr->type),			  &(attr->typeTag->oid)) != SECSuccess)	goto loser;    values = (SECItem**)PORT_ArenaAlloc (poolp, 2 * sizeof(SECItem *));    if (values == NULL)	goto loser;    if (value != NULL) {	SECItem *copy;	copy = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));	if (copy == NULL)	    goto loser;	if (SECITEM_CopyItem (poolp, copy, value) != SECSuccess)	    goto loser;	value = copy;    }    values[0] = value;    values[1] = NULL;    attr->values = values;    attr->encoded = encoded;    PORT_ArenaUnmark (poolp, mark);    return attr;loser:    PORT_Assert (mark != NULL);    PORT_ArenaRelease (poolp, mark);    return NULL;}static SECStatussec_pkcs7_add_attribute (SEC_PKCS7ContentInfo *cinfo,			 SEC_PKCS7Attribute ***attrsp,			 SEC_PKCS7Attribute *attr){    SEC_PKCS7Attribute **attrs;    SECItem *ct_value;    void *mark;    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)	return SECFailure;    attrs = *attrsp;    if (attrs != NULL) {	int count;	/*	 * We already have some attributes, and just need to add this	 * new one.	 */	/*	 * We should already have the *required* attributes, which were	 * created/added at the same time the first attribute was added.	 */	PORT_Assert (sec_PKCS7FindAttribute (attrs,					     SEC_OID_PKCS9_CONTENT_TYPE,					     PR_FALSE) != NULL);	PORT_Assert (sec_PKCS7FindAttribute (attrs,					     SEC_OID_PKCS9_MESSAGE_DIGEST,					     PR_FALSE) != NULL);	for (count = 0; attrs[count] != NULL; count++)	    ;	attrs = (SEC_PKCS7Attribute**)PORT_ArenaGrow (cinfo->poolp, attrs,				(count + 1) * sizeof(SEC_PKCS7Attribute *),				(count + 2) * sizeof(SEC_PKCS7Attribute *));	if (attrs == NULL)	    return SECFailure;	attrs[count] = attr;	attrs[count+1] = NULL;	*attrsp = attrs;	return SECSuccess;    }    /*     * This is the first time an attribute is going in.     * We need to create and add the required attributes, and then     * we will also add in the one our caller gave us.     */    /*     * There are 2 required attributes, plus the one our caller wants     * to add, plus we always end with a NULL one.  Thus, four slots.     */    attrs = (SEC_PKCS7Attribute**)PORT_ArenaAlloc (cinfo->poolp, 					   4 * sizeof(SEC_PKCS7Attribute *));    if (attrs == NULL)	return SECFailure;    mark = PORT_ArenaMark (cinfo->poolp);    /*     * First required attribute is the content type of the data     * being signed.     */    ct_value = &(cinfo->content.signedData->contentInfo.contentType);    attrs[0] = sec_pkcs7_create_attribute (cinfo->poolp,					   SEC_OID_PKCS9_CONTENT_TYPE,					   ct_value, PR_FALSE);    /*     * Second required attribute is the message digest of the data     * being signed; we leave the value NULL for now (just create     * the place for it to go), and the encoder will fill it in later.     */    attrs[1] = sec_pkcs7_create_attribute (cinfo->poolp,					   SEC_OID_PKCS9_MESSAGE_DIGEST,					   NULL, PR_FALSE);    if (attrs[0] == NULL || attrs[1] == NULL) {	PORT_ArenaRelease (cinfo->poolp, mark);	return SECFailure;     }    attrs[2] = attr;    attrs[3] = NULL;    *attrsp = attrs;    PORT_ArenaUnmark (cinfo->poolp, mark);    return SECSuccess;}/* * Add the signing time to the authenticated (i.e. signed) attributes * of "cinfo".  This is expected to be included in outgoing signed * messages for email (S/MIME) but is likely useful in other situations. * * This should only be added once; a second call will either do * nothing or replace an old signing time with a newer one. * * XXX This will probably just shove the current time into "cinfo" * but it will not actually get signed until the entire item is * processed for encoding.  Is this (expected to be small) delay okay? * * "cinfo" should be of type signedData (the only kind of pkcs7 data * that is allowed authenticated attributes); SECFailure will be returned * if it is not. */SECStatusSEC_PKCS7AddSigningTime (SEC_PKCS7ContentInfo *cinfo){    SEC_PKCS7SignerInfo **signerinfos;    SEC_PKCS7Attribute *attr;    SECItem stime;    SECStatus rv;    int si;    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)	return SECFailure;    signerinfos = cinfo->content.signedData->signerInfos;    /* There has to be a signer, or it makes no sense. */    if (signerinfos == NULL || signerinfos[0] == NULL)	return SECFailure;    rv = DER_TimeToUTCTime (&stime, PR_Now());    if (rv != SECSuccess)	return rv;    attr = sec_pkcs7_create_attribute (cinfo->poolp,				       SEC_OID_PKCS9_SIGNING_TIME,				       &stime, PR_FALSE);    SECITEM_FreeItem (&stime, PR_FALSE);    if (attr == NULL)	return SECFailure;    rv = SECSuccess;    for (si = 0; signerinfos[si] != NULL; si++) {	SEC_PKCS7Attribute *oattr;	oattr = sec_PKCS7FindAttribute (signerinfos[si]->authAttr,					SEC_OID_PKCS9_SIGNING_TIME, PR_FALSE);	PORT_Assert (oattr == NULL);	if (oattr != NULL)	    continue;	/* XXX or would it be better to replace it? */	rv = sec_pkcs7_add_attribute (cinfo, &(signerinfos[si]->authAttr),				      attr);	if (rv != SECSuccess)	    break;	/* could try to continue, but may as well give up now */    }    return rv;}/* * Add the specified attribute to the authenticated (i.e. signed) attributes * of "cinfo" -- "oidtag" describes the attribute and "value" is the * value to be associated with it.  NOTE! "value" must already be encoded; * no interpretation of "oidtag" is done.  Also, it is assumed that this * signedData has only one signer -- if we ever need to add attributes * when there is more than one signature, we need a way to specify *which* * signature should get the attribute. * * XXX Technically, a signed attribute can have multiple values; if/when * we ever need to support an attribute which takes multiple values, we * either need to change this interface or create an AddSignedAttributeValue * which can be called subsequently, and would then append a value. * * "cinfo" should be of type signedData (the only kind of pkcs7 data * that is allowed authenticated attributes); SECFailure will be returned * if it is not. */SECStatusSEC_PKCS7AddSignedAttribute (SEC_PKCS7ContentInfo *cinfo,			     SECOidTag oidtag,			     SECItem *value){    SEC_PKCS7SignerInfo **signerinfos;    SEC_PKCS7Attribute *attr;    PORT_Assert (SEC_PKCS7ContentType (cinfo) == SEC_OID_PKCS7_SIGNED_DATA);    if (SEC_PKCS7ContentType (cinfo) != SEC_OID_PKCS7_SIGNED_DATA)	return SECFailure;    signerinfos = cinfo->content.signedData->signerInfos;    /*     * No signature or more than one means no deal.     */    if (signerinfos == NULL || signerinfos[0] == NULL || signerinfos[1] != NULL)	return SECFailure;    attr = sec_pkcs7_create_attribute (cinfo->poolp, oidtag, value, PR_TRUE);    if (attr == NULL)	return SECFailure;    return sec_pkcs7_add_attribute (cinfo, &(signerinfos[0]->authAttr), attr);} /* * Mark that the signer certificates and their issuing chain should * be included in the encoded data.  This is expected to be used * in outgoing signed messages for email (S/MIME). * * "certdb" is the cert database to use for finding the chain. * It can be NULL, meaning use the default database. * * "cinfo" should be of type signedData or signedAndEnvelopedData; * SECFailure will be returned if it is not. */SECStatusSEC_PKCS7IncludeCertChain (SEC_PKCS7ContentInfo *cinfo,			   CERTCertDBHandle *certdb){    SECOidTag kind;    SEC_PKCS7SignerInfo *signerinfo, **signerinfos;    kind = SEC_PKCS7ContentType (cinfo);    switch (kind) {      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:	return SECFailure;		/* XXX set an error? */    }    if (signerinfos == NULL)		/* no signer, no certs? */	return SECFailure;		/* XXX set an error? */    if (certdb == NULL) {	certdb = CERT_GetDefaultCertDB();	if (certdb == NULL) {	    PORT_SetError (SEC_ERROR_BAD_DATABASE);	    return SECFailure;	}    }    /* XXX Should it be an error if we find no signerinfo or no certs? */    while ((signerinfo = *signerinfos++) != NULL) {	if (signerinfo->cert != NULL)	    /* get the cert chain.  don't send the root to avoid contamination	     * of old clients with a new root that they don't trust	     */	    signerinfo->certList = CERT_CertChainFromCert (signerinfo->cert,							   certUsageEmailSigner,							   PR_FALSE);    }    return SECSuccess;}/* * Helper function to add a certificate chain for inclusion in the * bag of certificates in a signedData. */static SECStatussec_pkcs7_add_cert_chain (SEC_PKCS7ContentInfo *cinfo,			  CERTCertificate *cert,			  CERTCertDBHandle *certdb){    SECOidTag kind;    CERTCertificateList *certlist, **certlists, ***certlistsp;    int count;    kind = SEC_PKCS7ContentType (cinfo);    switch (kind) {      case SEC_OID_PKCS7_SIGNED_DATA:	{	    SEC_PKCS7SignedData *sdp;	    sdp = cinfo->content.signedData;	    certlistsp = &(sdp->certLists);	}	break;      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:	{	    SEC_PKCS7SignedAndEnvelopedData *saedp;	    saedp = cinfo->content.signedAndEnvelopedData;	    certlistsp = &(saedp->certLists);	}	break;      default:	return SECFailure;		/* XXX set an error? */    }    if (certdb == NULL) {	certdb = CERT_GetDefaultCertDB();	if (certdb == NULL) {	    PORT_SetError (SEC_ERROR_BAD_DATABASE);	    return SECFailure;	}    }    certlist = CERT_CertChainFromCert (cert, certUsageEmailSigner, PR_FALSE);    if (certlist == NULL)	return SECFailure;    certlists = *certlistsp;    if (certlists == NULL) {	count = 0;	certlists = (CERTCertificateList**)PORT_ArenaAlloc (cinfo->poolp,				     2 * sizeof(CERTCertificateList *));    } else {	for (count = 0; certlists[count] != NULL; count++)	    ;	PORT_Assert (count);	/* should be at least one already */	certlists = (CERTCertificateList**)PORT_ArenaGrow (cinfo->poolp, 				 certlists,				(count + 1) * sizeof(CERTCertificateList *),				(count + 2) * sizeof(CERTCertificateList *));    }    if (certlists == NULL) {	CERT_DestroyCertificateList (certlist);	return SECFailure;    }    certlists[count] = certlist;    certlists[count + 1] = NULL;    *certlistsp = certlists;    return SECSuccess;}/* * Helper function to add a certificate for inclusion in the bag of * certificates in a signedData. */static SECStatussec_pkcs7_add_certificate (SEC_PKCS7ContentInfo *cinfo,			   CERTCertificate *cert){    SECOidTag kind;    CERTCertificate **certs, ***certsp;    int count;    kind = SEC_PKCS7ContentType (cinfo);    switch (kind) {      case SEC_OID_PKCS7_SIGNED_DATA:	{	    SEC_PKCS7SignedData *sdp;	    sdp = cinfo->content.signedData;	    certsp = &(sdp->certs);	}	break;      case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA:	{	    SEC_PKCS7SignedAndEnvelopedData *saedp;	    saedp = cinfo->content.signedAndEnvelopedData;	    certsp = &(saedp->certs);	}	break;      default:	return SECFailure;		/* XXX set an error? */    }    cert = CERT_DupCertificate (cert);    if (cert == NULL)	return SECFailure;    certs = *certsp;    if (certs == NULL) {	count = 0;	certs = (CERTCertificate**)PORT_ArenaAlloc (cinfo->poolp, 					      2 * sizeof(CERTCertificate *));    } else {	for (count = 0; certs[count] != NULL; count++)	    ;	PORT_Assert (count);	/* should be at least one already */	certs = (CERTCertificate**)PORT_ArenaGrow (cinfo->poolp, certs,				(count + 1) * sizeof(CERTCertificate *),				(count + 2) * sizeof(CERTCertificate *));    }    if (certs == NULL) {

⌨️ 快捷键说明

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