📄 cert.cxx
字号:
/* Copyright (C) 2005, 2004 Erik Eliasson, Johan Bilien 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*//* * Authors: Erik Eliasson <eliasson@it.kth.se> * Johan Bilien <jobi@via.ecp.fr>*/#include<config.h>
#include<libmcrypto/cert.h>
extern "C"{
#include<openssl/rsa.h>
#include<openssl/evp.h>
#include<openssl/objects.h>
#include<openssl/x509.h>
#include<openssl/err.h>
#include<openssl/pem.h>
#include<openssl/ssl.h>
}
#include<stdio.h>#include<assert.h>#include<iostream>
using namespace std;certificate::certificate():private_key(NULL),cert(NULL){}certificate::certificate( X509 * openssl_cert ):private_key(NULL){ if( openssl_cert == NULL ){ throw certificate_exception("X509 certificate is NULL"); } cert = openssl_cert;}certificate::certificate( const string cert_filename ):private_key(NULL){ FILE * fp; fp = fopen( cert_filename.c_str(), "r" ); if( fp == NULL ){ cerr << "Could not open the certificate file" << endl; throw certificate_exception_file( "Could not open the certificate file" ); } cert = PEM_read_X509( fp, NULL, NULL, NULL ); fclose( fp ); if( cert == NULL ){ cerr << "Invalid certificate file" << endl; throw certificate_exception_file( "Invalid certificate file" ); } file = cert_filename;}certificate::certificate( const string cert_filename, const string private_key_filename ){ FILE * fp; fp = fopen( cert_filename.c_str(), "r" ); if( fp == NULL ){ cerr << "Could not open the certificate file" << endl; throw certificate_exception_file( "Could not open the certificate file" ); } cert = PEM_read_X509( fp, NULL, NULL, NULL ); fclose( fp ); if( cert == NULL ){ cerr << "Invalid certificate file" << endl; throw certificate_exception_file( "Invalid certificate file" ); } set_pk( private_key_filename ); file = cert_filename;}certificate::certificate( unsigned char * der_cert, int length ):private_key(NULL){ cert = X509_new(); if( cert == NULL ) throw certificate_exception_init( "Could not create the certificate" );#if OPENSSL_VERSION_NUMBER >= 0x00908000L d2i_X509( &cert, (const unsigned char**)&der_cert, length );#else d2i_X509( &cert, (unsigned char**)&der_cert, length );#endif} certificate::~certificate(){ if( cert ) X509_free( cert ); cert = NULL; if( private_key ) EVP_PKEY_free( private_key ); private_key = NULL;}int certificate::sign_data( unsigned char * data, int data_length, unsigned char * sign, int * sign_length ){ EVP_MD_CTX ctx; int err; ERR_load_crypto_strings(); if( private_key == NULL ) { sign = NULL; *sign_length = 0;#ifdef DEBUG_OUTPUT cerr << "You need a private key to sign data" << endl;#endif return 1; } // FIXME EVP_SignInit( &ctx, EVP_sha1() ); EVP_SignUpdate( &ctx, data, data_length ); err = EVP_SignFinal( &ctx, sign, (unsigned int*)sign_length, private_key ); //EVP_MD_CTX_cleanup( &ctx ); if( err != 1 ) {#ifdef DEBUG_OUTPUT cerr << "An error occured when signing data" << endl;#endif ERR_print_errors_fp( stderr ); free( sign ); return 1; } return 0;}int certificate::verif_sign( unsigned char * sign, int sign_length, unsigned char * data, int data_length ){ EVP_PKEY * public_key; EVP_MD_CTX ctx; int err; ERR_load_crypto_strings(); if( cert == NULL ) {#ifdef DEBUG_OUTPUT cerr << "You need a certificate to verify a signature" << endl;#endif return -1; } public_key = X509_get_pubkey( cert ); if( public_key == NULL ) {#ifdef DEBUG_OUTPUT cerr << "Cound not read public key from certificate" << endl;#endif return -1; } EVP_VerifyInit( &ctx, EVP_sha1() ); EVP_VerifyUpdate( &ctx, data, data_length ); err = EVP_VerifyFinal( &ctx, sign, sign_length, public_key ); EVP_PKEY_free( public_key ); //EVP_MD_CTX_cleanup( &ctx ); if( err < 0 ) {#ifdef DEBUG_OUTPUT cerr << "An error occured while verifying signature" << endl;#endif ERR_print_errors_fp( stderr ); } return err;} int certificate::get_der_length(){ return i2d_X509( cert, NULL );}void certificate::get_der( unsigned char * output ){ int temp = i2d_X509( cert, &output); // don't want it to be incremented: output -= temp;}string certificate::get_name(){ string ret( X509_NAME_oneline( X509_get_subject_name( cert ),0 ,0 )); return ret;}string certificate::get_cn(){ string name = get_name(); size_t pos, pos2; pos = name.find( "/CN=" ); if( pos == string::npos ){ return "No common name"; } pos2 = name.find( "/", pos + 1 ); return name.substr( pos + 4, pos2 - pos - 4 );}string certificate::get_issuer(){ string ret( X509_NAME_oneline( X509_get_issuer_name( cert ),0 ,0 )); return ret;}string certificate::get_issuer_cn(){ string name = get_issuer(); size_t pos, pos2; pos = name.find( "/CN=" ); if( pos == string::npos ){ return "No common name"; } pos2 = name.find( "/", pos + 1 ); return name.substr( pos + 4, pos2 - pos - 4 );}string certificate::get_file(){ return file;}string certificate::get_pk_file(){ return pk_file;}void certificate::set_pk( string file ){ FILE * fp = NULL; fp = fopen( file.c_str(), "r" ); if( fp == NULL ){ cerr << "Could not open the private key file" << endl; throw certificate_exception_file( "Could not open the private key file" ); } private_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL); fclose( fp ); if( private_key == NULL ){ cerr << "Invalid private key file" << endl; throw certificate_exception_file( "Invalid private key file" ); } /* Check that the private key matches the certificate */ if( X509_check_private_key( cert, private_key ) != 1 ){ cerr << "Private key does not match the certificate" << endl; throw certificate_exception_pkey( "The private key does not match the certificate" ); } pk_file = file;}int certificate::control( ca_db * cert_db ){ int result; X509_STORE_CTX cert_store_ctx; X509_STORE_CTX_init( &cert_store_ctx, cert_db->get_db(), cert ,NULL ); if( X509_STORE_CTX_get_error( &cert_store_ctx) != 0 ){ //fprintf(stderr, "Could not initialize X509_STORE_CTX"); cerr << "Could not initialize X509_STORE_CTX" << endl; exit( 1 ); } result = X509_verify_cert( &cert_store_ctx ); //fprintf(stderr, "result: %d\n", result );#ifdef DEBUG_OUTPUT if( result == 0 ){ cerr << result << endl; cerr << X509_verify_cert_error_string( cert_store_ctx.error ) << endl; }#endif return result;} ca_db::ca_db(){ cert_db = X509_STORE_new(); if( cert_db == NULL ){ throw certificate_exception_init( "Could not create the certificate db" ); } items_index = items.begin();}ca_db::~ca_db(){ X509_STORE_free( cert_db );}void ca_db::lock(){ mLock.lock();}void ca_db::unlock(){ mLock.unlock();}X509_STORE * ca_db::get_db(){ return cert_db;}void ca_db::add_directory( string dir ){ X509_LOOKUP * lookup = NULL; ca_db_item * item = new ca_db_item(); lookup = X509_STORE_add_lookup( cert_db, X509_LOOKUP_hash_dir() ); if( lookup == NULL ) throw certificate_exception_init( "Could not create a directory lookup"); if( !X509_LOOKUP_add_dir( lookup, dir.c_str(), X509_FILETYPE_PEM ) ) throw certificate_exception_file( (string("Could not open the directory ")+dir).c_str() ); item->item = dir; item->type = CERT_DB_ITEM_TYPE_DIR; items.push_back( item ); items_index = items.begin();}void ca_db::add_file( string file ){ X509_LOOKUP * lookup = NULL; ca_db_item * item = new ca_db_item; lookup = X509_STORE_add_lookup( cert_db, X509_LOOKUP_file() ); if( lookup == NULL ) throw certificate_exception_init( "Could not create a file lookup" ); if( !X509_LOOKUP_load_file( lookup, file.c_str(), X509_FILETYPE_PEM ) ) throw certificate_exception_file( ("Could not open the file "+file).c_str() ); item->item = file; item->type = CERT_DB_ITEM_TYPE_FILE; items.push_back( item ); items_index = items.begin();}void ca_db::add_certificate( certificate * cert ){ ca_db_item * item = new ca_db_item(); X509_STORE_add_cert( cert_db, cert->get_openssl_certificate() ); item->item = ""; item->type = CERT_DB_ITEM_TYPE_OTHER; items.push_back( item ); items_index = items.begin();}void ca_db::remove( ca_db_item * removedItem ){ init_index(); while( items_index != items.end() ){ if( *(*items_index) == *removedItem ){ items.erase( items_index ); init_index(); return; } items_index ++; } init_index();}list<ca_db_item *> &ca_db::get_items(){ return items;}void ca_db::init_index(){ items_index = items.begin();}ca_db_item * ca_db::get_next(){ ca_db_item * tmp; if( items_index == items.end() ){ items_index = items.begin(); return NULL; } tmp = *items_index; items_index ++; return tmp;}certificate_chain::certificate_chain(){ item = cert_list.begin();}certificate_chain::certificate_chain( MRef<certificate *> cert ){ cert_list.push_back( cert ); item = cert_list.begin();}certificate_chain::~certificate_chain(){}void certificate_chain::lock(){ mLock.lock();}void certificate_chain::unlock(){ mLock.unlock();}bool certificate_chain::is_empty(){ return cert_list.empty();}void certificate_chain::add_certificate( MRef<certificate *> cert ){ if( !cert_list.empty() ){ MRef<certificate *> lastCert = *(--cert_list.end()); if( lastCert->get_issuer() != cert->get_name() ){ throw certificate_exception_chain( "The previous certificate in the chain is not" "issued by the given one" ); } } cert_list.push_back( cert ); item = cert_list.begin();}void certificate_chain::remove_last(){ cert_list.erase( -- cert_list.end() ); item = cert_list.begin();}void certificate_chain::init_index(){ item = cert_list.begin();}int certificate_chain::control( MRef<ca_db *> cert_db){ int result; X509_STORE_CTX cert_store_ctx; /* The first one, the one to verify */ X509 * cert; /* Chain of certificates */ STACK_OF(X509) * cert_stack; list< MRef<certificate *> >::iterator i = cert_list.begin(); if( i == cert_list.end() ){ cerr << "Certificate: Empty list of certificates" "to verify" << endl; return 0; } cert = (*i)->get_openssl_certificate(); cert_stack = sk_X509_new_null(); i++; for( ; i != cert_list.end(); i++ ){ sk_X509_push( cert_stack, (*i)->get_openssl_certificate() ); } X509_STORE_CTX_init( &cert_store_ctx, cert_db->get_db(), cert, cert_stack); if( X509_STORE_CTX_get_error( &cert_store_ctx) != 0 ){ //fprintf(stderr, "Could not initialize X509_STORE_CTX"); cerr << "Could not initialize X509_STORE_CTX" << endl; exit( 1 ); } result = X509_verify_cert( &cert_store_ctx );#ifdef DEBUG_OUTPUT if( result == 0 ){ cerr << result << endl; cerr << X509_verify_cert_error_string( cert_store_ctx.error ) << endl; }#endif return result;}MRef<certificate *> certificate_chain::get_next(){ MRef<certificate *> ret; if( item == cert_list.end() ){ item = cert_list.begin(); return NULL; } ret = *item; item ++; return ret;}MRef<certificate *> certificate_chain::get_first(){ if( cert_list.size() == 0 ){ return NULL; } return *(cert_list.begin());}void certificate_chain::clear(){ cert_list.clear();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -