1
1
package com .csviri .jenvtest ;
2
2
3
+ import org .bouncycastle .asn1 .x500 .X500Name ;
4
+ import org .bouncycastle .asn1 .x509 .Extension ;
5
+ import org .bouncycastle .asn1 .x509 .GeneralName ;
6
+ import org .bouncycastle .asn1 .x509 .GeneralNames ;
7
+ import org .bouncycastle .cert .X509CertificateHolder ;
8
+ import org .bouncycastle .cert .jcajce .JcaX509CertificateConverter ;
9
+ import org .bouncycastle .cert .jcajce .JcaX509v3CertificateBuilder ;
10
+ import org .bouncycastle .openssl .jcajce .JcaPEMWriter ;
11
+ import org .bouncycastle .operator .ContentSigner ;
12
+ import org .bouncycastle .operator .OperatorCreationException ;
13
+ import org .bouncycastle .operator .jcajce .JcaContentSignerBuilder ;
3
14
import org .slf4j .Logger ;
4
15
import org .slf4j .LoggerFactory ;
5
16
6
17
import java .io .File ;
18
+ import java .io .FileWriter ;
7
19
import java .io .IOException ;
20
+ import java .math .BigInteger ;
21
+ import java .security .KeyPair ;
22
+ import java .security .KeyPairGenerator ;
23
+ import java .security .NoSuchAlgorithmException ;
24
+ import java .security .cert .CertificateException ;
25
+ import java .security .cert .X509Certificate ;
26
+ import java .time .Instant ;
27
+ import java .time .temporal .ChronoUnit ;
28
+ import java .util .Date ;
8
29
9
- // todo impl in java
10
30
public class CertManager {
11
31
12
32
private static final Logger log = LoggerFactory .getLogger (CertManager .class );
@@ -23,7 +43,7 @@ public CertManager(String jenvtestDir) {
23
43
this .jenvtestDir = jenvtestDir ;
24
44
}
25
45
26
- public void ensureAPIServerCertificates () {
46
+ public void createCertificatesIfNeeded () {
27
47
try {
28
48
generateAPIServerCertificates ();
29
49
generateUserCertificates ();
@@ -40,13 +60,16 @@ private void generateAPIServerCertificates() throws IOException, InterruptedExce
40
60
return ;
41
61
}
42
62
log .debug ("Generating API Server certificates" );
43
- Process process = new ProcessBuilder ("openssl" , "req" , "-nodes" , "-x509" , "-sha256" , "-newkey" , "rsa:4096" , "-keyout" , key .getPath (), "-out" ,
44
- cert .getPath (),
45
- "-days" , "356" , "-subj" , "/CN=example.org" ,
46
- "-addext" , "subjectAltName = IP:127.0.0.1,DNS:kubernetes," +
47
- "DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster,DNS:kubernetes.default.svc.cluster.local" )
48
- .start ();
49
- process .waitFor ();
63
+ generateKeyAndCertificate ("CN=example.org" , new File (jenvtestDir , API_SERVER_KEY_NAME ),
64
+ new File (jenvtestDir , API_SERVER_CERT_NAME ),
65
+ new GeneralName (GeneralName .iPAddress , "127.0.0.1" ),
66
+ dns ("kubernetes" ), dns ("kubernetes.default" ),
67
+ dns ("kubernetes.default.svc" ), dns ("kubernetes.default.svc.cluster" ),
68
+ dns ("kubernetes.default.svc.cluster.local" ));
69
+ }
70
+
71
+ private GeneralName dns (String dns ) {
72
+ return new GeneralName (GeneralName .dNSName , dns );
50
73
}
51
74
52
75
private void generateUserCertificates () throws IOException , InterruptedException {
@@ -56,11 +79,46 @@ private void generateUserCertificates() throws IOException, InterruptedException
56
79
return ;
57
80
}
58
81
log .debug ("Generating Client certificates" );
59
- var process = new ProcessBuilder ("openssl" , "req" , "-nodes" , "-x509" , "-sha256" , "-newkey" ,
60
- "rsa:4096" , "-keyout" , key .getPath (), "-out" , cert .getPath (), "-days" , "356" , "-subj" ,
61
- "/O=system:masters/CN=jenvtest" )
62
- .start ();
63
- process .waitFor ();
82
+ generateKeyAndCertificate ("O=system:masters,CN=jenvtest" , new File (jenvtestDir , CLIENT_KEY_NAME ),
83
+ new File (jenvtestDir , CLIENT_CERT_NAME ));
84
+ }
85
+
86
+
87
+ private static void generateKeyAndCertificate (String dirName , File keyFile , File certFile , GeneralName ... generalNames ) {
88
+ try {
89
+ KeyPairGenerator keyGen = KeyPairGenerator .getInstance ("RSA" );
90
+
91
+ KeyPair certKeyPair = keyGen .generateKeyPair ();
92
+ X500Name name = new X500Name (dirName );
93
+ // If you issue more than just test certificates, you might want a decent serial number schema ^.^
94
+ BigInteger serialNumber = BigInteger .valueOf (System .currentTimeMillis ());
95
+ Instant validFrom = Instant .now ();
96
+ Instant validUntil = validFrom .plus (365 , ChronoUnit .DAYS );
97
+
98
+ JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder (
99
+ name ,
100
+ serialNumber ,
101
+ Date .from (validFrom ), Date .from (validUntil ),
102
+ name , certKeyPair .getPublic ());
103
+
104
+ if (generalNames .length > 0 ) {
105
+ builder .addExtension (Extension .subjectAlternativeName , false ,
106
+ new GeneralNames (generalNames ));
107
+ }
108
+
109
+ // Finally, sign the certificate:
110
+ ContentSigner signer = new JcaContentSignerBuilder ("SHA256WithRSA" ).build (certKeyPair .getPrivate ());
111
+ X509CertificateHolder certHolder = builder .build (signer );
112
+ X509Certificate cert = new JcaX509CertificateConverter ().getCertificate (certHolder );
113
+
114
+ try (FileWriter certWriter = new FileWriter (certFile ); JcaPEMWriter certPemWriter = new JcaPEMWriter (certWriter );
115
+ FileWriter keyWriter = new FileWriter (keyFile ); JcaPEMWriter keyPemWriter = new JcaPEMWriter (keyWriter )) {
116
+ certPemWriter .writeObject (cert );
117
+ keyPemWriter .writeObject (certKeyPair .getPrivate ());
118
+ }
119
+ } catch (NoSuchAlgorithmException | CertificateException | IOException | OperatorCreationException e ) {
120
+ throw new JenvtestException (e );
121
+ }
64
122
}
65
123
66
124
public String getClientCertPath () {
0 commit comments