diff --git a/keyvault/data-plane/README.md b/keyvault/data-plane/README.md
index d90d0450abdc..7d68af7378e6 100644
--- a/keyvault/data-plane/README.md
+++ b/keyvault/data-plane/README.md
@@ -83,7 +83,8 @@ To get the binaries of this library as distributed by Microsoft, ready for use w
com.microsoft.azure
azure-keyvault-complete
- 1.1.2
+ 1.2.0
+ pom
```
@@ -114,6 +115,7 @@ If you would like to become an active contributor to this project please follow
| Version | Comments |
| :-------: | :-------- |
+| [1.1.2](https://github.com/Azure/azure-keyvault-java/tree/1.1.2) | Version 1.1.2 release |
| [1.1.1](https://github.com/Azure/azure-keyvault-java/tree/1.1.1) | Version 1.1.1 release |
| [1.1](https://github.com/Azure/azure-keyvault-java/tree/1.1) | Version 1.1 release |
| [1.1-beta-1](https://github.com/Azure/azure-keyvault-java/tree/1.1-beta-1) | Version 1.1.0 **beta** release |
diff --git a/keyvault/data-plane/azure-keyvault-complete/pom.xml b/keyvault/data-plane/azure-keyvault-complete/pom.xml
index 11fd13065e2e..00f69fd66c81 100644
--- a/keyvault/data-plane/azure-keyvault-complete/pom.xml
+++ b/keyvault/data-plane/azure-keyvault-complete/pom.xml
@@ -7,13 +7,13 @@ the MIT License. See License.txt in the project root for license information. --
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
com.microsoft.azure
azure-keyvault-complete
- 1.1.2
+ 1.2.0
pom
diff --git a/keyvault/data-plane/azure-keyvault-core/pom.xml b/keyvault/data-plane/azure-keyvault-core/pom.xml
index cee82573a28b..6c7dfb51eadd 100644
--- a/keyvault/data-plane/azure-keyvault-core/pom.xml
+++ b/keyvault/data-plane/azure-keyvault-core/pom.xml
@@ -8,12 +8,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
azure-keyvault-core
- 1.1.2
+ 1.2.0
jar
Microsoft Azure SDK for Key Vault Core
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/pom.xml b/keyvault/data-plane/azure-keyvault-cryptography/pom.xml
index edcde42ea81d..9d1d354c8f84 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/pom.xml
+++ b/keyvault/data-plane/azure-keyvault-cryptography/pom.xml
@@ -7,12 +7,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
azure-keyvault-cryptography
- 1.1.2
+ 1.2.0
jar
Microsoft Azure SDK for Key Vault Cryptography
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java
new file mode 100644
index 000000000000..b9fbc358ce03
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java
@@ -0,0 +1,310 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import org.apache.commons.lang3.ArrayUtils;
+
+import com.microsoft.azure.keyvault.cryptography.algorithms.Ecdsa;
+import org.apache.commons.codec.binary.Hex;
+
+public final class SignatureEncoding {
+ // SignatureEncoding is intended to be a static class
+ private SignatureEncoding() { }
+
+ /**
+ * Converts an ASN.1 DER encoded ECDSA signature to a raw signature in the form R|S
+ * @param asn1DerSignature An ASN.1 DER encoded signature
+ * @param algorithm The algorithm used to produce the given ASN.1 DER encoded signature
+ * @return The raw format of the given ASN.1 DER encoded signature in the form R|S
+ */
+ public static byte[] fromAsn1Der(byte[] asn1DerSignature, String algorithm) throws NoSuchAlgorithmException {
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ // verify the given algoritm could be resolved
+ if (baseAlgorithm == null)
+ {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ // verify the given algoritm is an Ecdsa signature algorithm
+ if (!(baseAlgorithm instanceof Ecdsa))
+ {
+ throw new IllegalArgumentException("Invalid algorithm; must be an instance of ECDSA.");
+ }
+
+ return SignatureEncoding.fromAsn1Der(asn1DerSignature, (Ecdsa)baseAlgorithm);
+ }
+
+ /**
+ * Converts an ASN.1 DER encoded ECDSA signature to a raw signature in the form R|S
+ * @param asn1DerSignature An ASN.1 DER encoded signature
+ * @param algorithm The algorithm used to produce the given ASN.1 DER encoded signature
+ * @return The raw format of the given ASN.1 DER encoded signature in the form R|S
+ */
+ public static byte[] fromAsn1Der(byte[] asn1DerSignature, Ecdsa algorithm) {
+
+ try
+ {
+ return Asn1DerSignatureEncoding.Decode(asn1DerSignature, algorithm);
+ }
+ catch(IllegalArgumentException ex)
+ {
+ throw (IllegalArgumentException)new IllegalArgumentException(ex.getMessage() + " " + Hex.encodeHexString( asn1DerSignature )).initCause(ex);
+
+ }
+ }
+
+ /**
+ * Converts a raw ECDSA signature in the form R|S to an ASN.1 DER encoded signature.
+ * @param signature A raw ECDSA signature in the form R|S.
+ * @param algorithm The algorithm used to produce the given signature.
+ * @return The ASN.1 DER encoded signature of the given signature.
+ */
+ public static byte[] toAsn1Der(byte[] signature, String algorithm) throws NoSuchAlgorithmException {
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ // verify the given algoritm could be resolved
+ if (baseAlgorithm == null)
+ {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ // verify the given algoritm is an Ecdsa signature algorithm
+ if (!(baseAlgorithm instanceof Ecdsa))
+ {
+ throw new IllegalArgumentException("Invalid algorithm; must be an instance of ECDSA.");
+ }
+
+ return SignatureEncoding.toAsn1Der(signature, (Ecdsa)baseAlgorithm);
+ }
+
+ /**
+ * Converts a raw ECDSA signature in the form R|S to an ASN.1 DER encoded signature.
+ * @param signature A raw ECDSA signature in the form R|S.
+ * @param algorithm The algorithm used to produce the given signature.
+ * @return The ASN.1 DER encoded signature of the given signature.
+ */
+ public static byte[] toAsn1Der(byte[] signature, Ecdsa algorithm) {
+
+ try
+ {
+ return Asn1DerSignatureEncoding.Encode(signature, algorithm);
+ }
+ catch(IllegalArgumentException ex)
+ {
+ throw (IllegalArgumentException)new IllegalArgumentException(ex.getMessage() + " " + Hex.encodeHexString( signature )).initCause(ex);
+
+ }
+ }
+}
+
+
+final class Asn1DerSignatureEncoding {
+ // the EDCSA ASN.1 DER signature is in the format:
+ // 0x30 b1 0x02 b2 (vr) 0x02 b3 (vs)
+ // where:
+ // *b1 one or more bytes equal to the length, in bytes, of the remaining list of bytes (from the first 0x02 to the end of the encoding)
+ // *b2 one or more bytes equal to the length, in bytes, of (vr)
+ // *b3 one or more bytes equal to the length, in bytes, of (vs)
+ // (vr) is the signed big-endian encoding of the value "r", of minimal length
+ // (vs) is the signed big-endian encoding of the value "s", of minimal length
+ //
+ // * lengths which are less than 0x80 can be expressed in one byte. For lengths greater then 0x80 the first byte denotes the
+ // length in bytes of the length with the most significant bit masked off, i.e. 0x81 denotes the length is one byte long.
+
+ private Asn1DerSignatureEncoding() {
+
+ }
+
+ public static byte[] Encode(byte[] signature, Ecdsa algorithm)
+ {
+ int coordLength = algorithm.getCoordLength();
+
+ // verify that the signature is the correct length for the given algorithm
+ if (signature.length != (coordLength * 2))
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ // r is the first half of the signature
+ BigInteger r = new BigInteger(1, Arrays.copyOfRange(signature, 0, signature.length / 2));
+
+ // s is the second half of the signature
+ BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, signature.length / 2, signature.length));
+
+ // vr and vs are the compacted ASN.1 integer encoding, same as BigInteger encoding
+ byte[] rfield = encodeIntField(r);
+
+ byte[] sfield = encodeIntField(s);
+
+ ByteArrayOutputStream asn1DerSignature = new ByteArrayOutputStream();
+
+ asn1DerSignature.write(0x30);
+
+ // add the length of the fields
+ writeFieldLength(asn1DerSignature, rfield.length + sfield.length);
+
+ // write the fields
+ asn1DerSignature.write(rfield, 0, rfield.length);
+
+ asn1DerSignature.write(sfield, 0, sfield.length);
+
+ return asn1DerSignature.toByteArray();
+ }
+
+ public static byte[] Decode(byte[] bytes, Ecdsa algorithm)
+ {
+ int coordLength = algorithm.getCoordLength();
+
+ ByteArrayInputStream asn1DerSignature = new ByteArrayInputStream(bytes);
+
+ // verify byte 0 is 0x30
+ if (asn1DerSignature.read() != 0x30)
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ int objLen = readFieldLength(asn1DerSignature);
+
+ // verify the object lenth is equal to the remaining length of the _asn1DerSignature
+ if (objLen != asn1DerSignature.available())
+ {
+ throw new IllegalArgumentException(String.format("Invalid signature; invalid field len %d", objLen));
+ }
+
+ byte[] rawSignature = new byte[coordLength * 2];
+
+ // decode the r feild to the first half of _rawSignature
+ decodeIntField(asn1DerSignature, rawSignature, 0, coordLength);
+
+ // decode the s feild to the second half of _rawSignature
+ decodeIntField(asn1DerSignature, rawSignature, rawSignature.length / 2, coordLength);
+
+ return rawSignature;
+ }
+
+ private static byte[] encodeIntField(BigInteger i)
+ {
+ ByteArrayOutputStream field = new ByteArrayOutputStream();
+
+ field.write(0x02);
+
+ // get this byte array for the asn1 encoded integer
+ byte[] vi = i.toByteArray();
+
+ // write the length of the field
+ writeFieldLength(field, vi.length);
+
+ // write the field value
+ field.write(vi, 0, vi.length);
+
+ return field.toByteArray();
+ }
+
+ private static void writeFieldLength(ByteArrayOutputStream field, int len)
+ {
+ // if the length of vi is less then 0x80 we can fit the length in one byte
+ if(len < 0x80)
+ {
+ field.write(len);
+ }
+ // otherwise
+ else
+ {
+ // get the len as a byte array
+ byte[] blen = BigInteger.valueOf(len).toByteArray();
+
+ int lenlen = blen.length;
+
+ // the byte array might have a leading zero byte if so we need to discard this
+ if ( blen[0] == 0 )
+ {
+ lenlen--;
+ }
+
+ // write the continuation byte containing the length length in bytes
+ field.write(0x80 | lenlen);
+
+ // write the field lenth bytes
+ field.write(blen, blen.length - lenlen, lenlen);
+ }
+ }
+
+ private static void decodeIntField(ByteArrayInputStream bytes, byte[] dest, int index, int intlen)
+ {
+ // verify the first byte of field is 0x02
+ if (bytes.read() != 0x02)
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ //get the length of the field
+ int len = readFieldLength(bytes);
+
+ // if the most significant bit of the raw int was set an extra zero byte will be prepended to
+ // the asn1der encoded value so len can have a max value of intlen + 1
+
+ // validate that that len is within the max range and doesn't run past the end of bytes
+ if (len > intlen + 1 || len > bytes.available())
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ // if len is greater than intlen increment _bytesRead and decrement len
+ if (len > intlen)
+ {
+ bytes.skip(1);
+ len--;
+ }
+
+ bytes.read(dest, index + (intlen - len), len);
+ }
+
+ private static int readFieldLength(ByteArrayInputStream bytes)
+ {
+ int firstLenByte = bytes.read();
+
+ // if the high order bit of len is not set it is a single byte length so return
+ if ((firstLenByte & 0x80) == 0x00)
+ {
+ return firstLenByte;
+ }
+
+ // otherwise mask off the high order bit to get the number of bytes to read
+ int numLenBytes = firstLenByte ^ 0x80;
+
+ // if the number of len bytes is greater than the remaining signature the signature is invalid
+ if (numLenBytes > bytes.available())
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ byte[] lenBytes = new byte[numLenBytes];
+
+ bytes.read(lenBytes, 0, numLenBytes);
+
+ BigInteger bigLen = new BigInteger(1, lenBytes);
+
+ // for DSA signatures no feilds should be longer than can be expressed in an integer
+ // this means that the bitLength must be 31 or less to account for the leading zero of
+ // a positive integer
+ if (bigLen.bitLength() >= 31)
+ {
+ throw new IllegalArgumentException("Invalid signature.");
+ }
+
+ return bigLen.intValue();
+ }
+}
+
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java
index a13fa0767997..cd9ceacd9317 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java
@@ -7,6 +7,7 @@
import com.microsoft.azure.keyvault.cryptography.AsymmetricSignatureAlgorithm;
import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+import com.microsoft.azure.keyvault.cryptography.SignatureEncoding;
public abstract class Ecdsa extends AsymmetricSignatureAlgorithm {
@@ -15,21 +16,30 @@ protected Ecdsa() {
}
public ISignatureTransform createSignatureTransform(KeyPair key, Provider provider) {
- return new EcdsaSignatureTransform(key, provider);
+ return new EcdsaSignatureTransform(key, provider, this);
}
- abstract void checkDigestLength(byte[] digest);
-
+ public abstract int getDigestLength();
+ public abstract int getCoordLength();
+
+ private void checkDigestLength(byte[] digest)
+ {
+ if (digest.length != this.getDigestLength()) {
+ throw new IllegalArgumentException("Invalid digest length.");
+ }
+ }
+
class EcdsaSignatureTransform implements ISignatureTransform {
- private final String ALGORITHM = "NONEwithECDSA";
+ private final String ALGORITHM = "NONEwithECDSA";
private final KeyPair _keyPair;
-
private final Provider _provider;
-
- public EcdsaSignatureTransform(KeyPair keyPair, Provider provider) {
+ private final Ecdsa _algorithm;
+
+ public EcdsaSignatureTransform(KeyPair keyPair, Provider provider, Ecdsa algorithm) {
_keyPair = keyPair;
_provider = provider;
+ _algorithm = algorithm;
}
@Override
@@ -38,17 +48,17 @@ public byte[] sign(byte[] digest) throws GeneralSecurityException {
Signature signature = Signature.getInstance(ALGORITHM, _provider);
signature.initSign(_keyPair.getPrivate());
signature.update(digest);
- return signature.sign();
+ return SignatureEncoding.fromAsn1Der(signature.sign(), _algorithm);
}
@Override
public boolean verify(byte[] digest, byte[] signature) throws GeneralSecurityException {
Signature verify = Signature.getInstance(ALGORITHM, _provider);
- checkDigestLength(digest);
+ checkDigestLength(digest);
+ signature = SignatureEncoding.toAsn1Der(signature, _algorithm);
verify.initVerify(_keyPair.getPublic());
verify.update(digest);
return verify.verify(signature);
}
-
}
}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java
index c9ae074fbb56..9766f0018466 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java
@@ -1,12 +1,15 @@
package com.microsoft.azure.keyvault.cryptography.algorithms;
public class Es256 extends Ecdsa {
- public final static String ALGORITHM_NAME = "SHA256withECDSA";
+ public final static String ALGORITHM_NAME = "ES256";
@Override
- public void checkDigestLength(byte[] digest) {
- if (digest.length != 32) {
- throw new IllegalArgumentException("Invalid digest length.");
- }
+ public int getDigestLength() {
+ return 32;
+ }
+
+ @Override
+ public int getCoordLength() {
+ return 32;
}
}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java
index b788979f2b26..9da729997a44 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java
@@ -1,12 +1,15 @@
package com.microsoft.azure.keyvault.cryptography.algorithms;
public class Es256k extends Ecdsa {
- public final static String ALGORITHM_NAME = "NONEwithECDSA";
+ public final static String ALGORITHM_NAME = "ES256K";
@Override
- public void checkDigestLength(byte[] digest) {
- if (digest.length != 32) {
- throw new IllegalArgumentException("Invalid digest length.");
- }
+ public int getDigestLength() {
+ return 32;
+ }
+
+ @Override
+ public int getCoordLength() {
+ return 32;
}
}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java
index 7785fdbda61a..16ff088c6526 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java
@@ -2,12 +2,15 @@
public class Es384 extends Ecdsa {
- public final static String ALGORITHM_NAME = "SHA384withECDSA";
+ public final static String ALGORITHM_NAME = "ES384";
@Override
- public void checkDigestLength(byte[] digest) {
- if (digest.length != 48) {
- throw new IllegalArgumentException("Invalid digest length.");
- }
+ public int getDigestLength() {
+ return 48;
+ }
+
+ @Override
+ public int getCoordLength() {
+ return 48;
}
}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java
index 32fdd3769951..ef94fedb9de6 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java
@@ -2,12 +2,15 @@
public class Es512 extends Ecdsa {
- public final static String ALGORITHM_NAME = "SHA512withECDSA";
+ public final static String ALGORITHM_NAME = "ES512";
@Override
- public void checkDigestLength(byte[] digest) {
- if (digest.length != 64) {
- throw new IllegalArgumentException("Invalid digest length.");
- }
+ public int getDigestLength() {
+ return 64;
+ }
+
+ @Override
+ public int getCoordLength() {
+ return 66;
}
}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java
index 748c75f6f159..ef0c036938a2 100644
--- a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java
@@ -38,6 +38,11 @@
import com.google.common.collect.ImmutableMap;
import com.microsoft.azure.keyvault.cryptography.EcKey;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256k;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es512;
+import com.microsoft.azure.keyvault.cryptography.SignatureEncoding;
import com.microsoft.azure.keyvault.cryptography.test.resources.PemFile;
import com.microsoft.azure.keyvault.webkey.JsonWebKey;
import com.microsoft.azure.keyvault.webkey.JsonWebKeyCurveName;
@@ -214,15 +219,15 @@ private KeyPair getKeyFromFile(String privateKeyPath, String publicKeyPath) thro
return keyPair;
}
- private void testFromFile(String keyType, MessageDigest digest) throws Exception {
+ private void testFromFile(String keyType, MessageDigest digest, String algorithm) throws Exception {
String privateKeyPath = "src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "keynew.pem";
String publicKeyPath = "src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "keypubnew.pem";
EcKey newKey = new EcKey("akey", getKeyFromFile(privateKeyPath, publicKeyPath));
Path signatureLocation = Paths.get("src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "sig.der");
- byte[] signature = Files.readAllBytes(signatureLocation);
-
+ byte[] signature = SignatureEncoding.fromAsn1Der(Files.readAllBytes(signatureLocation), algorithm);
+
doVerify(newKey, digest, signature);
}
@@ -238,22 +243,22 @@ public void testCreateSECP256K1Key() throws Exception {
@Test
public void testFromP384File() throws Exception {
- testFromFile("p384", DIGEST_384);
+ testFromFile("p384", DIGEST_384, Es384.ALGORITHM_NAME);
}
@Test
public void testFromP521File() throws Exception {
- testFromFile("p521", DIGEST_512);
+ testFromFile("p521", DIGEST_512, Es512.ALGORITHM_NAME);
}
@Test
public void testFromP256File() throws Exception {
- testFromFile("p256", DIGEST_256);
+ testFromFile("p256", DIGEST_256, Es256.ALGORITHM_NAME);
}
@Test
public void testFromSEC256File() throws Exception{
- testFromFile("secp256", DIGEST_256);
+ testFromFile("secp256", DIGEST_256, Es256k.ALGORITHM_NAME);
}
@Test
diff --git a/keyvault/data-plane/azure-keyvault-extensions/pom.xml b/keyvault/data-plane/azure-keyvault-extensions/pom.xml
index 6c3af7a2693f..d71685206ea2 100644
--- a/keyvault/data-plane/azure-keyvault-extensions/pom.xml
+++ b/keyvault/data-plane/azure-keyvault-extensions/pom.xml
@@ -8,12 +8,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
azure-keyvault-extensions
- 1.1.2
+ 1.2.0
jar
Microsoft Azure SDK for Key Vault Extensions
diff --git a/keyvault/data-plane/azure-keyvault-test/pom.xml b/keyvault/data-plane/azure-keyvault-test/pom.xml
new file mode 100644
index 000000000000..92e8224b170d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-test/pom.xml
@@ -0,0 +1,81 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.2.0
+ ../pom.xml
+
+ azure-keyvault-test
+ azure-keyvault-test
+ http://maven.apache.org
+
+ UTF-8
+ playback
+
+
+
+ junit
+ junit
+ test
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+ test
+
+
+ com.microsoft.azure
+ azure-keyvault
+ test
+
+
+ com.microsoft.azure
+ azure-keyvault-cryptography
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-storage
+ 1.3.0
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-graph-rbac
+ 1.3.0
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-keyvault
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ 1.3.1-SNAPSHOT
+ test-jar
+ test
+
+
+ com.microsoft.azure
+ adal4j
+ test
+
+
+ com.microsoft.azure
+ azure-storage
+ 4.4.0
+ test
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java b/keyvault/data-plane/azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java
new file mode 100644
index 000000000000..92a006022bd2
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java
@@ -0,0 +1,334 @@
+package com.microsoft.azure.keyvault.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import com.microsoft.aad.adal4j.AuthenticationContext;
+import com.microsoft.aad.adal4j.AuthenticationResult;
+import com.microsoft.aad.adal4j.ClientCredential;
+import com.microsoft.azure.AzureResponseBuilder;
+import com.microsoft.azure.keyvault.KeyIdentifier;
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
+import com.microsoft.azure.keyvault.cryptography.EcKey;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.KeyOperationResult;
+import com.microsoft.azure.keyvault.models.KeyVerifyResult;
+import com.microsoft.azure.keyvault.requests.ImportKeyRequest;
+import com.microsoft.azure.keyvault.webkey.*;
+import com.microsoft.azure.management.resources.core.InterceptorManager;
+import com.microsoft.azure.management.resources.core.TestBase;
+import com.microsoft.azure.management.resources.fluentcore.utils.ResourceManagerThrottlingInterceptor;
+import com.microsoft.azure.serializer.AzureJacksonAdapter;
+import com.microsoft.rest.LogLevel;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.credentials.ServiceClientCredentials;
+import com.microsoft.rest.interceptors.LoggingInterceptor;
+public class EcKeyIntegrationTests {
+
+ private static TestBase.TestMode testMode = null;
+
+ protected InterceptorManager interceptorManager = null;
+
+ protected final static String ZERO_SUBSCRIPTION = "00000000-0000-0000-0000-000000000000";
+ protected final static String ZERO_TENANT = "00000000-0000-0000-0000-000000000000";
+ private static final String PLAYBACK_URI_BASE = "http://localhost:";
+ private static final String PLAYBACK_VAULT = "https://test-vault.vault.azure.net";
+
+ protected static String playbackUri = null;
+
+ static KeyVaultClient keyVaultClient;
+
+ static String VAULT_URI;
+
+
+ @Rule
+ public TestName testName = new TestName();
+
+
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ initTestMode();
+ initPlaybackUri();
+ }
+
+ @Before
+ public void beforeMethod() throws Exception {
+
+ RestClient restClient;
+ ServiceClientCredentials credentials = createTestCredentials();
+ interceptorManager = InterceptorManager.create(testName.getMethodName(), testMode);
+
+ if (isRecordMode()) {
+ VAULT_URI = System.getenv("VAULT_URI");
+ restClient = new RestClient.Builder().withBaseUrl("https://{vaultBaseUrl}")
+ .withSerializerAdapter(new AzureJacksonAdapter())
+ .withResponseBuilderFactory(new AzureResponseBuilder.Factory()).withCredentials(credentials)
+ .withLogLevel(LogLevel.NONE)
+ .withNetworkInterceptor(new LoggingInterceptor(LogLevel.BODY_AND_HEADERS))
+ .withNetworkInterceptor(interceptorManager.initInterceptor())
+ .withInterceptor(new ResourceManagerThrottlingInterceptor()).build();
+
+ interceptorManager.addTextReplacementRule("https://management.azure.com/", playbackUri + "/");
+ interceptorManager.addTextReplacementRule("https://graph.windows.net/", playbackUri + "/");
+ interceptorManager.addTextReplacementRule(VAULT_URI, PLAYBACK_VAULT);
+ keyVaultClient = new KeyVaultClient(restClient);
+ } else { // is Playback Mode
+ VAULT_URI = PLAYBACK_VAULT;
+ restClient = new RestClient.Builder().withBaseUrl(playbackUri + "/")
+ .withSerializerAdapter(new AzureJacksonAdapter())
+ .withResponseBuilderFactory(new AzureResponseBuilder.Factory()).withCredentials(credentials)
+ .withLogLevel(LogLevel.NONE)
+ .withNetworkInterceptor(new LoggingInterceptor(LogLevel.BODY_AND_HEADERS))
+ .withNetworkInterceptor(interceptorManager.initInterceptor())
+ .withInterceptor(new ResourceManagerThrottlingInterceptor()).build();
+ keyVaultClient = new KeyVaultClient(restClient);
+ }
+ }
+
+ @Test
+ public void testSignVerifyIntegrationES256() throws Exception {
+ validateSignVerifyInterop(importTestKey("itwkk-p256", P256TestKey()), JsonWebKeySignatureAlgorithm.ES256, "SHA-256");
+ }
+
+ @Test
+ public void testSignVerifyIntegrationES256K() throws Exception {
+ validateSignVerifyInterop(importTestKey("itwkk-p256k", P256KTestKey()), JsonWebKeySignatureAlgorithm.ES256K, "SHA-256");
+ }
+
+ @Test
+ public void testSignVerifyIntegrationES384() throws Exception {
+ validateSignVerifyInterop(importTestKey("itwkk-p384", P384TestKey()), JsonWebKeySignatureAlgorithm.ES384, "SHA-384");
+ }
+
+ @Test
+ public void testSignVerifyIntegrationES521() throws Exception {
+ validateSignVerifyInterop(importTestKey("itwkk-p521", P521TestKey()), JsonWebKeySignatureAlgorithm.ES512, "SHA-512");
+ }
+
+ private void validateSignVerifyInterop(JsonWebKey jwk, JsonWebKeySignatureAlgorithm algorithm, String digestAlg)
+ throws Exception {
+
+ EcKey key = EcKey.fromJsonWebKey(jwk, true);
+
+ KeyIdentifier keyId = new KeyIdentifier(jwk.kid());
+
+ // Test variables
+ byte[] plainText = new byte[100];
+ new Random(0x1234567L).nextBytes(plainText);
+ MessageDigest md = MessageDigest.getInstance(digestAlg);
+ md.update(plainText);
+ byte[] digest = md.digest();
+
+ // sign with both the client and the service
+ byte[] clientSig = key.signAsync(digest, algorithm.toString()).get().getLeft();
+ byte[] serverSig = keyVaultClient.sign(jwk.kid(), algorithm, digest).result();
+
+ // verify client signature with service and vice versa
+ Assert.assertTrue(keyVaultClient.verify(jwk.kid(), algorithm, digest, clientSig).value());
+ Assert.assertTrue(key.verifyAsync(digest, serverSig, algorithm.toString()).get());
+
+ key.close();
+ }
+
+ // crv P_256
+ // x 11232949079473245496693243696083285102762129989847161609854555188949850883563
+ // y 1879583613806065892642092774705384015240844626261169536236224087556053896803
+ // d 110376418358044062637363537183067346723507769076789115121629366563620220951085
+ private static JsonWebKey P256TestKey()
+ {
+ return new JsonWebKey()
+ .withKty(JsonWebKeyType.EC)
+ .withKeyOps(Arrays.asList(JsonWebKeyOperation.SIGN, JsonWebKeyOperation.VERIFY))
+ .withCrv(JsonWebKeyCurveName.P_256)
+ .withX(new BigInteger("11232949079473245496693243696083285102762129989847161609854555188949850883563").toByteArray())
+ .withY(new BigInteger("1879583613806065892642092774705384015240844626261169536236224087556053896803").toByteArray())
+ .withD(new BigInteger("110376418358044062637363537183067346723507769076789115121629366563620220951085").toByteArray());
+ }
+
+
+ // crv P_256K
+ // x 112542251246878300879834909875895196605604676102246979012590954738722135052808
+ // y 6774601013471644037178985795211162469224640637200491504041212042624768103421
+ // d 5788737892080795185076661111780678315827024120706807264074833863296072596641
+ private static JsonWebKey P256KTestKey()
+ {
+ return new JsonWebKey()
+ .withKty(JsonWebKeyType.EC)
+ .withKeyOps(Arrays.asList(JsonWebKeyOperation.SIGN, JsonWebKeyOperation.VERIFY))
+ .withCrv(JsonWebKeyCurveName.P_256K)
+ .withX(new BigInteger("112542251246878300879834909875895196605604676102246979012590954738722135052808").toByteArray())
+ .withY(new BigInteger("6774601013471644037178985795211162469224640637200491504041212042624768103421").toByteArray())
+ .withD(new BigInteger("5788737892080795185076661111780678315827024120706807264074833863296072596641").toByteArray());
+ }
+
+ // crv P_384
+ // x 25940251081638606466066580153999823282664621938556856505612612711663486152226861175055792115101185005519603532468591
+ // y 38849021239011943917620782277253508239698260816711858953045039688987325246933521190178660888358757011735327467604293
+ // d 32295109630567236352165497564914579106522760535338683398753720328854294758072198979189259927479998588892483377447907
+ private static JsonWebKey P384TestKey()
+ {
+ return new JsonWebKey()
+ .withKty(JsonWebKeyType.EC)
+ .withKeyOps(Arrays.asList(JsonWebKeyOperation.SIGN, JsonWebKeyOperation.VERIFY))
+ .withCrv(JsonWebKeyCurveName.P_384)
+ .withX(new BigInteger("25940251081638606466066580153999823282664621938556856505612612711663486152226861175055792115101185005519603532468591").toByteArray())
+ .withY(new BigInteger("38849021239011943917620782277253508239698260816711858953045039688987325246933521190178660888358757011735327467604293").toByteArray())
+ .withD(new BigInteger("32295109630567236352165497564914579106522760535338683398753720328854294758072198979189259927479998588892483377447907").toByteArray());
+ }
+
+ // crv P_521
+ // x 6855414495738791694053590132729898471597826721317714885490415738464754554924249115378421758975070989210614663357146557161470466328735789754640064414018012235
+ // y 3677272094599002495753508473603911533283562539125734660410262665439216117639982407670262587277222630266240230828668340712916997947964051679058455330395658230
+ // d 1119526436113918255892609748222452225184162390267181240143092765692579316239102968513115940220551308699050504250027618944913182129917648549423125636042752861
+ private static JsonWebKey P521TestKey()
+ {
+ return new JsonWebKey()
+ .withKty(JsonWebKeyType.EC)
+ .withKeyOps(Arrays.asList(JsonWebKeyOperation.SIGN, JsonWebKeyOperation.VERIFY))
+ .withCrv(JsonWebKeyCurveName.P_521)
+ .withX(new BigInteger("6855414495738791694053590132729898471597826721317714885490415738464754554924249115378421758975070989210614663357146557161470466328735789754640064414018012235").toByteArray())
+ .withY(new BigInteger("3677272094599002495753508473603911533283562539125734660410262665439216117639982407670262587277222630266240230828668340712916997947964051679058455330395658230").toByteArray())
+ .withD(new BigInteger("1119526436113918255892609748222452225184162390267181240143092765692579316239102968513115940220551308699050504250027618944913182129917648549423125636042752861").toByteArray());
+ }
+
+ private static JsonWebKey importTestKey(String keyName, JsonWebKey jwk) throws Exception {
+
+ KeyBundle keyBundle = keyVaultClient.importKey(VAULT_URI, keyName, jwk);
+
+ return jwk.withKid(keyBundle.key().kid());
+ }
+
+ private static AuthenticationResult getAccessToken(String authorization, String resource) throws Exception {
+
+ String clientId = System.getenv("arm.clientid");
+
+ if (clientId == null) {
+ throw new Exception("Please inform arm.clientid in the environment settings.");
+ }
+
+ String clientKey = System.getenv("arm.clientkey");
+ String username = System.getenv("arm.username");
+ String password = System.getenv("arm.password");
+
+ AuthenticationResult result = null;
+ ExecutorService service = null;
+ try {
+ service = Executors.newFixedThreadPool(1);
+ AuthenticationContext context = new AuthenticationContext(authorization, false, service);
+
+ Future future = null;
+
+ if (clientKey != null && password == null) {
+ ClientCredential credentials = new ClientCredential(clientId, clientKey);
+ future = context.acquireToken(resource, credentials, null);
+ }
+
+ if (password != null && clientKey == null) {
+ future = context.acquireToken(resource, clientId, username, password, null);
+ }
+
+ if (future == null) {
+ throw new Exception(
+ "Missing or ambiguous credentials - please inform exactly one of arm.clientkey or arm.password in the environment settings.");
+ }
+
+ result = future.get();
+ } finally {
+ service.shutdown();
+ }
+
+ if (result == null) {
+ throw new RuntimeException("authentication result was null");
+ }
+ return result;
+ }
+
+ private static ServiceClientCredentials createTestCredentials() throws Exception {
+ return new KeyVaultCredentials() {
+
+ @Override
+ public String doAuthenticate(String authorization, String resource, String scope) {
+ try {
+ if (isRecordMode()) {
+ AuthenticationResult authResult = getAccessToken(authorization, resource);
+ return authResult.getAccessToken();
+ } else {
+ return "";
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ };
+ }
+
+ @After
+ public void afterMethod() throws IOException {
+ interceptorManager.finalizeInterceptor();
+ }
+
+ private static void initPlaybackUri() throws IOException {
+ if (isPlaybackMode()) {
+ // 11080 and 11081 needs to be in sync with values in jetty.xml file
+ playbackUri = PLAYBACK_URI_BASE + "11080";
+ } else {
+ playbackUri = PLAYBACK_URI_BASE + "1234";
+ }
+ }
+
+ public static boolean isPlaybackMode() {
+ if (testMode == null)
+ try {
+ initTestMode();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Can't init test mode.");
+ }
+ return testMode == TestBase.TestMode.PLAYBACK;
+ }
+
+ public static boolean isRecordMode() {
+ return !isPlaybackMode();
+ }
+
+ private static void initTestMode() throws IOException {
+ String azureTestMode = System.getenv("AZURE_TEST_MODE");
+ if (azureTestMode != null) {
+ if (azureTestMode.equalsIgnoreCase("Record")) {
+ testMode = TestBase.TestMode.RECORD;
+ } else if (azureTestMode.equalsIgnoreCase("Playback")) {
+ testMode = TestBase.TestMode.PLAYBACK;
+ } else {
+ throw new IOException("Unknown AZURE_TEST_MODE: " + azureTestMode);
+ }
+ } else {
+ // System.out.print("Environment variable 'AZURE_TEST_MODE' has not been set
+ // yet. Using 'Playback' mode.");
+ testMode = TestBase.TestMode.PLAYBACK;
+ }
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/pom.xml b/keyvault/data-plane/azure-keyvault-webkey/pom.xml
index 19c30eeed8a0..d5d6477ab41c 100644
--- a/keyvault/data-plane/azure-keyvault-webkey/pom.xml
+++ b/keyvault/data-plane/azure-keyvault-webkey/pom.xml
@@ -6,12 +6,12 @@
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
azure-keyvault-webkey
- 1.1.2
+ 1.2.0
jar
Microsoft Azure SDK for Key Vault WebKey
diff --git a/keyvault/data-plane/azure-keyvault/pom.xml b/keyvault/data-plane/azure-keyvault/pom.xml
index 5d6a418f514d..05a6b2c736d4 100644
--- a/keyvault/data-plane/azure-keyvault/pom.xml
+++ b/keyvault/data-plane/azure-keyvault/pom.xml
@@ -6,12 +6,12 @@ the MIT License. See License.txt in the project root for license information. --
com.microsoft.azure
azure-keyvault-parent
- 1.1.2
+ 1.2.0
../pom.xml
azure-keyvault
- 1.1.2
+ 1.2.0
jar
Microsoft Azure SDK for Key Vault
@@ -193,7 +193,7 @@ the MIT License. See License.txt in the project root for license information. --
com.microsoft.azure
azure-client-authentication
- [1.1.0,2.0.0)
+ 1.6.3
test
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java
index aeb7fa06f4b8..2402f9d99b29 100644
--- a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java
@@ -11,9 +11,13 @@
import java.util.Map;
import java.util.Arrays;
import java.util.List;
+import java.util.UUID;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
import com.microsoft.rest.credentials.ServiceClientCredentials;
import com.microsoft.azure.keyvault.messagesecurity.HttpMessageSecurity;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
@@ -34,9 +38,13 @@ public abstract class KeyVaultCredentials implements ServiceClientCredentials {
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String BEARER_TOKEP_REFIX = "Bearer ";
+ private static final String CLIENT_ENCRYPTION_KEY_TYPE = "RSA";
+ private static final int CLIENT_ENCRYPTION_KEY_SIZE = 2048;
private List supportedMethods = Arrays.asList("sign", "verify", "encrypt", "decrypt", "wrapkey",
"unwrapkey");
+ private JsonWebKey clientEncryptionKey = null;
+
private final ChallengeCache cache = new ChallengeCache();
@Override
@@ -96,6 +104,22 @@ private Pair buildAuthenticatedRequest(Request ori
Map challengeMap) throws IOException {
Boolean supportsPop = supportsMessageProtection(originalRequest.url().toString(), challengeMap);
+
+ // if the service supports pop and a clientEncryptionKey has not been generated yet, generate
+ // the key that will be used for encryption on this and all subsequent protected requests
+ if (supportsPop && this.clientEncryptionKey == null) {
+ try {
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance(CLIENT_ENCRYPTION_KEY_TYPE);
+
+ generator.initialize(CLIENT_ENCRYPTION_KEY_SIZE);
+
+ this.clientEncryptionKey = JsonWebKey.fromRSA(generator.generateKeyPair()).withKid(UUID.randomUUID().toString());
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
AuthenticationResult authResult = getAuthenticationCredentials(supportsPop, challengeMap);
if (authResult == null) {
@@ -105,7 +129,8 @@ private Pair buildAuthenticatedRequest(Request ori
HttpMessageSecurity httpMessageSecurity = new HttpMessageSecurity(authResult.getAuthToken(),
supportsPop ? authResult.getPopKey() : "",
supportsPop ? challengeMap.get("x-ms-message-encryption-key") : "",
- supportsPop ? challengeMap.get("x-ms-message-signing-key") : "");
+ supportsPop ? challengeMap.get("x-ms-message-signing-key") : "",
+ this.clientEncryptionKey);
Request request = httpMessageSecurity.protectRequest(originalRequest);
return Pair.of(request, httpMessageSecurity);
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java
index ae55d1ea721a..938ed984559a 100644
--- a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java
@@ -62,7 +62,34 @@ public class HttpMessageSecurity {
*/
public HttpMessageSecurity(String clientSecurityToken, String clientSignatureKeyString,
String serverEncryptionKeyString, String serverSignatureKeyString) throws IOException {
+
+ this(clientSecurityToken, clientSignatureKeyString, serverEncryptionKeyString, serverSignatureKeyString, MessageSecurityHelper.generateJsonWebKey());
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param clientSecurityToken
+ * pop or bearer authentication token.
+ * @param clientSignatureKeyString
+ * string with client signing key (public + private parts) or null if
+ * not supported
+ * @param serverEncryptionKeyString
+ * string with server encryption key (public only) or null if not
+ * supported
+ * @param serverSignatureKeyString
+ * string with server signing key (public only) or null if not
+ * supported
+ * @param clientEncryptionKey
+ * client encryption key (public + private parts) or null if
+ * not supported
+ * @throws IOException
+ * throws IOException
+ */
+ public HttpMessageSecurity(String clientSecurityToken, String clientSignatureKeyString,
+ String serverEncryptionKeyString, String serverSignatureKeyString, JsonWebKey clientEncryptionKey) throws IOException {
+
this.clientSecurityToken = clientSecurityToken;
if (clientSignatureKeyString != null && !clientSignatureKeyString.equals("")) {
@@ -75,7 +102,7 @@ public HttpMessageSecurity(String clientSecurityToken, String clientSignatureKey
this.serverEncryptionKey = MessageSecurityHelper.jsonWebKeyFromString(serverEncryptionKeyString);
}
- this.clientEncryptionKey = MessageSecurityHelper.generateJsonWebKey();
+ this.clientEncryptionKey = clientEncryptionKey;
}
/**
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java
index 7ded26891a4d..a94f8b5db86d 100644
--- a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java
@@ -104,7 +104,7 @@ public static JsonWebKey generateJsonWebKey() {
return result;
} catch (NoSuchAlgorithmException e) {
// Unexpected. Should never be thrown.
- return null;
+ throw new RuntimeException(e);
}
}
diff --git a/keyvault/data-plane/pom.xml b/keyvault/data-plane/pom.xml
index be8ddf0150ad..1dd1cd0efc2c 100644
--- a/keyvault/data-plane/pom.xml
+++ b/keyvault/data-plane/pom.xml
@@ -11,7 +11,7 @@
1.0-SNAPSHOT
../../pom.client.xml
- 1.1.2
+ 1.2.0
azure-keyvault-parent
pom
@@ -95,27 +95,27 @@
com.microsoft.azure
azure-keyvault-webkey
- 1.1.2
+ 1.2.0
com.microsoft.azure
azure-keyvault-cryptography
- 1.1.2
+ 1.2.0
com.microsoft.azure
azure-keyvault-core
- 1.1.2
+ 1.2.0
com.microsoft.azure
azure-keyvault
- 1.1.2
+ 1.2.0
com.microsoft.azure
azure-keyvault-extensions
- 1.1.2
+ 1.2.0