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