GPG 入門

GnuPG は、Pretty Good Privacy (PGP) のOSS版です。

GNU Privacy Guard (GnuPG, GPGはOpenPGP標準の実装。以下のことを行います。

  • 暗号化
  • 電子署名
  • 公開鍵認証

例えば、パッケージマネージャーなどのインストーラーがダウンロードするソフトウェアが意図した作成者が作成したものであるか確認してからインストールします。これを実現する仕組みの一つです。 鍵管理には、公開鍵方式を使用しますが、認証局を設置せず、ユーザーそれぞれが鍵管理をして、取得した公開鍵を確認します。

GPGでは、以下の2つの秘密鍵を作ります。

  • 署名のためのmaster key
  • 署名に加えて暗号化を行うためのsub key

master keyは絶対に流出させないように厳重に管理し、普段の運用にsub keyを使用する。

master keyを使用するのは以下の場合です(参照: *** GPGで自分用の秘密鍵を1つに統一する)。

  • 他人の鍵に署名
  • 鍵を取り消し
  • UIDを強く信頼
  • 新しいsub keyを作成
  • 他の鍵の暗号化アルゴリズム、ハッシュ関数などを変更
  • 鍵の有効期限を指定

master keyは、オフライン環境で、一度もネットワークに繋いだことのないOSのような環境で実行し、厳重に管理します。信頼できない、OS上では実行してはいけない。 署名と暗号化に同一の鍵を使うと、暗号化アルゴリズム依存の脆弱性が生じる場合があるので、暗号化、署名、認証のそれぞれに専用のsub keyを作ると良い。

Web of Trust

公開鍵の正当性を確認するために、フィンガープリントが一致していることを確認します。正当性の確認が済んだ後,受け取った公開鍵に,自分の秘密鍵で署名することで準備完了です。

信頼できる人が信頼している公開鍵は信用することを、広げていきます。このように、互いに、鍵の署名を行いあうことで、信頼の関係を構築していくことで、信頼関係を構築します。 公開鍵の正当性の確認を行わないと、Web of Trust全体の信頼性が下がります。

自身の鍵ペアについては、公開鍵はWeb上で公開したり、鍵サーバーに登録し、メールを送る都度添付することで対応します。他の人は自身あてに暗号化メールを送ったり、他の人が自身の公開鍵で自身が署名した内容を検証できるようになります。

これらの公開鍵をまとめておくものが鍵束(Keyring)です。これは以下のようにバイナリーファイルとして格納されています。

# hexdump -C ~/.gnupg/pubring.kbx
00000000  00 00 00 20 01 01 00 02  4b 42 58 66 00 00 00 00  |... ....KBXf....|
00000010  61 b9 5c bc 61 ba a7 13  00 00 00 00 00 00 00 00  |a.\.a...........|
00000020  00 00 07 c2 02 01 00 00  00 00 00 66 00 00 07 48  |...........f...H|
:
000027f0  f2 ec 82 b0 06 00 03 67  70 67 00 d1 fd 7d fe cb  |.......gpg...}..|
00002800  a7 a0 a2 96 5e 5b 72 f9  d3 24 a8 3d b6 91 7c     |....^[r..$.=..||
0000280f

ただし、公開鍵は普段使いには、サイズが大きいため、電子指紋(鍵指紋)をメールのヘッダーやフッターに添付することで、Web上に公開しておいた公開鍵の電子指紋と比較することができる。

gpgコマンドの使い方

環境

以下のバージョンで検証。

GPGのバージョンは以下。

$ gpg --version
gpg (GnuPG) 2.2.33
libgcrypt 1.8.8
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/ec2-user/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB

RPMのバージョンは以下。

$ rpm --version
RPM version 4.11.3
Get Started
GPG鍵の生成

GPG鍵を生成。鍵の種類や有効期限などを聞かれるがここではすべてデフォルトのまま使用する。

$ gpg --gen-key
gpg (GnuPG) 2.2.33; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: Sample1
Email address: hayashier@example.com
You selected this USER-ID:          
    "Sample1 <hayashier@example.com>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? O

以下のような画面でパスフレーズを入力します。

                                                  ┌──────────────────────────────────────────────────────┐
                                                  │ Please enter the passphrase to                       │
                                                  │ protect your new key                                 │
                                                  │                                                      │
                                                  │ Passphrase: ________________________________________ │
                                                  │                                                      │
                                                  │       <OK>                              <Cancel>     │
                                                  └──────────────────────────────────────────────────────┘

インポートされている公開鍵の情報は以下。

$ gpg --list-keys
/home/ec2-user/.gnupg/pubring.gpg
---------------------------------
pub   rsa3072 2021-12-15 [SC] [expires: 2023-12-15]
      ACADDFEEB9D5D60EFAC9463544B04C2E699AC5F0
uid           [ultimate] Sample1 <hayashier@example.com>
sub   rsa3072 2021-12-15 [E] [expires: 2023-12-15]

なお、上記コマンドの初回実行時は以下のようなデバッグメッセージが出力されるので、自動化の際は注意。

$ gpg --list-keys 
gpg: directory `/home/ec2-user/.gnupg' created
gpg: new configuration file `/home/ec2-user/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/ec2-user/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/home/ec2-user/.gnupg/pubring.gpg' created
gpg: /home/ec2-user/.gnupg/trustdb.gpg: trustdb created
$ gpg --list-keys
$ 
GPGで暗号化、署名

まず、GPGはどのように扱うか基本を抑えておく必要がある。

$ echo "Hello, World" > test.txt

ファイルの署名には以下のコマンドを実行します。

$ gpg -s test.txt

以下のような入力画面が出てくるので、鍵作成時に指定したパスワードを入力します。

                                             ┌────────────────────────────────────────────────────────────────┐
                                             │ Please enter the passphrase to unlock the OpenPGP secret key:  │
                                             │ "Sample1 <hayashier@example.com>"                              │
                                             │ 3072-bit RSA key, ID AAC5DE59A84FCD28,                         │
                                             │ created 2021-12-15.                                            │
                                             │                                                                │
                                             │                                                                │
                                             │ Passphrase: ********__________________________________________ │
                                             │                                                                │
                                             │         <OK>                                    <Cancel>       │
                                             └────────────────────────────────────────────────────────────────┘

すると、以下のようなバイナリーファイルが作成されます。

$ hexdump -C test.txt.gpg 
00000000  a3 01 01 e2 01 1d fe 90  0d 03 00 08 01 c1 d2 ca  |................|
00000010  ea 38 27 7e e6 01 ac 1b  62 08 74 65 73 74 2e 74  |.8'~....b.test.t|
00000020  78 74 61 bd d0 49 48 65  6c 6c 6f 2c 20 57 6f 72  |xta..IHello, Wor|
00000030  6c 64 0a 89 01 b3 04 00  01 08 00 1d 16 21 04 43  |ld...........!.C|
00000040  1e ab 98 4a 91 25 b4 58  c3 24 bc c1 d2 ca ea 38  |...J.%.X.$.....8|
00000050  27 7e e6 05 02 61 bd d0  49 00 0a 09 10 c1 d2 ca  |'~...a..I.......|
00000060  ea 38 27 7e e6 16 68 0b  ff 48 ab 8e a5 87 d8 fd  |.8'~..h..H......|
00000070  7a 04 7c 7a 17 43 81 a6  c7 4e 20 37 09 04 fe be  |z.|z.C...N 7....|
00000080  92 68 89 e9 b9 67 54 d8  4e 64 9e 92 4e 5f a2 ee  |.h...gT.Nd..N_..|
00000090  0a ce 5b 09 2d 72 a3 3c  5d 56 bc 8a bc 44 9c 30  |..[.-r.<]V...D.0|
000000a0  a3 30 39 5b a6 9a b3 a0  09 f0 dc a8 6a c9 04 44  |.09[........j..D|
000000b0  c7 bf a6 ff 9e 97 ed 1e  78 38 58 88 56 56 83 f3  |........x8X.VV..|
000000c0  6b 94 6f 0c 05 79 83 05  96 19 89 7d 8f 59 72 75  |k.o..y.....}.Yru|
000000d0  2b 8a 4c 76 4f a0 cd e0  0e 71 d7 1b f1 78 aa 9d  |+.LvO....q...x..|
000000e0  3e ec 9d f8 c4 af 4f 32  67 69 11 22 44 33 e9 3e  |>.....O2gi."D3.>|
000000f0  22 77 aa 05 24 cd 8a f2  57 5e d5 db 0c cd 51 00  |"w..$...W^....Q.|
00000100  30 25 29 bd 01 1b f8 24  9a 86 67 cc 17 73 c3 90  |0%)....$..g..s..|
00000110  0c dd 5e dd 9e a3 4d 84  c6 6f 57 86 4e f2 8f 0c  |..^...M..oW.N...|
00000120  92 a7 2c 2b 11 aa e9 7a  b9 e1 1f 4a a3 3e e0 f2  |..,+...z...J.>..|
00000130  53 fc 16 a9 9e d1 e2 b5  5b ee e3 94 e7 0b 17 1d  |S.......[.......|
00000140  28 8a 35 f5 79 61 3b d8  d0 3b e3 d4 3a b9 7a 7e  |(.5.ya;..;..:.z~|
00000150  47 89 7b 10 56 bb c2 fc  ad 7d ad cb 5f ef b6 b7  |G.{.V....}.._...|
00000160  31 f1 7c d7 5b b7 cb fe  aa 8d 82 b0 32 5f c5 3a  |1.|.[.......2_.:|
00000170  8d 62 91 42 10 d8 96 2b  5e 9f 26 ef 9b e6 f2 26  |.b.B...+^.&....&|
00000180  43 95 ee 65 77 3b 5e 2c  c6 d1 f7 63 3a 4b 64 31  |C..ew;^,...c:Kd1|
00000190  d5 29 da 60 a9 d3 78 bd  4f 22 f7 27 f3 0c 0c b2  |.).`..x.O".'....|
000001a0  f4 18 ca 2a c5 6c 7c 84  77 68 0e 2d 58 a5 55 f6  |...*.l|.wh.-X.U.|
000001b0  05 7f bf 4a 23 d1 b4 ac  16 84 ae 0e b1 63 be 79  |...J#........c.y|
000001c0  99 45 b2 e5 95 59 94 ec  79 e9 e0 8f cd 9a 15 5d  |.E...Y..y......]|
000001d0  63 1c 35 ce 7f 84 02 de  d7 a5 21 f2 72 69 bf 06  |c.5.......!.ri..|
000001e0  98 93 1d ab 20 9a 45 33  7a                       |.... .E3z|
000001e9

-aオプションを使用することで、テキスト形式でファイルが出力されます。

$ gpg -s -a test.txt
$ cat test.txt.asc 
-----BEGIN PGP MESSAGE-----

owEB4gEd/pANAwAIAcHSyuo4J37mAawbYgh0ZXN0LnR4dGG90N5IZWxsbywgV29y
bGQKiQGzBAABCAAdFiEEQx6rmEqRJbRYwyS8wdLK6jgnfuYFAmG90N4ACgkQwdLK
6jgnfuYYZQv/XbZbbcWx2ZpOKs85ld6IPqiXlSTw3+8qh+pzWEiIvhopLGkzVjov
P0nSxSzKwmsmRaKAaLBLFulp0ZoL0/JW/Fu4UznyCB7m29UGJ4oBuGJj/5CKdkgJ
GQqED6H9OjAdts+uQq8iTZUwUVaMjQ8oUFgp5gLkZVEouxeKcDqeXz6BXhKuaXsi
iI7iQ/eHOSQZ3aQAcdBg+WPZgm3xoSEA7/x5aRdxtzt6E9+fLQe3nZ2XEYUOoGR3
BpOTqzvqvt5BiITfkReWtJIEmcTbGJpODQg4xXdfioUrIHA3pKX4rkOloYQj5baa
bssXlWSgErRGKvks/vOPrKbRFIT7WDrmCZ5+CfTS2Lug/v+yXpepSynuaK1q2Xm3
mXdTyQFmQKIFmbTczCMlpRXiCOzLh+cRhzyd+jM4I1sj0igkSu3KLCOOXQ6Wlrho
nEnfGnvHtqonb3cB5+wq6wJGplTYGyddni90SEX84oB4ifOxvXHuh6x5URzTlah/
sPg9PTU7L9Cf
=obJ6
-----END PGP MESSAGE-----

元のデータを残した状態で署名するには以下のように実行します。

$ gpg --clearsign test.txt
$ cat test.txt.asc 
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Hello, World
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCAAdFiEEQx6rmEqRJbRYwyS8wdLK6jgnfuYFAmG90ZcACgkQwdLK6jgn
fubo9gv9FqWLZ4BNK4juyxddiXOW08EuVaEOEPrzIFexqBbE8Qto+BNn9XnQNW00
GQ85+r9QRREE/ayXT3DC7u5MClL0AozPo7Fklnb25RRhapkPbIylWdiZtBhJJRmz
Qtqt9zABnz1IX06fA359cABfCpuce6gUIpI4XOPpnEpeAS1yP8MuGKRUQsBxE4G2
UVgJXmQ4h6jiIhtuudtHP4t70A3KUd1zCxd3BN0wv2K9DCcLQV4o0l/f2LXdqIG3
S9/uiEPAgEHrCMIys2Qo14KvL/9tOvX1F59VGUTTkaqBtU5wT7xf95DHkkcI0/Ub
t3gfQlvfRwuBw73JwWFxl8VTnQO6sDrOxnEt3DD4Xl1C1TPCDPTcWIYE4XpinKLR
QHT2tvv6c/ml7L6uD1RPyqGuDAoGwoYnb3SAekMcYOzapx1IlPJal6nsbwZ3qSlC
O6P0nvLwabMRGBAg3NNPzLEgdXjDl84rFuY3Rvtff12RMPYIVl7HkLzir0TRzqWh
wJQcbLb4
=4QtG
-----END PGP SIGNATURE-----

元のデータとは別に署名用のファイルを作成する場合は以下のように実行します。すると、バイナリ形式の署名ファイルが生成されます。

$ gpg --detach-sign test.txt
$ hexdump -C test.txt.sig
00000000  89 01 b3 04 00 01 08 00  1d 16 21 04 43 1e ab 98  |..........!.C...|
00000010  4a 91 25 b4 58 c3 24 bc  c1 d2 ca ea 38 27 7e e6  |J.%.X.$.....8'~.|
00000020  05 02 61 bd d1 e7 00 0a  09 10 c1 d2 ca ea 38 27  |..a...........8'|
00000030  7e e6 5d 9b 0b fe 3f b6  dc d7 62 4d ce bc ea bf  |~.]...?...bM....|
00000040  75 91 3c 1d 3a d4 6c a6  7e f0 4c 40 2f cf 0e 1e  |u.<.:.l.~.L@/...|
00000050  71 27 a0 27 19 ca 2a b6  9a b5 c4 92 38 8b 54 17  |q'.'..*.....8.T.|
00000060  0a 06 a9 92 f2 23 12 6d  b8 17 25 96 3c 9f 1c b1  |.....#.m..%.<...|
00000070  e4 1e 78 aa 3d bc 7c f3  80 98 01 61 58 9a 5f b5  |..x.=.|....aX._.|
00000080  ce 37 f7 8d 01 71 d2 b5  dd e2 ae 83 a7 6a 6d 06  |.7...q.......jm.|
00000090  de a0 f2 6a 11 af 40 e1  13 1f 66 b1 62 3e 0a 22  |...j..@...f.b>."|
000000a0  4f af ff 90 b6 b0 0d 93  a2 3e 92 44 73 4e ae d7  |O........>.DsN..|
000000b0  1e 8e 2f 6d 0c b8 d5 9e  be 61 29 29 5d a1 59 7a  |../m.....a))].Yz|
000000c0  25 97 ba 89 c4 63 a8 a2  67 da 49 34 87 82 c8 ba  |%....c..g.I4....|
000000d0  ee 40 ab 72 42 73 34 9c  2c ce 0c fd 20 0b f8 6a  |.@.rBs4.,... ..j|
000000e0  50 66 1f a4 47 e4 7d 37  0e ca 23 00 a6 68 85 31  |Pf..G.}7..#..h.1|
000000f0  7e 97 ce ee b8 b1 e9 b1  9f 92 04 4a 0b 96 15 22  |~..........J..."|
00000100  9e 9f 6b a7 74 31 a2 b0  a9 7a 0b 8d 5b 29 0f 6c  |..k.t1...z..[).l|
00000110  c7 85 29 f1 8e 93 02 69  52 8d d8 79 42 95 0e ac  |..)....iR..yB...|
00000120  9f ba d1 81 65 46 e6 7a  59 d8 08 5e 63 7a 71 3e  |....eF.zY..^czq>|
00000130  d1 28 43 53 74 8c 60 c8  77 cc fc 57 b5 2a 36 54  |.(CSt.`.w..W.*6T|
00000140  86 ab bd 9d ea 9f 1b 11  43 8d b8 c2 88 87 2c 2f  |........C.....,/|
00000150  0c 16 ba 3b eb 80 2f 8c  f9 5a 5d 5d ea 6e f0 cb  |...;../..Z]].n..|
00000160  66 c9 df 41 cc 76 d7 3a  77 43 56 fb 06 bf f0 bc  |f..A.v.:wCV.....|
00000170  17 66 d3 22 bc a6 78 4d  7e 59 25 a6 0d fa f6 42  |.f."..xM~Y%....B|
00000180  8d 55 73 a8 c7 05 6c 98  fe 76 cb 74 9c 73 eb 67  |.Us...l..v.t.s.g|
00000190  67 04 5e 50 22 81 c5 ef  f7 f0 e3 70 ed 0a 72 0d  |g.^P"......p..r.|
000001a0  6b 2b d4 4c 93 c3 d7 32  e8 58 72 26 71 f4 22 d6  |k+.L...2.Xr&q.".|
000001b0  d3 a9 3a 20 64 2a                                 |..: d*|
000001b6

