bool _verify_signature(LLPointer<LLCertificate> parent, 
					   LLPointer<LLCertificate> child)
{
	bool verify_result = FALSE; 
	LLSD cert1, cert2;
	parent->getLLSD(cert1);
	child->getLLSD(cert2);
	X509 *signing_cert = parent->getOpenSSLX509();
	X509 *child_cert = child->getOpenSSLX509();
	if((signing_cert != NULL) && (child_cert != NULL))
	{
		EVP_PKEY *pkey = X509_get_pubkey(signing_cert);
		
		
		if(pkey)
		{
			int verify_code = X509_verify(child_cert, pkey);
			verify_result = ( verify_code > 0);
			EVP_PKEY_free(pkey);
		}
		else
		{
			LL_WARNS("SECAPI") << "Could not validate the cert chain signature, as the public key of the signing cert could not be retrieved" << LL_ENDL;
		}

	}
	else
	{
		LL_WARNS("SECAPI") << "Signature verification failed as there are no certs in the chain" << LL_ENDL;
	}
	if(child_cert)
	{
		X509_free(child_cert);
	}
	if(signing_cert)
	{
		X509_free(signing_cert);
	}
	return verify_result;
}
//
// LLBasicCertificateChain
// This class represents a chain of certs, each cert being signed by the next cert
// in the chain.  Certs must be properly signed by the parent
LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store)
{

	// we're passed in a context, which contains a cert, and a blob of untrusted
	// certificates which compose the chain.
	if((store == NULL) || (store->cert == NULL))
	{
		LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL;
		return;
	}
	// grab the child cert
	LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert);

	add(current);
	if(store->untrusted != NULL)
	{
		// if there are other certs in the chain, we build up a vector
		// of untrusted certs so we can search for the parents of each
		// consecutive cert.
		LLBasicCertificateVector untrusted_certs;
		for(int i = 0; i < sk_X509_num(store->untrusted); i++)
		{
			LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i));
			untrusted_certs.add(cert);

		}		
		while(untrusted_certs.size() > 0)
		{
			LLSD find_data = LLSD::emptyMap();
			LLSD cert_data;
			current->getLLSD(cert_data);
			// we simply build the chain via subject/issuer name as the
			// client should not have passed in multiple CA's with the same 
			// subject name.  If they did, it'll come out in the wash during
			// validation.
			find_data[CERT_SUBJECT_NAME_STRING] = cert_data[CERT_ISSUER_NAME_STRING]; 
			LLBasicCertificateVector::iterator issuer = untrusted_certs.find(find_data);
			if (issuer != untrusted_certs.end())
			{
				current = untrusted_certs.erase(issuer);
				add(current);
			}
			else
			{
				break;
			}
		}
	}
}
// Insert a certificate into the store.  If the certificate already 
// exists in the store, nothing is done.
void  LLBasicCertificateVector::insert(iterator _iter, 
				       LLPointer<LLCertificate> cert)
{
	LLSD cert_info;
	cert->getLLSD(cert_info);
	if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST))
	{
		LLSD existing_cert_info = LLSD::emptyMap();
		existing_cert_info[CERT_MD5_DIGEST] = cert_info[CERT_MD5_DIGEST];
		if(find(existing_cert_info) == end())
		{
			BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get());
			llassert(basic_iter);
			if (basic_iter)
			{
				mCerts.insert(basic_iter->mIter, cert);
			}
		}
	}
}
void _validateCert(int validation_policy,
				  LLPointer<LLCertificate> cert,
				  const LLSD& validation_params,
				  int depth)
{

	LLSD current_cert_info;
	cert->getLLSD(current_cert_info);		
	// check basic properties exist in the cert
	if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING))
	{
		throw LLCertException(cert, "Cert doesn't have a Subject Name");				
	}
	
	if(!current_cert_info.has(CERT_ISSUER_NAME_STRING))
	{
		throw LLCertException(cert, "Cert doesn't have an Issuer Name");				
	}
	
	// check basic properties exist in the cert
	if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO))
	{
		throw LLCertException(cert, "Cert doesn't have an expiration period");				
	}
	if (!current_cert_info.has(CERT_SHA1_DIGEST))
	{
		throw LLCertException(cert, "No SHA1 digest");
	}

	if (validation_policy & VALIDATION_POLICY_TIME)
	{

		LLDate validation_date(time(NULL));
		if(validation_params.has(CERT_VALIDATION_DATE))
		{
			validation_date = validation_params[CERT_VALIDATION_DATE];
		}
		
		if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) ||
		   (validation_date > current_cert_info[CERT_VALID_TO].asDate()))
		{
			throw LLCertValidationExpirationException(cert, validation_date);
		}
	}
	if (validation_policy & VALIDATION_POLICY_SSL_KU)
	{
		if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() &&
			(!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], 
									   LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) ||
			!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], 
									  LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT)))))
		{
			throw LLCertKeyUsageValidationException(cert);
		}
		// only validate EKU if the cert has it
		if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() &&	   
		   (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], 
									LLSD((std::string)CERT_EKU_SERVER_AUTH))))
		{
			throw LLCertKeyUsageValidationException(cert);			
		}
	}
	if (validation_policy & VALIDATION_POLICY_CA_KU)
	{
		if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() &&
			(!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], 
									   (std::string)CERT_KU_CERT_SIGN)))
			{
				throw LLCertKeyUsageValidationException(cert);						
			}
	}
	
	// validate basic constraints
	if ((validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS) &&
		current_cert_info.has(CERT_BASIC_CONSTRAINTS) && 
		current_cert_info[CERT_BASIC_CONSTRAINTS].isMap())
	{
		if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) ||
		   !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA])
		{
				throw LLCertBasicConstraintsValidationException(cert);
		}
		if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) &&
			((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) &&
			 (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger())))
		{
			throw LLCertBasicConstraintsValidationException(cert);					
		}
	}
}