Security/Tizen 5.X Migration from OpenSSL 1.0.2 to OpenSSL 1.1.1 guide

From Tizen Wiki
Jump to: navigation, search

Porting/Migrating code from OpenSSL 1.0.2 to OpenSSL 1.1.1

Introduction

OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. It is also a general-purpose cryptography library. OpenSSL is widely used by developers and can be found in a huge number of products.

OpenSSL 1.1.1 was released on 11 September 2018. This is the latest LTS (Long Term Support) release, supported until September 2023. Previous LTS version, OpenSSL 1.0.2 will be supported until December 2019.

The headline new feature of OpenSSL 1.1.1 is TLSv1.3. This new version of the Transport Layer Security (formerly known as SSL) protocol was published by the IETF as RFC8446. This is a major rewrite of the standard and introduces significant changes, features and improvements which have been reflected in the new OpenSSL version.
Some of the benefits of TLSv1.3 include:

  • Improved connection times due to a reduction in the number of round trips required between the client and server.
  • The ability, in certain circumstances, for clients to start sending encrypted data to the server straight away without any round trips with the server required (a feature known as 0-RTT or “early data”).
  • Improved security due to the removal of various obsolete and insecure cryptographic algorithms and encryption of more of the connection handshake.

More information can be found in release notes: https://www.openssl.org/news/openssl-1.1.0-notes.html and https://www.openssl.org/news/openssl-1.1.1-notes.html

The API for OpenSSL 1.1.0 has been updated, but this broke the backwards compatibility (you can check out the list of things that no longer work and the notes on compatibility layer in the official OpenSSL documentation: https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes). One of the main goals of the OpenSSL 1.1.0 API changes was to encapsulate some of the data structures and to provide suitable interfaces for managing them.
The benefits of data encapsulation introduced in the new version of OpenSSL are:

  • Changing fields without breaking binary compatibility.
  • Making applications more robust as well as more assured about their correctness.
  • Easier to determine which (new) accessors and setters are needed.

Regarding API/ABI backward compatibility, please look at the report: https://abi-laboratory.pro/index.php?view=objects_report&l=openssl&v1=1.0.2p&v2=1.1.0 OpenSSL developers changed library so much, so simple re-compile is not enough, most of the code build atop OpenSSL 1.0.2 needs significant modification to be compiled against OpenSSL 1.1.1. This document is an attempt to aid such transition.

Migration tips and tricks

How to build your project with OpenSSL 1.1.1?

