LCOV - code coverage report
Current view: top level - zxid - smime-vfy.c (source / functions) Hit Total Coverage
Test: ZXID Code Coverage Lines: 66 141 46.8 %
Date: 2010-12-19 Functions: 5 7 71.4 %
Branches: 35 130 26.9 %

           Branch data     Line data    Source code
       1                 :            : /* smime-vfy.c  -  Utility functions for performing S/MIME signature
       2                 :            :  *                 verification and decryption.
       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,  fixed double free in decryption --Sampo
      14                 :            :  * 14.11.1999, added verification of detached sigs, i.e. clear sigs --Sampo
      15                 :            :  *
      16                 :            :  * This module has adopted ideas and control flow from
      17                 :            :  *    openssl-0.9.4/crypto/pkcs7/sign.c
      18                 :            :  *    openssl-0.9.4/crypto/pkcs7/verify.c
      19                 :            :  *    openssl-0.9.4/crypto/pkcs7/enc.c
      20                 :            :  *    openssl-0.9.4/crypto/pkcs7/dec.c
      21                 :            :  * which are Copyright (c) 1995-1998 Eric Young (eay@cryptsoft.com),
      22                 :            :  * All rights reserved. See file LICENSE for conditions.
      23                 :            :  *
      24                 :            :  * This module has been developed to support a Lingo XTRA that is supposed
      25                 :            :  * to provide crypto functionality. It may, however, be useful for other
      26                 :            :  * purposes as well.
      27                 :            :  *
      28                 :            :  * This is a very simple S/MIME library. For example the multipart
      29                 :            :  * boundary separators are hard coded and no effort is made to verify
      30                 :            :  * that mime entities are in their canonical form before signing (the
      31                 :            :  * caller should make sure they are, canonical form means using CRLF
      32                 :            :  * as line termination, among other things). Also the multipart functionality
      33                 :            :  * only understands up to 3 attachments. For many tasks this is enough,
      34                 :            :  * but if its not, feel free to write more generic utilities.
      35                 :            :  *
      36                 :            :  * Memory management: most routines malloc the results. Freeing them is
      37                 :            :  * application's responsibility. I use libc malloc, but if in doubt
      38                 :            :  * it might be safer to just leak the memory (i.e. don't ever free it).
      39                 :            :  * This library works entirely in memory, so maximum memory consumption
      40                 :            :  * might be more than twice the total size of all files to be encrypted.
      41                 :            :  */
      42                 :            : 
      43                 :            : /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
      44                 :            :  * All rights reserved.
      45                 :            :  *
      46                 :            :  * This package is an SSL implementation written
      47                 :            :  * by Eric Young (eay@cryptsoft.com).
      48                 :            :  * The implementation was written so as to conform with Netscapes SSL.
      49                 :            :  * 
      50                 :            :  * This library is free for commercial and non-commercial use as long as
      51                 :            :  * the following conditions are aheared to.  The following conditions
      52                 :            :  * apply to all code found in this distribution, be it the RC4, RSA,
      53                 :            :  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
      54                 :            :  * included with this distribution is covered by the same copyright terms
      55                 :            :  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
      56                 :            :  * 
      57                 :            :  * Copyright remains Eric Young's, and as such any Copyright notices in
      58                 :            :  * the code are not to be removed.
      59                 :            :  * If this package is used in a product, Eric Young should be given attribution
      60                 :            :  * as the author of the parts of the library used.
      61                 :            :  * This can be in the form of a textual message at program startup or
      62                 :            :  * in documentation (online or textual) provided with the package.
      63                 :            :  * 
      64                 :            :  * Redistribution and use in source and binary forms, with or without
      65                 :            :  * modification, are permitted provided that the following conditions
      66                 :            :  * are met:
      67                 :            :  * 1. Redistributions of source code must retain the copyright
      68                 :            :  *    notice, this list of conditions and the following disclaimer.
      69                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      70                 :            :  *    notice, this list of conditions and the following disclaimer in the
      71                 :            :  *    documentation and/or other materials provided with the distribution.
      72                 :            :  * 3. All advertising materials mentioning features or use of this software
      73                 :            :  *    must display the following acknowledgement:
      74                 :            :  *    "This product includes cryptographic software written by
      75                 :            :  *     Eric Young (eay@cryptsoft.com)"
      76                 :            :  *    The word 'cryptographic' can be left out if the rouines from the library
      77                 :            :  *    being used are not cryptographic related :-).
      78                 :            :  * 4. If you include any Windows specific code (or a derivative thereof) from 
      79                 :            :  *   the apps directory (application code) you must include an acknowledgement:
      80                 :            :  *   "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
      81                 :            :  * 
      82                 :            :  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
      83                 :            :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      84                 :            :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      85                 :            :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      86                 :            :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      87                 :            :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      88                 :            :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      89                 :            :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      90                 :            :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      91                 :            :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      92                 :            :  * SUCH DAMAGE.
      93                 :            :  * 
      94                 :            :  * The licence and distribution terms for any publically available version or
      95                 :            :  * derivative of this code cannot be changed.  i.e. this code cannot simply be
      96                 :            :  * copied and put under another distribution licence
      97                 :            :  * [including the GNU Public Licence.]
      98                 :            :  */
      99                 :            : 
     100                 :            : #include "platform.h"
     101                 :            : 
     102                 :            : #include <stdlib.h>
     103                 :            : #include <string.h>
     104                 :            : #include <time.h>
     105                 :            : 
     106                 :            : #if defined(macintosh) || defined(__INTEL__)
     107                 :            : #include "macglue.h"
     108                 :            : #endif
     109                 :            : 
     110                 :            : #include "logprint.h"
     111                 :            : 
     112                 :            : #include <openssl/crypto.h>
     113                 :            : #include <openssl/buffer.h>
     114                 :            : #include <openssl/stack.h>
     115                 :            : #include <openssl/bio.h>
     116                 :            : #include <openssl/x509.h>
     117                 :            : #include <openssl/pem.h>
     118                 :            : #include <openssl/err.h>
     119                 :            : 
     120                 :            : #define SMIME_INTERNALS  /* we want also our internal helper functions */
     121                 :            : #include "smimeutil.h"
     122                 :            : 
     123                 :            : /* ============= S I G N A T U R E   V E R I F I C A T I O N ============== */
     124                 :            : /* ==================== A N D   D E C R Y P T I O N ======================= */
     125                 :            : 
     126                 :            : /* Called by:  decrypt, smime_get_signer_info, smime_verify_signature */
     127                 :            : static PKCS7*
     128                 :            : get_pkcs7_from_pem(const char* enc_entity)
     129                 :          3 : {
     130                 :            :   const char* p;
     131                 :          3 :   char*  wrapped_enc_entity = NULL;
     132                 :          3 :   BIO*   rbio = NULL;
     133                 :          3 :   PKCS7* p7 = NULL;
     134                 :            :  
     135                 :            :   /* Check if encrypted entity is composed of raw data or if it has some
     136                 :            :    * headers. In the latter case, just skip the headers. Headers are
     137                 :            :    * separated from data by an empty line (hence sequence CRLF CRLF).*/
     138                 :            :   
     139         [ -  + ]:          3 :   if ((p = strstr(enc_entity, CRLF CRLF))) {
     140                 :          0 :     enc_entity = p+4;
     141         [ +  + ]:          3 :   } else if ((p = strstr(enc_entity, LF LF))) {
     142                 :          1 :     enc_entity = p+2;
     143         [ -  + ]:          2 :   } else if ((p = strstr(enc_entity, CR CR))) {
     144                 :          0 :     enc_entity = p+2;
     145                 :            :   }
     146                 :            :   
     147                 :            :   /* Make sure the pem markers are there */
     148                 :            :   
     149                 :            :   LOG_PRINT("get_pkcs7_from_pem: wrapping in pem markers");
     150                 :            : 
     151         [ -  + ]:          3 :   if (!(wrapped_enc_entity = wrap_in_pem_markers(enc_entity, "PKCS7")))
     152                 :          0 :     GOTO_ERR("no memory?");
     153                 :            :   LOG_PRINT("get_pkcs7_from_pem: wrapped.");
     154                 :            :   
     155                 :            :   /* Set up BIO so encrypted/signed data can be read from pem file */
     156                 :            :   
     157         [ +  - ]:          3 :   if (!(rbio = set_read_BIO_from_buf(wrapped_enc_entity, -1))) goto err;
     158                 :            :   
     159                 :            :   LOG_PRINT("get_pkcs7_from_pem: ready to read PKCS7 bio...");
     160                 :            : 
     161                 :            :   /* Load the PKCS7 object from a pem file to internal representation.
     162                 :            :    * this reads all of the data file. */
     163                 :            :   
     164         [ +  - ]:          3 :   if (!(p7=PEM_read_bio_PKCS7(rbio,NULL/*&x*/,NULL/*callback*/,NULL/*arg*/)))
     165                 :          3 :     GOTO_ERR("11 corrupt PEM PKCS7 file? (PEM_read_bio_PKCS7)");
     166                 :            : 
     167                 :            :   LOG_PRINT("get_pkcs7_from_pem: bio read");
     168                 :            : 
     169                 :          0 :   BIO_free_all(rbio);
     170                 :          0 :   OPENSSL_free(wrapped_enc_entity);
     171                 :          0 :   return p7;
     172                 :          3 : err:
     173         [ +  - ]:          3 :   if (rbio) BIO_free_all(rbio);
     174         [ +  - ]:          3 :   if (wrapped_enc_entity) OPENSSL_free(wrapped_enc_entity);
     175                 :          3 :   return NULL;
     176                 :            : }
     177                 :            : 
     178                 :            : /* Typically receiver has to know in what order the signature and encryption
     179                 :            :  * were applied (usually encryption is outermost) and then call these
     180                 :            :  * functions in right order, e.g:
     181                 :            :  */
     182                 :            : 
     183                 :            : /* Called by:  smime_decrypt */
     184                 :            : int  /* return size of data, -1 on failure */
     185                 :            : decrypt(X509* x509, EVP_PKEY* pkey, const char* enc_entity, char** data_out)
     186                 :          0 : {
     187                 :            :   char buf[4096];
     188                 :            :   int  i,n;
     189                 :          0 :   BIO* wbio = NULL;
     190                 :          0 :   BIO* p7bio = NULL;
     191                 :          0 :   PKCS7 *p7 = NULL;
     192                 :            : 
     193         [ #  # ]:          0 :   if (data_out) *data_out = NULL;
     194   [ #  #  #  #  :          0 :   if (!x509 || !pkey || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
             #  #  #  # ]
     195                 :            :   LOG_PRINT("decrypt: get_pkcs7_from_pem");
     196         [ #  # ]:          0 :   if (!(p7 = get_pkcs7_from_pem(enc_entity))) goto err;
     197                 :            :   
     198                 :            :   /* Decrypt the symmetric key with private key and obtain symmetric
     199                 :            :    * cipher stream (BIO). The cert is needed here to look up one of
     200                 :            :    * possibly multiple recipient infos present in PKCS7 object. Issuer
     201                 :            :    * and serial number must match (these two fields form unique ID for
     202                 :            :    * cert). Actual public key part of the X509 cert is not used for
     203                 :            :    * anything here.  */
     204                 :            : 
     205                 :            :   LOG_PRINT("decrypt: dataDecode");
     206         [ #  # ]:          0 :   if (!(p7bio=PKCS7_dataDecode(p7,pkey,NULL/*detached*/,x509)))
     207                 :          0 :     GOTO_ERR("12 no recipient matches cert or private key could not decrypt, i.e. wrong key (PKCS7_dataDecode)");
     208                 :            :   LOG_PRINT("decrypt: ready to pump");
     209                 :            : 
     210                 :            :   /* Pump data from p7bio to decrypt symmetric cipher */
     211                 :            :   
     212         [ #  # ]:          0 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     213                 :            : 
     214                 :            :   for (;;) {
     215         [ #  # ]:          0 :     if ((i=BIO_read(p7bio,buf,sizeof(buf))) <= 0) break;
     216                 :          0 :     BIO_write(wbio,buf,i);
     217                 :          0 :   }  
     218                 :          0 :   BIO_flush(wbio);
     219                 :          0 :   BIO_free_all(p7bio);
     220                 :          0 :   p7bio = NULL;
     221                 :          0 :   PKCS7_free(p7);
     222                 :          0 :   p7 = NULL;
     223                 :            : 
     224                 :            :   LOG_PRINT("decrypt: pump done");
     225                 :            : 
     226                 :            :   /* Return data (this should now be easier because we just freed
     227                 :            :    * some memory) */
     228                 :            : 
     229                 :          0 :   n = get_written_BIO_data(wbio, data_out);
     230                 :          0 :   BIO_free_all(wbio);
     231                 :          0 :   return n;  
     232                 :            :   
     233                 :          0 : err:  
     234         [ #  # ]:          0 :   if (p7)    PKCS7_free(p7);
     235         [ #  # ]:          0 :   if (wbio)  BIO_free_all(wbio);
     236         [ #  # ]:          0 :   if (p7bio) BIO_free_all(p7bio);
     237                 :          0 :   return -1;
     238                 :            : }
     239                 :            : 
     240                 :            : /* Called by:  main */
     241                 :            : int  /* return size of data, -1 on failure */
     242                 :            : smime_decrypt(const char* privkey,
     243                 :            :               const char* passwd,
     244                 :            :               const char* enc_entity,
     245                 :            :               char** data_out)
     246                 :          1 : {
     247                 :          1 :   int  n = -1;
     248                 :          1 :   EVP_PKEY *pkey = NULL;
     249                 :          1 :   X509  *x509 = NULL;
     250                 :            :   
     251         [ +  - ]:          1 :   if (data_out) *data_out = NULL;
     252   [ +  -  +  -  :          1 :   if (!privkey || !passwd || !enc_entity || !data_out) GOTO_ERR("NULL arg(s)");
             +  -  -  + ]
     253         [ -  + ]:          1 :   if (!(pkey = open_private_key(privkey, passwd))) goto err;
     254         [ #  # ]:          0 :   if (!(x509 = extract_certificate(privkey)))      goto err;
     255                 :          0 :   n = decrypt(x509, pkey, enc_entity, data_out);
     256                 :            :     
     257                 :          1 : err:  
     258         [ -  + ]:          1 :   if (pkey)  EVP_PKEY_free(pkey);
     259         [ -  + ]:          1 :   if (x509)  X509_free(x509);
     260                 :          1 :   return n;
     261                 :            : }
     262                 :            : 
     263                 :            : /* ------------------------------------------------ */
     264                 :            : 
     265                 :            : #if 0
     266                 :            : /* copied from verify.c */
     267                 :            : /* should be X509* but we can just have them as char*. (??? --Sampo) */
     268                 :            : /* Called by: */
     269                 :            : static int
     270                 :            : verify_callback(int ok, X509_STORE_CTX *ctx) {
     271                 :            :   char buf[256];
     272                 :            :   X509 *err_cert;
     273                 :            :   int err,depth;
     274                 :            : 
     275                 :            :   err_cert=X509_STORE_CTX_get_current_cert(ctx);
     276                 :            :   err=   X509_STORE_CTX_get_error(ctx);
     277                 :            :   depth= X509_STORE_CTX_get_error_depth(ctx);
     278                 :            : 
     279                 :            :   X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof(buf));
     280                 :            :   fprintf(stderr,"depth=%d %s\n",depth,buf);
     281                 :            :   if (!ok) {
     282                 :            :     fprintf(stderr,"verify error:num=%d:%s\n",err,
     283                 :            :             X509_verify_cert_error_string(err));
     284                 :            :     if (depth < 6) {
     285                 :            :       ok=1;
     286                 :            :       X509_STORE_CTX_set_error(ctx,X509_V_OK);
     287                 :            :     } else {
     288                 :            :       ok=0;
     289                 :            :       X509_STORE_CTX_set_error(ctx,X509_V_ERR_CERT_CHAIN_TOO_LONG);
     290                 :            :     }
     291                 :            :   }
     292                 :            :   switch (ctx->error) {
     293                 :            :   case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
     294                 :            :     X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert),buf,sizeof(buf));
     295                 :            :     fprintf(stderr,"issuer= %s\n",buf);
     296                 :            :     break;
     297                 :            : #if 1
     298                 :            :   case X509_V_ERR_CERT_NOT_YET_VALID:
     299                 :            :   case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
     300                 :            :     fprintf(stderr,"notBefore=");
     301                 :            :     /*ASN1_UTCTIME_print(bio_err,X509_get_notBefore(ctx->current_cert));
     302                 :            :       BIO_printf(bio_err,"\n");*/
     303                 :            :     break;
     304                 :            :   case X509_V_ERR_CERT_HAS_EXPIRED:
     305                 :            :   case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
     306                 :            :     fprintf(stderr,"notAfter=");
     307                 :            :     /*ASN1_UTCTIME_print(bio_err,X509_get_notAfter(ctx->current_cert));
     308                 :            :       BIO_printf(bio_err,"\n"); */
     309                 :            :     break;
     310                 :            : #endif
     311                 :            :   }
     312                 :            :   fprintf(stderr,"verify return:%d\n",ok);
     313                 :            :   return(ok);
     314                 :            : }
     315                 :            : 
     316                 :            : static int signed_seq2string_nid= -1;
     317                 :            : /* For this case, I will malloc the return strings */
     318                 :            : /* Called by:  smime_verify_signature */
     319                 :            : static int
     320                 :            : get_signed_seq2string(PKCS7_SIGNER_INFO *si, char **str1, char **str2) {
     321                 :            : #if 0
     322                 :            :   ASN1_TYPE *so;
     323                 :            :   if (signed_seq2string_nid == -1)
     324                 :            :     signed_seq2string_nid=
     325                 :            :       OBJ_create("1.9.9999","OID_example","Our example OID");
     326                 :            :   /* To retrieve */
     327                 :            :   so=PKCS7_get_signed_attribute(si,signed_seq2string_nid);
     328                 :            :   if (so && (so->type == V_ASN1_SEQUENCE))
     329                 :            :     {
     330                 :            :       ASN1_CTX c;
     331                 :            :       ASN1_STRING *s;
     332                 :            :       long length;
     333                 :            :       ASN1_OCTET_STRING *os1,*os2;
     334                 :            :       
     335                 :            :       s=so->value.sequence;
     336                 :            :       c.p=ASN1_STRING_data(s);
     337                 :            :       c.max=c.p+ASN1_STRING_length(s);
     338                 :            :       if (!asn1_GetSequence(&c,&length)) GOTO_ERR("") err;
     339                 :            :       /* Length is the length of the seqence */
     340                 :            :       
     341                 :            :       c.q=c.p;
     342                 :            :       if ((os1=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL) 
     343                 :            :         GOTO_ERR("");
     344                 :            :       c.slen-=(c.p-c.q);
     345                 :            :       
     346                 :            :       c.q=c.p;
     347                 :            :       if ((os2=d2i_ASN1_OCTET_STRING(NULL,&c.p,c.slen)) == NULL) 
     348                 :            :         GOTO_ERR("");
     349                 :            :       c.slen-=(c.p-c.q);
     350                 :            :       
     351                 :            :       if (!asn1_Finish(&c)) GOTO_ERR("") err;
     352                 :            :       *str1=Malloc(os1->length+1);
     353                 :            :       *str2=Malloc(os2->length+1);
     354                 :            :       memcpy(*str1,os1->data,os1->length);
     355                 :            :       memcpy(*str2,os2->data,os2->length);
     356                 :            :       (*str1)[os1->length]='\0';
     357                 :            :       (*str2)[os2->length]='\0';
     358                 :            :       ASN1_OCTET_STRING_free(os1);
     359                 :            :       ASN1_OCTET_STRING_free(os2);
     360                 :            :       return(1);
     361                 :            :     }
     362                 :            :  err:
     363                 :            : #endif
     364                 :            :   return(0);
     365                 :            : }
     366                 :            : #endif
     367                 :            : 
     368                 :            : /* Called by:  main */
     369                 :            : long  /* return serial on success, -1 on failure */
     370                 :            : smime_get_signer_info(const char* signed_entity,
     371                 :            :                       int info_ix,     /* 0 = first signer */
     372                 :            :                       char** issuer)   /* DN of the issuer */
     373                 :          1 : {
     374                 :          1 :   int serial = -1;
     375                 :          1 :   PKCS7* p7 = NULL;
     376                 :          1 :   STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
     377                 :            :   PKCS7_SIGNER_INFO* si;
     378                 :            :   
     379   [ +  -  -  + ]:          1 :   if (!signed_entity || !issuer) GOTO_ERR("NULL arg(s)");
     380                 :          1 :   *issuer = NULL;
     381                 :            :   
     382         [ -  + ]:          1 :   if (!(p7 = get_pkcs7_from_pem(signed_entity))) goto err;
     383         [ #  # ]:          0 :   if (!(sigs=PKCS7_get_signer_info(p7)))
     384                 :          0 :     GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
     385                 :            : 
     386         [ #  # ]:          0 :   if (info_ix >= sk_PKCS7_SIGNER_INFO_num(sigs))
     387                 :          0 :     GOTO_ERR("No more signers. info_ix too large.");
     388                 :            : 
     389         [ #  # ]:          0 :   if (!(si=sk_PKCS7_SIGNER_INFO_value(sigs,info_ix)))
     390                 :          0 :     GOTO_ERR("NULL signer info");
     391                 :            :   
     392                 :          0 :   *issuer = X509_NAME_oneline(si->issuer_and_serial->issuer, NULL,0);
     393                 :          0 :   serial = ASN1_INTEGER_get(si->issuer_and_serial->serial);
     394                 :            :   
     395                 :          1 : err:
     396         [ -  + ]:          1 :   if (p7) PKCS7_free(p7);
     397                 :          1 :   return serial;
     398                 :            : }
     399                 :            : 
     400                 :            : /* Called by:  main x3 */
     401                 :            : char* /* returns contents of the signed message, NULL if error */
     402                 :            : smime_verify_signature(const char* pubkey,
     403                 :            :                        const char* sig_entity,     /* signed entity
     404                 :            :                                                       or just the sigature */
     405                 :            :                        const char* detached_data,  /* possibly NULL */
     406                 :            :                        int detached_data_len)
     407                 :          2 : {
     408                 :          2 :   X509*  x509 = NULL;
     409                 :          2 :   PKCS7* p7 = NULL;
     410                 :          2 :   STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL;
     411                 :          2 :   X509_STORE* certs=NULL;
     412                 :          2 :   BIO*   detached = NULL;
     413                 :          2 :   BIO*   p7bio = NULL;
     414                 :          2 :   BIO*   wbio = NULL;
     415                 :          2 :   char*  data = NULL;
     416                 :            :   char   buf[4096];
     417                 :            :   int    i,x;
     418                 :            :   
     419   [ +  -  -  + ]:          2 :   if (!sig_entity || !pubkey) GOTO_ERR("NULL arg(s)");
     420         [ -  + ]:          2 :   if (!(p7 = get_pkcs7_from_pem(sig_entity))) goto err;
     421                 :            : 
     422                 :            :   /* Hmm, if its clear signed, we already provided the detached sig, but
     423                 :            :    * if its one sig blob, may be PKCS7_get_detached() provides BIO connected
     424                 :            :    * to the detached part. Go figure.
     425                 :            :    */
     426                 :            : 
     427   [ #  #  #  # ]:          0 :   if (detached_data && detached_data_len) {
     428         [ #  # ]:          0 :     if (!(detached = set_read_BIO_from_buf(detached_data, detached_data_len)))
     429                 :          0 :       goto err;
     430                 :            :   } else {
     431         [ #  # ]:          0 :     if (!PKCS7_get_detached(p7))
     432                 :          0 :       GOTO_ERR("15 cant extract signed data from signed entity (PKCS7_get_detached)");
     433                 :            :   }
     434         [ #  # ]:          0 :   if (!(p7bio=PKCS7_dataInit(p7,detached))) GOTO_ERR("PKCS7_dataInit");
     435                 :            :   
     436         [ #  # ]:          0 :   if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?");
     437                 :            :   
     438                 :            :   /* We now have to 'read' from p7bio to calculate message digest(s).
     439                 :            :    * I also take the opportunity to save the signed data. */
     440                 :            :   for (;;) {
     441                 :          0 :     i = BIO_read(p7bio,buf,sizeof(buf));
     442         [ #  # ]:          0 :     if (i <= 0) break;
     443                 :          0 :     BIO_write(wbio, buf, i);
     444                 :          0 :   }
     445                 :            :   
     446         [ #  # ]:          0 :   if (get_written_BIO_data(wbio, &data)==-1) goto err;
     447                 :          0 :   BIO_free_all(wbio);
     448                 :          0 :   wbio = NULL;
     449                 :            :   
     450                 :            :   /* We can now verify signatures */
     451         [ #  # ]:          0 :   if (!(sigs=PKCS7_get_signer_info(p7)))
     452                 :          0 :     GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
     453                 :            :   
     454                 :            :   /* Ok, first we need to, for each subject entry, see if we can verify */
     455         [ #  # ]:          0 :   for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sigs); i++) {
     456                 :            :     PKCS7_SIGNER_INFO *si;
     457                 :            :     
     458                 :          0 :     si=sk_PKCS7_SIGNER_INFO_value(sigs,i);
     459                 :            :     
     460                 :            :     /* The bio is needed here only to lookup the message digest context
     461                 :            :      * which presumably now contains the message digest. It will not be
     462                 :            :      * read, and hence its good for any number of iterations. This is so
     463                 :            :      * because MD bios pass the data right thru so they can be stacked
     464                 :            :      * to calculate multiple message digests simultaneously. Clever, eh?
     465                 :            :      */
     466                 :            : 
     467                 :            : #if 0
     468                 :            :     /* *** this is currently broken and thus disabled. --Sampo */
     469                 :            :     /* verifies by looking up the certificate from certs database,
     470                 :            :      * verifying the validity of the certificate, and finally
     471                 :            :      * validity of the signature */
     472                 :            : 
     473                 :            :     X509_STORE_CTX cert_ctx;
     474                 :            :     x=PKCS7_dataVerify(certs, &cert_ctx, p7bio, p7, si);
     475                 :            : #else
     476                 :            :     /* just verify the signature, given that we already have certificate
     477                 :            :      * candidate (see crypto/pk7_doit.c around line 675) */
     478                 :            : 
     479         [ #  # ]:          0 :     if (!(x509 = extract_certificate(pubkey))) goto err;
     480                 :          0 :     x=PKCS7_signatureVerify(p7bio, p7, si, x509);
     481                 :            : #endif
     482         [ #  # ]:          0 :     if (x <= 0) GOTO_ERR("14 sig verify failed");
     483                 :            :     
     484                 :            : #if 0
     485                 :            :     ASN1_UTCTIME *tm;
     486                 :            :     if ((tm=get_signed_time(si)) != NULL) {
     487                 :            :       //fprintf(stderr,"Signed time:");
     488                 :            :       //ASN1_UTCTIME_print(bio_out,tm);
     489                 :            :       ASN1_UTCTIME_free(tm);
     490                 :            :       //BIO_printf(bio_out,"\n");
     491                 :            :     }
     492                 :            : #endif
     493                 :            : #if 0
     494                 :            :     char *str1,*str2;
     495                 :            :     if (get_signed_seq2string(si,&str1,&str2)) {
     496                 :            :       fprintf(stderr,"String 1 is %s\n",str1);
     497                 :            :       fprintf(stderr,"String 2 is %s\n",str2);
     498                 :            :     }
     499                 :            : #endif
     500                 :            :   }
     501                 :            :   
     502                 :          0 :   BIO_free_all(p7bio);
     503                 :          0 :   PKCS7_free(p7);
     504                 :          0 :   X509_STORE_free(certs);
     505                 :          0 :   return data;    /* return the signed plain text */
     506                 :            : 
     507                 :          2 : err:
     508         [ -  + ]:          2 :   if (wbio) BIO_free_all(wbio);
     509         [ -  + ]:          2 :   if (p7bio) BIO_free_all(p7bio);
     510         [ -  + ]:          2 :   if (p7) PKCS7_free(p7);
     511         [ -  + ]:          2 :   if (certs) X509_STORE_free(certs);
     512         [ -  + ]:          2 :   if (data) OPENSSL_free(data);
     513                 :          2 :   return NULL;
     514                 :            : }
     515                 :            : 
     516                 :            : /* =========== C E R T   V E R I F I C A T I O N =========== */
     517                 :            : 
     518                 :            : /* Called by:  smime_verify_cert */
     519                 :            : int  /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
     520                 :            : verify_cert(X509* ca_cert, X509* cert)
     521                 :          0 : {
     522                 :          0 :   EVP_PKEY* pkey = NULL;
     523   [ #  #  #  # ]:          0 :   if (!ca_cert || !cert) GOTO_ERR("NULL arg(s)");
     524         [ #  # ]:          0 :   if (!(pkey=X509_get_pubkey(ca_cert))) GOTO_ERR("no memory?");
     525                 :          0 :   return X509_verify(cert, pkey);
     526                 :          0 : err:
     527                 :          0 :   return -1;
     528                 :            : }
     529                 :            : 
     530                 :            : /* Called by:  main */
     531                 :            : int  /* returns -1 if error, 0 if verfy fail, and 1 if verify OK */
     532                 :            : smime_verify_cert(const char* ca_cert_pem, const char* cert_pem)
     533                 :          1 : {
     534                 :          1 :   X509* ca_cert = NULL;
     535                 :          1 :   X509* cert = NULL;
     536                 :          1 :   int ret = -1;
     537   [ +  -  -  + ]:          1 :   if (!ca_cert_pem || !cert_pem) GOTO_ERR("NULL arg(s)");
     538         [ +  - ]:          1 :   if (!(ca_cert = extract_certificate(ca_cert_pem))) goto err;
     539         [ -  + ]:          1 :   if (!(cert = extract_certificate(cert_pem))) goto err;
     540                 :          0 :   ret = verify_cert(ca_cert, cert);
     541                 :          1 : err:
     542         [ +  - ]:          1 :   if (ca_cert) X509_free(ca_cert);
     543         [ -  + ]:          1 :   if (cert) X509_free(cert);
     544                 :          1 :   return ret;
     545                 :            : }
     546                 :            : 
     547                 :            : /* EOF  -  smime-vfy.c */

Generated by: LCOV version 1.9