The code in the question is based on a multi-phase approach:
- Sign the PDF injecting an empty byte array as signature container (by use of the
ExternalBlankSignatureContainer
). - Calculate the digest to sign (here incorrectly a digest for the whole file from the previous step is calculated, the digest must be calculated for the whole file except the signature container placeholder).
- Request signature container for that document hash.
- Inject signature container into the placeholder in the file from the first step.
If the signature server can take a long time to return a signature container, such an approach is appropriate but in the case at hand comments clarify
The server gives response quickly(just few seconds)
In such a use case one should proceed in a single step approach (as far as iText signing API calls are concerned):
PdfReader reader = new PdfReader(...);
PdfStamper stamper = PdfStamper.createSignature(reader, ..., '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "Signature");
ExternalSignatureContainer external = new RemoteSignatureContainer();
MakeSignature.signExternalContainer(appearance, external, 8192);
with a custom ExternalSignatureContainer
implementation RemoteSignatureContainer
:
class RemoteSignatureContainer implements ExternalSignatureContainer {
@Override
public byte[] sign(InputStream data) throws GeneralSecurityException {
[return a CMS signature container signing the data from the InputStream argument]
}
@Override
public void modifySigningDictionary(PdfDictionary signDic) {
signDic.put(PdfName.FILTER, PdfName.ADOBE_PPKLITE);
signDic.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED);
}
}
I don’t know your API to access your signature server but based on your UPDATE 2 I assume the sign
method in your RemoteSignatureContainer
would look like this:
@Override
public byte[] sign(InputStream data) throws GeneralSecurityException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
byte[] messageHash = messageDigest.digest(StreamUtil.inputStreamToArray(data));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < messageHash.length; ++i) {
sb.append(Integer.toHexString((messageHash[i] & 0xFF) | 0x100).substring(1, 3));
}
String msisdn = "97688888888";
try {
Client client = new Client(msisdn, sb.toString());
String strResult = client.sendRequest();
JSONObject jsonResult = new JSONObject(strResult);
String base64Signature = jsonResult
.getJSONObject("MSS_SignatureResp")
.getJSONObject("MSS_Signature")
.getString("Base64Signature");
return Base64.getDecoder().decode(base64Signature);
} catch (IOException | JSONException e) {
throw new GeneralSecurityException(e);
}
}
CLICK HERE to find out more related problems solutions.