Bài viết kỹ thuật

Danh sách tin cậy eIDAS và chữ ký PDF qualified

Quyết định rằng một chữ ký PDF là qualified theo eIDAS nghĩa là trả lời một câu hỏi chẳng liên quan gì mật mã học: chứng chỉ có được cấp bởi một dịch vụ tin cậy mà một quốc gia thành viên liệt kê là qualified tại thời điểm chữ ký được thực hiện hay không. Câu trả lời nằm trong một danh sách tin cậy, một tài liệu XML được công bố theo từng lãnh thổ, và toàn bộ giá trị của tài liệu đó phụ thuộc vào tính xác thực của nó. Vì vậy thành phần PDFium từ chối nhìn vào bên trong một danh sách cho đến khi có ai đó bảo lãnh nó. TPdfEuropeanTrustedList.ParseAuthenticated trao toàn bộ byte thô cho một IPdfTrustedListAuthenticator do caller cung cấp trước khi phân tích một dịch vụ nào, và nó chỉ tạo một snapshot nếu authenticator đó tường minh qua

Luồng xác-thực-trước-khi-phân-tích cho một danh sách tin cậy châu Âu trong Delphi: XML thô từ một lần lấy tươi hay snapshot cache đi qua IPdfTrustedListAuthenticator trước khi TPdfEuropeanTrustedList phân tích bất cứ gì
Danh sách tươi và danh sách cache gặp cùng authenticator, và một snapshot chỉ tồn tại sau khi nó qua

Thứ tự đó là thiết kế. Mọi thứ khác trong tính năng này đều suy ra từ nó, gồm cả những phần trông phiền toái

Phân tích được không có nghĩa là tin cậy được

Một danh sách tin cậy phân tích sạch sẽ cho bạn biết XML có dạng chuẩn. Nó chẳng nói gì với bạn về ai đã viết nó. Vì danh sách là nền móng cho toàn bộ quyết định trạng thái qualified của bạn, việc chấp nhận một danh sách chỉ vì nó phân tích được sẽ khiến quyết định vô nghĩa: một kẻ tấn công thay thế được danh sách có thể tuyên bố CA của chính họ là qualified

Cùng lý lẽ áp dụng cho caching, và đây là cái bẫy đáng được gọi tên. Bộ cache snapshot lưu XML gốc cùng một digest SHA-256, và sẽ rất dễ coi một digest khớp khi nạp là bằng chứng danh sách chính đáng. Nó không phải. Một digest được tính bởi cùng tiến trình đã lưu tệp, không dính dáng khóa nào, chỉ xác minh rằng các byte chưa đổi kể từ khi bạn ghi chúng; nếu danh sách là gian lận khi được cache, digest xác nhận nó là cùng danh sách gian lận đó. Vì vậy nạp một snapshot cache chạy qua cùng authenticator với việc phân tích một danh sách tươi. Toàn vẹn và xác thực là hai thuộc tính khác nhau và chỉ một trong hai cần khóa

uses
  FPdfTrustedList;

type
  TListAuthenticator = class(TInterfacedObject, IPdfTrustedListAuthenticator)
  public
    function Authenticate(const XmlData: TBytes;
      out AuthenticationDetails: string): Boolean;
  end;

function TListAuthenticator.Authenticate(const XmlData: TBytes;
  out AuthenticationDetails: string): Boolean;
begin
  // Chính sách của bạn nằm ở đây: xác minh chữ ký enveloped XMLDSIG
  // với chứng chỉ ký danh sách bạn đã ghim qua một kênh ngoài,
  // và mô tả những gì bạn đã kiểm cho dấu vết kiểm toán
  Result := VerifyEnvelopedXmlSignature(XmlData, FPinnedListSigner);
  if Result then
    AuthenticationDetails := 'XMLDSIG verified against pinned LOTL signer';
end;

var
  List: TPdfEuropeanTrustedList;
  Cache: TFileStream;
begin
  List := TPdfEuropeanTrustedList.ParseAuthenticated(RawXml,
    TListAuthenticator.Create, TPdfTrustedListOptions.Default);
  // Snapshot tồn tại chỉ vì authenticator đã gật đầu
  Cache := TFileStream.Create('tl-de.snapshot', fmCreate);
  try
    List.SaveCache(Cache);
  finally
    Cache.Free;
  end;
