correct handling of certificate chains

This commit is contained in:
David Rose 2009-09-06 21:05:06 +00:00
parent 3c0e701659
commit 104c27f20c
5 changed files with 250 additions and 207 deletions

View File

@ -49,7 +49,6 @@ bool got_chdir_to = false;
size_t scale_factor = 0; // -F
pset<string> dont_compress; // -Z
vector_string sign_params; // -S
pvector<Filename> cert_chain; // -N
// Default extensions not to compress. May be overridden with -Z.
string dont_compress_str = "jpg,png,mp3,ogg";
@ -225,21 +224,14 @@ help() {
" generate slightly smaller files, but compression takes longer. The\n"
" default is -" << default_compression_level << ".\n\n"
" -N ca-chain.crt\n"
" Adds the indicated certificate chain file to the multifile. This must\n"
" used in conjunction with -c or -u mode. The indicated file must be\n"
" a PEM-formatted collection of certificates, representing the chain of\n"
" authentication from the certificate used to sign the multifile (-S,\n"
" below), and a certificate authority. This may be necessary for\n"
" certain certificates whose signing authority is one or more steps\n"
" removed from a well-known certificate authority. You must add this\n"
" file to the multifile before signing it (or at least at the same time).\n\n"
" -S file.crt,file.key[,\"password\"]\n"
" -S file.crt,[chain.crt],file.key[,\"password\"]\n"
" Sign the multifile. The signing certificate should be in PEM form in\n"
" file.crt, with its private key in PEM form in file.key. If the key\n"
" is encrypted on-disk, specify the decryption password as the third\n"
" option. PEM form is the form accepted by the Apache web server. The\n"
" option. If a certificate chain is required, chain.crt should also\n"
" be specified; note that the commas should be supplied even if this\n"
" optional filename is omitted.\n"
" PEM form is the form accepted by the Apache web server. The\n"
" signature is written to the multifile to prove it is unchanged; any\n"
" subsequent change to the multifile will invalidate the signature.\n"
" This parameter may be repeated to sign the multifile with different\n"
@ -297,12 +289,10 @@ get_compression_level(const Filename &subfile_name) {
}
bool
do_add_files(Multifile *multifile, const pvector<Filename> &filenames,
bool cert_chain_flag);
do_add_files(Multifile *multifile, const pvector<Filename> &filenames);
bool
do_add_directory(Multifile *multifile, const Filename &directory_name,
bool cert_chain_flag) {
do_add_directory(Multifile *multifile, const Filename &directory_name) {
vector_string files;
if (!directory_name.scan_directory(files)) {
cerr << "Unable to scan directory " << directory_name << "\n";
@ -317,19 +307,18 @@ do_add_directory(Multifile *multifile, const Filename &directory_name,
filenames.push_back(subfile_name);
}
return do_add_files(multifile, filenames, cert_chain_flag);
return do_add_files(multifile, filenames);
}
bool
do_add_files(Multifile *multifile, const pvector<Filename> &filenames,
bool cert_chain_flag) {
do_add_files(Multifile *multifile, const pvector<Filename> &filenames) {
bool okflag = true;
pvector<Filename>::const_iterator fi;
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
const Filename &subfile_name = (*fi);
if (subfile_name.is_directory()) {
if (!do_add_directory(multifile, subfile_name, cert_chain_flag)) {
if (!do_add_directory(multifile, subfile_name)) {
okflag = false;
}
@ -353,12 +342,6 @@ do_add_files(Multifile *multifile, const pvector<Filename> &filenames,
if (verbose) {
cout << new_subfile_name << "\n";
}
if (cert_chain_flag) {
// Set the cert_chain flag on the file.
int index = multifile->find_subfile(new_subfile_name);
nassertr(index >= 0, false);
multifile->set_subfile_is_cert_chain(index, true);
}
}
}
}
@ -406,10 +389,7 @@ add_files(const vector_string &params) {
filenames.push_back(subfile_name);
}
bool okflag = do_add_files(multifile, filenames, false);
if (okflag && !cert_chain.empty()) {
okflag = do_add_files(multifile, cert_chain, true);
}
bool okflag = do_add_files(multifile, filenames);
if (multifile->needs_repack()) {
if (!multifile->repack()) {
@ -551,22 +531,28 @@ sign_multifile() {
const string &param = (*si);
size_t comma1 = param.find(',');
if (comma1 == string::npos) {
cerr << "Signing parameter requires a comma: " << param << "\n";
cerr << "Signing parameter requires two commas: " << param << "\n";
return false;
}
size_t comma2 = param.find(',', comma1 + 1);
if (comma2 == string::npos) {
cerr << "Signing parameter requires two commas: " << param << "\n";
return false;
}
size_t comma3 = param.find(',', comma2 + 1);
Filename certificate = Filename::from_os_specific(param.substr(0, comma1));
Filename chain = Filename::from_os_specific(param.substr(comma1 + 1, comma2 - comma1 - 1));
Filename pkey;
string password;
if (comma2 != string::npos) {
pkey = Filename::from_os_specific(param.substr(comma1 + 1, comma2 - comma1 - 1));
password = param.substr(comma2 + 1);
if (comma3 != string::npos) {
pkey = Filename::from_os_specific(param.substr(comma2 + 1, comma3 - comma2 - 1));
password = param.substr(comma3 + 1);
} else {
pkey = Filename::from_os_specific(param.substr(comma1 + 1));
pkey = Filename::from_os_specific(param.substr(comma2 + 1));
}
if (!multifile->add_signature(certificate, pkey, password)) {
if (!multifile->add_signature(certificate, chain, pkey, password)) {
return false;
}
}
@ -629,10 +615,6 @@ list_files(const vector_string &params) {
if (multifile->is_subfile_encrypted(i)) {
encrypted_symbol = 'e';
}
char cert_chain_symbol = ' ';
if (multifile->get_subfile_is_cert_chain(i)) {
cert_chain_symbol = 'N';
}
if (multifile->is_subfile_compressed(i)) {
size_t orig_length = multifile->get_subfile_length(i);
size_t internal_length = multifile->get_subfile_internal_length(i);
@ -641,25 +623,25 @@ list_files(const vector_string &params) {
ratio = (double)internal_length / (double)orig_length;
}
if (ratio > 1.0) {
printf("%12d worse %c%c %s %s\n",
printf("%12d worse %c %s %s\n",
(int)multifile->get_subfile_length(i),
encrypted_symbol, cert_chain_symbol,
encrypted_symbol,
format_timestamp(multifile->get_record_timestamp(),
multifile->get_subfile_timestamp(i)),
subfile_name.c_str());
} else {
printf("%12d %3.0f%% %c%c %s %s\n",
printf("%12d %3.0f%% %c %s %s\n",
(int)multifile->get_subfile_length(i),
100.0 - ratio * 100.0,
encrypted_symbol, cert_chain_symbol,
encrypted_symbol,
format_timestamp(multifile->get_record_timestamp(),
multifile->get_subfile_timestamp(i)),
subfile_name.c_str());
}
} else {
printf("%12d %c%c %s %s\n",
printf("%12d %c %s %s\n",
(int)multifile->get_subfile_length(i),
encrypted_symbol, cert_chain_symbol,
encrypted_symbol,
format_timestamp(multifile->get_record_timestamp(),
multifile->get_subfile_timestamp(i)),
subfile_name.c_str());
@ -691,7 +673,6 @@ list_files(const vector_string &params) {
#ifdef HAVE_OPENSSL
int num_signatures = multifile->get_num_signatures();
if (num_signatures != 0) {
multifile->load_certificate_chains();
cout << "\n";
for (i = 0; i < num_signatures; ++i) {
cout << "Signed by " << multifile->get_signature_common_name(i);
@ -747,7 +728,7 @@ main(int argc, char *argv[]) {
extern char *optarg;
extern int optind;
static const char *optflags = "crutxkvz123456789Z:T:S:T:f:OC:ep:P:F:h";
static const char *optflags = "crutxkvz123456789Z:T:S:f:OC:ep:P:F:h";
int flag = getopt(argc, argv, optflags);
Filename rel_path;
while (flag != EOF) {
@ -815,9 +796,6 @@ main(int argc, char *argv[]) {
case 'Z':
dont_compress_str = optarg;
break;
case 'N':
cert_chain.push_back(Filename::from_os_specific(optarg));
break;
case 'S':
sign_params.push_back(optarg);
break;

View File

@ -520,3 +520,37 @@ get_last_byte_pos() const {
return max(_index_start + (streampos)_index_length,
_data_start + (streampos)_data_length) - (streampos)1;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::CertRecord::Constructor
// Access: Public
// Description: Ownership of the X509 object is passed into the
// CertRecord; it will be freed when the CertRecord
// destructs.
////////////////////////////////////////////////////////////////////
INLINE Multifile::CertRecord::
CertRecord(X509 *cert) :
_cert(cert)
{
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::CertRecord::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Multifile::CertRecord::
CertRecord(const Multifile::CertRecord &copy) :
_cert(X509_dup(copy._cert))
{
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::CertRecord::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE Multifile::CertRecord::
~CertRecord() {
X509_free(_cert);
}

View File

@ -570,6 +570,10 @@ update_subfile(const string &subfile_name, const Filename &filename,
// subsequent changes to the Multifile will
// automatically invalidate and remove the signature.
//
// The chain filename may be empty if the certificate
// does not require an authenticating certificate chain
// (e.g. because it is self-signed).
//
// The specified private key must match the certificate,
// and the Multifile must be open in read-write mode.
// The private key is only used for generating the
@ -589,10 +593,12 @@ update_subfile(const string &subfile_name, const Filename &filename,
// parameter will be used as the password to decrypt it.
////////////////////////////////////////////////////////////////////
bool Multifile::
add_signature(const Filename &certificate, const Filename &pkey,
const string &password) {
add_signature(const Filename &certificate, const Filename &chain,
const Filename &pkey, const string &password) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
CertChain cert_chain;
// Read the certificate file from VFS. First, read the complete
// file into memory.
string certificate_data;
@ -612,6 +618,34 @@ add_signature(const Filename &certificate, const Filename &pkey,
return false;
}
// Store the first X509--the actual certificate--as the first record
// in our CertChain object.
cert_chain.push_back(CertRecord(x509));
// Read the rest of the certificates in the chain file.
if (!chain.empty()) {
string chain_data;
if (!vfs->read_file(chain, chain_data, true)) {
express_cat.info()
<< "Could not read " << chain << ".\n";
return false;
}
BIO *chain_mbio = BIO_new_mem_buf((void *)chain_data.data(), chain_data.size());
X509 *c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
while (c != NULL) {
cert_chain.push_back(c);
c = PEM_read_bio_X509(chain_mbio, NULL, NULL, (void *)"");
}
BIO_free(chain_mbio);
if (cert_chain.size() == 1) {
express_cat.info()
<< "Could not read certificate chain in " << chain << ".\n";
return false;
}
}
// Now do the same thing with the private key. This one may be
// password-encrypted on disk.
string pkey_data;
@ -621,7 +655,6 @@ add_signature(const Filename &certificate, const Filename &pkey,
return false;
}
// Create an in-memory BIO to read the "file" from the buffer.
BIO *pkey_mbio = BIO_new_mem_buf((void *)pkey_data.data(), pkey_data.size());
EVP_PKEY *evp_pkey = PEM_read_bio_PrivateKey(pkey_mbio, NULL, NULL,
(void *)password.c_str());
@ -629,18 +662,57 @@ add_signature(const Filename &certificate, const Filename &pkey,
if (evp_pkey == NULL) {
express_cat.info()
<< "Could not read private key in " << pkey << ".\n";
X509_free(x509);
return false;
}
bool result = add_signature(x509, evp_pkey);
bool result = add_signature(cert_chain, evp_pkey);
EVP_PKEY_free(evp_pkey);
X509_free(x509);
return result;
}
#endif // HAVE_OPENSSL
#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
// Function: Multifile::add_signature
// Access: Published
// Description: Adds a new signature to the Multifile. This
// signature associates the indicated certificate with
// the current contents of the Multifile. When the
// Multifile is read later, the signature will still be
// present only if the Multifile is unchanged; any
// subsequent changes to the Multifile will
// automatically invalidate and remove the signature.
//
// If chain is non-NULL, it represents the certificate
// chain that validates the certificate.
//
// The specified private key must match the certificate,
// and the Multifile must be open in read-write mode.
// The private key is only used for generating the
// signature; it is not written to the Multifile and
// cannot be retrieved from the Multifile later.
// (However, the certificate *can* be retrieved from the
// Multifile later, to identify the entity that created
// the signature.)
//
// This implicitly causes a repack() operation if one is
// needed. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool Multifile::
add_signature(X509 *certificate, STACK *chain, EVP_PKEY *pkey) {
// Convert the certificate and chain into our own CertChain
// structure.
CertChain cert_chain;
cert_chain.push_back(CertRecord(certificate));
if (chain != NULL) {
int num = sk_num(chain);
for (int i = 0; i < num; ++i) {
cert_chain.push_back(CertRecord((X509 *)sk_value(chain, i)));
}
}
}
#endif // HAVE_OPENSSL
#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
@ -654,6 +726,10 @@ add_signature(const Filename &certificate, const Filename &pkey,
// subsequent changes to the Multifile will
// automatically invalidate and remove the signature.
//
// The signature certificate is the first certificate on
// the CertChain object. Any remaining certificates are
// support certificates to authenticate the first one.
//
// The specified private key must match the certificate,
// and the Multifile must be open in read-write mode.
// The private key is only used for generating the
@ -667,7 +743,7 @@ add_signature(const Filename &certificate, const Filename &pkey,
// needed. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool Multifile::
add_signature(X509 *certificate, EVP_PKEY *pkey) {
add_signature(const Multifile::CertChain &cert_chain, EVP_PKEY *pkey) {
if (_needs_repack) {
if (!repack()) {
return false;
@ -677,18 +753,26 @@ add_signature(X509 *certificate, EVP_PKEY *pkey) {
return false;
}
}
// Now encode that list of certs to a stream in DER form.
stringstream der_stream;
StreamWriter der_writer(der_stream);
der_writer.add_uint32(cert_chain.size());
// Encode the certificate into DER form for writing to the
// Multifile.
int der_len = i2d_X509(certificate, NULL);
unsigned char *der_buf = new unsigned char[der_len];
unsigned char *p = der_buf;
i2d_X509(certificate, &p);
string der_string((char *)der_buf, der_len);
delete[] der_buf;
istringstream der_stream(der_string);
CertChain::const_iterator ci;
for (ci = cert_chain.begin(); ci != cert_chain.end(); ++ci) {
X509 *cert = (*ci)._cert;
int der_len = i2d_X509(cert, NULL);
unsigned char *der_buf = new unsigned char[der_len];
unsigned char *p = der_buf;
i2d_X509(cert, &p);
der_writer.append_data(der_buf, der_len);
delete[] der_buf;
}
// Create a temporary Subfile for writing out the signature.
der_stream.seekg(0);
Subfile *subfile = new Subfile;
subfile->_pkey = pkey;
subfile->_flags |= SF_signature;
@ -733,9 +817,10 @@ get_num_signatures() const {
// Description: Returns the nth signature found on the Multifile.
// See the comments in get_num_signatures().
////////////////////////////////////////////////////////////////////
X509 *Multifile::
const Multifile::CertChain &Multifile::
get_signature(int n) const {
nassertr(n >= 0 && n < (int)_signatures.size(), NULL);
static CertChain error_chain;
nassertr(n >= 0 && n < (int)_signatures.size(), error_chain);
return _signatures[n];
}
#endif // HAVE_OPENSSL
@ -752,10 +837,10 @@ get_signature(int n) const {
////////////////////////////////////////////////////////////////////
string Multifile::
get_signature_subject_name(int n) const {
X509 *x509 = get_signature(n);
nassertr(x509 != NULL, "");
const CertChain &cert_chain = get_signature(n);
nassertr(!cert_chain.empty(), string());
X509_NAME *xname = X509_get_subject_name(x509);
X509_NAME *xname = X509_get_subject_name(cert_chain[0]._cert);
if (xname != NULL) {
// We use "print" to dump the output to a memory BIO. Is
// there an easier way to extract the X509_NAME text? Curse
@ -786,12 +871,12 @@ get_signature_subject_name(int n) const {
////////////////////////////////////////////////////////////////////
string Multifile::
get_signature_common_name(int n) const {
X509 *x509 = get_signature(n);
nassertr(x509 != NULL, "");
const CertChain &cert_chain = get_signature(n);
nassertr(!cert_chain.empty(), string());
// A complex OpenSSL interface to extract out the common name in
// utf-8.
X509_NAME *xname = X509_get_subject_name(x509);
X509_NAME *xname = X509_get_subject_name(cert_chain[0]._cert);
if (xname != NULL) {
int pos = X509_NAME_get_index_by_NID(xname, NID_commonName, -1);
if (pos != -1) {
@ -831,11 +916,11 @@ get_signature_common_name(int n) const {
////////////////////////////////////////////////////////////////////
void Multifile::
write_signature_certificate(int n, ostream &out) const {
X509 *x509 = get_signature(n);
nassertv(x509 != NULL);
const CertChain &cert_chain = get_signature(n);
nassertv(!cert_chain.empty());
BIO *mbio = BIO_new(BIO_s_mem());
X509_print(mbio, x509);
X509_print(mbio, cert_chain[0]._cert);
char *pp;
long pp_size = BIO_get_mem_data(mbio, &pp);
@ -844,49 +929,6 @@ write_signature_certificate(int n, ostream &out) const {
}
#endif // HAVE_OPENSSL
#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
// Function: Multifile::load_certificate_chains
// Access: Published
// Description: Loads any certificate chains specified in the
// Multifile into the global certificate store. This
// may be necessary to successfully validate the
// certificate used to sign the multifile in
// validate_signature_certificate(), below.
////////////////////////////////////////////////////////////////////
void Multifile::
load_certificate_chains() {
OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
Subfiles::iterator si;
for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
Subfile *subfile = (*si);
if ((subfile->_flags & SF_cert_chain) != 0) {
// If it's a certificate chain, add it to the global chain list.
// Read the cert chain into memory.
istream *stream = open_read_subfile(subfile);
nassertv(stream != NULL);
pvector<unsigned char> buffer;
bool success = read_to_pvector(buffer, *stream);
nassertv(success);
close_read_subfile(stream);
// Now it to the global chain.
if (!buffer.empty()) {
int result = sslw->load_certificates_from_ram((char *)&buffer[0], buffer.size());
if (result > 0) {
express_cat.info()
<< "Loaded " << result << " certificates from "
<< subfile->_name << "\n";
}
}
}
}
}
#endif // HAVE_OPENSSL
#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
// Function: Multifile::validate_signature_certificate
@ -902,17 +944,32 @@ int Multifile::
validate_signature_certificate(int n) const {
int verify_result = -1;
X509 *x509 = get_signature(n);
nassertr(x509 != NULL, false);
const CertChain &chain = get_signature(n);
nassertr(!chain.empty(), false);
OpenSSLWrapper *sslw = OpenSSLWrapper::get_global_ptr();
// Copy our CertChain structure into an X509 pointer and
// accompanying STACK pointer.
X509 *x509 = chain[0]._cert;
STACK *stack = NULL;
if (chain.size() > 1) {
stack = sk_new(NULL);
for (size_t n = 1; n < chain.size(); ++n) {
sk_push(stack, (char *)chain[n]._cert);
}
}
// Create the X509_STORE_CTX for verifying the cert and chain.
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx, sslw->get_x509_store(), x509, NULL);
X509_STORE_CTX_init(ctx, sslw->get_x509_store(), x509, stack);
X509_STORE_CTX_set_cert(ctx, x509);
X509_verify_cert(ctx);
verify_result = X509_STORE_CTX_get_error(ctx);
if (X509_verify_cert(ctx)) {
verify_result = 0;
} else {
verify_result = X509_STORE_CTX_get_error(ctx);
}
if (express_cat.is_debug()) {
express_cat.debug()
@ -920,6 +977,7 @@ validate_signature_certificate(int n) const {
<< "\n";
}
sk_free(stack);
X509_STORE_CTX_cleanup(ctx);
X509_STORE_CTX_free(ctx);
@ -1393,51 +1451,6 @@ is_subfile_encrypted(int index) const {
return (_subfiles[index]->_flags & SF_encrypted) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::set_subfile_is_cert_chain
// Access: Published
// Description: Sets the cert_chain flag on the indicated subfile.
// This should be set for any subfiles that define the
// certificate chain that will be necessary to validate
// signatures that are subsequently used to sign the
// multifile.
//
// Note that the certificate chain subfiles must be
// added and this flag set *before* signing the
// multifile.
////////////////////////////////////////////////////////////////////
void Multifile::
set_subfile_is_cert_chain(int index, bool flag) {
nassertv(is_write_valid());
nassertv(index >= 0 && index < (int)_subfiles.size());
Subfile *subfile = _subfiles[index];
bool current_flag = (subfile->_flags & SF_cert_chain) != 0;
if (current_flag != flag) {
if (flag) {
subfile->_flags |= SF_cert_chain;
} else {
subfile->_flags &= ~SF_cert_chain;
}
subfile->rewrite_index_flags(*_write);
}
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::get_subfile_is_cert_chain
// Access: Published
// Description: Returns the cert_chain flag on the indicated subfile.
// This should be set for any subfiles that define the
// certificate chain that will be necessary to validate
// signatures that are subsequently used to sign the
// multifile.
////////////////////////////////////////////////////////////////////
bool Multifile::
get_subfile_is_cert_chain(int index) const {
nassertr(index >= 0 && index < (int)_subfiles.size(), false);
return (_subfiles[index]->_flags & SF_cert_chain) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::get_index_end
// Access: Published
@ -2021,13 +2034,6 @@ clear_subfiles() {
delete subfile;
}
_cert_special.clear();
Certificates::iterator ci;
for (ci = _signatures.begin(); ci != _signatures.end(); ++ci) {
X509 *cert = (*ci);
X509_free(cert);
}
_signatures.clear();
#endif // HAVE_OPENSSL
Subfiles::iterator fi;
@ -2288,21 +2294,36 @@ check_signatures() {
StreamReader reader(*stream);
size_t sig_size = reader.get_uint32();
string sig_string = reader.extract_bytes(sig_size);
size_t num_certs = reader.get_uint32();
// Read the remaining buffer of certificate data.
pvector<unsigned char> buffer;
bool success = read_to_pvector(buffer, *stream);
nassertv(success);
close_read_subfile(stream);
X509 *x509 = NULL;
// Now convert each of the certificates to an X509 object, and
// store it in our CertChain.
CertChain chain;
EVP_PKEY *pkey = NULL;
if (!buffer.empty()) {
const unsigned char *bp = (const unsigned char *)&buffer[0];
x509 = d2i_X509(NULL, &bp, buffer.size());
const unsigned char *bp_end = bp + buffer.size();
X509 *x509 = d2i_X509(NULL, &bp, bp_end - bp);
while (num_certs > 0 && x509 != NULL) {
chain.push_back(CertRecord(x509));
--num_certs;
x509 = d2i_X509(NULL, &bp, bp_end - bp);
}
if (num_certs != 0 || x509 != NULL) {
express_cat.warning()
<< "Extra data in signature record.\n";
}
}
if (x509 != NULL) {
pkey = X509_get_pubkey(x509);
if (!chain.empty()) {
pkey = X509_get_pubkey(chain[0]._cert);
}
if (pkey != NULL) {
@ -2342,20 +2363,13 @@ check_signatures() {
(unsigned char *)sig_string.data(),
sig_string.size(), pkey);
if (verify_result == 1) {
// The signature matches; save the certificate.
_signatures.push_back(x509);
x509 = NULL;
// The signature matches; save the certificate and its chain.
_signatures.push_back(chain);
} else {
// Bad match.
_needs_repack = true;
}
}
if (x509 != NULL) {
// If we still have the X509 pointer by this point, we haven't
// saved it anywhere, so free it now.
X509_free(x509);
}
}
#endif // HAVE_OPENSSL

View File

@ -84,17 +84,28 @@ PUBLISHED:
int compression_level);
#ifdef HAVE_OPENSSL
bool add_signature(const Filename &certificate, const Filename &pkey,
class CertRecord {
public:
INLINE CertRecord(X509 *cert);
INLINE CertRecord(const CertRecord &copy);
INLINE ~CertRecord();
X509 *_cert;
};
typedef pvector<CertRecord> CertChain;
bool add_signature(const Filename &certificate,
const Filename &chain,
const Filename &pkey,
const string &password = "");
bool add_signature(X509 *certificate, EVP_PKEY *pkey);
bool add_signature(X509 *certificate, STACK *chain, EVP_PKEY *pkey);
bool add_signature(const CertChain &chain, EVP_PKEY *pkey);
int get_num_signatures() const;
X509 *get_signature(int n) const;
const CertChain &get_signature(int n) const;
string get_signature_subject_name(int n) const;
string get_signature_common_name(int n) const;
void write_signature_certificate(int n, ostream &out) const;
void load_certificate_chains();
int validate_signature_certificate(int n) const;
#endif // HAVE_OPENSSL
@ -114,8 +125,6 @@ PUBLISHED:
time_t get_subfile_timestamp(int index) const;
bool is_subfile_compressed(int index) const;
bool is_subfile_encrypted(int index) const;
void set_subfile_is_cert_chain(int index, bool flag);
bool get_subfile_is_cert_chain(int index) const;
streampos get_index_end() const;
streampos get_subfile_internal_start(int index) const;
@ -147,8 +156,7 @@ private:
SF_data_invalid = 0x0004,
SF_compressed = 0x0008,
SF_encrypted = 0x0010,
SF_cert_chain = 0x0020,
SF_signature = 0x0040,
SF_signature = 0x0020,
};
class Subfile {
@ -209,7 +217,7 @@ private:
PendingSubfiles _cert_special;
#ifdef HAVE_OPENSSL
typedef pvector<X509 *> Certificates;
typedef pvector<CertChain> Certificates;
Certificates _signatures;
#endif

View File

@ -36,6 +36,7 @@ OpenSSLWrapper() {
OpenSSL_add_all_algorithms();
_x509_store = X509_STORE_new();
X509_STORE_set_default_paths(_x509_store);
// Load in any default certificates listed in the Config.prc file.
int num_certs = ssl_certificates.get_num_unique_values();
@ -67,6 +68,10 @@ OpenSSLWrapper::
//
// Returns the number of certificates read on success,
// or 0 on failure.
//
// You should call this only with trusted,
// locally-stored certificates; not with certificates
// received from an untrusted source.
////////////////////////////////////////////////////////////////////
int OpenSSLWrapper::
load_certificates(const Filename &filename) {
@ -100,10 +105,14 @@ load_certificates(const Filename &filename) {
////////////////////////////////////////////////////////////////////
// Function: OpenSSLWrapper::load_certificates_from_ram
// Access: Public
// Description: Reads a chain of certificates from the indicated
// data buffer and adds them to the X509_STORE object.
// Returns the number of certificates read on success,
// or 0 on failure.
// Description: Reads a chain of trusted certificates from the
// indicated data buffer and adds them to the X509_STORE
// object. Returns the number of certificates read on
// success, or 0 on failure.
//
// You should call this only with trusted,
// locally-stored certificates; not with certificates
// received from an untrusted source.
////////////////////////////////////////////////////////////////////
int OpenSSLWrapper::
load_certificates_from_ram(const char *data, size_t data_size) {