Let OpenSslContext take pre-encoded pkcs#8 private key/cert bytes

Motivation

OpenSslContext is expecting Java's PrivateKey and X509Certificate objects as input
(for JdkSslContext API compatibility reasons) but doesn't really use them beyond
turning them into PEM/PKCS#8 strings.

This conversion can be entirely skipped if the user can pass in private keys and
certificates in a format that Netty's OpenSSL code can digest.

Modifications

Two new classes have been added that act as a wrapper around the pre-encoded byte[]
and also retain API compatibility to JdkSslContext.

Result

It's possible to pass PEM encoded bytes straight into OpenSSL without having to
parse them (e.g. File to Java's PrivateKey) and then encode them (i.e. PrivateKey
into PEM/PKCS#8).

File pemPrivateKeyFile;
byte[] pemBytes = readBytes(pemPrivateKeyFile);
PemPrivateKey pemPrivateKey = PemPrivateKey.valueOf(pemBytes);

SslContextBuilder.forServer(pemPrivateKey)
    .sslProvider(SslProvider.OPENSSL)
This commit is contained in:
Roger Kapsi 2016-06-08 18:14:45 -04:00 committed by Norman Maurer
parent c3abb9146e
commit cc580e3ba1
6 changed files with 877 additions and 55 deletions

View File

@ -17,9 +17,6 @@ package io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.base64.Base64;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
@ -36,10 +33,8 @@ import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateRevokedException;
@ -55,11 +50,6 @@ import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBeha
import static io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
public abstract class OpenSslContext extends SslContext {
private static final byte[] BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
private static final byte[] END_CERT = "\n-----END CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
private static final byte[] BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
private static final byte[] END_PRIVATE_KEY = "\n-----END PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslContext.class);
/**
* To make it easier for users to replace JDK implemention with OpenSsl version we also use
@ -513,32 +503,14 @@ public abstract class OpenSslContext extends SslContext {
if (key == null) {
return 0;
}
ByteBuf buffer = Unpooled.directBuffer();
try {
buffer.writeBytes(BEGIN_PRIVATE_KEY);
ByteBuf wrappedBuf = Unpooled.wrappedBuffer(key.getEncoded());
final ByteBuf encodedBuf;
try {
encodedBuf = Base64.encode(wrappedBuf, true);
try {
buffer.writeBytes(encodedBuf);
} finally {
zerooutAndRelease(encodedBuf);
}
} finally {
zerooutAndRelease(wrappedBuf);
}
buffer.writeBytes(END_PRIVATE_KEY);
return newBIO(buffer);
} finally {
// Zero out the buffer and so the private key it held.
zerooutAndRelease(buffer);
}
}
private static void zerooutAndRelease(ByteBuf buffer) {
buffer.setZero(0, buffer.capacity());
buffer.release();
ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
try {
return toBIO(allocator, pem.retain());
} finally {
pem.release();
}
}
/**
@ -549,30 +521,52 @@ public abstract class OpenSslContext extends SslContext {
if (certChain == null) {
return 0;
}
ByteBuf buffer = Unpooled.directBuffer();
if (certChain.length == 0) {
throw new IllegalArgumentException("certChain can't be empty");
}
ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
try {
for (X509Certificate cert: certChain) {
buffer.writeBytes(BEGIN_CERT);
ByteBuf wrappedBuf = Unpooled.wrappedBuffer(cert.getEncoded());
try {
ByteBuf encodedBuf = Base64.encode(wrappedBuf, true);
try {
buffer.writeBytes(encodedBuf);
return toBIO(allocator, pem.retain());
} finally {
encodedBuf.release();
pem.release();
}
}
private static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
try {
// We can turn direct buffers straight into BIOs. No need to
// make a yet another copy.
ByteBuf content = pem.content();
if (content.isDirect()) {
return newBIO(content.retainedSlice());
}
ByteBuf buffer = allocator.directBuffer(content.readableBytes());
try {
buffer.writeBytes(content);
return newBIO(buffer.retainedSlice());
} finally {
wrappedBuf.release();
try {
// If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
// need to zero out the bytes of the copy before we're releasing it.
if (pem.isSensitive()) {
SslUtils.zeroout(buffer);
}
buffer.writeBytes(END_CERT);
}
return newBIO(buffer);
} finally {
buffer.release();
}
}
} finally {
pem.release();
}
}
private static long newBIO(ByteBuf buffer) throws Exception {
try {
long bio = SSL.newMemBIO();
int readable = buffer.readableBytes();
if (SSL.writeToBIO(bio, OpenSsl.memoryAddress(buffer), readable) != readable) {
@ -580,6 +574,9 @@ public abstract class OpenSslContext extends SslContext {
throw new IllegalStateException("Could not write data to memory BIO");
}
return bio;
} finally {
buffer.release();
}
}
static void checkKeyManagerFactory(KeyManagerFactory keyManagerFactory) {

View File

@ -0,0 +1,55 @@
/*
* 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 compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.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 io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
/**
* A marker interface for PEM encoded values.
*/
interface PemEncoded extends ByteBufHolder {
/**
* Returns {@code true} if the PEM encoded value is considered
* sensitive information such as a private key.
*/
boolean isSensitive();
@Override
PemEncoded copy();
@Override
PemEncoded duplicate();
@Override
PemEncoded retainedDuplicate();
@Override
PemEncoded replace(ByteBuf content);
@Override
PemEncoded retain();
@Override
PemEncoded retain(int increment);
@Override
PemEncoded touch();
@Override
PemEncoded touch(Object hint);
}

View File

@ -0,0 +1,218 @@
/*
* 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 compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.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 io.netty.handler.ssl;
import java.security.PrivateKey;
import javax.security.auth.Destroyable;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.util.AbstractReferenceCounted;
import io.netty.util.CharsetUtil;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.ObjectUtil;
/**
* This is a special purpose implementation of a {@link PrivateKey} which allows the
* user to pass PEM/PKCS#8 encoded key material straight into {@link OpenSslContext}
* without having to parse and re-encode bytes in Java land.
*
* All methods other than what's implemented in {@link PemEncoded} and {@link Destroyable}
* throw {@link UnsupportedOperationException}s.
*
* @see PemEncoded
* @see OpenSslContext
* @see #valueOf(byte[])
* @see #valueOf(ByteBuf)
*/
public final class PemPrivateKey extends AbstractReferenceCounted implements PrivateKey, PemEncoded {
private static final byte[] BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
private static final byte[] END_PRIVATE_KEY = "\n-----END PRIVATE KEY-----\n".getBytes(CharsetUtil.US_ASCII);
private static final String PKCS8_FORMAT = "PKCS#8";
/**
* Creates a {@link PemEncoded} value from the {@link PrivateKey}.
*/
static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect, PrivateKey key) {
// We can take a shortcut if the private key happens to be already
// PEM/PKCS#8 encoded. This is the ideal case and reason why all
// this exists. It allows the user to pass pre-encoded bytes straight
// into OpenSSL without having to do any of the extra work.
if (key instanceof PemEncoded) {
return ((PemEncoded) key).retain();
}
ByteBuf encoded = Unpooled.wrappedBuffer(key.getEncoded());
try {
ByteBuf base64 = SslUtils.toBase64(allocator, encoded);
try {
int size = BEGIN_PRIVATE_KEY.length + base64.readableBytes() + END_PRIVATE_KEY.length;
boolean success = false;
final ByteBuf pem = useDirect ? allocator.directBuffer(size) : allocator.buffer(size);
try {
pem.writeBytes(BEGIN_PRIVATE_KEY);
pem.writeBytes(base64);
pem.writeBytes(END_PRIVATE_KEY);
PemValue value = new PemValue(pem, true);
success = true;
return value;
} finally {
// Make sure we never leak that PEM ByteBuf if there's an Exception.
if (!success) {
SslUtils.zerooutAndRelease(pem);
}
}
} finally {
SslUtils.zerooutAndRelease(base64);
}
} finally {
SslUtils.zerooutAndRelease(encoded);
}
}
/**
* Creates a {@link PemPrivateKey} from raw {@code byte[]}.
*
* ATTENTION: It's assumed that the given argument is a PEM/PKCS#8 encoded value.
* No input validation is performed to validate it.
*/
public static PemPrivateKey valueOf(byte[] key) {
return valueOf(Unpooled.wrappedBuffer(key));
}
/**
* Creates a {@link PemPrivateKey} from raw {@code ByteBuf}.
*
* ATTENTION: It's assumed that the given argument is a PEM/PKCS#8 encoded value.
* No input validation is performed to validate it.
*/
public static PemPrivateKey valueOf(ByteBuf key) {
return new PemPrivateKey(key);
}
private final ByteBuf content;
private PemPrivateKey(ByteBuf content) {
this.content = ObjectUtil.checkNotNull(content, "content");
}
@Override
public boolean isSensitive() {
return true;
}
@Override
public ByteBuf content() {
int count = refCnt();
if (count <= 0) {
throw new IllegalReferenceCountException(count);
}
return content;
}
@Override
public PemPrivateKey copy() {
return replace(content.copy());
}
@Override
public PemPrivateKey duplicate() {
return replace(content.duplicate());
}
@Override
public PemPrivateKey retainedDuplicate() {
return replace(content.retainedDuplicate());
}
@Override
public PemPrivateKey replace(ByteBuf content) {
return new PemPrivateKey(content);
}
@Override
public PemPrivateKey touch() {
content.touch();
return this;
}
@Override
public PemPrivateKey touch(Object hint) {
content.touch(hint);
return this;
}
@Override
public PemPrivateKey retain() {
return (PemPrivateKey) super.retain();
}
@Override
public PemPrivateKey retain(int increment) {
return (PemPrivateKey) super.retain(increment);
}
@Override
protected void deallocate() {
// Private Keys are sensitive. We need to zero the bytes
// before we're releasing the underlying ByteBuf
SslUtils.zerooutAndRelease(content);
}
@Override
public byte[] getEncoded() {
throw new UnsupportedOperationException();
}
@Override
public String getAlgorithm() {
throw new UnsupportedOperationException();
}
@Override
public String getFormat() {
return PKCS8_FORMAT;
}
/**
* NOTE: This is a JDK8 interface/method. Due to backwards compatibility
* reasons it's not possible to slap the {@code @Override} annotation onto
* this method.
*
* @see Destroyable#destroy()
*/
public void destroy() {
release(refCnt());
}
/**
* NOTE: This is a JDK8 interface/method. Due to backwards compatibility
* reasons it's not possible to slap the {@code @Override} annotation onto
* this method.
*
* @see Destroyable#isDestroyed()
*/
public boolean isDestroyed() {
return refCnt() == 0;
}
}

View File

@ -0,0 +1,105 @@
/*
* 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 compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.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 io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.AbstractReferenceCounted;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.ObjectUtil;
/**
* A PEM encoded value.
*
* @see PemEncoded
* @see PemPrivateKey#toPEM(ByteBufAllocator, boolean, java.security.PrivateKey)
* @see PemX509Certificate#toPEM(ByteBufAllocator, boolean, java.security.cert.X509Certificate[])
*/
class PemValue extends AbstractReferenceCounted implements PemEncoded {
private final ByteBuf content;
private final boolean sensitive;
public PemValue(ByteBuf content, boolean sensitive) {
this.content = ObjectUtil.checkNotNull(content, "content");
this.sensitive = sensitive;
}
@Override
public boolean isSensitive() {
return sensitive;
}
@Override
public ByteBuf content() {
int count = refCnt();
if (count <= 0) {
throw new IllegalReferenceCountException(count);
}
return content;
}
@Override
public PemValue copy() {
return replace(content.copy());
}
@Override
public PemValue duplicate() {
return replace(content.duplicate());
}
@Override
public PemValue retainedDuplicate() {
return replace(content.retainedDuplicate());
}
@Override
public PemValue replace(ByteBuf content) {
return new PemValue(content, sensitive);
}
@Override
public PemValue touch() {
return (PemValue) super.touch();
}
@Override
public PemValue touch(Object hint) {
content.touch(hint);
return this;
}
@Override
public PemValue retain() {
return (PemValue) super.retain();
}
@Override
public PemValue retain(int increment) {
return (PemValue) super.retain(increment);
}
@Override
protected void deallocate() {
if (sensitive) {
SslUtils.zeroout(content);
}
content.release();
}
}

View File

@ -0,0 +1,415 @@
/*
* 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 compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.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 io.netty.handler.ssl;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Principal;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.ObjectUtil;
/**
* This is a special purpose implementation of a {@link X509Certificate} which allows
* the user to pass PEM/PKCS#8 encoded data straight into {@link OpenSslContext} without
* having to parse and re-encode bytes in Java land.
*
* All methods other than what's implemented in {@link PemEncoded}'s throw
* {@link UnsupportedOperationException}s.
*
* @see PemEncoded
* @see OpenSslContext
* @see #valueOf(byte[])
* @see #valueOf(ByteBuf)
*/
public final class PemX509Certificate extends X509Certificate implements PemEncoded {
private static final byte[] BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
private static final byte[] END_CERT = "\n-----END CERTIFICATE-----\n".getBytes(CharsetUtil.US_ASCII);
/**
* Creates a {@link PemEncoded} value from the {@link X509Certificate}s.
*/
static PemEncoded toPEM(ByteBufAllocator allocator, boolean useDirect,
X509Certificate... chain) throws CertificateEncodingException {
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException("X.509 certificate chain can't be null or empty");
}
// We can take a shortcut if there is only one certificate and
// it already happens to be a PemEncoded instance. This is the
// ideal case and reason why all this exists. It allows the user
// to pass pre-encoded bytes straight into OpenSSL without having
// to do any of the extra work.
if (chain.length == 1) {
X509Certificate first = chain[0];
if (first instanceof PemEncoded) {
return ((PemEncoded) first).retain();
}
}
boolean success = false;
ByteBuf pem = null;
try {
for (X509Certificate cert : chain) {
if (cert == null) {
throw new IllegalArgumentException("Null element in chain: " + Arrays.toString(chain));
}
if (cert instanceof PemEncoded) {
pem = append(allocator, useDirect, (PemEncoded) cert, chain.length, pem);
} else {
pem = append(allocator, useDirect, cert, chain.length, pem);
}
}
PemValue value = new PemValue(pem, false);
success = true;
return value;
} finally {
// Make sure we never leak the PEM's ByteBuf in the event of an Exception
if (!success && pem != null) {
pem.release();
}
}
}
/**
* Appends the {@link PemEncoded} value to the {@link ByteBuf} (last arg) and returns it.
* If the {@link ByteBuf} didn't exist yet it'll create it using the {@link ByteBufAllocator}.
*/
private static ByteBuf append(ByteBufAllocator allocator, boolean useDirect,
PemEncoded encoded, int count, ByteBuf pem) {
ByteBuf content = encoded.content();
if (pem == null) {
// see the other append() method
pem = newBuffer(allocator, useDirect, content.readableBytes() * count);
}
pem.writeBytes(content.slice());
return pem;
}
/**
* Appends the {@link X509Certificate} value to the {@link ByteBuf} (last arg) and returns it.
* If the {@link ByteBuf} didn't exist yet it'll create it using the {@link ByteBufAllocator}.
*/
private static ByteBuf append(ByteBufAllocator allocator, boolean useDirect,
X509Certificate cert, int count, ByteBuf pem) throws CertificateEncodingException {
ByteBuf encoded = Unpooled.wrappedBuffer(cert.getEncoded());
try {
ByteBuf base64 = SslUtils.toBase64(allocator, encoded);
try {
if (pem == null) {
// We try to approximate the buffer's initial size. The sizes of
// certificates can vary a lot so it'll be off a bit depending
// on the number of elements in the array (count argument).
pem = newBuffer(allocator, useDirect,
(BEGIN_CERT.length + base64.readableBytes() + END_CERT.length) * count);
}
pem.writeBytes(BEGIN_CERT);
pem.writeBytes(base64);
pem.writeBytes(END_CERT);
} finally {
base64.release();
}
} finally {
encoded.release();
}
return pem;
}
private static ByteBuf newBuffer(ByteBufAllocator allocator, boolean useDirect, int initialCapacity) {
return useDirect ? allocator.directBuffer(initialCapacity) : allocator.buffer(initialCapacity);
}
/**
* Creates a {@link PemX509Certificate} from raw {@code byte[]}.
*
* ATTENTION: It's assumed that the given argument is a PEM/PKCS#8 encoded value.
* No input validation is performed to validate it.
*/
public static PemX509Certificate valueOf(byte[] key) {
return valueOf(Unpooled.wrappedBuffer(key));
}
/**
* Creates a {@link PemX509Certificate} from raw {@code ByteBuf}.
*
* ATTENTION: It's assumed that the given argument is a PEM/PKCS#8 encoded value.
* No input validation is performed to validate it.
*/
public static PemX509Certificate valueOf(ByteBuf key) {
return new PemX509Certificate(key);
}
private final ByteBuf content;
private PemX509Certificate(ByteBuf content) {
this.content = ObjectUtil.checkNotNull(content, "content");
}
@Override
public boolean isSensitive() {
// There is no sensitive information in a X509 Certificate
return false;
}
@Override
public int refCnt() {
return content.refCnt();
}
@Override
public ByteBuf content() {
int count = refCnt();
if (count <= 0) {
throw new IllegalReferenceCountException(count);
}
return content;
}
@Override
public PemX509Certificate copy() {
return replace(content.copy());
}
@Override
public PemX509Certificate duplicate() {
return replace(content.duplicate());
}
@Override
public PemX509Certificate retainedDuplicate() {
return replace(content.retainedDuplicate());
}
@Override
public PemX509Certificate replace(ByteBuf content) {
return new PemX509Certificate(content);
}
@Override
public PemX509Certificate retain() {
content.retain();
return this;
}
@Override
public PemX509Certificate retain(int increment) {
content.retain(increment);
return this;
}
@Override
public PemX509Certificate touch() {
content.touch();
return this;
}
@Override
public PemX509Certificate touch(Object hint) {
content.touch(hint);
return this;
}
@Override
public boolean release() {
return content.release();
}
@Override
public boolean release(int decrement) {
return content.release(decrement);
}
@Override
public byte[] getEncoded() throws CertificateEncodingException {
throw new UnsupportedOperationException();
}
@Override
public boolean hasUnsupportedCriticalExtension() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> getCriticalExtensionOIDs() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> getNonCriticalExtensionOIDs() {
throw new UnsupportedOperationException();
}
@Override
public byte[] getExtensionValue(String oid) {
throw new UnsupportedOperationException();
}
@Override
public void checkValidity() throws CertificateExpiredException,
CertificateNotYetValidException {
throw new UnsupportedOperationException();
}
@Override
public void checkValidity(Date date) throws CertificateExpiredException,
CertificateNotYetValidException {
throw new UnsupportedOperationException();
}
@Override
public int getVersion() {
throw new UnsupportedOperationException();
}
@Override
public BigInteger getSerialNumber() {
throw new UnsupportedOperationException();
}
@Override
public Principal getIssuerDN() {
throw new UnsupportedOperationException();
}
@Override
public Principal getSubjectDN() {
throw new UnsupportedOperationException();
}
@Override
public Date getNotBefore() {
throw new UnsupportedOperationException();
}
@Override
public Date getNotAfter() {
throw new UnsupportedOperationException();
}
@Override
public byte[] getTBSCertificate() throws CertificateEncodingException {
throw new UnsupportedOperationException();
}
@Override
public byte[] getSignature() {
throw new UnsupportedOperationException();
}
@Override
public String getSigAlgName() {
throw new UnsupportedOperationException();
}
@Override
public String getSigAlgOID() {
throw new UnsupportedOperationException();
}
@Override
public byte[] getSigAlgParams() {
throw new UnsupportedOperationException();
}
@Override
public boolean[] getIssuerUniqueID() {
throw new UnsupportedOperationException();
}
@Override
public boolean[] getSubjectUniqueID() {
throw new UnsupportedOperationException();
}
@Override
public boolean[] getKeyUsage() {
throw new UnsupportedOperationException();
}
@Override
public int getBasicConstraints() {
throw new UnsupportedOperationException();
}
@Override
public void verify(PublicKey key)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
throw new UnsupportedOperationException();
}
@Override
public void verify(PublicKey key, String sigProvider)
throws CertificateException, NoSuchAlgorithmException,
InvalidKeyException, NoSuchProviderException, SignatureException {
throw new UnsupportedOperationException();
}
@Override
public PublicKey getPublicKey() {
throw new UnsupportedOperationException();
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof PemX509Certificate)) {
return false;
}
PemX509Certificate other = (PemX509Certificate) o;
return content.equals(other.content);
}
@Override
public int hashCode() {
return content.hashCode();
}
@Override
public String toString() {
return content.toString(CharsetUtil.UTF_8);
}
}

View File

@ -16,7 +16,10 @@
package io.netty.handler.ssl;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.base64.Base64Dialect;
/**
* Constants for SSL packets.
@ -125,6 +128,35 @@ final class SslUtils {
ctx.close();
}
/**
* Fills the {@link ByteBuf} with zero bytes.
*/
static void zeroout(ByteBuf buffer) {
if (!buffer.isReadOnly()) {
buffer.setZero(0, buffer.capacity());
}
}
/**
* Fills the {@link ByteBuf} with zero bytes and releases it.
*/
static void zerooutAndRelease(ByteBuf buffer) {
zeroout(buffer);
buffer.release();
}
/**
* Same as {@link Base64#encode(ByteBuf, boolean)} but allows the use of a custom {@link ByteBufAllocator}.
*
* @see Base64#encode(ByteBuf, boolean)
*/
static ByteBuf toBase64(ByteBufAllocator allocator, ByteBuf src) {
ByteBuf dst = Base64.encode(src, src.readerIndex(),
src.readableBytes(), true, Base64Dialect.STANDARD, allocator);
src.readerIndex(src.writerIndex());
return dst;
}
private SslUtils() {
}
}