| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| /* |
| * SMIME message methods |
| */ |
| |
| #include "cmslocal.h" |
| #include "smime.h" |
| |
| #include "cert.h" |
| #include "keyhi.h" |
| #include "secasn1.h" |
| #include "secitem.h" |
| #include "secoid.h" |
| #include "pk11func.h" |
| #include "prtime.h" |
| #include "secerr.h" |
| |
| #if 0 |
| /* |
| * NSS_SMIMEMessage_CreateEncrypted - start an S/MIME encrypting context. |
| * |
| * "scert" is the cert for the sender. It will be checked for validity. |
| * "rcerts" are the certs for the recipients. They will also be checked. |
| * |
| * "certdb" is the cert database to use for verifying the certs. |
| * It can be NULL if a default database is available (like in the client). |
| * |
| * This function already does all of the stuff specific to S/MIME protocol |
| * and local policy; the return value just needs to be passed 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().) |
| */ |
| NSSCMSMessage * |
| NSS_SMIMEMessage_CreateEncrypted(CERTCertificate *scert, |
| CERTCertificate **rcerts, |
| CERTCertDBHandle *certdb, |
| PK11PasswordFunc pwfn, |
| void *pwfn_arg) |
| { |
| NSSCMSMessage *cmsg; |
| long cipher; |
| SECOidTag encalg; |
| int keysize; |
| int mapi, rci; |
| |
| cipher = smime_choose_cipher (scert, rcerts); |
| if (cipher < 0) |
| return NULL; |
| |
| mapi = smime_mapi_by_cipher (cipher); |
| if (mapi < 0) |
| return NULL; |
| |
| /* |
| * XXX This is stretching it -- CreateEnvelopedData should probably |
| * take a cipher itself of some sort, because we cannot know what the |
| * future will bring in terms of parameters for each type of algorithm. |
| * For example, just an algorithm and keysize is *not* sufficient to |
| * fully specify the usage of RC5 (which also needs to know rounds and |
| * block size). Work this out into a better API! |
| */ |
| encalg = smime_cipher_map[mapi].algtag; |
| keysize = smime_keysize_by_cipher (cipher); |
| if (keysize < 0) |
| return NULL; |
| |
| cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient, |
| certdb, encalg, keysize, |
| pwfn, pwfn_arg); |
| if (cinfo == NULL) |
| return NULL; |
| |
| for (rci = 0; rcerts[rci] != NULL; rci++) { |
| if (rcerts[rci] == scert) |
| continue; |
| if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient, |
| NULL) != SECSuccess) { |
| SEC_PKCS7DestroyContentInfo (cinfo); |
| return NULL; |
| } |
| } |
| |
| return cinfo; |
| } |
| |
| |
| /* |
| * Start an S/MIME signing context. |
| * |
| * "scert" is the cert that will be used to sign the data. It will be |
| * checked for validity. |
| * |
| * "ecert" is the signer's encryption cert. If it is different from |
| * scert, then it will be included in the signed message so that the |
| * recipient can save it for future encryptions. |
| * |
| * "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). |
| * |
| * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1). |
| * XXX There should be SECMIME functions for hashing, or the hashing should |
| * be built into this interface, which we would like because we would |
| * support more smartcards that way, and then this argument should go away.) |
| * |
| * "digest" is the actual digest of the data. It must be provided in |
| * the case of detached data or NULL if the content will be included. |
| * |
| * This function already does all of the stuff specific to S/MIME protocol |
| * and local policy; the return value just needs to be passed 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().) |
| */ |
| |
| NSSCMSMessage * |
| NSS_SMIMEMessage_CreateSigned(CERTCertificate *scert, |
| CERTCertificate *ecert, |
| CERTCertDBHandle *certdb, |
| SECOidTag digestalgtag, |
| SECItem *digest, |
| PK11PasswordFunc pwfn, |
| void *pwfn_arg) |
| { |
| NSSCMSMessage *cmsg; |
| NSSCMSSignedData *sigd; |
| NSSCMSSignerInfo *signerinfo; |
| |
| /* See note in header comment above about digestalg. */ |
| /* Doesn't explain this. PORT_Assert (digestalgtag == SEC_OID_SHA1); */ |
| |
| cmsg = NSS_CMSMessage_Create(NULL); |
| if (cmsg == NULL) |
| return NULL; |
| |
| sigd = NSS_CMSSignedData_Create(cmsg); |
| if (sigd == NULL) |
| goto loser; |
| |
| /* create just one signerinfo */ |
| signerinfo = NSS_CMSSignerInfo_Create(cmsg, scert, digestalgtag); |
| if (signerinfo == NULL) |
| goto loser; |
| |
| /* Add the signing time to the signerinfo. */ |
| if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) |
| goto loser; |
| |
| /* and add the SMIME profile */ |
| if (NSS_SMIMESignerInfo_AddSMIMEProfile(signerinfo, scert) != SECSuccess) |
| goto loser; |
| |
| /* now add the signerinfo to the signeddata */ |
| if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) |
| goto loser; |
| |
| /* include the signing cert and its entire chain */ |
| /* note that there are no checks for duplicate certs in place, as all the */ |
| /* essential data structures (like set of certificate) are not there */ |
| if (NSS_CMSSignedData_AddCertChain(sigd, scert) != SECSuccess) |
| goto loser; |
| |
| /* If the encryption cert and the signing cert differ, then include |
| * the encryption cert too. */ |
| if ( ( ecert != NULL ) && ( ecert != scert ) ) { |
| if (NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) |
| goto loser; |
| } |
| |
| return cmsg; |
| loser: |
| if (cmsg) |
| NSS_CMSMessage_Destroy(cmsg); |
| return NULL; |
| } |
| #endif |