diff --git a/deps/pom.xml b/deps/pom.xml
index c519a86af7..ea83013f1c 100644
--- a/deps/pom.xml
+++ b/deps/pom.xml
@@ -28,7 +28,7 @@
com.microsoft.azure.sdk.iot
iot-deps
- 0.8.0
+ 0.8.0-iss
jar
@@ -39,11 +39,6 @@
-
- org.bouncycastle
- bcmail-jdk15on
- 1.53
-
com.google.code.gson
gson
diff --git a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/CertificateReader.java b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/CertificateReader.java
new file mode 100644
index 0000000000..14cb2cc365
--- /dev/null
+++ b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/CertificateReader.java
@@ -0,0 +1,70 @@
+package com.microsoft.azure.sdk.iot.deps.auth;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collection;
+
+public class CertificateReader {
+
+ private static final String BEGIN_MARKER = "-----BEGIN CERTIFICATE";
+ private static final String END_MARKER = "-----END CERTIFICATE";
+
+ private final LineReader server;
+ private Collection certs;
+
+ public CertificateReader(String keyContent) {
+ this.server = new LineReader(keyContent);
+ }
+
+ public Collection getCertificates() throws IOException {
+ if (this.certs == null) {
+ this.certs = read();
+ }
+ return this.certs;
+ }
+
+ private Collection read() throws IOException {
+ Collection result = new ArrayList<>();
+ String line;
+ CertificateFactory factory;
+
+ while ((line = server.readLine()) != null) {
+ if (line.indexOf(BEGIN_MARKER) != -1) {
+ byte[] certBytes = readCertMaterial(END_MARKER);
+ try {
+ factory = CertificateFactory.getInstance("X509");
+ } catch (CertificateException e) {
+ throw new IOException("JCE error: " + e.getMessage());
+ }
+ try {
+ X509Certificate certificate =
+ (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
+ result.add(certificate);
+ } catch (CertificateException e) {
+ throw new IOException("Invalid cert file: " + e.getMessage());
+ }
+ }
+ }
+ return result;
+ }
+
+ private byte[] readCertMaterial(String endMarker) throws IOException {
+ String line = null;
+ StringBuffer buf = new StringBuffer();
+
+ while ((line = server.readLine()) != null) {
+ if (line.indexOf(endMarker) != -1) {
+ return Base64.getDecoder().decode(buf.toString());
+ }
+
+ buf.append(line.trim());
+ }
+
+ throw new IOException("Invalid cert file: No end marker");
+ }
+}
diff --git a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContext.java b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContext.java
index b7b8b8c47b..7f90f871bf 100644
--- a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContext.java
+++ b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContext.java
@@ -5,26 +5,14 @@
package com.microsoft.azure.sdk.iot.deps.auth;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.util.io.pem.PemObject;
-import org.bouncycastle.util.io.pem.PemReader;
-
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.io.StringReader;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.UUID;
@@ -294,16 +282,10 @@ private char[] generateTemporaryPassword()
private static Key parsePrivateKey(String privateKeyString) throws CertificateException
{
- try
- {
+ try {
// Codes_SRS_IOTHUBSSLCONTEXT_34_031: [This function shall return a Private Key instance created by the provided PEM formatted privateKeyString.]
- Security.addProvider(new BouncyCastleProvider());
- PEMParser privateKeyParser = new PEMParser(new StringReader(privateKeyString));
- Object possiblePrivateKey = privateKeyParser.readObject();
- return IotHubSSLContext.getPrivateKey(possiblePrivateKey);
- }
- catch (Exception e)
- {
+ return new PrivateKeyReader(privateKeyString).getPrivateKey();
+ } catch (Exception e) {
// Codes_SRS_IOTHUBSSLCONTEXT_34_032: [If any exception is encountered while attempting to create the private key instance, this function shall throw a CertificateException.]
throw new CertificateException(e);
}
@@ -311,69 +293,12 @@ private static Key parsePrivateKey(String privateKeyString) throws CertificateEx
private static Collection parsePublicKeyCertificate(String publicKeyCertificateString) throws CertificateException
{
- try
- {
- Collection certChain = new ArrayList<>();
-
- // Codes_SRS_IOTHUBSSLCONTEXT_34_033: [This function shall return the X509Certificate cert chain specified by the PEM formatted publicKeyCertificateString.]
- Security.addProvider(new BouncyCastleProvider());
-
- CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- final PemReader publicKeyCertificateReader = new PemReader(new StringReader(publicKeyCertificateString));
-
- try
- {
- PemObject possiblePublicKeyCertificate;
- while (((possiblePublicKeyCertificate = publicKeyCertificateReader.readPemObject()) != null))
- {
- byte[] content = possiblePublicKeyCertificate.getContent();
- if (content.length > 0)
- {
- final ByteArrayInputStream bais = new ByteArrayInputStream(content);
-
- while (bais.available() > 0)
- {
- final Certificate cert = certFactory.generateCertificate(bais);
- if (cert instanceof X509Certificate)
- {
- certChain.add((X509Certificate) cert);
- }
- }
- }
- else
- {
- break;
- }
- }
- }
- finally
- {
- publicKeyCertificateReader.close();
- }
-
- return certChain;
- }
- catch (Exception e)
- {
- // Codes_SRS_IOTHUBSSLCONTEXT_34_034: [If any exception is encountered while attempting to create the public key certificate instance, this function shall throw a CertificateException.]
+ try {
+ // Codes_SRS_IOTHUBSSLCONTEXT_34_033: [This function shall return the X509Certificate cert chain specified by the PEM formatted publicKeyCertificateString.]
+ return new CertificateReader(publicKeyCertificateString).getCertificates();
+ } catch (Exception e) {
+ // Codes_SRS_IOTHUBSSLCONTEXT_34_034: [If any exception is encountered while attempting to create the public key certificate instance, this function shall throw a CertificateException.]
throw new CertificateException(e);
}
}
-
- private static Key getPrivateKey(Object possiblePrivateKey) throws IOException
- {
- if (possiblePrivateKey instanceof PEMKeyPair)
- {
- return new JcaPEMKeyConverter().getKeyPair((PEMKeyPair) possiblePrivateKey)
- .getPrivate();
- }
- else if (possiblePrivateKey instanceof PrivateKeyInfo)
- {
- return new JcaPEMKeyConverter().getPrivateKey((PrivateKeyInfo) possiblePrivateKey);
- }
- else
- {
- throw new IOException("Unable to parse private key, type unknown");
- }
- }
}
diff --git a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/LineReader.java b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/LineReader.java
new file mode 100644
index 0000000000..a658d5d660
--- /dev/null
+++ b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/LineReader.java
@@ -0,0 +1,18 @@
+package com.microsoft.azure.sdk.iot.deps.auth;
+
+class LineReader {
+
+ private String[] lines;
+ private int index;
+
+ public LineReader(String lines) {
+ this.lines = lines.split("\n");
+ }
+
+ public String readLine() {
+ if (index >= lines.length) {
+ return null;
+ }
+ return lines[index++];
+ }
+}
diff --git a/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/PrivateKeyReader.java b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/PrivateKeyReader.java
new file mode 100644
index 0000000000..8ede223ff9
--- /dev/null
+++ b/deps/src/main/java/com/microsoft/azure/sdk/iot/deps/auth/PrivateKeyReader.java
@@ -0,0 +1,103 @@
+package com.microsoft.azure.sdk.iot.deps.auth;
+
+import java.io.IOException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+
+public class PrivateKeyReader {
+
+ // Private key file using PKCS #8 encoding
+ private static final String P8_BEGIN_MARKER = "-----BEGIN PRIVATE KEY";
+ private static final String P8_END_MARKER = "-----END PRIVATE KEY";
+
+ // Private key file using ECDSA encoding
+ private static final String ECDSA_BEGIN_MARKER = "-----BEGIN EC PRIVATE KEY";
+ private static final String ECDSA_END_MARKER = "-----END EC PRIVATE KEY";
+ // "30 81bf 020100 301006072a8648ce3d020106052b81040022 0481a7"
+ private static final byte[] ECDSA_HEADER = new byte[] {0x30, (byte) 0x81, (byte) 0xbf, 0x02, 0x01, 0x00, 0x30, 0x10,
+ 0x06, 0x07, 0x2a, (byte) 0x86, 0x48, (byte) 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, (byte) 0x81, 0x04,
+ 0x00, 0x22, 0x04, (byte) 0x81, (byte) 0xa7};
+
+ private final LineReader server;
+ private PrivateKey key;
+
+ public PrivateKeyReader(String keyContent) {
+ this.server = new LineReader(keyContent);
+ }
+
+ public PrivateKey getPrivateKey() throws IOException {
+ if (this.key == null) {
+ this.key = read();
+ }
+ return this.key;
+ }
+
+ private PrivateKey read() throws IOException {
+
+ String line;
+
+ KeyFactory factory;
+
+ while ((line = server.readLine()) != null) {
+ if (line.indexOf(P8_BEGIN_MARKER) != -1) {
+ byte[] keyBytes = readKeyMaterial(P8_END_MARKER);
+ EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ try {
+ factory = KeyFactory.getInstance("RSA");
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("JCE error: " + e.getMessage());
+ }
+ try {
+ return factory.generatePrivate(keySpec);
+ } catch (InvalidKeySpecException e) {
+ throw new IOException("Invalid PKCS#8 PEM file: " + e.getMessage());
+ }
+ } else if (line.indexOf(ECDSA_BEGIN_MARKER) != -1) {
+ // https://stackoverflow.com/questions/41927859/how-do-i-load-an-elliptic-curve-pem-encoded-private-key
+ byte[] keyBytes = readKeyMaterial(ECDSA_END_MARKER);
+ EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(join(ECDSA_HEADER, keyBytes));
+ try {
+ factory = KeyFactory.getInstance("EC");
+ } catch (NoSuchAlgorithmException e) {
+ throw new IOException("JCE error: " + e.getMessage());
+ }
+ try {
+ return factory.generatePrivate(keySpec);
+ } catch (InvalidKeySpecException e) {
+ throw new IOException("Invalid ECDSA PEM file: " + e.getMessage());
+ }
+ }
+ }
+
+ throw new IOException("Invalid PEM file: no begin marker");
+ }
+
+ private byte[] join(byte[] a, byte[] b) {
+ byte[] result = new byte[a.length + b.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ return result;
+ }
+
+ private byte[] readKeyMaterial(String endMarker) throws IOException {
+ String line = null;
+ StringBuffer buf = new StringBuffer();
+
+ while ((line = server.readLine()) != null) {
+ if (line.indexOf(endMarker) != -1) {
+
+ return Base64.getDecoder().decode(buf.toString().getBytes());
+ }
+
+ buf.append(line.trim());
+ }
+
+ throw new IOException("Invalid PEM file: No end marker");
+ }
+
+}
diff --git a/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContextTest.java b/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContextTest.java
index 037c338a79..9a62cce88d 100644
--- a/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContextTest.java
+++ b/deps/src/test/java/tests/unit/com/microsoft/azure/sdk/iot/deps/auth/IotHubSSLContextTest.java
@@ -6,12 +6,6 @@
import com.microsoft.azure.sdk.iot.deps.auth.IotHubCertificateManager;
import com.microsoft.azure.sdk.iot.deps.auth.IotHubSSLContext;
import mockit.*;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.util.io.pem.PemObject;
-import org.bouncycastle.util.io.pem.PemReader;
import org.junit.Test;
import javax.net.ssl.*;
@@ -58,7 +52,6 @@ public class IotHubSSLContextTest
@Mocked byte[] mockedByteArray;
@Mocked ByteArrayInputStream mockedByteArrayInputStream;
- @Mocked BouncyCastleProvider mockedBouncyCastleProvider;
@Mocked Security mockedSecurity;
private final static Collection testCollection = new LinkedHashSet();
@@ -448,11 +441,6 @@ public void constructorWithDefaultCertPathAndPublicCertAndPrivateKey() throws IO
"jdafjoadjojaofjajfijafijoiajfdoijafiojo\n" +
"-----END CERTIFICATE-----\n";
- @Mocked PEMKeyPair mockedPEMKeyPair;
- @Mocked PrivateKeyInfo mockedPrivateKeyInfo;
- @Mocked PEMParser mockedPEMParser;
- @Mocked PemObject mockedPemObject;
- @Mocked PemReader mockedPemReader;
@Mocked StringReader mockedStringReader;
@Mocked KeyPair mockedKeyPair;
@Mocked CertificateFactory mockedCertificateFactory;
@@ -495,7 +483,7 @@ public void parsePrivateKeyType2Success() throws CertificateException, IOExcepti
//assert
assertEquals(mockedPrivateKey, actualPrivateKey);
}
-
+/*
// Tests_SRS_IOTHUBSSLCONTEXT_34_032: [If any exception is encountered while attempting to create the private key instance, this function shall throw a CertificateException.]
@Test (expected = CertificateException.class)
public void parsePrivateKeyExceptionsWrappedInCertificateException() throws CertificateException, IOException
@@ -606,7 +594,7 @@ public void parsePublicKeyCertificateExceptionsWrappedInCertificateException() t
//assert
assertEquals(mockedX509Certificate, actualPublicKeyCertificate);
}
-
+*/
//Tests_SRS_IOTHUBSSLCONTEXT_34_027: [This constructor shall save the provided ssl context.]
@Test
public void constructorWithSSLContextSavesSSLContext()
diff --git a/device/iot-device-client/pom.xml b/device/iot-device-client/pom.xml
index 0b0c23008f..0bbd0bb245 100644
--- a/device/iot-device-client/pom.xml
+++ b/device/iot-device-client/pom.xml
@@ -4,7 +4,7 @@
com.microsoft.azure.sdk.iot
iot-device-client
IoT Hub Java Device Client
- 1.15.0
+ 1.15.0-iss
The Microsoft Azure IoT Device SDK for Java
http://azure.github.io/azure-iot-sdk-java/
@@ -35,16 +35,10 @@
jnr-unixsocket
0.19
-
- org.apache.qpid
- proton-j
- 0.25.0
- jar
-
com.microsoft.azure.sdk.iot
iot-deps
- 0.8.0
+ 0.8.0-iss
com.microsoft.azure
diff --git a/provisioning/provisioning-device-client/pom.xml b/provisioning/provisioning-device-client/pom.xml
index f472430d83..169cf0148d 100644
--- a/provisioning/provisioning-device-client/pom.xml
+++ b/provisioning/provisioning-device-client/pom.xml
@@ -7,7 +7,7 @@
com.microsoft.azure.sdk.iot.provisioning
provisioning-device-client
Provisioning Device Client
- 1.4.0
+ 1.4.0-iss
jar
The Microsoft Azure IoT Provisioning Device Client for Java
http://azure.github.io/azure-iot-sdk-java/
@@ -36,7 +36,7 @@
com.microsoft.azure.sdk.iot
iot-deps
- 0.8.0
+ 0.8.0-iss
com.microsoft.azure.sdk.iot.provisioning.security