お断り: 本記事は C2PA Technical Specification v2.3(2026年4月時点)、c2pa-rs および c2patool の公式ドキュメントとソースコードを筆者が読解・整理したものです。SDK やツールのバージョンにより CLI フラグ名や挙動は変わる可能性があります。実装の根拠として用いる際は、必ず各ライブラリの最新ドキュメントおよびC2PA 公式仕様をご確認ください。本記事に誤りや古くなった箇所を見つけられた場合は、記事末尾のフィードバック枠よりお知らせいただけると助かります。
はじめに
C2PA 検証の「Trust」という概念を頭で理解しても、実際に Untrusted → Trusted の状態変化を目で見ないと、どうも腑に落ちないところがあります。そこで本記事では手を動かすほうに振り切って、OpenSSL で自前の Root CA と EE 証明書を作り、c2pa-rs で署名し、c2patool で検証するところまでを一気通貫でやってみます。
ゴールは以下の 2 点です。
- 何も工夫せず署名した状態だと、c2patool の検証結果に
signingCredential.untrustedが出ることを確認する - 自前の Root CA をトラストアンカーに登録すると、同じ画像の同じ Manifest が
signingCredential.trustedになる、という状態変化を体験する
C2PA の Manifest や Trust List の概念は第4回と第7回で整理しているので、用語が気になったら適宜参照してください。
この記事で組み立てる全体像
ざっとこんな流れで進めます。上から順に、証明書を用意 → 署名 → 検証、という 3 段構成です。
(素の画像)"] end subgraph S2["Step 2: 証明書を作る"] CA["Root CA
ca.pem / ca.key"] EE["EE 証明書
ee.pem / ee.key"] CA -->|発行| EE end subgraph S3["Step 3: 署名"] SIGN["c2pa-rs で署名"] OUT["output.jpg
(Manifest 入り)"] SIGN --> OUT end subgraph S45["Step 4-5: 検証"] VER{"c2patool で
チェーン照合"} NG["untrusted"] OK["trusted"] VER -->|アンカー無し| NG VER -->|ca.pem をアンカーに登録| OK end IMG --> SIGN EE -->|chain.pem として渡す| SIGN OUT --> VER CA -->|--trust_anchors| VER
登場する用語を先に整理
この記事は OpenSSL と c2pa-rs と c2patool を往復するので、証明書まわりの用語がそれなりに出てきます。最初にざっと目を通しておくと、後のコマンドを読むときに迷子になりにくいです。ざっくり説明しているため、正確な内容を知りたい方は別途ググっていただければと思います。
| 用語 | ざっくり説明 | どこで出てくるか |
|---|---|---|
| openssl | 鍵と証明書を作ることができるコマンドラインツール。openssl ecparam / openssl req / openssl x509 を叩いて鍵や証明書を生成する | Step 2 全般 |
| Root CA(ルート認証局) | 信頼の起点になる自己署名証明書。ほかの証明書に「この人は本物です」と署名する権限を持つ | ca.pem。Step 2 で作って、Step 5 でトラストアンカーに登録 |
| EE 証明書(End-Entity) | チェーンの末端にある、実際にモノ・人・サーバーを指す証明書。これ以上下位には署名できない | ee.pem。C2PA では「この画像に署名した署名者」にあたる |
| 証明書チェーン | EE 証明書から Root CA までを縦に並べた束。検証側はチェーンをたどって Root まで遡れるかを確認する | chain.pem(= ee.pem + ca.pem)。c2pa-rs に渡すのはこちら |
| CSR(Certificate Signing Request) | EE 側が「この公開鍵と情報で証明書を発行してほしい」と CA に出す申請 | ee.csr。openssl req -new が作る中間ファイル |
| PEM | 証明書や鍵を -----BEGIN HOGEHOGE----- のような形で始まるフォーマットで書かれたファイル。cat で素直に連結できる | .pem 拡張子のファイル全部 |
| ECDSA P-256(prime256v1) | 楕円曲線暗号による署名アルゴリズム。C2PA が許容する署名方式のうち無難な選択肢 | openssl ecparam -name prime256v1 |
| keyUsage | 証明書の「基本的な用途」を宣言する拡張。digitalSignature を入れると署名用途で使える | v3_ee.cnf の keyUsage |
| extendedKeyUsage(EKU) | keyUsage の追加用途。どんな種類の署名に使っていいかを OID で列挙する | v3_ee.cnf の extendedKeyUsage |
| OID | 用途や拡張を識別する国際的な番号体系。ドット区切りの数字列で表現する | 今回は Claim Signing 用 OID を使用(固定値) |
| Claim Signing 用 OID | C2PA の Claim 署名専用であることを示す OID 1.3.6.1.4.1.311.76.59.1.9 | v3_ee.cnf の extendedKeyUsage に記述 |
| Claim Signing 用 EKU | 上記 OID を EKU に入れた状態そのもの。これが無いと c2pa-rs が署名時点で証明書を受け付けない | EE 証明書の条件として Step 2 冒頭で触れる |
| トラストアンカー | 検証側が「ここから下のチェーンは信頼する」と決めた起点の証明書。今回は Root CA の PEM | --trust_anchors=ca.pem |
| C2PA Trust List | C2PA 公式が管理する、信頼できる Root CA 一覧の PEM。公式と自前を連結すれば両方同時に信頼できる | Step 5 末尾の anchors.pem |
この表の中で、手で書くのは ca.pem(Root CA)と ee.pem(EE 証明書)の 2 枚だけで、残りはそこから派生して出来るファイルです。
事前準備
使うツールは以下のとおりです。執筆時点の手元環境のバージョンを記載しておきます。
- Rust 1.94.0
- OpenSSL 3.6.2(自前 CA の発行用)
- c2patool 0.26.15(
trustサブコマンドと--trust_anchorsオプションを使う)
c2patool は cargo で入れるのが一番ラクです。
cargo install c2patool
c2patool --version
# => c2patool 0.26.15
作業ディレクトリを切っておきます。以降のコマンドはとくに断りがなければ、この /tmp/c2pa-trust-anchor/ をカレントにして実行する前提です。パスが .. や相対になっている箇所も、ここが起点だと思って読んでください。
cd /tmp
mkdir -p c2pa-trust-anchor && cd c2pa-trust-anchor
pwd
# => /tmp/c2pa-trust-anchor
Step 1: サンプル画像を用意
NASA アポロ17号のパブリックドメイン画像を拝借してきます。第5回と同じく、c2pa-rs リポジトリのテストフィクスチャから取ってくるのが手軽です。
curl -sL -o input.jpg \
https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/earth_apollo17.jpg
まだ素の JPEG なので、念のため確認しておきます。
c2patool input.jpg
# => Error: No claim found
Manifest が入っていないことをここで見ておくと、後で署名後との差分がクリアになります。
Step 2: 自前の Root CA と EE 証明書を OpenSSL で発行
C2PA の署名で使う EE 証明書には、いくつか満たすべき技術要件があります。第7回で触れた条件のうち、自前で作る段階でちゃんと入れておかないといけないのはこのあたりです。
- EE 証明書の
keyUsageにdigitalSignatureを含める - EE 証明書の
extendedKeyUsageに Claim Signing 用 OID(1.3.6.1.4.1.311.76.59.1.9)を含める - Root CA の
basicConstraintsはcritical, CA:TRUEにしておく - 署名アルゴリズムは ECDSA P-256 を使う(C2PA 仕様で許可されているもののうち、いちばん無難な選択肢)
Claim Signing 用 EKU が入っていないと、c2pa-rs が署名時点で CertificateProfileError(InvalidCertificate) を返して署名自体を通してくれません(筆者も試しに抜いて動かして確認しました)。ここが地味に引っかかるポイントです。
設定ファイルを書く
まず Root CA 用と EE 用の OpenSSL 設定ファイルを作ります。
cat > v3_ca.cnf <<'EOF'
[req]
distinguished_name = dn
x509_extensions = v3_ca
prompt = no
[dn]
CN = TechThanks Test Root CA
O = TechThanks Test
[v3_ca]
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
EOF
cat > v3_ee.cnf <<'EOF'
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = 1.3.6.1.4.1.311.76.59.1.9
EOF
余談: この 2 つの cnf ファイルは何を宣言しているのか
設定ファイルの各行は「これから作る証明書にどんな情報・拡張を載せるか」を OpenSSL に伝える設計書です。-config / -extfile で読み込まれ、証明書発行時に X509v3 extensions として焼き込まれます。
v3_ca.cnf — Root CA 用
[req] セクションは openssl req コマンドの動作設定です。
distinguished_name = dn: Subject(発行先の名前)を[dn]セクションから読むx509_extensions = v3_ca:-x509で自己署名証明書を作るときの拡張を[v3_ca]から読むprompt = no: 対話プロンプトを出さずファイルの値をそのまま使う
[dn] セクションに書いた CN と O がそのまま Subject DN になります。自己署名なので、これが Issuer にもコピーされます。
[v3_ca] セクションが Root CA たる所以の本体です。
basicConstraints = critical, CA:TRUE: 「この証明書は CA である」と宣言。他の証明書に署名できるkeyUsage = critical, keyCertSign, cRLSign: 鍵の用途を制限。keyCertSignは証明書への署名、cRLSignは失効リストへの署名
v3_ee.cnf — EE(署名者)証明書用
こちらはセクションヘッダ無しでベタ書き。openssl x509 -req -extfile v3_ee.cnf で読むときは、ファイル全体が拡張セットとして解釈されます。
basicConstraints = CA:FALSE: 「この証明書は CA じゃない」= チェーンの末端。これより下には署名できないkeyUsage = critical, digitalSignature: データへの署名用途専用。keyCertSignが無いので他の証明書には署名不可extendedKeyUsage = 1.3.6.1.4.1.311.76.59.1.9: C2PA Claim Signing 専用の OID。これが無いと c2pa-rs が署名時点でCertificateProfileErrorを返して通してくれない
EE は「署名するだけの実働メンバー」、CA は「部下に権限を渡す管理職」、と役割が明確に分離されています。
critical フラグの意味
critical を付けた拡張は、検証ソフトが「この拡張の意味を知らない」場合に証明書全体を拒否します。付けないと無視されて通過してしまうので、信頼の根幹になる basicConstraints と keyUsage には必ず付けておきます。
なぜ Root 側と EE 側で設定ファイルを分けるのか
OpenSSL のコマンド体系では、Root CA 作成は openssl req -x509 -config v3_ca.cnf、EE 証明書発行は openssl x509 -req -extfile v3_ee.cnf で、読み込む設定形式が違います。req は [req] → [dn] → [v3_ca] という参照構造、x509 -extfile は「拡張だけ書いたファイル」をそのまま読むため、ファイルを分けて書いています。
実際に焼き込まれた結果を確認
cnf に書いた内容がそのまま証明書の拡張領域に入っていることを、作成後に確認できます。
openssl x509 -in ca.pem -noout -text | grep -A2 "X509v3"
# X509v3 Basic Constraints: critical
# CA:TRUE
# X509v3 Key Usage: critical
# Certificate Sign, CRL Sign
openssl x509 -in ee.pem -noout -text | grep -A1 "X509v3"
# X509v3 Basic Constraints:
# CA:FALSE
# X509v3 Key Usage: critical
# Digital Signature
# X509v3 Extended Key Usage:
# 1.3.6.1.4.1.311.76.59.1.9
Root CA の鍵と自己署名証明書を作る
# Root CA 秘密鍵(ECDSA P-256)
openssl ecparam -name prime256v1 -genkey -noout -out ca.key
# Root CA 自己署名証明書(10年有効)
openssl req -new -x509 -key ca.key -out ca.pem -days 3650 -config v3_ca.cnf
これで「TechThanks 自前のルート CA」ができました。
EE 証明書を CA に発行してもらう
EE 側の鍵を作って CSR を出し、先ほどの Root CA で署名してもらいます。
# EE 秘密鍵
openssl ecparam -name prime256v1 -genkey -noout -out ee.key
# CSR
openssl req -new -key ee.key -out ee.csr \
-subj "/CN=TechThanks Test Signer/O=TechThanks Test"
# CA 署名で EE 証明書を発行
openssl x509 -req -in ee.csr -CA ca.pem -CAkey ca.key -CAcreateserial \
-out ee.pem -days 365 -extfile v3_ee.cnf
c2pa-rs の create_signer::from_files には、EE 証明書と Root CA 証明書を連結した「証明書チェーン PEM」を渡す決まりです。並びは EE を先、Root CA を後ろにしておきます。
cat ee.pem ca.pem > chain.pem
中身を軽く確認しておきます。
openssl x509 -in ee.pem -noout -ext extendedKeyUsage
# => X509v3 Extended Key Usage:
# 1.3.6.1.4.1.311.76.59.1.9
Claim Signing EKU がちゃんと入っていることを確認できました。
ここまでで作った鍵・証明書・派生ファイルの関係を図にすると、こうなっています。EE 側は自分の鍵ペアから公開鍵だけを抜いて ee.csr(署名要求)を組み立て、Root CA に提出します。Root CA は受け取った CSR の公開鍵を取り出し、拡張を追加したうえで CA 秘密鍵で署名することで ee.pem を発行します。つまり ee.pem は EE が作るものではなく、あくまで CA が発行する成果物 という関係です。最後に EE 側が手元の ee.pem と配布された ca.pem を連結して chain.pem を組み立てる、という流れになります。
鍵ペア(秘密鍵+公開鍵)")] CSR["ee.csr
署名要求
(公開鍵+Subject+EE自己署名)"] EEKEY -->|公開鍵を載せて
EE秘密鍵で所有証明| CSR end subgraph CAside["Root CA(発行する側)"] CAKEY[("ca.key
鍵ペア(秘密鍵+公開鍵)")] CAPEM["ca.pem
自己署名証明書"] CAKEY -->|公開鍵を載せて
秘密鍵で自己署名| CAPEM end CSR -->|①CAに提出| EEPEM["ee.pem
EE 証明書
(CSRの公開鍵+CAの署名)"] CAKEY -->|②CA秘密鍵で署名して発行| EEPEM EEPEM --> CHAIN["chain.pem
= ee.pem + ca.pem"] CAPEM --> CHAIN
この時点で /tmp/c2pa-trust-anchor/ はこういう状態です。
tree
# .
# ├── ca.key # Root CA の秘密鍵
# ├── ca.pem # Root CA 証明書(← これを後で --trust_anchors に渡す)
# ├── ca.srl # openssl x509 -CAcreateserial が作るシリアル管理ファイル
# ├── chain.pem # ee.pem + ca.pem を連結したチェーン(署名時に渡す)
# ├── ee.csr # EE の証明書署名要求
# ├── ee.key # EE の秘密鍵(← これも署名時に渡す)
# ├── ee.pem # Root CA に署名された EE 証明書
# ├── input.jpg # 署名対象のサンプル画像
# ├── v3_ca.cnf
# └── v3_ee.cnf
これ以降のステップで主役になるのは ca.pem(検証側のトラストアンカー)、chain.pem と ee.key(署名側が使う)、そして input.jpg の 4 つです。
Step 3: c2pa-rs で自前の証明書を使って署名
Rust のプロジェクトを /tmp/c2pa-trust-anchor/signer/ に切ります。証明書や画像は親ディレクトリに置いたままにして、コード側から ../ で参照する構成にすると、ファイルが二重管理にならずに済みます。
# /tmp/c2pa-trust-anchor/ にいる前提
cargo new signer
cd signer
cargo add c2pa --features file_io
cargo add serde_json
src/main.rs を以下の内容に差し替えます。chain.pem / ee.key / input.jpg はひとつ上の階層にあるので、パスを ../ 付きで指定しています。
// src/main.rs
use c2pa::{create_signer, Builder, SigningAlg};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut builder = Builder::default()
.with_definition(r#"{
"title": "my_photo.jpg",
"claim_generator_info": [{
"name": "TechThanksTrustAnchorDemo",
"version": "1.0.0"
}],
"assertions": [{
"label": "c2pa.actions.v2",
"data": {
"actions": [{
"action": "c2pa.created",
"digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"
}]
},
"created": true
}]
}"#)?;
// 自前のチェーン PEM と EE 秘密鍵で署名者を作る
let signer = create_signer::from_files(
"../chain.pem",
"../ee.key",
SigningAlg::Es256,
Some("http://timestamp.digicert.com".to_string()),
)?;
builder.sign_file(&*signer, "../input.jpg", "../output.jpg")?;
println!("署名完了: ../output.jpg");
Ok(())
}
第5回で使った EphemeralSigner との違いは、create_signer::from_files で自前の PEM と鍵を渡しているところだけです。署名者を差し替えれば、Builder 側のコードは同じまま動きます。
ビルドして署名します。
cargo run
# => 署名完了: ../output.jpg
署名が終わったところで、作業ディレクトリ全体を見直しておきます(ビルド成果物の signer/target/ は大きいので除外)。
cd .. # /tmp/c2pa-trust-anchor/ に戻る
tree -I target
# .
# ├── ca.key
# ├── ca.pem
# ├── ca.srl
# ├── chain.pem
# ├── ee.csr
# ├── ee.key
# ├── ee.pem
# ├── input.jpg # 署名前の元画像
# ├── output.jpg # 自前 EE 証明書で署名した画像
# ├── signer
# │ ├── Cargo.lock
# │ ├── Cargo.toml
# │ └── src
# │ └── main.rs
# ├── v3_ca.cnf
# └── v3_ee.cnf
以降の c2patool の検証コマンドも、この /tmp/c2pa-trust-anchor/ をカレントにしたまま実行します。
Step 4: c2patool で検証(トラストアンカーなし)
まずはトラストアンカーを何も指定せず、素の状態で c2patool に食わせます。--detailed を付けると validation_results が JSON で返ってくるので、そこを抜き出します。
c2patool output.jpg --detailed | jq '.validation_results'
validation_results の中身はだいたいこんな形になります(抜粋)。
{
"activeManifest": {
"success": [
{ "code": "claimSignature.insideValidity" },
{ "code": "claimSignature.validated" },
{ "code": "assertion.hashedURI.match" },
{ "code": "assertion.dataHash.match" }
],
"informational": [
{ "code": "timeStamp.untrusted" }
],
"failure": [
{
"code": "signingCredential.untrusted",
"explanation": "signing certificate untrusted"
}
]
}
}
claimSignature.insideValidity や assertion.hashedURI.match は成功していて、Manifest 自体の整合性は取れています。一方で signingCredential.untrusted が failure 側に入っている。これは「署名自体は正しいけど、この署名者(証明書)を誰が信頼しているのか分からない」という C2PA なりの言い分です。
ここまでが「自前の CA を誰にも信じてもらえていない」状態です。
Step 5: 自前 Root CA をトラストアンカーに登録
C2PA 仕様の Section 14.4.1 C2PA Signers では、検証側は C2PA 公式の Trust List を必ず含めたうえで、独自のトラストアンカーを追加してもよい、と定められています。今回はそこで言う「独自のトラストアンカー」に、自前の ca.pem を足し込んでやるわけです。
検証側が実際に何を見ているかを図にすると、こうなります。output.jpg に埋まっている EE 証明書から Root CA までのチェーンをたどって、その Root がトラストアンカー一覧と一致するか、で判定が切り替わります。
(ee.pem)"] CAIN["Root CA 証明書
(ca.pem)"] EEIN -->|チェーンをたどる| CAIN end CAIN --> MATCH{"Root がアンカーに
登録されているか?"} ANCHOR[("--trust_anchors
で渡した PEM")] ANCHOR --> MATCH MATCH -->|一致| OK["signingCredential.trusted"] MATCH -->|未登録| NG["signingCredential.untrusted"]
c2patool の trust サブコマンドでは --trust_anchors オプションで、トラストアンカーを並べた PEM ファイルを指定できます(環境変数 C2PATOOL_TRUST_ANCHORS でも可)。複数の Root CA を信頼したい場合は、PEM を縦に並べた 1 ファイルにしておけば OK です。
--detailed は trust サブコマンドの前に置く必要があります。/tmp/c2pa-trust-anchor/ をカレントにしたまま、同じディレクトリにある ca.pem を渡します。
c2patool output.jpg --detailed trust --trust_anchors=ca.pem \
| jq '.validation_results'
{
"activeManifest": {
"success": [
{ "code": "signingCredential.trusted",
"explanation": "signing certificate trusted, found in System trust anchors" },
{ "code": "claimSignature.insideValidity" },
{ "code": "claimSignature.validated" },
{ "code": "assertion.hashedURI.match" },
{ "code": "assertion.dataHash.match" }
],
"informational": [
{ "code": "timeStamp.untrusted" }
],
"failure": []
}
}
failure が空になり、signingCredential.trusted が success に積まれました。同じ output.jpg に対して、検証側のトラストアンカー設定を変えただけで判定が切り替わる、というのが C2PA の「Trust」の実体です。画像側には何も手を加えていません。
環境変数で設定しておくと便利
CI や検証サーバーでは、毎回 CLI に渡すより環境変数にしておくほうがラクです。
# /tmp/c2pa-trust-anchor/ をカレントにした状態で
export C2PATOOL_TRUST_ANCHORS="$(pwd)/ca.pem"
c2patool output.jpg --detailed trust \
| jq '.validation_results.activeManifest.success[] | select(.code=="signingCredential.trusted")'
# => { "code": "signingCredential.trusted", ... }
C2PA 公式の Trust List も合わせて使いたいときは、公式 PEM と自前 PEM を連結した 1 ファイルを作って、それを --trust_anchors に渡せば両方信頼できます。こちらもカレントが /tmp/c2pa-trust-anchor/ 前提です(ここを外して signer/ 等で cat ca.pem してしまうと、ファイルが見つからず Trust List 側しか連結されないので注意)。
# /tmp/c2pa-trust-anchor/ にいることを確認
pwd
# => /tmp/c2pa-trust-anchor
curl -sL -o c2pa-trust-list.pem \
https://raw.githubusercontent.com/c2pa-org/conformance-public/refs/heads/main/trust-list/C2PA-TRUST-LIST.pem
cat c2pa-trust-list.pem ca.pem > anchors.pem
# 連結できたか軽く確認(Trust List の枚数 + 自前 Root CA 1 枚になっていれば OK)
grep -c "BEGIN CERTIFICATE" anchors.pem
c2patool output.jpg --detailed trust --trust_anchors=anchors.pem \
| jq '.validation_results'
運用上は、自前 CA のローテーションや失効を運用チーム側で管理しつつ、C2PA 公式の Trust List は定期的に上書きで取りに行く、みたいな構成になります。
どういうときに使う話なのか
この「自前 CA をトラストアンカーに入れる」やり方は、次のようなシチュエーションで効いてきます。
- 社内ワークフロー用の C2PA 署名基盤を先行して作りたい。公式 Trust List への登録審査はまだだけど、検証側(社内の画像レビューツールなど)を自前で用意するなら、プライベートな CA で回しておける
- 外部認証局から C2PA 証明書を取得するプロセスに入る前に、PoC や検証環境で Trusted 状態の挙動まで通しで検証しておきたい
- 公式 Trust List とは別に、「このパートナー企業の署名者だけは信頼する」といった、取引先単位のトラスト関係を作りたい
逆に、一般公開する画像や、不特定多数に検証してもらうコンテンツに対しては、自前 CA を信じてくれるのは自分たちだけなので意味がありません。公開向けは素直に公式 Trust List の CA で発行してもらう、というのが筋です。このあたりの棲み分けは第7回でも触れています。
まとめ
自前で作った Root CA を c2patool のトラストアンカーに追加すると、同じ output.jpg の検証結果が signingCredential.untrusted → signingCredential.trusted に切り替わる、というのを一気通貫で見てきました。ポイントをざっくりまとめておきます。
- 署名側(c2pa-rs)は EE 証明書の EKU に Claim Signing OID(
1.3.6.1.4.1.311.76.59.1.9)を入れておく - 検証側(c2patool)は
--trust_anchorsで、信頼したい Root CA の PEM を渡す - Trusted かどうかは画像に焼き付いた情報ではなく、検証側の設定で決まる
C2PA の Trust 評価は、この「検証者がどの CA を信頼するか」を差し替えられる仕組みの上に成り立っています。社内ワークフロー向けに自前 CA を回すか、公式 CA から発行してもらうかの判断も、結局はこの差し替え単位で考えると整理しやすいです。
参考リンク
- C2PA Technical Specification v2.3
- C2PA Trust List(GitHub)
- c2pa-rs
- c2patool 使い方ドキュメント
- C2PA Certificate Policy
TechThanks は Content Credentials の実装支援に取り組んでいます。C2PA の署名基盤構築や検証パイプラインの設計、自前 CA 運用の設計までお気軽にご相談ください。