make OCSP response unique - pdf

I sign document with PADES LTV Profile. Signer library is written base on Pdfbox library.
I have one problem.
In PADES LTV profile, the final revision must be checked in online (It means that OCSP responses, CRLS and certificates of this revision must not be in document secure store (DSS)).
For testing, I add 12 revision to my document.
Every time when I add new revision, I do not add certificates and ocsp responses of this current revision to the DSS. I add previous revisions certificates and ocsp responses to the DSS. I do this because last revision must be checked in online. So I must not add OCSP response of last revision to the DSS. I do so, but sometimes Adobe reader thinks that last revision have embedded OCSP response in the document.
The problem might be is that following:
Each ocsp response must be unique, even if when we generate them with the same certificate. In the other words, If we request ocsp object twice, they must be unique.
For this I do that following but it does not work:
private OCSPReq buildOcspRequest(X509Certificate issuerCert, BigInteger serialNumber, File inputDocument) {
InputStream is = new FileInputStream(inputDocument);
X509CertificateHolder certificateHolder;
certificateHolder = new X509CertificateHolder(issuerCert.getEncoded());
CertificateID id = new CertificateID(new BcDigestCalculatorProvider().get(CertificateID.HASH_SHA1), certificateHolder, serialNumber);
OCSPReqBuilder ocspReqBuilder = new OCSPReqBuilder();
ocspReqBuilder.addRequest(id);
DigestCalculatorProvider digestCalculatorProvider;
JcaDigestCalculatorProviderBuilder digestCalcProvBuilder = new JcaDigestCalculatorProviderBuilder().setProvider("BC");
digestCalculatorProvider = digestCalcProvBuilder.build();
// get SHA 256
DigestCalculator digest = digestCalculatorProvider.get(AlgorithmIdentifier.getInstance("2.16.840.1.101.3.4.2.1"));
OutputStream os = digest.getOutputStream();
IOUtils.copy(is, os);
byte[] messageImprint = digest.getDigest();
BigInteger time = BigInteger.valueOf(System.currentTimeMillis());
// time + imprint
byte[] nonce = ArrayUtils.addAll(time.toByteArray(), messageImprint);
Extension extension = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, nonce);
ocspReqBuilder.setRequestExtensions(new Extensions(extension));
return ocspReqBuilder.build();
}
this is testing pdf link SAMPLE PDF
I might create 4 revision and everything might be all right ... I don't know , sometimes it happens... When I was testing, the problem occours when I create many revisions... THE LAST REVISION THINKS THAT OCSP RESPONSE OF PREVIOUS REVISIONS IS IT'S OWN!

In PADES LTV profile, the final revision must be checked in online
No.
PAdES, i.e. ETSI TS 102 778, in part 4 (PAdES-LTV Profile) merely recommends this:
4.3 Validation Process
It is recommended that that validation process be as follows:
1) The "latest" document Time-stamp should be validated at current time with validation data collected at the current time.
The word should indicates a recommendation, and the sentence before actually spells it out.
But let's assume you want to follow the recommendation. Your interpretation
(It means that OCSP responses, CRLS and certificates of this revision must not be in document secure store (DSS)).
is not correct still: There may be validation related information (OCSP responses, CRLs, certificates) in the document which (seen as isolated information) apply to the outer time stamp or signature. If you time stamp your document twice in short succession using the same time stamp service and add a CRL for certificates used in the first time stamp in the time between, chances are that the outer time stamp involves certificates covered by this CRL and is applied in the validity interval indicated by the CRL.
No, it is the responsibility of the verifier not to use these information if the verifier chose to follow the PAdES-LTV recommendation quoted above.
Adobe Reader does not claim to follow this recommendation (at least as far as I know). Thus, if you verify the signatures and time stamps using Adobe Reader, information contained in the document may be used to verify the outer time stamp, too.
Actually Adobe originally loved the concept of first retrieving validation related information and signing and time stamping everything including those information thereafter.
The problem might be is that following:
Each ocsp response must be unique, even if when we generate them with the same certificate. In the other words, If we request ocsp object twice, they must be unique.
No. While it is good style to use nonces, your observation has nothing to do with them.
The reason why Adobe Reader sometimes (and only sometimes) makes use of already embedded information for verifying outer signatures / time stamps is that OCSP responses and CRLs have validity intervals defined by their thisUpdate and nextUpdate fields which sometimes (if you add multiple time stamps by the same TSA) in spite of being embedded for the validation of an older time stamp still encompass the time of the newly added one (and, thus, are also used for their validation).
If you want to prevent this, you have to check the OCSP responses and CRLs already contained in the PDF or just now added to it by you, inspect those whose respective validity interval has not yet ended, and not apply any time stamp to the document whose certificates can be validated with them.