先程同様に-aオプションを付与することで、テキスト形式で署名ファイルを生成します。

$ gpg --detach-sign -a test.txt
$ cat test.txt.asc 
-----BEGIN PGP SIGNATURE-----

iQGzBAABCAAdFiEEQx6rmEqRJbRYwyS8wdLK6jgnfuYFAmG90ikACgkQwdLK6jgn
fubgHQv8CkZgPQ318Trh4GCDMyQ9CnI/MyWpyRe2WDhNTVWgfhjYGQjGK+pEuGkj
RTIL3eXwF7JDx2ZU5B/Xo8BIjarl+3Ole7gEVw79dO6gUFPXmRxK8ar5GbgrnvIB
pvuTs1QxAZrAguSuw0tamw8oWMk1BSn3L1JL4UCSFj9brGATAKjfCdxDDocFWcZL
Ed4DGXzkRH2oZT1QoaMmg9Xe8SK1dhw16SnSCpswIHaGCLp4RI/5hgWdsbaFKL/p
sdkbMIJcRhY6CvaLhaRVUxZXpNnWFvFuNfQVtw6JnKBWPSTJpBAGl97T2H5wVohQ
XHGTfElu18F4pHFD/6Fae6+fcyTDKol/EEeJBCEwjxFZuwHTcSznMlsCxPtXectC
s+/77cCXeI8QCqLc7GYNtnwOoXN4axLmD4+B2KAkXz7ykX5mbpm2Xr1z2MkUXutA
1QWbMFxGT3Tk60WQi+4uRR5HEucHhPtMlc816Z/1ZJx0ooKhfnW4IEptGhl4cema
kJGjn5VC
=bKZi
-----END PGP SIGNATURE-----

署名を検証。署名ファイルと同じディレクトリに元のファイルがあることを前提としている。

$ gpg --verify test.txt.sig
gpg: assuming signed data in 'test.txt'
gpg: Signature made Sat Dec 18 12:19:51 2021 UTC
gpg:                using RSA key 431EAB984A9125B458C324BCC1D2CAEA38277EE6
gpg: Good signature from "Sample1 <hayashier@example.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 431E AB98 4A91 25B4 58C3  24BC C1D2 CAEA 3827 7EE6

ここで、ファイル名を変更してみます。

$ mv test.txt test.changed.txt

すると、データがないものと認識されてしまいます。

$ gpg --verify test.txt.sig
gpg: no signed data
gpg: can't hash datafile: No data

引数に変更後のファイル名を指定すると、正常に署名を検証できます。

$ gpg --verify test.txt.sig test.changed.txt 
gpg: Signature made Sat Dec 18 12:19:51 2021 UTC
gpg:                using RSA key 431EAB984A9125B458C324BCC1D2CAEA38277EE6
gpg: Good signature from "Sample1 <hayashier@example.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 431E AB98 4A91 25B4 58C3  24BC C1D2 CAEA 3827 7EE6

RPMでGPG署名

RPMパッケージの作成

RPMパッケージにGPGで署名する前に、簡単なRPMファイルを作成しておく。

以下、Amazon Linux 2での検証です。CentOS 7でもおおよそ同様に検証できるでしょう。 RPM環境のセットアップと、目的のアプリケーションの用意。

$ sudo yum install rpm-build rpmdevtools git -y
$ rpmdev-setuptree
$ cd $HOME/rpmbuild
$ mkdir motd-1.0
$ echo "THIS IS MY CUSTOM MOTD" > motd-1.0/motd
$ tar -czvf SOURCES/motd-1.0.tar.gz motd-1.0
$ rpmdev-newspec SPECS/motd.spec

以下の内容でSpecファイルを作成

$ cat SPECS/motd.spec
Name:           motd
Version:        1.0
Release:        1%{?dist}
Summary:        Test Summary

License:        Test License
Source0:        motd-%{version}.tar.gz

BuildArch:      noarch
%define _topdir %(echo $PWD)/

%description
This is my custom MOTD config

%prep
%setup -q


%install
rm -rf $RPM_BUILD_ROOT
install -d $RPM_BUILD_ROOT/etc
install motd $RPM_BUILD_ROOT/etc/motd

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,root,root,-)
/etc/motd

%doc

%changelog

rpmの作成 + インストール。

$ rpmbuild -ba -v SPECS/motd.spec
$ sudo rpm -ivh RPMS/noarch/motd-1.0-1.amzn2.noarch.rpm --force

結果確認。

$ cat /etc/motd 
THIS IS MY CUSTOM MOTD

SSHでログイン時にも反映されていることを確認。

$ ssh -i ~/.ssh/myprivate.pem ec2-user@xxx.xxx.xxx.xxx
Last login: Thu Dec  2 09:29:00 2021 from 205.251.233.182
THIS IS MY CUSTOM MOTD