Change RPM spec file from packaging directory and edit your cmake/make files like in below example:

	../packaging/*.spec
	...
	-	BuildRequires: pkgconfig(openssl)
	+	BuildRequires: pkgconfig(openssl1.1)
	...
	-	BuildRequires: pkgconfig(libssl)
	+	BuildRequires: pkgconfig(libssl1.1)
	...
	-	BuildRequires: pkgconfig(libcrypto)
	+	BuildRequires: pkgconfig(libcrypto1.1)
	...

	../CMakeLists.txt OR ../configure.ac
	...
	PKG_CHECK_MODULES(PROJECT_DEP REQUIRED
	...
	-	openssl
	+	openssl1.1
	...
	-	libssl
	+	libssl1.1
	...
	-	libcrypto
	+	libcrypto1.1
	...
	)
	...

In case of upstream projects, changing RPM spec file is probably the one thing you should do. Sometimes you need to upgrade your project to the latest upstream version, most of upstream projects has been integrated with new OpenSSL already. In other cases, when your project building failed, you must fix your source code.

How to support OpenSSL 1.0.2 and 1.1.1 in your project?

Please use #ifdef in your source code like below:

	#if OPENSSL_VERSION_NUMBER < 0x10100000L // OpenSSL 1.0.2
		EVP_MD_CTX mdctx;
		EVP_MD_CTX_init(&mdctx);
		EVP_MD_CTX_cleanup(&mdctx);
	#else // OpenSSL 1.1.1
		EVP_MD_CTX *mdctx;
		mdctx = EVP_MD_CTX_new();
		EVP_MD_CTX_free(mdctx); // do not forget to free after usage or error
	#endif 

How to initialize OpenSSL 1.1.1?

Initializing and using OpenSSL 1.0.2 in multithreaded application was quite complicated (https://wiki.openssl.org/index.php/Library_Initialization). With OpenSSL 1.1.1 it's simple. If you are using OpenSSL 1.1.0 or above, then the library will initialize itself automatically. Optionally you can explicitly initialize it using OPENSSL_init_ssl() or OPENSSL_init_crypto().

Source code changes examples

Note: The examples below omits error checks. For production code, check return of the function and bail accordingly.
Note: If you find in your project things that should be changed and below list doesn't contain such example, please don't hesitate to add this example here. That will simplify another engineers work for sure.

Direct struct member access to accessor functions


  • BIGNUM accessing functions
		BIGNUM dh_pub;
	-	if (dh_pub->neg) ...
	+	if (BN_is_negative(dh_pub)) ...

	-	BN_num_bits(key->rsa->n);
	+	RSA_bits(key->rsa);  
  • struct DH became opaque, use accessors
		DH *dh;

	-	BN_sub(tmp, dh->p, BN_value_one());
	+	const BIGNUM *p;
	+	DH_get0_pqg(dh, &p, NULL, NULL);
	+	BN_sub(tmp, p, BN_value_one());

	-	dh->length = MIN(need * 2, pbits - 1);
	+	DH_set_length(dh, MIN(need * 2, pbits - 1));

	-	if (!dh_pub_is_valid(dh, dh->pub_key))) ...
	+	BIGNUM *pub_key, *priv_key;
	+	DH_get0_key(dh, &pub_key, &priv_key);
	+	if (!dh_pub_is_valid(dh, pub_key)) ...

	*_get0_*() functions doesn't increment the reference count of the BIGNUM, so do NOT BN_free() the values returned (Zero means they don't increment refcount).

		BIGNUM *modulus, *gen;

	-	dh->p = modulus;
	-	dh->g = gen;
	+	DH_set0_pqg(dh, modulus, NULL, gen);

	*_set0_*() functions takes ownership of the passed in BIGNUM*, so you should allocate it by BN_new(), and not free them after passing them in (except if *set0*() failed)
	Most of the *_set0_* functions just stashes the passed parameters to internal structures, but some does parameter checking and could fail, you must check the return code.  
  • struct RSA became opaque
		RSA *key;

	-	if (BN_num_bits(key->e) < 2) ...
	-	olen = BN_num_bytes(key->n);
	+	const BIGNUM *e, *n;
	+	RSA_get0_key(key, &n, &e, NULL);
	+	if (BN_num_bits(e) < 2) ...
	+	olen = BN_num_bytes(n);

	-	BN_num_bytes(key->n);
	+	RSA_size(key);

		RSA *rsa;

	-	... rsa->p, rsa->q, rsa->d, ...
	+	const BIGNUM *q, *d, *p;
	+	RSA_get0_key(rsa, NULL, NULL, &d);
	+	RSA_get0_factors(rsa, &p, &q);
	+	... p, q, d, ...

		BIGNUM *dmq1, *dmp1;

	-	rsa->dmq1 = dmq1;
	-	rsa->dmp1 = dmp1;
	+	RSA_set0_crt_params(rsa, dmp1, dmq1, NULL);

		/* receives data from buffer */
	-	buffer_get_bignum_bits(b, rsa->d);
	-	buffer_get_bignum_bits(b, rsa->n);
	-	buffer_get_bignum_bits(b, rsa->iqmp);
	-	buffer_get_bignum_bits(b, rsa->q);
	-	buffer_get_bignum_bits(b, rsa->p);

	+	BIGNUM *d = NULL, *n = NULL, *iqmp = NULL, *q = NULL, *p = NULL;
	+	BIGNUM *dmp1 = NULL, *dmq1 = NULL; /* dummy input to set in RSA_set0_crt_params */
	+	d = BN_new(); n = BN_new(); iqmp = BN_new();
	+	q = BN_new(); p = BN_new();

	+	buffer_get_bignum_bits(b, d);
	+	buffer_get_bignum_bits(b, n);
	+	buffer_get_bignum_bits(b, iqmp);
	+	buffer_get_bignum_bits(b, q);
	+	buffer_get_bignum_bits(b, p);

	+	RSA_set0_key(rsa, n, rsa_e, d);
	+	RSA_set0_factors(rsa, p, q);
	+	/* dmp1, dmq1 should not be NULL for initial set0 */
	+	dmp1 = BN_new(); BN_clear(dmp1);
	+	dmq1 = BN_new(); BN_clear(dmq1);
	+	RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);

		struct sshkey *key;
	-	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) ...
	+	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) ...  
  • struct RSA_METHOD became opaque, real struct must be replaced by a pointer and allocated accordingly
	-	RSA_METHOD helper_rsa;
	+	RSA_METHOD *helper_rsa;

	-	memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
	+	helper_rsa = RSA_meth_dup(RSA_get_default_method());
	-	helper_rsa.name = "ssh-pkcs11-helper";
	-	helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
	+	RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper");
	+	RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt);

	-	RSA_METHOD rsa_method;
	+	RSA_METHOD *rsa_method;
		const RSA_METHOD *def = RSA_get_default_method();
		RSA *rsa;
		...
	-	... = def->finish;
	+	... = RSA_meth_get_finish(def);

	-	memcpy(&rsa_method, def, sizeof(k11->rsa_method));
	-	rsa_method.name = "pkcs11";
	-	rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt;
	-	rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt;
	-	rsa_method.finish = pkcs11_rsa_finish;
	+	rsa_method = RSA_meth_new("pkcs11", RSA_meth_get_flags(def));
	+	RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt);
	+	RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt);
	+	RSA_meth_set_finish(rsa_method, pkcs11_rsa_finish);  
  • EVP_CIPHER_CTX became opaque
	-	EVP_CIPHER_CTX  evp;
	+	EVP_CIPHER_CTX  *evp;

	Every EVP_* functions manipulating on EVP_CIPHER_CTX should be passing opaque pointer, not a reference of real struct

	-	EVP_CIPHER_CTX_init(&evp);
	+	evp = EVP_CIPHER_CTX_new();
	+	EVP_CIPHER_CTX_free(evp);	/* do not forget to free after usage or error */

	-	EVP_CipherInit(&evp, EVP_des_cbc(), k1, NULL, enc);
	+	EVP_CipherInit(evp, EVP_des_cbc(), k1, NULL, enc);

	-	EVP_Cipher(&evp, dest, (u_char *)src, len);
	+	EVP_Cipher(evp, dest, (u_char *)src, len);

	-	EVP_CIPHER_CTX_cleanup(&evp);
	+	EVP_CIPHER_CTX_free(evp);

	-	memcpy(evp.iv, iv, 8);	/* direct write to Initial Vector */
	+	memcpy(EVP_CIPHER_CTX_iv_noconst(evp), iv, 8);	/* use accessor */

	-	memcpy(iv, evp.iv, len);	/* direct read from Initial Vector */
	+	memcpy(iv, EVP_CIPHER_CTX_iv(evp), len);

	-	... = (evp)->cipher_data;
	+	... = EVP_CIPHER_CTX_get_cipher_data(evp);
	-	... = (evp)->cipher->ctx_size;
	+	... = EVP_CIPHER_impl_ctx_size(EVP_CIPHER_CTX_cipher(evp));
	-	... = (evp)->flags;
	+	... = EVP_CIPHER_CTX_flags(evp);

	-	EVP_CIPHER_type(evp->cipher);
	+	EVP_CIPHER_CTX_type(evp);

	-	EVP_CIPHER_nid(evp->cipher);
	+	EVP_CIPHER_CTX_nid(evp);  
  • HMAC_CTX became opaque
	-	HMAC_CTX hctx;
	+	HMAC_CTX *hctx;

	Every HMAC_* functions manipulating on HMAC_CTX should be passing opaque pointer, not a reference of real struct

	-	HMAC_CTX_init(&hctx);
	+	hctx = HMAC_CTX_new();
	+	HMAC_CTX_free(hctx);	/* do not forget to free after usage or error */

	-	HMAC_Init_ex(&hctx, hmac_key, key_sz, EVP_sha1(), NULL);
	+	HMAC_Init_ex(hctx, hmac_key, key_sz, EVP_sha1(), NULL);

	-	HMAC_Update(&hctx, in, in_sz);
	+	HMAC_Update(hctx, in, in_sz);

	-	HMAC_Final(&hctx, out, NULL);
	+	HMAC_Final(hctx, out, NULL);

	-	HMAC_CTX_cleanup(&hctx);
	+	HMAC_CTX_free(hctx);  
  • EVP_CIPHER became opaque, initializers must use accessors which is cumbersome
	-	static EVP_CIPHER ssh1_3des;
	-	memset(&ssh1_3des, 0, sizeof(ssh1_3des));
	-	ssh1_3des.nid = NID_undef;
	-	ssh1_3des.block_size = 8;
	-	ssh1_3des.iv_len = 0;
	-	ssh1_3des.key_len = 16;
	-	ssh1_3des.init = ssh1_3des_init;
	-	ssh1_3des.cleanup = ssh1_3des_cleanup;
	-	ssh1_3des.do_cipher = ssh1_3des_cbc;
	-	ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;

	+	static EVP_CIPHER *ssh1_3des_p;
	+	ssh1_3des_p = EVP_CIPHER_meth_new(NID_undef, /*block_size*/8, /*key_len*/16);
	+	EVP_CIPHER_meth_set_iv_length(ssh1_3des_p, 0);
	+	EVP_CIPHER_meth_set_init(ssh1_3des_p, ssh1_3des_init);
	+	EVP_CIPHER_meth_set_cleanup(ssh1_3des_p, ssh1_3des_cleanup);
	+	EVP_CIPHER_meth_set_do_cipher(ssh1_3des_p, ssh1_3des_cbc);
	+	EVP_CIPHER_meth_set_flags(ssh1_3des_p, EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH);

	-	static EVP_CIPHER ssh1_bf;
	+	static EVP_CIPHER *ssh1_bfp;

	-	memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
	-	orig_bf = ssh1_bf.do_cipher;
	-	ssh1_bf.key_len = 32;
	+	orig_bf = EVP_CIPHER_meth_get_do_cipher(EVP_bf_cbc());
	+	ssh1_bfp = EVP_CIPHER_meth_new(NID_undef, /*block_size*/8, /*key_len*/32);

	-	ssh1_bf.do_cipher = bf_ssh1_cipher;
	+	EVP_CIPHER_meth_set_do_cipher(ssh1_bfp, bf_ssh1_cipher);
	+	/* set remaining members of new ssh1_bfp */
	+	EVP_CIPHER_meth_set_iv_length(ssh1_bfp, 8);
	+	EVP_CIPHER_meth_set_flags(ssh1_bfp, EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CBC_MODE);
	+	EVP_CIPHER_meth_set_init(ssh1_bfp, EVP_CIPHER_meth_get_init(EVP_bf_cbc()));
	+	EVP_CIPHER_meth_set_cleanup(ssh1_bfp, EVP_CIPHER_meth_get_cleanup(EVP_bf_cbc()));
	+	EVP_CIPHER_meth_set_impl_ctx_size(ssh1_bfp, /*sizeof(EVP_BF_KEY) == */sizeof(BF_KEY));
	+	EVP_CIPHER_meth_set_set_asn1_params(ssh1_bfp, EVP_CIPHER_set_asn1_iv);
	+	EVP_CIPHER_meth_set_get_asn1_params(ssh1_bfp, EVP_CIPHER_get_asn1_iv);
	+	EVP_CIPHER_meth_set_ctrl(ssh1_bfp, NULL);
	+	/*app_data = NULL*/  
  • EVP_MD_CTX became opaque, replace real struct with a pointer, and allocate it on first usage
	-	EVP_MD_CTX mdctx;
	+	EVP_MD_CTX *mdctx;

	-	EVP_MD_CTX_init(&mdctx);
	+	mdctx = EVP_MD_CTX_new();

	-	EVP_MD_CTX_cleanup(&mdctx);
	+	EVP_MD_CTX_free(mdctx);	/* do not forget to free after usage or error */  
  • EVP_PKEY became opaque
	-	switch (EVP_PKEY_type(pubkey->type)) {}
	+	switch (EVP_PKEY_type(EVP_PKEY_id(pubkey))) {}

	-	evp->pkey.rsa
	+	EVP_PKEY_get0_RSA(evp);  
  • struct DSA became opaque
		DSA *dsa;

	-	dsa->p = BN_new();
	-	dsa->q = BN_new();
	-	dsa->g = BN_new();
	-	dsa->pub_key = BN_new();
	+	BIGNUM *p = NULL, *q = NULL, *g = NULL, *pubkey = NULL;
	+	p = BN_new(); q = BN_new(); g = BN_new(); pub_key = BN_new();
	+	DSA_set0_pqg(dsa, p, q, g);
	+	DSA_set0_key(dsa, pubkey, NULL);

	-	BN_cmp(a->dsa->p, b->dsa->p) == 0 && ...
	-	BN_cmp(a->dsa->q, b->dsa->q) == 0 && ...
	+	const BIGNUM *a_p, *a_q, *a_g, ...
	+	const BIGNUM *b_p, *b_q, *b_g, ...
	+	DSA_get0_pqg(a->dsa, &a_p, &a_q, &a_g);
	+	DSA_get0_pqg(b->dsa, &b_p, &b_q, &b_g);
	+	BN_cmp(a_p, b_p) == 0 && ...
	+	BN_cmp(a_q, b_q) == 0 && ...
  • DSA_SIG became opaque
		DSA_SIG *sig;
		...
	-	rlen = BN_num_bytes(sig->r);
	-	slen = BN_num_bytes(sig->s);
		const BIGNUM *r, *s;
	+	DSA_SIG_get0(sig, &r, &s);
	+	rlen = BN_num_bytes(r);
	+	slen = BN_num_bytes(s);

	-	sig->r = r;
	-	sig->s = s;
	+	DSA_SIG_set0(sig, r, s);
  • ECDSA_SIG became opaque
		ECDSA_SIG *sig;
	-	... sig->r, sig->s, ...
	+	const BIGNUM *r, *s;
	+	ECDSA_SIG_get0(sig, &r, &s);
	+	... r, s, ...

		/* this assigns sig->r, sig->s */
	-	if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || sshbuf_get_bignum2(sigbuf, sig->s) != 0) ...
	+	BIGNUM *r = NULL, *s = NULL;
	+	r = BN_new(); s = BN_new();
	+	if (sshbuf_get_bignum2(sigbuf, r) != 0 || sshbuf_get_bignum2(sigbuf, s) != 0) ...
	+	ECDSA_SIG_set0(sig, r, s);  
  • struct BIO became opaque, use setters for initialization
	-	bio = BIO_new(&BioMethods);
	-	bio->ptr = (char*)statePtr;
	-	bio->init = 1;
	-	bio->shutdown = flags;
	+	bio = BIO_new(BIO_s_tcl());
	+	BIO_set_data(bio, (void*)statePtr);
	+	BIO_set_init(bio, 1);
	+	BIO_set_shutdown(bio, flags);

	-	static BIO_METHOD BioMethods = {
	-		BIO_TYPE_TCL, "tcl",
	-		BioWrite,
	-		BioRead,
	-		BioPuts,
	-		NULL,      /* BioGets */
	-		BioCtrl,
	-		BioNew,
	-		BioFree,
	-	};

		BIO_METHOD * BIO_s_tcl() {
	-		return &BioMethods;
	+		static BIO_METHOD *biom = NULL;
	+		if (!biom) {
	+			biom = BIO_meth_new(BIO_TYPE_TCL, "tcl");
	+			BIO_meth_set_write(biom, BioWrite);
	+			BIO_meth_set_read(biom, BioRead);
	+			BIO_meth_set_puts(biom, BioPuts);
	+			BIO_meth_set_ctrl(biom, BioCtrl);
	+			BIO_meth_set_create(biom, BioNew);
	+			BIO_meth_set_destroy(biom, BioFree);
	+		}
	+		return biom;
		}

		BIO bio;

	-	Tcl_Channel chan = Tls_GetParent((State*)(bio->ptr));
	+	Tcl_Channel chan = Tls_GetParent((State*)BIO_get_data(bio));

	-	bio->ptr = *((char **)ptr);
	-	bio->shutdown = (int)num;
	-	bio->init = 1;
	+	BIO_set_data(bio, *((char **)ptr));
	+	BIO_set_shutdown(bio, (int)num);
	+	BIO_set_init(bio, 1);

	-	ret = bio->num;
	+	ret = BIO_get_fd(bio, ptr);

	-	ret = bio->shutdown;
	+	ret = BIO_get_shutdown(bio);

	-	bio->shutdown = (int)num;
	+	BIO_set_shutdown(bio, (int)num);

	-	bio->flags = 0;
	+	BIO_clear_flags(bio, 0);

	bio->num (file descriptor) could be set by BIO_set_fd(), but since this callbacks the routine set by BIO_meth_set_ctrl(biom, BioCtrl), beware of infinite loops.
	Recommend to not touch bio->num member and leave it alone.  
  • BN_CTX became opaque
	-	BN_CTX ctx;
	+	BN_CTX *ctx;
	+	ctx = BN_CTX_new();
	+	BN_CTX_free(ctx);	/* do not forget to free after usage or error */  

