0

I sign a PDF and I add update version in which I write the DSS with its CRLs, Certs, VRI.

19 0 obj
    [15 0 R 16 0 R]
endobj
20 0 obj
    [13 0 R 14 0 R]
endobj
11 0 obj
    [15 0 R 16 0 R]
endobj
12 0 obj 
    [13 0 R 14 0 R]
endobj
17 0 obj
<<
    /CRL 11 0 R
    /Cert 12 0 R
>>
endobj
18 0 obj
<<
    /5F44CF6F351DFD45FB62F3D0ED046408BC892797 17 0 R
>>
endobj
21 0 obj
<<
    /VRI 18 0 R
    /CRLs 19 0 R
    /Certs 20 0 R
>>

I am confused about how should I write the Certificate and CRL streams.

15 0 obj
<<
    /Length 1454
    /Filter /FlateDecode
>>
stream
xÚ3hb0hb{ÅÄÈhÀÉÆªÍÇÌ$ÅÊ`àcÈä2‡²°    3…Šˆ€8\¼®y%E¥Å%:žyÉz†ªÊ
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—
ZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½— 
endstream
endobj

16 0 obj
<<
    /Length 1477
    /Filter /FlateDecode
>>
stream
„kâR7Å41*!‡#8Íñ3 Ź˜@‰o=«‡çƒ#yë:X]r\~}¼)/Ñmç×£¦³äsËê]ÓÕ_+µ¥$Ô¿}¾ÜÏiÁÝT!¹ôi–Í9üÀ}Џ|
ìŒH¿GÓø^ú¿ÔVÜK–qõ†µ®“¸»Ý*Žh¾JzåU7c~÷•ÔêýK*îú®¹¸DcÁ­³·NtV~Vóåíé5\‚&½|¶NäïŽ[K­
î›NRZbXd{0%KW÷ýY¯’ó‚-ØÂÛ„OÏó½z•î    ‰`®•®   K-›2}tÖ§^_8;xÉì¥Ó®~›.g9A'Õüê½—›oÇ:ç-¶?
endstream
endobj

13 0 obj
<<
    /Length 1240
    /Filter /FlateDecode
