1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * SMIME message methods 7 */ 8 9 #include "cmslocal.h" 10 #include "smime.h" 11 12 #include "cert.h" 13 #include "keyhi.h" 14 #include "secasn1.h" 15 #include "secitem.h" 16 #include "secoid.h" 17 #include "pk11func.h" 18 #include "prtime.h" 19 #include "secerr.h" 20 21 #if 0 22 /* 23 * NSS_SMIMEMessage_CreateEncrypted - start an S/MIME encrypting context. 24 * 25 * "scert" is the cert for the sender. It will be checked for validity. 26 * "rcerts" are the certs for the recipients. They will also be checked. 27 * 28 * "certdb" is the cert database to use for verifying the certs. 29 * It can be NULL if a default database is available (like in the client). 30 * 31 * This function already does all of the stuff specific to S/MIME protocol 32 * and local policy; the return value just needs to be passed to 33 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data, 34 * and finally to SEC_PKCS7DestroyContentInfo(). 35 * 36 * An error results in a return value of NULL and an error set. 37 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) 38 */ 39 NSSCMSMessage * 40 NSS_SMIMEMessage_CreateEncrypted(CERTCertificate *scert, 41 CERTCertificate **rcerts, 42 CERTCertDBHandle *certdb, 43 PK11PasswordFunc pwfn, 44 void *pwfn_arg) 45 { 46 NSSCMSMessage *cmsg; 47 long cipher; 48 SECOidTag encalg; 49 int keysize; 50 int mapi, rci; 51 52 cipher = smime_choose_cipher (scert, rcerts); 53 if (cipher < 0) 54 return NULL; 55 56 mapi = smime_mapi_by_cipher (cipher); 57 if (mapi < 0) 58 return NULL; 59 60 /* 61 * XXX This is stretching it -- CreateEnvelopedData should probably 62 * take a cipher itself of some sort, because we cannot know what the 63 * future will bring in terms of parameters for each type of algorithm. 64 * For example, just an algorithm and keysize is *not* sufficient to 65 * fully specify the usage of RC5 (which also needs to know rounds and 66 * block size). Work this out into a better API! 67 */ 68 encalg = smime_cipher_map[mapi].algtag; 69 keysize = smime_keysize_by_cipher (cipher); 70 if (keysize < 0) 71 return NULL; 72 73 cinfo = SEC_PKCS7CreateEnvelopedData (scert, certUsageEmailRecipient, 74 certdb, encalg, keysize, 75 pwfn, pwfn_arg); 76 if (cinfo == NULL) 77 return NULL; 78 79 for (rci = 0; rcerts[rci] != NULL; rci++) { 80 if (rcerts[rci] == scert) 81 continue; 82 if (SEC_PKCS7AddRecipient (cinfo, rcerts[rci], certUsageEmailRecipient, 83 NULL) != SECSuccess) { 84 SEC_PKCS7DestroyContentInfo (cinfo); 85 return NULL; 86 } 87 } 88 89 return cinfo; 90 } 91 92 93 /* 94 * Start an S/MIME signing context. 95 * 96 * "scert" is the cert that will be used to sign the data. It will be 97 * checked for validity. 98 * 99 * "ecert" is the signer's encryption cert. If it is different from 100 * scert, then it will be included in the signed message so that the 101 * recipient can save it for future encryptions. 102 * 103 * "certdb" is the cert database to use for verifying the cert. 104 * It can be NULL if a default database is available (like in the client). 105 * 106 * "digestalg" names the digest algorithm (e.g. SEC_OID_SHA1). 107 * XXX There should be SECMIME functions for hashing, or the hashing should 108 * be built into this interface, which we would like because we would 109 * support more smartcards that way, and then this argument should go away.) 110 * 111 * "digest" is the actual digest of the data. It must be provided in 112 * the case of detached data or NULL if the content will be included. 113 * 114 * This function already does all of the stuff specific to S/MIME protocol 115 * and local policy; the return value just needs to be passed to 116 * SEC_PKCS7Encode() or to SEC_PKCS7EncoderStart() to create the encoded data, 117 * and finally to SEC_PKCS7DestroyContentInfo(). 118 * 119 * An error results in a return value of NULL and an error set. 120 * (Retrieve specific errors via PORT_GetError()/XP_GetError().) 121 */ 122 123 NSSCMSMessage * 124 NSS_SMIMEMessage_CreateSigned(CERTCertificate *scert, 125 CERTCertificate *ecert, 126 CERTCertDBHandle *certdb, 127 SECOidTag digestalgtag, 128 SECItem *digest, 129 PK11PasswordFunc pwfn, 130 void *pwfn_arg) 131 { 132 NSSCMSMessage *cmsg; 133 NSSCMSSignedData *sigd; 134 NSSCMSSignerInfo *signerinfo; 135 136 /* See note in header comment above about digestalg. */ 137 /* Doesn't explain this. PORT_Assert (digestalgtag == SEC_OID_SHA1); */ 138 139 cmsg = NSS_CMSMessage_Create(NULL); 140 if (cmsg == NULL) 141 return NULL; 142 143 sigd = NSS_CMSSignedData_Create(cmsg); 144 if (sigd == NULL) 145 goto loser; 146 147 /* create just one signerinfo */ 148 signerinfo = NSS_CMSSignerInfo_Create(cmsg, scert, digestalgtag); 149 if (signerinfo == NULL) 150 goto loser; 151 152 /* Add the signing time to the signerinfo. */ 153 if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) 154 goto loser; 155 156 /* and add the SMIME profile */ 157 if (NSS_SMIMESignerInfo_AddSMIMEProfile(signerinfo, scert) != SECSuccess) 158 goto loser; 159 160 /* now add the signerinfo to the signeddata */ 161 if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) 162 goto loser; 163 164 /* include the signing cert and its entire chain */ 165 /* note that there are no checks for duplicate certs in place, as all the */ 166 /* essential data structures (like set of certificate) are not there */ 167 if (NSS_CMSSignedData_AddCertChain(sigd, scert) != SECSuccess) 168 goto loser; 169 170 /* If the encryption cert and the signing cert differ, then include 171 * the encryption cert too. */ 172 if ( ( ecert != NULL ) && ( ecert != scert ) ) { 173 if (NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) 174 goto loser; 175 } 176 177 return cmsg; 178 loser: 179 if (cmsg) 180 NSS_CMSMessage_Destroy(cmsg); 181 return NULL; 182 } 183 #endif 184