作成されたパッケージは以下のように、Signatureがnoneより無署名状態。

$ rpm -qpi ~/rpmbuild/RPMS/noarch/motd-1.0-1.amzn2.noarch.rpm 
Name        : motd
Version     : 1.0
Release     : 1.amzn2
Architecture: noarch
Install Date: (not installed)
Group       : Unspecified
Size        : 23
License     : Test License
Signature   : (none)
Source RPM  : motd-1.0-1.amzn2.src.rpm
Build Date  : Thu Dec  2 09:30:17 2021
Build Host  : ip-172-31-10-148.us-west-2.compute.internal
Relocations : (not relocatable)
Summary     : Test Summary
Description :
This is my custom MOTD config
実際にRPMに対してgpgで署名(ファイルに対する署名)

署名を付加するのに必要なライブラリをインストール。

$ sudo yum install rpm-sign -y

署名の状態を確認する。

$ rpm --checksig motd-1.0-1.amzn2.noarch.rpm 
motd-1.0-1.amzn2.noarch.rpm: sha1 md5 OK

署名を付加する。

$ echo "%_gpg_name Sample1" >> ~/.rpmmacros
$ rpm --addsign motd-1.0-1.amzn2.noarch.rpm 

raw RPM マクロ定義、すなわち、上記署名は以下のデフォルト値が適用されている。後ほどカスタムマクロを用いてGPGの設定を編集する。

$ rpm --showrc | egrep "gpg|signature|tmppath"
-14: __gpg	%{_bindir}/gpg2
-14: __gpg_check_password_cmd	%{__gpg} 
	gpg --batch --no-verbose --passphrase-fd 3 -u "%{_gpg_name}" -so -
-14: __gpg_sign_cmd	%{__gpg} 
	gpg --batch --no-verbose --no-armor --passphrase-fd 3 
	%{?_gpg_digest_algo:--digest-algo %{_gpg_digest_algo}} 
	-u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}
-14: _tmppath	%{_var}/tmp

GPGの署名も有効であることが確認できる。

$ rpm --checksig motd-1.0-1.amzn2.noarch.rpm 
motd-1.0-1.amzn2.noarch.rpm: RSA sha1 ((MD5) PGP) md5 NOT OK (MISSING KEYS: (MD5) PGP#699ac5f0) 

以下でも署名が有効であることが確認できる。

$ rpm -q --qf '%{SIGPGP:pgpsig} %{SIGGPG:pgpsig}\n' -p motd-1.0-1.amzn2.noarch.rpm 
RSA/SHA1, Thu Dec  2 13:23:22 2021, Key ID c76aabff28c0b322 (none)

Signatureも付加されている。

$ rpm -qpi motd-1.0-1.amzn2.noarch.rpm 
Name        : motd
Version     : 1.0
Release     : 1.amzn2
Architecture: noarch
Install Date: (not installed)
Group       : Unspecified
Size        : 23
License     : Test License
Signature   : (none)
Source RPM  : motd-1.0-1.amzn2.src.rpm
Build Date  : Thu Dec  2 09:30:17 2021
Build Host  : ip-172-31-10-148.us-west-2.compute.internal
Relocations : (not relocatable)
Summary     : Test Summary
Description :
This is my custom MOTD config

.gnupg/以下には以下のようなファイルが生成されている。

$ ls ~/.gnupg/
gpg-agent.conf  gpg.conf  openpgp-revocs.d  private-keys-v1.d  pubring.gpg  pubring.gpg~  secring.gpg  sshcontrol  trustdb.gpg

カスタムマクロファイル

GPGの設定を先程は、デフォルト設定で署名したが、設定した値で署名する。

そのためにカスタムマクロファイルを作成。custom_rpm.macrosという名前で以下のファイルを作成

%__gpg  /usr/bin/gpg
%_signature     gpg
%_gpg_name      Sample1
%__gpg_check_password_cmd       /bin/true
%__gpg_sign_cmd %{__gpg} --batch --no-verbose --use-agent --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}
%_tmppath       /tmp/

以下のように実行

$ rpm --macros=custom_rpm.macros -vvv --addsign motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
motd-1.0-1.amzn2.noarch.rpm:
D: Expected size:         2092 = lead(96)+sigs(180)+pad(4)+data(1812)
D:   Actual size:         2092
D: GPG sig size: 461
D: Got 461 bytes of GPG sig
D: GPG sig size: 461
D: Got 461 bytes of GPG sig
D: Signature: size(1136)+pad(0)

署名されていることが確認できる。

$ rpm -qpi motd-1.0-1.amzn2.noarch.rpm
warning: motd-1.0-1.amzn2.noarch.rpm: Header V4 RSA/SHA256 Signature, key ID 699ac5f0: NOKEY
Name        : motd
Version     : 1.0
Release     : 1.amzn2
Architecture: noarch
Install Date: (not installed)
Group       : Unspecified
Size        : 23
License     : Test License
Signature   : RSA/SHA256, Sat Dec 18 12:35:36 2021, Key ID 44b04c2e699ac5f0
Source RPM  : motd-1.0-1.amzn2.src.rpm
Build Date  : Thu Dec  2 09:30:17 2021
Build Host  : ip-172-31-10-148.us-west-2.compute.internal
Relocations : (not relocatable)
Summary     : Test Summary
Description :
This is my custom MOTD config

鍵に対する署名

前述の通り、GPGではWeb of Trustの仕組みを利用します。公開鍵への署名は、公開鍵のフィンガープリントを--sign-keyオプションで指定します。その後、その情報を共有するため、公開鍵の鍵IDまたはフィンガープリントを--send-keysオプションで指定して、鍵サーバーに送ります。

公開鍵(自身のを含む)の署名情報を更新するために、--refresh-keysを実行する必要がある。

GPGキーの削除

作成したGPGキーを削除する方法は以下。秘密鍵を削除してから公開鍵を削除する。

秘密鍵:

$ gpg --list-secret-keys
$ gpg --delete-secret-keys Sample1

公開鍵:

$ gpg --list-key
$ gpg --delete-keys Sample1

生成したGPGキーをエクスポートして、RPMにインポートすることもできる。

$ gpg --export -a 'RPM Build Test User' > RPM-GPG-KEY-pbuild-test-user
$ cat RPM-GPG-KEY-pbuild-test-user 
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)

mQENBGGos5QBCACzm3O593jFSpggkvCProHcyYaiRwQOV/wuGjalaCSIkWZ3KXpK
oHmOJNoQEiYjtHYRKqUzVCthk9m78ASfTki8t+TL0uUf0lot5TI43AT6XAOcZBgr
Mz7Fa4ef6JZWaYqv6iUMHafS/Uk98ReEHPhrb4wJn2/QOrKvn7re7KMmHlZ1WFdM
rx/SNbw/3CRtZhL+cPCCRA1EMu74dCY+4FrfFvh/AQ8R/JBSLOYaPnbfjZYNondf
lcfZ+nBe6KzxbQWXwohW/SxDxSHaDPPwho63HLhT6pwLj7bsqR9F+dl1GqXV7GQX
6gxVbJNLF+1h3PzqBtZaB5a/USfTG/qipxRtABEBAAG0TlJQTSBCdWlsZCBUZXN0
IFVzZXIgKFJQTSBCdWlsZGVyIFRlc3QgR1BHIFNpZ25pbmcgS2V5KSA8aGF5c2hv
Z29AYW1hem9uLmNvLmpwPokBOQQTAQIAIwUCYaizlAIbAwcLCQgHAwIBBhUIAgkK
CwQWAgMBAh4BAheAAAoJEMdqq/8owLMilEkIAJ9CwXvTgnLFQmhelPRAu2QOj5hj
EqphwGlnedCM5wd8iSGmP7cJ8FlcFsShYCQRemG5+9HKjGXLrpbWssgSeFxHYHy5
eRgHMAllO8G+S3TTFFOGlsMX54mSK+P3Ydyn9XnZLxQFmRppWeRfnaRDQrSV4bFI
+cAMwJ/YK5s+TM3IB5Fmt05G89TfQrXPDnDotPJy4TN0Ma2RVtXOCRiOZ25KJeXH
vlhT5FEDSuT34G89LbBdYHA71mwStqI5YnX3/weNEy7f6R+sjVeCTLIKfV7c9HiH
1Cmromjxq/cuhgaRVbjt2UWD/xjmLtzQxgMXqR24SWcj853oxMOzY6MsUEK5AQ0E
YaizlAEIANUEqn9uGKE2qb3IfC6wEOLaPbn/T3KxQIemjzH3t2bZRp9NGK5Fv4y8
FBHQ5OnLUtY+PegW7AMbfWYC5llR8YsdxbkDNexYYXUkYitzRVNGZIh47DZ5Hg3F
DSZILkpwG14tcaCuawFTgHyMTPonHeqlTs0Yyf3s+WHJyr3UrBMtNDz7GGbnmeah
qbWgVQ2f0DdIDCyKEgfKyB4CwjEdQFQz0vGBcBixAucp8UKQm5f8pRFMqvNtPHne
N9lMqR0Hnj7I1GyYoaGLtBIdizxQuiHPOTDG3Dvg0V3sCtdp99AxdIVxB2+j6L48
UlOAY3J1VT6f/qqH6R+xROsnfSX5X30AEQEAAYkBHwQYAQIACQUCYaizlAIbDAAK
CRDHaqv/KMCzIjoBB/9HTKBIprdog3UwARrRJTGpumjE/4JSY8lPss4Q73jAO+n8
7kqeg7LyFxneuPpYnPVu6LHrQ+JoPQb9myM3zLXJbzjAyF+1/HpeQaM5L/WzJJ6K
VTVVaYTBdtmFr/z/DjVJJUcCUJDQBqMsO+SdpTN8oJ3/1wa/DQpodZD3WlhPkce4
Xtw49GRnw3iFFohrZlD+xSO6GzFQy54FB9iUdJBb98UXxX8OBeaSgLgo6B89Hler
7/1etMCwBbRiwVY++q5RyN467pz/ZxE/qBmKgKNaEiUuM0jS5iYtlxJXd9BEdnY6
nrOISjiGFn1zYKxEmVDKvnZCk3QuB2OvTteAzLys
=CaiQ
-----END PGP PUBLIC KEY BLOCK-----
$ sudo rpm --import RPM-GPG-KEY-pbuild-test-user 

RPMレポジトリのGPGキーを除去する方法は以下。

$ rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n'
gpg-pubkey-c87f5b1a-593863f8	gpg(Amazon Linux <amazon-linux@amazon.com>)
gpg-pubkey-28c0b322-61a8b394	gpg(RPM Build Test User (RPM Builder Test GPG Signing Key) <hayashier@example.com>)
gpg-pubkey-77392555-61a8ccf4	gpg(RPM Build Test User 2 (RPM Signing Key Test 2) <hayashier@example.com>)
gpg-pubkey-61dcf3cd-61a8d830	gpg(Test1 (Test1 Comment) <hayashier@example.com>)
gpg-pubkey-54c79201-61adc686	gpg(Test2 (Test2 comment) <hayashier@example.com>)
$ sudo rpm -e gpg-pubkey-54c79201-61adc686
rpm --import or gpg --import

利用しているパッケージ管理次第では、両方必要であったり、どちらも使用しなくてもインストールの過程で必要に応じて鍵をインポートするといったこともある。 相互に作用したり、片方しかなければ独立したような動作になることもある。

秘密鍵のエクスポート

