tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

smimemessage.c (6386B)


      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 = NULL;
    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    /* sigd (and therefore cmsg) has adopted signerinfo */
    164    signerinfo = NULL;
    165 
    166    /* include the signing cert and its entire chain */
    167    /* note that there are no checks for duplicate certs in place, as all the */
    168    /* essential data structures (like set of certificate) are not there */
    169    if (NSS_CMSSignedData_AddCertChain(sigd, scert) != SECSuccess)
    170        goto loser;
    171 
    172    /* If the encryption cert and the signing cert differ, then include
    173     * the encryption cert too. */
    174    if ( ( ecert != NULL ) && ( ecert != scert ) ) {
    175        if (NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess)
    176            goto loser;
    177    }
    178 
    179    return cmsg;
    180 loser:
    181    if (cmsg)
    182        NSS_CMSMessage_Destroy(cmsg);
    183    if (signerinfo)
    184        NSS_CMSSignerInfo_Destroy(signerinfo);
    185    return NULL;
    186 }
    187 #endif