diff options
8 files changed, 128 insertions, 81 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java b/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java index 0bc13cd0..6b48566e 100644 --- a/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java +++ b/src/main/java/org/bouncycastle/crypto/tls/TlsClientProtocol.java @@ -86,7 +86,7 @@ public class TlsClientProtocol extends TlsProtocol { this.tlsClient.notifyHandshakeComplete();
}
- protected TlsContext getContext() {
+ protected AbstractTlsContext getContext() {
return tlsClientContext;
}
@@ -254,7 +254,7 @@ public class TlsClientProtocol extends TlsProtocol { */
sendClientKeyExchangeMessage();
- establishMasterSecret(tlsClientContext, keyExchange);
+ establishMasterSecret(getContext(), keyExchange);
/*
* Initialize our cipher suite
@@ -396,7 +396,7 @@ public class TlsClientProtocol extends TlsProtocol { this.connection_state = CS_SERVER_SUPPLEMENTAL_DATA;
this.keyExchange = tlsClient.getKeyExchange();
- this.keyExchange.init(this.tlsClientContext);
+ this.keyExchange.init(getContext());
}
protected void receiveNewSessionTicketMessage(ByteArrayInputStream buf) throws IOException {
@@ -420,13 +420,13 @@ public class TlsClientProtocol extends TlsProtocol { this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
}
- ProtocolVersion client_version = this.tlsClientContext.getClientVersion();
+ ProtocolVersion client_version = getContext().getClientVersion();
if (!server_version.isEqualOrEarlierVersionOf(client_version)) {
this.failWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
}
this.recordStream.setWriteVersion(server_version);
- this.tlsClientContext.setServerVersion(server_version);
+ getContext().setServerVersion(server_version);
this.tlsClient.notifyServerVersion(server_version);
/*
@@ -578,7 +578,7 @@ public class TlsClientProtocol extends TlsProtocol { this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
}
- this.tlsClientContext.setClientVersion(client_version);
+ getContext().setClientVersion(client_version);
TlsUtils.writeVersion(client_version, buf);
buf.write(securityParameters.clientRandom);
diff --git a/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java b/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java index 366632a8..0c40fb72 100644 --- a/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java +++ b/src/main/java/org/bouncycastle/crypto/tls/TlsProtocol.java @@ -78,7 +78,7 @@ public abstract class TlsProtocol { this.secureRandom = secureRandom;
}
- protected abstract TlsContext getContext();
+ protected abstract AbstractTlsContext getContext();
protected abstract TlsPeer getPeer();
diff --git a/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java b/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java index e1a911f1..d18af0ec 100644 --- a/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java +++ b/src/main/java/org/bouncycastle/crypto/tls/TlsServerProtocol.java @@ -9,6 +9,9 @@ import java.security.SecureRandom; import java.util.Hashtable;
import java.util.Vector;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.util.Arrays;
public class TlsServerProtocol extends TlsProtocol {
@@ -68,7 +71,7 @@ public class TlsServerProtocol extends TlsProtocol { this.tlsServer.notifyHandshakeComplete();
}
- protected TlsContext getContext() {
+ protected AbstractTlsContext getContext() {
return tlsServerContext;
}
@@ -131,7 +134,7 @@ public class TlsServerProtocol extends TlsProtocol { this.connection_state = CS_SERVER_SUPPLEMENTAL_DATA;
this.keyExchange = tlsServer.getKeyExchange();
- this.keyExchange.init(this.tlsServerContext);
+ this.keyExchange.init(getContext());
TlsCredentials serverCredentials = tlsServer.getCredentials();
if (serverCredentials == null) {
@@ -212,8 +215,7 @@ public class TlsServerProtocol extends TlsProtocol { this.keyExchange.skipClientCredentials();
} else {
- ProtocolVersion equivalentTLSVersion = tlsServerContext.getServerVersion()
- .getEquivalentTLSVersion();
+ ProtocolVersion equivalentTLSVersion = getContext().getServerVersion().getEquivalentTLSVersion();
if (ProtocolVersion.TLSv12.isEqualOrEarlierVersionOf(equivalentTLSVersion)) {
/*
@@ -308,7 +310,7 @@ public class TlsServerProtocol extends TlsProtocol { * SSL 3.0 If the server has sent a certificate request Message, the client must send
* either the certificate message or a no_certificate alert.
*/
- if (tlsServerContext.getServerVersion().isSSL() && certificateRequest != null) {
+ if (getContext().getServerVersion().isSSL() && certificateRequest != null) {
notifyClientCertificate(Certificate.EMPTY_CHAIN);
}
break;
@@ -384,10 +386,19 @@ public class TlsServerProtocol extends TlsProtocol { assertEmpty(buf);
- /*
- * TODO Verify 'clientCertificateSignature' over 'this.certificateVerifyHash', against
- * 'this.clientCertificate'.
- */
+ // Verify the CertificateVerify message contains a correct signature.
+ try {
+ TlsSigner tlsSigner = TlsUtils.createTlsSigner(this.clientCertificateType);
+ tlsSigner.init(getContext());
+
+ org.bouncycastle.asn1.x509.Certificate x509Cert = this.clientCertificate.getCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(keyInfo);
+
+ tlsSigner.verifyRawSignature(clientCertificateSignature, publicKey, certificateVerifyHash);
+ } catch (Exception e) {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
}
protected void receiveClientHelloMessage(ByteArrayInputStream buf) throws IOException {
@@ -438,7 +449,7 @@ public class TlsServerProtocol extends TlsProtocol { * ClientHello. Including both is NOT RECOMMENDED.
*/
- tlsServerContext.setClientVersion(client_version);
+ getContext().setClientVersion(client_version);
tlsServer.notifyClientVersion(client_version);
@@ -494,7 +505,7 @@ public class TlsServerProtocol extends TlsProtocol { assertEmpty(buf);
- establishMasterSecret(tlsServerContext, keyExchange);
+ establishMasterSecret(getContext(), keyExchange);
/*
* Initialize our cipher suite
@@ -553,14 +564,14 @@ public class TlsServerProtocol extends TlsProtocol { TlsUtils.writeUint24(0, buf);
ProtocolVersion server_version = tlsServer.getServerVersion();
- if (!server_version.isEqualOrEarlierVersionOf(tlsServerContext.getClientVersion())) {
+ if (!server_version.isEqualOrEarlierVersionOf(getContext().getClientVersion())) {
this.failWithError(AlertLevel.fatal, AlertDescription.internal_error);
}
recordStream.setReadVersion(server_version);
recordStream.setWriteVersion(server_version);
recordStream.setRestrictReadVersion(true);
- tlsServerContext.setServerVersion(server_version);
+ getContext().setServerVersion(server_version);
TlsUtils.writeVersion(server_version, buf);
diff --git a/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java b/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java index ffc79d2a..abf2482e 100644 --- a/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java +++ b/src/main/java/org/bouncycastle/crypto/tls/TlsUtils.java @@ -790,9 +790,16 @@ public class TlsUtils }
}
- public static short getClientCertificateType(Certificate clientCertificate)
+ public static short getClientCertificateType(Certificate clientCertificate) throws IOException
{
- // FIXME
+ if (clientCertificate.isEmpty())
+ return -1;
+
+ org.bouncycastle.asn1.x509.Certificate x509Cert = clientCertificate.getCertificateAt(0);
+
+ // TODO Handle other types
+
+ validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
return ClientCertificateType.rsa_sign;
}
@@ -809,6 +816,20 @@ public class TlsUtils }
}
+ public static TlsSigner createTlsSigner(short clientCertificateType) {
+ switch (clientCertificateType)
+ {
+ case ClientCertificateType.dss_sign:
+ return new TlsDSSSigner();
+ case ClientCertificateType.ecdsa_sign:
+ return new TlsECDSASigner();
+ case ClientCertificateType.rsa_sign:
+ return new TlsRSASigner();
+ default:
+ throw new IllegalArgumentException("'clientCertificateType' is not a type with signing capability");
+ }
+ }
+
static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
diff --git a/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java b/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java index 13c87028..b8b34e5e 100644 --- a/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java +++ b/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSClient.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.PrintStream;
import org.bouncycastle.asn1.x509.Certificate;
-import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.tls.AlertLevel;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.ClientCertificateType;
@@ -12,7 +11,6 @@ import org.bouncycastle.crypto.tls.DefaultTlsClient; import org.bouncycastle.crypto.tls.ProtocolVersion;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsCredentials;
-import org.bouncycastle.util.encoders.Hex;
public class MockDTLSClient extends DefaultTlsClient {
@@ -50,8 +48,8 @@ public class MockDTLSClient extends DefaultTlsClient { System.out.println("Received server certificate chain of length " + chain.length);
for (Certificate entry : chain) {
// TODO Create fingerprint based on certificate signature algorithm digest
- System.out.println(" fingerprint:SHA-256 " + fingerprint(entry) + " (" + entry.getSubject()
- + ")");
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " ("
+ + entry.getSubject() + ")");
}
}
@@ -70,28 +68,4 @@ public class MockDTLSClient extends DefaultTlsClient { }
};
}
-
- private static String fingerprint(Certificate c) throws IOException {
- byte[] der = c.getEncoded();
- byte[] sha1 = sha256DigestOf(der);
- byte[] hexBytes = Hex.encode(sha1);
- String hex = new String(hexBytes, "ASCII").toUpperCase();
-
- StringBuffer fp = new StringBuffer();
- int i = 0;
- fp.append(hex.substring(i, i + 2));
- while ((i += 2) < hex.length()) {
- fp.append(':');
- fp.append(hex.substring(i, i + 2));
- }
- return fp.toString();
- }
-
- private static byte[] sha256DigestOf(byte[] input) {
- SHA256Digest d = new SHA256Digest();
- d.update(input, 0, input.length);
- byte[] result = new byte[d.getDigestSize()];
- d.doFinal(result, 0);
- return result;
- }
-}
\ No newline at end of file +}
diff --git a/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java b/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java index 363bf79c..ca182036 100644 --- a/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java +++ b/src/test/java/org/bouncycastle/crypto/tls/test/MockDTLSServer.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.io.PrintStream;
import org.bouncycastle.asn1.x509.Certificate;
-import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.tls.AlertLevel;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.ClientCertificateType;
@@ -12,7 +11,6 @@ import org.bouncycastle.crypto.tls.DefaultTlsServer; import org.bouncycastle.crypto.tls.ProtocolVersion;
import org.bouncycastle.crypto.tls.TlsEncryptionCredentials;
import org.bouncycastle.crypto.tls.TlsSignerCredentials;
-import org.bouncycastle.util.encoders.Hex;
public class MockDTLSServer extends DefaultTlsServer {
@@ -35,15 +33,15 @@ public class MockDTLSServer extends DefaultTlsServer { }
public CertificateRequest getCertificateRequest() {
- return new CertificateRequest(new short[]{ ClientCertificateType.rsa_sign }, null);
+ return new CertificateRequest(new short[] { ClientCertificateType.rsa_sign }, null);
}
public void notifyClientCertificate(org.bouncycastle.crypto.tls.Certificate clientCertificate) throws IOException {
Certificate[] chain = clientCertificate.getCertificateList();
- System.out.println("Received server certificate chain of length " + chain.length);
+ System.out.println("Received client certificate chain of length " + chain.length);
for (Certificate entry : chain) {
// TODO Create fingerprint based on certificate signature algorithm digest
- System.out.println(" fingerprint:SHA-256 " + fingerprint(entry) + " (" + entry.getSubject()
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + entry.getSubject()
+ ")");
}
}
@@ -65,28 +63,4 @@ public class MockDTLSServer extends DefaultTlsServer { return TlsTestUtils.loadSignerCredentials(context, new String[] { "x509-server.pem", "x509-ca.pem" },
"x509-server-key.pem");
}
-
- private static String fingerprint(Certificate c) throws IOException {
- byte[] der = c.getEncoded();
- byte[] sha1 = sha256DigestOf(der);
- byte[] hexBytes = Hex.encode(sha1);
- String hex = new String(hexBytes, "ASCII").toUpperCase();
-
- StringBuffer fp = new StringBuffer();
- int i = 0;
- fp.append(hex.substring(i, i + 2));
- while ((i += 2) < hex.length()) {
- fp.append(':');
- fp.append(hex.substring(i, i + 2));
- }
- return fp.toString();
- }
-
- private static byte[] sha256DigestOf(byte[] input) {
- SHA256Digest d = new SHA256Digest();
- d.update(input, 0, input.length);
- byte[] result = new byte[d.getDigestSize()];
- d.doFinal(result, 0);
- return result;
- }
}
diff --git a/src/test/java/org/bouncycastle/crypto/tls/test/TlsProtocolTest.java b/src/test/java/org/bouncycastle/crypto/tls/test/TlsProtocolTest.java index 86f36ed1..403b5682 100644 --- a/src/test/java/org/bouncycastle/crypto/tls/test/TlsProtocolTest.java +++ b/src/test/java/org/bouncycastle/crypto/tls/test/TlsProtocolTest.java @@ -8,9 +8,13 @@ import java.security.SecureRandom; import junit.framework.TestCase;
+import org.bouncycastle.asn1.x509.Certificate;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.tls.AlertDescription;
import org.bouncycastle.crypto.tls.AlertLevel;
+import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.CipherSuite;
+import org.bouncycastle.crypto.tls.ClientCertificateType;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.DefaultTlsServer;
import org.bouncycastle.crypto.tls.ServerOnlyTlsAuthentication;
@@ -21,6 +25,7 @@ import org.bouncycastle.crypto.tls.TlsEncryptionCredentials; import org.bouncycastle.crypto.tls.TlsFatalAlert;
import org.bouncycastle.crypto.tls.TlsServerProtocol;
import org.bouncycastle.crypto.tls.TlsSignerCredentials;
+import org.bouncycastle.util.encoders.Hex;
public class TlsProtocolTest extends TestCase {
@@ -96,9 +101,30 @@ public class TlsProtocolTest extends TestCase { }
public TlsAuthentication getAuthentication() throws IOException {
- return new ServerOnlyTlsAuthentication() {
+ return new TlsAuthentication() {
public void notifyServerCertificate(org.bouncycastle.crypto.tls.Certificate serverCertificate)
throws IOException {
+ Certificate[] chain = serverCertificate.getCertificateList();
+ System.out.println("Received server certificate chain of length " + chain.length);
+ for (Certificate entry : chain) {
+ // TODO Create fingerprint based on certificate signature algorithm digest
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " ("
+ + entry.getSubject() + ")");
+ }
+ }
+
+ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException {
+ short[] certificateTypes = certificateRequest.getCertificateTypes();
+ if (certificateTypes != null) {
+ for (int i = 0; i < certificateTypes.length; ++i) {
+ if (certificateTypes[i] == ClientCertificateType.rsa_sign) {
+ // TODO Create a distinct client certificate for use here
+ return TlsTestUtils.loadSignerCredentials(context, new String[] { "x509-server.pem",
+ "x509-ca.pem" }, "x509-server-key.pem");
+ }
+ }
+ }
+ return null;
}
};
}
@@ -124,6 +150,21 @@ public class TlsProtocolTest extends TestCase { + alertDescription + ")");
}
+ public CertificateRequest getCertificateRequest() {
+ return new CertificateRequest(new short[] { ClientCertificateType.rsa_sign }, null);
+ }
+
+ public void notifyClientCertificate(org.bouncycastle.crypto.tls.Certificate clientCertificate)
+ throws IOException {
+ Certificate[] chain = clientCertificate.getCertificateList();
+ System.out.println("Received client certificate chain of length " + chain.length);
+ for (Certificate entry : chain) {
+ // TODO Create fingerprint based on certificate signature algorithm digest
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " ("
+ + entry.getSubject() + ")");
+ }
+ }
+
protected TlsEncryptionCredentials getRSAEncryptionCredentials() throws IOException {
return TlsTestUtils.loadEncryptionCredentials(context, new String[] { "x509-server.pem", "x509-ca.pem" },
"x509-server-key.pem");
diff --git a/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestUtils.java b/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestUtils.java index a10ef2b4..95805375 100644 --- a/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestUtils.java +++ b/src/test/java/org/bouncycastle/crypto/tls/test/TlsTestUtils.java @@ -5,6 +5,7 @@ import java.io.InputStream; import java.io.InputStreamReader;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.tls.Certificate;
@@ -17,6 +18,7 @@ import org.bouncycastle.crypto.tls.TlsEncryptionCredentials; import org.bouncycastle.crypto.tls.TlsSignerCredentials;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
@@ -43,6 +45,30 @@ public class TlsTestUtils { + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS"
+ "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0=");
+ static String fingerprint(org.bouncycastle.asn1.x509.Certificate c) throws IOException {
+ byte[] der = c.getEncoded();
+ byte[] sha1 = sha256DigestOf(der);
+ byte[] hexBytes = Hex.encode(sha1);
+ String hex = new String(hexBytes, "ASCII").toUpperCase();
+
+ StringBuffer fp = new StringBuffer();
+ int i = 0;
+ fp.append(hex.substring(i, i + 2));
+ while ((i += 2) < hex.length()) {
+ fp.append(':');
+ fp.append(hex.substring(i, i + 2));
+ }
+ return fp.toString();
+ }
+
+ static byte[] sha256DigestOf(byte[] input) {
+ SHA256Digest d = new SHA256Digest();
+ d.update(input, 0, input.length);
+ byte[] result = new byte[d.getDigestSize()];
+ d.doFinal(result, 0);
+ return result;
+ }
+
static TlsAgreementCredentials loadAgreementCredentials(TlsContext context,
String[] certResources, String keyResource) throws IOException {
|