2.2.33では以下。

$ keyid=$(gpg --list-secret-keys | gpg --list-secret-keys | grep -B 1 "SampleGpg1" | grep -v uid | sed -e 's/[[:blank:]]//g' | tail -n 1) && echo $keyid
$ gpg --export-secret-keys --armor --output gpg-samplegpg1-secret $keyid
$ cat gpg-samplegpg1-secret
-----BEGIN PGP PRIVATE KEY BLOCK-----
:

2.0.22では以下。

$ keyid=$(gpg --list-secret-keys | gpg --list-secret-keys | grep -B 1 "Sample1" | grep sec | awk '{print $2}' | sed -e 's/.*\///' | tail -n 1)
$ gpg --export-secret-keys --armor --output gpg-private-sample1 $keyid
$ cat gpg-private-sample1 
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v2.0.22 (GNU/Linux)
:

gpg --list-secret-keysを2回繰り返しているのは初回実行時に以下のようにgpgからのメッセージが出てしまうため。

$ keyid=$(gpg --list-secret-keys | grep -B 1 "SampleGpg1" | grep -v uid | sed -e 's/[[:blank:]]//g' | tail -n 1) && echo $keyid
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2023-12-16
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
$ keyid=$(gpg --list-secret-keys | grep -B 1 "SampleGpg1" | grep -v uid | sed -e 's/[[:blank:]]//g' | tail -n 1) && echo $keyid
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

オプション

man gpgの結果でいくつかオプションを記載。使用したオプションをいくつか抜粋。

       --batch

       --no-batch
              Use  batch  mode.   Never ask, do not allow interactive commands.  --no-batch disables this option.  Note that even with a filename given on the command
              line, gpg might still need to read from STDIN (in particular if gpg figures that the input is a detached signature and no data file has been specified).
              Thus if you do not want to feed data via STDIN, you should connect STDIN to `/dev/null'.
:
       --no-verbose
              Reset verbose level to 0.
:
       --no-secmem-warning
              Suppress the warning about "using insecure memory".
:
       --sign

       -s     Make  a  signature.  This command may be combined with --encrypt (for a signed and encrypted message), --symmetric (for a signed and symmetri-
              cally encrypted message), or --encrypt and --symmetric together (for a signed message that may be decrypted via a secret key or a passphrase).
              The key to be used for signing is chosen by default or can be set with the --local-user and --default-key options.
:
       --detach-sign

       -b     Make a detached signature.
:
       --armor

       -a     Create ASCII armored output.  The default is to create the binary OpenPGP format.


       --no-armor
              Assume the input data is not in ASCII armored format.
:
       --output file

       -o file
              Write output to file.
--sign / --clear-sign / --detach-sign の違い
  • -s(--sign)

    • ファイルへの署名
    • バイナリファイルが生成
  • --clear-sign

    • データを残したまま署名
    • ファイル上部に署名した元データが入っている
  • --detach-sign

    • 元のデータと署名ファイルを分離して生成
    • 署名の検証をユーザーに強制したくない場合等

適宜、以下のオプションも併用する形で活用すると良い。

公開鍵の共有方法

  1. 手作業で交換する方法
  2. 鍵サーバーを使って交換する方法

1つめについて、例えば、公開鍵を手作業で交換したものを以下のようにインポートできる。(公開鍵の例は https://gnupg.org/signature_key.html のものを使用)

$ cat << EOS > gnupg-signature-key.txt
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
eiInsGZ/+h5XYrpXTgA=
=4+Sn
-----END PGP PUBLIC KEY BLOCK-----
EOS
$ cat gnupg-signature-key.txt | gpg --import

2つめについては、以下のようにインポート。

$ gpg --keyserver keyserver.ubuntu.com --recv-key 5B80C5754298F0CB55D8ED6ABCEF7E294B092E28 6DAA6E64A76D2840571B4902528897B826403ADA AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD 02F38DFF731FF97CB039A1DA549E695E905BA208

鍵サーバーには種類があるので、好きなものを選べば良い。SKS Keyserver Network(hkp://keys.gnupg.net)がDeprecated。そのため、他のGPG鍵サーバーを利用すると良い。

  • keyserver.ubuntu.com
  • keys.openpgp.org
  • pgp.mit.edu

鍵サーバーがSPOFになる可能性があるが、鍵サーバープールを使用することで、鍵サーバーを集めることによって信頼性が保証される。 GPGの設定ファイル~/.gnupg/gpg.confのkeyserverに指定する。

$ ls -al ~/.gnupg/gpg.conf 
-rw------- 1 ec2-user ec2-user 7680 Dec 14 10:18 /home/ec2-user/.gnupg/gpg.conf

<!--

利用例

たとえば、MySQLではGPGを利用したインストール方法について、以下のように案内されています。

Operator SDKでは、以下のように案内されています。

Topics

GPGに関連するいくつかの話題について触れていきます。

Yumレポジトリの作成

自前でYumレポジトリを作成します。このとき、レポジトリで管理するRPMにGPG鍵で署名しておきます。

最初に、Yumレポジトリを作成する上でオプションの作業ですが、GPG鍵に秘密鍵で署名しておきます。gpg --export -a 'Test1'コマンドで公開鍵をエクスポートしたものは後ほど使用するので、控えておきます。

$ sudo su
# gpg --gen-key
# gpg --export -a 'Test1'
# rpm --define "_gpg_name Test1" --addsign test-1.0-1.amzn2.noarch.rpm

Webサーバーを用意し、そこにRPMパッケージを配置します。ここでは、Apacheを使用します。作成したディレクトリ直下(/var/www/rpmrepo/x86_64/rpmtest)に目的のrpmファイル(ここでは、motd-1.0-1.amzn2.noarch.rpm)を配置します。

# yum install httpd -y
# mkdir -p /var/www/rpmrepo/x86_64/rpmtest
# cp test-1.0-1.amzn2.noarch.rpm /var/www/rpmrepo/x86_64/rpmtest/

Apacheの設定ファイルを変更します。

# vim /etc/httpd/conf/httpd.conf 
# Before
DocumentRoot "/var/www/html/"
# After
DocumentRoot "/var/www/"

設定を読み込みます。

# systemctl start httpd

Yumレポジトリを作成していきます。createrepo_cパッケージをインストールします(createrepoはobsoleted)。

# yum install createrepo_c -y

実際にレポジトリを作成します。レポジトリ内のファイルを更新した場合は、--updateオプションを付与してコマンドを実行します。アーキテクチャ毎にディレクトリを作成する場合は、それごとにcreaterepoコマンドを実行する。

# createrepo -s sha256 /var/www/rpmrepo/x86_64/

するとrepodataというディレクトリとその配下にメタデータが作成され、ここにrepomd.xmlも作成されます。 treeコマンドでディレクトリを確認すると以下のようになっています(インストールしていない場合は、yum install tree -yでインストール可能)。

# tree /var/www/rpmrepo/x86_64/
/var/www/rpmrepo/x86_64/
|-- test-1.0-1.amzn2.noarch.rpm
`-- repodata
    |-- 5218112b0b159a0b1615532dcf7ceb47cb7900c06dcd0a310656ba1dcc7f2d13-other.sqlite.bz2
    |-- 5f4df02d743c67fff2afb7b461e74b15385ede8bd07fecdc3b7db3c8043daddd-filelists.xml.gz
    |-- c3feb12f3bc05bde1ca443b3a18f647e14de7c16bc7c783e4e8a60730f00d501-filelists.sqlite.bz2
    |-- c6a899f41d7332e7f99051b077db4a44846b06701fc8ff9746b68b371fcc3a4f-other.xml.gz
    |-- cb4369dfa7ba3084f8d4f30c87a5efbfc707f35dd11aa33ace0d6cff9650e807-primary.sqlite.bz2
    |-- e3f815c84b54ede3784f167d6e766069da11ec894bc32a06b45e5c6ba7d206ba-primary.xml.gz
    `-- repomd.xml

1 directory, 8 files

repomd.xmlには以下のようなファイルが作成されています。

<?xml version="1.0" encoding="UTF-8"?>
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
  <revision>1639883424</revision>
  <data type="primary">
    <checksum type="sha256">5458165e4c403030f018772e8b94a21424e93ebf288407f52724fffb14a5b287</checksum>
    <open-checksum type="sha256">bacebcaba37b934ae4a352b61215b772d8f37a666af9222f6e7070676d40432d</open-checksum>
    <location href="repodata/5458165e4c403030f018772e8b94a21424e93ebf288407f52724fffb14a5b287-primary.xml.gz"/>
    <timestamp>1639883424</timestamp>
    <size>613</size>
    <open-size>1147</open-size>
  </data>
  <data type="filelists">
    <checksum type="sha256">51fe632fa208c2802f7ef36252de47e0ee0a4ce026579b9c72a6c3260ad5aafd</checksum>
    <open-checksum type="sha256">4498a658d030875ed6a3159796f8d3836fb7dce669bcae079cb259dafc19da0a</open-checksum>
    <location href="repodata/51fe632fa208c2802f7ef36252de47e0ee0a4ce026579b9c72a6c3260ad5aafd-filelists.xml.gz"/>
    <timestamp>1639883424</timestamp>
    <size>240</size>
    <open-size>317</open-size>
  </data>
  <data type="other">
    <checksum type="sha256">3823765b2701bd593d2cbef41e58f0973943b5e6d1d79d4355735b7a51238a8b</checksum>
    <open-checksum type="sha256">30e16f56d09457bd1265643d565d6a137a20da202a5ee5a93214d1b9e27fca19</open-checksum>
    <location href="repodata/3823765b2701bd593d2cbef41e58f0973943b5e6d1d79d4355735b7a51238a8b-other.xml.gz"/>
    <timestamp>1639883424</timestamp>
    <size>227</size>
    <open-size>288</open-size>
  </data>
  <data type="primary_db">
    <checksum type="sha256">5f86a71d7d89901a4c4507d0cd55182bfc480d90e88952954be81414edd2b7e0</checksum>
    <open-checksum type="sha256">840eeabedc1816e13e369bc0324b3fe8eeb85558347718a338d619b409feb2d1</open-checksum>
    <location href="repodata/5f86a71d7d89901a4c4507d0cd55182bfc480d90e88952954be81414edd2b7e0-primary.sqlite.bz2"/>
    <timestamp>1639883424</timestamp>
    <size>1825</size>
    <open-size>30720</open-size>
    <database_version>10</database_version>
  </data>
  <data type="filelists_db">
    <checksum type="sha256">3361c1db37aef3cdc8414abfa46e8d1c70aefd2e16510a7cb65f9ea14b18564e</checksum>
    <open-checksum type="sha256">86ac4a9fa98bcba332e686aa08ed82ae0e49db04b137ee1fe9c244e1a70e654c</open-checksum>
    <location href="repodata/3361c1db37aef3cdc8414abfa46e8d1c70aefd2e16510a7cb65f9ea14b18564e-filelists.sqlite.bz2"/>
    <timestamp>1639883424</timestamp>
    <size>712</size>
    <open-size>7168</open-size>
    <database_version>10</database_version>
  </data>
  <data type="other_db">
    <checksum type="sha256">5c39d881720de15448f0fdbeb96acb51156d9d609bea7c78d0c1bc720b20f4cf</checksum>
    <open-checksum type="sha256">8727f6561e1621f2d95685e3ddf60e8b1b607aabe6d82d86e0a68913a4fbea6d</open-checksum>
    <location href="repodata/5c39d881720de15448f0fdbeb96acb51156d9d609bea7c78d0c1bc720b20f4cf-other.sqlite.bz2"/>
    <timestamp>1639883424</timestamp>
    <size>659</size>
    <open-size>6144</open-size>
    <database_version>10</database_version>
  </data>
</repomd>

クライアント側でレポジトリの設定をします。

$ sudo vim /etc/yum.repos.d/rpmtest.repo
[rpmtest]
name=Sample RPM package
baseurl=http://34.209.96.87/rpmrepo/x86_64

gpg --export -a 'Test1'で出力したファイルを例えば、RPM-GPG-KEY-pbuild-sample1といったファイル名で作成し、これに貼り付けます。その後、RPMに読み込みます。

$ sudo rpm --import RPM-GPG-KEY-pbuild-sample1

キャッシュをクリアします。

$ sudo yum clean all

レポジトリが追加されていることが確認できます。

$ yum repolist
Failed to set locale, defaulting to C
Loaded plugins: extras_suggestions, kernel-livepatch, langpacks, priorities, update-motd
repo id                                                                          repo name                                                                           status
!amzn2-core/2/x86_64                                                             Amazon Linux 2 core repository                                                      26926
amzn2extra-docker/2/x86_64                                                       Amazon Extras repo for docker                                                          55
amzn2extra-kernel-5.10/2/x86_64                                                  Amazon Extras repo for kernel-5.10                                                     95
amzn2extra-livepatch/2/x86_64                                                    Amazon Extras repo for livepatch                                                       72
rpmtest                                                                          Sample RPM package                                                                      1
repolist: 27149

レポジトリ情報が確認できるようになります。

$ sudo yum info --disablerepo=* --enablerepo=rpmtest test
Failed to set locale, defaulting to C
Loaded plugins: copr, extras_suggestions, kernel-livepatch, langpacks, priorities, update-motd
Available Packages
Name        : test
Arch        : noarch
Version     : 1.0
Release     : 1.amzn2
Size        : 2.0 k
Repo        : rpmtest
Summary     : Test Summary
License     : Test License
Description : This is my custom TEST config

以下のようにインストールできるようになります。

$ sudo yum install --disablerepo=* --enablerepo=rpmtest test

GPG鍵でRPMに署名していない場合は、以下のようにインストールが中断して、実行できません。その場合、署名するか、gpgcheck=0オプションを先程のrepoファイルに追加する必要があります。

$ sudo yum install --disablerepo=* --enablerepo=rpmtest test
Failed to set locale, defaulting to C
Loaded plugins: copr, extras_suggestions, kernel-livepatch, langpacks, priorities, update-motd
Resolving Dependencies
--> Running transaction check
---> Package test.noarch 0:1.0-1.amzn2 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===========================================================================================================================================================================
 Package                               Arch                                    Version                                      Repository                                Size
===========================================================================================================================================================================
Installing:
 test                                  noarch                                  1.0-1.amzn2                                  rpmtest                                  2.0 k

Transaction Summary
===========================================================================================================================================================================
Install  1 Package

Total download size: 2.0 k
Installed size: 23  
Is this ok [y/d/N]: y
Downloading packages:
Package test-1.0-1.amzn2.noarch.rpm is not signed
test-1.0-1.amzn2.noarch.rpm                                                                                                                         | 2.0 kB  00:00:00     


Package test-1.0-1.amzn2.noarch.rpm is not signed

<!--

既に別パッケージによって管理されているファイルについては、衝突してYumではインストールできない。

$ sudo yum install --disablerepo=* --enablerepo=rpmtest motd : Running transaction test

Transaction check error: file /etc/motd from install of motd-1.0-1.amzn2.noarch conflicts with file from package setup-2.8.71-10.amzn2.0.1.noarch

Error Summary

$ rpm -qf /etc/motd
setup-2.8.71-10.amzn2.0.1.noarch

-->

署名処理の自動化

  1. GPG Agent + Preset phraseの利用(後述)
  2. expectコマンドと--passphrase-fdオプションを利用してパスワード入力する方法

2つめについて、例えば、以下のコマンドを実行する。

#!/bin/bash

file=~/list.txt
pass_phrase=Test1234
key_file=/home/ec2-user/gpg-private-sample1
fingerprint=ffad0f14
RPM_SIGN_MAX_ATTEMPTS=3

sudo yum install expect -y

for rpm_file in `cat $file`
do
    echo "Checking: $rpm_file"
    package_fig=$(rpm -qp $rpm_file --qf "%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{none}| %{NVRA}\n" | grep "Key ID" | awk '{print substr($9,0,8)}')
    if [[ $package_fig =~ $fingerprint ]]; then
        echo "RPM is already signed, no need to resign."
    else
        for ((i=0; i<$RPM_SIGN_MAX_ATTEMPTS; i++)); do
            gpg --import $key_file
            expect -c '
                set timeout -1
                spawn rpm --define "__gpg /usr/bin/gpg" --define "_gpg_name Sample1" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch --passphrase-fd 3 --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}"  --addsign '"$rpm_file"'
                expect "Enter pass phrase:"
                send "'"$pass_phrase\n"'"
                expect "Pass phrase is good."
                expect eof
                catch wait result
                exit [lindex $result 3]
                ' 3<&0

            package_fig=$(rpm -qp $rpm_file --qf "%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{none}| %{NVRA}\n" | grep "Key ID" | awk '{print substr($9,0,8)}')
            if [[ $package_fig =~ $fingerprint ]]; then
                continue 2
            fi
         done

         exit 1
    fi
done

gpg-agent

  • gpg-agentは GnuPGの中核コンポーネントで,秘密鍵の管理を行い一定期間キャッシュ

  • gpg、gpgconf、gpg-connect-agentなどのコンポーネントから起動し、互いに通信起

  • Pinentry

    • PinentryはパスフレーズやスマートカードのPINコードを入力する際にgpg-agentから呼び出し
    • gpgに--batch--pinentry-mode loopbackオプションとパスフレーズ指定オプション(--passphrase, --passphrase-fd, --passphrase-file)をセットで指定している場合はPinentryを迂回する方法もある。
  • GnuPG 2.1.0からgpg-agentとpinentryの利用が必須

    • これによって--passphrase-fd 0コマンドラインオプションによって STDIN からパイプで渡されたパスフレーズの後方互換性が損ねられています。
    • 古いリリースと同じような機能を使うには2つのことをする必要があります:
      • loopback pinentry モードの許可
        • ``~/.gnupg/gpg-agent.confallow-loopback-pinentry`を追加し、設定ファイルの読み込み。
      • gpgコマンドをloopbackモードで使用。以下2通りの方法。
        • gpgコマンドの--pinentry-mode loopbackオプション
          $ gpg --pinentry-mode loopback ...
          
        • ~/.gnupg/gpg.confpinentry-mode loopbackを追加

