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