end;

Validator không sở hữu chính sách mạng

Một validator PAdES không có việc gì phải quyết định cách tiếp cận danh sách các danh sách tin cậy, có đi qua proxy hay không, thử lại bao nhiêu lần, hay làm gì khi một lãnh thổ không với tới được. Đó là các quyết định ứng dụng và triển khai, và trong các môi trường được quản lý chúng thường xuyên bị kiểm toán. Vì vậy các bản cập nhật đến qua IPdfTrustedListSource, thứ được trao một URI và một trần byte và trả về các byte

Thứ thành phần này thi hành là các bất biến khiến một bản cập nhật là một bản cập nhật chứ không phải một sự thay thế. Update đòi hỏi lãnh thổ không đổi, số thứ tự tăng nghiêm ngặt, và thời gian phát hành không lùi lại. Ba phép kiểm đó đánh bại các cuộc tấn công hạ cấp rõ ràng nhất: phát lại một danh sách cũ vẫn liệt kê một dịch vụ đã bị rút khỏi danh sách, hay tráo vào một danh sách của lãnh thổ khác mà bạn chưa từng định tin các dịch vụ của nó

Các bất biến cập nhật do thành phần danh sách tin cậy PDFium thi hành: lãnh thổ không đổi, số thứ tự tăng nghiêm ngặt và thời gian phát hành không bao giờ lùi, cùng nhau chặn các cuộc tấn công hạ cấp
Ba phép kiểm đơn điệu phân biệt một bản cập nhật chính đáng với một danh sách bị phát lại hay thay thế

Các giới hạn parser, và chẳng có DTD nào cả

TPdfTrustedListOptions chặn trần kích thước XML, số token, độ sâu lồng nhau, số dịch vụ, số chứng chỉ và kích thước của một chứng chỉ riêng lẻ, với một hàm lớp Default cung cấp các giá trị dùng được. Các danh sách tin cậy là những tài liệu công bố có kích thước đoán trước được, nên các biên rẻ để đặt và chẳng có danh sách chính đáng nào cần vượt chúng

Riêng biệt và vô điều kiện, parser từ chối các khai báo DTD và entity. Điều đó chặn cả tấn công từ chối dịch vụ nới rộng entity lẫn lộ trình tiết lộ entity ngoài trong một lần từ chối, và nó chẳng tốn gì vì các danh sách tin cậy không dùng entity. Bất kỳ parser XML nào với tới được từ đầu vào không tin cậy đều nên được cấu hình theo cách này; sự khác biệt ở đây là lời từ chối không thể cấu hình, nên nó không thể bị tắt bởi một thay đổi tùy chọn hiền lành

Trạng thái qualified được ghi cạnh niềm tin chuỗi, không hòa vào nó

Phía đánh giá được tách biệt một cách có chủ đích. TPadesTrustValidationOptions.QualifiedTrustEvaluator nhận một IPdfQualifiedTrustEvaluator, thứ mà snapshot danh sách tin cậy hiện thực. Trong lúc xác thực, evaluator nhận chứng chỉ lá, chuỗi và một thời gian xác thực, khớp các chứng chỉ dịch vụ bằng phép so sánh DER chính xác với người ký và chuỗi, kết hợp trạng thái dịch vụ, định danh loại dịch vụ và các URI qualifier tại khoảnh khắc đó, và trả về một bản ghi đánh giá

Kết quả rơi vào hai nơi trên mỗi chữ ký: QualifiedTrustStatus như một trạng thái thô, và QualifiedTrust như đánh giá đầy đủ với lãnh thổ, tên nhà cung cấp, tên dịch vụ, định danh loại, trạng thái và thời điểm bắt đầu trạng thái. Điều nó không làm là đổi CertificateTrustStatus. Niềm tin chuỗi hệ thống và trạng thái qualified trả lời hai câu hỏi khác nhau, và một báo cáo gộp chúng không thể phân biệt "tin cậy nhưng không qualified" với "qualified nhưng chuỗi không xác thực được", cả hai đều có thật và cả hai cần cách xử lý khác nhau

