How to sign PDF with a x.509 signature/certificate - java

tl;dr: I'm looking for a CLI tool that can be fed with a x.509 file and an input PDF and out comes a signed PDF. Best scenario for NodeJS
Hi there. I'm getting a little bit frustrated. I'm looking for a tool which can sign PDF files using the command line. I do use an online service called handy-signatur.at (A service from www.a-trust.at) that generates a x.509 certificate.
I found a page that mentions several tools but it seems that all of them are out of date.
I tried PortableSigner in particular, but that needs Java 6 and I couldn't get it to work on Ubuntu (Server and Desktop edition) 17.04.
/edit: I can't get PortableSigner to work because Java 6 and 7 is no longer available and probably not even safe to use.
Is there any commandline tool out there to sign PDFs?
Thank you guys so much!

Seems PortableSigner do the work.
If you are worried about Java 7 support. Try it with Java 8, probably the digital signature functions still work because nothing important has changed between 7&8
Alternatively, implementing a signature program with Java using libraries like PDFBox or itext is relatively easy. Here you have a full example with pdfbox. Note that it has a main
https://svn.apache.org/repos/asf/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java
usage:
java org.apache.pdfbox.examples.signature.CreateSignature
<pkcs12_keystore> <password> <pdf_to_sign>

You can write your own Java scripts here is the reference
http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/AcrobatDC_js_api_reference.pdf
var myEngine = security.getHandler( "Adobe.PPKLite" );
myEngine.login( "password", "/C/Users/username/Desktop/PrivateUser.pfx" );
var myInfo = {password: "password",
reason: "SaveAs Test",
mdp: "defaultAndComments"};
this.certifyInvisibleSign({
oSig:myEngine,
oInfo:myInfo,
cDIPath:"/c/temp/sigSign.pdf",
cLegalAttest: "Certified using JavaScript",
bUI:false
});

As far as I could find, openSSL is the only maintained tool which might support inputting an x.509 file and a PDF in order to generate a signed PDF file.
See the openSSL man page for x509.
I also found a PortableSigner2 project, but it also wasn't current.

PortableSigner is a tool to digitally sign PDFs with X.509 certificates.
It's a Java app so the installation of a compatible JRE is required (according to the website: 1.6 and 1.7).
You can refer the following link to get the detailed information for the same
http://portablesigner.sourceforge.net/

As others have mentioned, the openssl command can do this but it took me a while to find an example.
Here's the website with a good example:
https://raymii.org/s/tutorials/Sign_and_verify_text_files_to_public_keys_via_the_OpenSSL_Command_Line.html
and the commands in case the link doesn't work:
To sign:
openssl dgst -sha256 -sign mycert.key -out sign.txt.sha256 sign.txt
Where mycert.key is the private key of your x509 certificate.
To verify:
openssl dgst -sha256 -verify mycert.pub -signature sign.txt.sha256 sign.txt
Where mycert.pub is the public key of your certificate (NOT the certificate itself).

Related

Sign Android Native apk with Adobe Air certificate

