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