Đánh giá niềm tin qualified PAdES trong Delphi: IPdfQualifiedTrustEvaluator khớp chứng chỉ dịch vụ bằng so sánh DER chính xác và điền QualifiedTrustStatus cùng QualifiedTrust trong khi CertificateTrustStatus giữ nguyên
Niềm tin chuỗi và trạng thái qualified eIDAS được ghi cạnh nhau để cả hai phát hiện đều nhìn thấy
var
  Options: TPadesTrustValidationOptions;
  Report: TPadesValidationResult;
  I: Integer;
begin
  Options := TPadesTrustValidationOptions.Default;
  Options.CheckRevocation := True;
  Options.QualifiedTrustEvaluator := List;      // snapshot đã được xác thực
  Options.QualifiedValidationTime := SigningTime; // không phải Now
  Report := Pdf.ValidatePadesTrust(Options);

  for I := 0 to High(Report.Signatures) do
    if Report.Signatures[I].QualifiedTrustStatus = pcsValid then
      Writeln(Format('signature %d qualified by %s / %s (%s)',
        [I, Report.Signatures[I].QualifiedTrust.Territory,
         Report.Signatures[I].QualifiedTrust.ProviderName,
         Report.Signatures[I].QualifiedTrust.ServiceName]))
    else if Report.Signatures[I].QualifiedTrustStatus = pcsIndeterminate then
      // Không có dịch vụ khớp, hay snapshot không trả lời được cho thời điểm này
      Writeln(Format('signature %d: qualified status undetermined', [I]));
end;

Vì sao thời gian xác thực không phải bây giờ

Vì việc qualified là thuộc tính của một khoảnh khắc. Một dịch vụ tin cậy có thể được trao trạng thái qualified, sau đó bị rút lại, rồi còn được phục hồi nữa, và mỗi lần chuyển tiếp đó mang một thời điểm bắt đầu trong danh sách. Một chữ ký thực hiện trong khi dịch vụ còn qualified vẫn qualified sau đó; một chữ ký thực hiện trước khi được cấp không trở thành qualified hồi tố. Đánh giá theo thời gian hiện tại vì vậy cho câu trả lời sai theo cả hai hướng

Danh sách mang theo những gì cần cho việc này: mỗi bản ghi dịch vụ có một thời điểm bắt đầu trạng thái và một cờ phân biệt các mục lịch sử với các mục hiện hành, và evaluator kết hợp chúng với thời gian bạn cung cấp. Trong thực tế, thời gian đó đến từ một dấu thời gian đáng tin cậy trên chữ ký chứ không phải từ thời gian ký được tuyên bố trong CMS, đó là lý do vật liệu xác thực dài hạn quan trọng ngay cả với một câu hỏi trông như một tra cứu chính sách; phía dấu thời gian và DSS được đề cập trong bài viết về chữ ký dài hạn

Điều bạn vẫn phải tự dựng

Ba thứ, và chẳng thứ nào thuộc về một thư viện PDF. Authenticator, nghĩa là xác minh XMLDSIG thật sự với một chứng chỉ ký danh sách mà bạn thu được qua một kênh bạn tin. Chính sách lấy dữ liệu, nghĩa là bạn làm mới thế nào và bao lâu một lần, và ứng dụng của bạn làm gì khi một lần làm mới thất bại. Và phạm vi lãnh thổ, nghĩa là bạn mang theo những danh sách nào, một quyết định kinh doanh về các quốc gia thành viên mà đối tác của bạn ký

Thứ bạn nhận từ thành phần là phần dễ sai một cách tinh vi: thứ tự xác-thực-trước-khi-phân-tích, phân tích XML có biên và không entity, các bất biến cập nhật đơn điệu, khớp dịch vụ DER chính xác, đánh giá trạng thái lịch sử, và một kết quả tách khỏi niềm tin chuỗi thông thường. Nếu vấn đề trước mắt của bạn cơ bản hơn — một validator từ chối một chữ ký mà bạn tin là ổn — các nguyên nhân quen thuộc được lập danh mục trong vì sao validator từ chối chữ ký PAdES, và bề mặt kiểm tra chữ ký được mô tả trong kiểm tra chữ ký và các cấp PAdES. Năng lực của thành phần được liệt kê trên trang sản phẩm PDFium Delphi component