مقاله فنی

امضای PAdES از راه دور با PDFium VCL: HSM و کلیدهای ابری

PDFiumPas امضای PAdES را به دو فراخوانی تقسیم می‌کند تا کلید خصوصی هرگز مجبور نباشد درون فرآیند شما باشد. PreparePadesRemoteSignature یک به‌روزرسانی افزایشی با یک جای‌نگه‌دار /Contents با عرض ثابت و خالی می‌نویسد و یک رکورد درخواست بازمی‌گرداند که دایجست SHA-256 سند، ByteRange دقیق و یک اثر انگشت از فایل آماده‌شده را حمل می‌کند. CompletePadesRemoteSignature CMS جدا‌شده‌ای را که سرویس امضای شما بازمی‌گرداند می‌گیرد و آن را درون آن جایگاه رزروشده می‌گذارد

بین آن دو فراخوانی، ممکن است دقایق یا ساعت‌ها بگذرد، فرآیند می‌تواند دوباره راه‌اندازی شود، و کار می‌تواند به یک ماشین دیگر منتقل شود. آن شکاف کل دلیلی است که این API به این شکل طراحی شده

چرا یک کلید از راه دور نمی‌تواند از فراخوانی امضای معمولی استفاده کند؟

چون SignPadesBytes فرض می‌کند عملیات امضا درون خود فراخوانی اتفاق می‌افتد. آن به‌روزرسانی افزایشی را می‌سازد، دایجست را روی ByteRange محاسبه می‌کند، آن را امضا می‌کند، و نتیجه را می‌نویسد، همه پیش از بازگشت. این دقیقاً درست است وقتی کلید در فروشگاه گواهی ویندوز یا در یک فایل PKCS#12 که بارگذاری کرده‌اید زندگی می‌کند

این وقتی غیرممکن است که کلید در یک HSM شبکه‌ای، یک دستگاه ایجاد امضای واجد شرایط اداره‌شده توسط یک ارائه‌دهنده خدمات اعتماد، یا یک API امضای ابری که نیازمند تأیید کاربر روی یک تلفن است زندگی می‌کند. در آن موارد، دنباله یک فراخوانی تابع نیست، یک گفت‌وگو است: شما یک دایجست می‌فرستید، چیز دیگری یک انسان را احراز می‌کند، و یک CMS بعداً بازمی‌گردد. یک API همگام نمی‌تواند «بعداً» را بدون مسدودکردن یک رشته روی عملیاتی که ممکن است به یک عامل دوم نیاز داشته باشد بیان کند

پروتکل دومرحله‌ای

مرحله اول سند را آماده می‌کند. PDFiumPas فیلد امضا و دیکشنری مقدار را ضمیمه می‌کند، ContentsSize بایت از فضای کدگذاری‌شده hex را در /Contents رزرو می‌کند، ByteRange را اطراف آن رزرو محاسبه می‌کند، و یک TPadesRemoteSigningRequest شامل FormatVersion، PreparedFingerprint، DocumentDigest، ByteRange چهارعنصری، ContentsHexOffset و ContentsSize تولید می‌کند

تنها مقداری که سرویس امضای شما نیاز دارد DocumentDigest است: همان SHA-256 که SignedData نوع CAdES بازگردانده‌شده باید به‌عنوان دایجست پیام خود حمل کند. هرچیز دیگر در رکورد وجود دارد تا مرحله دوم بتواند اثبات کند فایلی که کامل می‌کند همان فایلی است که آن دایجست از آن محاسبه شده

uses
  FPdfPades;

var
  Options: TPadesRemoteSignOptions;
  Request: TPadesRemoteSigningRequest;
  Source, Prepared, Session: TFileStream;
begin
  Options := TPadesRemoteSignOptions.Default;
  Options.Reason := 'Approved by finance';
  Options.Location := 'Lisbon';
  Options.Name := 'A. Moreira';
  Options.SigningTimeUtc := NowUtc;
  Options.ContentsSize := 16384;   // بایت‌های hex رزروشده برای CMS

  Source := TFileStream.Create('contract.pdf', fmOpenRead or fmShareDenyWrite);
  Prepared := TFileStream.Create('contract.prepared.pdf', fmCreate);
  try
    PreparePadesRemoteSignature(Source, Prepared, Options, Request);
  finally
    Prepared.Free;
    Source.Free;
  end;

  // نشست را پایا کن تا یک اجرای بعدی - یا یک ماشین دیگر - بتواند آن را تمام کند
  Session := TFileStream.Create('contract.signreq', fmCreate);
  try
    SavePadesRemoteSigningRequest(Session, Request);
  finally
    Session.Free;
  end;

  SendDigestToSigningService(Request.DocumentDigest);