I need help with signing Android Native app with existing .p12 certificate generated for Adobe Air. Application was done in Adobe Air few years ago, signed and published to Google play. Now when moving from Adobe Air to Android Native, in order to upgrade app to the new version on store, it needs to be signed with the same private key. The problem is that it is not possible to open/read the key via keytool on newer versions of java. Trying to read the .p12 certificate will return:
java.security.cert.CertificateException: Unable to initialize, java.io.IOException: DerInputStream.getLength(): Redundant length bytes found
or
keytool error: java.io.IOException: Invalid keystore format
depending on a command I'm trying to execute.
(1) Asking old friend Google didn't bring much, but more frustration. I did like it was suggested in jira ticket of openjdk, i tried to use OpenSSL to fix redundant bytes in this way:
openssl pkcs12 -in pkcs12-file -out key-and-cert -nodes -passin pass:abcXYZ
openssl pkcs12 -in key-and-cert -export -out new-pkcs12-file -passout pass:abcXYZ
This commands will execute successfully, BUT, the generated SHA1 key (...:F7) will not be the same as original one (...:E5)! That actually is not a surprise, since changing any part of the file(like removing redundant bytes) will end in different SHA key. Ok, so obviously this is not a solution.
(2) Next thing I tried, was to extract private key and certs as plain text(.pem) files from my original .p12 certificate, in order to try to create a new .jks file. So I managed to extract my private key, and my certs from original .p12 certificate into plain text. Then using keytools and openssl I tried to create my new .jks file with original data as mentioned here:
How to Creat JKS KeyStore file from existing private key and certificate
Well, it worked in a way that my new .jks file was created, BUT the SHA1 key (again ...:F7) was not the same as the original one (...:E5).
(3) My next step was reading and looking a much more over the internet. Found some solutions that are suggesting that conversion was last working in java 1.8.0_111, and every distribution of java above that had the same problem. So, let's install java 1.8.0_111 and give it a shot. Sure, it didn't worked. The problem stayed the same. Also tried in java 1.10, and Oracle versions, still not working
(4) Last thing I did, I installed java 1.6 and tried with it, and there was no problem, it worked perfectly, i managed to read the .p12 with no problem, convert it to .jks with no problems at all, worked like a charm. Generated SHA1 key (...:E5) was the same as the original one (...:E5)!!!
BUT, the problem is that application I need to sign with that certificate is developed with java 1.8, and java 1.8 can't read that certificate. So I'm quite frustrated at this point, since it's already couple of days I'm losing on this problem.
So, can't read it, can't regenerate it, can't sign the app ...
So my question is: is it possible, and if it is, how to sign Android apk with .p12 certificate?
I'm not sure how common this problem is, but any possible help is more then welcome.
I finally did manage to find the best solution to this problem that I was facing. And actually the solution was right in front of me, with a little bit of effort.
I tried switching to java 1.6 version just to sign the app, and actually I did manage to do the signing. Afterwords i would transfer the app again to 1.8 java environment and did the zipalign, successfully! When I managed all of this, i was really happy, hoping Google Play will finally accept the apk.
My hope died as soon as I uploaded the apk to the store. Google Play said that not all the files were signed and that I need to upload apk with all files signed. Can you imagine the level of frustration?
My problem was i had old .p12 certificate that was not possible to read in AndroidStudio or to convert to jks, but I was able to extract my private key, and my certificate from that file.
After I tried to look around a bit more, I managed to find the solution with apksigner tool.
Actually what i did was, I built an .apk signed with debug key, and after that just used apksigner tool, provided with my private key and certificate file, and finally the apk was signed. Then I was able to upload the apk to the Google Play Store with no problems.
The command that I used to sign the apk with apksigner tool is:
./apksigner sign --key <your_private_key_in_.pcks8> --cert <your_certificate_in.der> <your_debug_signed_application_in.apk>
Here it is necessary to notice that your key has to be in .pcks8 format, otherwise the command wont work. Also apksigner was run as script on linux, thats why "./" before apksigner. If you have this tool on windows or installed on some other way, you should be good to start command just with apksigner.exe or apksigner.
If you have your key in plain text (.pem) format, transfering it to the .pcks8 format can be done with openssl command:
openssl pkcs8 -topk8 -inform PEM -outform DER -in <your_private_key_in.pem> -out <your_private_key_in.pcks8> -nocrypt
Hate to be the bearer of bad news, but this is one of the reasons why version control is paramount in enterprise environments. When things update, builds can break.
There are three things I thought of which I didn't see listed above:
1] If you are using an IDE like Android Studio or IntelliJ, you could try breaking your project down into Java 1.8 code and Java 1.6 code. For example, you could create a keystore-signing module, and then add gradle commands for it to build using Java 1.6, while the rest of your project modules build using Java 1.8.
2] You could try creating your own signing class, and make direct calls to Java 1.6 classes which you could add manually to your project.
3] You could use a new keystore, change your package name, and point your former store listing to your new Java 1.8 app. This is probably the least preferable as it would be considered a new app on the store.
We could not sign our apps with legit certificates. So instead we published using a self-made certificate to compile / publish the app. Then we used Microsoft's Signtool(.exe) to do the job. Worked like a charm.

Speed up jarsigner with hardware token?

I formerly signed jar files using a locally installed keystore as part of an automated build. I'm now faced with having to use a hardware-based device, due to recent changes to minimal code signing requirements, and while I've figured out how to do it, I'm seeing extreme slow-downs.
Just as one example, a jar file with 180 classes that I could formerly sign in about half a second is now taking about 30 seconds. As it's going, I see my token device's access light flashing a few times a second, presumably once for each class in the jar file.
Is there any way to speed this up, e.g. some way to reduce the token accesses to a single access for the entire jar file?
It was not an answer, but it is too long for a comment:
If your supposition of an access to the token for any file is correct, then it would mean the hash of the files is also being calculated in the device, not only the signature.
Does your PKCS11 device have a logging option that could show which pkcs11 calls are the device receiving (hash operations are called C_Digest in PKCS11) to confirm?
Maybe with the option mentioned in java keytool with opensc pkcs#11 provider only works with debug option enabled (I haven't tried it)
Since I don't know if there's any way to tell jarsigner to hash by software and to sign by hardware, if you can't find a better answer, maybe you can write your own provider: ( http://docs.oracle.com/javase/7/docs/technotes/guides/security/crypto/HowToImplAProvider.html ) :
implementing a software hash (MessageDigestSpi, just forwarding the call to the default software java provider)
and a device signature (SignatureSpi, just forwarding the call to the PKCS11 provider configured in java ). I think it was Signature signature = Signature.getInstance("SHA1withRSA", "SunPKCS11") and so on. And analog for KeyStoreSpi.
And then call jarsigner with your provider as parameter.
Try adding -sigalg SHA512withRSA to your jarsigner options.
For further information, check my answer to a related question