実際に動作を検証。

~/.gnupg/gpg-agent.confに以下のようなファイルを作成し、適宜設定を事前に読み込んでおく。

pinentry-program /usr/bin/pinentry-curses
allow-preset-passphrase
$ /usr/local/bin/gpgconf --reload gpg-agent

以下のように実行。KeygripはOpenPGP鍵以外の鍵にも対応するためのもの。

$ /usr/local/bin/gpg-agent --daemon --allow-preset-passphrase --no-detach --log-file gpg_agent_log_file --debug-level guru
$ GPG_KEYGRIP=$(/usr/local/bin/gpg --with-keygrip --list-key | grep Sample1 -B 2 | grep Keygrip | awk -F = '{print $2}' | sed -e 's/[[:blank:]]//g' | tail -n 1) && echo $GPG_KEYGRIP
$ GPG_PASSPHRASE_HEX=$(echo Test1234 | tr -d '\n' | hexdump -v -e '/1 "%02X"') && echo $GPG_PASSPHRASE_HEX
$ GPG_AGENT_SOCKET=$(gpgconf --list-dirs | grep agent-socket | sed -e 's/.*://g') && echo $GPG_AGENT_SOCKET
$ echo "PRESET_PASSPHRASE $GPG_KEYGRIP -1 $GPG_PASSPHRASE_HEX" | /usr/local/bin/gpg-connect-agent -S $GPG_AGENT_SOCKET
$ gpg-connect-agent reloadagent /bye

以下のように実行すると、特にパスワードを要求されることなく、署名ができる。

$ rpm_file=./motd-1.0-1.amzn2.noarch.rpm
$ rpm --define "__gpg  /usr/local/bin/gpg" --define "_gpg_name Sample1" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch -vv --no-secmem-warning --sign --detach-sign --no-armor -u %{_gpg_name} --output %{__signature_filename} %{__plaintext_filename}" --addsign $rpm_file

gpg-agentをssh-agentとして使用

  • gpg-agentがSSH-agentとしても機能するようにする。
    • ~/.gnupg/gpg-agent.confenable-ssh-supportを追加。

GPG最新バージョンをインストール

CentOSやUbuntuでレポジトリからGPGをインストールしてきても、最新は2.3.3。LTSで2.2.33(?)だが、2.0.22と古い。

#!/bin/bash
# Script to build and install GnuPG 2.2.33 for Amazon Linux 2 and MacOS
# Link: https://gnupg.org/download/
# Run:
# $ export PATH=/usr/local/bin/:$PATH
# $ chmod +x install-gpg22.sh
# $ sudo ./install-gpg22.sh

set -euvx -o pipefail
trap 'echo "ERROR: line no = $LINENO, exit status = $?" >&2; exit 1' ERR

GNUPG_VERSION=2.2.33

LIBGPG_ERROR_VERSION=1.43
LIBGCRYPT_VERSION=1.9.4
LIBKSBA_VERSION=1.6.0
LIBASSUAN_VERSION=2.5.5
NPTH_VERSION=1.6
NTBTLS_VERSION=0.2.0

WORKSPACE_DIR=/tmp/gnupg
ROOT_DIR=/usr/local
LIBRARY_DIR=$ROOT_DIR/lib
INSTALL_DIR=/usr/local/bin/

if [[ "$(uname -r)" == *amzn2* ]]; then
    yum install gcc rpm-sign sqlite-devel gnutls-devel -y
fi

mkdir -p $WORKSPACE_DIR && cd $WORKSPACE_DIR || exit 1

# Verifying downloads.
# Actually, We should import GPG key by running the following command.
#
#     $ gpg --keyserver keyserver.ubuntu.com --recv-key 5B80C5754298F0CB55D8ED6ABCEF7E294B092E28 6DAA6E64A76D2840571B4902528897B826403ADA AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD 02F38DFF731FF97CB039A1DA549E695E905BA208
#
# For example, we want to verify by using imported keys as follows.
#
#     $ gpg -d libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2.sig
#
# However, the version of GPG key is old (like, 2.0.x). So gpg process causes `gpg: Can't check signature: Invalid public key algorithm` error because this version does not support EDDSA as follows.
#
#     $ gpg --version
#     gpg (GnuPG) 2.0.22
#     libgcrypt 1.5.3
#     Copyright (C) 2013 Free Software Foundation, Inc.
#     License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
#     This is free software: you are free to change and redistribute it.
#     There is NO WARRANTY, to the extent permitted by law.
# 
#     Home: ~/.gnupg
#     Supported algorithms:
#     Pubkey: RSA, ?, ?, ELG, DSA
#     Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
#             CAMELLIA128, CAMELLIA192, CAMELLIA256
#     Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
#     Compression: Uncompressed, ZIP, ZLIB, BZIP2
#
# That is why we check integrity by using SHA-1 check sums retrieved from this link https://gnupg.org/download/integrity_check.html as a workaround.