end;

Complete چه چیزی را رد می‌کند، و چرا هر بررسی وجود دارد؟

تکمیل همان جایی است که یک طراحی امضای از راه دور معمولاً به مشکل می‌خورد، پس اعتبارسنجی عمداً بی‌گذشت است. CompletePadesRemoteSignature یک PDF آماده‌شده که اثر انگشت آن دیگر با درخواست مطابقت ندارد، یک ByteRange که با مختصات جای‌نگه‌دار ثبت‌شده مطابقت ندارد، محدودکننده‌های /Contents تغییریافته، یک جای‌نگه‌دار که دیگر خالی نیست، یک CMS بزرگ‌تر از رزرو، یک CMS که دقیقاً یک مقدار DER نیست، یک شکل پشتیبانی‌نشده از SignedData، یک ویژگی گمشده signing-certificate-v2، و یک CMS که دایجست پیام آن با دایجست سند آماده‌شده برابر نیست را رد می‌کند

هرکدام از این‌ها به یک شکست واقعی نگاشت می‌شود. بررسی‌های اثر انگشت و ByteRange موردی را می‌گیرند که کسی فایل آماده‌شده را بین مراحل دوباره تولید کرده، که یک امضا تولید می‌کرد که در برابر بایت‌هایی که کسی ندارد اعتبارسنجی می‌شود. بررسی جای‌نگه‌دار-خالی تکمیل دوگانه را می‌گیرد، جایی که یک CMS دوم روی امضایی که از پیش وجود دارد نوشته می‌شود. بررسی دایجست پیام خطرناک‌ترین مورد را می‌گیرد: یک CMS به‌درستی تشکیل‌شده که روی یک سند متفاوت امضا شده، همان چیزی که وقتی یک صف دو نشست امضای همزمان را قاطی می‌کند دریافت می‌کنید. بدون آن، فایلی تولید می‌کردید که امضاشده به نظر می‌رسد و در همه‌جا اعتبارسنجی شکست می‌خورد، یا بدتر، تأیید یک نفر دیگر را حمل می‌کند

الزام signing-certificate-v2 یک مسئله انطباق PAdES است تا یک مسئله یکپارچگی. ETSI EN 319 142 لازم دارد گواهی امضا درون ویژگی‌های امضاشده متصل شود، و یک CMS که فاقد آن ویژگی است حتی اگر از نظر رمزنگاری تأیید شود یک امضای PAdES نیست. رد آن در تکمیل یعنی اینجا آن را می‌فهمید، نه در یک گزارش اعتبارسنج از یک مشتری، موضوعی که بیشتر در چرا اعتبارسنج‌ها امضاهای PAdES را رد می‌کنند بررسی شده

var
  Request: TPadesRemoteSigningRequest;
  Session, Prepared, Dest: TFileStream;
  CmsDer: TBytes;
begin
  Session := TFileStream.Create('contract.signreq', fmOpenRead);
  try
    Request := LoadPadesRemoteSigningRequest(Session);
  finally
    Session.Free;
  end;

  CmsDer := FetchDetachedCmsFromService;   // بازگردانده‌شده توسط HSM یا TSP

  Prepared := TFileStream.Create('contract.prepared.pdf', fmOpenRead);
  Dest := TFileStream.Create('contract.signed.pdf', fmCreate);
  try
    try
      CompletePadesRemoteSignature(Prepared, Dest, Request, CmsDer);
    except
      on E: EPadesCrypto do
        // هر رد یک دلیل مشخص حمل می‌کند؛ آن را عیناً لاگ کن
        FailSession(E.Message);
    end;
  finally
    Dest.Free;
    Prepared.Free;
  end;
end;

عبور از مرزهای فرآیند و ماشین