API semantical changes

  • Disabling TLSv1 has different API.
		SSL *handle;
		...
		handle->options |= SSL_OP_NO_TLSv1;

	+	#if OPENSSL_VERSION_NUMBER >= 0x10100000L
	+		SSL_set_min_proto_version(handle, TLS1_1_VERSION);
	+	#else
	+		SSL_set_options(handle, SSL_OP_NO_TLSv1);
	+	#endif
  • EVP_CipherInit() has semantics changed to clear all previous settings, so you may want to replace it with EVP_CipherInit_ex(), if the original code is building parameters by multiple EVP_CipherInit() calls.
	-	EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1);
	+	EVP_CipherInit_ex(cc->evp, NULL, NULL, (u_char *)key, NULL, -1); 
  • X509_STORE_CTX_get_app_data() has changed semantics. Compilers wouldn't catch this change, not replacing this will likely cause Segmentation Fault.
	-	SSL *ssl = (SSL*)X509_STORE_CTX_get_app_data(ctx);
	+	SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());

How to check that your binary/library use OpenSSL 1.1.1?

The easiest way is as follows, please install 'binutils' package which provides 'objdump' tool, then you can do something like this:

# objdump -p /usr/apps/org.tizen.browser/bin/browser | grep -E 'libcrypto.so|libssl.so'
NEEDED               libssl.so.1.1
NEEDED               libcrypto.so.1.1 (it means that browser application is linked directly with OpenSSL 1.1.1)