echo "First, Installing dependencies."
echo "Installing Libgpg-error..."
curl -L https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2 -O
if [[ $(sha1sum libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2) != "e71b77e8e32023dfd9cb06504942aa8e028c8795  libgpg-error-1.43.tar.bz2" ]] ; then
	exit 1
fi
tar xvf libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2
pushd libgpg-error-${LIBGPG_ERROR_VERSION} || exit 1
./configure --prefix=$ROOT_DIR
make
make install
popd

echo "Installing Libgcrypt..."
curl -L https://gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-${LIBGCRYPT_VERSION}.tar.bz2 -O
if [[ $(sha1sum libgcrypt-${LIBGCRYPT_VERSION}.tar.bz2) != "1bccc8393482fa1953323ff429c6b5ba5676eb1a  libgcrypt-1.9.4.tar.bz2" ]] ; then
	exit 1
fi
tar xvf libgcrypt-${LIBGCRYPT_VERSION}.tar.bz2
pushd libgcrypt-${LIBGCRYPT_VERSION} || exit 1
./configure --prefix=$ROOT_DIR --with-libgpg-error-prefix=$ROOT_DIR
make
make install
popd

echo "Installing Libassuan..."
curl -L https://gnupg.org/ftp/gcrypt/libassuan/libassuan-${LIBASSUAN_VERSION}.tar.bz2 -O
if [[ $(sha1sum libassuan-${LIBASSUAN_VERSION}.tar.bz2) != "ec4f67c0117ccd17007c748a392ded96dc1b1ae9  libassuan-2.5.5.tar.bz2" ]] ; then
	exit 1
fi
tar xvf libassuan-${LIBASSUAN_VERSION}.tar.bz2
pushd libassuan-${LIBASSUAN_VERSION} || exit 1
./configure --prefix=$ROOT_DIR --with-libgpg-error-prefix=$ROOT_DIR
make
make install
popd

echo "Installing Libksba..."
curl -L https://gnupg.org/ftp/gcrypt/libksba/libksba-${LIBKSBA_VERSION}.tar.bz2 -O
if [[ $(sha1sum libksba-${LIBKSBA_VERSION}.tar.bz2) != "d71e18a71b44d7f0e93180e05971857b4900c788  libksba-1.6.0.tar.bz2" ]] ; then
	exit 1
fi
tar xvf libksba-${LIBKSBA_VERSION}.tar.bz2
pushd libksba-${LIBKSBA_VERSION} || exit 1
./configure --prefix=$ROOT_DIR --with-libgpg-error-prefix=$ROOT_DIR
make
make install
popd

echo "Installing ntbTLS..."
curl -L https://gnupg.org/ftp/gcrypt/ntbtls/ntbtls-${NTBTLS_VERSION}.tar.bz2 -O
if [[ $(sha1sum ntbtls-${NTBTLS_VERSION}.tar.bz2) != "3bbd98e5cfff7ca7514ae600599f0e1c1f351566  ntbtls-0.2.0.tar.bz2" ]] ; then
	exit 1
fi
tar xvf ntbtls-${NTBTLS_VERSION}.tar.bz2
pushd ntbtls-${NTBTLS_VERSION} || exit 1
./configure --prefix=$ROOT_DIR --with-libgpg-error-prefix=$ROOT_DIR --with-libgcrypt-prefix=$ROOT_DIR  --with-ksba-prefix=$ROOT_DIR
make
make install
popd

echo "Installing nPth..."
curl -L https://gnupg.org/ftp/gcrypt/npth/npth-${NPTH_VERSION}.tar.bz2 -O
if [[ $(sha1sum npth-${NPTH_VERSION}.tar.bz2) != "f9d63e9747b027e4e404fe3c20c73c73719e1731  npth-1.6.tar.bz2" ]] ; then
	exit 1
fi
tar xvf npth-${NPTH_VERSION}.tar.bz2 
pushd npth-${NPTH_VERSION} || exit 1
./configure --prefix=$ROOT_DIR
make
make install
popd

echo "Installing GnuPG..."
curl -L https://gnupg.org/ftp/gcrypt/gnupg/gnupg-${GNUPG_VERSION}.tar.bz2 -O
if [[ $(sha1sum gnupg-${GNUPG_VERSION}.tar.bz2) != "70053b799a79139e0e7889282805fc889dd22540  gnupg-2.2.33.tar.bz2" ]] ; then
	exit 1
fi
tar xvf gnupg-${GNUPG_VERSION}.tar.bz2 
pushd gnupg-${GNUPG_VERSION} || exit 1
./configure --prefix=$ROOT_DIR --with-libgpg-error-prefix=$ROOT_DIR --with-libgcrypt-prefix=$ROOT_DIR --with-libassuan-prefix=$ROOT_DIR --with-ksba-prefix=$ROOT_DIR --with-npth-prefix=$ROOT_DIR --with-ntbtls-prefix=$ROOT_DIR
make
make install
popd

if [[ "$(uname -r)" == *amzn2* ]]; then
    echo $LIBRARY_DIR | tee /etc/ld.so.conf.d/gpg2.conf && ldconfig -v
fi

cp ./gnupg-2.2.33/g10/gpg $INSTALL_DIR
cp ./gnupg-2.2.33/agent/gpg-agent $INSTALL_DIR
cp ./gnupg-2.2.33/tools/gpgconf $INSTALL_DIR
cp ./gnupg-2.2.33/tools/gpg-connect-agent $INSTALL_DIR

echo "Successfully built and installed GnuPG ${GNUPG_VERSION} to $INSTALL_DIR"

echo "Dependencies under /usr/local are as follows"
ls $LIBRARY_DIR | egrep 'libgpg-error|libgcrypt|libksba|libassuan|ntbtls|npth|gnupg'
rm -Rf $WORKSPACE_DIR

GPG_AGENT_ROOT=$HOME/.gnupg
GPG_AGENT_CONF=$GPG_AGENT_ROOT/gpg-agent.conf

if [ ! -e $GPG_AGENT_CONF ]; then
	mkdir $GPG_AGENT_ROOT
	touch $GPG_AGENT_CONF
fi

set +euvx
trap - ERR

echo "Configuring GPG Agent..."
grep pinentry-program $GPG_AGENT_CONF
if [[ $? -eq 1 ]]; then
    echo "pinentry-program /usr/bin/pinentry-curses" >> $GPG_AGENT_CONF
fi

grep allow-preset-passphrase $GPG_AGENT_CONF
if [[ $? -eq 1 ]]; then
    echo "allow-preset-passphrase" >> $GPG_AGENT_CONF
fi
/usr/local/bin/gpgconf --reload gpg-agent

echo "Showing Version..."
/usr/local/bin/gpg --version
/usr/local/bin/gpg-agent --version
/usr/local/bin/gpg-connect-agent --version
/usr/local/bin/gpgconf --version

echo "Done!"

exit 0

Errors

以下、検証時に遭遇したエラーと対処法のまとめを記録。

rpm: /usr/bin/rpmsign: No such file or directory

以下のコマンドを実行したところエラー

$ rpm --addsign motd-1.0-1.amzn2.noarch.rpm
rpm: /usr/bin/rpmsign: No such file or directory

--addsignオプションを使用するためには別途rpm-signライブラリをインストールする必要がある。

$ sudo yum install rpm-sign -y

You must set "%_gpg_name" in your macro file

以下のコマンドを実行したところエラー

$ rpm --addsign motd-1.0-1.amzn2.noarch.rpm
You must set "%_gpg_name" in your macro file

以下のように実行すればOK。

$ rpm --define "_gpg_name Sample1" --addsign motd-1.0-1.amzn2.noarch.rpm

もしくは、.rpmmacrosに%_gpg_nameを定義する形でも良い。

$ echo "%_gpg_name RPM Build Test User" >> ~/.rpmmacros
$ /bin/rpm -vvv --addsign motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
motd-1.0-1.amzn2.noarch.rpm:
D: Expected size:         2092 = lead(96)+sigs(180)+pad(4)+data(1812)
D:   Actual size:         2092
D: GPG sig size: 287
D: Got 287 bytes of GPG sig
D: GPG sig size: 287
D: Got 287 bytes of GPG sig
D: Signature: size(784)+pad(0)
[ec2-user@ip-172-31-10-148 ~]$ /bin/rpm -vvv --addsign motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
motd-1.0-1.amzn2.noarch.rpm:
D: Expected size:         2692 = lead(96)+sigs(784)+pad(0)+data(1812)
D:   Actual size:         2692
D: GPG sig size: 287
D: Got 287 bytes of GPG sig
D: GPG sig size: 287
D: Got 287 bytes of GPG sig
warning: motd-1.0-1.amzn2.noarch.rpm already contains identical signature, skipping

error: rpmMkTemp failed

sudoをつければエラー解消

$ /bin/rpm --macros=custom_rpm.macros -vvv --addsign motd-1.0-1.amzn2.noarch.rpm
:
error: error creating temporary file /tmp/rpmtest/rpm-tmp.Uz4bQN: Permission denied
error: rpmMkTemp failed

gpg: packet(3) with unknown version 0

もともとのカスタムマクロは以下だった。

%__gpg  /usr/bin/gpg
%_signature     gpg
%_gpg_name      Test1
%__gpg_check_password_cmd       /bin/true
%__gpg_sign_cmd %{__gpg} --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}
%_tmppath       /tmp/

gpgコマンド実行時におけるオプション指定がそもそもだめだった。--signと--detach-signを添えてあげる必要があった。以下で問題を解消した。

%__gpg  /usr/bin/gpg
%_signature     gpg
%_gpg_name      Test1
%__gpg_check_password_cmd       /bin/true
%__gpg_sign_cmd %{__gpg} --batch --no-verbose --use-agent --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}
%_tmppath       /tmp/

上記原因を見つけるために、gpgコマンドで実際の動作確認をしてデバッグしていった。

その後、.rpmmacrosをゼロベースで作成しながら、raw RPM マクロ定義に値が反映されているかを確認しながら検証していった。

$ cat .rpmmacros 
%__gpg  /usr/local/bin/gpg
%_signature     gpg
%_gpg_name      Test1
%__gpg_check_password_cmd       true
%__gpg_sign_cmd %{__gpg} --no-armor -u '%{_gpg_name}' -sbo %{__signature_filename} %{__plaintext_filename}
%_tmppath       /tmp/

上記確認の都度、raw RPM マクロ定義に反映されていっているか確認をしていった。

$ rpm --showrc | egrep "gpg|signature|tmppath"
-13: __gpg	/usr/local/bin/gpg
-13: __gpg_check_password_cmd	true
-13: __gpg_reserved_space	4096
-13: __gpg_sign_cmd	%{__gpg} --no-armor -u '%{_gpg_name}' -sbo %{__signature_filename} %{__plaintext_filename}
-13: _gpg_name	Test1
-13: _signature	gpg
-13: _tmppath	/tmp/

その後、以下のようにファイル名を変更して、--macros=custom_rpm.macrosオプションを指定して実行できるようにした。

$ mv  ~/.macros custom_rpm.macros 

以下を用意し、デバッグをしやすいようにしておいた。

