22
22
import java .io .IOException ;
23
23
import java .security .GeneralSecurityException ;
24
24
import java .security .KeyStore ;
25
- import java .security .NoSuchAlgorithmException ;
25
+ import java .security .Security ;
26
26
import java .security .cert .CertificateException ;
27
+ import java .security .cert .PKIXBuilderParameters ;
28
+ import java .security .cert .X509CertSelector ;
27
29
import java .security .cert .X509Certificate ;
30
+ import javax .net .ssl .CertPathTrustManagerParameters ;
28
31
import javax .net .ssl .KeyManager ;
29
32
import javax .net .ssl .SSLContext ;
30
33
import javax .net .ssl .TrustManager ;
31
34
import javax .net .ssl .TrustManagerFactory ;
32
35
import javax .net .ssl .X509TrustManager ;
33
36
37
+ import org .neo4j .driver .internal .RevocationStrategy ;
38
+
39
+ import static org .neo4j .driver .internal .RevocationStrategy .VERIFY_IF_PRESENT ;
40
+ import static org .neo4j .driver .internal .RevocationStrategy .requiresRevocationChecking ;
34
41
import static org .neo4j .driver .internal .util .CertificateTool .loadX509Cert ;
35
42
36
43
/**
37
44
* A SecurityPlan consists of encryption and trust details.
38
45
*/
39
46
public class SecurityPlanImpl implements SecurityPlan
40
47
{
41
- public static SecurityPlan forAllCertificates ( boolean requiresHostnameVerification ) throws GeneralSecurityException
48
+ public static SecurityPlan forAllCertificates ( boolean requiresHostnameVerification , RevocationStrategy revocationStrategy ) throws GeneralSecurityException
42
49
{
43
50
SSLContext sslContext = SSLContext .getInstance ( "TLS" );
44
51
sslContext .init ( new KeyManager [0 ], new TrustManager []{new TrustAllTrustManager ()}, null );
45
52
46
- return new SecurityPlanImpl ( true , sslContext , requiresHostnameVerification );
53
+ return new SecurityPlanImpl ( true , sslContext , requiresHostnameVerification , revocationStrategy );
54
+ }
55
+
56
+ public static SecurityPlan forCustomCASignedCertificates ( File certFile , boolean requiresHostnameVerification ,
57
+ RevocationStrategy revocationStrategy )
58
+ throws GeneralSecurityException , IOException
59
+ {
60
+ SSLContext sslContext = configureSSLContext ( certFile , revocationStrategy );
61
+ return new SecurityPlanImpl ( true , sslContext , requiresHostnameVerification , revocationStrategy );
62
+ }
63
+
64
+ public static SecurityPlan forSystemCASignedCertificates ( boolean requiresHostnameVerification , RevocationStrategy revocationStrategy )
65
+ throws GeneralSecurityException , IOException
66
+ {
67
+ SSLContext sslContext = configureSSLContext ( null , revocationStrategy );
68
+ return new SecurityPlanImpl ( true , sslContext , requiresHostnameVerification , revocationStrategy );
47
69
}
48
70
49
- public static SecurityPlan forCustomCASignedCertificates ( File certFile , boolean requiresHostnameVerification )
71
+ private static SSLContext configureSSLContext ( File customCertFile , RevocationStrategy revocationStrategy )
50
72
throws GeneralSecurityException , IOException
51
73
{
52
- // A certificate file is specified so we will load the certificates in the file
53
- // Init a in memory TrustedKeyStore
54
- KeyStore trustedKeyStore = KeyStore .getInstance ( "JKS" );
74
+ KeyStore trustedKeyStore = KeyStore .getInstance ( KeyStore .getDefaultType () );
55
75
trustedKeyStore .load ( null , null );
56
76
57
- // Load the certs from the file
58
- loadX509Cert ( certFile , trustedKeyStore );
77
+ if ( customCertFile != null )
78
+ {
79
+ // A certificate file is specified so we will load the certificates in the file
80
+ loadX509Cert ( customCertFile , trustedKeyStore );
81
+ }
82
+ else
83
+ {
84
+ loadSystemCertificates ( trustedKeyStore );
85
+ }
86
+
87
+ // Configure certificate revocation checking (X509CertSelector() selects all certificates)
88
+ PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters ( trustedKeyStore , new X509CertSelector () );
59
89
60
- // Create TrustManager from TrustedKeyStore
61
- TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance ( "SunX509" );
62
- trustManagerFactory .init ( trustedKeyStore );
90
+ // sets checking of stapled ocsp response
91
+ pkixBuilderParameters .setRevocationEnabled ( requiresRevocationChecking ( revocationStrategy ) );
92
+
93
+ if ( requiresRevocationChecking ( revocationStrategy ) )
94
+ {
95
+ // enables status_request extension in client hello
96
+ System .setProperty ( "jdk.tls.client.enableStatusRequestExtension" , "true" );
97
+
98
+ if ( revocationStrategy .equals ( VERIFY_IF_PRESENT ) )
99
+ {
100
+ // enables soft-fail behaviour if no stapled response found.
101
+ Security .setProperty ( "ocsp.enable" , "true" );
102
+ }
103
+ }
63
104
64
105
SSLContext sslContext = SSLContext .getInstance ( "TLS" );
106
+
107
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance ( TrustManagerFactory .getDefaultAlgorithm () );
108
+ trustManagerFactory .init ( new CertPathTrustManagerParameters ( pkixBuilderParameters ) );
65
109
sslContext .init ( new KeyManager [0 ], trustManagerFactory .getTrustManagers (), null );
66
110
67
- return new SecurityPlanImpl ( true , sslContext , requiresHostnameVerification ) ;
111
+ return sslContext ;
68
112
}
69
113
70
- public static SecurityPlan forSystemCASignedCertificates ( boolean requiresHostnameVerification ) throws NoSuchAlgorithmException
114
+ private static void loadSystemCertificates ( KeyStore trustedKeyStore ) throws GeneralSecurityException , IOException
71
115
{
72
- return new SecurityPlanImpl ( true , SSLContext .getDefault (), requiresHostnameVerification );
116
+ // To customize the PKIXParameters we need to get hold of the default KeyStore, no other elegant way available
117
+ TrustManagerFactory tempFactory = TrustManagerFactory .getInstance ( TrustManagerFactory .getDefaultAlgorithm () );
118
+ tempFactory .init ( (KeyStore ) null );
119
+
120
+ // Get hold of the default trust manager
121
+ X509TrustManager x509TrustManager = null ;
122
+ for ( TrustManager trustManager : tempFactory .getTrustManagers () )
123
+ {
124
+ if ( trustManager instanceof X509TrustManager )
125
+ {
126
+ x509TrustManager = (X509TrustManager ) trustManager ;
127
+ break ;
128
+ }
129
+ }
130
+
131
+ if ( x509TrustManager == null )
132
+ {
133
+ throw new CertificateException ( "No system certificates found" );
134
+ }
135
+ else
136
+ {
137
+ // load system default certificates into KeyStore
138
+ loadX509Cert ( x509TrustManager .getAcceptedIssuers (), trustedKeyStore );
139
+ }
73
140
}
74
141
75
142
public static SecurityPlan insecure ()
76
143
{
77
- return new SecurityPlanImpl ( false , null , false );
144
+ return new SecurityPlanImpl ( false , null , false ,
145
+ RevocationStrategy .NO_CHECKS );
78
146
}
79
147
80
148
private final boolean requiresEncryption ;
81
149
private final SSLContext sslContext ;
82
150
private final boolean requiresHostnameVerification ;
151
+ private final RevocationStrategy revocationStrategy ;
83
152
84
- private SecurityPlanImpl ( boolean requiresEncryption , SSLContext sslContext , boolean requiresHostnameVerification )
153
+ private SecurityPlanImpl ( boolean requiresEncryption , SSLContext sslContext , boolean requiresHostnameVerification , RevocationStrategy revocationStrategy )
85
154
{
86
155
this .requiresEncryption = requiresEncryption ;
87
156
this .sslContext = sslContext ;
88
157
this .requiresHostnameVerification = requiresHostnameVerification ;
158
+ this .revocationStrategy = revocationStrategy ;
89
159
}
90
160
91
161
@ Override
@@ -106,6 +176,12 @@ public boolean requiresHostnameVerification()
106
176
return requiresHostnameVerification ;
107
177
}
108
178
179
+ @ Override
180
+ public RevocationStrategy revocationStrategy ()
181
+ {
182
+ return revocationStrategy ;
183
+ }
184
+
109
185
private static class TrustAllTrustManager implements X509TrustManager
110
186
{
111
187
public void checkClientTrusted ( X509Certificate [] chain , String authType ) throws CertificateException
0 commit comments