control: tag -1 help
control: tag -1 moreinfo

Hi Kurt,

I have prepared a patch that allows most of bro to build with OpenSSL
1.1. There are still some issues that I haven't been able to figure out
with looking at the OpenSSL source. Please have a look at the attached
patch.

The remaining issues (all in
bro-2.4.0+dfsg/src/file_analysis/analyzer/x509/functions.bif) are about
what seems to be missing OCSP getter functions:

- For OCSP_RECPID *rid:
  - rid->type
  - rid->value.byKey->length
  - rid->value.byKey->data

- For OCSP_BASICRESP *basic:
  - basic->certs
  - basic->tbsResponseData->responderId

(For my rebuild, I simply commented out those parts.)

Even after we get this sorted out, I would be really uncomfortable with
carrying these patches if upstream decides that supporting OpenSSL 1.1
can wait for another year or so.

Cheers,
-Hilko
>From 95f998455d6b052d032251ed88914a2487390c31 Mon Sep 17 00:00:00 2001
From: Hilko Bengen <ben...@debian.org>
Date: Sat, 2 Jul 2016 12:39:31 +0200
Subject: [PATCH] OpenSSL 1.1

---
 src/File.cc                                   |  4 +--
 src/file_analysis/analyzer/x509/X509.cc       | 49 ++++++++++++++++-----------
 src/file_analysis/analyzer/x509/functions.bif | 46 +++++++++++++------------
 3 files changed, 57 insertions(+), 42 deletions(-)

diff --git a/src/File.cc b/src/File.cc
index e62ca73..74efaa4 100644
--- a/src/File.cc
+++ b/src/File.cc
@@ -688,7 +688,7 @@ void BroFile::InitEncrypt(const char* keyfile)
 	// Depending on the OpenSSL version, EVP_*_cbc()
 	// returns a const or a non-const.
 	EVP_CIPHER* cipher_type = (EVP_CIPHER*) EVP_bf_cbc();
-	cipher_ctx = new EVP_CIPHER_CTX;
+	cipher_ctx = EVP_CIPHER_CTX_new();
 
 	unsigned char secret[EVP_PKEY_size(pub_key)];
 	unsigned char* psecret = secret;
@@ -743,7 +743,7 @@ void BroFile::FinishEncrypt()
 			return;
 			}
 
-		delete cipher_ctx;
+		EVP_CIPHER_CTX_free(cipher_ctx);
 		cipher_ctx = 0;
 		}
 	}
diff --git a/src/file_analysis/analyzer/x509/X509.cc b/src/file_analysis/analyzer/x509/X509.cc
index d960474..f9ebeb0 100644
--- a/src/file_analysis/analyzer/x509/X509.cc
+++ b/src/file_analysis/analyzer/x509/X509.cc
@@ -138,7 +138,9 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
 	// we only read 255 bytes because byte 256 is always 0.
 	// if the string is longer than 255, that will be our null-termination,
 	// otherwhise i2t does null-terminate.
-	if ( ! i2t_ASN1_OBJECT(buf, 255, ssl_cert->cert_info->key->algor->algorithm) )
+	ASN1_OBJECT *algorithm;
+	X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, X509_get_X509_PUBKEY(ssl_cert));
+	if ( ! i2t_ASN1_OBJECT(buf, 255, algorithm) )
 		buf[0] = 0;
 
 	pX509Cert->Assign(7, new StringVal(buf));
@@ -149,14 +151,17 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
 	// actually should be (namely - rsaEncryption), so that OpenSSL will parse out the
 	// key later. Otherwise it will just fail to parse the certificate key.
 
-	ASN1_OBJECT* old_algorithm = 0;
-	if ( OBJ_obj2nid(ssl_cert->cert_info->key->algor->algorithm) == NID_md5WithRSAEncryption )
+	if ( X509_get_signature_nid(ssl_cert) == NID_md5WithRSAEncryption )
 		{
-		old_algorithm = ssl_cert->cert_info->key->algor->algorithm;
-		ssl_cert->cert_info->key->algor->algorithm = OBJ_nid2obj(NID_rsaEncryption);
+		X509_PUBKEY_set0_param(X509_get_X509_PUBKEY(ssl_cert), OBJ_nid2obj(NID_rsaEncryption), 0, NULL, NULL, 0);
+		}
+        else
+		{
+		ASN1_OBJECT_free(algorithm);
+		algorithm = 0;
 		}
 