$ gpg --gen-key
$ gpg --export -a 'Sample1' > RPM-GPG-KEY-pbuild-sample1
$ cat RPM-GPG-KEY-pbuild-sample1
$ sudo rpm --import RPM-GPG-KEY-pbuild-test1
$ rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n'
$ rpm -qpi motd-1.0-1.amzn2.noarch.rpm 
$ rpm --macros=custom_rpm.macros -vvv --addsign motd-1.0-1.amzn2.noarch.rpm 

Pass phrase check failed or gpg key expired

rpm --addsignを実行したところ、以下のエラー。

$ rpm --define "_gpg_name Test1" --addsign motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
gpg: signing failed: Operation cancelled
gpg: signing failed: Operation cancelled
Pass phrase check failed or gpg key expired

ここでは、GnuPGの設定は不要であったため、一旦すべて削除することで解消

$ rm -Rf .gnupg/

__gpg_signで入力待ち

いずれの場合も必要な情報がrpmコマンドに適切に入力できていないために状況が発生していた。

Pattern 1

以下の状態だと、その外のfor文で読み込んでいたfor rpm_file in cat $filecat $fileがファイルディスクリプターのNo.0としてこれを読み込んでいた。

rpm --define \"__gpg /usr/bin/gpg\" --define \"_gpg_name Sample1\" --define \"%__gpg_check_password_cmd /bin/true\" --define \"%__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}\" --addsign $rpm_file

--passphrase-fdを指定しないと、cat $fileをstdinの情報として読み込み、入力待ち状態になってしまっていたことが原因。 そのため、これを実行していたexpect文の末尾に3<&0を追加し、標準入力を新しいファイル記述子に複製して、--passphrase-fd 3のようにファイルディスクリプターの番号を引数として指定した

rpm --define \"__gpg /usr/bin/gpg\" --define \"_gpg_name Sample1\" --define \"%__gpg_check_password_cmd /bin/true\" --define \"%__gpg_sign_cmd %{__gpg} gpg --batch --passphrase-fd 3 --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}\" --addsign $rpm_file 3<&0

Pattern 2

expectコマンド中で使用していたが、expect命令で指定していた一致するメッセージが来ないため、待機状態になっていた。

gpg: skipped "Sample1": No secret key

rpmコマンドで--addsignを実行したところ、以下のエラー。spawnはexpectコマンド中で使用しているため。

spawn rpm --define __gpg  %{_bindir}/gpg2 --define _gpg_name Sample1 --define %__gpg_check_password_cmd /bin/true --define %__gpg_sign_cmd %{__gpg} gpg --batch --passphrase-fd 3 --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u %{_gpg_name} --output %{__signature_filename} %{__plaintext_filename} --addsign /tmp/sample/motd-1.0-2.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
/tmp/sample/motd-1.0-2.amzn2.noarch.rpm:
gpg: skipped "Sample1": No secret key
gpg: signing failed: No secret key
error: gpg exec failed (2)

秘密鍵をインポートしていなかったことが原因。秘密鍵をインポートすれば解消。

error: Macro % has illegal name (%define)

いらない二重引用符をつけていた

18c20
<             spawn rpm --define \"__gpg  %{_bindir}/gpg2\" --define \"_gpg_name Sample1\" --define \"%__gpg_check_password_cmd /bin/true\" --define \"%__gpg_sign_cmd %{__gpg} gpg --batch --passphrase-fd 3 --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}\" --addsign '"$rpm_file"'
---
>             spawn rpm --define "__gpg  %{_bindir}/gpg2" --define "_gpg_name Sample1" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch --passphrase-fd 3 --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}" --addsign '"$rpm_file"'

warning: motd-1.0-1.amzn2.noarch.rpm: Header V4 RSA/SHA1 Signature, key ID ac73620c: NOKEY

パッケージをダウンロードしてrpmコマンドでインストールする場合、自動でGPG署名のチェックが行われるが、パッケージリリース元のGPG公開鍵がサーバに取り込まれていない場合以下のような警告が出る

$ rpm -qpi motd-1.0-1.amzn2.noarch.rpm      
warning: motd-1.0-1.amzn2.noarch.rpm: Header V4 RSA/SHA1 Signature, key ID ac73620c: NOKEY

正しく署名の確認を行うにはGPG公開鍵のインポートを行わなくてはならない rpm --import /Path/To/PublicKeyのようにインポートする。

gpg-agent: no gpg-agent running in this session

$ /usr/bin/gpg-agent --allow-preset-passphrase --no-detach --pinentry-program /bin/exit --write-env-file gpg_agent_info_env --log-file gpg_agent_log_file --debug-level guru
gpg-agent[14150]: enabled debug flags: command mpi crypto memory cache memstat hashing assuan
gpg-agent: no gpg-agent running in this session
gpg-agent: random usage: poolsize=600 mixed=0 polls=0/0 added=0/0
              outmix=0 getlvl1=0/0 getlvl2=0/0
gpg-agent: secmem usage: 0/32768 bytes in 0 blocks

--daemonをつけて起動する必要があった。

$ /usr/bin/gpg-agent --daemon --allow-preset-passphrase --no-detach --pinentry-program /bin/exit --write-env-file gpg_agent_info_env --log-file gpg_agent_log_file --debug-level guru
gpg-agent[14287]: enabled debug flags: command mpi crypto memory cache memstat hashing assuan

ERR 67108924 Not supported <GPG Agent> - no --allow-preset-passphrase

gpg-connect-agentコマンドでPRESET_PASSPHRASEでパスワードを事前登録しようとしたところ下記のエラー

$ gpg-connect-agent -S $GPG_AGENT_SOCKET
> PRESET_PASSPHRASE 3C877B122B7C71913E57CF63A07F4150AC73620C -1 5465737431323334
ERR 67108924 Not supported <GPG Agent> - no --allow-preset-passphrase
$ echo "PRESET_PASSPHRASE $GPG_FINGERPRINT -1 $GPG_PASSPHRASE_HEX" | gpg-connect-agent -S $GPG_AGENT_SOCKET
ERR 67108924 Not supported <GPG Agent> - no --allow-preset-passphrase

~/.gnupg/以下にgpg-agent.confという名前のファイルを作成し、allow-preset-passphraseの文字列を追記した上でGPG Agentの設定を読み込み直す必要があった。

$ echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
$ gpgconf --reload gpg-agent

gpg: Can't check signature: Invalid public key algorithm

Amazon Linux 2上だと、以下のエラー

$ gpg -d libgpg-error-1.43.tar.bz2.sig 
gpg: Signature made Wed Nov  3 14:03:23 2021 UTC using ? key ID 26403ADA
gpg: Can't check signature: Invalid public key algorithm
gpg: Signature made Wed Nov 24 01:07:32 2021 UTC using ? key ID 19C6C8BD
gpg: Can't check signature: Invalid public key algorithm

検証環境のバージョンは以下。

$ gpg --version
gpg (GnuPG) 2.0.22
libgcrypt 1.5.3
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, ?, ?, ELG, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

バージョンが古いことが原因だった。以下のようにバージョンを上げたところ、解消

$ gpg --version
gpg (GnuPG) 2.2.33
libgcrypt 1.8.8
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/ec2-user/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed
$ gpg -d libgpg-error-1.43.tar.bz2.sig 
gpg: assuming signed data in 'libgpg-error-1.43.tar.bz2'
gpg: Signature made Wed Nov  3 14:03:23 2021 UTC
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2023-12-14
gpg: Good signature from "Werner Koch (dist signing 2020)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 6DAA 6E64 A76D 2840 571B  4902 5288 97B8 2640 3ADA
gpg: Signature made Wed Nov 24 01:07:32 2021 UTC
gpg:                using EDDSA key AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD
gpg: Good signature from "Niibe Yutaka (GnuPG Release Key)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: AC8E 115B F73E 2D8D 47FA  9908 E98E 9B2D 19C6 C8BD

MacOS上だと、バージョンが2.2.33であるため、最初から正常に検証できる。

$ gpg -d libgpg-error-1.43.tar.bz2.sig 
gpg: assuming signed data in 'libgpg-error-1.43.tar.bz2'
gpg: Signature made 水 11/ 3 23:03:23 2021 JST
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: Good signature from "Werner Koch (dist signing 2020)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 6DAA 6E64 A76D 2840 571B  4902 5288 97B8 2640 3ADA
gpg: Signature made 水 11/24 10:07:32 2021 JST
gpg:                using EDDSA key AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD
gpg: Good signature from "Niibe Yutaka (GnuPG Release Key)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: AC8E 115B F73E 2D8D 47FA  9908 E98E 9B2D 19C6 C8BD
$ gpg --version
gpg (GnuPG) 2.2.33
libgcrypt 1.8.8
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /Users/hayashier/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

gpg: error while loading shared libraries: libgcrypt.so.20: cannot open shared object file: No such file or directory

Amazon Linux 2の環境で、GnuPGの最新版をインストールし、コマンドを実行しようとしたところ、以下のエラー。

$ gpg --version
gpg: error while loading shared libraries: libgcrypt.so.20: cannot open shared object file: No such file or directory

以下を実行する必要があった。ライブラリのインストール先をgpg2.confに指定して、ldconfigコマンドで読み込む。

echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/gpg2.conf && sudo ldconfig -v

gpg: agent_genkey failed: No pinentry

gpgをインストール後コマンドを実行すると以下のエラー

$ gpg --gen-key
gpg (GnuPG) 2.2.33; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: Sample1
Email address: hayashier@example.com
You selected this USER-ID:          
    "Sample1 <hayashier@example.com>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: agent_genkey failed: No pinentry
Key generation failed: No pinentry

gpg-agent.confに設定を追加して、gpg-agentの設定を読み込み直す必要があった。

echo "pinentry-program /usr/bin/pinentry-curses" >> ~/.gnupg/gpg-agent.conf
gpgconf --reload gpg-agent

gpg: key AAC5DE59A84FCD28/AAC5DE59A84FCD28: error sending to agent: Operation cancelled

gpg --importしたところ、操作が途中でキャンセルされている。秘密鍵のインポートがOperation cancelledと表示されている。

$ /usr/local/bin/gpg --import /tmp/gpg-secret-sample1
gpg: starting migration from earlier GnuPG versions
gpg: porting secret keys from '/root/.gnupg/secring.gpg' to gpg-agent
gpg: migration succeeded
gpg: key AAC5DE59A84FCD28: public key "Sample1 <hayashier@example.com>" imported
gpg: key AAC5DE59A84FCD28/AAC5DE59A84FCD28: error sending to agent: Operation cancelled
gpg: error reading '/tmp/gpg-secret-sample1': Operation cancelled
gpg: import from '/tmp/gpg-secret-sample1' failed: Operation cancelled
gpg: Total number processed: 0
gpg:               imported: 1
gpg:       secret keys read: 1

rpm --importでパスワード入力していないことが原因。パイプライン中ではインタラクティブなパスワード入力画面がないことに起因。ためしに、GPGの鍵生成時にパスワードを設定せずに実行したところ、以下のように正常に実行された。

$ /usr/local/bin/gpg --import /tmp/gpg-secret-sample-1
gpg: starting migration from earlier GnuPG versions
gpg: porting secret keys from '/root/.gnupg/secring.gpg' to gpg-agent
gpg: migration succeeded
gpg: key A711DC45371329D4: public key "Sample1 <hayashier@example.com>" imported
gpg: key A711DC45371329D4: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

パスワードが設定された状態でも、--batchオプションで解消した。