Related

Signed PDF is not LTV-ready

I am trying to sign a PDF with BouncyCastle CMS. Signing works, but Adobe Reader tells me it is not LTV-ready.
As far as I can see, the CRLs are embedded in the CMS SignedData. The certficates are embedded too. A timestamp also is embedded.
The signature is a detached signature and put in the "reserved space".
Why is the signature still not LTV-ready? Am I doing something obvious wrong?
Signed Test-PDF: http://www.filedropper.com/outputx
Code:
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
// CertificateChain
List<Certificate> certList = Arrays.asList(certChain);
try {
Hashtable signedAttrs = new Hashtable();
X509Certificate signingCert = (X509Certificate) certList.get(0);
gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC")
.setSignedAttributeGenerator(new AttributeTable(signedAttrs))
.build("SHA256withRSA", privKey, signingCert));
gen.addCertificates(new JcaCertStore(certList));
boolean embedCrls = true;
if (embedCrls) {
X509CRL[] crls = fetchCRLs(signingCert);
for (X509CRL crl : crls) {
gen.addCRL(new JcaX509CRLHolder(crl));
}
}
// gen.addOtherRevocationInfo(arg0, arg1);
CMSProcessableByteArray processable = new CMSProcessableByteArray(IOUtils.toByteArray(content));
CMSSignedData signedData = gen.generate(processable, false);
if (tsaClient != null) {
signedData = signTimeStamps(signedData);
}
return signedData.getEncoded();
} catch (Exception e) {
throw new RuntimeException(e);
}
In interoperable PDF signatures there are two ways to add validation related information, and neither of them uses the default CMS way of adding CRLs that your code uses.
Adding Pre-Fetched Data In Signed Attributes
The old, ISO 32000-1 style "PKCS#7 Signatures as used in ISO 32000" (later based on CMS instead of PKCS#7) are specified to include revocation information in a dedicated signed attribute for an OID registered by Adobe:
12.8.3.3.2 Revocation Information
The adbe Revocation Information attribute:
adbe-revocationInfoArchival OBJECT IDENTIFIER ::=
{ adbe(1.2.840.113583) acrobat(1) security(1) 8 }
The value of the revocation information attribute can include any of the following data types:
Certificate Revocation Lists (CRLs), described in RFC 3280 (see the Bibliography): CRLs are generally large and therefore should not be embedded in the PKCS#7 object.
Online Certificate Status Protocol (OCSP) Responses, described in RFC 2560, X.509 Internet Public Key Infrastructure Online Certificate Status Protocol—OCSP (see the Bibliography): These are generally small and constant in size and should be the data type included in the PKCS#7 object.
Custom revocation information: The format is not prescribed by this specification, other than that it be encoded as an OCTET STRING. The application should be able to determine the type of data contained within the OCTET STRING by looking at the associated OBJECT IDENTIFIER.
adbe's Revocation Information attribute value has ASN.1 type RevocationInfoArchival:
RevocationInfoArchival ::= SEQUENCE {
crl [0] EXPLICIT SEQUENCE of CRLs, OPTIONAL
ocsp [1] EXPLICIT SEQUENCE of OCSP Responses, OPTIONAL
otherRevInfo [2] EXPLICIT SEQUENCE of OtherRevInfo, OPTIONAL
}
OtherRevInfo ::= SEQUENCE {
Type OBJECT IDENTIFIER
Value OCTET STRING
}
(Obviously this is merely Pseudo-ASN.1...)
As this structure is the value of a signed attribute, revocation information must be fetched before signing to be added like this.
Adding Data In Document Security Stores (DSS)
For their PAdES signatures ETSI specified extra PDF structures to be added to signed PDF documents which can carry extra validation related information, see ETSI EN 319 142. These structures later were integrated in ISO 32000-2:
12.8.4.3 Document Security Store (DSS)
The document security store (DSS), when present, shall be a dictionary that shall be the value of a DSS key in the document catalog dictionary (see 7.7.2, "Document catalog dictionary"). This dictionary may contain:
an array of all certificates used for the signatures, including timestamp signatures, that occur in the document. It shall also hold all the auxiliary certificates required to validate the certificates participating in certificate chain validations.
an array of all Certificate Revocation Lists (CRL) (see Internet RFC 5280) used for some of the signatures, and
an array of all Certificate Status Protocol (OCSP) responses (see Internet RFC 6960) used for some of the signatures.
a VRI key whose value shall be a dictionary containing one VRI dictionary (validation-related information) for each signature represented in CMS format.
Any VRI dictionaries, if present, shall be located in document incremental update sections. If the signature dictionary to which a VRI dictionary applies is itself in an incremental update section, the DSS/VRI update shall be done later than the signature update. The inclusion of VRI dictionary entries is optional. All validation material referenced in VRI entries is included in DSS entries too.
...
As you can read already here, this structure is designed for adding information after signing. This goes along with the ETSI favoring revocation information generated after the signature for validation.
And In PDFBox
You mention PDFBox in your tags, so you appear to use PDFBox for signing.
To add pre-fetched validation data to the signed adbe-revocationInfoArchival attribute, you merely have to add an attribute as defines above to the signedAttrs of your code.
To add data in document security stores (DSS) you can use the code of the PDFBox example AddValidationInformation as mentioned by #Tilman in a comment.

Verify user identity on my site, using SSL Certificates

I need to register companies on my site for an electronic procurement system. Up to now these were local companies I could meet physically and give credentials to, but now they can be companies based anywhere in the world.
The solution is to have an online registration process whereby they submit a third party certificate. So say Verisign says they are 'Company X' so I register them as Company X and issue them credentials.
How can I implement this on my site? Do I simply give them a field in the registration form where they upload their certificate file? Do I then manually check these certificates in my back office? How does one check this manually? Is there a way to automate this process?
Once they have an account, should I simply request the credentials I issue them with to log in, or can all future logins request the same certificate file? In these a particular format for certificates I can request or should I allow a number of common formats that different certificate vendors provide?
Thanks in advance.
Being able to provide a certificate does unfortunately not prove anything. A certificate is completely public, and anyone can get a hold of the SSL certificate for any website. The certificate contains a public key. Proving ownership of the corresponding private key is what's required.
This is possible to do, but it requires that your users are technical enough to know how to run scripts and/or OpenSSL terminal commands so that they can sign something with their private key. Having the users upload their private key is of course a big no-no, as it means you can now act as the user, and that would require an enormous amount of trust in you to discard the private key after you've verified it.
From a technical perspective, you can do the verification by creating some kind of challenge, for example a random string, and have the user encrypt this string with their private key. If you decrypt this string with the public key in the certificate, and get the original string back, then you know that they have possession of the corresponding private key.
Here's a self-contained Ruby script that demonstrates this, with comments indicating which part of it is run on your side, and which part is run on their side.
require "openssl"
## This happens on the client side. They generate a private key and a certificate.
## This particular certificate is not signed by a CA - it is assumed that a CA
## signature check is already done elsewhere on the user cert.
user_keypair = OpenSSL::PKey::RSA.new(2048)
user_cert = OpenSSL::X509::Certificate.new
user_cert.not_before = Time.now
user_cert.subject = OpenSSL::X509::Name.new([
["C", "NO"],
["ST", "Oslo"],
["L", "Oslo"],
["CN", "August Lilleaas"]
])
user_cert.issuer = user_cert.subject
user_cert.not_after = Time.now + 1000000000 # 40 or so years
user_cert.public_key = user_keypair.public_key
user_cert.sign(user_keypair, OpenSSL::Digest::SHA256.new)
File.open("/tmp/user-cert.crt", "w+") do |f|
f.write user_cert.to_pem
end
## This happens on your side - generate a random phrase, and agree on a digest algorithm
random_phrase = "A small brown fox"
digest = OpenSSL::Digest::SHA256.new
## The client signs (encrypts a cheksum) the random phrase
signature = user_keypair.sign(digest, random_phrase)
## On your side, verify the signature using the user's certificate.
your_user_cert = OpenSSL::X509::Certificate.new(File.new("/tmp/user-cert.crt"))
puts your_user_cert.public_key.verify(digest, signature, random_phrase + "altered")
# => falase
puts your_user_cert.public_key.verify(digest, signature, random_phrase)
# => true
## On your side - attempting to verify with another public key/keypair fails
malicious_keypair = OpenSSL::PKey::RSA.new(2048)
puts malicious_keypair.public_key.verify(digest, signature, random_phrase)
Note that this script does not take into account the CA verification step - you also obviously want to verify that the user's certificate is verified by a CA, such as Verisign that you mentioned, because anyone can issue a certificate and hold a private key for foo.com - it's the CA signature of the certificate that provides authenticity guarantees.

Adding authenticated attributes using MS CryptoApi

I'm struggling adding authenticated attributes (OCSP data) to my message using CryptoApi. I first used CryptoApi's simplified message functions, but now switch to the low-level message functions, thinking that I would be able to control the message structure better. But I am once again stuck. My process is as follows:
Initialize CMSG_SIGNER_ENCODE_INFO and CMSG_SIGNED_ENCODE_INFO structure
I create a CRYPT_ATTRIBUTE for the ocsp date and specifies it in the CMSG_SIGNER_ENCODE_INFO structure
I then call CryptMsgCalculateEncodedLength to get the size
CryptMsgOpenToEncode with CMSG_SIGNED as the message type
CryptMsgUpdate, to insert my content into the message
CryptMsgGetParam with CMSG_CONTENT_PARAM to get the encoded blob
CryptMsgClose, I'm done with the message for now.
I open the message again to get the CMSG_ENCRYPTED_DIGEST, which is sent to a TSA and the result is added as an unaunthenticated attribute using CryptMsgControl.
I'm using this to sign signature tags in Adobe. So when there is no authenticated attributes, I receive three green check from Adobe:
The document has not been modified...
The document is signed by the current user
The signature includes an embedded timestamp (and the timestamp is validate)
But as soon as the authenticated attribute is added the signer's identity is invalidated and the timestamp data in incorrect. The CMSG_COMPUTED_HASH_PARAM when authenticated attributes are added and when not, differs. Should this not be the same? Since the document digest is of the content of the document and not of the authenticated attribute.
Is there another way to add authenticated attributes? I've tried to add it as a signer using CryptMsgControl, but that did not help either...
how about this step on adding the authenticated attributes for signing, example time stamping,
CryptEncodeObject(PKCS_7_ASN_ENCODING, szOID_RSA_signingTime, &curtime, pTime, &szTime);
pTime = (BYTE *)LocalAlloc(GPTR, szTime);
CryptEncodeObject(PKCS_7_ASN_ENCODING, szOID_RSA_signingTime, &curtime, pTime, &szTime);
time_blob.cbData = szTime;
time_blob.pbData = pTime;
attrib[0].pszObjId = szOID_RSA_signingTime;
attrib[0].cValue = 1;
attrib[0].rgValue = &time_blob;
CosignerInfo.cAuthAttr = 1;
CosignerInfo.rgAuthAttr = attrib;
and that Cosigner params is from CMSG_SIGNER_ENCODE_INFO CosignerInfo;

ocsps are not shown but I have in DSS

I've just sign document. and Add LTV too (with Document Secure Story and TSA); but adobe reader tells me that LTV is not enabled.
I found the problem. Adobe reader tells me that OCSP is not embedded in the document.
After adding time stamp I just create DSS dictionary and add certificates and ocsp responses.
PDDocumentCatalog catalog = template.getDocumentCatalog();
COSDictionary catalogDictionary = catalog.getCOSDictionary();
COSDictionary dssDictionary = new COSDictionary();
COSArray cosOcsps = CertUtils.getOcspResponseCosArray(ocspResp);
COSArray cosCerts = CertUtils.getCertificateCosArray(certs);
dssDictionary.setItem(COSName.getPDFName("Certs"), cosCerts);
dssDictionary.setItem(COSName.getPDFName("OCSPs"), cosOcsps);
catalogDictionary.setItem(COSName.getPDFName("DSS"), dssDictionary);
is not that enough to add OCSPs?
I sign document like Pades-BES. does it needs VRI? I know that id does not need.
that's sample
PDF Document
The specification ETSI TS 102 778-4 (aka PAdES part 4) in Annex A.1 Document Security Store requires the value of the OCSPs entry in a DSS dictionary to be
An array of (indirect references to) streams, each containing a BER-encoded Online Certificate Status Protocol (OCSP) response (see RFC 2560 [8]). This array contains OCSPs that may be used in the validation of any signatures in the document.
You, on the other hand, only used an array of the BasicOCSPResponse objects which were contained in the original OCSPResponse objects you received.
OCSPResponse ::= SEQUENCE {
responseStatus OCSPResponseStatus,
responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
ResponseBytes ::= SEQUENCE {
responseType OBJECT IDENTIFIER,
response OCTET STRING }
For a basic OCSP responder, responseType will be id-pkix-ocsp-basic.
The value for response SHALL be the DER encoding of BasicOCSPResponse.
BasicOCSPResponse ::= SEQUENCE {
tbsResponseData ResponseData,
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
(from section 4.2.1 ASN.1 Specification of the OCSP Response of RFC 2560)
Probably you were not aware that you only used this inner object because many security libraries after requesting an OCSP response unwrap the original OCSPResponse, check the contained OCSPResponseStatus, and (if it indicates success) only return the contained BasicOCSPResponse or (otherwise) throw some exception.
If that's the case, you can simply wrap your BasicOCSPResponse in an OCSPResponse using the OCSPResponseStatus value successful (0) before putting it into the document.

How should an application authenticate with a datastore?

I'm writing an iPad game that sends hi-score type data (ie data beyond what Game Center supports) to a Google appengine datastore. It sends these updates via http GET or POST requests, such as http://myapp.appspot.com/game/hiscore/925818
Here is how I thought to ensure the appengine datastore isn't spammed with false data.
zip/encrypt the payload data using hardcoded p#ssw0rd saved in the iOS binary. Encode that binary data as base64. Pass base64 payload in the url query string or in the POST data. At handler, unbase64, then unzip data with p#ssw0rd. Follow instructions in payload to update highscore-type data.
CON: If p#ssw0rd is somehow derived from the iOS binary, this scheme can be defeated.
Is this adequate/sufficient? Is there another way to do this?
There is absolutely no way to make sure it's your client that sends the data. All you can try is to obfuscate some thing to make it harder for spammers to submit data.
However I think there are two thing you can do:
Have some kind of secrect key saved in the binary
Have a custom algorithm calculating some checksum
Maybe you can go with a combination of both. Let me give you an example:
Create some custom (complex!) alorithm like (simplyfied):
var result = ((score XOR score / 5) XOR score * 8) BITSHIFT_BY 3
Then use your static stored key with that result and a well known hash function like:
var hash = SHA256(StaticKey + result)
Then send that hash with the score to the server. The server has to "validate" the hash by performing the exact same steps (evaluate algorithm + do the SHA256 stuff) and compare the hashes. If they match the score hopefully comes from your app otherwise throw it away, it comes from a spammer.
However this is only one thing you can do. Have a look at the link from mfanto, there are many other ideas that you can look at.
Be sure to not tell anybody about how you're doing it since this is security through obscurity.
Ok me, there are 2 methods to do this.
1) Purchase an SSL certificate for $FREE.99 and open HTTPS connections only to your server to submit hiscore type data. Connection speed should be around 500 ms due to handshake roundtrip time.
2) Embed an RSA public key certificate in your iOS app, and have the RSA private key on your server.
You can then do 1 of 2 things with this second scheme:
IF your data messages are really small (≤256 B) you can just encrypt and send 256B packages (RSA payload is limited by the number of bits in the key)
ELSE IF the data is too large (>256B), generate a random symmetric key (AES), and pack:
SYMMETRIC AES KEY ENCRYPTED WITH RSA PUBLIC KEY
BINARY DATA ENCODED WITH SYMMETRIC AES KEY
The server then takes the first 256 bytes and decodes it, then the server uses that AES key to decrypt the rest of the message.
The above 2 only prevent eavesdropping, but it means the data format of your messages is hidden. At some level, it is still a type of security by obscurity, since if the hacker has your public key AND your message format, they can manufacture messages.