Java 9 deprecating SHA1 certificates, or another issue at work?

[UPDATE] Oracle just revised the crypto roadmap (https://www.java.com/en/jre-jdk-cryptoroadmap.html), they will not deprecate SHA-1 for codesigning: 2017-03-14 Target date changed from 2017-04-18 to 2017-07-18. Narrowed scope from all SHA-1 usage: only TLS will be affected, *code signing will not not be affected at this time*.
This does not affect, in any way, the fine answer I received below, as it will apply, no doubt, in the future.
--
Original post:
Attempting to run our Webstart-deployed Java application on JRE 9 ea 153, I get the following popup:
Looking further at details, I see that the certificate will still be valid for a while:
, therefore, I am wondering if deprecating SHA1 is the reason?
This certainly does sound like a policy in line with (others' in the industry), but the message doesn't really sound neophyte-friendly (especially if it is meant to face end-users), so I am left wondering.
I looked for a roadmap. This is what I found, but I'm not sure whether I'm interpreting correctly this paragraph correctly:
Disable SHA-1 in certificate chains anchored by roots included by default in Oracle's JDK; local or enterprise CAs are not affected. Signed code that is timestamped before 2017-01-01 is not affected.
as the reason for the failure above. I would very much appreciate a confirmation.
FWIW, our certificate is issued by a CA, which I presume is different from an "enterprise" CA.
Thank you.
If that signed Jar is meant to be used by end-users there is no way a package that was SHA1 signed in 2017 is going to work.
Phasing out SHA1 was announced a long time ago.
Only way would be to install a local CA or something, but that is not going to happen on end-user machines (neither should it).
To sign a Jar for your end-users you need a new valid SHA-256 Cert from your CA, and re-sign any Jar that was signed with the old one AFTER 31.12.2016.
Your cert would have expired in a few month anyway.
Whether you have to dualsign your jars depends on the oldest JVM version you are targeting. As far as i understand it anything >=1.4.2 supports SHA-256. If you want to target even older Versions (hell when i started programming java 1.5 was already considered OLD) you would need something like dual-signing. More Information can be found here and here
"How to dual sign a jar" is probably a new topic because it is hardly related to this question i think.

Java web application security - sign, ssl & csr

With the Java 8 security update, uploading a java application onto a webpage has been a nightmare. Self-signing is no longer a valid option (as it appears to me). I have recently bought a GeoTrust RapidSSL certificate in hopes that the website will be secured enough for Java not to block the application, but hasn't been like that (its been so confusing all-round).
My webhost setup the ssl so its there, website uses https. But the second area needs to be configured (I'm thinking by me), it wants me to choose the 'Web Server Type' which I believe its CPanel & WHM and underneath 'CSR' (image: http://postimg.org/image/jdnjjt6gr/).
Now I use Eclipse, and I installed this Keytool plugin (link: http://marketplace.eclipse.org/content/keytool) which allows me to create a keystore & csr (I really have no idea what a keystore, keytool, csr and jks are; I tried to study them on docs and available websites but its just all confusing). When i tried to create a simple one it gave me a bunch of numbers which Im presuming is encrypted with a Begin and a End on its borders (top and bottom).
I'm really confused on what I need to do, I just want to get my application running - I'm just really annoyed by this security block. What can I do? or What am I supposed to do? & Could anyone briefly explain what keystore, keytool, csr and jks are briefly?
Thanks in advance. If you could simplify things and/or give examples, that would be extremely helpful.

Is it possible to re-sign a Java applet with a newer certificate?

I have a signed Java applet, and the certificate just expired. I have a new certificate, but I'm not sure that I can find the original, unsigned applet jar file. Is there any way that I can take the signed jar and replace the old certificate with a new one? Thanks.
You can't wrap it.
However, you should be able to simply re-sign the JAR with a different certificate. Signing a JAR doesn't encrypt it in anyway. It just adds stuff to the manifest section.
This is not a security issue. The re-signed certificate is different to the original one, the end-user has to accept it all over again. (I don't think you can avoid that ... because it would be a security issue!)
Anyway, the simple approach is to just try re-signing the signed applet JAR, and see whether it works, and how it behaves when you try to run it as a user.
To solve a similar situation I deleted all signature files under META-INF/*.SF and META-INF/*.RSA and signed it again.
META-INF/MANIFEST.MF now contains both the old (unused) lines with SHA-1 hash and the new SHA-256 ones; the remaining old ones don't seem to be a problem: jarsigner -verify -verbose reports everything's OK with the new signature.

Categories