1 package org
.argeo
.cms
.bc
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.io
.OutputStream
;
7 import java
.lang
.reflect
.InvocationTargetException
;
8 import java
.math
.BigInteger
;
9 import java
.net
.InetAddress
;
10 import java
.nio
.file
.Files
;
11 import java
.nio
.file
.Path
;
12 import java
.security
.GeneralSecurityException
;
13 import java
.security
.KeyPair
;
14 import java
.security
.KeyPairGenerator
;
15 import java
.security
.KeyStore
;
16 import java
.security
.PrivateKey
;
17 import java
.security
.Provider
;
18 import java
.security
.SecureRandom
;
19 import java
.security
.Security
;
20 import java
.security
.cert
.Certificate
;
21 import java
.security
.cert
.CertificateException
;
22 import java
.security
.cert
.X509Certificate
;
23 import java
.util
.Arrays
;
24 import java
.util
.Date
;
26 import javax
.security
.auth
.x500
.X500Principal
;
28 import org
.argeo
.api
.cms
.CmsLog
;
29 import org
.bouncycastle
.asn1
.pkcs
.PrivateKeyInfo
;
30 import org
.bouncycastle
.cert
.X509CertificateHolder
;
31 import org
.bouncycastle
.cert
.X509v3CertificateBuilder
;
32 import org
.bouncycastle
.cert
.jcajce
.JcaX509CertificateConverter
;
33 import org
.bouncycastle
.cert
.jcajce
.JcaX509v3CertificateBuilder
;
34 import org
.bouncycastle
.openssl
.PEMParser
;
35 import org
.bouncycastle
.openssl
.jcajce
.JcaPEMKeyConverter
;
36 import org
.bouncycastle
.openssl
.jcajce
.JceOpenSSLPKCS8DecryptorProviderBuilder
;
37 import org
.bouncycastle
.operator
.ContentSigner
;
38 import org
.bouncycastle
.operator
.InputDecryptorProvider
;
39 import org
.bouncycastle
.operator
.OperatorCreationException
;
40 import org
.bouncycastle
.operator
.jcajce
.JcaContentSignerBuilder
;
41 import org
.bouncycastle
.pkcs
.PKCS8EncryptedPrivateKeyInfo
;
42 import org
.bouncycastle
.pkcs
.PKCSException
;
44 /** Utilities around the BouncyCastle crypto library. */
45 public class BcUtils
{
46 private final static CmsLog log
= CmsLog
.getLog(BcUtils
.class);
48 private final static String BC_SECURITY_PROVIDER_FIPS
= "BCFIPS";
49 // private final static String BC_SECURITY_PROVIDER_NON_FIPS = "BC";
50 public final static String BC_SECURITY_PROVIDER
;
54 clss
= Class
.forName("org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider");
55 } catch (ClassNotFoundException e
) {
56 log
.warn("Bouncy Castle FIPS provider could not be initialised,"
57 + " we assume the non-FIPS provider is configured externally. (" + e
+ ")");
59 clss
= Class
.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
60 } catch (ClassNotFoundException e1
) {
66 Provider provider
= (Provider
) clss
.getDeclaredConstructor().newInstance();
67 Security
.addProvider(provider
);
68 BC_SECURITY_PROVIDER
= provider
.getName();
69 } catch (IllegalAccessException
| InstantiationException
| IllegalArgumentException
70 | InvocationTargetException
| NoSuchMethodException
| SecurityException e
) {
71 throw new IllegalStateException("Cannot load Bouncy Castle provider " + clss
, e
);
74 throw new IllegalStateException("Cannot load any Bouncy Castle provider");
78 public static boolean isFipsProvider() {
79 return BC_SECURITY_PROVIDER
.equals(BC_SECURITY_PROVIDER_FIPS
);
83 * openssl req -x509 -newkey rsa:3072 -keyout node.key -out node.crt -sha256 -days 365 -nodes -subj "/O=UNSECURE/OU=UNSECURE/CN=$(hostname)"
85 public static void createSelfSignedKeyStore(Path keyStorePath
, char[] keyStorePassword
, String keyStoreType
) {
86 // for (Provider provider : Security.getProviders())
87 // System.out.println(provider.getName());
88 // File keyStoreFile = keyStorePath.toFile();
89 char[] keyPwd
= Arrays
.copyOf(keyStorePassword
, keyStorePassword
.length
);
90 if (!Files
.exists(keyStorePath
)) {
92 Files
.createDirectories(keyStorePath
.getParent());
93 KeyStore keyStore
= getKeyStore(keyStorePath
, keyStorePassword
, keyStoreType
);
94 generateSelfSignedCertificate(keyStore
,
95 new X500Principal("CN=" + InetAddress
.getLocalHost().getHostName() + ",OU=UNSECURE,O=UNSECURE"),
97 saveKeyStore(keyStorePath
, keyStorePassword
, keyStore
);
98 if (log
.isDebugEnabled())
99 log
.debug("Created self-signed unsecure keystore " + keyStorePath
);
100 } catch (Exception e
) {
102 if (Files
.size(keyStorePath
) == 0)
103 Files
.delete(keyStorePath
);
104 } catch (IOException e1
) {
107 log
.error("Cannot create keystore " + keyStorePath
, e
);
110 throw new IllegalStateException("Keystore " + keyStorePath
+ " already exists");
114 public static X509Certificate
generateSelfSignedCertificate(KeyStore keyStore
, X500Principal x500Principal
,
115 int keySize
, char[] keyPassword
) {
117 KeyPairGenerator kpGen
= KeyPairGenerator
.getInstance("RSA", BC_SECURITY_PROVIDER
);
118 kpGen
.initialize(keySize
, new SecureRandom());
119 KeyPair pair
= kpGen
.generateKeyPair();
120 Date notBefore
= new Date(System
.currentTimeMillis() - 10000);
121 Date notAfter
= new Date(System
.currentTimeMillis() + 365 * 24L * 3600 * 1000);
122 BigInteger serial
= BigInteger
.valueOf(System
.currentTimeMillis());
123 X509v3CertificateBuilder certGen
= new JcaX509v3CertificateBuilder(x500Principal
, serial
, notBefore
,
124 notAfter
, x500Principal
, pair
.getPublic());
125 ContentSigner sigGen
= new JcaContentSignerBuilder("SHA256WithRSAEncryption")
126 .setProvider(BC_SECURITY_PROVIDER
).build(pair
.getPrivate());
127 X509Certificate cert
= new JcaX509CertificateConverter().setProvider(BC_SECURITY_PROVIDER
)
128 .getCertificate(certGen
.build(sigGen
));
129 cert
.checkValidity(new Date());
130 cert
.verify(cert
.getPublicKey());
132 keyStore
.setKeyEntry(x500Principal
.getName(), pair
.getPrivate(), keyPassword
, new Certificate
[] { cert
});
134 } catch (GeneralSecurityException
| OperatorCreationException e
) {
135 throw new RuntimeException("Cannot generate self-signed certificate", e
);
139 public static PrivateKey
loadPemPrivateKey(Reader reader
, char[] keyPassword
) {
140 try (PEMParser pemParser
= new PEMParser(reader
)) {
141 JcaPEMKeyConverter converter
= new JcaPEMKeyConverter().setProvider(BC_SECURITY_PROVIDER
);
142 Object object
= pemParser
.readObject();
143 PrivateKeyInfo privateKeyInfo
;
144 if (object
instanceof PKCS8EncryptedPrivateKeyInfo
) {
145 if (keyPassword
== null)
146 throw new IllegalArgumentException("A key password is required");
147 InputDecryptorProvider decProv
= new JceOpenSSLPKCS8DecryptorProviderBuilder().build(keyPassword
);
148 privateKeyInfo
= ((PKCS8EncryptedPrivateKeyInfo
) object
).decryptPrivateKeyInfo(decProv
);
149 } else if (object
instanceof PrivateKeyInfo
) {
150 privateKeyInfo
= (PrivateKeyInfo
) object
;
152 throw new IllegalArgumentException("Unsupported format for private key");
154 return converter
.getPrivateKey(privateKeyInfo
);
155 } catch (IOException
| OperatorCreationException
| PKCSException e
) {
156 throw new RuntimeException("Cannot read private key", e
);
160 public static X509Certificate
loadPemCertificate(Reader reader
) {
161 try (PEMParser pemParser
= new PEMParser(reader
)) {
162 X509CertificateHolder certHolder
= (X509CertificateHolder
) pemParser
.readObject();
163 X509Certificate cert
= new JcaX509CertificateConverter().setProvider(BC_SECURITY_PROVIDER
)
164 .getCertificate(certHolder
);
166 } catch (IOException
| CertificateException e
) {
167 throw new RuntimeException("Cannot read private key", e
);
171 private static KeyStore
getKeyStore(Path keyStoreFile
, char[] keyStorePassword
, String keyStoreType
) {
173 KeyStore store
= KeyStore
.getInstance(keyStoreType
, BC_SECURITY_PROVIDER
);
174 if (Files
.exists(keyStoreFile
)) {
175 try (InputStream fis
= Files
.newInputStream(keyStoreFile
)) {
176 store
.load(fis
, keyStorePassword
);
182 } catch (GeneralSecurityException
| IOException e
) {
183 throw new RuntimeException("Cannot load keystore " + keyStoreFile
, e
);
187 private static void saveKeyStore(Path keyStoreFile
, char[] keyStorePassword
, KeyStore keyStore
) {
189 try (OutputStream fis
= Files
.newOutputStream(keyStoreFile
)) {
190 keyStore
.store(fis
, keyStorePassword
);
192 } catch (GeneralSecurityException
| IOException e
) {
193 throw new RuntimeException("Cannot save keystore " + keyStoreFile
, e
);
201 // public static void main(String args[]) {
202 // createSelfSignedKeyStore(Paths.get("./selfsigned.p12"), "demo".toCharArray(), "PKCS12");