⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cert_support.c

📁 读写Smart卡加解密接口的程序
💻 C
字号:
/* * $Id: cert_support.c,v 1.2 2003/09/10 10:42:34 aet Exp $ * * Copyright (C) 2001, 2002 *  Anna Erika Suortti <asuortti@cc.hut.fi> *  Antti Tapaninen <aet@cc.hut.fi> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#ifdef HAVE_CONFIG_H#include <config.h>#endif#if defined(HAVE_OPENSSL)#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <ctype.h>#include <sys/types.h>#include <openssl/err.h>#include "cert_support.h"#define CHECK_CTX(ctx, val)			\  if (!ctx) {					\    return val;					\  }#define CHECK_CTX_VOID(ctx)			\  if (!ctx) {					\    return;					\  }scCertificate *certAlloc(void){  scCertificate *scCert = (scCertificate *) malloc(sizeof(scCertificate));  if (scCert) {    memset(scCert, 0, sizeof(scCertificate));  }  return scCert;}static void certFreeBuffer(unsigned char *certbuf){  if (certbuf) {    free(certbuf);  }  certbuf = NULL;}void certFree(scCertificate * cert){  CHECK_CTX_VOID(cert);  if (cert) {    if (cert->pubkey) {      certFreePublicKey(cert->pubkey);    }    cert->pubkey = NULL;    if (cert->crl) {      certFreeCRL(cert->crl);    }    cert->crl = NULL;    if (cert->cert) {      certFreeCertificate(cert->cert);    }    cert->cert = NULL;    if (cert->crlbuf) {      certFreeBuffer(cert->crlbuf);    }    cert->crlbuf = NULL;    cert->crllen = 0;    if (cert->buf) {      certFreeBuffer(cert->buf);    }    cert->buf = NULL;    cert->len = 0;    free(cert);    cert = NULL;  }}void certFreeAll(scCertificate ** cert){  scCertificate **p = cert;  int i;  CHECK_CTX_VOID(*p);  for (i = 0; p[i]; i++) {    certFree(p[i]);    p[i] = NULL;  }}X509 *certParseCertificate(unsigned char *certbuf, unsigned int certlen){  X509 *cert = NULL;  unsigned char *certptr = certbuf;  CHECK_CTX(certptr, NULL);  /* Parse DER encoded certificate into the x509 structure */  cert = X509_new();  if (!d2i_X509(&cert, &certptr, certlen)) {    return NULL;  }  return cert;}void certFreeCertificate(X509 * cert){  CHECK_CTX_VOID(cert);  X509_free(cert);  cert = NULL;}X509_CRL *certParseCRL(unsigned char *crlbuf, unsigned int crllen){  X509_CRL *crl = NULL;  unsigned char *crlptr = crlbuf;  CHECK_CTX(crlptr, NULL);  /* Parse DER encoded certificate into the x509 crl structure */  crl = X509_CRL_new();  if (!d2i_X509_CRL(&crl, &crlptr, crllen)) {    return NULL;  }  return crl;}void certFreeCRL(X509_CRL * crl){  CHECK_CTX_VOID(crl);  X509_CRL_free(crl);  crl = NULL;}EVP_PKEY *certParsePublicKey(X509 * cert){  EVP_PKEY *pubkey = NULL;  CHECK_CTX(cert, NULL);  pubkey = X509_get_pubkey(cert);  return pubkey;}void certFreePublicKey(EVP_PKEY * pk){  CHECK_CTX_VOID(pk);  EVP_PKEY_free(pk);  pk = NULL;}/* This function checks the validity of the certificate given * in cert and returns 0 if successful and -1 on error. */int certCheckValidity(X509 * cert){  CHECK_CTX(cert, -1);  /* Check validity dates against the current time     notBefore < current time and notAfter > current time */  if (X509_cmp_current_time(X509_get_notBefore(cert)) < 0 &&      X509_cmp_current_time(X509_get_notAfter(cert)) > 0) {    return 0;  } else {    if (X509_cmp_current_time(X509_get_notBefore(cert)) > 0) {#if 0      log_message("Certificate not valid yet\n");#endif    } else {#if 0      log_message("Certificate not valid anymore\n");#endif    }    return -1;  }  return -1;}/* This function checks whether the bit bit is set in the keyUsage * BITSTRING of the certificate given as argument ie. whether * the key in the certificate is fit for a certain use. * Returns 1 if set, 0 if not set and -1 on error. */int certCheckKeyUsage(X509 * cert, unsigned int bit){  int loc = -1, rv = -1;  ASN1_BIT_STRING *b_asn = NULL;  unsigned char *bitstr = NULL;  X509_EXTENSION *ext = NULL;  CHECK_CTX(cert, -1);  /* keyUsage bits run from 0 to 8 */  if (bit > 8) {    return -1;  }  /* Try to parse keyUsage extension out of the certificate */  loc = X509_get_ext_by_NID(cert, NID_key_usage, 0);  /* No keyUsage existing, bail out */  if (loc < 0) {    return -1;  }  ext = X509_get_ext(cert, loc);  if (!ext) {    return -1;  }  bitstr = ext->value->data;  if (!d2i_ASN1_BIT_STRING(&b_asn, &bitstr, ext->value->length)) {    return -1;  }  if (ASN1_BIT_STRING_get_bit(b_asn, bit)) {    rv = 1;  } else {    rv = 0;  }  ASN1_BIT_STRING_free(b_asn);  return rv;}#define ASN1_SEQ 0x30#define ASN1_CHOICE 0xa0/* This function parses the CRL distribution point from the    certificate.    Returns CRL location or NULL on error. */char *certGetCRLDistributionPoint(X509 * cert){  X509_EXTENSION *ext = NULL;  ASN1_OCTET_STRING *o_asn = NULL;  char *crlbuf = NULL, *distpoint = NULL;  int rv = -1, crllen = 0;  int asnlen = 0, i = 0, j = 0, k = 0;  CHECK_CTX(cert, NULL);  /* Try to parse crlDistributionPoints extension out of the certificate */  rv = X509_get_ext_by_NID(cert, NID_crl_distribution_points, 0);  if (rv < 0) {    return NULL;  }  ext = X509_get_ext(cert, rv);  if (!ext) {    return NULL;  }  o_asn = X509_EXTENSION_get_data(ext);  if (!o_asn) {    return NULL;  }  for (i = 0; i < o_asn->length;) {    switch (*(o_asn->data + i)) {    case ASN1_SEQ:      {	i++;	if (*(o_asn->data + i) & 0x80) {	  asnlen = (*(o_asn->data + i) & ~0x80);	  i++;	  crllen = 0;	  for (j = 0; j < asnlen; j++) {	    if (j == 0) {	      crllen += (*(o_asn->data + i));	    } else {	      crllen += (j * 0x100) * (*(o_asn->data + i));	    }	    i++;	  }	} else {	  i++;	  crllen = (*(o_asn->data + i));	}	break;      }    case ASN1_CHOICE:      {	i++;	if (*(o_asn->data + i) & 0x80) {	  asnlen = (*(o_asn->data + i) & ~0x80);	  i++;	  crllen = 0;	  for (j = 0; j < asnlen; j++) {	    if (j == 0) {	      crllen += (*(o_asn->data + i));	    } else {	      crllen += (j * 0x100) * (*(o_asn->data + i));	    }	    i++;	  }	} else {	  i++;	  crllen = (*(o_asn->data + i));	  i++;	}	for (j = 0; j < crllen; j++) {	  if (*(o_asn->data + i) == 0x86) {	    i++;	    if (*(o_asn->data + i) & 0x80) {	      asnlen = (*(o_asn->data + i) & ~0x80);	      i++;	      crllen = 0;	      for (j = 0; j < asnlen; j++) {		if (j == 0) {		  crllen += (*(o_asn->data + i));		} else {		  crllen += (j * 0x100) * (*(o_asn->data + i));		}		i++;	      }	    } else {	      crllen = (*(o_asn->data + i));	      i++;	    }	    crlbuf = (char *) malloc(crllen + 1);	    if (!crlbuf) {	      return NULL;	    }	    memset(crlbuf, 0, crllen + 1);	    memcpy(crlbuf, (o_asn->data + i), crllen);	    for (k = 0; k < crllen; k++) {	      i++;	    }	    break;	  }	  i++;	}	break;      }    default:      return NULL;    }  }  distpoint = (char *) malloc(crllen + 1);  if (!distpoint) {    free(crlbuf);    return NULL;  }  memset(distpoint, 0, crllen + 1);  memcpy(distpoint, crlbuf, crllen);  free(crlbuf);  return distpoint;}/* This function checks whether the X.509 format certificate cert    is self-signed (ie. issuer and subject names match).    Returns 1 if it is self-signed, 0 if it is not and -1 on error. */int certIsSelfSigned(X509 * cert){  CHECK_CTX(cert, -1);  if (!X509_NAME_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert))) {    return 1;  } else {    return 0;  }}/* This function returns the issuer of the X.509 format certificate    cert. */char *certGetIssuer(X509 * cert){  CHECK_CTX(cert, NULL);  return X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);}/* This function returns the subject of the X.509 format certificate    cert. */char *certGetSubject(X509 * cert){  CHECK_CTX(cert, NULL);  return X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);}char *certParseDN(char *entry, char *field){  char *token = NULL, *value = NULL, *p = NULL;  CHECK_CTX(entry, NULL);  CHECK_CTX(field, NULL);  token = strtok(entry, "/");  if (!token) {    return NULL;  }  if ((p = strstr(token, field))) {    p = p + strlen(field);    if (*p == '=') {      p++;    }    value = (char *) malloc((strlen(p) + 1) * sizeof(char));    if (!value) {      return NULL;    }    strcpy(value, p);    return value;  }  while ((token = strtok(NULL, "/"))) {    if ((p = strstr(token, field))) {      p = p + strlen(field);      if (*p == '=') {	p++;      }      value = (char *) malloc((strlen(p) + 1) * sizeof(char));      if (!value) {	return NULL;      }      strcpy(value, p);      return value;    }  }  return NULL;}/* This function searches the serial number list of a CRL for    serialNumber.    Returns 1 if found, 0 if not found and -1 on error. */static int certIsRevoked(ASN1_STRING * serialNumber, X509_CRL_INFO * crlinfo){  int i = 0, numrevoked = 0, revoked = 0;  if (!serialNumber || !crlinfo) {    return -1;  }  numrevoked = sk_num(crlinfo->revoked);  for (i = 0; i < numrevoked && !revoked; i++) {    X509_REVOKED *r = (X509_REVOKED *) sk_value(crlinfo->revoked, i);    if (!ASN1_INTEGER_cmp(serialNumber, r->serialNumber)) {      revoked = 1;    }  }  return revoked;}/* This function sets up a certificate store with all the CA certificates * in X509CAcert and checks the validity and the issuer signature of * the user certificate and all the CA certificates. This couldn't be * tested with a real certificate chain, though, as we have none. * Returns 0 on success and the real openssl error on error (NOTE: these * are positive integers!). */int certVerifyCAChain(scCertificate ** CAcerts, X509 * cert){  scCertificate *currCAcert = CAcerts[0];  X509 *usercert = cert, *x509CAcert = NULL;  ASN1_INTEGER *serialNumber = NULL;  EVP_PKEY *pubkey = NULL;  X509_STORE_CTX cst_ctx;  X509_STORE *cst = NULL;  X509_CRL *x509crl = NULL;  int rv = 0, err = 0, i = 0;  /* There has to be a user certificate and at least one CA certificate */  if (!usercert || !currCAcert) {    return -1;  }  x509CAcert = (X509 *) currCAcert->cert;  if (!x509CAcert) {#if 0    log_messagex(L_DEBUG, "No CA certs given as argument!\n");#endif    return -1;  }  /* Set up store */  cst = X509_STORE_new();  if (!cst) {#if 0    log_messagex(L_DEBUG, "Could not create certificate store, bailing out.\n");#endif    return -1;  }  /* Add all CA certificates to the store (direction is not     important, openssl should create a chain for us). */  while (x509CAcert) {    rv = X509_STORE_add_cert(cst, x509CAcert);    /* O joy, sometimes openssl returns 0 for OK and       sometimes for error */    if (!rv) {      /* FIXME: Get real error */      err = 1;      X509_STORE_free(cst);      return err;    }    i++;    currCAcert = CAcerts[i];    if (!currCAcert) {      break;    }    x509CAcert = (X509 *) currCAcert->cert;  }  /* Don't care what algorithm the hash uses, just add everything */  SSLeay_add_all_algorithms();  /* Init check of user certificate against CA certs in store */  X509_STORE_CTX_init(&cst_ctx, cst, usercert, NULL);  rv = X509_verify_cert(&cst_ctx);  if (rv < 0) {    err = -1;  } else {    err = X509_STORE_CTX_get_error(&cst_ctx);  }  X509_STORE_CTX_cleanup(&cst_ctx);  X509_STORE_free(cst);  /* FIXME: Check CRL here by hand, will be in openssl version 0.9.7.     Do nothing fancy for now, because a real CRL check will probably     be implemented in openssl before we need multiple CRLs. */  if (!err) {    serialNumber = X509_get_serialNumber(usercert);    currCAcert = CAcerts[0];    x509crl = (X509_CRL *) currCAcert->crl;    x509CAcert = (X509 *) currCAcert->cert;    i = 0;    while (currCAcert && x509CAcert && x509crl) {      if (!serialNumber) {	err = 1;	break;      }      if (!x509crl->crl || !x509CAcert->cert_info) {	err = 1;	break;      }#if 0      log_messagex(L_DEBUG, "CA Issuer: %s\n", X509_NAME_oneline(x509CAcert->cert_info->subject, NULL, 0));      log_messagex(L_DEBUG, "CRL Issuer: %s\n", X509_NAME_oneline(x509crl->crl->issuer, NULL, 0));#endif#if 1      /* Check that CRL issuer and CA subject match */      rv = X509_NAME_cmp(x509crl->crl->issuer, x509CAcert->cert_info->subject);      if (rv != 0) {	err = X509_V_ERR_SUBJECT_ISSUER_MISMATCH;	break;      }#endif      /* Check signature */      pubkey = (EVP_PKEY *) certParsePublicKey(x509CAcert);      if (!pubkey) {	err = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;	break;      }      /* Check signature */      if ((rv = X509_CRL_verify(x509crl, pubkey) < 1)) {	err = X509_V_ERR_CRL_SIGNATURE_FAILURE;	break;      }      /* Check CRL validity */      if ((rv = X509_cmp_current_time(X509_CRL_get_nextUpdate(x509crl))) < 0) {	err = X509_V_ERR_CRL_HAS_EXPIRED;	break;      }      /* Check whether the serial number is among the revoked */      if (certIsRevoked(serialNumber, x509crl->crl) != 0) {	err = X509_V_ERR_CERT_REVOKED;	break;      }      serialNumber = X509_get_serialNumber(x509CAcert);      i++;      currCAcert = CAcerts[i];      if (!currCAcert) {	break;      }      x509crl = (X509_CRL *) currCAcert->crl;      x509CAcert = (X509 *) currCAcert->cert;    }  }  EVP_cleanup();  return err;}const char *certError(unsigned long error){  static char buf[1024];  /* FIXME */  ERR_load_ERR_strings();  ERR_load_crypto_strings();  snprintf(buf, 1024, "%s", ERR_error_string(error, NULL));  ERR_free_strings();  return (char *) &buf[0];}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -