[解決済][cmake][AArch64] AArch64環境かつAlpine Linuxだとgnutlsライブラリを見つけられない? その2

AIX、UNIX、Linux, ContainerAArch64, Alpine, ARM, cmake, docker, gnutls

先日、Alpine Linuxでgetdnsをbuildしようとするとcmakeのmoduleがgnutlsライブラリを見つけることが出来ない、という記事を書きました。

前回の記事

最終的にはissueにて報告したわけですがすぐに反応がありました。

getdnsのレポジトリ

前回のその1への反応

--- CMakeLists.txt.bak  2020-02-23 09:33:05.735484712 +0900
+++ CMakeLists.txt      2020-02-23 09:37:04.087814273 +0900
@@ -364,7 +364,8 @@
 # GnuTLS and Nettle. If using GnuTLS, we need the Nettle dev stuff to
 # handle digital signature algorithms. GnuTLS uses Nettle internally.
 if (USE_GNUTLS)
-  find_package(GnuTLS "3.5.0" REQUIRED)
+  find_package(PkgConfig REQUIRED)
+  pkg_check_modules(GnuTLS REQUIRED gnutls>=3.5)
   find_package(Nettle REQUIRED)

   set(tlsdir "gnutls")
   set(HAVE_NETTLE 1)

As others have found, the fundamental problem here is that we expect to find the GnuTLS DANE library (used for certificate validation), and this is not included in the Alpine GnuTLS package build. Furthermore, as we note in the README:

A project to allow user selection of either OpenSSL or GnuTLS is currently a work in progress. At present a user may select to use GnuTLS for the majority of the supported functionality, however, OpenSSL is still required for some cryptographic functions.

So, enabling GnuTLS will NOT currently remove the requirement to link against OpenSSL. At present, therefore, I would suggest that packagers should not be using GnuTLS.

Finally, I’ve avoided using the cmake PkgConfig module, for the simple reason that the primary goal of moving to a cmake build is to enable building on Windows natively (i.e. without MinGW or other Unixy environment).

https://github.com/getdnsapi/getdns/issues/457#issuecomment-590289153

  • GnuTLS DANEライブラリ(証明書の検証に使用)を見つけることを期待している。
  • cmake PkgConfigモジュールの使用を避けた。
    • cmakeビルドに移行する主な目的は、Windows上でネイティブに(つまり、MinGWや他のUnixy環境なしで)ビルドできるようにすることであるという単純な理由から

ということでその1での対応はgetdnsからすると正しくない対応だったようです。

新しい提案

Since there is no package gnuTLS-openssl on Alpine you can try to rebuild gnutTLS.
Basically you get probably the same result when building gnuTLS with the switch --enable-openssl-compatibility. Unfortunately both Arch and Alpine linux do not have that switch default enabled in their packages.

If you wish you can add “--enable-openssl-compatibility" to the configure script of gnuTLS, so the API will automatically be installed.

https://github.com/getdnsapi/getdns/issues/457#issuecomment-590402868

GnuTLSを自前でbuildする。その際 --enable-openssl-compatibility を有効にした上でbuildするのはどうだろうか?という提案です。

実際にやってみた

gnutlsは以下のconfigureオプションでbuildしました。この記事時点では3.6.12です。

./configure \
       --with-gnu-ld \
       --disable-doc \
       --disable-tests \
       --enable-shared \
       --enable-openssl-compatibility

gnutlsをbuild出来たので改めてgetdnsをbuildしてみたところ、以下のようにconfigureでgnutlsライブラリを検索するようになっていました。