SavePadesRemoteSigningRequest و LoadPadesRemoteSigningRequest نشست را از طریق یک قالب باینری پایدار و نسخه‌دار سریالی می‌کنند، همان چیزی که این طراحی را عملی می‌کند نه فقط درست. یک برنامه وب می‌تواند یک سند را در یک درخواست آماده کند، PDF آماده‌شده و blob نشست را ذخیره کند، یک دایجست را برای یک امضای کارت‌هوشمند به مرورگر بازگرداند، و فایل را در یک هندلر درخواست کاملاً متفاوت تکمیل کند

فیلد FormatVersion همان چیزی است که این امنیت را در سراسر ارتقاها حفظ می‌کند. یک نشست نوشته‌شده توسط یک نسخه ساخته‌شده قدیمی‌تر و بارگذاری‌شده توسط نسخه جدیدتر، به‌طور صریح شناسایی یا رد می‌شود، نه اینکه به‌عنوان یک رکورد به‌شکل متفاوت به‌اشتباه خوانده شود. اگر صف شما می‌تواند نشست‌ها را برای روزها نگه دارد، نسخه قالب را به‌عنوان یک حقیقت عملیاتی که ارزش لاگ‌کردن دارد در نظر بگیرید، نه یک جزئیات پیاده‌سازی

اندازه‌گذاری جای‌نگه‌دار

ContentsSize تنها پارامتری است که باید درباره آن فکر کنید، چون پیش از وجود CMS ثابت می‌شود. آن رزرو کدگذاری‌شده hex را می‌شمارد، پس یک CMS نوع DER با اندازه 6 کیلوبایت به حداقل 12 کیلوبایت فضا نیاز دارد، و پیاده‌سازی رزرو را در 64 مگابایت سقف می‌گذارد

خیلی کم رزرو کنید و تکمیل با یک خطای CMS بیش‌ازحد بزرگ پس از اینکه سرویس امضای شما از پیش کارش را انجام داده شکست می‌خورد، که روی یک سرویس امضای واجد شرایط اندازه‌گیری‌شده یعنی یک عملیات هدررفته. خیلی زیاد رزرو کنید و هر سند امضاشده آن padding را برای همیشه حمل می‌کند. رویکرد معقول اندازه‌گیری‌کردن است: یک سند را با زنجیره گواهی واقعی خود امضا کنید، طول DER را نگاه کنید، آن را برای hex دوبرابر کنید، سپس اگر قصد ارتقا به یک امضای سطح T دارید فضای سخاوتمندانه‌ای برای توکن مهر زمان اضافه کنید. زنجیره‌هایی با چندین واسطه و یک پاسخ OCSP طولانی سریع‌تر از آنچه مردم انتظار دارند رشد می‌کنند

پس از امضا چه اتفاقی می‌افتد

یک امضای از راه دور تکمیل‌شده PAdES B-B است. اعتبارسنجی بلندمدت به یک مهر زمان و مواد اعتبارسنجی نیاز دارد، که یک به‌روزرسانی افزایشی جداگانه است که یک DSS و دیکشنری‌های VRI به‌ازای هر امضای آن را اضافه می‌کند، توضیح داده‌شده در امضاهای بلندمدت با مهر زمان RFC 3161 و DSS. آن گام محلی است: گواهی‌ها، پاسخ‌های OCSP و CRLها را اضافه می‌کند، که هیچ‌کدام به کلید خصوصی نیاز ندارند

پیش از عرضه، آنچه تولید کرده‌اید را با همان مسیر کدی که یک طرف متکی استفاده می‌کند اعتبارسنجی کنید، که در بازرسی امضاهای دیجیتال و سطوح PAdES پوشش داده شده. امضا و اعتبارسنجی کد متفاوتی هستند، و یک پایپ‌لاین امضای از راه دور دقیقاً همان‌جایی است که آن دو می‌توانند بدون اینکه کسی متوجه شود از هم فاصله بگیرند تا زمانی که یک اعتبارسنج بیرونی این را بگوید

PDFiumPas یک کامپوننت Delphi و Lazarus حول موتور PDFium با یک پشته PAdES بومی در Pascal است، پس امضا، مهرزنی زمان و اعتبارسنجی بدون ابزارهای خط‌فرمان خارجی کار می‌کنند. مستندات کامل API و یک نسخه آزمایشی در صفحه کامپوننت Delphi PDFium موجود است