Skip to content

Commit 5f6b761

Browse files
lasnownSupremeSovietfpandyz
authored
feat: implement JPEG and PDF C2PA signing functionality
Added features: - Python implementation for core C2PA objects - Python implementation for injecting C2PA manifests into JPEG/JPEG and PDF files - c2pie CLI tool for file signing --------- Co-authored-by: SupremeSoviet <112272101+SupremeSoviet@users.noreply.github.com> Co-authored-by: fpandyz <5389368+fpandyz@users.noreply.github.com>
1 parent ed9b169 commit 5f6b761

File tree

17 files changed

+547
-467
lines changed

17 files changed

+547
-467
lines changed

.env-example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
C2PIE_KEY_FILEPATH=tests/credentials/ps256.pem
2-
C2PIE_CERT_FILEPATH=tests/credentials/ps256.pub
1+
C2PIE_PRIVATE_KEY_FILE=tests/credentials/private-key.pem
2+
C2PIE_CERTIFICATE_CHAIN_FILE=tests/credentials/certificate-chain.pub
33
TEST_PDF_PATH=tests/test_files/test_doc.pdf
44
TEST_IMAGE_PATH=tests/test_files/test_image.jpg

.github/workflows/lint-and-test.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ name: Linting and Testing
22

33
on:
44
push:
5-
branches:
6-
- '**'
5+
branches-ignore:
6+
- master
7+
- release/**
78
paths-ignore:
89
- '**.md'
910
- 'docs/**'
@@ -175,8 +176,8 @@ jobs:
175176
--cov=c2pie \
176177
-v
177178
env:
178-
C2PIE_KEY_FILEPATH: ${{ vars.C2PIE_KEY_FILEPATH }}
179-
C2PIE_CERT_FILEPATH: ${{ vars.C2PIE_CERT_FILEPATH }}
179+
C2PIE_PRIVATE_KEY_FILE: ${{ vars.C2PIE_PRIVATE_KEY_FILE }}
180+
C2PIE_CERTIFICATE_CHAIN_FILE: ${{ vars.C2PIE_CERTIFICATE_CHAIN_FILE }}
180181

181182
- name: Upload coverage artifact
182183
if: (matrix.python-version == '3.12') && (matrix.os == 'ubuntu-latest')

.github/workflows/publish-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Package Publishing
22

33
on:
44
release:
5-
types: [created]
5+
types: [created, published]
66

77
permissions:
88
contents: write

.github/workflows/publish-release.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,18 @@ on:
44
push:
55
branches:
66
- master
7-
- release/**
8-
create:
9-
branches:
10-
- release/**
7+
- 'release/*'
118

129
permissions:
13-
contents: read
10+
contents: write
1411

1512
jobs:
1613
linting-and-testing:
1714
name: Linting and Testing
1815
uses: ./.github/workflows/lint-and-test.yml
1916
permissions:
20-
contents: write
2117
packages: read
18+
contents: write
2219

2320
release:
2421
name: Create and Publish Release
@@ -28,9 +25,6 @@ jobs:
2825
group: ${{ github.workflow }}-release-${{ github.ref_name }}
2926
cancel-in-progress: false
3027

31-
permissions:
32-
contents: write
33-
3428
steps:
3529
- name: Checkout Repository on Release Branch
3630
uses: actions/checkout@v4
@@ -88,7 +82,7 @@ jobs:
8882

8983
- name: Semantic Version Release
9084
id: release
91-
uses: python-semantic-release/python-semantic-release@v10.4.1
85+
uses: python-semantic-release/python-semantic-release@v8.3.0
9286
with:
9387
github_token: ${{ secrets.GITHUB_TOKEN }}
9488
git_committer_name: "github-actions"
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
name: Execute Readme Steps
2+
3+
on:
4+
push:
5+
branches:
6+
- feature/*
7+
8+
jobs:
9+
sign-steps:
10+
runs-on: ubuntu-24.04
11+
container: python:3.9.2-buster
12+
steps:
13+
- name: Generate Certificates, Install c2pie, and Sign Image and PDF
14+
run: |
15+
# Generate private key and certificate chain:
16+
openssl genpkey \
17+
-algorithm RSA-PSS \
18+
-pkeyopt rsa_keygen_bits:2048 \
19+
-pkeyopt rsa_pss_keygen_md:sha256 \
20+
-pkeyopt rsa_pss_keygen_mgf1_md:sha256 \
21+
-pkeyopt rsa_pss_keygen_saltlen:32 \
22+
-out private_key.key
23+
24+
openssl req -new -x509 \
25+
-key private_key.key \
26+
-sha256 -days 825 \
27+
-subj "/C=US/ST=CA/L=Somewhere/O=C2PA Test Signing Cert/OU=FOR TESTING_ONLY/CN=C2PA PSS Signer/emailAddress=pie@example.com" \
28+
-addext "basicConstraints=critical,CA:false" \
29+
-addext "keyUsage=critical,digitalSignature,nonRepudiation" \
30+
-addext "extendedKeyUsage=critical,emailProtection" \
31+
-out certificate_chain.pem
32+
33+
# Export created private key and certificate chain files into env variables:
34+
export C2PIE_PRIVATE_KEY_FILE=./private_key.key
35+
export C2PIE_CERTIFICATE_CHAIN_FILE=./certificate_chain.pem
36+
37+
# Install package
38+
pip install c2pie
39+
40+
# Download test image and PDF from this repo
41+
wget https://raw.githubusercontent.com/TourmalineCore/c2pie/refs/heads/master/example_app/test_files/test_image.jpg
42+
wget https://raw.githubusercontent.com/TourmalineCore/c2pie/refs/heads/master/example_app/test_files/test_doc.pdf
43+
44+
# Sign files
45+
c2pie sign --input_file ./test_image.jpg
46+
c2pie sign --input_file ./test_doc.pdf
47+
48+
- name: Upload Signed Image
49+
uses: actions/upload-artifact@v4
50+
with:
51+
name: signed_test_image
52+
path: signed_test_image.jpg
53+
54+
- name: Upload Signed PDF
55+
uses: actions/upload-artifact@v4
56+
with:
57+
name: signed_test_doc
58+
path: signed_test_doc.pdf
59+
60+
verify-steps:
61+
needs: sign-steps
62+
runs-on: ubuntu-24.04
63+
steps:
64+
- name: Download Signed Image
65+
uses: actions/download-artifact@v5
66+
with:
67+
name: signed_test_image
68+
69+
- name: Download Signed PDF
70+
uses: actions/download-artifact@v5
71+
with:
72+
name: signed_test_doc
73+
74+
- name: Install Rust toolchain and c2patool
75+
uses: baptiste0928/cargo-install@v3
76+
with:
77+
crate: c2patool
78+
79+
- name: Validate Signed Image and PDF
80+
run: |
81+
c2patool signed_test_image.jpg
82+
echo "$(c2patool signed_test_image.jpg)" >> image_validation_results.json
83+
c2patool signed_test_doc.pdf
84+
echo "$(c2patool signed_test_doc.pdf)" >> pdf_validation_results.json
85+
86+
- name: Download jq and Get validation results
87+
id: validation_check
88+
run: |
89+
sudo apt install jq
90+
echo "image_validation_results=$(jq -r .validation_state image_validation_results.json)" >> $GITHUB_OUTPUT
91+
echo "pdf_validation_results=$(jq -r .validation_state pdf_validation_results.json)" >> $GITHUB_OUTPUT
92+
93+
- name: Debug validation check
94+
run: |
95+
echo "Image validation result extracted from file: ${{ steps.validation_check.outputs.image_validation_results }}"
96+
echo "PDF validation result extracted from file: ${{ steps.validation_check.outputs.pdf_validation_results }}"
97+
98+
- name: Fail if validation failed
99+
if: ${{ steps.validation_check.outputs.image_validation_results == 'Invalid' || steps.validation_check.outputs.pdf_validation_results == 'Invalid' }}
100+
run: |
101+
echo "Invalid C2PA signature in one of the files. Check logs of the previous step."
102+
exit 1
103+

0 commit comments

Comments
 (0)