電子署名
v0.3.38で追加。PDF Oxideは/AcroForm /Fields → /Sigから署名を読み取り、/Contents内のCMSエンベロープを検査し、RFC 5652 §5.4の署名者属性チェックを埋め込み証明書に対して実行します。また、呼び出し元が提供したドキュメントバイトに対して §11.2のmessageDigestチェックも実行します。
対象範囲。 このページは既存署名の読み取りと検証を扱います: 列挙、CMSの暗号チェック、PAdESレベルの分類、DSS検査、RFC 3161タイムスタンプ。署名を作成するには — PKCS#12/PEM資格情報を読み込んでCMSまたはPAdES B-B/B-T/B-LT署名を生成する — PDFへの署名: 電子署名とPAdESを参照してください(v0.3.50でリリース、issue #235)。
検証内容
- RSA-PKCS#1 v1.5 over SHA-1 / SHA-256 / SHA-384 / SHA-512 — 実質的にすべての署名済みPDFで使用されるパディング方式 —
Valid/Invalidを返します。 - RSA-PSS と ECDSA は
Unknown/UnsupportedFeatureExceptionとして返されます。これらが必要な呼び出し元は、Signature.GetCertificate()/.get_certificate()で埋め込み証明書を取得して独自のチェックを実行できます。 - 信頼ルートの検索、有効期限ウィンドウ、署名者DNは、埋め込み証明書の検証結果に記録されます。
クイックサンプル
Rust
use pdf_oxide::PdfDocument;
let doc = PdfDocument::open("signed.pdf")?;
for sig in doc.signatures() {
println!("{} → {:?}", sig.signer_name(), sig.verify()?);
// End-to-end with document bytes
let pdf_bytes = std::fs::read("signed.pdf")?;
println!("detached ok = {:?}", sig.verify_detached(&pdf_bytes)?);
// Cert inspection + trust-root / expiry / signer DN
let result = pdf_oxide::SignatureVerifier::verify(&sig, &pdf_bytes)?;
println!("signer DN = {}", result.signer_dn);
}
Python
from pdf_oxide import PdfDocument
doc = PdfDocument("signed.pdf")
for sig in doc.signatures():
print(sig.signer_name, "→", sig.verify())
# End-to-end with document bytes
with open("signed.pdf", "rb") as f:
pdf_bytes = f.read()
for sig in doc.signatures():
print("detached ok =", sig.verify_detached(pdf_bytes))
Node / TypeScript
import { PdfDocument } from "pdf-oxide";
import { readFileSync } from "fs";
const doc = PdfDocument.open("signed.pdf");
for (const sig of doc.signatures()) {
console.log(sig.signerName, "→", sig.verify());
console.log("detached ok =", sig.verifyDetached(readFileSync("signed.pdf")));
}
C#
using PdfOxide;
using var doc = PdfDocument.Open("signed.pdf");
foreach (var sig in doc.Signatures)
{
Console.WriteLine($"{sig.SignerName} → {sig.Verify()}");
var cert = sig.GetCertificate();
Console.WriteLine($"subject={cert.Subject} issuer={cert.Issuer} valid={cert.IsValid}");
}
Go (CGo-only)
import (
"fmt"
"os"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
doc, _ := pdfoxide.Open("signed.pdf")
defer doc.Close()
pdfBytes, _ := os.ReadFile("signed.pdf")
sigs, _ := doc.Signatures()
for _, sig := range sigs {
ok, _ := sig.Verify()
fmt.Printf("%s → %v\n", sig.SignerName, ok)
// End-to-end with document bytes
detachedOk, _ := sig.VerifyDetached(pdfBytes)
fmt.Println("detached ok =", detachedOk)
}
WASM
import init, { PdfDocument } from "pdf-oxide-wasm/web";
await init();
const doc = new PdfDocument(bytes);
for (const sig of doc.signatures()) {
console.log(sig.signerName, "→", sig.verify());
}
C++
#include <pdf_oxide/pdf_oxide.hpp>
#include <fstream>
auto doc = pdf_oxide::Document::open("signed.pdf");
std::ifstream f("signed.pdf", std::ios::binary);
std::vector<std::uint8_t> pdf_bytes((std::istreambuf_iterator<char>(f)), {});
for (int i = 0; i < doc.get_signature_count(); ++i) {
auto sig = doc.get_signature(i);
std::cout << sig.signer_name() << " → " << sig.verify() << "\n"; // 1 valid / 0 invalid / -1 unknown
std::cout << "detached ok = " << sig.verify_detached(pdf_bytes) << "\n";
}
Swift
import PdfOxide
import Foundation
let doc = try Document.open("signed.pdf")
let pdfBytes = [UInt8](try Data(contentsOf: URL(fileURLWithPath: "signed.pdf")))
for i in 0..<(try doc.signatureCount()) {
guard let sig = try doc.signature(i) else { continue }
print(try sig.signerName(), "→", try sig.verify()) // 1 valid / 0 invalid / -1 unknown
print("detached ok =", try sig.verifyDetached(pdfBytes))
}
Dart
import 'dart:io';
import 'package:pdf_oxide/pdf_oxide.dart';
final doc = PdfDocument.open('signed.pdf');
final pdfBytes = File('signed.pdf').readAsBytesSync();
for (var i = 0; i < doc.getSignatureCount(); i++) {
final sig = doc.getSignature(i);
print('${sig.signerName} → ${sig.verify()}'); // 1 valid / 0 invalid / -1 unknown
print('detached ok = ${sig.verifyDetached(pdfBytes)}');
}
R
library(pdfoxide)
doc <- pdf_open("signed.pdf")
pdf_bytes <- readBin("signed.pdf", "raw", file.info("signed.pdf")$size)
for (i in seq_len(pdf_signature_count(doc)) - 1L) {
sig <- pdf_get_signature(doc, i)
cat(pdf_signature_signer_name(sig), "→", pdf_signature_verify(sig), "\n") # 1 valid / 0 invalid / -1 unknown
cat("detached ok =", pdf_signature_verify_detached(sig, pdf_bytes), "\n")
}
Julia
using PdfOxide
doc = open_document("signed.pdf")
pdf_bytes = read("signed.pdf")
for i in 0:(get_signature_count(doc) - 1)
sig = get_signature(doc, i)
println(signature_get_signer_name(sig), " → ", signature_verify(sig)) # 1 valid / 0 invalid / -1 unknown
println("detached ok = ", signature_verify_detached(sig, pdf_bytes))
end
Zig
const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;
var doc = try pdf_oxide.Document.open("signed.pdf");
const pdf_bytes = try std.fs.cwd().readFileAlloc(a, "signed.pdf", 1 << 30);
var i: i32 = 0;
const count = try doc.signatureCount();
while (i < count) : (i += 1) {
var sig = try doc.signature(i);
const name = try sig.signerName(a);
std.debug.print("{s} → {}\n", .{ name, try sig.verify() }); // 1 valid / 0 invalid / -1 unknown
std.debug.print("detached ok = {}\n", .{try sig.verifyDetached(pdf_bytes)});
}
Objective-C
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"signed.pdf" error:&err];
NSData *pdfBytes = [NSData dataWithContentsOfFile:@"signed.pdf"];
int32_t count = [doc signatureCountWithError:&err];
for (int32_t i = 0; i < count; i++) {
POXSignatureInfo *sig = [doc signatureAtIndex:i error:&err];
NSLog(@"%@ → %d", [sig signerNameError:&err], [sig verifyError:&err]); // 1 valid / 0 invalid / -1 unknown
NSLog(@"detached ok = %d", [sig verifyDetached:pdfBytes error:&err]);
}
Elixir
{:ok, doc} = PdfOxide.open("signed.pdf")
pdf_bytes = File.read!("signed.pdf")
{:ok, count} = PdfOxide.signature_count(doc)
for i <- 0..(count - 1) do
{:ok, sig} = PdfOxide.signature(doc, i)
{:ok, name} = PdfOxide.signature_signer_name(sig)
{:ok, verdict} = PdfOxide.signature_verify(sig) # 1 valid / 0 invalid / -1 unknown
{:ok, detached} = PdfOxide.signature_verify_detached(sig, pdf_bytes)
IO.puts("#{name} → #{verdict}")
IO.puts("detached ok = #{detached}")
end
Signature
署名の列挙と検査。すべてのバインディングで利用可能。
| プロパティ / メソッド | 説明 |
|---|---|
.signer_name / .SignerName |
署名者の証明書からのCommon Name。C ABI / Swiftアクセサ: signing_name / signerName()。 |
.reason / .Reason |
署名理由(例: “このドキュメントを承認します”)。C ABI / Swiftアクセサ: signing_reason / signingReason()。 |
.location / .Location |
ロケーションフィールド。C ABI / Swiftアクセサ: signing_location / signingLocation()。 |
.contact_info |
連絡先情報フィールド |
.signing_time / .SigningTime |
CMSエンベロープのUTC署名時刻(C#ではDateTimeOffset?) |
.pades_level / padesLevel() |
CMS属性のみから分類されたPAdESベースライン(B_B/B_T)。B_LTには追加でドキュメント/DSSが必要 — 下記のdssと組み合わせて使用。 |
.has_timestamp() / hasTimestamp() |
この署名にRFC 3161タイムスタンプが埋め込まれている場合にTrue。 |
.add_timestamp(ts) / addTimestamp(_:) |
解析済みTimestampを署名に付加(C ABI / Swift)。 |
.verify() / .Verify() |
RFC 5652 §5.4の署名者属性チェックを埋め込み証明書に対して実行。Valid / Invalid / Unknownを返す。 |
.verify_detached(pdf_bytes) / .VerifyDetached(pdfBytes) |
呼び出し元が提供したドキュメントバイトに対してRFC 5652 §11.2のmessageDigestチェックを追加実行。 |
.get_certificate() / .GetCertificate() |
より詳細な検査のためにCertificateを返す。 |
ドキュメントレベルでは、verify_all_signatures() / verifyAllSignatures()がすべての署名に対して署名者チェックを実行し、単一のロールアップ結果を返します: 1 = すべて有効、0 = 少なくとも1つ無効、-1 = 少なくとも1つ不明/未サポート。
use pdf_oxide::PdfDocument;
let doc = PdfDocument::open("signed.pdf")?;
for sig in doc.signatures() {
println!("level={:?} timestamped={}", sig.pades_level(), sig.has_timestamp());
}
Certificate
x509-parserを使って/ContentsブロブからX.509証明書を抽出。v0.3.38以降、すべてのバインディングで利用可能(Python / Go / WASMアクセサは初回リリース直後に追加)。
| プロパティ / メソッド | 説明 |
|---|---|
.subject |
証明書保持者のDistinguished Name |
.issuer |
発行CAのDN |
.serial |
シリアル番号(ビッグエンディアンバイト列または文字列) |
.not_before |
有効期間開始(DateTimeOffset) |
.not_after |
有効期間終了 |
.is_valid |
not_before ≤ now ≤ not_afterの場合True |
Dss — Document Security Store
/DSS(ISO 32000-2 §12.8.4.3)はPAdES-B-LT署名の長期検証資料を保持します: ドキュメントレベルのDER証明書、CRL、OCSPレスポンス、署名ごとのVRIキー。ドキュメントから読み取ります。None/nullはPDFにDSSがないことを示します(エラーではありません)。Rust、Python、Go、C#、Swiftで利用可能。
Rust
use pdf_oxide::PdfDocument;
use pdf_oxide::signatures::read_dss;
let doc = PdfDocument::open("ltv.pdf")?;
if let Some(dss) = read_dss(&doc)? {
println!("certs={} crls={} ocsps={} vri={}",
dss.certificates.len(), dss.crls.len(), dss.ocsp_responses.len(), dss.vri.len());
}
Python
import pdf_oxide
doc = pdf_oxide.PdfDocument("ltv.pdf")
dss = doc.dss()
if dss is not None:
print("certs", len(dss.certs), "crls", len(dss.crls),
"ocsps", len(dss.ocsps), "vri", len(dss.vri))
Go
doc, _ := pdfoxide.Open("ltv.pdf")
defer doc.Close()
dss, _ := doc.DSS() // nil when the PDF has no /DSS
if dss != nil {
fmt.Printf("certs=%d crls=%d ocsps=%d vri=%d\n",
len(dss.Certs), len(dss.CRLs), len(dss.OCSPs), dss.VRICount)
}
C#
using var doc = PdfDocument.Open("ltv.pdf");
var dss = doc.GetDss(); // null when the PDF has no /DSS
if (dss is not null)
{
Console.WriteLine($"certs={dss.Certificates.Count} crls={dss.Crls.Count} " +
$"ocsps={dss.OcspResponses.Count} vri={dss.VriCount}");
}
Swift
if let dss = try doc.dss() {
print("certs=\(try dss.certCount()) crls=\(try dss.crlCount()) " +
"ocsps=\(try dss.ocspCount()) vri=\(try dss.vriCount())")
}
C++
try {
auto dss = doc.get_dss(); // throws if the PDF has no /DSS
std::cout << "certs=" << dss.cert_count() << " crls=" << dss.crl_count()
<< " ocsps=" << dss.ocsp_count() << " vri=" << dss.vri_count() << "\n";
} catch (const pdf_oxide::Error&) {
// no DSS present
}
Dart
try {
final dss = doc.getDss(); // throws if the PDF has no /DSS
print('certs=${dss.certCount} crls=${dss.crlCount} '
'ocsps=${dss.ocspCount} vri=${dss.vriCount}');
} on PdfOxideError {
// no DSS present
}
R
dss <- pdf_get_dss(doc) # NULL when the PDF has no /DSS
if (!is.null(dss)) {
cat("certs=", pdf_dss_cert_count(dss), "crls=", pdf_dss_crl_count(dss),
"ocsps=", pdf_dss_ocsp_count(dss), "vri=", pdf_dss_vri_count(dss), "\n")
}
Julia
dss = document_get_dss(doc) # nothing when the PDF has no /DSS
if dss !== nothing
println("certs=", dss_cert_count(dss), " crls=", dss_crl_count(dss),
" ocsps=", dss_ocsp_count(dss), " vri=", dss_vri_count(dss))
end
Zig
var dss = try doc.dss(); // error if the PDF has no /DSS
std.debug.print("certs={} crls={} ocsps={} vri={}\n", .{
try dss.certCount(), try dss.crlCount(), try dss.ocspCount(), try dss.vriCount(),
});
Objective-C
POXDss *dss = [doc dssWithError:&err]; // nil when the PDF has no /DSS
if (dss != nil) {
NSLog(@"certs=%d crls=%d ocsps=%d vri=%d",
[dss certCount], [dss crlCount], [dss ocspCount], [dss vriCount]);
}
Elixir
case PdfOxide.document_dss(doc) do
{:ok, dss} ->
IO.puts("certs=#{PdfOxide.dss_cert_count(dss)} crls=#{PdfOxide.dss_crl_count(dss)} " <>
"ocsps=#{PdfOxide.dss_ocsp_count(dss)} vri=#{PdfOxide.dss_vri_count(dss)}")
_ -> :no_dss # the PDF has no /DSS
end
| C ABI / Swiftメソッド | Python / Go / C#相当 | 説明 |
|---|---|---|
cert_count() |
len(dss.certs) / len(dss.Certs) / dss.Certificates.Count |
ドキュメントレベルのDER証明書(/Certs) |
crl_count() |
len(dss.crls) / len(dss.CRLs) / dss.Crls.Count |
ドキュメントレベルのDER CRL(/CRLs) |
ocsp_count() |
len(dss.ocsps) / len(dss.OCSPs) / dss.OcspResponses.Count |
ドキュメントレベルのDER OCSPレスポンス(/OCSPs) |
vri_count() |
len(dss.vri) / dss.VRICount / dss.VriCount |
署名ごとの/VRIエントリ(/Contentsの大文字16進SHA-1) |
B-LTAアーカイブ用/DocTimeStamp(pades_levelでは報告できないドキュメント全体のシグナル)を確認するには、has_document_timestamp(pdf_bytes)(Rust/Python)、doc.HasDocumentTimestamp()(Go/C#)、またはdoc.hasTimestamp()(Swift)を呼び出してください。
Timestamp — RFC 3161 TSTInfo
署名のTimeStampToken属性、またはスタンドアロンのRFC 3161レスポンスからタイムスタンプブロブを解析。すべてのバインディングで利用可能(NodeサポートはV0.3.38リリース後に追加)。
Rust
use pdf_oxide::Timestamp;
let ts = Timestamp::parse(&tst_bytes)?;
println!("{} serial={} tsa={}", ts.time(), ts.serial(), ts.tsa_name());
Python
from pdf_oxide import Timestamp
ts = Timestamp.parse(tst_bytes)
print(ts.time, ts.serial, ts.policy_oid, ts.tsa_name, ts.hash_algorithm)
C#
var ts = Timestamp.Parse(tstBytes);
Console.WriteLine($"{ts.Time} serial={ts.Serial} tsa={ts.TsaName}");
Node / TypeScript
import { Timestamp } from "pdf-oxide";
const ts = Timestamp.parse(tstBytes);
console.log(ts.time, ts.serial, ts.policyOid, ts.tsaName, ts.hashAlgorithm);
ts.close();
Go
ts, _ := pdfoxide.ParseTimestamp(tstBytes)
fmt.Println(ts.Time, ts.Serial, ts.PolicyOid, ts.TsaName, ts.HashAlgorithm)
WASM
import init, { Timestamp } from "pdf-oxide-wasm/web";
await init();
const ts = Timestamp.parse(tstBytes);
console.log(ts.time, ts.serial, ts.policyOid, ts.tsaName, ts.hashAlgorithm);
C++
auto ts = pdf_oxide::Timestamp::parse(tst_bytes);
std::cout << ts.time() << " serial=" << ts.serial() << " tsa=" << ts.tsa_name()
<< " policy=" << ts.policy_oid() << " hash=" << ts.hash_algorithm() << "\n";
Swift
let ts = try Timestamp.parse(tstBytes)
print(try ts.time(), "serial=\(try ts.serial())", "tsa=\(try ts.tsaName())",
"policy=\(try ts.policyOid())", "hash=\(try ts.hashAlgorithm())")
Dart
final ts = Timestamp.parse(tstBytes);
print('${ts.time} serial=${ts.serial} tsa=${ts.tsaName} '
'policy=${ts.policyOid} hash=${ts.hashAlgorithm}');
R
ts <- pdf_timestamp_parse(tst_bytes)
cat(pdf_timestamp_time(ts), "serial=", pdf_timestamp_serial(ts),
"tsa=", pdf_timestamp_tsa_name(ts), "policy=", pdf_timestamp_policy_oid(ts),
"hash=", pdf_timestamp_hash_algorithm(ts), "\n")
Julia
ts = timestamp_parse(tst_bytes)
println(timestamp_get_time(ts), " serial=", timestamp_get_serial(ts),
" tsa=", timestamp_get_tsa_name(ts), " policy=", timestamp_get_policy_oid(ts),
" hash=", timestamp_get_hash_algorithm(ts))
Zig
const a = std.heap.page_allocator;
var ts = try pdf_oxide.Timestamp.parse(tst_bytes);
const serial = try ts.serial(a);
const tsa = try ts.tsaName(a);
std.debug.print("{} serial={s} tsa={s} hash={}\n", .{
try ts.time(), serial, tsa, try ts.hashAlgorithm(),
});
Objective-C
POXTimestamp *ts = [POXTimestamp parse:tstBytes error:&err];
NSLog(@"%lld serial=%@ tsa=%@ policy=%@ hash=%d",
[ts timeError:&err], [ts serialError:&err], [ts tsaNameError:&err],
[ts policyOidError:&err], [ts hashAlgorithmError:&err]);
Elixir
{:ok, ts} = PdfOxide.timestamp_parse(tst_bytes)
{:ok, time} = PdfOxide.timestamp_time(ts)
{:ok, serial} = PdfOxide.timestamp_serial(ts)
{:ok, tsa} = PdfOxide.timestamp_tsa_name(ts)
IO.puts("#{time} serial=#{serial} tsa=#{tsa}")
| プロパティ | 説明 |
|---|---|
.time |
TSAが主張するUTC時刻 |
.serial |
このタイムスタンプの固有シリアル番号 |
.policy_oid |
TSAポリシーOID |
.tsa_name |
TSA識別子 |
.hash_algorithm |
message_imprintに使用されたハッシュアルゴリズム |
.message_imprint |
署名対象ペイロードのハッシュ |
.verify() |
埋め込みTSA証明書に対してTSTInfoの署名を確認 |
TsaClient — RFC 3161 HTTPクライアント
HTTP経由でタイムスタンプ局に新規タイムスタンプを要求します。Cargoのtsa-clientフィーチャーが必要。WASM以外のすべてのバインディングで利用可能(NodeサポートはV0.3.38リリース後に追加; WASMは意図的に除外 — ureqはwasm32にコンパイルできません)。
Rust
use pdf_oxide::TsaClient;
let client = TsaClient::new("https://freetsa.org/tsr")
.with_timeout(std::time::Duration::from_secs(30))
.with_hash_algorithm(pdf_oxide::HashAlgorithm::Sha256)
.with_nonce(true);
let ts = client.request_timestamp(&pdf_bytes)?;
println!("{} serial={}", ts.time(), ts.serial());
Python
from pdf_oxide import TsaClient
client = TsaClient(
url="https://freetsa.org/tsr",
username=None,
password=None,
timeout_seconds=30,
hash_algorithm=2, # 2 = SHA-256
use_nonce=True,
cert_req=True,
)
ts = client.request_timestamp(pdf_bytes)
print(ts.time, ts.serial)
Node / TypeScript
import { TsaClient } from "pdf-oxide";
const client = new TsaClient({
url: "https://freetsa.org/tsr",
timeoutSeconds: 30,
hashAlgorithm: 2, // 2 = SHA-256
useNonce: true,
certReq: true,
});
const ts = client.requestTimestamp(pdfBytes);
console.log(ts.time, ts.serial);
ts.close();
client.close();
C#
var client = new TsaClient("https://freetsa.org/tsr");
var ts = client.RequestTimestamp(pdfBytes);
Console.WriteLine($"{ts.Time} serial={ts.Serial}");
Go
client := pdfoxide.NewTsaClient("https://freetsa.org/tsr")
ts, err := client.RequestTimestamp(pdfBytes)
if err != nil { log.Fatal(err) }
fmt.Println(ts.Time, ts.Serial)
C++
auto client = pdf_oxide::TsaClient::create("https://freetsa.org/tsr");
auto ts = client.request_timestamp(pdf_bytes);
std::cout << ts.time() << " serial=" << ts.serial() << "\n";
Swift
let client = try TsaClient.create(url: "https://freetsa.org/tsr")
let ts = try client.requestTimestamp(pdfBytes)
print(try ts.time(), "serial=\(try ts.serial())")
Dart
final client = TsaClient.create('https://freetsa.org/tsr');
final ts = client.requestTimestamp(pdfBytes);
print('${ts.time} serial=${ts.serial}');
R
client <- pdf_tsa_client_create("https://freetsa.org/tsr")
ts <- pdf_tsa_request_timestamp(client, pdf_bytes)
cat(pdf_timestamp_time(ts), "serial=", pdf_timestamp_serial(ts), "\n")
Julia
client = tsa_client_create("https://freetsa.org/tsr")
ts = tsa_request_timestamp(client, pdf_bytes)
println(timestamp_get_time(ts), " serial=", timestamp_get_serial(ts))
Zig
const a = std.heap.page_allocator;
var client = try pdf_oxide.TsaClient.create("https://freetsa.org/tsr", "", "", 30, 0, true, true);
var ts = try client.requestTimestamp(pdf_bytes);
const serial = try ts.serial(a);
std.debug.print("{} serial={s}\n", .{ try ts.time(), serial });
Objective-C
POXTsaClient *client = [POXTsaClient createWithUrl:@"https://freetsa.org/tsr"
username:nil password:nil
timeout:30 hashAlgo:0
useNonce:YES certReq:YES error:&err];
POXTimestamp *ts = [client requestTimestamp:pdfBytes error:&err];
NSLog(@"%lld serial=%@", [ts timeError:&err], [ts serialError:&err]);
Elixir
{:ok, client} = PdfOxide.tsa_client("https://freetsa.org/tsr")
{:ok, ts} = PdfOxide.tsa_request_timestamp(client, pdf_bytes)
{:ok, time} = PdfOxide.timestamp_time(ts)
{:ok, serial} = PdfOxide.timestamp_serial(ts)
IO.puts("#{time} serial=#{serial}")
TsaClientはRFC 3161 TimeStampReqをHTTP POSTで送信し、ノンスとHTTP Basic認証(username / passwordが設定されている場合)を使用します。レスポンスは展開され、Timestamp::parseで解析されます。
バインディングカバレッジ一覧
v0.3.38時点で完全対応: WASMでのTsaClientという意図的な例外を除き、すべての署名サーフェスがすべてのバインディングで提供されています。
| サーフェス | Rust | Python | Node | C# | Go | WASM |
|---|---|---|---|---|---|---|
Signature 列挙と検証 |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Certificate 検査 |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Dss (/DSS) 検査 |
✓ | ✓ | — | ✓ | ✓ | — |
Timestamp 解析と検証 |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
TsaClient HTTPリクエスト |
✓ | ✓ | ✓ | ✓ | ✓ | — |
署名(sign_pdf_bytes / PAdES) |
✓ | ✓ | — | ✓ | ✓ | — |
TsaClient × WASMの—は意図的かつ永続的です: ureqはwasm32にコンパイルできません。サーバーサイドのバインディングからTsaClientを呼び出し、ブラウザでレスポンスを検査する必要がある場合はWASMで生のタイムスタンプバイトをTimestamp.parse()に渡してください。
関連ページ
- PDFへの署名: 電子署名とPAdES — CMSおよびPAdES B-B/B-T/B-LT署名の作成
- メタデータとXMP — ドキュメントレベルのメタデータ抽出
- APIリファレンス — RustサイドのSignatureVerifierサーフェス