I have a S/MIME application that creates signatures but does not
include the signing certificate in the message on the presumption that
receiver already has it (and it is in his, and not mine, interest to
enforce the signed contract ;-).

This works fine with Netscape (only gripe is that Netscape apparently
does not accept signatures made with self signed certificate, but
thats not fatal). But when I try to do it with openssl, it seg faults
because crypto/pk7_doit.c, around line 626 on OpenSSL-0.9.4-release
because of NULL pointer as explained in comments:

int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, BIO *bio,
             PKCS7 *p7, PKCS7_SIGNER_INFO *si)
        {
        PKCS7_ISSUER_AND_SERIAL *ias;
        int ret=0,i;
        STACK_OF(X509) *cert;
        X509 *x509;

        if (PKCS7_type_is_signed(p7))
                {
                cert=p7->d.sign->cert;
                }
        else if (PKCS7_type_is_signedAndEnveloped(p7))
                {
                cert=p7->d.signed_and_enveloped->cert;
                /* my signature causes this path to be taken. As there
                 * are no certificates, cert will be NULL --Sampo */
                }
        else
                {
                PKCS7err(PKCS7_F_PKCS7_DATAVERIFY,PKCS7_R_WRONG_PKCS7_TYPE);
                goto err;
                }
        /* XXXXXXXXXXXXXXXXXXXXXXX */
        ias=si->issuer_and_serial;

        /* BOOOOM! in the next line because cert is NULL --Sampo */
        x509=X509_find_by_issuer_and_serial(cert,ias->issuer,ias->serial);

        (snip)
        }

I presume that the author of this code still had not completed it as
there is this huge XXXXX comment. Still, I find it illadviced to go
looking for certs in the message itself. Shouldn't the code go looking
for the messages in the certificate database (as passed in the
arguments cert_store and ctx)?

The code I use to call this function follows

smime_verify_signature(char* pubkey, char* signed_entity)
{
  X509*  x509 = NULL;
  PKCS7* p7 = NULL;
  STACK_OF(PKCS7_SIGNER_INFO) *sigs;
  X509_STORE* certs=NULL;
  BIO*   detached = NULL;
  BIO*   p7bio;
  char   buf[4096];
  int    i,x;
  
  if (!(p7 = get_pkcs7_from_pem(signed_entity))) goto err;

  /* Use EAY style directory of hash-symlinks pointing to certs certificate
   * store. */
  if (!(certs=X509_STORE_new())) GOTO_ERR("no memory?");
  X509_STORE_set_default_paths(certs);
  X509_STORE_load_locations(certs,NULL,"certs");
  X509_STORE_set_verify_cb_func(certs,verify_callback);
  ERR_clear_error();

  detached = (BIO*)PKCS7_get_detached(p7);
  if (!(p7bio=PKCS7_dataInit(p7,detached))) GOTO_ERR("PKCS7_dataInit");
  
  /* We now have to 'read' from p7bio to calculate message digest(s) */
  for (;;) {
    i = BIO_read(p7bio,buf,sizeof(buf));
    if (i <= 0) break;
  }

  /* We can now verify signatures */
  if (!(sigs=PKCS7_get_signer_info(p7)))
    GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)");
  
  /* Ok, first we need to, for each subject entry, see if we can verify */
  for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sigs); i++) {
    X509_STORE_CTX cert_ctx;
    PKCS7_SIGNER_INFO *si;
    ASN1_UTCTIME *tm;
    char *str1,*str2;
    
    si=sk_PKCS7_SIGNER_INFO_value(sigs,i);
    
    /* The bio is needed here only to lookup the message digest context
     * which presumably now contains the message digest. It will not be
     * read, and hence its good for any number of iterations. This is so
     * because MD bios pass the data right thru so they can be stacked
     * to calculate multiple message digests simultaneously. Clever, eh?
     */

#if 1
    /* verifies by looking up the certificate from certs database,
     * verifying the validity of the certificate, and finally
     * validity of the signature */

    x=PKCS7_dataVerify(certs, &cert_ctx, p7bio, p7, si);
#else
    /* just verify the signature, given that we already have certificate
     * candidate (see crypto/pk7_doit.c around line 675) */

    if (!(x509 = extract_certificate(pubkey))) goto err;
    x=PKCS7_signatureVerify(p7bio, p7, si, x509);
#endif
    if (x <= 0) GOTO_ERR("14 sig verify failed");
    
  }
  
  BIO_free_all(p7bio);
  PKCS7_free(p7);
  X509_STORE_free(certs);
  return "ok";

err:
  return NULL;
}

If I use PKCS7_signatureVerify() it works fine (even for self signed
certs), but obviously I do not have guarantee about validity of the
certificate itself.

--Sampo
______________________________________________________________________
OpenSSL Project                                 http://www.openssl.org
Development Mailing List                       [EMAIL PROTECTED]
Automated List Manager                           [EMAIL PROTECTED]

Reply via email to