# objdump -p /usr/lib/libyaca.so.0 | grep -E 'libcrypto.so|libssl.so'
NEEDED               libssl.so.1.0.0
NEEDED               libcrypto.so.1.0.0 (it means that yaca library is linked directly with OpenSSL 1.0.2) 

I have changed my RPM spec/cmake/make files correctly and my project is still using OpenSSL 1.0.2, what's wrong?

The cause of such issue can be some wrong pkgconfig file. Some libraries have wrong pkgconfig files, which expose unnecessary libraries to the program that is linking with this library. If the program will not be using the symbols of the required library, it should not be linking directly to that library.

How to detect and fix such issue? During building your project you will see something like below:

[   13s] [31/226] installing libopenssl1.1-1.1.1b-1.8
[   16s] [65/226] installing libopenssl-1.0.2r-11.19
[   18s] [87/226] installing openssl-1.0.2r-11.19
[   30s] [164/226] installing libopenssl1.1-devel-1.1.1b-1.8
[   30s] [168/226] installing libopenssl-devel-1.0.2r-11.19 

you have installed two OpenSSL devel packages in GBS chroot, this is the source of the problem.

Please enter your GBS chroot with command 'gbs chroot -r ...' and find the wrong pkgconfig file.

# cd /usr/lib/pkgconfig/
# grep Requires: *.pc | grep -E 'openssl|libssl|libcrypto'
cryptsvc.pc:Requires: libcrypto dlog

# rpm -qfi cryptsvc.pc | grep VCS // find cryptsvc.pc source code git path
VCS         : platform/core/security/libcryptsvc#a0b2212373b088c39c1f41f59f888a353113acae 

prepare and push commit like below:

-cryptsvc.pc:Requires: libcrypto dlog
+cryptsvc.pc:Requires: 

Summary

As you can see, converting to OpenSSL 1.1.0 can be tedious, but it's mostly going to be a matter of looking at the manpages or header file, and finding the appropriate functions to get or set the fields that you used to directly manipulate. Fortunately, this kind of thing will be found at compile-time.

  • Read the changelog and the official guidelines and recommendations for coping with the changes in OpenSSL 1.1.0.
  • See our examples, do it your own way specific to you product.
  • Watch out for memory leaks.
  • Test beforehand, test afterwards. Run Tizen TCT test suite. Test, test, test...