openssl實作了标準的x509v3數字證書,其源碼在crypto/x509和crypto/x509v3中。其中x509目錄實作了數字證書以及證書申請相關的各種函數,包括了X509和X509_REQ結構的設定、讀取、列印和比較;數字證書的驗證、摘要;各種公鑰的導入導出等功能。x509v3目錄主要實作了數字證書擴充項相關的函數。
在進行身份認證時,首先要對發送給伺服器進行認證的x509證書有效性進行驗證,在Openssl中,可以用一個API接口可以實作:int X509_verify_cert(X509_STORE_CTX *ctx);
接口中形參是X509_STORE_CTX(X509證書庫上下文)類型,在X509證書庫上下文中,存在一個X509證書庫和一個待驗證的X509證書,可以加入信任的證書鍊,也可以加入CRL證書鍊(證書撤銷清單)~
對X509證書有效性進行驗證可以由以下幾個函數來完成~
X509_STORE_CTX *ctx; //證書上下文
X509_STORE *cert_store; //證書庫,存在證書鍊
X509* x509; //待驗證X509證書
ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx,cert_store,x509,NULL);
X509_verify_cert(ctx);//根據傳回值可以确認X509證書是否有效,也可以根據X509_STORE_CTX_get_error和X509_verify_cert_error_string函數來确認無效原因
示例程式如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#define CERT_PATH "/home/dengaj/Desktop/openssl"
#define ROOT_CERT "RootCert.crt"
#define CARD_CERT "CardCert.crt"
#define GET_DEFAULT_CA_CERT(str) sprintf(str, "%s/%s", CERT_PATH, ROOT_CERT)
#define GET_CUSTOM_CERT(str, path, name) sprintf(str, "%s/%s", path, name)
#define MAX_LEGTH 4096
int my_load_cert(unsigned char *str, unsigned long *str_len,
const char *verify_cert, const unsigned int cert_len)
{
FILE *fp;
fp = fopen(verify_cert, "rb");
if ( NULL == fp)
{
fprintf(stderr, "fopen fail\n");
return -1;
}
*str_len = fread(str, 1, cert_len, fp);
fclose(fp);
return 0;
}
X509 *der_to_x509(const unsigned char *der_str, unsigned int der_str_len)
{
X509 *x509;
x509 = d2i_X509(NULL, &der_str, der_str_len);
if ( NULL == x509 )
{
fprintf(stderr, "d2i_X509 fail\n");
return NULL;
}
return x509;
}
int x509_verify()
{
int ret;
char cert[MAX_LEGTH];
unsigned char user_der[MAX_LEGTH];
unsigned long user_der_len;
X509 *user = NULL;
unsigned char ca_der[MAX_LEGTH];
unsigned long ca_der_len;
X509 *ca = NULL;
X509_STORE *ca_store = NULL;
X509_STORE_CTX *ctx = NULL;
STACK_OF(X509) *ca_stack = NULL;
/* x509初始化 */
ca_store = X509_STORE_new();
ctx = X509_STORE_CTX_new();
/* root ca*/
GET_DEFAULT_CA_CERT(cert);
/* 從檔案中讀取 */
my_load_cert(ca_der, &ca_der_len, cert, MAX_LEGTH);
/* DER編碼轉X509結構 */
ca = der_to_x509(ca_der, ca_der_len);
/* 加入證書存儲區 */
ret = X509_STORE_add_cert(ca_store, ca);
if ( ret != 1 )
{
fprintf(stderr, "X509_STORE_add_cert fail, ret = %d\n", ret);
goto EXIT;
}
/* 需要校驗的證書 */
GET_CUSTOM_CERT(cert, CERT_PATH, CARD_CERT);
my_load_cert(user_der, &user_der_len, cert, MAX_LEGTH);
user = der_to_x509(user_der, user_der_len);
ret = X509_STORE_CTX_init(ctx, ca_store, user, ca_stack);
if ( ret != 1 )
{
fprintf(stderr, "X509_STORE_CTX_init fail, ret = %d\n", ret);
goto EXIT;
}
//openssl-1.0.1c/crypto/x509/x509_vfy.h
ret = X509_verify_cert(ctx);
if ( ret != 1 )
{
fprintf(stderr, "X509_verify_cert fail, ret = %d, error id = %d, %s\n",
ret, ctx->error, X509_verify_cert_error_string(ctx->error));
goto EXIT;
}
fprintf(stdout, "X509_verify_cert successful\n");
EXIT:
X509_free(user);
X509_free(ca);
X509_STORE_CTX_cleanup(ctx);
X509_STORE_CTX_free(ctx);
X509_STORE_free(ca_store);
return ret == 1 ? 0 : -1;
}
int main()
{
OpenSSL_add_all_algorithms();
x509_verify();
return 0;
}
第二種方法使用
int X509_verify(X509 * x509, EVP_PKEY * pkey);
X509 * root;
X509 * mycert;
//Get root certificate into root
//Get mycert into mycert.
//Get the public key.
EVP_PKEY * pubkey = X509_get_pubkey(root);
//verify. result less than or 0 means not verified or some error.
int result = X509_verify(mycert, pubkey);
//free the public key.
EVP_PKEY_free(pubkey);