Found Threads: TRUE 
Found Libidn2: /usr/lib/libidn2.so (found suitable version "2.3.0", minimum required is "2.0.0")
Found GnuTLS: /usr/local/lib/libgnutls.so;/usr/local/lib/libgnutls-dane.so (found suitable version "3.6.1
2c", minimum required is "3.5.0") 
Found Nettle: /usr/lib/libgmp.so;/usr/lib/libnettle.so;/usr/lib/libhogweed.so (found version "3.5") 

がしかし、

[ 35%] Building C object CMakeFiles/getdns_objects.dir/src/jsmn/jsmn.c.o 
[ 36%] Building C object CMakeFiles/getdns_objects.dir/src/yxml/yxml.c.o
[ 37%] Building C object CMakeFiles/getdns_objects.dir/src/tls/val_secalgo.c.o
/usr/src/src/tls/val_secalgo.c: In function '_verify_nettle_ecdsa':
/usr/src/src/tls/val_secalgo.c:1729:36: error: 'nettle_secp_256r1' undeclared (first use in this function); 
did you mean 'nettle_get_secp_256r1'?                      
 1729 |    nettle_ecc_point_init(&pubkey, &nettle_secp_256r1);                                     
      |                                    ^~~~~~~~~~~~~~~~~
      |                                    nettle_get_secp_256r1
/usr/src/src/tls/val_secalgo.c:1729:36: note: each undeclared identifier is reported only once for each function it appears in                                                       
/usr/src/src/tls/val_secalgo.c:1746:36: error: 'nettle_secp_384r1' undeclared (first use in this function); 
did you mean 'nettle_get_secp_384r1'?                    
 1746 |    nettle_ecc_point_init(&pubkey, &nettle_secp_384r1);
      |                                    ^~~~~~~~~~~~~~~~~
      |                                    nettle_get_secp_384r1
make[2]: *** [CMakeFiles/getdns_objects.dir/build.make:492: CMakeFiles/getdns_objects.dir/src/tls/val_secalg
o.c.o] Error 1
make[2]: *** Waiting for unfinished jobs.... 
make[1]: *** [CMakeFiles/Makefile2:1087: CMakeFiles/getdns_objects.dir/all] Error 2    
make: *** [Makefile:141: all] Error 2     

nettle関連の部分でのエラー?が発生するようです。そのことを続けて報告したところ以下のような返信が。

Then you have to change in the folder '/getdns-1.6.0-rc.1/src/tls/’ the file “val_secalgo.c' for line 1729 as suggested into 'nettle_ecc_point_init(&pubkey, &nettle_get_secp_256r1);'

The same with line 1746 'nettle_get_secp_384r1'

https://github.com/getdnsapi/getdns/issues/457#issuecomment-590781928

I’ve submitted a PR fixing #458. Note that the suggested fix above is incorrect – the use of e.g. &nettle_secp_256r1 needs to be replaced by nettle_get_secp_256r1(), not &nettle_get_secp_256r1.

https://github.com/getdnsapi/getdns/issues/457#issuecomment-590870760

ということで以下のようなpatchを作って適用してみました。ちなみに返信の中でnettleパッケージはGitHubからcloneしてという手順を案内されていますが、Alpine Linuxのパッケージャーにあるnettle-devを使用しても問題ありませんでした。

--- val_secalgo.c.org   2020-02-25 18:58:55.952479729 +0900
+++ val_secalgo.c       2020-02-25 19:00:03.316578892 +0900
@@ -1726,7 +1726,7 @@
                {
                        uint8_t digest[SHA256_DIGEST_SIZE];
                        mpz_t x, y;
-                       nettle_ecc_point_init(&pubkey, &nettle_secp_256r1);
+                       nettle_ecc_point_init(&pubkey, nettle_get_secp_256r1);
                        nettle_mpz_init_set_str_256_u(x, SHA256_DIGEST_SIZE, key);
                        nettle_mpz_init_set_str_256_u(y, SHA256_DIGEST_SIZE, key+SHA256_DIGEST_SIZE);
                        nettle_mpz_set_str_256_u(signature.r, SHA256_DIGEST_SIZE, sigblock);
@@ -1743,7 +1743,7 @@
                {
                        uint8_t digest[SHA384_DIGEST_SIZE];
                        mpz_t x, y;
-                       nettle_ecc_point_init(&pubkey, &nettle_secp_384r1);
+                       nettle_ecc_point_init(&pubkey, nettle_get_secp_384r1);
                        nettle_mpz_init_set_str_256_u(x, SHA384_DIGEST_SIZE, key);
                        nettle_mpz_init_set_str_256_u(y, SHA384_DIGEST_SIZE, key+SHA384_DIGEST_SIZE);
                        nettle_mpz_set_str_256_u(signature.r, SHA384_DIGEST_SIZE, sigblock);

これで無事にGnuTLSを有効にした状態でgetdnsをbuildすることが出来ました。

@hanvinke さん、@banburybill さん、アドバイス、Pull Requestありがとうございました。

追記

その後、本件に対応したPRが作成され無事にMergeされました。

この記事を書いた人
kometchtech

kometchtech
うつ病を患いながら、IT業界の末席にいるおっさんエンジニア。科学計算をしたことがないのに、HPC分野にお邪魔している。興味のある分野で学習したことをblogにまとめつつ、うつ病の経過症状のメモも置いておく日々。じつはRouterboard User Group JPの中の人でもある。
Amazon欲しいものリスト / Arm板を恵んでくれる人募集中