From 88c95a8e567caa98e99dbd79504d20191c315295 Mon Sep 17 00:00:00 2001 From: Naomi Kirby Date: Wed, 5 Jun 2024 14:30:55 -0700 Subject: [PATCH] Update: Use Debian bookworm as base docker image (#898) * Update base docker image to debian:bookworm * Re-sign database test certs with a valid subjectAltName * Fix COSE signature tests on Golang 1.17 and later * Add /go/bin to path * Use curl instead of wget for apk signing tests * gpg2: Remove deprecated --secret-keyring option The --secret-keyring option has been silently ignored since GPG v2.1, so it never did anything anyways, and in more recent builds this now generates a console warning. We should simply remove it. This should be fine so long as we are making use of the --homedir option to prevent unexpected changes to the user's GPG keyring. * Fix verifier/contentsignature tests for Go >= 1.17 * Use debian:bookworm as image for Circle CI lint-vet-fmt job. * Install some extra packages for lint-vet-fmt job. * Combine package installation steps * Generate a sensible version.json even when developing locally * Slim down autograph container Applying the techniques from mozilla-services/autograph#861 to this pull request, and adding a workaround for the git error in the build_test_xpis.sh script. * Add argument to select Golang version * Bump CircleCI workers to cimg/go:1.19 * Remove staticcheck version pinning * Fix ARG reuse after FROM * Some staticcheck fixes --- .circleci/config.yml | 16 ++-- .dockerignore | 1 + Dockerfile | 86 +++++++++++++++++----- Makefile | 4 +- bin/run_unit_tests.sh | 2 +- database/generate-test-certs.sh | 19 +++++ database/server.crt | 68 +++++++++++------ signer/gpg2/README.md | 3 +- signer/gpg2/gpg2.go | 6 -- signer/gpg2/gpg2_test.go | 4 - signer/xpi/cose_test.go | 12 ++- tools/autograph-client/build_test_apks.sh | 10 ++- tools/autograph-client/build_test_gpg.sh | 4 +- tools/autograph-client/build_test_xpis.sh | 7 +- tools/autograph-monitor/Makefile | 2 +- tools/autograph-monitor/monitor.go | 3 +- tools/softhsm/Dockerfile | 9 +-- verifier/contentsignature/Makefile | 2 +- verifier/contentsignature/verifier_test.go | 41 ++++++++--- version.sh | 26 +++++-- 20 files changed, 220 insertions(+), 105 deletions(-) create mode 100755 database/generate-test-certs.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 9aa1e897c..8c90eefd7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,8 +8,13 @@ version: 2.1 jobs: lint-vet-fmt: docker: - - image: golang:1.16-buster + - image: debian:bookworm steps: + - run: + name: install dependencies + command: | + apt-get update + apt-get install -y golang build-essential git ca-certificates libltdl-dev - checkout - run: name: check crypto11 not used in signers @@ -28,11 +33,6 @@ jobs: command: | make -s fmt-diff | tee fmt.diff test -z "$(cat fmt.diff)" - - run: - name: install packages for crypto11 headers for go vet - command: | - apt-get update - apt-get install -y libltdl-dev - run: name: run go vet command: | @@ -50,7 +50,7 @@ jobs: unit-test: # based on the official golang image with more docker stuff docker: - - image: cimg/go:1.16 + - image: cimg/go:1.19 auth: username: $DOCKER_USER password: $DOCKER_PASS @@ -80,7 +80,7 @@ jobs: build-integrationtest-verify: # based on the official golang image with more docker stuff docker: - - image: cimg/go:1.16 + - image: cimg/go:1.19 auth: username: $DOCKER_USER password: $DOCKER_PASS diff --git a/.dockerignore b/.dockerignore index e69de29bb..2d2ecd68d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -0,0 +1 @@ +.git/ diff --git a/Dockerfile b/Dockerfile index 599a2b4d2..54e413595 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,67 @@ -FROM golang:1.16.10-buster +ARG GO_VERSION=1.19 + +#------------------------------------------------------------------------------ +# Build Stage +#------------------------------------------------------------------------------ +FROM debian:bookworm as builder +ARG GO_VERSION + +ENV DEBIAN_FRONTEND='noninteractive' \ + PATH="${PATH}:/usr/lib/go-${GO_VERSION}/bin:/go/bin" \ + GOPATH='/go' + +## Enable bookworm-backports +RUN echo "deb http://deb.debian.org/debian/ bookworm-backports main" > /etc/apt/sources.list.d/bookworm-backports.list +RUN echo "deb-src http://deb.debian.org/debian/ bookworm-backports main" >> /etc/apt/sources.list.d/bookworm-backports.list + +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get -y install \ + libltdl-dev \ + gpg libncurses5 \ + devscripts \ + apksigner \ + golang-${GO_VERSION} \ + build-essential + +ADD . /app/src/autograph + +RUN cd /app/src/autograph && go install . +RUN cd /app/src/autograph/tools/autograph-monitor && go build -o /go/bin/autograph-monitor . +RUN cd /app/src/autograph/tools/autograph-client && go build -o /go/bin/autograph-client . + +#------------------------------------------------------------------------------ +# Deployment Stage +#------------------------------------------------------------------------------ +FROM debian:bookworm +ARG GO_VERSION EXPOSE 8000 -ENV GODEBUG=x509ignoreCN=0 - -RUN addgroup --gid 10001 app \ - && \ - adduser --gid 10001 --uid 10001 \ - --home /app --shell /sbin/nologin \ - --disabled-password app \ - && \ - echo 'deb http://archive.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/buster-backports.list && \ - apt update && \ - apt -y upgrade && \ - apt -y install libltdl-dev gpg libncurses5 devscripts && \ - apt -y install -t buster-backports apksigner && \ - apt-get clean +ENV DEBIAN_FRONTEND='noninteractive' \ + PATH="${PATH}:/usr/lib/go-${GO_VERSION}/bin:/go/bin" \ + GOPATH='/go' + +## Enable bookworm-backports +RUN echo "deb http://deb.debian.org/debian/ bookworm-backports main" > /etc/apt/sources.list.d/bookworm-backports.list +RUN echo "deb-src http://deb.debian.org/debian/ bookworm-backports main" >> /etc/apt/sources.list.d/bookworm-backports.list + +# Install required packages +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get -y install --no-install-recommends \ + libltdl-dev \ + gpg \ + libncurses5 \ + devscripts \ + apksigner \ + golang-${GO_VERSION} \ + build-essential \ + curl \ + jq + +# Cleanup after package installation +RUN apt-get clean && \ + rm -rf /var/lib/apt/lists/* # fetch the RDS CA bundles # https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html#UsingWithRDS.SSL.CertificatesAllRegions @@ -22,15 +69,14 @@ RUN curl -o /usr/local/share/old-rds-ca-bundle.pem https://s3.amazonaws.com/rds- curl -o /usr/local/share/new-rds-ca-bundle.pem https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem && \ cat /usr/local/share/old-rds-ca-bundle.pem /usr/local/share/new-rds-ca-bundle.pem > /usr/local/share/rds-combined-ca-bundle.pem +# Copy compiled appliation from the builder. ADD . /app/src/autograph ADD autograph.yaml /app ADD version.json /app +COPY --from=builder /go/bin /go/bin/ -RUN cd /app/src/autograph && go install . - -RUN cd /app/src/autograph/tools/autograph-monitor && go build -o /go/bin/autograph-monitor . -RUN cd /app/src/autograph/tools/autograph-client && go build -o /go/bin/autograph-client . - +# Setup the worker and entrypoint. +RUN useradd --uid 10001 --home-dir /app --shell /sbin/nologin app USER app WORKDIR /app CMD /go/bin/autograph diff --git a/Makefile b/Makefile index 8db058bdb..3594abe8b 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ install-goveralls: go install github.com/mattn/goveralls@v0.0.11 install-staticcheck: - go install honnef.co/go/tools/cmd/staticcheck@v0.2.2 + go install honnef.co/go/tools/cmd/staticcheck@v0.4.7 install-go-mod-upgrade: go get github.com/oligot/go-mod-upgrade @@ -69,7 +69,7 @@ race: go test -race -covermode=atomic -count=1 $(PACKAGE_NAMES) staticcheck: - $(GOPATH)/bin/staticcheck -go 1.16 $(PACKAGE_NAMES) | tee /tmp/autograph-staticcheck.txt + $(GOPATH)/bin/staticcheck $(PACKAGE_NAMES) | tee /tmp/autograph-staticcheck.txt # ignore errors in pkgs # ignore SA1019 for DSA being deprecated refs: GH #667 test 0 -eq $$(grep -c -Pv '^/go/pkg/mod/|SA1019' /tmp/autograph-staticcheck.txt) diff --git a/bin/run_unit_tests.sh b/bin/run_unit_tests.sh index a5cc13130..ded91ff25 100755 --- a/bin/run_unit_tests.sh +++ b/bin/run_unit_tests.sh @@ -14,7 +14,7 @@ if [ "$REPORT_COVERAGE" = "true" ]; then make install-goveralls fi # run app unit tests -make generate test +make test # run monitor unit tests make -C tools/autograph-monitor test diff --git a/database/generate-test-certs.sh b/database/generate-test-certs.sh new file mode 100755 index 000000000..533738b6d --- /dev/null +++ b/database/generate-test-certs.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Generate the self-signed root certificate. +if [ ! -f root.key ] || [ ! -f root.crt ]; then + openssl req -x509 -nodes -out root.crt -keyout root.key \ + -subj "/CN=db-root" -addext "subjectAltName = DNS:db-root" +fi + +# Re-use existing server keys, if present. +SERVERKEYARG="-keyout" +if [ -f server.key ]; then + SERVERKEYARG="-key" +fi + +# Generate the database server certificate. +openssl req -new -nodes -out server.csr ${SERVERKEYARG} server.key \ + -subj "/CN=db" -addext "subjectAltName = DNS:db" +openssl x509 -req -in server.csr -days 3650 -text -out server.crt \ + -CA root.crt -CAkey root.key -copy_extensions copy diff --git a/database/server.crt b/database/server.crt index 2fb09ce24..691d55baa 100644 --- a/database/server.crt +++ b/database/server.crt @@ -1,17 +1,17 @@ Certificate: Data: - Version: 1 (0x0) + Version: 3 (0x2) Serial Number: - 27:45:33:71:5e:9f:7b:f7:65:2c:b8:82:91:53:8f:53:05:98:f5:df - Signature Algorithm: NULL + 5d:ab:b9:68:f6:95:5e:5d:f7:92:3c:0e:b6:28:3c:7a:4e:70:d2:9a + Signature Algorithm: sha256WithRSAEncryption Issuer: CN = db Validity - Not Before: Apr 10 13:05:16 2020 GMT - Not After : Feb 22 13:05:16 2029 GMT + Not Before: Apr 23 21:30:45 2024 GMT + Not After : Apr 21 21:30:45 2034 GMT Subject: CN = db Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) + Public-Key: (2048 bit) Modulus: 00:a4:db:dc:f9:ed:47:f5:fa:51:9c:39:e0:d0:a5: 98:81:8d:82:1b:6d:49:c6:23:ed:af:76:51:17:26: @@ -32,21 +32,45 @@ Certificate: 7f:9a:ad:7b:6a:e0:6f:86:71:c3:ab:3d:b4:4b:7e: 77:df Exponent: 65537 (0x10001) - Signature Algorithm: NULL + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:db + X509v3 Subject Key Identifier: + 39:1E:64:C3:92:C9:3A:C4:87:E0:68:09:1D:EE:77:75:2D:95:77:8C + X509v3 Authority Key Identifier: + F6:D1:E0:3E:A2:38:64:1A:63:A6:8C:0F:22:B5:0D:29:E3:AA:75:1E + Signature Algorithm: sha256WithRSAEncryption + Signature Value: + 83:79:4a:fd:3a:8a:72:58:f7:7e:62:75:f9:dc:67:83:72:f4: + ae:81:f9:16:e2:a4:a7:d5:21:d0:dc:43:cd:47:cb:92:bf:70: + 29:2b:77:ad:ba:ab:e5:10:43:0a:4a:fd:66:b7:0c:f0:26:ab: + b3:57:78:b0:9f:ef:98:b1:50:21:97:a5:12:3b:a3:24:84:e6: + 6d:55:58:26:d2:85:ad:28:83:04:08:cd:23:37:c9:32:43:3e: + 9f:87:67:d9:0f:eb:21:b2:e7:30:f9:14:18:1a:b5:b0:1a:af: + 11:4b:98:34:82:d1:92:71:d7:4b:a3:e8:b1:68:4e:92:0a:55: + 31:32:69:9a:c7:88:8f:b7:e7:b5:25:68:88:47:31:39:b1:63: + d9:f6:20:56:b3:4b:90:59:37:65:2d:b8:12:e3:c8:21:50:dc: + 54:86:aa:70:7e:18:e1:cb:0a:77:76:43:88:b8:d9:f8:a2:a5: + 5c:11:a3:f5:78:1b:e6:8b:22:3c:d2:c0:52:2b:36:82:4e:38: + cc:b2:9e:c1:79:da:64:5b:08:31:f4:bc:d9:8a:73:b3:d0:b0: + b2:e9:b6:12:6f:1a:61:4f:74:5b:91:66:f6:13:19:3a:92:c4: + ea:18:e4:ef:8b:e6:95:eb:a1:06:eb:ca:46:4b:64:ba:3b:4c: + cc:96:72:c5 -----BEGIN CERTIFICATE----- -MIICoTCCAYkCFB89vhi87lSAwggIa2stDT8b7ZVpMA0GCSqGSIb3DQEBCwUAMA0x -CzAJBgNVBAMMAmRiMB4XDTIwMDQxMDEzMDUxNloXDTI5MDIyMjEzMDUxNlowDTEL -MAkGA1UEAwwCZGIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCk29z5 -7Uf1+lGcOeDQpZiBjYIbbUnGI+2vdlEXJnqqYtmmqH/+K86zR0mgDOYgvJotm0vN -nfR6ZgBIMH0WKsBbAWu8qzT/rmrUF2IeO5X43y6x29pT7wkjCO7NFVM83me30xYD -t3oGLtryhNIca5lxN5i9ZmV3aGIPJKannP6QxTHveib6VbqU+IwpZ8owe/IAg8/2 -KxU1DY2jlyL0BnrxGRWstWuPPZsHy7/5APvIWrKtE/G6vsrp67ZX/FFGRA4ZK3ql -Bq5azSbppkuu+Tc2+f03lsneFrBxYBwa77arF/fOAETEKRl9iPAvFre6n3+arXtq -4G+GccOrPbRLfnffAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIpBJ0vmcKjJ4Okc -aBvLahUPp/AfKuNdt6oVHKdtHNhAJWg1QhWod/YcROwSxjOYWbVRHKYntXZTGoeA -9Mc5/iP0H00L7mFc6SCUDGtSIRaHCRZF6RsP+QlkJ+kO0Kme/4omkopAiZ0wfqgz -ybGiXu/UxnbNPuPffQWcljPZHSfDEkefOFgoV5pNCaiT7HJ941b1QhsV3mIN95bq -woKiHGO9xlpBKcil9z8eH10hcn9hzVc97/CRkeLjjk4wKzf0/CNuUmDk1710SCcf -gdAuqyRUjRYT4AvrI86cm6kbzHPiSkRg4VTz7hj2mP2bb0CLxpgfVmr6i1SwgFMB -nMyt1oU= +MIIC+TCCAeGgAwIBAgIUXau5aPaVXl33kjwOtig8ek5w0powDQYJKoZIhvcNAQEL +BQAwDTELMAkGA1UEAwwCZGIwHhcNMjQwNDIzMjEzMDQ1WhcNMzQwNDIxMjEzMDQ1 +WjANMQswCQYDVQQDDAJkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKTb3PntR/X6UZw54NClmIGNghttScYj7a92URcmeqpi2aaof/4rzrNHSaAM5iC8 +mi2bS82d9HpmAEgwfRYqwFsBa7yrNP+uatQXYh47lfjfLrHb2lPvCSMI7s0VUzze +Z7fTFgO3egYu2vKE0hxrmXE3mL1mZXdoYg8kpqec/pDFMe96JvpVupT4jClnyjB7 +8gCDz/YrFTUNjaOXIvQGevEZFay1a489mwfLv/kA+8hasq0T8bq+yunrtlf8UUZE +DhkreqUGrlrNJummS675Nzb5/TeWyd4WsHFgHBrvtqsX984ARMQpGX2I8C8Wt7qf +f5qte2rgb4Zxw6s9tEt+d98CAwEAAaNRME8wDQYDVR0RBAYwBIICZGIwHQYDVR0O +BBYEFDkeZMOSyTrEh+BoCR3ud3UtlXeMMB8GA1UdIwQYMBaAFPbR4D6iOGQaY6aM +DyK1DSnjqnUeMA0GCSqGSIb3DQEBCwUAA4IBAQCDeUr9OopyWPd+YnX53GeDcvSu +gfkW4qSn1SHQ3EPNR8uSv3ApK3etuqvlEEMKSv1mtwzwJquzV3iwn++YsVAhl6US +O6MkhOZtVVgm0oWtKIMECM0jN8kyQz6fh2fZD+shsucw+RQYGrWwGq8RS5g0gtGS +cddLo+ixaE6SClUxMmmax4iPt+e1JWiIRzE5sWPZ9iBWs0uQWTdlLbgS48ghUNxU +hqpwfhjhywp3dkOIuNn4oqVcEaP1eBvmiyI80sBSKzaCTjjMsp7BedpkWwgx9LzZ +inOz0LCy6bYSbxphT3RbkWb2Exk6ksTqGOTvi+aV66EG68pGS2S6O0zMlnLF -----END CERTIFICATE----- diff --git a/signer/gpg2/README.md b/signer/gpg2/README.md index f47facd8c..969844d9d 100644 --- a/signer/gpg2/README.md +++ b/signer/gpg2/README.md @@ -18,11 +18,10 @@ $ go run client.go -d $(base64 /tmp/pgpinput.txt) -k pgpsubkey \ # import the public key returned by autograph into a temp keyring $ gpg --no-default-keyring --keyring /tmp/testkeyring.pgp \ - --secret-keyring /tmp/testsecring.gpg --import /tmp/testkey.asc + --import /tmp/testkey.asc # verify the signature using the temp keyring $ gpg --no-default-keyring --keyring /tmp/testkeyring.pgp \ - --secret-keyring /tmp/testsecring.gpg \ --verify /tmp/testsig.pgp /tmp/pgpinput.txt ``` diff --git a/signer/gpg2/gpg2.go b/signer/gpg2/gpg2.go index db33e8fb8..331f4c743 100644 --- a/signer/gpg2/gpg2.go +++ b/signer/gpg2/gpg2.go @@ -33,7 +33,6 @@ const ( ModeDebsign = "debsign" keyRingFilename = "autograph_gpg2_keyring.gpg" - secRingFilename = "autograph_gpg2_secring.gpg" gpgConfFilename = "gpg.conf" // gpgConfContentsHead is the static part of the gpg config @@ -204,7 +203,6 @@ func createKeyRing(s *GPG2Signer) (dir string, err error) { } keyRingPath := filepath.Join(dir, keyRingFilename) - secRingPath := filepath.Join(dir, secRingFilename) // call gpg to create a new keyring and load the public key in it gpgLoadPublicKey := exec.Command("gpg", @@ -213,7 +211,6 @@ func createKeyRing(s *GPG2Signer) (dir string, err error) { "--homedir", dir, "--no-default-keyring", "--keyring", keyRingPath, - "--secret-keyring", secRingPath, "--no-tty", "--batch", "--yes", @@ -233,7 +230,6 @@ func createKeyRing(s *GPG2Signer) (dir string, err error) { "--no-options", "--homedir", dir, "--keyring", keyRingPath, - "--secret-keyring", secRingPath, "--no-tty", "--batch", "--yes", @@ -292,7 +288,6 @@ func (s *GPG2Signer) SignData(data []byte, options interface{}) (signer.Signatur return nil, fmt.Errorf("gpg2: can only sign monitor data in %s mode", ModeGPG2) } keyRingPath := filepath.Join(s.tmpDir, keyRingFilename) - secRingPath := filepath.Join(s.tmpDir, secRingFilename) // write the input to a temp file tmpContentFile, err := ioutil.TempFile(s.tmpDir, fmt.Sprintf("gpg2_%s_input", s.ID)) @@ -319,7 +314,6 @@ func (s *GPG2Signer) SignData(data []byte, options interface{}) (signer.Signatur "--homedir", s.tmpDir, "--no-default-keyring", "--keyring", keyRingPath, - "--secret-keyring", secRingPath, "--armor", "--no-tty", "--batch", diff --git a/signer/gpg2/gpg2_test.go b/signer/gpg2/gpg2_test.go index b1353e049..97640aa4a 100644 --- a/signer/gpg2/gpg2_test.go +++ b/signer/gpg2/gpg2_test.go @@ -100,7 +100,6 @@ func assertClearSignedFilesVerify(t *testing.T, signer *GPG2Signer, testname str "--homedir", tmpDir, "--no-default-keyring", "--keyring", filepath.Join(tmpDir, "autograph_test_gpg2_keyring.gpg"), - "--secret-keyring", filepath.Join(tmpDir, "autograph_test_gpg2_secring.gpg"), "--import", publicKeyPath) out, err := gnupgCreateKeyring.CombinedOutput() if err != nil { @@ -122,7 +121,6 @@ func assertClearSignedFilesVerify(t *testing.T, signer *GPG2Signer, testname str "--homedir", tmpDir, "--no-default-keyring", "--keyring", filepath.Join(tmpDir, "autograph_test_gpg2_keyring.gpg"), - "--secret-keyring", filepath.Join(tmpDir, "autograph_test_gpg2_secring.gpg"), "--batch", "--yes", "--pinentry-mode", "error", @@ -366,7 +364,6 @@ func TestSignData(t *testing.T) { // call gnupg to create a new keyring, load the key in it gnupgCreateKeyring := exec.Command("gpg", "--no-default-keyring", "--keyring", "/tmp/autograph_test_gpg2_keyring.gpg", - "--secret-keyring", "/tmp/autograph_test_gpg2_secring.gpg", "--import", tmpPublicKeyFile.Name()) out, err := gnupgCreateKeyring.CombinedOutput() if err != nil { @@ -376,7 +373,6 @@ func TestSignData(t *testing.T) { // verify the signature gnupgVerifySig := exec.Command("gpg", "--no-default-keyring", "--keyring", "/tmp/autograph_test_gpg2_keyring.gpg", - "--secret-keyring", "/tmp/autograph_test_gpg2_secring.gpg", "--verify", tmpSignatureFile.Name(), tmpContentFile.Name()) out, err = gnupgVerifySig.CombinedOutput() if err != nil { diff --git a/signer/xpi/cose_test.go b/signer/xpi/cose_test.go index 7796fe221..68658a419 100644 --- a/signer/xpi/cose_test.go +++ b/signer/xpi/cose_test.go @@ -312,7 +312,8 @@ func TestIsValidCOSESignatureErrs(t *testing.T) { }, results: []string{ "xpi: COSE Signature kid value is not a byte array", - "xpi: failed to parse X509 EE certificate from COSE Signature: asn1: structure error: tags don't match (16 vs {class:1 tag:15 length:75 isCompound:false})", + "xpi: failed to parse X509 EE certificate from COSE Signature: asn1: structure error: tags don't match", + "xpi: failed to parse X509 EE certificate from COSE Signature: x509: malformed certificate", }, }, //9 @@ -326,7 +327,8 @@ func TestIsValidCOSESignatureErrs(t *testing.T) { }, }, results: []string{ - "xpi: failed to parse X509 EE certificate from COSE Signature: asn1: structure error: tags don't match (16 vs {class:1 tag:15 length:75 isCompound:false})", + "xpi: failed to parse X509 EE certificate from COSE Signature: asn1: structure error: tags don't match", + "xpi: failed to parse X509 EE certificate from COSE Signature: x509: malformed certificate", }, }, } @@ -398,7 +400,8 @@ func TestIsValidCOSEMessageErrs(t *testing.T) { }, results: []string{ "xpi: expected SignMessage Protected Headers kid value 0 to be a byte slice got with type ", - "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: asn1: structure error: tags don't match (16 vs {class:1 tag:14 length:111 isCompound:true})", + "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: asn1: structure error: tags don't match", + "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: x509: malformed certificate", }, }, //5 @@ -415,7 +418,8 @@ func TestIsValidCOSEMessageErrs(t *testing.T) { }, }, results: []string{ - "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: asn1: structure error: tags don't match (16 vs {class:1 tag:14 length:111 isCompound:true})", + "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: asn1: structure error: tags don't match", + "xpi: SignMessage Signature Protected Headers kid value 0 does not decode to a parseable X509 cert: x509: malformed certificate", }, }, //6 diff --git a/tools/autograph-client/build_test_apks.sh b/tools/autograph-client/build_test_apks.sh index 0978e1faa..deae19924 100755 --- a/tools/autograph-client/build_test_apks.sh +++ b/tools/autograph-client/build_test_apks.sh @@ -9,20 +9,22 @@ FENNEC_NIGHTLY_URL=https://archive.mozilla.org/pub/mobile/nightly/2018/10/2018-1 FENNEC_BETA_URL=https://archive.mozilla.org/pub/mobile/releases/64.0b9/android-api-16/en-US/fennec-64.0b9.en-US.android-arm.apk FOCUS_LATEST_URL=https://archive.mozilla.org/pub/android/focus/latest/Focus-arm.apk -wget -t 5 $FENNEC_NIGHTLY_URL $FENNEC_BETA_URL $FOCUS_LATEST_URL +curl --retry 5 $FENNEC_NIGHTLY_URL -o fennec-nightly.apk +curl --retry 5 $FENNEC_BETA_URL -o fennec-beta.apk +curl --retry 5 $FOCUS_LATEST_URL -o focus-latest.apk HAWK_USER=${HAWK_USER:-alice} HAWK_SECRET=${HAWK_SECRET:-fs5wgcer9qj819kfptdlp8gm227ewxnzvsuj9ztycsx08hfhzu} TARGET=${TARGET:-'http://127.0.0.1:8000'} # Sign Fennec Beta -go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f fennec-64.0b9.en-US.android-arm.apk -o fennec-legacy-sha1.resigned.apk -k legacy_apk_with_rsa -pk7digest sha1 +go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f fennec-beta.apk -o fennec-legacy-sha1.resigned.apk -k legacy_apk_with_rsa -pk7digest sha1 # Sign with ECDSA -go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f Focus-arm.apk -o focus-ecdsa.v2.resigned.apk -k apk_cert_with_ecdsa_sha256 +go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f focus-latest.apk -o focus-ecdsa.v2.resigned.apk -k apk_cert_with_ecdsa_sha256 # Sign with RSA -go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f Focus-arm.apk -o focus-rsa.v2.resigned.apk -k testapp-android +go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f focus-latest.apk -o focus-rsa.v2.resigned.apk -k testapp-android # Sign Aligned APK with ECDSA go run client.go -t $TARGET -u $HAWK_USER -p $HAWK_SECRET -f ../../signer/apk2/aligned-two-files.apk -o aligned-two-files.ecdsa.v2.signed.apk -k apk_cert_with_ecdsa_sha256 diff --git a/tools/autograph-client/build_test_gpg.sh b/tools/autograph-client/build_test_gpg.sh index 29c43c851..753f64d0e 100755 --- a/tools/autograph-client/build_test_gpg.sh +++ b/tools/autograph-client/build_test_gpg.sh @@ -29,7 +29,7 @@ if [ "$#" -eq 0 ]; then if [ "$VERIFY" = "1" ]; then # import the public key returned by autograph into a temp keyring - gpg --no-options --homedir "${test_dir}" --no-default-keyring --keyring "${test_dir}/testkeyring.pgp" --secret-keyring "${test_dir}/testsecring.gpg" --import "${test_dir}/testkey.asc" + gpg --no-options --homedir "${test_dir}" --no-default-keyring --keyring "${test_dir}/testkeyring.pgp" --import "${test_dir}/testkey.asc" # verify the signature using the temp keyring echo "running: gpg --no-options --homedir \"${test_dir}\" --no-default-keyring --keyring \"${test_dir}/testkeyring.pgp\" --verify \"${test_dir}/testsig.pgp\" <(base64 -d \"${test_dir}/pgpinput.txt\")" @@ -42,7 +42,7 @@ else if [ "$VERIFY" = "1" ]; then # import the public key returned by autograph into a temp keyring - gpg --no-options --homedir "${test_dir}" --no-default-keyring --keyring "${test_dir}/testkeyring.pgp" --secret-keyring "${test_dir}/testsecring.gpg" --import "${test_dir}/testkey.asc" + gpg --no-options --homedir "${test_dir}" --no-default-keyring --keyring "${test_dir}/testkeyring.pgp" --import "${test_dir}/testkey.asc" # verify the signature using the temp keyring for signed in signed_*; do diff --git a/tools/autograph-client/build_test_xpis.sh b/tools/autograph-client/build_test_xpis.sh index 25d9b95c3..b7bff0aaf 100755 --- a/tools/autograph-client/build_test_xpis.sh +++ b/tools/autograph-client/build_test_xpis.sh @@ -11,15 +11,16 @@ set -e # INPUT_FILE=$1 -OUTPUT_BASENAME=autograph-$(git rev-parse --short HEAD)-$CONFIG-$(basename $INPUT_FILE '.zip')-PKCS7 +TARGET=${TARGET:-'http://127.0.0.1:8000'} + +PROJECT_SHORTHASH=$(curl -s "${TARGET}/__version__" | jq -r '.commit' | head -c8) +OUTPUT_BASENAME=autograph-$PROJECT_SHORTHASH-$CONFIG-$(basename $INPUT_FILE '.zip')-PKCS7 HAWK_USER=${HAWK_USER:-alice} HAWK_SECRET=${HAWK_SECRET:-fs5wgcer9qj819kfptdlp8gm227ewxnzvsuj9ztycsx08hfhzu} CN=${CN:-testaddon@allizom} VERIFICATION_TIME=${VERIFICATION_TIME:-""} -TARGET=${TARGET:-'http://127.0.0.1:8000'} - if [[ "$VERIFICATION_TIME" = "" ]]; then COMMON_ARGS="-t $TARGET -f $INPUT_FILE -u $HAWK_USER -p $HAWK_SECRET -cn $CN -k $SIGNER_ID -r $TRUST_ROOTS" else diff --git a/tools/autograph-monitor/Makefile b/tools/autograph-monitor/Makefile index 7ea29bb91..8a136d61d 100644 --- a/tools/autograph-monitor/Makefile +++ b/tools/autograph-monitor/Makefile @@ -21,7 +21,7 @@ race: lint: $(GOPATH)/bin/golint *.go staticcheck: - $(GOPATH)/bin/staticcheck -go 1.16 *.go + $(GOPATH)/bin/staticcheck *.go vet: go vet *.go clean: diff --git a/tools/autograph-monitor/monitor.go b/tools/autograph-monitor/monitor.go index 49e311aa7..597aabefb 100644 --- a/tools/autograph-monitor/monitor.go +++ b/tools/autograph-monitor/monitor.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" "net/http" "os" @@ -148,7 +147,7 @@ func monitor() (err error) { defer resp.Body.Close() if resp.StatusCode != http.StatusCreated { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { log.Printf("error reading failed monitor response body: %s", err) } diff --git a/tools/softhsm/Dockerfile b/tools/softhsm/Dockerfile index 7e954eca7..9175ce596 100644 --- a/tools/softhsm/Dockerfile +++ b/tools/softhsm/Dockerfile @@ -1,11 +1,10 @@ FROM autograph-app USER root -RUN apt update && \ - apt -y upgrade && \ - apt -y install jq softhsm2 python3 python3-pip python3-ruamel.yaml && \ - apt-get clean && \ - python3 -m pip install yq +RUN apt-get update && \ + apt-get -y upgrade && \ + apt-get -y install jq yq softhsm2 python3 python3-ruamel.yaml && \ + apt-get clean # copy the config ADD autograph.softhsm.yaml /app/ diff --git a/verifier/contentsignature/Makefile b/verifier/contentsignature/Makefile index 4543c9346..8c146340c 100644 --- a/verifier/contentsignature/Makefile +++ b/verifier/contentsignature/Makefile @@ -11,7 +11,7 @@ fmt-fix: lint: $(GOPATH)/bin/golint . staticcheck: - $(GOPATH)/bin/staticcheck -go 1.16 . + $(GOPATH)/bin/staticcheck . race: go test -race -covermode=atomic -count=1 . showcoverage: test diff --git a/verifier/contentsignature/verifier_test.go b/verifier/contentsignature/verifier_test.go index 574128f9f..635c1b49e 100644 --- a/verifier/contentsignature/verifier_test.go +++ b/verifier/contentsignature/verifier_test.go @@ -966,7 +966,7 @@ func Test_ParseChain(t *testing.T) { chain []byte wantCerts []*x509.Certificate wantErr bool - wantErrStr string + wantErrStr []string }{ { name: "NormandyDevChain2021 parses", @@ -992,70 +992,87 @@ func Test_ParseChain(t *testing.T) { chain: []byte(""), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to PEM decode EE/leaf certificate from chain", + wantErrStr: []string{"failed to PEM decode EE/leaf certificate from chain"}, }, { name: "EE bad PEM type fails", chain: []byte(testSignerP384PEM), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to PEM decode EE/leaf certificate from chain", + wantErrStr: []string{"failed to PEM decode EE/leaf certificate from chain"}, }, { name: "EE bad PEM content fails", chain: []byte(badPEMContent), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "error parsing EE/leaf certificate from chain: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} tbsCertificate @2", + wantErrStr: []string{ + "error parsing EE/leaf certificate from chain: asn1: structure error: tags don't match", + "error parsing EE/leaf certificate from chain: x509: malformed tbs certificate", + }, }, { name: "inter bad PEM type fails", chain: []byte(firefoxPkiStageRoot + "\nthis is not a PEM"), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to PEM decode intermediate certificate from chain", + wantErrStr: []string{"failed to PEM decode intermediate certificate from chain"}, }, { name: "inter bad PEM content fails", chain: []byte(firefoxPkiStageRoot + "\n" + badPEMContent), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to parse intermediate certificate from chain: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} tbsCertificate @2", + wantErrStr: []string{ + "failed to parse intermediate certificate from chain: asn1: structure error: tags don't match", + "failed to parse intermediate certificate from chain: x509: malformed tbs certificate", + }, }, { name: "root bad PEM type fails", chain: []byte(firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\nthis is not a PEM"), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to PEM decode root certificate from chain", + wantErrStr: []string{"failed to PEM decode root certificate from chain"}, }, { name: "inter bad PEM content fails", chain: []byte(firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\n" + badPEMContent), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "failed to parse root certificate from chain: asn1: structure error: tags don't match (16 vs {class:0 tag:2 length:1 isCompound:false}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:0 set:false omitEmpty:false} tbsCertificate @2", + wantErrStr: []string{ + "failed to parse root certificate from chain: asn1: structure error: tags don't match", + "failed to parse root certificate from chain: x509: malformed tbs certificate", + }, }, { name: "trailing data fails", chain: []byte(firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\n!!!!extra"), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "found trailing data after root certificate in chain", + wantErrStr: []string{"found trailing data after root certificate in chain"}, }, { name: "extra cert fails", chain: []byte(firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot + "\n" + firefoxPkiStageRoot), wantCerts: []*x509.Certificate{}, wantErr: true, - wantErrStr: "found trailing data after root certificate in chain", + wantErrStr: []string{"found trailing data after root certificate in chain"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotCerts, err := ParseChain(tt.chain) - if tt.wantErr && (err != nil) && err.Error() != tt.wantErrStr { - t.Errorf("ParseChain() error.Error() = '%s', wanted wantErrStr '%s'", err, tt.wantErrStr) + if tt.wantErr && (err != nil) { + anyMatches := false + for _, result := range tt.wantErrStr { + if strings.HasPrefix(err.Error(), result) { + anyMatches = true + } + } + if !anyMatches { + t.Errorf("ParseChain() error = '%s'", err) + } } if (err != nil) != tt.wantErr { t.Errorf("ParseChain() error = %v, wantErr %v", err, tt.wantErr) diff --git a/version.sh b/version.sh index 94fad31ed..ec72d332f 100755 --- a/version.sh +++ b/version.sh @@ -3,10 +3,24 @@ set -e cd "$(dirname "$0")" + # create a version.json per https://github.com/mozilla-services/Dockerflow/blob/main/docs/version_object.md -printf '{"commit":"%s","version":"%s","source":"https://github.com/%s/%s","build":"%s"}\n' \ -"$CIRCLE_SHA1" \ -"$CIRCLE_TAG" \ -"$CIRCLE_PROJECT_USERNAME" \ -"$CIRCLE_PROJECT_REPONAME" \ -"$CIRCLE_BUILD_URL" > version.json +if [ -n "$CIRCLE_SHA1" ]; then + # We are running in CircleCI. + printf '{"commit":"%s","version":"%s","source":"https://github.com/%s/%s","build":"%s"}\n' \ + "$CIRCLE_SHA1" \ + "$CIRCLE_TAG" \ + "$CIRCLE_PROJECT_USERNAME" \ + "$CIRCLE_PROJECT_REPONAME" \ + "$CIRCLE_BUILD_URL" > version.json +elif [ -d .git ]; then + # Try pulling info from git directly. + printf '{"commit":"%s","version":"%s","source":"%s","build":"%s"}\n' \ + "$(git rev-parse HEAD)" \ + "$(git describe --tags)" \ + "$(git remote get-url origin)" \ + "" > version.json +elif [ ! -f version.json ]; then + # Otherwise, give up and create an empty version file. + echo '{"commit":"","version":"","source":"","build":""}\n' > version.json +fi