]> git.argeo.org Git - lgpl/argeo-commons.git/blob - PkiUtils.java
474a8995061040ca824a0b54fd8d373af54403db
[lgpl/argeo-commons.git] / PkiUtils.java
1 package org.argeo.cms.internal.runtime;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.io.Reader;
7 import java.math.BigInteger;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.security.GeneralSecurityException;
11 import java.security.KeyPair;
12 import java.security.KeyPairGenerator;
13 import java.security.KeyStore;
14 import java.security.KeyStoreException;
15 import java.security.PrivateKey;
16 import java.security.SecureRandom;
17 import java.security.Security;
18 import java.security.cert.Certificate;
19 import java.security.cert.CertificateException;
20 import java.security.cert.X509Certificate;
21 import java.util.Date;
22
23 import javax.security.auth.x500.X500Principal;
24
25 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
26 import org.bouncycastle.cert.X509CertificateHolder;
27 import org.bouncycastle.cert.X509v3CertificateBuilder;
28 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
29 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
30 import org.bouncycastle.jce.provider.BouncyCastleProvider;
31 import org.bouncycastle.openssl.PEMParser;
32 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
33 import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
34 import org.bouncycastle.operator.ContentSigner;
35 import org.bouncycastle.operator.InputDecryptorProvider;
36 import org.bouncycastle.operator.OperatorCreationException;
37 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
38 import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
39 import org.bouncycastle.pkcs.PKCSException;
40
41 /**
42 * Utilities around private keys and certificate, mostly wrapping BouncyCastle
43 * implementations.
44 */
45 class PkiUtils {
46 final static String PKCS12 = "PKCS12";
47
48 private final static String SECURITY_PROVIDER;
49 static {
50 Security.addProvider(new BouncyCastleProvider());
51 SECURITY_PROVIDER = "BC";
52 }
53
54 public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal,
55 int keySize, char[] keyPassword) {
56 try {
57 KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
58 kpGen.initialize(keySize, new SecureRandom());
59 KeyPair pair = kpGen.generateKeyPair();
60 Date notBefore = new Date(System.currentTimeMillis() - 10000);
61 Date notAfter = new Date(System.currentTimeMillis() + 365 * 24L * 3600 * 1000);
62 BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
63 X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(x500Principal, serial, notBefore,
64 notAfter, x500Principal, pair.getPublic());
65 ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
66 .build(pair.getPrivate());
67 X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
68 .getCertificate(certGen.build(sigGen));
69 cert.checkValidity(new Date());
70 cert.verify(cert.getPublicKey());
71
72 keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(), keyPassword, new Certificate[] { cert });
73 return cert;
74 } catch (GeneralSecurityException | OperatorCreationException e) {
75 throw new RuntimeException("Cannot generate self-signed certificate", e);
76 }
77 }
78
79 public static KeyStore getKeyStore(Path keyStoreFile, char[] keyStorePassword, String keyStoreType) {
80 try {
81 KeyStore store = KeyStore.getInstance(keyStoreType, SECURITY_PROVIDER);
82 if (Files.exists(keyStoreFile)) {
83 try (InputStream fis = Files.newInputStream(keyStoreFile)) {
84 store.load(fis, keyStorePassword);
85 }
86 } else {
87 store.load(null);
88 }
89 return store;
90 } catch (GeneralSecurityException | IOException e) {
91 throw new RuntimeException("Cannot load keystore " + keyStoreFile, e);
92 }
93 }
94
95 public static void saveKeyStore(Path keyStoreFile, char[] keyStorePassword, KeyStore keyStore) {
96 try {
97 try (OutputStream fis = Files.newOutputStream(keyStoreFile)) {
98 keyStore.store(fis, keyStorePassword);
99 }
100 } catch (GeneralSecurityException | IOException e) {
101 throw new RuntimeException("Cannot save keystore " + keyStoreFile, e);
102 }
103 }
104
105 // public static byte[] pemToPKCS12(final String keyFile, final String cerFile, final String password)
106 // throws Exception {
107 // // Get the private key
108 // FileReader reader = new FileReader(keyFile);
109 //
110 // PEMReader pem = new PemReader(reader, new PasswordFinder() {
111 // @Override
112 // public char[] getPassword() {
113 // return password.toCharArray();
114 // }
115 // });
116 //
117 // PrivateKey key = ((KeyPair) pem.readObject()).getPrivate();
118 //
119 // pem.close();
120 // reader.close();
121 //
122 // // Get the certificate
123 // reader = new FileReader(cerFile);
124 // pem = new PEMReader(reader);
125 //
126 // X509Certificate cert = (X509Certificate) pem.readObject();
127 //
128 // pem.close();
129 // reader.close();
130 //
131 // // Put them into a PKCS12 keystore and write it to a byte[]
132 // ByteArrayOutputStream bos = new ByteArrayOutputStream();
133 // KeyStore ks = KeyStore.getInstance("PKCS12");
134 // ks.load(null);
135 // ks.setKeyEntry("alias", (Key) key, password.toCharArray(), new java.security.cert.Certificate[] { cert });
136 // ks.store(bos, password.toCharArray());
137 // bos.close();
138 // return bos.toByteArray();
139 // }
140
141 public static void loadPem(KeyStore keyStore, Reader key, char[] keyPassword, Reader cert) {
142 PrivateKey privateKey = loadPemPrivateKey(key, keyPassword);
143 X509Certificate certificate = loadPemCertificate(cert);
144 try {
145 keyStore.setKeyEntry(certificate.getSubjectX500Principal().getName(), privateKey, keyPassword,
146 new java.security.cert.Certificate[] { certificate });
147 } catch (KeyStoreException e) {
148 throw new RuntimeException("Cannot store PEM certificate", e);
149 }
150 }
151
152 public static PrivateKey loadPemPrivateKey(Reader reader, char[] keyPassword) {
153 try (PEMParser pemParser = new PEMParser(reader)) {
154 JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
155 Object object = pemParser.readObject();
156 PrivateKeyInfo privateKeyInfo;
157 if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
158 if (keyPassword == null)
159 throw new IllegalArgumentException("A key password is required");
160 InputDecryptorProvider decProv = new JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword);
161 privateKeyInfo = ((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv);
162 } else if (object instanceof PrivateKeyInfo) {
163 privateKeyInfo = (PrivateKeyInfo) object;
164 } else {
165 throw new IllegalArgumentException("Unsupported format for private key");
166 }
167 return converter.getPrivateKey(privateKeyInfo);
168 } catch (IOException | OperatorCreationException | PKCSException e) {
169 throw new RuntimeException("Cannot read private key", e);
170 }
171 }
172
173 public static X509Certificate loadPemCertificate(Reader reader) {
174 try (PEMParser pemParser = new PEMParser(reader)) {
175 X509CertificateHolder certHolder = (X509CertificateHolder) pemParser.readObject();
176 X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
177 .getCertificate(certHolder);
178 return cert;
179 } catch (IOException | CertificateException e) {
180 throw new RuntimeException("Cannot read private key", e);
181 }
182 }
183
184 public static void main(String[] args) throws Exception {
185 final String ALGORITHM = "RSA";
186 final String provider = "BC";
187 SecureRandom secureRandom = new SecureRandom();
188 long begin = System.currentTimeMillis();
189 for (int i = 512; i < 1024; i = i + 2) {
190 try {
191 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM, provider);
192 keyGen.initialize(i, secureRandom);
193 keyGen.generateKeyPair();
194 } catch (Exception e) {
195 System.err.println(i + " : " + e.getMessage());
196 }
197 }
198 System.out.println((System.currentTimeMillis() - begin) + " ms");
199
200 // // String text = "a";
201 // String text =
202 // "testtesttesttesttesttesttesttesttesttesttesttesttesttesttest";
203 // try {
204 // System.out.println(text);
205 // PrivateKey privateKey;
206 // PublicKey publicKey;
207 // char[] password = "changeit".toCharArray();
208 // String alias = "CN=test";
209 // KeyStore keyStore = KeyStore.getInstance("pkcs12");
210 // File p12file = new File("test.p12");
211 // p12file.delete();
212 // if (!p12file.exists()) {
213 // keyStore.load(null);
214 // generateSelfSignedCertificate(keyStore, new X500Principal(alias),
215 // 513, password);
216 // try (OutputStream out = new FileOutputStream(p12file)) {
217 // keyStore.store(out, password);
218 // }
219 // }
220 // try (InputStream in = new FileInputStream(p12file)) {
221 // keyStore.load(in, password);
222 // privateKey = (PrivateKey) keyStore.getKey(alias, password);
223 // publicKey = keyStore.getCertificateChain(alias)[0].getPublicKey();
224 // }
225 // // KeyPair key;
226 // // final KeyPairGenerator keyGen =
227 // // KeyPairGenerator.getInstance(ALGORITHM);
228 // // keyGen.initialize(4096, new SecureRandom());
229 // // long begin = System.currentTimeMillis();
230 // // key = keyGen.generateKeyPair();
231 // // System.out.println((System.currentTimeMillis() - begin) + " ms");
232 // // keyStore.load(null);
233 // // keyStore.setKeyEntry("test", key.getPrivate(), password, null);
234 // // try(OutputStream out=new FileOutputStream(p12file)) {
235 // // keyStore.store(out, password);
236 // // }
237 // // privateKey = key.getPrivate();
238 // // publicKey = key.getPublic();
239 //
240 // Cipher encrypt = Cipher.getInstance(ALGORITHM);
241 // encrypt.init(Cipher.ENCRYPT_MODE, publicKey);
242 // byte[] encrypted = encrypt.doFinal(text.getBytes());
243 // String encryptedBase64 =
244 // Base64.getEncoder().encodeToString(encrypted);
245 // System.out.println(encryptedBase64);
246 // byte[] encryptedFromBase64 =
247 // Base64.getDecoder().decode(encryptedBase64);
248 //
249 // Cipher decrypt = Cipher.getInstance(ALGORITHM);
250 // decrypt.init(Cipher.DECRYPT_MODE, privateKey);
251 // byte[] decrypted = decrypt.doFinal(encryptedFromBase64);
252 // System.out.println(new String(decrypted));
253 // } catch (Exception e) {
254 // e.printStackTrace();
255 // }
256
257 }
258
259 }