-	if ( ! i2t_ASN1_OBJECT(buf, 255, ssl_cert->sig_alg->algorithm) )
+	if ( ! i2t_ASN1_OBJECT(buf, 255, OBJ_nid2obj(X509_get_signature_nid(ssl_cert))) )
 		buf[0] = 0;
 
 	pX509Cert->Assign(8, new StringVal(buf));
@@ -165,14 +170,16 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
 	EVP_PKEY *pkey = X509_extract_key(ssl_cert);
 	if ( pkey != NULL )
 		{
-		if ( pkey->type == EVP_PKEY_DSA )
+		if ( DSA *dsa = EVP_PKEY_get0_DSA(pkey) )
 			pX509Cert->Assign(9, new StringVal("dsa"));
 
-		else if ( pkey->type == EVP_PKEY_RSA )
+		else if ( RSA *rsa = EVP_PKEY_get0_RSA(pkey) )
 			{
 			pX509Cert->Assign(9, new StringVal("rsa"));
 
-			char *exponent = BN_bn2dec(pkey->pkey.rsa->e);
+			const BIGNUM *e;
+			RSA_get0_key(EVP_PKEY_get0_RSA(pkey), NULL, &e, NULL);
+			char *exponent = BN_bn2dec(e);
 			if ( exponent != NULL )
 				{
 				pX509Cert->Assign(11, new StringVal(exponent));
@@ -181,7 +188,7 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
 				}
 			}
 #ifndef OPENSSL_NO_EC
-		else if ( pkey->type == EVP_PKEY_EC )
+		else if ( EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey) )
 			{
 			pX509Cert->Assign(9, new StringVal("ecdsa"));
 			pX509Cert->Assign(12, KeyCurve(pkey));
@@ -190,8 +197,8 @@ RecordVal* file_analysis::X509::ParseCertificate(X509Val* cert_val, const char*
 
 		// set key algorithm back. We do not have to free the value that we created because (I think) it
 		// comes out of a static array from OpenSSL memory.
-		if ( old_algorithm )
-			ssl_cert->cert_info->key->algor->algorithm = old_algorithm;
+		if ( algorithm )
+			X509_PUBKEY_set0_param(X509_get_X509_PUBKEY(ssl_cert), algorithm, 0, NULL, NULL, 0);
 
 		unsigned int length = KeyLength(pkey);
 		if ( length > 0 )
@@ -262,7 +269,7 @@ void file_analysis::X509::ParseExtension(X509_EXTENSION* ex)
 
 	BIO *bio = BIO_new(BIO_s_mem());
 	if( ! X509V3_EXT_print(bio, ex, 0, 0))
-		M_ASN1_OCTET_STRING_print(bio,ex->value);
+		ASN1_STRING_print(bio,(ASN1_STRING *)X509_EXTENSION_get_data(ex));
 
 	StringVal* ext_val = GetExtensionFromBIO(bio);
 
@@ -444,7 +451,7 @@ StringVal* file_analysis::X509::KeyCurve(EVP_PKEY *key)
 	// well, we do not have EC-Support...
 	return NULL;
 #else
-	if ( key->type != EVP_PKEY_EC )
+	if ( EVP_PKEY_base_id(key) != EVP_PKEY_EC )
 		{
 		// no EC-key - no curve name
 		return NULL;
@@ -452,7 +459,7 @@ StringVal* file_analysis::X509::KeyCurve(EVP_PKEY *key)
 
 	const EC_GROUP *group;
 	int nid;
-	if ( (group = EC_KEY_get0_group(key->pkey.ec)) == NULL)
+	if ( (group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key))) == NULL)
 		// I guess we could not parse this
 		return NULL;
 
@@ -473,12 +480,16 @@ unsigned int file_analysis::X509::KeyLength(EVP_PKEY *key)
 	{
 	assert(key != NULL);
 
-	switch(key->type) {
+	switch(EVP_PKEY_base_id(key)) {
 	case EVP_PKEY_RSA:
-		return BN_num_bits(key->pkey.rsa->n);
+		const BIGNUM *n;
+		RSA_get0_key(EVP_PKEY_get0_RSA(key), &n, NULL, NULL);
+		return BN_num_bits(n);
 
 	case EVP_PKEY_DSA:
-		return BN_num_bits(key->pkey.dsa->p);
+		const BIGNUM *p;
+		DSA_get0_pqg(EVP_PKEY_get0_DSA(key), &p, NULL, NULL);
+		return BN_num_bits(p);
 
 #ifndef OPENSSL_NO_EC
 	case EVP_PKEY_EC:
@@ -488,7 +499,7 @@ unsigned int file_analysis::X509::KeyLength(EVP_PKEY *key)
 			// could not malloc bignum?
 			return 0;
 
-		const EC_GROUP *group = EC_KEY_get0_group(key->pkey.ec);
+		const EC_GROUP *group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key));
 
 		if ( ! group )
 			{
diff --git a/src/file_analysis/analyzer/x509/functions.bif b/src/file_analysis/analyzer/x509/functions.bif
index 216f4c6..9524f0a 100644
--- a/src/file_analysis/analyzer/x509/functions.bif
+++ b/src/file_analysis/analyzer/x509/functions.bif
@@ -331,8 +331,8 @@ function x509_ocsp_verify%(certs: x509_opaque_vector, ocsp_reply: string, root_c
 	result = X509_verify_cert(csc);
 	if ( result != 1 )
 		{
-		const char *reason = X509_verify_cert_error_string((*csc).error);
-		rval = x509_result_record(result, X509_verify_cert_error_string((*csc).error));
+		const char *reason = X509_verify_cert_error_string(X509_STORE_CTX_get_error(csc));
+		rval = x509_result_record(result, X509_verify_cert_error_string(X509_STORE_CTX_get_error(csc)));
 		goto x509_ocsp_cleanup;
 		}
 
@@ -357,15 +357,15 @@ function x509_ocsp_verify%(certs: x509_opaque_vector, ocsp_reply: string, root_c
 	else
 		{
 		// issuer not in list sent by server, check store
-		X509_OBJECT obj;
-		int lookup = X509_STORE_get_by_subject(csc, X509_LU_X509, X509_get_subject_name(cert), &obj);
+		X509_OBJECT *obj = X509_OBJECT_new();
+		int lookup = X509_STORE_get_by_subject(csc, X509_LU_X509, X509_get_subject_name(cert), obj);
 		if ( lookup <= 0)
 			{
 			rval = x509_result_record(lookup, "Could not find issuer of host certificate");
 			goto x509_ocsp_cleanup;
 			}
 
-		certid = OCSP_cert_to_id(NULL, cert, obj.data.x509);
+		certid = OCSP_cert_to_id(NULL, cert,X509_OBJECT_get0_X509( obj));
 		}
 
 
@@ -376,18 +376,22 @@ function x509_ocsp_verify%(certs: x509_opaque_vector, ocsp_reply: string, root_c
 		}
 
 	// for now, assume we have one reply...
-	single = sk_OCSP_SINGLERESP_value(basic->tbsResponseData->responses, 0);
+	single = OCSP_resp_get0(basic, 0);
 	if ( ! single )
 		{
 		rval = x509_result_record(-1, "Could not lookup OCSP response information");
 		goto x509_ocsp_cleanup;
 		}
 
-	if ( OCSP_id_cmp(certid, single->certId) != 0 )
+	if ( OCSP_id_cmp(certid, OCSP_SINGLERESP_get0_id(single)) != 0 )
 		return x509_result_record(-1, "OCSP reply is not for host certificate");
 
 	// next - check freshness of proof...
-	if ( ! ASN1_GENERALIZEDTIME_check(single->thisUpdate) || ! ASN1_GENERALIZEDTIME_check(single->nextUpdate) )
+	ASN1_GENERALIZEDTIME *thisUpdate;
+	ASN1_GENERALIZEDTIME *nextUpdate;
+	int type;
+	type = OCSP_single_get0_status(single, NULL, NULL, &thisUpdate, &nextUpdate);
+	if ( ! ASN1_GENERALIZEDTIME_check(thisUpdate) || ! ASN1_GENERALIZEDTIME_check(nextUpdate) )
 		{
 		rval = x509_result_record(-1, "OCSP reply contains invalid dates");
 		goto x509_ocsp_cleanup;
@@ -400,16 +404,16 @@ function x509_ocsp_verify%(certs: x509_opaque_vector, ocsp_reply: string, root_c
 	// Well, we will do it manually.
 
 
-	if ( X509_cmp_time(single->thisUpdate, &vtime) > 0 )
+	if ( X509_cmp_time(thisUpdate, &vtime) > 0 )
 		rval = x509_result_record(-1, "OCSP reply specifies time in future");
-	else if ( X509_cmp_time(single->nextUpdate, &vtime) < 0 )
+	else if ( X509_cmp_time(nextUpdate, &vtime) < 0 )
 		rval = x509_result_record(-1, "OCSP reply expired");
-	else if ( single->certStatus->type != V_OCSP_CERTSTATUS_GOOD )
-		rval = x509_result_record(-1, OCSP_cert_status_str(single->certStatus->type));
+	else if ( type != V_OCSP_CERTSTATUS_GOOD )
+		rval = x509_result_record(-1, OCSP_cert_status_str(type));
 
 	// if we have no error so far, we are done.
 	if ( !rval )
-		rval = x509_result_record(1, OCSP_cert_status_str(single->certStatus->type));
+		rval = x509_result_record(1, OCSP_cert_status_str(type));
 
 x509_ocsp_cleanup:
 
@@ -486,18 +490,18 @@ function x509_verify%(certs: x509_opaque_vector, root_certs: table_string_of_str
 	if ( ! untrusted_certs )
 		return x509_result_record(-1, "Problem initializing list of untrusted certificates");
 
-	X509_STORE_CTX csc;
-	X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs);
-	X509_STORE_CTX_set_time(&csc, 0, (time_t) verify_time);
-	X509_STORE_CTX_set_flags(&csc, X509_V_FLAG_USE_CHECK_TIME);
+	X509_STORE_CTX *csc = X509_STORE_CTX_new();
+	X509_STORE_CTX_init(csc, ctx, cert, untrusted_certs);
+	X509_STORE_CTX_set_time(csc, 0, (time_t) verify_time);
+	X509_STORE_CTX_set_flags(csc, X509_V_FLAG_USE_CHECK_TIME);
 
-	int result = X509_verify_cert(&csc);
+	int result = X509_verify_cert(csc);
 
 	VectorVal* chainVector = 0;
 
 	if ( result == 1 ) // we have a valid chain. try to get it...
 		{
-		STACK_OF(X509)* chain = X509_STORE_CTX_get1_chain(&csc); // get1 = deep copy
+		STACK_OF(X509)* chain = X509_STORE_CTX_get1_chain(csc); // get1 = deep copy
 
 		if ( ! chain )
 			{
@@ -529,11 +533,11 @@ function x509_verify%(certs: x509_opaque_vector, root_certs: table_string_of_str
 
 x509_verify_chainerror:
 
-	X509_STORE_CTX_cleanup(&csc);
+	X509_STORE_CTX_cleanup(csc);
 
 	sk_X509_free(untrusted_certs);
 
-	RecordVal* rrecord = x509_result_record(csc.error, X509_verify_cert_error_string(csc.error), chainVector);
+	RecordVal* rrecord = x509_result_record(X509_STORE_CTX_get_error(csc), X509_verify_cert_error_string(X509_STORE_CTX_get_error(csc)), chainVector);
 
 	return rrecord;
 	%}
-- 
2.8.1

Reply via email to