-
Notifications
You must be signed in to change notification settings - Fork 426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Removing connection properties: fipsProvider and fips #433
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1577,9 +1577,7 @@ void enableSSL(String host, | |
String tmfDefaultAlgorithm = null; // Default algorithm (typically X.509) used by the TrustManagerFactory | ||
SSLHandhsakeState handshakeState = SSLHandhsakeState.SSL_HANDHSAKE_NOT_STARTED; | ||
|
||
boolean isFips = false; | ||
String trustStoreType = null; | ||
String fipsProvider = null; | ||
|
||
// If anything in here fails, terminate the connection and throw an exception | ||
try { | ||
|
@@ -1597,13 +1595,6 @@ void enableSSL(String host, | |
trustStoreType = SQLServerDriverStringProperty.TRUST_STORE_TYPE.getDefaultValue(); | ||
} | ||
|
||
fipsProvider = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.FIPS_PROVIDER.toString()); | ||
isFips = Boolean.valueOf(con.activeConnectionProperties.getProperty(SQLServerDriverBooleanProperty.FIPS.toString())); | ||
|
||
if (isFips) { | ||
validateFips(fipsProvider, trustStoreType, trustStoreFileName); | ||
} | ||
|
||
assert TDS.ENCRYPT_OFF == con.getRequestedEncryptionLevel() || // Login only SSL | ||
TDS.ENCRYPT_ON == con.getRequestedEncryptionLevel(); // Full SSL | ||
|
||
|
@@ -1647,12 +1638,8 @@ void enableSSL(String host, | |
if (logger.isLoggable(Level.FINEST)) | ||
logger.finest(toString() + " Finding key store interface"); | ||
|
||
if (isFips) { | ||
ks = KeyStore.getInstance(trustStoreType, fipsProvider); | ||
} | ||
else { | ||
ks = KeyStore.getInstance(trustStoreType); | ||
} | ||
|
||
ks = KeyStore.getInstance(trustStoreType); | ||
ksProvider = ks.getProvider(); | ||
|
||
// Next, load up the trust store file from the specified location. | ||
|
@@ -1710,14 +1697,12 @@ void enableSSL(String host, | |
tmf.init(ks); | ||
tm = tmf.getTrustManagers(); | ||
|
||
// if the host name in cert provided use it or use the host name Only if it is not FIPS | ||
if (!isFips) { | ||
if (null != hostNameInCertificate) { | ||
tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], hostNameInCertificate)}; | ||
} | ||
else { | ||
tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], host)}; | ||
} | ||
// if the host name in cert provided use it or use the host name | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case of FIPS our driver should delegate responsibility of validating certificate to JVM. In this case we are using our own TrustManager i.e.
If I am correctly remember in order to remove error If you want to get rid of fips attribute then you have to come up with function which will detect if JVM is in FIPS mode or not. You can find logic in our test cases as well as on internet. And then in case of configured FIPS one should not used custom created TrustManagers. I will suggest instead of merging back in master / dev branch come up with Remember to test with at-least following FIPS implementations:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for pointing this out. I am able to reproduce the exception, will investigate and get back to you. |
||
if (null != hostNameInCertificate) { | ||
tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], hostNameInCertificate)}; | ||
} | ||
else { | ||
tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], host)}; | ||
} | ||
} // end if (!con.trustServerCertificate()) | ||
|
||
|
@@ -1821,70 +1806,6 @@ void enableSSL(String host, | |
} | ||
} | ||
|
||
/** | ||
* Validate FIPS if fips set as true | ||
* | ||
* Valid FIPS settings: | ||
* <LI>Encrypt should be true | ||
* <LI>trustServerCertificate should be false | ||
* <LI>if certificate is not installed FIPSProvider & TrustStoreType should be present. | ||
* | ||
* @param fipsProvider | ||
* FIPS Provider | ||
* @param trustStoreType | ||
* @param trustStoreFileName | ||
* @throws SQLServerException | ||
* @since 6.1.4 | ||
*/ | ||
private void validateFips(final String fipsProvider, | ||
final String trustStoreType, | ||
final String trustStoreFileName) throws SQLServerException { | ||
boolean isValid = false; | ||
boolean isEncryptOn; | ||
boolean isValidTrustStoreType; | ||
boolean isValidTrustStore; | ||
boolean isTrustServerCertificate; | ||
boolean isValidFipsProvider; | ||
|
||
String strError = SQLServerException.getErrString("R_invalidFipsConfig"); | ||
|
||
isEncryptOn = (TDS.ENCRYPT_ON == con.getRequestedEncryptionLevel()); | ||
|
||
// Here different FIPS provider supports different KeyStore type along with different JVM Implementation. | ||
isValidFipsProvider = !StringUtils.isEmpty(fipsProvider); | ||
isValidTrustStoreType = !StringUtils.isEmpty(trustStoreType); | ||
isValidTrustStore = !StringUtils.isEmpty(trustStoreFileName); | ||
isTrustServerCertificate = con.trustServerCertificate(); | ||
|
||
if (isEncryptOn && !isTrustServerCertificate) { | ||
if (logger.isLoggable(Level.FINER)) | ||
logger.finer(toString() + " Found parameters are encrypt is true & trustServerCertificate false"); | ||
|
||
isValid = true; | ||
|
||
if (isValidTrustStore) { | ||
// In case of valid trust store we need to check fipsProvider and TrustStoreType. | ||
if (!isValidFipsProvider || !isValidTrustStoreType) { | ||
isValid = false; | ||
strError = SQLServerException.getErrString("R_invalidFipsProviderConfig"); | ||
|
||
if (logger.isLoggable(Level.FINER)) | ||
logger.finer(toString() + " FIPS provider & TrustStoreType should pass with TrustStore."); | ||
} | ||
if (logger.isLoggable(Level.FINER)) | ||
logger.finer(toString() + " Found FIPS parameters seems to be valid."); | ||
} | ||
} | ||
else { | ||
strError = SQLServerException.getErrString("R_invalidFipsEncryptConfig"); | ||
} | ||
|
||
if (!isValid) { | ||
throw new SQLServerException(strError, null, 0, null); | ||
} | ||
|
||
} | ||
|
||
private final static String SEPARATOR = System.getProperty("file.separator"); | ||
private final static String JAVA_HOME = System.getProperty("java.home"); | ||
private final static String JAVA_SECURITY = JAVA_HOME + SEPARATOR + "lib" + SEPARATOR + "security"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing fipsProvider will not directly impact. But think of following cases:
You can configure BouncyCastle FIPS provider in two ways :
I added fipsProvider for 2nd case.
Also on Oracle site mentioned following:
Configuring SunJSSE for FIPS Mode
SunJSSE is configured in FIPS mode by associating it with an appropriate FIPS 140 certified cryptographic provider that supplies the implementations for all cryptographic algorithms required by SunJSSE. This can be done in one of the following ways:
edit the file ${java.home}/lib/security/java.security and modify the line that lists com.sun.net.ssl.internal.ssl.Provider to list the provider name of the FIPS 140 certified cryptographic provider. For example if the name of the cryptographic provider is SunPKCS11-NSS, change the line from
security.provider.4=com.sun.net.ssl.internal.ssl.Provider`
to
security.provider.4=com.sun.net.ssl.internal.ssl.Provider SunPKCS11-NSS
The class for the provider of the given name must also be listed as a security provider in the java.security file.
at runtime, call the constructor of the SunJSSE provider that takes a java.security.Provider object as a parameter. For example, if the variable cryptoProvider is a reference to the cryptographic provider, call new com.sun.net.ssl.internal.ssl.Provider(cryptoProvider).
at runtime, call the constructor of the SunJSSE provider that takes a String object as a parameter. For example if the cryptographic provider is called SunPKCS11-NSS call new com.sun.net.ssl.internal.ssl.Provider("SunPKCS11-NSS"). A provider with the specified name must be one of the configured security providers.
Within a given Java process, SunJSSE can be used either in FIPS mode or in default mode, but not both at the same time. Once SunJSSE has been initialized, it is not possible to change the mode. This means that if one of the runtime configuration options is used (option 2 or 3), the configuration must take place before any SSL/TLS operation.
Ref: Oracle FIPS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @nsidhaye ,
Thank you so much for detailed comments. We appreciate the time and effort.
As I mentioned above, if
fipsProvider
is not specified,KeyStore.getInstance()
traverses the list of registered security Providers -Security.getProviders()
and returns the matchingKeyStore
object.Example, in case of option 3, user would make sure
BouncyCastleFipsProvider
is installed before creating a connection.When the drivers calls
KeyStore.getInstance(trustStoreType)
before TLS Handshake,BCFIPS
will already be in the list of installed providers.Please let me know if I am missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After further investigation, I figured out the root cause of the issue,
Provider
IBMJCEFIPS
does not contain a keystore. When an application callsds.setFIPSProvider("IBMJCEFIPS");
, the driver throws an exception, because there are no matching keystore types forIBMJCEFIPS
. The users should use non-IBMJCEFIPS keystores to store the keys. See this page. This means, the provider that contains keystore is not necessarily the same as the provider that contains FIPS-complaint algorithms. Below is a sample app that would work for IBM users with the current implementation.This way we are not introducing any breaking changes, but the connection property
fipsProvider
has a confusing name.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ulvi :
In this case as FIPSProvider is non-FIPS it's not fip connection. One can test it by FipsEnvTest#isFips
For one of user I forked out SSLProtocol which having 2 fixes:
Keystore.getInstance(...)
. (Need to test what happens in JDK 9 & Bouncy Castle for configurable configuration)Unfortunately, we did not finalize on solution with user, but this worked on user environment with appropriate SSL certificate.
If you use my SSLProtocol fork and use following code for IBM FIPS.
Possibly @v-xiangs might have some information. Feel free to call me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @nsidhaye ,
Thank you for the comments. I am definitely open to a discussion over a call. Please email me your contact details at v-ulibra@microsoft.com.
fipsProvider
connection property is only used to load the keys. Users will still have to create the keys using a FIPS-approved provider. Non FIPS provider keystores can be used to store those keys and this will not affect FIPS compliant mode. Please, take a look at this article., especially the last section.Of course this test will fail if you pass in non-FIPS provider. That test just checks whether a provider is FIPS compliant or not, it does not check if FIPS mode is enabled. As I mentioned above, non FIPS provider is used to only store the keys.
Let me explain what happens when you don't set
fipsProvider
property. In this case, since you did not specify the provider, the driver will traverse the registered providers and find the matching keystore. So if you setkeystoreType
toJKS
, the matching provider that contains this Keystore is a non-FIPS provider. You can put a breakpoint at this line and check the provider name.Keystore.getInstance(storeType, "IBMJCEFIPS")
does not work, becauseIBMJCEFIPS
does not contain any keystores. That's why we need to use non-FIPS provider to store the keys. If the given provider contains the specifiedstoreType
,Keystore.getInstance(storeType, provider)
is perfectly valid. See this page.Thanks again for valuable comments and talk to you soon :)