/* * 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().) */ SEC_PKCS7ContentInfo * SECMIME_CreateEncrypted(CERTCertificate *scert, CERTCertificate **rcerts, CERTCertDBHandle *certdb, SECKEYGetPasswordKey pwfn, void *pwfn_arg) { SEC_PKCS7ContentInfo *cinfo; 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_maps[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; }
static int EncryptFile(FILE *outFile, FILE *inFile, struct recipient *recipients, char *progName) { SEC_PKCS7ContentInfo *cinfo; SEC_PKCS7EncoderContext *ecx; struct recipient *rcpt; SECStatus rv; if (outFile == NULL || inFile == NULL || recipients == NULL) return -1; /* XXX Need a better way to handle that certUsage stuff! */ /* XXX keysize? */ cinfo = SEC_PKCS7CreateEnvelopedData (recipients->cert, certUsageEmailRecipient, NULL, SEC_OID_DES_EDE3_CBC, 0, NULL, NULL); if (cinfo == NULL) return -1; for (rcpt = recipients->next; rcpt != NULL; rcpt = rcpt->next) { rv = SEC_PKCS7AddRecipient (cinfo, rcpt->cert, certUsageEmailRecipient, NULL); if (rv != SECSuccess) { SECU_PrintError(progName, "error adding recipient \"%s\"", rcpt->nickname); return -1; } } ecx = SEC_PKCS7EncoderStart (cinfo, EncryptOut, outFile, NULL); if (ecx == NULL) return -1; for (;;) { char ibuf[1024]; int nb; if (feof(inFile)) break; nb = fread(ibuf, 1, sizeof(ibuf), inFile); if (nb == 0) { if (ferror(inFile)) { PORT_SetError(SEC_ERROR_IO); rv = SECFailure; } break; } rv = SEC_PKCS7EncoderUpdate(ecx, ibuf, nb); if (rv != SECSuccess) break; } if (SEC_PKCS7EncoderFinish(ecx, NULL, NULL) != SECSuccess) rv = SECFailure; SEC_PKCS7DestroyContentInfo (cinfo); if (rv != SECSuccess) return -1; return 0; }