diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cde3fb3..7d066db 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: Tests -on: [push, pull_request] +on: [pull_request] jobs: test_linux: @@ -13,54 +13,54 @@ jobs: - name: Run tests run: | ./test.sh - test_windows: - name: Windows build and tests - runs-on: windows-latest - steps: - - name: Checkout source code - uses: actions/checkout@v2 + # test_windows: + # name: Windows build and tests + # runs-on: windows-latest + # steps: + # - name: Checkout source code + # uses: actions/checkout@v2 - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1 + # - name: Add msbuild to PATH + # uses: microsoft/setup-msbuild@v1 - - name: Install dependencies - run: | - Invoke-WebRequest -URI https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable-msvc.zip -OutFile libsodium-1.0.18-stable-msvc.zip - tar -xf libsodium-1.0.18-stable-msvc.zip - rm libsodium-1.0.18-stable-msvc.zip - cp .\libsodium\x64\Release\v143\dynamic\libsodium.dll $env:PGROOT\lib - Invoke-WebRequest -URI https://github.com/theory/pgtap/archive/refs/tags/v1.2.0.zip -OutFile pgtap.zip - tar -xf pgtap.zip - rm pgtap.zip - cd pgtap-1.2.0 - cp .\sql\pgtap.sql.in .\sql\pgtap.sql - perl.exe '-pi.bak' -e "s/TAPSCHEMA/tap/g" .\sql\pgtap.sql - perl.exe '-pi.bak' -e "s/__OS__/win32/g" .\sql\pgtap.sql - perl.exe '-pi.bak' -e "s/__VERSION__/0.24/g" .\sql\pgtap.sql - perl.exe '-pi.bak' -e "s/^-- ## //g" .\sql\pgtap.sql - cp .\sql\pgtap.sql $env:PGROOT\share\extension - cp .\pgtap.control $env:PGROOT\share\extension - cp .\contrib\pgtap.spec $env:PGROOT\share\contrib - ren $env:PGROOT\share\extension\pgtap.sql $env:PGROOT\share\extension\pgtap--1.2.0.sql - shell: pwsh + # - name: Install dependencies + # run: | + # Invoke-WebRequest -URI https://download.libsodium.org/libsodium/releases/libsodium-1.0.18-stable-msvc.zip -OutFile libsodium-1.0.18-stable-msvc.zip + # tar -xf libsodium-1.0.18-stable-msvc.zip + # rm libsodium-1.0.18-stable-msvc.zip + # cp .\libsodium\x64\Release\v143\dynamic\libsodium.dll $env:PGROOT\lib + # Invoke-WebRequest -URI https://github.com/theory/pgtap/archive/refs/tags/v1.2.0.zip -OutFile pgtap.zip + # tar -xf pgtap.zip + # rm pgtap.zip + # cd pgtap-1.2.0 + # cp .\sql\pgtap.sql.in .\sql\pgtap.sql + # perl.exe '-pi.bak' -e "s/TAPSCHEMA/tap/g" .\sql\pgtap.sql + # perl.exe '-pi.bak' -e "s/__OS__/win32/g" .\sql\pgtap.sql + # perl.exe '-pi.bak' -e "s/__VERSION__/0.24/g" .\sql\pgtap.sql + # perl.exe '-pi.bak' -e "s/^-- ## //g" .\sql\pgtap.sql + # cp .\sql\pgtap.sql $env:PGROOT\share\extension + # cp .\pgtap.control $env:PGROOT\share\extension + # cp .\contrib\pgtap.spec $env:PGROOT\share\contrib + # ren $env:PGROOT\share\extension\pgtap.sql $env:PGROOT\share\extension\pgtap--1.2.0.sql + # shell: pwsh - - name: Run msbuild - working-directory: ./build - run: | - msbuild pgsodium.vcxproj /p:libsodiumLocation=..\libsodium /p:PostgreSQLLocation=%PGROOT% /p:Configuration=Release /p:Platform=x64 /p:platformToolset=v143 + # - name: Run msbuild + # working-directory: ./build + # run: | + # msbuild pgsodium.vcxproj /p:libsodiumLocation=..\libsodium /p:PostgreSQLLocation=%PGROOT% /p:Configuration=Release /p:Platform=x64 /p:platformToolset=v143 - - name: Install pgsodium, update config, and restart - run: | - cp .\build\x64\Release\pgsodium.dll $env:PGROOT\lib - cp pgsodium.control $env:PGROOT\share\extension - cp .\sql\* $env:PGROOT\share\extension - cp .\getkey_scripts\pgsodium_getkey.bat $env:PGDATA\ - ((Get-Content -Path $env:PGDATA\postgresql.conf) -Replace "#shared_preload_libraries = ''","shared_preload_libraries = 'pgsodium'") | Set-Content -Path $env:PGDATA\postgresql.conf - Add-Content -Path $env:PGDATA\postgresql.conf -Value ("pgsodium.getkey_script = '$env:PGDATA\pgsodium_getkey.bat'" -Replace "\\","/") - & $env:PGBIN\pg_ctl restart -D $env:PGDATA - shell: pwsh + # - name: Install pgsodium, update config, and restart + # run: | + # cp .\build\x64\Release\pgsodium.dll $env:PGROOT\lib + # cp pgsodium.control $env:PGROOT\share\extension + # cp .\sql\* $env:PGROOT\share\extension + # cp .\getkey_scripts\pgsodium_getkey.bat $env:PGDATA\ + # ((Get-Content -Path $env:PGDATA\postgresql.conf) -Replace "#shared_preload_libraries = ''","shared_preload_libraries = 'pgsodium'") | Set-Content -Path $env:PGDATA\postgresql.conf + # Add-Content -Path $env:PGDATA\postgresql.conf -Value ("pgsodium.getkey_script = '$env:PGDATA\pgsodium_getkey.bat'" -Replace "\\","/") + # & $env:PGBIN\pg_ctl restart -D $env:PGDATA + # shell: pwsh - - name: Run pgsodium tests - run: | - & $env:PGBIN\psql -q -U postgres -f .\test\test.sql - shell: pwsh + # - name: Run pgsodium tests + # run: | + # & $env:PGBIN\psql -q -U postgres -f .\test\test.sql + # shell: pwsh diff --git a/Dockerfile b/Dockerfile index 86cbe88..39ae9e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,60 +1,108 @@ -FROM ubuntu:latest +# Build stage - contains all build dependencies +FROM debian:bookworm-slim AS builder ARG version ARG DEBIAN_FRONTEND=noninteractive -# install base dependences +# Install build dependencies RUN apt-get update && \ - apt-get install -y make cmake git curl build-essential m4 sudo gdbserver \ - gdb libreadline-dev bison flex zlib1g-dev tmux zile zip vim gawk wget libicu-dev pkg-config - -# add postgres user and make data dir -RUN groupadd -r postgres && useradd --no-log-init -r -m -s /bin/bash -g postgres -G sudo postgres -RUN echo "postgres ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \ - chmod 0440 /etc/sudoers.d/user - -ENV PGDATA /home/postgres/data -RUN /bin/rm -Rf "$PGDATA" && mkdir "$PGDATA" -WORKDIR "/home/postgres" - -# get postgres source and compile with debug and no optimization -RUN git clone --branch REL_${version}_STABLE https://github.com/postgres/postgres.git --depth=1 && \ - cd postgres && ./configure \ - --prefix=/usr/ \ - --enable-debug \ - --enable-depend --enable-cassert --enable-profiling \ - CFLAGS="-ggdb -Og -g3 -fno-omit-frame-pointer" \ -# CFLAGS="-O3" \ - && make -j 4 && make install - -RUN chown postgres:postgres /home/postgres - -RUN curl -s -L https://github.com/theory/pgtap/archive/v1.2.0.tar.gz | tar zxvf - && cd pgtap-1.2.0 && make && make install -RUN curl -s -L https://github.com/jedisct1/libsodium/releases/download/1.0.20-RELEASE/libsodium-1.0.20.tar.gz | tar zxvf - && cd libsodium-1.0.20 && ./configure && make check && make -j 4 install -RUN cpan App::cpanminus && cpan TAP::Parser::SourceHandler::pgTAP && cpan App::prove - -RUN git clone --depth 1 https://github.com/lacanoid/pgddl.git -RUN cd pgddl && make && make install && cd .. - -RUN mkdir "/home/postgres/pgsodium" -WORKDIR "/home/postgres/pgsodium" -COPY . . -RUN make -j 4 && make install -RUN ldconfig -RUN cd `pg_config --sharedir`/extension/ -RUN cp getkey_scripts/pgsodium_getkey_urandom.sh `pg_config --sharedir`/extension/pgsodium_getkey -RUN sed -i 's/exit//g' `pg_config --sharedir`/extension/pgsodium_getkey -RUN chmod +x `pg_config --sharedir`/extension/pgsodium_getkey -RUN cp `pg_config --sharedir`/extension/pgsodium_getkey /getkey + apt-get install -y --no-install-recommends \ + make cmake git curl build-essential m4 \ + libreadline-dev bison flex zlib1g-dev \ + libicu-dev pkg-config ca-certificates \ + perl cpanminus && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /build + +# Build PostgreSQL +RUN curl -s -L https://ftp.postgresql.org/pub/source/v${version}/postgresql-${version}.tar.gz | tar zxf - && \ + cd postgresql-${version} && \ + ./configure --prefix=/usr/local/pgsql CFLAGS="-O3" && \ + make -j$(nproc) && \ + make install && \ + cd .. && rm -rf postgresql-${version} + +# Build libsodium +RUN curl -s -L https://github.com/jedisct1/libsodium/releases/download/1.0.20-RELEASE/libsodium-1.0.20.tar.gz | tar zxf - && \ + cd libsodium-1.0.20 && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && rm -rf libsodium-1.0.20 + +# Build pgTAP (for testing) +RUN curl -s -L https://github.com/theory/pgtap/archive/v1.2.0.tar.gz | tar zxf - && \ + cd pgtap-1.2.0 && \ + PATH=/usr/local/pgsql/bin:$PATH make && \ + PATH=/usr/local/pgsql/bin:$PATH make install && \ + cd .. && rm -rf pgtap-1.2.0 -RUN chown -R postgres:postgres /home/postgres/pgsodium -RUN chown -R postgres:postgres /home/postgres/data +# Build pgddl +RUN git clone --depth 1 https://github.com/lacanoid/pgddl.git && \ + cd pgddl && \ + PATH=/usr/local/pgsql/bin:$PATH make && \ + PATH=/usr/local/pgsql/bin:$PATH make install && \ + cd .. && rm -rf pgddl -# make postgres a sudoer -RUN echo "postgres ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \ - chmod 0440 /etc/sudoers.d/user +# Build pgsodium +COPY . /build/pgsodium +RUN cd pgsodium && \ + PATH=/usr/local/pgsql/bin:$PATH make -j$(nproc) && \ + PATH=/usr/local/pgsql/bin:$PATH make install -# start the database +# Install Perl test dependencies +RUN cpanm --notest TAP::Parser::SourceHandler::pgTAP + +# Runtime stage - minimal dependencies +FROM debian:bookworm-slim +ARG DEBIAN_FRONTEND=noninteractive + +# Install only runtime dependencies +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libreadline8 zlib1g libicu72 ca-certificates \ + perl sudo locales && \ + rm -rf /var/lib/apt/lists/* && \ + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \ + locale-gen + +ENV LANG=en_US.UTF-8 \ + LC_ALL=en_US.UTF-8 \ + PATH=/usr/local/pgsql/bin:/usr/local/bin:$PATH \ + PGDATA=/home/postgres/data + +# Copy PostgreSQL and extensions from builder +COPY --from=builder /usr/local/pgsql /usr/local/pgsql +COPY --from=builder /usr/local/lib/libsodium* /usr/local/lib/ +COPY --from=builder /usr/local/include/sodium* /usr/local/include/ +COPY --from=builder /usr/local/share/perl /usr/local/share/perl +COPY --from=builder /usr/local/lib/x86_64-linux-gnu/perl /usr/local/lib/x86_64-linux-gnu/perl +COPY --from=builder /usr/local/bin/pg_prove /usr/local/bin/ + +# Create postgres user +RUN groupadd -r postgres && \ + useradd --no-log-init -r -m -s /bin/bash -g postgres -G sudo postgres && \ + echo "postgres ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/postgres && \ + chmod 0440 /etc/sudoers.d/postgres + +# Setup getkey script +RUN mkdir -p /usr/local/pgsql/share/extension && \ + cp /usr/local/pgsql/share/extension/pgsodium_getkey_urandom.sh \ + /usr/local/pgsql/share/extension/pgsodium_getkey 2>/dev/null || true +COPY --from=builder /build/pgsodium/getkey_scripts/pgsodium_getkey_urandom.sh \ + /usr/local/pgsql/share/extension/pgsodium_getkey +RUN sed -i 's/exit//g' /usr/local/pgsql/share/extension/pgsodium_getkey && \ + chmod +x /usr/local/pgsql/share/extension/pgsodium_getkey && \ + cp /usr/local/pgsql/share/extension/pgsodium_getkey /getkey + +# Update library cache +RUN ldconfig + +# Initialize database as postgres user USER postgres -RUN initdb -D "$PGDATA" +WORKDIR /home/postgres +RUN mkdir -p "$PGDATA" && \ + initdb -D "$PGDATA" + EXPOSE 5432 -CMD ["/usr/bin/postgres"] +CMD ["postgres", "-D", "/home/postgres/data"] diff --git a/src/aead.c b/src/aead.c index 1d3ce8e..60d8c99 100644 --- a/src/aead.c +++ b/src/aead.c @@ -15,7 +15,7 @@ PG_FUNCTION_INFO_V1 (pgsodium_crypto_aead_ietf_noncegen); Datum pgsodium_crypto_aead_ietf_noncegen (PG_FUNCTION_ARGS) { - int result_size = + size_t result_size = VARHDRSZ + crypto_aead_chacha20poly1305_IETF_NPUBBYTES; bytea *result = _pgsodium_zalloc_bytea (result_size); randombytes_buf (VARDATA (result), @@ -165,8 +165,8 @@ pgsodium_crypto_aead_ietf_encrypt_by_id (PG_FUNCTION_ARGS) pgsodium_derive_helper (key_id, crypto_aead_chacha20poly1305_IETF_KEYBYTES, context); result_size = - VARSIZE_ANY (message) + crypto_aead_chacha20poly1305_IETF_ABYTES; - result = _pgsodium_zalloc_bytea (result_size); + VARSIZE_ANY_EXHDR (message) + crypto_aead_chacha20poly1305_IETF_ABYTES; + result = _pgsodium_zalloc_bytea (result_size + VARHDRSZ); crypto_aead_chacha20poly1305_ietf_encrypt (PGSODIUM_UCHARDATA (result), &result_size, PGSODIUM_UCHARDATA (message), @@ -174,8 +174,6 @@ pgsodium_crypto_aead_ietf_encrypt_by_id (PG_FUNCTION_ARGS) associated != NULL ? PGSODIUM_UCHARDATA_ANY (associated) : NULL, associated != NULL ? VARSIZE_ANY_EXHDR (associated) : 0, NULL, PGSODIUM_UCHARDATA (nonce), PGSODIUM_UCHARDATA (key)); - SET_VARSIZE (result, - VARHDRSZ + result_size + crypto_aead_chacha20poly1305_IETF_ABYTES); PG_RETURN_BYTEA_P (result); } @@ -221,9 +219,9 @@ pgsodium_crypto_aead_ietf_decrypt_by_id (PG_FUNCTION_ARGS) pgsodium_derive_helper (key_id, crypto_aead_chacha20poly1305_IETF_KEYBYTES, context); - ciphertext_len = VARSIZE_ANY_EXHDR (ciphertext) - - crypto_aead_chacha20poly1305_IETF_ABYTES; - result = _pgsodium_zalloc_bytea (ciphertext_len); + ciphertext_len = VARSIZE_ANY_EXHDR (ciphertext); + result = _pgsodium_zalloc_bytea (ciphertext_len + VARHDRSZ - + crypto_aead_chacha20poly1305_IETF_ABYTES); success = crypto_aead_chacha20poly1305_ietf_decrypt ( @@ -254,7 +252,7 @@ PGDLLEXPORT PG_FUNCTION_INFO_V1 (pgsodium_crypto_aead_det_noncegen); Datum pgsodium_crypto_aead_det_noncegen (PG_FUNCTION_ARGS) { - int result_size = VARHDRSZ + crypto_aead_det_xchacha20_NONCEBYTES; + size_t result_size = VARHDRSZ + crypto_aead_det_xchacha20_NONCEBYTES; bytea *result = _pgsodium_zalloc_bytea (result_size); randombytes_buf (VARDATA (result), crypto_aead_det_xchacha20_NONCEBYTES); PG_RETURN_BYTEA_P (result); diff --git a/src/auth.c b/src/auth.c index 6410e4e..65c45ab 100644 --- a/src/auth.c +++ b/src/auth.c @@ -109,7 +109,7 @@ pgsodium_crypto_auth_verify_by_id (PG_FUNCTION_ARGS) key_id = PG_GETARG_INT64 (2); context = PG_GETARG_BYTEA_PP (3); - key = pgsodium_derive_helper (key_id, crypto_secretbox_KEYBYTES, context); + key = pgsodium_derive_helper (key_id, crypto_auth_KEYBYTES, context); ERRORIF (VARSIZE_ANY_EXHDR (mac) != crypto_auth_BYTES, "%s: invalid mac"); ERRORIF (VARSIZE_ANY_EXHDR (key) != crypto_auth_KEYBYTES, diff --git a/src/box.c b/src/box.c index 5f09769..f0ba3d0 100644 --- a/src/box.c +++ b/src/box.c @@ -303,7 +303,7 @@ pgsodium_crypto_box_seal_open (PG_FUNCTION_ARGS) ERRORIF (VARSIZE_ANY_EXHDR (ciphertext) <= crypto_box_SEALBYTES, "%s: invalid message"); - result_size = VARSIZE (ciphertext) - crypto_box_SEALBYTES; + result_size = VARSIZE_ANY (ciphertext) - crypto_box_SEALBYTES; result = _pgsodium_zalloc_bytea (result_size); success = crypto_box_seal_open ( PGSODIUM_UCHARDATA (result), diff --git a/src/secretbox.c b/src/secretbox.c index 3cc3ab9..cc7cc40 100644 --- a/src/secretbox.c +++ b/src/secretbox.c @@ -31,7 +31,7 @@ PG_FUNCTION_INFO_V1 (pgsodium_crypto_secretbox_noncegen); Datum pgsodium_crypto_secretbox_noncegen (PG_FUNCTION_ARGS) { - int result_size = VARHDRSZ + crypto_secretbox_NONCEBYTES; + size_t result_size = VARHDRSZ + crypto_secretbox_NONCEBYTES; bytea *result = _pgsodium_zalloc_bytea (result_size); randombytes_buf (VARDATA (result), crypto_secretbox_NONCEBYTES); PG_RETURN_BYTEA_P (result); diff --git a/test.sh b/test.sh index 372335c..811b391 100755 --- a/test.sh +++ b/test.sh @@ -2,7 +2,7 @@ set -e -versions=${1:-13 14 15 16} +versions=${1:-14.19 15.14 16.10 17.6 18.0} for version in $versions do diff --git a/test/pgsodium_schema.sql b/test/pgsodium_schema.sql index b182383..4aa6dcc 100644 --- a/test/pgsodium_schema.sql +++ b/test/pgsodium_schema.sql @@ -177,7 +177,33 @@ SELECT bag_eq($$ ('view pgsodium.masking_rule' ::text), ('view pgsodium.valid_key' ::text), ('view pgsodium.seclabel' ::text) - $$, + $$ || + -- PostgreSQL 17+ automatically creates array types for composite types + CASE WHEN current_setting('server_version_num')::int >= 170000 THEN + $$ UNION VALUES + ('type pgsodium._key_id_context[]' ::text), + ('type pgsodium.crypto_box_keypair[]' ::text), + ('type pgsodium.crypto_kx_keypair[]' ::text), + ('type pgsodium.crypto_kx_session[]' ::text), + ('type pgsodium.crypto_sign_keypair[]' ::text), + ('type pgsodium.crypto_signcrypt_keypair[]' ::text), + ('type pgsodium.crypto_signcrypt_state_key[]' ::text), + ('type pgsodium.key[]' ::text), + ('type pgsodium.key_status[]' ::text), + ('type pgsodium.key_type[]' ::text), + ('type pgsodium.decrypted_key' ::text), + ('type pgsodium.decrypted_key[]' ::text), + ('type pgsodium.mask_columns' ::text), + ('type pgsodium.mask_columns[]' ::text), + ('type pgsodium.masking_rule' ::text), + ('type pgsodium.masking_rule[]' ::text), + ('type pgsodium.seclabel' ::text), + ('type pgsodium.seclabel[]' ::text), + ('type pgsodium.valid_key' ::text), + ('type pgsodium.valid_key[]' ::text), + ('type pgsodium.key' ::text) + $$ + ELSE '' END, 'Check extension object list'); @@ -339,7 +365,18 @@ SELECT results_eq( ARRAY[ 'key_key_context_check', 'pgsodium_raw', - 'key_parent_key_fkey', + 'key_parent_key_fkey' + ]::name[] || +-- PostgreSQL 18+ automatically creates NOT NULL constraints as named constraints +CASE WHEN current_setting('server_version_num')::int >= 180000 THEN + ARRAY[ + 'key_created_not_null', + 'key_id_not_null' + ]::name[] +ELSE + ARRAY[]::name[] +END || + ARRAY[ 'key_pkey', 'pgsodium_key_unique_name' ]::name[],