>>
stream
%ŸwC[í2×¾Iej©úkŽ-:ݳÔ<¼a£ƒô/5›‡~zÒ•7ü9uãcfk?ËÅ`ßÃ:Èb—’‚Ÿõ{ÏÅ—¢{]HçQ”9w(ÂB#í×g¥ìþè
^–F«š/r§š¿ì=#,^pëO€{äú=}RÎêð¦ÉŠ7or¼±Ëtë–x·˜§LÌŒŒ‹› Cd0€eùÿ³°03±>0P ñUY$
endstream
endobj

14 0 obj
<<
    /Length 1159
    /Filter /FlateDecode
>>
stream
4!>T‚êPpÎI,.V0Ò™@ûœºƒ=LÍš•㈑•¹‰‘Ÿ(ÎÅÔÄÈÈplŽ÷A¯¹7k/[‡O\}
öe™¨îö£œ¶ä'¶ÌpžªweÞª[¡$¼ØÍþþtó[½xÉO4ÞZ¥ØŸ^g ø,mu„_Rz™_PÏê.||º¶*þîÝxv½"»êôó»ø%Ü%ý
endstream
endobj

Please ignore the lengths and content of the streams above. I truncated them so the lengths don't correspond anymore. The streams are bigger than that.

The issue is that my PDF is not LTV enabled and I tested some scenarios from which I concluded that my stream are not being written the right way.

I use the following structure from WinCrypt.h:

typedef struct _CERT_CONTEXT {
    DWORD                   dwCertEncodingType;
    BYTE                    *pbCertEncoded;
    DWORD                   cbCertEncoded;
    PCERT_INFO              pCertInfo;
    HCERTSTORE              hCertStore;
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;

I go through them and get the bytes this way:

PCCERT_CONTEXT  cngContext = (PCCERT_CONTEXT)(*itChain);
ByteArray certBytes(cngContext->pbCertEncoded, (size_t)cngContext->cbCertEncoded);

Then I just apply FlateDecode on the obtained bytes and write them into the PDF like a stream as you can see in the second block of code.

Am I missing any step? Like a conversion or something? I saw that the stream should be BER-Encoded. So should I transform the bytes into BER-Encoded and then apply FlateDecode?

Edit:

You can find My File here

  • Can you post a link to the PDF file for download? – Mihai Iancu Feb 27 '20 at 18:22
  • I added at the bottom – Petru Avramescu Feb 28 '20 at 08:36
  • 2
    The streams are already DER encoded. The problem is (possibly) that the streams in the CRLs array are not CRLs but OCSP responses. The CRL list from Godaddy ( http://crl.godaddy.com/repository/mastergodaddy2issuing.crl, referenced in one of the OCSP responses) is 118MB. – iPDFdev Feb 28 '20 at 12:11
  • The documentation states that CRLs streams shall be BER-encoded. Could this be a problem? For the record, I saw that DER is a subset of BER. Also, why would I get OCSP instead of CRL.. can you please check this post? It's also mine and someone noticed the same thing with OCSP. https://stackoverflow.com/questions/60413766/cant-figure-out-why-my-pdf-signature-is-not-ltv-enabled/60435058?noredirect=1#comment106942426_60435058 – Petru Avramescu Feb 28 '20 at 13:17
  • How did you figure it out it was DER tho? – Petru Avramescu Feb 28 '20 at 13:50
  • 1
    As checked in two answers to your [previous question](https://stackoverflow.com/q/60413766/1729265) your "CRLs" simply are not CRLs. They are OCSP responses wrapped in some other structure. Thus, you may play around with the encoding as hard as you want, you won't get a LTV-enabled PDF by embedding those structures *as **CRLs*** in the DSS. Instead extract the actual OCSP responses and embed them as **OCSPs**. – mkl Mar 02 '20 at 11:00

1 Answers1

0

SOLUTION

The problem was the stream of CRLs that I was writing in the PDF file.

Having the CRL_CONTEXT structures from each Certificate, I just took the pbCrlEncoded variable and write it directly in the stream of the CRL.

enter image description here

enter image description here

It seemed correct but I noticed I didn't have any CRL_ENTRY in the CRL_INFO of this structure so the encoded BYTEs didn't contain any list of revoked certificates. Therefore, found that the certificates have a URL from where you can download the updated CRL. You can do that by opening Manage Computer Certificates in Windows -> find your Certificate and Open the Certificate -> Details -> CRL Distribution Points -> URL = "..". By accessing this url, the browser automatically downloads the CRL Info. You can access it and see some informations like Next Update which is the last day that this list is valid. After that, I'm assuming that you need to download it again for getting an updated version. Also you can see the list itself of revoked certificates.

This is the list I needed to put into the CRLs streams in PDF. So I found a method to do that download process by code. This is a snippet of code used:

PCERT_CHAIN_ELEMENT chainElement; // this is the certification in the chain
pExtension = CertFindExtension(szOID_CRL_DIST_POINTS, chainElement->pCertContext->pCertInfo->cExtension, chainElement->pCertContext->pCertInfo->rgExtension);
if (!pExtension)
    return ByteArray();

if (!CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, 0, &cbStructInfo))
    return ByteArray();

if (!(pvStructInfo = LocalAlloc(LMEM_FIXED, cbStructInfo)))
    return ByteArray();

CryptDecodeObject(X509_ASN_ENCODING, szOID_CRL_DIST_POINTS, pExtension->Value.pbData, pExtension->Value.cbData, 0, pvStructInfo, &cbStructInfo);

pInfo = (CRL_DIST_POINTS_INFO*)pvStructInfo;

Net::HttpRequest req;
Net::HttpRequestOptions ops;
ops.verb = Net::GET;
crllist = req.send(pInfo->rgDistPoint->DistPointName.FullName.rgAltEntry->pwszURL);

This way I obtained the Bytes that I could paste in PDF after applying FlateDecode on them. Now the PDF is LTV Enabled.

  • While this certainly can be done, it is not really great. As has already been discussed in response to your previous question, there actually was a wrapped OCSP response in the `CrlEncoded` buffer, so you did already have revocation information which you merely would have to extract properly and add to the OCSPs section. Fetching the CRL creates extra network traffic with the PKI infrastructure. Also in general OCSP responses should be preferred as they usually are shorter (in some PKIs extremely so) than CRLs and more up-to-date. – mkl Mar 05 '20 at 17:14