nl.topicus.jdbc.shaded.io.netty.handler.ssl.OpenSslKeyMaterialManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spanner-jdbc Show documentation
Show all versions of spanner-jdbc Show documentation
JDBC Driver for Google Cloud Spanner
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in nl.topicus.jdbc.shaded.com.liance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.nl.topicus.jdbc.shaded.org.licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.handler.ssl;
import nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.buffer.ByteBufAllocator;
import nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.internal.tcnative.CertificateRequestedCallback;
import nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.internal.tcnative.SSL;
import javax.nl.topicus.jdbc.shaded.net.ssl.SSLException;
import javax.nl.topicus.jdbc.shaded.net.ssl.X509KeyManager;
import javax.security.auth.x500.X500Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.handler.ssl.ReferenceCountedOpenSslContext.freeBio;
import static nl.topicus.jdbc.shaded.io.nl.topicus.jdbc.shaded.net.y.handler.ssl.ReferenceCountedOpenSslContext.toBIO;
/**
* Manages key material for {@link OpenSslEngine}s and so set the right {@link PrivateKey}s and
* {@link X509Certificate}s.
*/
class OpenSslKeyMaterialManager {
// Code in this class is inspired by code of conscrypts:
// - https://android.googlesource.nl.topicus.jdbc.shaded.com.platform/external/
// conscrypt/+/master/src/main/java/nl.topicus.jdbc.shaded.org.conscrypt/OpenSSLEngineImpl.java
// - https://android.googlesource.nl.topicus.jdbc.shaded.com.platform/external/
// conscrypt/+/master/src/main/java/nl.topicus.jdbc.shaded.org.conscrypt/SSLParametersImpl.java
//
static final String KEY_TYPE_RSA = "RSA";
static final String KEY_TYPE_DH_RSA = "DH_RSA";
static final String KEY_TYPE_EC = "EC";
static final String KEY_TYPE_EC_EC = "EC_EC";
static final String KEY_TYPE_EC_RSA = "EC_RSA";
// key type mappings for types.
private static final Map KEY_TYPES = new HashMap();
static {
KEY_TYPES.put("RSA", KEY_TYPE_RSA);
KEY_TYPES.put("DHE_RSA", KEY_TYPE_RSA);
KEY_TYPES.put("ECDHE_RSA", KEY_TYPE_RSA);
KEY_TYPES.put("ECDHE_ECDSA", KEY_TYPE_EC);
KEY_TYPES.put("ECDH_RSA", KEY_TYPE_EC_RSA);
KEY_TYPES.put("ECDH_ECDSA", KEY_TYPE_EC_EC);
KEY_TYPES.put("DH_RSA", KEY_TYPE_DH_RSA);
}
private final X509KeyManager keyManager;
private final String password;
OpenSslKeyMaterialManager(X509KeyManager keyManager, String password) {
this.keyManager = keyManager;
this.password = password;
}
void setKeyMaterial(ReferenceCountedOpenSslEngine engine) throws SSLException {
long ssl = engine.sslPointer();
String[] authMethods = SSL.authenticationMethods(ssl);
Set aliases = new HashSet(authMethods.length);
for (String authMethod : authMethods) {
String type = KEY_TYPES.get(authMethod);
if (type != null) {
String alias = chooseServerAlias(engine, type);
if (alias != null && aliases.add(alias)) {
setKeyMaterial(ssl, alias);
}
}
}
}
CertificateRequestedCallback.KeyMaterial keyMaterial(ReferenceCountedOpenSslEngine engine, String[] keyTypes,
X500Principal[] issuer) throws SSLException {
String alias = chooseClientAlias(engine, keyTypes, issuer);
long keyBio = 0;
long keyCertChainBio = 0;
long pkey = 0;
long certChain = 0;
try {
// TODO: Should we cache these and so not need to do a memory copy all the time ?
X509Certificate[] certificates = keyManager.getCertificateChain(alias);
if (certificates == null || certificates.length == 0) {
return null;
}
PrivateKey key = keyManager.getPrivateKey(alias);
keyCertChainBio = toBIO(certificates);
certChain = SSL.parseX509Chain(keyCertChainBio);
if (key != null) {
keyBio = toBIO(key);
pkey = SSL.parsePrivateKey(keyBio, password);
}
CertificateRequestedCallback.KeyMaterial material = new CertificateRequestedCallback.KeyMaterial(
certChain, pkey);
// Reset to 0 so we do not free these. This is needed as the client certificate callback takes ownership
// of both the key and the certificate if they are returned from this method, and thus must not
// be freed here.
certChain = pkey = 0;
return material;
} catch (SSLException e) {
throw e;
} catch (Exception e) {
throw new SSLException(e);
} finally {
freeBio(keyBio);
freeBio(keyCertChainBio);
SSL.freePrivateKey(pkey);
SSL.freeX509Chain(certChain);
}
}
private void setKeyMaterial(long ssl, String alias) throws SSLException {
long keyBio = 0;
long keyCertChainBio = 0;
long keyCertChainBio2 = 0;
try {
// TODO: Should we cache these and so not need to do a memory copy all the time ?
X509Certificate[] certificates = keyManager.getCertificateChain(alias);
if (certificates == null || certificates.length == 0) {
return;
}
PrivateKey key = keyManager.getPrivateKey(alias);
// Only encode one time
PemEncoded encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, certificates);
try {
keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
if (key != null) {
keyBio = toBIO(key);
}
SSL.setCertificateBio(ssl, keyCertChainBio, keyBio, password);
// We may have more then one cert in the chain so add all of them now.
SSL.setCertificateChainBio(ssl, keyCertChainBio2, true);
} finally {
encoded.release();
}
} catch (SSLException e) {
throw e;
} catch (Exception e) {
throw new SSLException(e);
} finally {
freeBio(keyBio);
freeBio(keyCertChainBio);
freeBio(keyCertChainBio2);
}
}
protected String chooseClientAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine,
String[] keyTypes, X500Principal[] issuer) {
return keyManager.chooseClientAlias(keyTypes, issuer, null);
}
protected String chooseServerAlias(@SuppressWarnings("unused") ReferenceCountedOpenSslEngine engine, String type) {
return keyManager.chooseServerAlias(type, null, null);
}
}