This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-certstore/src/x509.c
fengweihao 1aa39ca8d5 支持显示证书的公钥算法
支持签名算法和公钥匹配检查
2020-02-27 15:12:58 +08:00

1292 lines
28 KiB
C

/*************************************************************************
> File Name: cert_session.c
> Author:
> Mail:
> Created Time: Fri 01 Jun 2018 02:00:56 AM PDT
************************************************************************/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
/* openssl**/
#include <opensslv.h>
#include <ssl.h>
#include <err.h>
#include <rand.h>
#include <x509.h>
#include <x509v3.h>
#include <crypto.h>
#include <engine.h>
#include <pkcs12.h>
#include "rt_string.h"
#include "rt_common.h"
#include "rt_stdlib.h"
#include "rt_file.h"
#include "rt_time.h"
#include "rt_tmr.h"
#include "bufferevent.h"
#include "listener.h"
#include "event_compat.h"
#include "http.h"
#include "buffer.h"
#include "util-internal.h"
enum x509_input_file{
INPUT_FILE_CERT,
INPUT_FILE_KEY,
INPUT_FILE_CRL,
INPUT_FILE_LIST,
INPUT_FILE_CHECK,
INPUT_FILE_HOST,
INPUT_FILE_ALGO,
INPUT_FILE_CHAIN,
};
#define LOCAL_USER_PEN 1
#define LOCAL_USER_DER 2
#define LOCAL_USER_P12 3
BIO *bio_err = NULL;
static const struct value_string format_vals[] =
{
{LOCAL_USER_PEN, "PEM TEXT FILE"},
{LOCAL_USER_DER, "DER BINARY FILE"},
{LOCAL_USER_P12, "P12 BINARY FILE"},
};
static void help()
{
printf("Welcome to x509 %s\n", "1.1.1");
printf("x509 <-incert |-inkey | -incrl | -inlist> arg\n"
"Usage:\n"
" -incert | input certificate file\n"
" -inkey | input private key file\n"
" -incrl | input certificate revocation list\n"
" -inlist | input certificate list file,format = pem\n"
" -incheck | input certificate file and intpu key file\n"
" -inhost | input san file and intpu fqdn file\n"
" -inalgo | input certificate file and public key algorithm\n");
}
static X509* base_load_pkcs12(BIO *in, EVP_PKEY **pkey, X509 **x, STACK_OF(X509) **ca)
{
PKCS12 *p12;
const char *pass = "";
X509 *_x = NULL;
EVP_PKEY *_pkey;
STACK_OF(X509) *_ca = NULL;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
p12 = d2i_PKCS12_bio(in, NULL);
if (p12 == NULL) {
goto finish;
}
if (!PKCS12_parse(p12, pass, &_pkey, &_x, &_ca)) {
goto finish;
}
if (x)
*x = _x;
if (pkey)
*pkey = _pkey;
if (ca)
*ca = _ca;
finish:
if (p12)
PKCS12_free(p12);
return _x;
}
static void cert_base_load_stack_info(BIO * in_bio, STACK_OF(X509) **stack_ca)
{
int x509_cnt = 0;
X509_INFO *x509_info;
STACK_OF(X509) *stack_x509 = NULL;
STACK_OF(X509_INFO) *stack_x509_info = NULL;
if ((stack_x509 = sk_X509_new_null()) == NULL)
{
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
goto finish;
}
stack_x509_info = PEM_X509_INFO_read_bio(in_bio, NULL, NULL, NULL);
if (stack_x509_info == NULL)
{
X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_PEM_LIB);
goto finish;
}
while (sk_X509_INFO_num(stack_x509_info)) {
x509_info = sk_X509_INFO_shift(stack_x509_info);
if (x509_info->x509 != NULL) {
sk_X509_push(stack_x509, x509_info->x509);
x509_info->x509 = NULL;
x509_cnt++;
}
X509_INFO_free(x509_info);
}
if (x509_cnt >= 1)
*stack_ca = stack_x509;
finish:
if (stack_x509_info != NULL)
sk_X509_INFO_free(stack_x509_info);
return;
}
int x509_get_last_ca(const char *file, X509 *cx509)
{
int last = 0;
X509 *x = NULL;
BIO *bio = NULL;
if ((bio = BIO_new(BIO_s_file())) == NULL)
{
goto finish;
}
if (BIO_read_filename(bio, file) <= 0)
{
goto finish;
}
while(NULL!=(x=PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)))
{
if (0 == X509_NAME_cmp(X509_get_issuer_name(x), X509_get_subject_name(cx509)))
{
last = 1;
X509_free(x);
break;
};
X509_free(x);
}
BIO_free (bio);
finish:
return last;
}
X509* x509_get_root_ca(const char *file, STACK_OF(X509) **stack_ca)
{
int x509_cnt = 0;
X509 *x = NULL, *node = NULL, *root = NULL;
BIO *bio = NULL;
STACK_OF(X509) *stack_x509 = NULL;
if ((bio = BIO_new(BIO_s_file())) == NULL)
{
goto finish;
}
if (BIO_read_filename(bio, file) <= 0)
{
goto finish;
}
if ((stack_x509 = sk_X509_new_null()) == NULL)
{
X509err(X509_F_X509_VERIFY_CERT, ERR_R_MALLOC_FAILURE);
goto finish;
}
while(NULL!=(x=PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)))
{
if (0 == X509_NAME_cmp(X509_get_issuer_name(x), X509_get_subject_name(x)))
{
/*This is root ca**/
root = x;
continue;
};
/*This is last ca*/
if (x509_get_last_ca(file, x) == 0)
{
node = x;
continue;
}
sk_X509_push(stack_x509, x);
x509_cnt++;
X509_free(x);
}
if (x509_cnt >= 1)
*stack_ca = stack_x509;
if (node != NULL)
X509_free(root);
else
node = root;
BIO_free (bio);
finish:
return node;
}
static X509 *
cert_base_load_x509 (BIO * in_bio, STACK_OF(X509) **stack_ca, int iFormat)
{
X509 *x = NULL;
switch (iFormat)
{
case LOCAL_USER_DER:
x = d2i_X509_bio (in_bio, NULL);
break;
case LOCAL_USER_PEN:
x = PEM_read_bio_X509 (in_bio, NULL, NULL, NULL);
cert_base_load_stack_info(in_bio, stack_ca);
break;
case LOCAL_USER_P12:
x = base_load_pkcs12(in_bio, NULL, &x, stack_ca);
break;
default:
break;
}
return x;
}
static X509 *
cert_load_x509(char *file, int *informat, STACK_OF(X509) **stack_ca)
{
BIO *in = NULL;
X509 *x509 = NULL;
if(!file){
goto finish;
}
if ((in = BIO_new(BIO_s_file())) == NULL) {
goto finish;
}
if (BIO_read_filename(in, file) <= 0) {
goto finish;
}
/**try pem */
if ((x509 = cert_base_load_x509(in, stack_ca, LOCAL_USER_PEN)) != NULL){
*informat = LOCAL_USER_PEN;
goto end;
}
#if 0
(void)BIO_reset (in);
if ((x509 = cert_base_load_x509(in, stack_ca, LOCAL_USER_P12)) != NULL){
*informat = LOCAL_USER_P12;
goto end;
}
(void)BIO_reset (in);
if ((x509 = cert_base_load_x509(in, stack_ca, LOCAL_USER_DER)) != NULL){
*informat = LOCAL_USER_DER;
goto end;
}
#endif
end:
BIO_free (in);
in = NULL;
finish:
return x509;
}
EVP_PKEY * cert_base_key_x509 (BIO * bio, int iFormat, char *strPwd)
{
EVP_PKEY *pkey = NULL;
switch (iFormat){
case LOCAL_USER_PEN:
pkey = PEM_read_bio_PrivateKey (bio, NULL, NULL, strPwd);
break;
case LOCAL_USER_P12:
base_load_pkcs12(bio, &pkey, NULL, NULL);
break;
default:
break;
}
return pkey;
}
EVP_PKEY * cert_load_key(char *keyfile, int *informat)
{
EVP_PKEY *pkey = NULL;
BIO *in = NULL;
if(!keyfile){
goto finish;
}
if ((in = BIO_new(BIO_s_file())) == NULL) {
goto finish;
}
if (BIO_read_filename(in, keyfile) <= 0) {
goto finish;
}
if ((pkey = cert_base_key_x509 (in, LOCAL_USER_PEN, "")) != NULL){
*informat = LOCAL_USER_PEN;
goto finish;
}
(void)BIO_reset (in);
if ((pkey = cert_base_key_x509 (in, LOCAL_USER_P12, "")) != NULL){
*informat = LOCAL_USER_P12;
goto finish;
}
finish:
if (in != NULL)
BIO_free (in);
return pkey;
}
int x509_get_ValidDate(X509 *x509)
{
BIO *STDout = NULL;
STDout = BIO_new_fp(stdout, BIO_NOCLOSE);
printf("CA notBefore : ");
ASN1_TIME_print(STDout, X509_get_notBefore(x509));
printf("\n");
printf("CA notAfter : ");
ASN1_TIME_print(STDout, X509_get_notAfter(x509));
printf("\n");
BIO_free_all(STDout);
return 0;
}
static char*
x509_get_alt_name(X509 *x509)
{
int i, size = 0, gtype = 0;
char *gnname = NULL;
GENERAL_NAMES* subjectAltNames = (GENERAL_NAMES*)X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL);
int cnt = sk_GENERAL_NAME_num(subjectAltNames);
if (cnt < 0)
goto finish;
int gnnamelen = cnt * 64;
gnname = (char *)malloc(gnnamelen);
if (!gnname)
goto finish;
memset(gnname, 0, gnnamelen);
for (i = 0; i < cnt; i++)
{
GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);
ASN1_STRING *uri = GENERAL_NAME_get0_value(generalName, &gtype);
if (gtype == GEN_DNS)
{
size += snprintf(gnname + size, gnnamelen, "%s;", ASN1_STRING_data(uri));
if (size < 0)
continue;
}
}
finish:
return gnname;
}
void x509_get_name(X509_NAME *name, int obase)
{
BIO *out = NULL;
out = BIO_new(BIO_s_file());
if (out == NULL) {
ERR_print_errors(bio_err);
goto finish;
}
BIO_set_fp(out, stdout, BIO_NOCLOSE);
X509_NAME_print(out, name, obase);
finish:
if (out != NULL)
BIO_free_all(out);
return;
}
char *x509_get_cn(X509 *x509)
{
char *CName = NULL;
int iLen = 0, CNlen = 256;
X509_NAME *pSubName = NULL;
pSubName = X509_get_subject_name(x509);
if (!pSubName){
goto finish;
}
CName = kmalloc(CNlen, MPF_CLR, -1);
if (!CName){
goto finish;
}
iLen = X509_NAME_get_text_by_NID(pSubName, NID_commonName, CName, CNlen-1);
if (iLen > 0){
return CName;
}
finish:
return NULL;
}
char *x509_get_SubjectName(X509 *x509)
{
int iLen = 0;
char *csSubName = NULL;
char csBuf[256] = {0};
X509_NAME *pSubName = NULL;
csSubName = (char *)malloc(1024);
if (!csSubName)
goto finish;
pSubName = X509_get_subject_name(x509);
if (!pSubName){
goto finish;
}
memset(csBuf, 0, 256);
memset(csSubName, 0, 1024);
iLen = X509_NAME_get_text_by_NID(pSubName, NID_countryName, csBuf, 255);
if (iLen > 0){
strcat(csSubName, "C=");
strcat(csSubName, csBuf);
strcat(csSubName, ", ");
}
memset(csBuf, 0, 256);
iLen = X509_NAME_get_text_by_NID(pSubName, NID_organizationName, csBuf, 255);
if (iLen > 0){
strcat(csSubName, "O=");
strcat(csSubName, csBuf);
strcat(csSubName, ", ");
}
memset(csBuf, 0, 256);
iLen = X509_NAME_get_text_by_NID(pSubName, NID_organizationalUnitName, csBuf, 255);
if (iLen > 0) {
strcat(csSubName, "OU=");
strcat(csSubName, csBuf);
strcat(csSubName, ", ");
}
memset(csBuf, 0, 256);
iLen = X509_NAME_get_text_by_NID(pSubName, NID_commonName, csBuf, 255);
if (iLen > 0){
strcat(csSubName, "CN=");
strcat(csSubName, csBuf);
}
finish:
return csSubName;
}
#define R_RSA_ALGO_1024 1024
#define R_RSA_ALGO_2048 2048
#define R_RSA_ALGO_4096 4096
#define R_DH_ALGO_1024 1
typedef struct {
const char *name; /* NIST Name of curve */
int nid; /* Curve NID */
} x509_algo_name;
static x509_algo_name algo_name[] = {
{"rsa1024", R_RSA_ALGO_1024},
{"rsa2048", R_RSA_ALGO_2048},
{"rsa4096", R_RSA_ALGO_4096},
{"secp256r1", NID_X9_62_prime256v1},
{"secp384r1",NID_secp384r1}
};
static size_t x509_algo_str2idx(const char *public_algo)
{
size_t i = 0;
if(public_algo == NULL)
{
goto finish;
}
if (0 == strcasecmp(public_algo, "dh1024"))
{
return R_DH_ALGO_1024;
}
for (i = 0; i < sizeof(algo_name) / sizeof(x509_algo_name); i++)
{
if (0 == strcasecmp(public_algo, algo_name[i].name))
{
return algo_name[i].nid;
}
}
finish:
return R_RSA_ALGO_2048;
}
int x509_check_pubKeytype(X509 *x509, const char *algo)
{
int xret = 1, nid = 0;
EVP_PKEY *pkey = NULL;
pkey = X509_get_pubkey(x509);
if (pkey == NULL)
{
printf("Unable to load Public Key\n");
}
switch(pkey->type)
{
case EVP_PKEY_RSA:
xret = 1;
break;
case EVP_PKEY_EC:
nid = x509_algo_str2idx(algo);
switch(nid)
{
case NID_X9_62_prime256v1:
case NID_secp384r1:
xret = 1;
break;
default:
xret = 0;
break;
}
break;
case EVP_PKEY_DH:
nid = x509_algo_str2idx(algo);
switch(nid)
{
case R_RSA_ALGO_1024:
case R_RSA_ALGO_2048:
case R_RSA_ALGO_4096:
xret = 1;
break;
default:
xret = 0;
break;
}
break;
default:
xret = 0;
break;
}
return xret;
}
void x509_get_pubKeytype(X509 *x509)
{
EVP_PKEY *pkey = NULL;
pkey = X509_get_pubkey(x509);
if (pkey == NULL)
{
printf("Unable to load Public Key\n");
}
const char *type = OBJ_nid2ln(pkey->type);
printf("PKey Algorithm : %s\n", type);
if (pkey->type == EVP_PKEY_EC)
{
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
int nid;
const char *cname, *asnl;
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
EC_KEY_free(ec);
cname = EC_curve_nid2nist(nid);
asnl = OBJ_nid2sn(nid);
printf("ASN1 OID : %s\n", cname);
printf("NIST CURVE : %s\n", asnl);
}
}
char* x509_get_ExtBasicConstraints(X509 *x509)
{
int crit = 0;
char value[512] = {0};
BASIC_CONSTRAINTS *bcons = NULL;
if (!x509)
return NULL;
bcons = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(x509, NID_basic_constraints, &crit, NULL);
if (!bcons)
return NULL;
if (!bcons->ca)
{
strcat(value, "Subject Type=End Entity; ");
strcat(value, "Path Length Constraint=None");
}
else
{
char temp[128] = {0};
if (bcons->pathlen != NULL)
snprintf(temp, 128, "Path Length Constraint=%d", bcons->pathlen->type);
else
snprintf(temp, 128, "Path Length Constraint=None");
strcat(value, "Subject Type=CA; ");
strcat(value, temp);
}
BASIC_CONSTRAINTS_free(bcons);
char *base_cons = NULL;
int base_cons_len = strlen(value) + 1;
base_cons = (char *)malloc(base_cons_len);
if (!base_cons)
return NULL;
strncpy(base_cons, value, base_cons_len);
return base_cons;
}
static char*
x509_get_fingerprint(X509 *x509)
{
char *rkey = NULL;
unsigned int len = 0, i = 0;
char hex[EVP_MAX_MD_SIZE] = {0};
unsigned char fdig[EVP_MAX_MD_SIZE] = {0};
rkey = (char *)malloc(512);
if (!rkey)
goto finish;
X509_digest(x509, EVP_sha1(), fdig, &len);
for (i = 0; i < len ; ++i){
sprintf(hex + i * sizeof(unsigned char) * 2, "%02x", fdig[i]);
}
snprintf(rkey, 511, "%s", hex);
finish:
return rkey;
}
char *x509_get_sn(X509 *x509)
{
ASN1_INTEGER *asn1_i = NULL;
BIGNUM *bignum = NULL;
char *serial = NULL;
asn1_i = X509_get_serialNumber(x509);
bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
if (bignum == NULL) {
goto finish;
}
serial = BN_bn2hex(bignum);
if (serial == NULL) {
goto finish;
}
BN_free(bignum);
finish:
return serial;
}
char *x509_get_version(X509 *x509)
{
unsigned int v = 0;
v = X509_get_version(x509);
switch(v){
case 0:
return "V1";
case 1:
return "V2";
case 2:
return "V3";
default:
break;
}
return NULL;
}
int X509_check_valid_date(X509 *x509)
{
int day, sec;
/*Certificate is issued earlier than the current time*/
if (ASN1_TIME_diff(&day, &sec, X509_get_notBefore(x509), NULL) == 0)
return -1;
if (day <= 0 && sec <= 0)
return -1;
/*Certificate expiration is less than the current time*/
if (ASN1_TIME_diff(&day, &sec, NULL, X509_get_notAfter(x509)) == 0)
return -1;
if (day <= 0 && sec <= 0)
return -1;
/*Certificate expires less than the date of issue*/
if (ASN1_TIME_diff(&day, &sec, X509_get_notBefore(x509), X509_get_notAfter(x509)) == 0)
return -1;
if (day <= 0 && sec <= 0)
return -1;
return 0;
}
int x509_parse_cert(char *certfile, char *host)
{
int xret = -1;
int informat = 0;
X509 *x509 = NULL;
STACK_OF(X509) *stack_ca = NULL;
x509 = cert_load_x509(certfile, &informat, &stack_ca);
if (!x509){
printf("unable to load certificate\n");
goto finish;
}
printf("Successful certificate conversion\n");
printf("Ca Format : %s\n", val_to_str(informat, format_vals));
printf("Ca Constraints : %s\n", (x509_get_ExtBasicConstraints(x509) != NULL)?x509_get_ExtBasicConstraints(x509): "NULL");
if (informat == LOCAL_USER_P12 || informat == LOCAL_USER_PEN){
if (stack_ca){
printf("Chain Length : %d\n", sk_X509_num(stack_ca) + 1);
}else{
printf("Chain Length : %d\n", 1);
}
}
printf("Ca Version : %s\n", (x509_get_version(x509) != NULL)?x509_get_version(x509) : "NULL");
printf("Ca Serial : %s\n", (x509_get_sn(x509) != NULL)?x509_get_sn(x509) : "NULL");
printf("Ca Issuer : ");
x509_get_name(X509_get_issuer_name(x509), 16);
printf("\n");
printf("Ca SubjectName : ");
x509_get_name(X509_get_subject_name(x509), 16);
printf("\n");
char *alt_name = x509_get_alt_name(x509);
printf("Ca AltName : %s\n", (alt_name != NULL)?alt_name:"NULL");
free(alt_name);
printf("Ca Fingerprint : %s\n", x509_get_fingerprint(x509));
x509_get_ValidDate(x509);
printf("Ca valid date : %s\n", (X509_check_valid_date(x509) == 0)?"valid":"expire");
x509_get_pubKeytype(x509);
/* self testing***/
if (host != NULL)
{
if (X509_check_host(x509, host, strlen(host), 0, NULL) == 1)
printf("Match host name: %s\n", "Successful matching");
else
printf("Match host name: %s\n", "Matching failure");
}
xret = 0;
finish:
return xret;
}
int x509_parse_key(char *keyfile)
{
int xret = -1;
int informat = 0;
EVP_PKEY *pkey = NULL;
pkey = cert_load_key(keyfile, &informat);
if (!pkey){
printf("unable to load private key\n");
goto finish;
}
printf("Successful private key conversion\n");
printf("Key Format : %s\n", val_to_str(informat, format_vals));
xret = 0;
finish:
return xret;
}
static X509_CRL *
x509_load_crl(char *crlfile, int *informat)
{
BIO *in = NULL;
X509_CRL *x = NULL;
in = BIO_new(BIO_s_file());
if (in == NULL) {
ERR_print_errors(bio_err);
goto free;
}
if (BIO_read_filename(in, crlfile) <= 0) {
perror(crlfile);
goto finish;
}
if ((x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL)) != NULL){
*informat = LOCAL_USER_PEN;
goto finish;
}
if ((x = d2i_X509_CRL_bio(in, NULL)) != NULL){
*informat = LOCAL_USER_DER;
goto finish;
}
free:
BIO_free(in);
finish:
return x;
}
char *x509_get_crlNumber(X509_CRL *crl)
{
ASN1_INTEGER *crlnum;
BIGNUM *bignum = NULL;
char *crl_number = NULL;
crlnum = X509_CRL_get_ext_d2i(crl, NID_crl_number, NULL, NULL);
bignum = ASN1_INTEGER_to_BN(crlnum, NULL);
if (bignum == NULL) {
goto finish;
}
crl_number = BN_bn2dec(bignum);
if (crl_number == NULL) {
goto finish;
}
BN_free(bignum);
finish:
return crl_number;
}
int x509_parse_crl(char *crlfile)
{
X509_CRL *crl = NULL;
int informat = 0;
int xret = -1;
crl = x509_load_crl(crlfile, &informat);
if (!crl){
printf("unable to load Certificate Revocation List\n");
goto finish;
}
printf("Successful certificate revocation list conversion\n");
long l = 0;
l = X509_CRL_get_version(crl);
printf("CRL Format : %s\n", val_to_str(informat, format_vals));
printf("CRL Version : %lu\n", l + 1);
printf("CRL Issuer : ");
x509_get_name(X509_CRL_get_issuer(crl), 16);
printf("\n");
printf("CRL Number : %s\n", x509_get_crlNumber(crl));
finish:
return xret;
}
static int
x509_parse_cert_list(char *certlist)
{
int xret = 0;
BIO *in = NULL;
X509* x = NULL;
int count = 0;
in = BIO_new(BIO_s_file());
if (in == NULL) {
ERR_print_errors(bio_err);
goto finish;
}
if (BIO_read_filename(in, certlist) <= 0) {
perror(certlist);
goto err;
}
printf("Certificate List:\n");
for (;;) {
x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
if (x == NULL) {
if (count == 0)
printf("bad input format specified for input cert list\n");
goto err;
}
printf("Cert list Issuer : ");
x509_get_name(X509_get_issuer_name(x), 16);
printf("\n");
count++;
X509_free(x);
x = NULL;
}
err:
if (x != NULL)
X509_free(x);
if (in != NULL)
BIO_free(in);
printf("Certificate List Number : %d\n", count);
finish:
return xret;
}
static int
decoder_argv_parser(int argc, char **argv, char **infile, char **infile2)
{
int i = 0;
int iformat = -1;
for (i = 0; argv[i] != NULL; i++){
/** run version parser */
if (STRCMP (argv[i], "-inkey") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
iformat = INPUT_FILE_KEY;
break;
}
if (STRCMP(argv[i], "-incert") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
*infile2 = argv[i+2];
iformat = INPUT_FILE_CERT;
break;
}
if (STRCMP(argv[i], "-incrl") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
iformat = INPUT_FILE_CRL;
break;
}
if (STRCMP(argv[i], "-inlist")== 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
iformat = INPUT_FILE_LIST;
break;
}
if (STRCMP(argv[i], "-incheck") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
*infile2 = argv[i+2];
iformat = INPUT_FILE_CHECK;
break;
}
if (STRCMP(argv[i], "-inhost") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
*infile2 = argv[i+2];
iformat = INPUT_FILE_HOST;
break;
}
if (STRCMP(argv[i], "-inalgo") == 0){
if (--argc < 1)
goto help;
*infile = argv[i+1];
*infile2 = argv[i+2];
iformat = INPUT_FILE_ALGO;
break;
}
}
goto finish;
help:
help();
finish:
return iformat;
}
static int
x509_parse_check(char *cafile, char *keyfile)
{
int informat = 0;
EVP_PKEY *pkey = NULL;
pkey = cert_load_key(keyfile, &informat);
if (!pkey){
printf("unable to load private key\n");
goto finish;
}
X509 *x509 = NULL;
STACK_OF(X509) *stack_ca = NULL;
x509 = x509_get_root_ca(cafile, &stack_ca);
if (!x509){
printf("unable to load certificate\n");
goto finish;
}
if (!X509_check_private_key(x509, pkey)) {
printf("Matching failure\n");
}else{
printf("Successful matching\n");
}
finish:
return 0;
}
static X509 *make_cert()
{
X509 *x509 = X509_new();
if (x509 == NULL)
goto out;
if (!X509_set_version(x509, 3))
goto out;
return x509;
out:
return NULL;
}
char *execute_read_file(const char *filename)
{
FILE *file = NULL;
long length = 0;
char *content = NULL;
size_t read_chars = 0;
file = fopen(filename, "rb");
if (file == NULL)
{
goto cleanup;
}
if (fseek(file, 0, SEEK_END) != 0)
{
goto cleanup;
}
length = ftell(file);
if (length < 0)
{
goto cleanup;
}
if (fseek(file, 0, SEEK_SET) != 0)
{
goto cleanup;
}
/* allocate content buffer */
content = (char*)malloc((size_t)length + sizeof(""));
if (content == NULL)
{
goto cleanup;
}
/* read the file into memory */
read_chars = fread(content, sizeof(char), (size_t)length, file);
if ((long)read_chars != length)
{
free(content);
content = NULL;
goto cleanup;
}
content[read_chars] = '\0';
cleanup:
if (file != NULL)
{
fclose(file);
}
return content;
}
char *str_trim(const char *str)
{
unsigned int uLen = strlen(str);
if(0 == uLen){
return '\0';
}
char *strRet = (char *)malloc(uLen + 1);
memset(strRet, 0, uLen+1);
unsigned int i = 0, j = 0;
for(i=0; i<uLen+1; i++)
{
if(str[i] != ' ')
{
strRet[j++] = str[i];
}
}
strRet[j] = '\0';
return strRet;
}
static int set_altname(X509 *crt, int type, const char *sanfile)
{
int ret = 0;
GENERAL_NAMES *gens = NULL;
GENERAL_NAME *gen = NULL;
ASN1_IA5STRING *ia5 = NULL;
gens = sk_GENERAL_NAME_new_null();
if (gens == NULL)
goto out;
char *buff = execute_read_file(sanfile);
if (buff == NULL){
goto finish;
}
char *sanline=NULL, *host = NULL;
char seps[] = ";";
sanline = strtok(buff, seps);
while (sanline)
{
asprintf(&host, "%s", sanline);
gen = GENERAL_NAME_new();
if (gen == NULL)
goto out;
ia5 = ASN1_IA5STRING_new();
if (ia5 == NULL)
goto out;
if (!ASN1_STRING_set(ia5, host, -1))
goto out;
switch (type) {
case GEN_EMAIL:
case GEN_DNS:
GENERAL_NAME_set0_value(gen, type, ia5);
ia5 = NULL;
break;
default:
abort();
}
sk_GENERAL_NAME_push(gens, gen);
gen = NULL;
free(host);
sanline = strtok(NULL, seps);
if (sanline == NULL || strlen(sanline) == 1)
{
break;
}
}
if (!X509_add1_ext_i2d(crt, NID_subject_alt_name, gens, 0, 0))
goto out;
ret = 1;
out:
ASN1_IA5STRING_free(ia5);
GENERAL_NAME_free(gen);
finish:
GENERAL_NAMES_free(gens);
return ret;
}
int x509_check_host(const char *sanfile, const char *urlfile)
{
#define LINE_SIZE (1024)
FILE *fp = NULL;
char line[LINE_SIZE];
if (sanfile == NULL || urlfile == NULL){
goto help;
}
X509 *x509 = make_cert();
if (x509 == NULL)
return -1;
set_altname(x509, GEN_DNS, sanfile);
fp = fopen(urlfile, "r");
assert(fp != NULL);
while(fgets(line, LINE_SIZE - 1, fp))
{
if (line[0] == '\0' || X509_check_host(x509, line, strlen(line) -1, 0, NULL) != 1)
{
printf("Fqdn :%.*s Status: %s\n", (int)(strlen(line)-1), line, "Matching failure");
}
}
fclose(fp);
goto finish;
help:
help();
finish:
return 0;
}
int x509_check_pubKeytype2(X509 *x509, const char *algo)
{
const char *signature = NULL;
int sig_nid = 0, nid = 0, xret = 0;
sig_nid = OBJ_obj2nid(x509->sig_alg->algorithm);
if (sig_nid == NID_undef)
{
printf("get signature algorithm failed\n");
}
signature = OBJ_nid2ln(sig_nid);
if (signature == NULL)
{
goto error;
}
printf("Signature Algorithm : %s\n", signature);
if (strcasestr(signature, "ecdsa"))
{
nid = x509_algo_str2idx(algo);
switch(nid)
{
case NID_X9_62_prime256v1:
case NID_secp384r1:
xret = 1;
break;
default:
xret = 0;
break;
}
}
if (strcasestr(signature, "RSAEncryption"))
{
xret = 1;
}
error:
return xret;
}
int x509_check_algo(char *certfile, const char *algo)
{
X509 *x509 = NULL;
int informat = 0, xret = NULL;
STACK_OF(X509) *stack_ca = NULL;
if (certfile == NULL || algo == NULL)
{
goto help;
}
x509 = cert_load_x509(certfile, &informat, &stack_ca);
if (!x509){
printf("unable to load certificate\n");
goto finish;
}
xret = x509_check_pubKeytype2(x509, algo);
if(xret == 0)
{
printf("Matching failure\n");
}
else
{
printf("Successful matching\n");
}
goto finish;
help:
help();
finish:
return 0;
}
int x509_check_format(int argc, char **argv)
{
int iformat = -1;
char *infile = NULL, *infile2 = NULL;
iformat = decoder_argv_parser(argc, argv, &infile, &infile2);
if (!infile && iformat < 0)
goto help;
switch(iformat){
case INPUT_FILE_KEY:
x509_parse_key(infile);
break;
case INPUT_FILE_CERT:
x509_parse_cert(infile, infile2);
break;
case INPUT_FILE_CRL:
x509_parse_crl(infile);
break;
case INPUT_FILE_LIST:
x509_parse_cert_list(infile);
break;
case INPUT_FILE_CHECK:
x509_parse_check(infile, infile2);
break;
case INPUT_FILE_HOST:
x509_check_host(infile, infile2);
break;
case INPUT_FILE_ALGO:
x509_check_algo(infile, infile2);
break;
default:
goto help;
}
goto finish;
help:
help();
finish:
return 0;
}
int main(int argc, char **argv)
{
x509_check_format(argc, argv);
}