OpenSSL Developers -

Here's a useful little hack I consed up this morning when confronted
yet again with the question "Is this really the correct private key
file that goes with the certificate I'm trying to use (or have I lost
the #@$&*% private key file yet again)" ... :)  It even seems to work.
Or at least, when I give it the right private key, it's happy.  And
when I give it the wrong private key, it's unhappy in the right sort
of way.

TT

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "err.h"
#include "evp.h"
#include "rand.h"
#include "x509.h"
#include "x509v3.h"
#include "pem.h"

static char* usage[]={
"usage: vericert\n",
" -cert file    certificate file (x509 or pkcs7), required\n",
" -key file     key file, required\n",
" -pass string  passphrase, optional\n",
NULL
};

static char* passphrase;

static X509* getcert(char* file) {
  FILE* fp;
  X509* cert = NULL;
  STACK* sk = NULL;
  PKCS7 *pk7 = NULL;

  if ((fp = fopen(file, "rb")) == NULL) {
    fprintf(stderr, "failed to open file %s\n", file);
    goto err;
  }
  pk7 = PEM_read_PKCS7(fp, NULL, NULL);
  fclose(fp);
  fp = NULL;
  if (pk7) {
    if (!PKCS7_type_is_signed(pk7)) {
      fprintf(stderr, "pkcs7 file %s is not pkcs7 signed type\n", file);
      goto err;
    }
    cert = (X509*)sk_value(pk7->d.sign->cert,sk_num(pk7->d.sign->cert)-1);
    if (!(cert = X509_dup(cert))) {
      ERR_print_errors_fp(stderr);
      fprintf(stderr, "trying to duplicate cert from pkcs7 file %s\n", file);
      goto err;
    }
    PKCS7_free(pk7);
  } 
  else {
    if ((fp = fopen(file, "rb")) == NULL) {
      fprintf(stderr, "failed to open file %s\n", file);
      goto err;
    }
    cert = PEM_read_X509(fp, NULL, NULL);
    fclose(fp);
    fp = NULL;
  }
  if (!cert) {
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "trying to read cert in %s\n", file);
    goto err;
  }
  return cert;
err:
  return NULL;
}

static int key_callback(char *buf, int len, int verify) {
  int i;
  if (passphrase == NULL) return(0);
  i=strlen(passphrase);
  i=(i > len)?len:i;
  memcpy(buf,passphrase,i);
  return(i);
}

static EVP_PKEY* getkey(char* file) {
  FILE* fp;
  EVP_PKEY *k = NULL;

  if ((fp = fopen(file, "rb")) == NULL) {
    fprintf(stderr, "failed to open file %s\n", file);
    goto err;
  }
  k = PEM_read_PrivateKey(fp, NULL, (passphrase) ? key_callback : NULL);
  fclose(fp);
  if (!k) {
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "trying to read private key\n");
    goto err;
  }
  return k;
err:
  return NULL;
}

int main(int argc, char **argv) {
  unsigned char bytes[1024], sig[1024];
  char* cfile=NULL,* kfile=NULL,** pp;
  unsigned int len;
  int badops=0;
  EVP_MD_CTX ctx;
  EVP_PKEY* privkey,* pubkey;
  X509* cert;

  argc--; argv++;
  while (argc >= 1) {
    if (strcmp(*argv,"-cert") == 0) {
      if (--argc < 1) goto bad;
      cfile = *(++argv);
    } else if (strcmp(*argv,"-key") == 0) {
      if (--argc < 1) goto bad;
      kfile = *(++argv);
    } else if (strcmp(*argv,"-pass") == 0) {
      if (--argc < 1) goto bad;
      passphrase = *(++argv);
    } else {
bad:
      fprintf(stderr,"unknown option %s\n",*argv);
      badops=1;
      break;
    }
    argc--;
    argv++;
  }
  if (badops || !cfile || !kfile) {
    for (pp=usage; (*pp != NULL); pp++)
      fprintf(stderr,*pp);
    goto err;
  }
  if (!cfile) {
    badops++;
    fprintf(stderr, "Error, missing required argument -cert\n");
  }
  if (!kfile) {
    badops++;
    fprintf(stderr, "Error, missing required argument -key\n");
  }
  if (badops) 
    goto err;

#ifdef WINDOWS
  RAND_screen();
#endif
  SSLeay_add_all_algorithms();

  if (!(cert = getcert(cfile))) 
    goto err;
  if (!(pubkey = X509_PUBKEY_get(X509_get_X509_PUBKEY(cert)))) {
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "trying to get public key out of certificate\n");
    goto err;
  }
  X509_free(cert);

  if (!(privkey = getkey(kfile))) 
    goto err;

  RAND_bytes(bytes, sizeof(bytes));

  len = EVP_PKEY_size(privkey);

  EVP_SignInit(&ctx, EVP_sha1());
  EVP_SignUpdate(&ctx, bytes, sizeof bytes);
  if (!EVP_SignFinal(&ctx, sig, &len, privkey)){
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "trying to sign input\n");
    goto err;
  }

  EVP_VerifyInit(&ctx,EVP_sha1());
  EVP_VerifyUpdate(&ctx, bytes, sizeof bytes);
  if (EVP_VerifyFinal(&ctx, sig, len, pubkey) <= 0) {
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "trying to verify input\n");
    goto err;
  }

  fprintf(stdout, "ok\n");
  return 1;
err:
  return 0;
}

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

Reply via email to