From 1667ef9585c38d8e61ac99875211416e7d1f60de Mon Sep 17 00:00:00 2001 From: Yaroslav Date: Wed, 27 Mar 2024 18:28:44 +0500 Subject: [PATCH] feat: support PKCS8 keys for APK signing (#804) * support PKCS8 keys for APK signing Call correct parsing function for given RSA key depending on its PEM header. So we can use both PKCS1 and PKCS8 keys to sign APK files. Fixes https://github.com/goreleaser/nfpm/issues/799 * fix golangci-lint warnings --- internal/sign/rsa.go | 28 +++++++++++++++++--- internal/sign/rsa_test.go | 38 +++++++++++++++++++++------ internal/sign/testdata/rsa_pkcs8.priv | 28 ++++++++++++++++++++ internal/sign/testdata/rsa_pkcs8.pub | 9 +++++++ 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 internal/sign/testdata/rsa_pkcs8.priv create mode 100644 internal/sign/testdata/rsa_pkcs8.pub diff --git a/internal/sign/rsa.go b/internal/sign/rsa.go index 6dd60e82..58afb9a1 100644 --- a/internal/sign/rsa.go +++ b/internal/sign/rsa.go @@ -20,6 +20,11 @@ var ( errNoRSAKey = errors.New("key is not an RSA key") ) +const ( + PKCS1PrivkeyPreamble = "RSA PRIVATE KEY" + PKCS8PrivkeyPreamble = "PRIVATE KEY" +) + // RSASignSHA1Digest signs the provided SHA1 message digest. The key file // must be in the PEM format and can either be encrypted or not. func RSASignSHA1Digest(sha1Digest []byte, keyFile, passphrase string) ([]byte, error) { @@ -53,9 +58,26 @@ func RSASignSHA1Digest(sha1Digest []byte, keyFile, passphrase string) ([]byte, e blockData = decryptedBlockData } - priv, err := x509.ParsePKCS1PrivateKey(blockData) - if err != nil { - return nil, fmt.Errorf("parse PKCS1 private key: %w", err) + var priv crypto.Signer + + switch block.Type { + case PKCS1PrivkeyPreamble: + priv, err = x509.ParsePKCS1PrivateKey(blockData) + if err != nil { + return nil, fmt.Errorf("parse PKCS#1 private key: %w", err) + } + case PKCS8PrivkeyPreamble: + privAny, err := x509.ParsePKCS8PrivateKey(blockData) + if err != nil { + return nil, fmt.Errorf("parse PKCS#8 private key: %w", err) + } + privTmp, ok := privAny.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("cannot sign with given private key") + } + priv = privTmp + default: + return nil, fmt.Errorf(`key type "%v" is not supported`, block.Type) } signature, err := priv.Sign(rand.Reader, sha1Digest, crypto.SHA1) diff --git a/internal/sign/rsa_test.go b/internal/sign/rsa_test.go index bbe836ef..839a3029 100644 --- a/internal/sign/rsa_test.go +++ b/internal/sign/rsa_test.go @@ -17,8 +17,9 @@ func TestRSASignAndVerify(t *testing.T) { pubKey string passphrase string }{ - {"unprotected", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub", ""}, - {"protected", "testdata/rsa.priv", "testdata/rsa.pub", pass}, + {"unprotected pkcs1", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub", ""}, + {"protected pkcs1", "testdata/rsa.priv", "testdata/rsa.pub", pass}, + {"unprotected pkcs8", "testdata/rsa_pkcs8.priv", "testdata/rsa_pkcs8.pub", ""}, } for _, testCase := range testCases { @@ -54,18 +55,39 @@ func TestInvalidHash(t *testing.T) { func TestRSAVerifyWrongKey(t *testing.T) { digest := sha1.New().Sum(nil) // nolint:gosec - sig, err := rsaSign(bytes.NewReader(digest), "testdata/rsa_unprotected.priv", "") - require.NoError(t, err) + testCases := []struct { + name string + privKey string + pubKey string + }{ + {"pkcs1", "testdata/rsa_unprotected.priv", "testdata/rsa_unprotected.pub"}, + {"pkcs8", "testdata/rsa_pkcs8.priv", "testdata/rsa_pkcs8.pub"}, + } + + for _, testCase := range testCases { + sig, err := rsaSign(bytes.NewReader(digest), testCase.privKey, "") + require.NoError(t, err) - err = RSAVerifySHA1Digest(digest, sig, "testdata/rsa.pub") - require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error") + err = RSAVerifySHA1Digest(digest, sig, testCase.pubKey) + require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error") + } } func TestRSAVerifyWrongSignature(t *testing.T) { digest := sha1.New().Sum(nil) // nolint:gosec - err := RSAVerifySHA1Digest(digest, []byte{}, "testdata/rsa.pub") - require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error") + testCases := []struct { + name string + pubKey string + }{ + {"pkcs1", "testdata/rsa.pub"}, + {"pkcs8", "testdata/rsa_pkcs8.pub"}, + } + + for _, testCase := range testCases { + err := RSAVerifySHA1Digest(digest, []byte{}, testCase.pubKey) + require.EqualError(t, err, "verify PKCS1v15 signature: crypto/rsa: verification error") + } } func TestRSAVerifyWrongPublicKeyFormat(t *testing.T) { diff --git a/internal/sign/testdata/rsa_pkcs8.priv b/internal/sign/testdata/rsa_pkcs8.priv new file mode 100644 index 00000000..dce8973a --- /dev/null +++ b/internal/sign/testdata/rsa_pkcs8.priv @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbfacH7+FQJmKF +2gadVTUGceI/Edjo0RDHG9Y9xLlA1VJ+HppgHGDYkek+kqLRSwcqKJ8g58M8hYRK +saOAa2OnMfgQ+B0qg191i7VwNrCm4YxgbP1t0z1QWUYX4G97hV+wS7MUFVz8+2H1 +2I4aKw3iNoBINIKlDJgVgxvR4v85Ly4sEFT7PNl7xEE7sxIOiDMv/EL+M4HXrdx7 +OCE4IcwyCyJFmBcSoc/qbTO87LDE/K4EBR0Lte/IJApid3u1gwfliOEeyCKVh1JH +AMNJ7s5RjpuW6XJMNMba+CyUTDiGmnbbxvEGvb6trJfDUHd2ChsD+3HR2qx4lNQA +epdUrQsdAgMBAAECggEAMvw3qhTTUlJwTWZtZeuukw4uP3dOWxqBWrcBJ70ESWak +MG68bnn5FyWhuCrIznQuuGDSQgsEI5FiPxWPhNutPN/TH2H7KG525K+s2GGj3EgF +WzrGDdZlZj4ulYpJazh6l1GmShKCVLOyODDzJWn94h/F4b/s3xkTVN/tPO6NWcNJ +MHUM8wYXtUP4jqfJvWljJPFrzKZBRVnB9PV+VtZRtX880VnMwQ76CjC8fLbaJQRT +XXDLl12FkULWQzJieQr8XJLhb8hLSytBovbqbO24NbMjGFx1hxHdwyziceDPtu04 +4R11Zi/YK4DOYi7wrQfxuqyquHH0lAPK648b60HBMwKBgQD2mYzqCq11qHKjrKLV +AR3ufemcN40b7PjcxpXccaNzEzkBaWlRlqhdhO/naLXKHM97hNotji002/whANx5 +0MYcjdo+VnYT/OYmxexVbsLjFsV0B9LOY1zrSyBAxxyjlSTdjBslOXMDtDnPKpZQ +ydjqFqlrpAZNXuOjBtaRVcC7pwKBgQDj24740wfDnuzbOKxcaTzBLf+Ak7aNI3xz +E8e9A2yOUBWhnpmi0fwiws5IE0ghqJBWrjdrwjna+B9Gs6HKMyTNatCYh8SdjxgQ +JivJ3jrKVrP8ixojz/cuNDXC6KJEHvklaLARMO6BPSaB88oR425Y0BZcw2XBNuU/ +JS1YGCLLmwKBgCFWiPJrFyA88aKnCCx7xiwj4Z049V69HrfaMRBoXIyGIMLMGWzq +TUC3ZCeIxGrakkJEp6pY+kuXIfLkRupBC0d49fRPhA8XtZWwVE8Idlh1D6SsGhfE +3x8APRAE2x5SX3WEJ3dU2PO7PcWAIGozn5umDKl8t01mcqfrmL51NWUpAoGAVDtf +EAbbMOq4PpYlyYexyOwbLsnsSyKaJ+RhCzOP1tAuHvAFdZZQsfz3ytct7BtnOFPw +8un6/0KINVfEcH4VlcZt1GUkPuaeC6JAv8BiVVhV8v7tK93+T1tHoITlL2+PxM99 +fu1qzeXwLUwVICXGLhjGm4Y0QIftmTlCGPXbLw8CgYBDiihffbawacxp79CZJUyd +DFvVvCLgwu1K9JRyykxyVPOZAcS/7x5IzRhpQdy51A5xG4WjBkNghGNosbnSaiFr +cCzEtKiNHefbSNUd5T3w8NO97y26BmtylyUrx+qIGr5XWHYFUFmgAmErqFVRLheT +4E9lCp7uSkx2AlbSgs+ugQ== +-----END PRIVATE KEY----- diff --git a/internal/sign/testdata/rsa_pkcs8.pub b/internal/sign/testdata/rsa_pkcs8.pub new file mode 100644 index 00000000..50e644e9 --- /dev/null +++ b/internal/sign/testdata/rsa_pkcs8.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA232nB+/hUCZihdoGnVU1 +BnHiPxHY6NEQxxvWPcS5QNVSfh6aYBxg2JHpPpKi0UsHKiifIOfDPIWESrGjgGtj +pzH4EPgdKoNfdYu1cDawpuGMYGz9bdM9UFlGF+Bve4VfsEuzFBVc/Pth9diOGisN +4jaASDSCpQyYFYMb0eL/OS8uLBBU+zzZe8RBO7MSDogzL/xC/jOB163cezghOCHM +MgsiRZgXEqHP6m0zvOywxPyuBAUdC7XvyCQKYnd7tYMH5YjhHsgilYdSRwDDSe7O +UY6blulyTDTG2vgslEw4hpp228bxBr2+rayXw1B3dgobA/tx0dqseJTUAHqXVK0L +HQIDAQAB +-----END PUBLIC KEY-----