p7create.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,321 行 · 第 1/3 页
C
1,321 行
CERT_DestroyCertificate (cert); return SECFailure; } certs[count] = cert; certs[count + 1] = NULL; *certsp = certs; return SECSuccess;}/* * Create a PKCS7 certs-only container. * * "cert" is the (first) cert that will be included. * * "include_chain" specifies whether the entire chain for "cert" should * be included. * * "certdb" is the cert database to use for finding the chain. * It can be NULL in when "include_chain" is false, or when meaning * use the default database. * * More certs and chains can be added via AddCertificate and AddCertChain. * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */SEC_PKCS7ContentInfo *SEC_PKCS7CreateCertsOnly (CERTCertificate *cert, PRBool include_chain, CERTCertDBHandle *certdb){ SEC_PKCS7ContentInfo *cinfo; SECStatus rv; cinfo = sec_pkcs7_create_signed_data (NULL, NULL); if (cinfo == NULL) return NULL; if (include_chain) rv = sec_pkcs7_add_cert_chain (cinfo, cert, certdb); else rv = sec_pkcs7_add_certificate (cinfo, cert); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } return cinfo;}/* * Add "cert" and its entire chain to the set of certs included in "cinfo". * * "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_PKCS7AddCertChain (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert, CERTCertDBHandle *certdb){ SECOidTag kind; kind = SEC_PKCS7ContentType (cinfo); if (kind != SEC_OID_PKCS7_SIGNED_DATA && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA) return SECFailure; /* XXX set an error? */ return sec_pkcs7_add_cert_chain (cinfo, cert, certdb);}/* * Add "cert" to the set of certs included in "cinfo". * * "cinfo" should be of type signedData or signedAndEnvelopedData; * SECFailure will be returned if it is not. */SECStatusSEC_PKCS7AddCertificate (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert){ SECOidTag kind; kind = SEC_PKCS7ContentType (cinfo); if (kind != SEC_OID_PKCS7_SIGNED_DATA && kind != SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA) return SECFailure; /* XXX set an error? */ return sec_pkcs7_add_certificate (cinfo, cert);}static SECStatussec_pkcs7_init_encrypted_content_info (SEC_PKCS7EncryptedContentInfo *enccinfo, PRArenaPool *poolp, SECOidTag kind, PRBool detached, SECOidTag encalg, int keysize){ SECStatus rv; PORT_Assert (enccinfo != NULL && poolp != NULL); if (enccinfo == NULL || poolp == NULL) return SECFailure; /* * XXX Some day we may want to allow for other kinds. That needs * more work and modifications to the creation interface, etc. * For now, allow but notice callers who pass in other kinds. * They are responsible for creating the inner type and encoding, * if it is other than DATA. */ PORT_Assert (kind == SEC_OID_PKCS7_DATA); enccinfo->contentTypeTag = SECOID_FindOIDByTag (kind); PORT_Assert (enccinfo->contentTypeTag && enccinfo->contentTypeTag->offset == kind); rv = SECITEM_CopyItem (poolp, &(enccinfo->contentType), &(enccinfo->contentTypeTag->oid)); if (rv != SECSuccess) return rv; /* Save keysize and algorithm for later. */ enccinfo->keysize = keysize; enccinfo->encalg = encalg; return SECSuccess;}/* * Add a recipient to a PKCS7 thing, verifying their cert first. * Any error returns SECFailure. */static SECStatussec_pkcs7_add_recipient (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert, SECCertUsage certusage, CERTCertDBHandle *certdb){ SECOidTag kind; SEC_PKCS7RecipientInfo *recipientinfo, **recipientinfos, ***recipientinfosp; SECItem *dummy; void *mark; int count; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { case SEC_OID_PKCS7_ENVELOPED_DATA: { SEC_PKCS7EnvelopedData *edp; edp = cinfo->content.envelopedData; recipientinfosp = &(edp->recipientInfos); } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saedp; saedp = cinfo->content.signedAndEnvelopedData; recipientinfosp = &(saedp->recipientInfos); } break; default: return SECFailure; /* XXX set an error? */ } /* * XXX I think that CERT_VerifyCert should do this if *it* is passed * a NULL database. */ if (certdb == NULL) { certdb = CERT_GetDefaultCertDB(); if (certdb == NULL) return SECFailure; /* XXX set an error? */ } if (CERT_VerifyCert (certdb, cert, PR_TRUE, certusage, PR_Now(), cinfo->pwfn_arg, NULL) != SECSuccess) { /* XXX Did CERT_VerifyCert set an error? */ return SECFailure; } mark = PORT_ArenaMark (cinfo->poolp); recipientinfo = (SEC_PKCS7RecipientInfo*)PORT_ArenaZAlloc (cinfo->poolp, sizeof(SEC_PKCS7RecipientInfo)); if (recipientinfo == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } dummy = SEC_ASN1EncodeInteger (cinfo->poolp, &recipientinfo->version, SEC_PKCS7_RECIPIENT_INFO_VERSION); if (dummy == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } PORT_Assert (dummy == &recipientinfo->version); recipientinfo->cert = CERT_DupCertificate (cert); if (recipientinfo->cert == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } recipientinfo->issuerAndSN = CERT_GetCertIssuerAndSN (cinfo->poolp, cert); if (recipientinfo->issuerAndSN == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } /* * Okay, now recipientinfo is all set. We just need to put it into * the main structure. * * If this is the first recipient, allocate a new recipientinfos array; * otherwise, reallocate the array, making room for the new entry. */ recipientinfos = *recipientinfosp; if (recipientinfos == NULL) { count = 0; recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaAlloc ( cinfo->poolp, 2 * sizeof(SEC_PKCS7RecipientInfo *)); } else { for (count = 0; recipientinfos[count] != NULL; count++) ; PORT_Assert (count); /* should be at least one already */ recipientinfos = (SEC_PKCS7RecipientInfo **)PORT_ArenaGrow ( cinfo->poolp, recipientinfos, (count + 1) * sizeof(SEC_PKCS7RecipientInfo *), (count + 2) * sizeof(SEC_PKCS7RecipientInfo *)); } if (recipientinfos == NULL) { PORT_ArenaRelease (cinfo->poolp, mark); return SECFailure; } recipientinfos[count] = recipientinfo; recipientinfos[count + 1] = NULL; *recipientinfosp = recipientinfos; PORT_ArenaUnmark (cinfo->poolp, mark); return SECSuccess;}/* * Start a PKCS7 enveloping context. * * "cert" is the cert for the recipient. It will be checked for validity. * * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient) * XXX Maybe SECCertUsage should be split so that our caller just says * "email" and *we* add the "recipient" part -- otherwise our caller * could be lying about the usage; we do not want to allow encryption * certs for signing or vice versa. * * "certdb" is the cert database to use for verifying the cert. * It can be NULL if a default database is available (like in the client). * * "encalg" specifies the bulk encryption algorithm to use (e.g. SEC_OID_RC2). * * "keysize" specifies the bulk encryption key size, in bits. * * The return value can be passed to functions which add things to * it like more recipients, then eventually to SEC_PKCS7Encode() or to * SEC_PKCS7EncoderStart() to create the encoded data, and finally to * SEC_PKCS7DestroyContentInfo(). * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */extern SEC_PKCS7ContentInfo *SEC_PKCS7CreateEnvelopedData (CERTCertificate *cert, SECCertUsage certusage, CERTCertDBHandle *certdb, SECOidTag encalg, int keysize, SECKEYGetPasswordKey pwfn, void *pwfn_arg){ SEC_PKCS7ContentInfo *cinfo; SEC_PKCS7EnvelopedData *envd; SECStatus rv; cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENVELOPED_DATA, PR_FALSE, pwfn, pwfn_arg); if (cinfo == NULL) return NULL; rv = sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } envd = cinfo->content.envelopedData; PORT_Assert (envd != NULL); /* * XXX Might we want to allow content types other than data? * If so, via what interface? */ rv = sec_pkcs7_init_encrypted_content_info (&(envd->encContentInfo), cinfo->poolp, SEC_OID_PKCS7_DATA, PR_FALSE, encalg, keysize); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } /* XXX Anything more to do here? */ return cinfo;}/* * Add another recipient to an encrypted message. * * "cinfo" should be of type envelopedData or signedAndEnvelopedData; * SECFailure will be returned if it is not. * * "cert" is the cert for the recipient. It will be checked for validity. * * "certusage" describes the encryption usage (e.g. certUsageEmailRecipient) * XXX Maybe SECCertUsage should be split so that our caller just says * "email" and *we* add the "recipient" part -- otherwise our caller * could be lying about the usage; we do not want to allow encryption * certs for signing or vice versa. * * "certdb" is the cert database to use for verifying the cert. * It can be NULL if a default database is available (like in the client). */SECStatusSEC_PKCS7AddRecipient (SEC_PKCS7ContentInfo *cinfo, CERTCertificate *cert, SECCertUsage certusage, CERTCertDBHandle *certdb){ return sec_pkcs7_add_recipient (cinfo, cert, certusage, certdb);}/* * Create an empty PKCS7 data content info. * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */SEC_PKCS7ContentInfo *SEC_PKCS7CreateData (void){ return sec_pkcs7_create_content_info (SEC_OID_PKCS7_DATA, PR_FALSE, NULL, NULL);}/* * Create an empty PKCS7 encrypted content info. * * "algorithm" specifies the bulk encryption algorithm to use. * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */SEC_PKCS7ContentInfo *SEC_PKCS7CreateEncryptedData (SECOidTag algorithm, int keysize, SECKEYGetPasswordKey pwfn, void *pwfn_arg){ SEC_PKCS7ContentInfo *cinfo; SECAlgorithmID *algid; SEC_PKCS7EncryptedData *enc_data; SECStatus rv; cinfo = sec_pkcs7_create_content_info (SEC_OID_PKCS7_ENCRYPTED_DATA, PR_FALSE, pwfn, pwfn_arg); if (cinfo == NULL) return NULL; enc_data = cinfo->content.encryptedData; algid = &(enc_data->encContentInfo.contentEncAlg); switch (algorithm) { case SEC_OID_RC2_CBC: case SEC_OID_DES_EDE3_CBC: case SEC_OID_DES_CBC: rv = SECOID_SetAlgorithmID (cinfo->poolp, algid, algorithm, NULL); break; default: { /* * Assume password-based-encryption. At least, try that. */ SECAlgorithmID *pbe_algid; pbe_algid = PK11_CreatePBEAlgorithmID (algorithm, 1, NULL); if (pbe_algid == NULL) { rv = SECFailure; } else { rv = SECOID_CopyAlgorithmID (cinfo->poolp, algid, pbe_algid); SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE); } } break; } if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } rv = sec_pkcs7_init_encrypted_content_info (&(enc_data->encContentInfo), cinfo->poolp, SEC_OID_PKCS7_DATA, PR_FALSE, algorithm, keysize); if (rv != SECSuccess) { SEC_PKCS7DestroyContentInfo (cinfo); return NULL; } return cinfo;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?