1781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckipackage signtool;
2781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
3781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.io.*;
4781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.util.Properties;
5781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.util.ArrayList;
6781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
7781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.internet.*;
8781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.MessagingException;
9781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.mail.Session;
10781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.activation.MailcapCommandMap;
11781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport javax.activation.CommandMap;
12781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
13781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.PrivateKey;
14781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.Security;
15781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.KeyFactory;
16781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.KeyStore;
17781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.NoSuchAlgorithmException;
18781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.spec.PKCS8EncodedKeySpec;
19781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.spec.InvalidKeySpecException;
20781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.X509Certificate;
21781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateFactory;
22781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.Certificate;
23781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateException;
24781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport java.security.cert.CertificateEncodingException;
25781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
26781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.jce.provider.BouncyCastleProvider;
27781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
28781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
29781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.ContentSigner;
30781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
31781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSProcessableByteArray;
32781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedGenerator;
33781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedDataGenerator;
34781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedGenerator;
35781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSProcessable;
36781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSSignedData;
37781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cms.CMSTypedData;
38781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.cert.jcajce.JcaCertStore;
39781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.util.Store;
40781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.ASN1InputStream;
41781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.DEROutputStream;
42781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckiimport org.bouncycastle.asn1.ASN1Object;
43781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
44781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
45781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzyckipublic class SignImg {
46781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
47781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    /* It reads private key in pkcs#8 formate
48781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki     * Conversion:
49781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki     * openssl pkcs8 -topk8 -nocrypt -outform DER < inkey.pem > outkey.pk8
50781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki     */
51781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static PrivateKey getPrivateKey(String path) throws IOException, FileNotFoundException, NoSuchAlgorithmException, InvalidKeySpecException {
52781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        File file = new File(path);
53781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        FileInputStream fis = new FileInputStream(file);
54781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        byte[] data = new byte[(int)file.length()];
55781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.read(data);
56781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.close();
57781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
58781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        PKCS8EncodedKeySpec kspec = new PKCS8EncodedKeySpec(data);
59781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        KeyFactory kf = KeyFactory.getInstance("RSA");
60781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        PrivateKey privateKey = kf.generatePrivate(kspec);
61781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
62781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        return privateKey;
63781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
64781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
65781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static MimeBodyPart getContent(String path) throws IOException, FileNotFoundException, MessagingException {
66781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        MimeBodyPart body = new MimeBodyPart();
67781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
68781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        File file = new File(path);
69781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        FileInputStream fis = new FileInputStream(file);
70781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        byte[] data = new byte[(int)file.length()];
71781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.read(data);
72781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.close();
73781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
74781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        body.setContent(data, "application/octet-stream");
75781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
76781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        return body;
77781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
78781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
79781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static CMSProcessableByteArray getCMSContent(String path) throws IOException, FileNotFoundException, MessagingException {
80781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        File file = new File(path);
81781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        FileInputStream fis = new FileInputStream(file);
82781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        byte[] data = new byte[(int)file.length()];
83781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.read(data);
84781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        fis.close();
85781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        CMSProcessableByteArray cms = new CMSProcessableByteArray(data);
86781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
87781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        return cms;
88781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
89781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
90781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static X509Certificate readCert(String path) throws IOException, FileNotFoundException, CertificateException {
91781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        File file = new File(path);
92781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        FileInputStream is = new FileInputStream(file);
93781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
94781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        CertificateFactory cf = CertificateFactory.getInstance("X.509");
95781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        Certificate cert = cf.generateCertificate(is);
96781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        is.close();
97781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
98781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        return (X509Certificate) cert;
99781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
100781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
101781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static void save(MimeBodyPart content, String path) throws IOException, FileNotFoundException, MessagingException {
102781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        File file = new File(path);
103781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        FileOutputStream os = new FileOutputStream(file);
104781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
105781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        content.writeTo(os);
106781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
107781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        os.close();
108781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
109781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
110781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    private static Store certToStore(X509Certificate certificate) throws CertificateEncodingException {
111781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
112781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        certList.add(certificate);
113781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        return new JcaCertStore(certList);
114781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
115781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
116781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    public static void setDefaultMailcap()
117781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    {
118781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        MailcapCommandMap _mailcap =
119781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            (MailcapCommandMap)CommandMap.getDefaultCommandMap();
120781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
121781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        _mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
122781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        _mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
123781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        _mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
124781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        _mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
125781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        _mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
126781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
127781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        CommandMap.setDefaultCommandMap(_mailcap);
128781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
129781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
130781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    public static void main(String[] args) {
131781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        try {
132781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            if (args.length < 4) {
133781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki                System.out.println("Usage: signimg data private_key certificate output");
134781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki                return;
135781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            }
136781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("Signing the image");
137781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            setDefaultMailcap();
138781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
139781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            Security.addProvider(new BouncyCastleProvider());
140781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
141781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            PrivateKey key = getPrivateKey(args[1]);
142781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("File read sucessfully");
143781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
144781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
145781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
146781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            CMSTypedData body = getCMSContent(args[0]);
147781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("Content read sucessfully");
148781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
149781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            X509Certificate cert = (X509Certificate) readCert(args[2]);
150781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("Certificate read sucessfully");
151781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
152781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(key);
153781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
154781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            Store certs = certToStore(cert);
155781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
156781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            generator.addCertificates(certs);
157781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            generator.addSignerInfoGenerator(
158781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki                          new JcaSignerInfoGeneratorBuilder(
159781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki                                new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
160781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki                          .build(sha256Signer, cert));
161781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
162781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            CMSSignedData signed = generator.generate(body, true);
163781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("Signed");
164781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
165781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            Properties props = System.getProperties();
166781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            Session session = Session.getDefaultInstance(props, null);
167781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
168781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            File file = new File(args[3]);
169781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            FileOutputStream os = new FileOutputStream(file);
170781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
171781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            ASN1InputStream asn1 = new ASN1InputStream(signed.getEncoded());
172781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            ByteArrayOutputStream out = new ByteArrayOutputStream();
173781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            DEROutputStream dOut = new DEROutputStream(os);
174781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            dOut.writeObject(ASN1Object.fromByteArray(signed.getEncoded()));
175781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki
176781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        }
177781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        catch (Exception ex) {
178781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki            System.out.println("Exception during programm execution: " + ex.getMessage());
179781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki        }
180781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki    }
181781f9fc4af6002f5eb47b2bad852e1090d525298Szymon Starzycki}
182