LCOV - code coverage report
Current view: top level - zxid - smime-enc.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 86 150 57.3 %
Date: 2010-12-19 Functions: 5 8 62.5 %
Branches: 36 116 31.0 %

           Branch data     Line data    Source code
       1                 :            : /* smime-enc.c  -  Utility functions for performing S/MIME signatures
       2                 :            :  *                 and encryption.
       3                 :            :  *
       4                 :            :  * Copyright (c) 1999 Sampo Kellomaki <sampo@iki.fi>, All Rights Reserved.
       5                 :            :  * License: This software may be distributed under the same license
       6                 :            :  *          terms as openssl (i.e. free, but mandatory attribution).
       7                 :            :  *          See file LICENSE for details.
       8                 :            :  *
       9                 :            :  * 11.9.1999, Created. --Sampo
      10                 :            :  * 13.9.1999, 0.1 released. Now adding verify. --Sampo
      11                 :            :  * 1.10.1999, improved error handling, fixed decrypt --Sampo
      12                 :            :  * 6.10.1999, separated from smimeutil.c --Sampo
      13                 :            :  * 9.10.1999, reviewed for free problems --Sampo
      14                 :            :  *
      15                 :            :  * This module has adopted ideas and control flow from
      16                 :            :  *    openssl-0.9.4/crypto/pkcs7/sign.c
      17                 :            :  *    openssl-0.9.4/crypto/pkcs7/verify.c
      18                 :            :  *    openssl-0.9.4/crypto/pkcs7/enc.c
      19                 :            :  *    openssl-0.9.4/crypto/pkcs7/dec.c
      20                 :            :  * which are Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com),
      21                 :            :  * All rights reserved. See file LICENSE for conditions.
      22                 :            :  *
      23                 :            :  * This module has been developed to support a Lingo XTRA that is supposed
      24                 :            :  * to provide crypto functionality. It may, however, be useful for other
      25                 :            :  * purposes as well.
      26                 :            :  *
      27                 :            :  * This is a very simple S/MIME library. For example the multipart
      28                 :            :  * boundary separators are hard coded and no effort is made to verify
      29                 :            :  * that mime entities are in their canonical form before signing (the
      30                 :            :  * caller should make sure they are, canonical form means using CRLF
      31                 :            :  * as line termination, among other things). Also the multipart functionality
      32                 :            :  * only understands up to 3 attachments. For many tasks this is enough,
      33                 :            :  * but if its not, feel free to write more generic utilities.
      34                 :            :  *
      35                 :            :  * Memory management: most routines malloc the results. Freeing them is
      36                 :            :  * application's responsibility. I use libc malloc, but if in doubt
      37                 :            :  * it might be safer to just leak the memory (i.e. don't ever free it).
      38                 :            :  * This library works entirely in memory, so maximum memory consumption
      39                 :            :  * might be more than twice the total size of all files to be encrypted.
      40                 :            :  */
      41                 :            : 
      42                 :            : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
      43                 :            :  * All rights reserved.
      44                 :            :  *
      45                 :            :  * This package is an SSL implementation written
      46                 :            :  * by Eric Young (eay@cryptsoft.com).
      47                 :            :  * The implementation was written so as to conform with Netscapes SSL.
      48                 :            :  * 
      49                 :            :  * This library is free for commercial and non-commercial use as long as
      50                 :            :  * the following conditions are aheared to.  The following conditions
      51                 :            :  * apply to all code found in this distribution, be it the RC4, RSA,
      52                 :            :  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
      53                 :            :  * included with this distribution is covered by the same copyright terms
      54                 :            :  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
      55                 :            :  * 
      56                 :            :  * Copyright remains Eric Young's, and as such any Copyright notices in
      57                 :            :  * the code are not to be removed.
      58                 :            :  * If this package is used in a product, Eric Young should be given attribution
      59                 :            :  * as the author of the parts of the library used.
      60                 :            :  * This can be in the form of a textual message at program startup or
      61                 :            :  * in documentation (online or textual) provided with the package.
      62                 :            :  * 
      63                 :            :  * Redistribution and use in source and binary forms, with or without
      64                 :            :  * modification, are permitted provided that the following conditions
      65                 :            :  * are met:
      66                 :            :  * 1. Redistributions of source code must retain the copyright
      67                 :            :  *    notice, this list of conditions and the following disclaimer.
      68                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      69                 :            :  *    notice, this list of conditions and the following disclaimer in the
      70                 :            :  *    documentation and/or other materials provided with the distribution.
      71                 :            :  * 3. All advertising materials mentioning features or use of this software
      72                 :            :  *    must display the following acknowledgement:
      73                 :            :  *    "This product includes cryptographic software written by
      74                 :            :  *     Eric Young (eay@cryptsoft.com)"
      75                 :            :  *    The word 'cryptographic' can be left out if the rouines from the library
      76                 :            :  *    being used are not cryptographic related :-).
      77                 :            :  * 4. If you include any Windows specific code (or a derivative thereof) from 
      78                 :            :  *   the apps directory (application code) you must include an acknowledgement:
      79                 :            :  *   "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
      80                 :            :  * 
      81                 :            :  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
      82                 :            :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      83                 :            :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      84                 :            :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      85                 :            :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      86                 :            :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      87                 :            :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      88                 :            :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      89                 :            :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      90                 :            :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      91                 :            :  * SUCH DAMAGE.
      92                 :            :  * 
      93                 :            :  * The licence and distribution terms for any publically available version or
      94                 :            :  * derivative of this code cannot be changed.  i.e. this code cannot simply be
      95                 :            :  * copied and put under another distribution licence
      96                 :            :  * [including the GNU Public Licence.]
      97                 :            :  */
      98                 :            : 
      99                 :            : #include "platform.h"
     100                 :            : 
     101                 :            : #include <stdio.h>
     102                 :            : #include <string.h>
     103                 :            : #include <time.h>
     104                 :            : 
     105                 :            : #if defined(macintosh) || defined(__INTEL__)
     106                 :            : #include "macglue.h"
     107                 :            : #endif
     108                 :            : 
     109                 :            : #include "logprint.h"
     110                 :            : 
     111                 :            : #include <openssl/buffer.h>
     112                 :            : #include <openssl/bio.h>
     113                 :            : #include <openssl/x509.h>
     114                 :            : #include <openssl/pem.h>
     115                 :            : #include <openssl/err.h>
     116                 :            : #include <openssl/rand.h>
     117                 :            : 
     118                 :            : #define SMIME_INTERNALS  /* we want also our internal helper functions */
     119                 :            : #include "smimeutil.h"
     120                 :            : 
     121                 :            : /* ============= S I G N I N G   &   E N C R Y P T I O N ============= */
     122                 :            : 
     123                 :            : /* Typically signing and encryption involves a sequence of calls like
     124                 :            :  *
     125                 :            :  *  msg = smime_encrypt(pubkey,
     126                 :            :  *           smime_clear_sign(privkey, password,
     127                 :            :  *              mime_mk_multipart(text, file1, len1, type1, name1,
     128                 :            :  *                                      NULL,  0,    NULL,  NULL,
     129                 :            :  *                                      NULL,  0,    NULL,  NULL)));
     130                 :            :  */
     131                 :            : 
     132                 :            : /* Helper function for signing and signature verification. */
     133                 :            : 
     134                 :            : /* Called by:  clear_sign, sign */
     135                 :            : static BIO*
     136                 :            : smime_sign_engine(X509* x509, EVP_PKEY* pkey,
     137                 :            :                   const char* mime_entity, int detach)
     138                 :          0 : {
     139                 :            :   int i;
     140                 :            :   char buf[4096];
     141                 :          0 :   BIO*  p7bio = NULL;
     142                 :          0 :   BIO*  bio = NULL;
     143                 :          0 :   PKCS7* p7 = NULL;
     144                 :            :   PKCS7_SIGNER_INFO* si;
     145                 :            : 
     146                 :            :   /* Set up BIOs and PKCS7 machinery */
     147                 :            : 
     148                 :            :   LOG_PRINT3("sig engine %x %x", x509, pkey);  
     149                 :            :   LOG_PRINT3("           %x %d", mime_entity, detach);
     150   [ #  #  #  #  :          0 :   if (!x509 || !pkey || !mime_entity) GOTO_ERR("NULL arg(s)");
                   #  # ]
     151         [ #  # ]:          0 :   if (!(bio = set_read_BIO_from_buf(mime_entity, -1))) goto err;
     152                 :            :   LOG_PRINT("PKCS7_new");
     153                 :            :   /*Log_malloc = Log;*/
     154         [ #  # ]:          0 :   if (!(p7=PKCS7_new())) GOTO_ERR("no memory?");
     155                 :            :   LOG_PRINT("PKCS7_set_type");
     156                 :          0 :   PKCS7_set_type(p7,NID_pkcs7_signed);
     157                 :            :   /*Log_malloc = NULL;*/
     158                 :            :   LOG_PRINT("Adding sig");
     159         [ #  # ]:          0 :   if (!(si=PKCS7_add_signature(p7,x509,pkey,EVP_sha1())))
     160                 :          0 :     GOTO_ERR("PKCS7_add_signature");
     161                 :            :   
     162                 :            :   LOG_PRINT("Adding signed attribute");
     163                 :            :   /* If you do this then you get signing time automatically added */
     164                 :          0 :   PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT,
     165                 :            :                              OBJ_nid2obj(NID_pkcs7_data));
     166                 :            :   /*PKCS7_add_certificate(p7,x509);*/
     167         [ #  # ]:          0 :   if (detach) PKCS7_set_detached(p7,1);
     168                 :            :   
     169                 :            :   /* Set the content of the signed to 'data' */
     170                 :          0 :   PKCS7_content_new(p7,NID_pkcs7_data);
     171                 :            :   
     172         [ #  # ]:          0 :   if (!(p7bio=PKCS7_dataInit(p7,NULL))) GOTO_ERR("PKCS7_dataInit");
     173                 :            :   
     174                 :            :   /* pump data from file to special PKCS7 BIO. This hashes it. */
     175                 :            : 
     176                 :            :   LOG_PRINT("pumping");
     177                 :            :   
     178                 :            :   for (;;)    {
     179                 :          0 :     i=BIO_read(bio,buf,sizeof(buf));
     180         [ #  # ]:          0 :     if (i <= 0) break;
     181                 :          0 :     BIO_write(p7bio,buf,i);
     182                 :          0 :   }
     183                 :          0 :   BIO_flush(p7bio);
     184                 :            :   
     185                 :            :   LOG_PRINT("data final...");
     186         [ #  # ]:          0 :   if (!PKCS7_dataFinal(p7,p7bio)) GOTO_ERR("PKCS7_dataFinal");
     187                 :          0 :   BIO_free_all(p7bio);
     188                 :          0 :   p7bio = NULL;
     189                 :          0 :   BIO_free_all(bio);
     190                 :            :   
     191         [ #  # ]:          0 :   if (!(bio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     192                 :            :   LOG_PRINT("Writing data to bio");
     193                 :          0 :   PEM_write_bio_PKCS7(bio,p7);
     194                 :          0 :   BIO_flush(bio);
     195                 :          0 :   PKCS7_free(p7);
     196                 :            :   
     197                 :            :   LOG_PRINT2("sig engine done %x", bio);
     198                 :          0 :   return bio;  /* return written memory bio (must be freed by caller)
     199                 :            :                 * caller will extract the data from buffer. */
     200                 :            : 
     201                 :          0 : err:
     202         [ #  # ]:          0 :   if (p7bio) BIO_free_all(p7bio);
     203         [ #  # ]:          0 :   if (p7)    PKCS7_free(p7);
     204         [ #  # ]:          0 :   if (bio)   BIO_free_all(bio);
     205                 :            :   LOG_PRINT("sig engine error");
     206                 :          0 :   return NULL;
     207                 :            : }
     208                 :            : 
     209                 :            : /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature
     210                 :            :  * is stored as separate mime entity so the message proper stays visible.
     211                 :            :  * I canonicalize the entity (LF->CRLF) because correct signature
     212                 :            :  * verification depends on this.
     213                 :            :  */
     214                 :            : 
     215                 :            : /*
     216                 :            : MIME-Version: 1.0
     217                 :            : Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg
     218                 :            : =sha1; boundary=sig42
     219                 :            : 
     220                 :            : --sig42
     221                 :            : Content-Type: text/plain
     222                 :            : 
     223                 :            : message to be signed
     224                 :            : --sig42
     225                 :            : Content-Type: application/x-pkcs7-signature; name="smime.p7s"
     226                 :            : Content-Transfer-Encoding: base64
     227                 :            : Content-Disposition: attachment; filename="smime.p7s"
     228                 :            : Content-Description: S/MIME Clear Signed Message
     229                 :            : 
     230                 :            : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
     231                 :            : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
     232                 :            : G0DXAj0zd/4AAAAA==
     233                 :            : --sig42--
     234                 :            : */
     235                 :            : 
     236                 :            : /* Called by:  smime_clear_sign */
     237                 :            : char*  /* returns smime encoded clear signed blob, or NULL if error */
     238                 :            : clear_sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity)
     239                 :          0 : {
     240                 :            :   char* b;
     241                 :            :   char* b64;
     242                 :          0 :   BIO*  wbio = 0;
     243                 :            :   int   n;
     244                 :            :   
     245                 :            :   LOG_PRINT("clear sig, canon entity...");
     246         [ #  # ]:          0 :   if (!(mime_entity = mime_canon(mime_entity))) goto err;
     247                 :            :   LOG_PRINT("clear sig, entity canoned. Now sig engine");
     248                 :            :   
     249                 :            :   /* Run crypto stuff over the mime_entity */
     250                 :            :   
     251         [ #  # ]:          0 :   if (!(wbio = smime_sign_engine(x509, pkey, mime_entity, 1))) goto err;
     252                 :            :   LOG_PRINT("clear sig: signed, now get data");
     253                 :          0 :   n = BIO_get_mem_data(wbio,&b64);
     254                 :            :   LOG_PRINT("clear sig: cut pem markers...");
     255         [ #  # ]:          0 :   if (!(b64 = cut_pem_markers_off(b64, n, "PKCS7"))) goto err;
     256                 :            :   
     257                 :            :   /* Wrap up the result in multipart/signed object */
     258                 :            :   
     259         [ #  # ]:          0 :   if (!(b = smime_mk_multipart_signed(mime_entity, b64))) goto err;
     260                 :            :   
     261                 :            :   LOG_PRINT("clear sig: done. free bio");
     262                 :          0 :   BIO_free_all(wbio);  /* this will also free b64 because b64 hangs from bio */
     263                 :          0 :   return b;
     264                 :            : 
     265                 :          0 : err:
     266         [ #  # ]:          0 :   if (wbio) BIO_free_all(wbio);
     267                 :          0 :   return NULL;
     268                 :            : }
     269                 :            : 
     270                 :            : /* Called by:  main x2 */
     271                 :            : char*
     272                 :            : smime_clear_sign(const char* privkey,
     273                 :            :                  const char* password,
     274                 :            :                  const char* mime_entity)
     275                 :          5 : {
     276                 :          5 :   char* b = NULL;
     277                 :          5 :   X509* x509 = NULL;
     278                 :          5 :   EVP_PKEY* pkey = NULL;
     279                 :            : 
     280                 :            :   /* Get key and certificate (why do we need both?) */
     281                 :            :   
     282         [ -  + ]:          5 :   if (!(pkey = open_private_key(privkey, password))) goto err;
     283         [ #  # ]:          0 :   if (!(x509 = extract_certificate(privkey))) goto err;
     284                 :          0 :   if (!(b = clear_sign(x509, pkey, mime_entity))) goto err;
     285                 :            : 
     286                 :          5 : err:
     287         [ -  + ]:          5 :   if (pkey)  EVP_PKEY_free(pkey);
     288         [ -  + ]:          5 :   if (x509)  X509_free(x509);
     289                 :          5 :   return b;
     290                 :            : }
     291                 :            : 
     292                 :            : /* Sign a mime entity, such as produced by mime_mk_multipart(). Signature
     293                 :            :  * and entity are output as one base64 blob so the entity is not trivially
     294                 :            :  * visible. */
     295                 :            : 
     296                 :            : /*
     297                 :            : MIME-Version: 1.0
     298                 :            : Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m"
     299                 :            : Content-Transfer-Encoding: base64
     300                 :            : Content-Disposition: attachment; filename="smime.p7m"
     301                 :            : Content-Description: S/MIME Signed Message
     302                 :            : 
     303                 :            : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
     304                 :            : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
     305                 :            : G0DXAj0zd/4AAAAA==
     306                 :            :  */
     307                 :            : 
     308                 :            : /* Called by:  smime_sign */
     309                 :            : char*  /* returns smime blob, NULL if error */
     310                 :            : sign(X509* x509, EVP_PKEY* pkey, const char* mime_entity)
     311                 :          0 : {
     312                 :            :   char* b;
     313                 :            :   char* b64;
     314                 :            :   BIO*  wbio;
     315                 :            :   int   n;
     316                 :            : 
     317                 :          0 :   mime_entity = mime_canon(mime_entity);
     318                 :            :   
     319                 :            :   /* Run crypto stuff over the mime_entity */
     320                 :            :   
     321         [ #  # ]:          0 :   if (!(wbio = smime_sign_engine(x509, pkey, mime_entity, 0))) goto err;
     322                 :          0 :   n = BIO_get_mem_data(wbio,&b64);
     323         [ #  # ]:          0 :   if (!(b64 = cut_pem_markers_off(b64, n, "PKCS7"))) goto err;
     324                 :            : 
     325                 :            :   /* Add headers */
     326                 :            : 
     327         [ #  # ]:          0 :   if (!(b = strdup("Content-type: application/x-pkcs7-mime; name=\"smime.p7m\"" CRLF
     328                 :            :                    "Content-transfer-encoding: base64" CRLF
     329                 :            :                    "Content-Disposition: attachment; filename=\"smime.p7m\"" CRLF
     330                 :          0 :                    CRLF))) GOTO_ERR("no memory?");
     331         [ #  # ]:          0 :   if (!(b = concat(b, b64))) GOTO_ERR("no memory?");
     332                 :            :   
     333                 :          0 :   BIO_free_all(wbio);  /* also frees b64 */
     334                 :          0 :   return b;
     335                 :            :   
     336                 :          0 : err:
     337         [ #  # ]:          0 :   if (wbio) BIO_free_all(wbio);
     338                 :          0 :   return NULL;
     339                 :            : }
     340                 :            : 
     341                 :            : /* Called by:  main */
     342                 :            : char*
     343                 :            : smime_sign(const char* privkey, const char* password, const char* mime_entity)
     344                 :          1 : {
     345                 :          1 :   char* b = NULL;
     346                 :          1 :   X509* x509 = NULL;
     347                 :          1 :   EVP_PKEY* pkey = NULL;
     348                 :            : 
     349                 :            :   /* Get key and certificate (why do we need both?) */
     350                 :            :   
     351         [ -  + ]:          1 :   if (!(pkey = open_private_key(privkey, password))) goto err;
     352         [ #  # ]:          0 :   if (!(x509 = extract_certificate(privkey))) goto err;
     353                 :          0 :   if (!(b = sign(x509, pkey, mime_entity))) goto err;
     354                 :            : 
     355                 :          1 : err:
     356         [ -  + ]:          1 :   if (pkey)  EVP_PKEY_free(pkey);
     357         [ -  + ]:          1 :   if (x509)  X509_free(x509);
     358                 :          1 :   return b;
     359                 :            : }
     360                 :            : 
     361                 :            : /* Encrypt a mime entity such as produced by smime_clear_sign(). */
     362                 :            : 
     363                 :            : /*
     364                 :            : MIME-Version: 1.0
     365                 :            : Content-Type: application/x-pkcs7-mime; name="smime.p7m"
     366                 :            : Content-Transfer-Encoding: base64
     367                 :            : Content-Disposition: attachment; filename="smime.p7m"
     368                 :            : Content-Description: S/MIME Encrypted Message
     369                 :            : 
     370                 :            : MIAGCSqGSIb3DQEHA6CAMIIIZQIBADGCATcwggEzAgEAMIGbMIGVMQswCQYDVQQG
     371                 :            : EwJQVDEPMA0GA1UEBxMGTGlzYm9hMRcwFQYDVQQKEw5OZXVyb25pbywgTGRhLjEZ
     372                 :            : G0DXAj0zd/4AAAAA==
     373                 :            :  */
     374                 :            : 
     375                 :            : /* Called by:  smime_encrypt */
     376                 :            : char*
     377                 :            : encrypt1(X509* x509, const char* mime_entity)
     378                 :          5 : {
     379                 :            :   time_t t;
     380                 :            :   char* b;
     381                 :            :   char* b64;
     382                 :            :   int   i, n;
     383                 :            :   char  buf[4096];
     384                 :          5 :   BIO*  p7bio = NULL;
     385                 :          5 :   BIO*  rbio = NULL;
     386                 :          5 :   BIO*  wbio = NULL;
     387                 :          5 :   PKCS7* p7 = NULL;;
     388                 :            :   
     389                 :          5 :   t = time(NULL);
     390                 :          5 :   RAND_seed(&t,sizeof(t));
     391                 :            : #ifdef WINDOWS
     392                 :            :   RAND_screen(); /* Loading video display memory into random state */
     393                 :            : #endif
     394                 :            : 
     395                 :            :   LOG_PRINT3("encrypt1", x509, mime_entity);
     396                 :            : 
     397                 :            :   /* Set up BIOs and PKCS7 machinery */
     398                 :            :   
     399         [ +  + ]:          5 :   if (!(rbio = set_read_BIO_from_buf(mime_entity, -1))) goto err;
     400                 :            :   
     401         [ -  + ]:          3 :   if (!(p7=PKCS7_new())) GOTO_ERR("no memory?");
     402                 :          3 :   PKCS7_set_type(p7,NID_pkcs7_enveloped);
     403                 :            : 
     404                 :            : #if 1
     405         [ -  + ]:          3 :   if (!PKCS7_set_cipher(p7,EVP_des_ede3_cbc()))
     406                 :          0 :     GOTO_ERR("PKCS7_set_cipher des-ede3-cbc");
     407                 :            : #else
     408                 :            :   /* SECURITY CAVEAT: weak cipher by default */
     409                 :            :   if (!PKCS7_set_cipher(p7,EVP_rc2_40_cbc()))
     410                 :            :     GOTO_ERR("PKCS7_set_cipher rc2-40-cbc");
     411                 :            : #endif
     412                 :            : 
     413                 :            :   LOG_PRINT("encrypt1: add recipient");
     414                 :            : 
     415         [ -  + ]:          3 :   if (!PKCS7_add_recipient(p7,x509)) GOTO_ERR("PKCS7_add_recipient");
     416                 :            :   
     417                 :            :   LOG_PRINT("encrypt1: data init");
     418         [ -  + ]:          3 :   if (!(p7bio=PKCS7_dataInit(p7,NULL))) GOTO_ERR("PKCS7_dataInit");
     419                 :            :   
     420                 :            :   /* pump data from file to special PKCS7 BIO. This encrypts it. */
     421                 :            :   
     422                 :            :   LOG_PRINT("encrypt1: pump");
     423                 :            :   for (;;)    {
     424                 :          6 :     i=BIO_read(rbio,buf,sizeof(buf));
     425         [ +  + ]:          6 :     if (i <= 0) break;
     426                 :          3 :     BIO_write(p7bio,buf,i);
     427                 :          3 :   }
     428                 :          3 :   BIO_flush(p7bio);
     429                 :            :   
     430                 :            :   LOG_PRINT("encrypt1: dataFinal");
     431         [ -  + ]:          3 :   if (!PKCS7_dataFinal(p7,p7bio)) GOTO_ERR("PKCS7_dataFinal");
     432                 :          3 :   BIO_free_all(rbio);
     433                 :          3 :   BIO_free_all(p7bio);
     434                 :          3 :   rbio = p7bio = NULL;
     435                 :            : 
     436         [ -  + ]:          3 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     437                 :            :   LOG_PRINT("encrypt1: write bio");
     438                 :          3 :   PEM_write_bio_PKCS7(wbio,p7);
     439                 :          3 :   BIO_flush(wbio);
     440                 :          3 :   PKCS7_free(p7);
     441                 :          3 :   p7 = NULL;
     442                 :            :   
     443                 :            :   LOG_PRINT("encrypt1: cutting markers");
     444                 :          3 :   n = BIO_get_mem_data(wbio,&b64);
     445                 :          3 :   b64 = cut_pem_markers_off(b64, n, "PKCS7");
     446                 :            :   
     447                 :            :   LOG_PRINT("encrypt1: wrapping in headers");
     448         [ -  + ]:          3 :   if (!(b = strdup("Content-type: application/x-pkcs7-mime; name=\"smime.p7m\""
     449                 :            :                    CRLF
     450                 :            :                    "Content-transfer-encoding: base64" CRLF
     451                 :            :                    "Content-Disposition: attachment; filename=\"smime.p7m\""
     452                 :          0 :                    CRLF CRLF)))  GOTO_ERR("no memory?");
     453         [ -  + ]:          3 :   if (!(b = concat(b, b64)))  GOTO_ERR("no memory?");
     454                 :            :   
     455                 :          3 :   BIO_free_all(wbio);  /* also frees b64 */
     456                 :            :   LOG_PRINT("encrypt1: OK");
     457                 :            : 
     458                 :          3 :   t = time(NULL);
     459                 :          3 :   RAND_seed(&t,sizeof(t));
     460                 :          3 :   RAND_write_file(randomfile);
     461                 :            : 
     462                 :          3 :   return b; /* return value must be freed by caller */
     463                 :            :   
     464                 :          2 : err:
     465         [ -  + ]:          2 :   if (rbio)  BIO_free_all(rbio);
     466         [ -  + ]:          2 :   if (p7bio) BIO_free_all(p7bio);
     467         [ -  + ]:          2 :   if (wbio)  BIO_free_all(wbio);
     468         [ -  + ]:          2 :   if (p7)    PKCS7_free(p7);
     469                 :          2 :   return NULL;
     470                 :            : }
     471                 :            : 
     472                 :            : /* Called by:  main */
     473                 :            : char*
     474                 :            : smime_encrypt(const char* pubkey, const char* mime_entity)
     475                 :          5 : {
     476                 :          5 :   char* b = NULL;
     477                 :            :   X509* x509;
     478                 :            :   
     479                 :            :   /* Get certificate */
     480                 :            :   
     481         [ +  - ]:          5 :   if (!(x509 = extract_certificate(pubkey))) goto err;
     482                 :          5 :   b = encrypt1(x509, mime_entity);
     483                 :            :   
     484                 :          5 : err:
     485                 :            :   //if (x509) X509_free(x509);
     486                 :          5 :   return b; /* return value must be freed by caller */
     487                 :            : }
     488                 :            : 
     489                 :            : /* ================= base64 encoding and decoding ================= */
     490                 :            : 
     491                 :            : /* Called by:  attach, main x2, mime_base64_entity */
     492                 :            : int /* returns number of bytes in result. b64 is NULL terminated */
     493                 :            : smime_base64(int encp /* true == encode */, const char* data, int len, char** out)
     494                 :          6 : {
     495                 :            :   BIO* b64bio;
     496                 :          6 :   BIO* rbio = NULL;
     497                 :          6 :   BIO* wbio = NULL;
     498                 :            :   char buf[4096];
     499                 :          6 :   int  n = -1;
     500                 :            :   
     501         [ +  - ]:          6 :   if (out) *out = NULL;
     502   [ +  -  -  + ]:          6 :   if (!data || !out) GOTO_ERR("NULL arg");
     503                 :            : 
     504                 :            :   /* create two memory buffer BIOs */
     505                 :            :   
     506         [ +  - ]:          6 :   if (!(rbio = set_read_BIO_from_buf(data, len))) goto err;
     507         [ -  + ]:          6 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     508                 :            :   
     509                 :            :   /* insert base64 filter */
     510                 :            :   
     511         [ -  + ]:          6 :   if (!(b64bio=BIO_new(BIO_f_base64()))) GOTO_ERR("no memory?");
     512         [ +  + ]:          6 :   if (encp)
     513                 :          5 :     wbio=BIO_push(b64bio,wbio);
     514                 :            :   else
     515                 :          1 :     rbio=BIO_push(b64bio,rbio);
     516                 :            : 
     517                 :            :   /* pump stuff through filter */
     518                 :            : 
     519                 :            :   for (;;) {
     520         [ +  + ]:         12 :     if ((n=BIO_read(rbio,buf,sizeof(buf))) <= 0) break;
     521         [ -  + ]:          6 :     if (BIO_write(wbio, buf,n) != n) GOTO_ERR("no memory? (base64 pump)");
     522                 :          6 :   }
     523                 :            : 
     524                 :            :   /* free BIOs and return base64 encoded block */
     525                 :            :   
     526                 :          6 :   n = get_written_BIO_data(wbio, out); /* if error (-1) will just propagate */
     527                 :            : 
     528                 :          6 : err:
     529         [ +  - ]:          6 :   if (wbio) BIO_free_all(wbio);  /* b64bio is freed as part of the stack */
     530         [ +  - ]:          6 :   if (rbio) BIO_free_all(rbio);
     531                 :          6 :   return n;
     532                 :            : }
     533                 :            : 
     534                 :            : /* EOF  -  smime-enc.c */

Generated by: LCOV version 1.9