$ gpg --batch --import /tmp/gpg-secret-sample1
gpg: starting migration from earlier GnuPG versions
gpg: porting secret keys from '/root/.gnupg/secring.gpg' to gpg-agent
gpg: migration succeeded
gpg: key AAC5DE59A84FCD28: public key "Sample1 <hayashier@example.com>" imported
gpg: key AAC5DE59A84FCD28: secret key imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

rpm: /usr/bin/rpmsign: No such file or directory

rpmコマンドで--addsignオプションを付与して実行したところ、以下のエラー。

$ rpm --define "__gpg /usr/local/bin/gpg" --define "_gpg_name Sample1" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}" --addsign $rpm_file
rpm: /usr/bin/rpmsign: No such file or directory

rpm-signをインストールして解消。

$ sudo yum install rpm-sign -y

configure: error: libgpg-error is needed.

Amazon Linux 2で、rootユーザー環境で、libgpg-errorに依存する他のライブラリを./configureするときに、既にインストールされているにも関わらず、上記エラー。ec2-userだと問題なく、インストールできる。

ライブラリの場所を明示的に指定する必要があった。libgpg-error以外の他のライブラリも同様。./configure --helpでそれらしきオプションを探してくる。

./configure --prefix=/tmp/gpnug --with-libgpg-error-prefix=/tmp/gpnug

You need libksba to build this program.

ntbtlsをビルド時に以下のエラー

configure:
***
*** You need libksba to build this program.
*** This library is for example available at
***   ftp://ftp.gnupg.org/gcrypt/libksba/
*** (at least version 1.2.0 using API 1 is required).
***
configure: error: 
***
*** Required libraries not found. Please consult the above messages
*** and install them before running configure again.
***
make: *** No targets specified and no makefile found.  Stop.
make: *** No rule to make target `install'.  Stop.

--helpオプション上は--with-libksba-prefixとなっているが、--with-ksba-prefixが正しい。libksbaのバグ。

# ./configure --help | grep prefix
  --prefix=PREFIX         install architecture-independent files in PREFIX
  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
an installation prefix other than `/usr/local' using `--prefix',
for instance `--prefix=$HOME'.
  --program-prefix=PREFIX            prepend PREFIX to installed program names
  --with-libgpg-error-prefix=PFX
                          prefix where GPG Error is installed (optional)
  --with-libgcrypt-prefix=PFX
                          prefix where LIBGCRYPT is installed (optional)
  --with-libksba-prefix=PFX
                          prefix where KSBA is installed (optional)

No package 'gnutls' found

./configureを実行していたところ、上記エラー。gnutls-develをインストールする。

$ sudo yum install gnutls-devel -y

No package 'sqlite3' found

./configureを実行していたところ、上記エラー。sqlite-develをインストールする。

$ sudo yum install sqlite-devel -y

WARNING: server 'gpg-agent' is older than us (2.0.22 < 2.2.33)

# rpm --define "__gpg /usr/local/bin/gpg" --define "_gpg_name Sample1" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-secmem-warning --sign --detach-sign --no-armor -u '%{_gpg_name}' --output %{__signature_filename} %{__plaintext_filename}"  --addsign $rpm_file
Enter pass phrase: 
Pass phrase is good.
./motd-1.0-1.amzn2.noarch.rpm:
gpg: WARNING: server 'gpg-agent' is older than us (2.0.22 < 2.2.33)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.
gpg: signing failed: Invalid length specifier in S-expression
gpg: signing failed: Invalid length specifier in S-expression
error: gpg exec failed (2)

gpg-agentのバージョンがgpgよりも古いことが原因。 合わせて他の関連バイナリのバージョン(gpg-agent, gpg-connect-agent, gpgconf)もgpgに合わせた。

$ INSTALL_DIR=/usr/local/bin/
$ cp ./gnupg-2.2.33/g10/gpg $INSTALL_DIR
$ cp ./gnupg-2.2.33/agent/gpg-agent $INSTALL_DIR
$ cp ./gnupg-2.2.33/tools/gpgconf $INSTALL_DIR
$ cp ./gnupg-2.2.33/tools/gpg-connect-agent $INSTALL_DIR

gpg --importがexit 2で終了する。

バージョンによって挙動が異なることもある様子。自己署名のようなログが流れていたのでそれに起因している可能性がある。 スクリプトを終了するような環境で処理を止めたくない場合は || trueのように実行することもできるが、GPG鍵をインポートしたくてもバージョンが古く対応していないアルゴリズムで署名されていたので、回避策として、ファイルのハッシュ値を比較して、GPG鍵を利用しない方向で対応した。

gpg: pinentry launched (23774 unknown 0.8.1 ? ? ?)

rpm --addsign実行時に、以下のメッセージが出て処理に失敗。

# rpm --define "__gpg  /usr/local/bin/gpg" --define "_gpg_name Sample3" --define "%__gpg_check_password_cmd /bin/true" --define "%__gpg_sign_cmd %{__gpg} gpg --batch -vv --no-secmem-warning --sign --detach-sign --no-armor -u %{_gpg_name} --output %{__signature_filename} %{__plaintext_filename}" --addsign motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
motd-1.0-1.amzn2.noarch.rpm:
gpg: writing to '/var/tmp/rpm-tmp.bm0upg.sig'
gpg: pinentry launched (18127 unknown 0.8.1 ? ? ?)
gpg: signing failed: No passphrase given
gpg: signing failed: No passphrase given
error: gpg exec failed (2)

expectコマンド中での場合は、以下のようなエラー。

spawn rpm --define __gpg  /usr/local/bin/gpg --define _gpg_name Sample1 --define %__gpg_check_password_cmd /bin/true --define %__gpg_sign_cmd %{__gpg} gpg --batch -vv --no-secmem-warning --sign --detach-sign --no-armor -u %{_gpg_name} --output %{__signature_filename} %{__plaintext_filename} --addsign /tmp/sample/motd-1.0-1.amzn2.noarch.rpm
Enter pass phrase: 
Pass phrase is good.
/tmp/sample/motd-1.0-1.amzn2.noarch.rpm:
gpg: writing to '/var/tmp/rpm-tmp.ISKqRF.sig'
gpg: pinentry launched (23742 unknown 0.8.1 ? ? ?)
gpg: signing failed: Operation cancelled
gpg: signing failed: Operation cancelled
error: gpg exec failed (2)

以下のようなパスワード入力画面が出てしまっていることが理由。

                                                         ┌────────────────────────────────────────────────────────────────┐
                                                         │ Please enter the passphrase to unlock the OpenPGP secret key:  │
                                                         │ "SampleGpg1 <hayashier@example.com>"                           │
                                                         │ 3072-bit RSA key, ID 187D25C1E2CFA3BD,                         │
                                                         │ created 2021-12-16.                                            │
                                                         │                                                                │
                                                         │                                                                │
                                                         │ Passphrase: __________________________________________________ │
                                                         │                                                                │
                                                         │         <OK>                                    <Cancel>	      │
                                                         └────────────────────────────────────────────────────────────────┘

インポートしている秘密鍵と実際に指定しているGPG名が不一致で、GPGエージェントによるパスワード入力が効かなかったことが原因。以下のようにechoによるパスフレーズ(echo "PRESET_PASSPHRASE $GPG_KEYGRIP -1 $GPG_PASSPHRASE_HEX" | /usr/local/bin/gpg-connect-agent -S $GPG_AGENT_SOCKET)を実行していた。

rpm_file=./motd-1.0-1.amzn2.noarch.rpm
kill $(ps aux | grep "gpg-agent --" | awk '{print $2}') 
ps aux | grep gpg-agent
/usr/local/bin/gpgconf --reload gpg-agent
/usr/local/bin/gpg-agent --daemon --allow-preset-passphrase --no-detach --log-file gpg_agent_log_file --debug-level guru
GPG_KEYGRIP=$(/usr/local/bin/gpg --with-keygrip --list-key | grep Sample1 -B 2 | grep Keygrip | awk -F = '{print $2}' | sed -e 's/[[:blank:]]//g' | tail -n 1) && echo $GPG_KEYGRIP
GPG_PASSPHRASE_HEX=$(echo Test1234 | tr -d '\n' | hexdump -v -e '/1 "%02X"') && echo $GPG_PASSPHRASE_HEX
GPG_AGENT_SOCKET=$(gpgconf --list-dirs | grep agent-socket | sed -e 's/.*://g') && echo $GPG_AGENT_SOCKET
echo "PRESET_PASSPHRASE $GPG_KEYGRIP -1 $GPG_PASSPHRASE_HEX" | /usr/local/bin/gpg-connect-agent -S $GPG_AGENT_SOCKET

以下がechoコマンドによるもののときのログ

2021-12-16 05:10:10 gpg-agent[18402] DBG: agent_get_cache '5A3AA79AAEC2864B4C7E0AE40571E00499328023'.0 (mode 2) ...
2021-12-16 05:10:10 gpg-agent[18402] DBG: ... miss
2021-12-16 05:10:10 gpg-agent[18402] starting a new PIN Entry
2021-12-16 05:10:10 gpg-agent[18402] DBG: connection to PIN entry established
2021-12-16 05:10:10 gpg-agent[18402] DBG: chan_10 -> INQUIRE PINENTRY_LAUNCHED 18432 unknown 0.8.1 ? ? ?
2021-12-16 05:10:10 gpg-agent[18402] DBG: chan_10 <- END

/usr/libexec/gpg-preset-passphrase --passphrase $GPG_PASS_PHRASE --preset $GPG_KEYGRIPを実行の方がシンプルで、こちらを利用することにした。

gpg: keyserver receive failed: No name

Ubuntu上で実行したところ以下のエラー

$ gpg --keyserver hkp://keys.gnupg.net --recv-key 6DAA6E64A76D2840571B4902528897B826403ADA AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
gpg: keyserver receive failed: No name

SKS Keyserver NetworkがDeprecatedになって、利用できない状態。そのため、他のGPG鍵サーバーを利用すると良い。

gpg: Can't check signature: No public key

Amazon Linux 2上で以下のようにキーをインポート後、

$ gpg --keyserver hkp://keys.gnupg.net --recv-key 6DAA6E64A76D2840571B4902528897B826403ADA AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD D8692123C4065DEA5E0F3AB5249B39D24F25E3B6

以下のように署名を検証

$ LIBGPG_ERROR_VERSION=1.43
$ curl -L https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2 -O
$ curl -L https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2.sig -O
$ gpg -d libgpg-error-${LIBGPG_ERROR_VERSION}.tar.bz2.sig

すると以下のエラー

gpg: assuming signed data in 'libgpg-error-1.43.tar.bz2'
gpg: Signature made Wed Nov  3 14:03:23 2021 UTC
gpg:                using EDDSA key 6DAA6E64A76D2840571B4902528897B826403ADA
gpg: Good signature from "Werner Koch (dist signing 2020)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 6DAA 6E64 A76D 2840 571B  4902 5288 97B8 2640 3ADA
gpg: Signature made Wed Nov 24 01:07:32 2021 UTC
gpg:                using EDDSA key AC8E115BF73E2D8D47FA9908E98E9B2D19C6C8BD
gpg: Can't check signature: No public key

SKS Keyserver NetworkがDeprecatedになって、利用できない状態。そのため、他のGPG鍵サーバーを利用すると良い。

Links

GnuPG

RPM

My Twitter & RSS

Leave a Reply

Your email address will not be published. Required fields are marked *