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