mirror of https://github.com/apache/jclouds.git
Fixed decoding of some PKCS1 encoded public keys
This commit is contained in:
parent
c267108cbb
commit
d36ca103f3
|
@ -46,12 +46,14 @@ package org.jclouds.crypto.pem;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
|
||||||
import net.oauth.signature.pem.PKCS1EncodedKeySpec;
|
import org.bouncycastle.asn1.ASN1Object;
|
||||||
|
import org.bouncycastle.asn1.ASN1Sequence;
|
||||||
|
import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;
|
||||||
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PKCS#1 encoded public key spec.
|
* PKCS#1 encoded public key spec.
|
||||||
*
|
*
|
||||||
*
|
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public class PKCS1EncodedPublicKeySpec {
|
public class PKCS1EncodedPublicKeySpec {
|
||||||
|
@ -65,7 +67,7 @@ public class PKCS1EncodedPublicKeySpec {
|
||||||
* DER encoded octet stream
|
* DER encoded octet stream
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public PKCS1EncodedPublicKeySpec(byte[] keyBytes) throws IOException {
|
public PKCS1EncodedPublicKeySpec(final byte[] keyBytes) throws IOException {
|
||||||
decode(keyBytes);
|
decode(keyBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +81,31 @@ public class PKCS1EncodedPublicKeySpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the modulus and public exponent by reusing {@link PKCS1EncodedKeySpec}
|
* Decode PKCS#1 encoded private key into RSAPrivateCrtKeySpec.
|
||||||
|
* <p>
|
||||||
|
* Keys here can be in two different formats. They can have the algorithm
|
||||||
|
* encoded, or they can have only the modulus and the public exponent.
|
||||||
|
* <p>
|
||||||
|
* The latter is not a valid PEM encoded file, but it is a valid DER encoded
|
||||||
|
* RSA key, so this method should also support it.
|
||||||
|
*
|
||||||
|
* @param keyBytes
|
||||||
|
* Encoded PKCS#1 rsa key.
|
||||||
*/
|
*/
|
||||||
private void decode(byte[] keyBytes) throws IOException {
|
private void decode(final byte[] keyBytes) throws IOException {
|
||||||
PKCS1EncodedKeySpec privateSpec = new PKCS1EncodedKeySpec(keyBytes);
|
RSAPublicKeyStructure pks = null;
|
||||||
|
ASN1Sequence seq = (ASN1Sequence) ASN1Object.fromByteArray(keyBytes);
|
||||||
keySpec = new RSAPublicKeySpec(privateSpec.getKeySpec().getModulus(), privateSpec.getKeySpec()
|
try {
|
||||||
.getPublicExponent());
|
// Try to parse the public key normally. If the algorithm is not
|
||||||
|
// present in the encoded key, an IllegalArgumentException will be
|
||||||
|
// raised.
|
||||||
|
SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(seq);
|
||||||
|
pks = new RSAPublicKeyStructure((ASN1Sequence) info.getPublicKey());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// If the algorithm is not found in the encoded key, try to extract
|
||||||
|
// just the modulus and the public exponent to build the public key.
|
||||||
|
pks = new RSAPublicKeyStructure(seq);
|
||||||
|
}
|
||||||
|
keySpec = new RSAPublicKeySpec(pks.getModulus(), pks.getPublicExponent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
package org.jclouds.crypto;
|
package org.jclouds.crypto;
|
||||||
|
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
|
@ -27,6 +29,8 @@ import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.interfaces.RSAPrivateCrtKey;
|
import java.security.interfaces.RSAPrivateCrtKey;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.security.spec.RSAPublicKeySpec;
|
||||||
|
|
||||||
import org.jclouds.io.Payloads;
|
import org.jclouds.io.Payloads;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
@ -42,6 +46,10 @@ public class PemsTest {
|
||||||
|
|
||||||
public static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyb2ZJJqGm0KKR+8nfQJN\nsSd+F9tXNMV7CfOcW6jsqs8EZgiVR09hD1IYOj4YqM0qJONlgyg4xRWewdSG7QTP\nj1lJpVAida9sXy2+kzyagZA1Am0OZcbqb5hoeIDgcX+eDa79s0u0DomjcfO9EKhv\nHLBz+zM+3QqPRkPV8nYTbfs+HjVzzOU6D1B0XR3+IPZZl2AnWs2d0qhnStHcDUvn\nRVQ0P482YwN9VgceOZtpPz0DCKEJ5Tx5STub8k0/zt/VAMHQafLSuQMLd2s4ZLuO\nZptN//uAsTmxireqd37z+8ZTdBbJ8LEpJ+iCXuSfm5aUh7iw6oxvToY2AL53+jK2\nUQIDAQAB\n-----END PUBLIC KEY-----\n";
|
public static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyb2ZJJqGm0KKR+8nfQJN\nsSd+F9tXNMV7CfOcW6jsqs8EZgiVR09hD1IYOj4YqM0qJONlgyg4xRWewdSG7QTP\nj1lJpVAida9sXy2+kzyagZA1Am0OZcbqb5hoeIDgcX+eDa79s0u0DomjcfO9EKhv\nHLBz+zM+3QqPRkPV8nYTbfs+HjVzzOU6D1B0XR3+IPZZl2AnWs2d0qhnStHcDUvn\nRVQ0P482YwN9VgceOZtpPz0DCKEJ5Tx5STub8k0/zt/VAMHQafLSuQMLd2s4ZLuO\nZptN//uAsTmxireqd37z+8ZTdBbJ8LEpJ+iCXuSfm5aUh7iw6oxvToY2AL53+jK2\nUQIDAQAB\n-----END PUBLIC KEY-----\n";
|
||||||
|
|
||||||
|
private static final String PUBLIC_KEY_PKCS1 = "-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp0ytgXbPzqJwOOixn7bT\na6VAiNvVIOn+yDPoWbyEfc0li93BHIwv01KW/mn55IXnSbMw86rdxisvwPHFfb7U\nRuKuTzME6yrphBiancmNjushZZeBWb8jqJhnFIKbaaOqew0LZSyG9ycYODB/HDK/\npWTV4Bd1OtLHBNFrnIf+r3HOjJsa4rmKWXgSQIQO7be/iRHysApV9tfVH8lo1ETn\nA08JTrQwDgo9St9YNbydb5V0CiLiQsOaIbY09buUK9lXthh/rrRVbGbSwQM6OYdX\nIEZTN2BFvQ0p5pH8AiTwFqb0ICO46a0SjfGcXNjC/QfHljAPY3T5xyIOODM8afHC\nnwIDAQAB\n-----END RSA PUBLIC KEY-----\n";
|
||||||
|
|
||||||
|
private static final String PUBLIC_KEY_PKCS1_RAW = "-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAp0ytgXbPzqJwOOixn7bTa6VAiNvVIOn+yDPoWbyEfc0li93BHIwv\n01KW/mn55IXnSbMw86rdxisvwPHFfb7URuKuTzME6yrphBiancmNjushZZeBWb8j\nqJhnFIKbaaOqew0LZSyG9ycYODB/HDK/pWTV4Bd1OtLHBNFrnIf+r3HOjJsa4rmK\nWXgSQIQO7be/iRHysApV9tfVH8lo1ETnA08JTrQwDgo9St9YNbydb5V0CiLiQsOa\nIbY09buUK9lXthh/rrRVbGbSwQM6OYdXIEZTN2BFvQ0p5pH8AiTwFqb0ICO46a0S\njfGcXNjC/QfHljAPY3T5xyIOODM8afHCnwIDAQAB\n-----END RSA PUBLIC KEY-----\n";
|
||||||
|
|
||||||
private static final String CERTIFICATE = "-----BEGIN CERTIFICATE-----\nMIIClzCCAgCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEwMDczMDIwNDEzMFoXDTIwMDcyNzIwNDEzMFowADCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAMm9mSSahptCikfvJ30CTbEnfhfbVzTFewnznFuo\n7KrPBGYIlUdPYQ9SGDo+GKjNKiTjZYMoOMUVnsHUhu0Ez49ZSaVQInWvbF8tvpM8\nmoGQNQJtDmXG6m+YaHiA4HF/ng2u/bNLtA6Jo3HzvRCobxywc/szPt0Kj0ZD1fJ2\nE237Ph41c8zlOg9QdF0d/iD2WZdgJ1rNndKoZ0rR3A1L50VUND+PNmMDfVYHHjmb\naT89AwihCeU8eUk7m/JNP87f1QDB0Gny0rkDC3drOGS7jmabTf/7gLE5sYq3qnd+\n8/vGU3QWyfCxKSfogl7kn5uWlIe4sOqMb06GNgC+d/oytlECAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQBftzSZxstWw60GqRTDNN/F2GnrdtnKBoXzHww3r6jtGEylYq20\n5KfKpEx+sPX0gyZuYJiXC2CkEjImAluWKcdN9ZF6VD541sheAjbiaU7q7ZsztTxF\nWUH2tCvHeDXYKPKek3QzL7bYpUhLnCN/XxEv6ibeMDwtI7f5qpk2Aspzcw==\n-----END CERTIFICATE-----\n";
|
private static final String CERTIFICATE = "-----BEGIN CERTIFICATE-----\nMIIClzCCAgCgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMCVVMx\nEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNVBAoM\nDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2UxMjAw\nBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUuY29t\nMB4XDTEwMDczMDIwNDEzMFoXDTIwMDcyNzIwNDEzMFowADCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAMm9mSSahptCikfvJ30CTbEnfhfbVzTFewnznFuo\n7KrPBGYIlUdPYQ9SGDo+GKjNKiTjZYMoOMUVnsHUhu0Ez49ZSaVQInWvbF8tvpM8\nmoGQNQJtDmXG6m+YaHiA4HF/ng2u/bNLtA6Jo3HzvRCobxywc/szPt0Kj0ZD1fJ2\nE237Ph41c8zlOg9QdF0d/iD2WZdgJ1rNndKoZ0rR3A1L50VUND+PNmMDfVYHHjmb\naT89AwihCeU8eUk7m/JNP87f1QDB0Gny0rkDC3drOGS7jmabTf/7gLE5sYq3qnd+\n8/vGU3QWyfCxKSfogl7kn5uWlIe4sOqMb06GNgC+d/oytlECAwEAATANBgkqhkiG\n9w0BAQUFAAOBgQBftzSZxstWw60GqRTDNN/F2GnrdtnKBoXzHww3r6jtGEylYq20\n5KfKpEx+sPX0gyZuYJiXC2CkEjImAluWKcdN9ZF6VD541sheAjbiaU7q7ZsztTxF\nWUH2tCvHeDXYKPKek3QzL7bYpUhLnCN/XxEv6ibeMDwtI7f5qpk2Aspzcw==\n-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -67,7 +75,7 @@ public class PemsTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPrivateKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
public void testPrivateKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
||||||
RSAPrivateCrtKey key = (RSAPrivateCrtKey) KeyFactory.getInstance("RSA").generatePrivate(
|
RSAPrivateCrtKey key = (RSAPrivateCrtKey) KeyFactory.getInstance("RSA").generatePrivate(
|
||||||
Pems.privateKeySpec(Payloads.newStringPayload(PRIVATE_KEY)));
|
Pems.privateKeySpec(Payloads.newStringPayload(PRIVATE_KEY)));
|
||||||
String encoded = Pems.pem(key);
|
String encoded = Pems.pem(key);
|
||||||
assertEquals(encoded, PRIVATE_KEY.replaceAll("\n", "\n").trim());
|
assertEquals(encoded, PRIVATE_KEY.replaceAll("\n", "\n").trim());
|
||||||
}
|
}
|
||||||
|
@ -75,14 +83,41 @@ public class PemsTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRSAPublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
public void testRSAPublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
||||||
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(
|
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(
|
||||||
Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY))));
|
Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY))));
|
||||||
assertEquals(encoded, PUBLIC_KEY.replaceAll("PUBLIC", "RSA PUBLIC").replaceAll("\n", "\n").trim());
|
assertEquals(encoded, PUBLIC_KEY.replaceAll("PUBLIC", "RSA PUBLIC").replaceAll("\n", "\n").trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRSAPKCS1PublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
||||||
|
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(
|
||||||
|
Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY_PKCS1))));
|
||||||
|
assertEquals(encoded, PUBLIC_KEY_PKCS1.replaceAll("\n", "\n").trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRSAPKCS1RawPublicKeySpecPem() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
|
||||||
|
KeySpec spec = Pems.publicKeySpec(Payloads.newStringPayload(PUBLIC_KEY_PKCS1_RAW));
|
||||||
|
String encoded = Pems.pem(KeyFactory.getInstance("RSA").generatePublic(spec));
|
||||||
|
KeySpec generatedSpec = Pems.publicKeySpec(encoded);
|
||||||
|
|
||||||
|
assertTrue(spec instanceof RSAPublicKeySpec);
|
||||||
|
assertTrue(generatedSpec instanceof RSAPublicKeySpec);
|
||||||
|
|
||||||
|
// The encoded is different because the generatePublic method adds the
|
||||||
|
// algorithm to the key.
|
||||||
|
assertNotEquals(encoded, PUBLIC_KEY_PKCS1_RAW.replaceAll("\n", "\n").trim());
|
||||||
|
// Verify that the modulus and public exponent of the encoded key are the
|
||||||
|
// same than the ones in the original key
|
||||||
|
assertEquals(RSAPublicKeySpec.class.cast(spec).getModulus(), RSAPublicKeySpec.class.cast(generatedSpec)
|
||||||
|
.getModulus());
|
||||||
|
assertEquals(RSAPublicKeySpec.class.cast(spec).getPublicExponent(), RSAPublicKeySpec.class.cast(generatedSpec)
|
||||||
|
.getPublicExponent());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testX509CertificatePem() throws IOException, CertificateException {
|
public void testX509CertificatePem() throws IOException, CertificateException {
|
||||||
String encoded = Pems.pem(Pems.x509Certificate(Payloads.newStringPayload(CERTIFICATE), CertificateFactory
|
String encoded = Pems.pem(Pems.x509Certificate(Payloads.newStringPayload(CERTIFICATE),
|
||||||
.getInstance("X.509")));
|
CertificateFactory.getInstance("X.509")));
|
||||||
assertEquals(encoded, CERTIFICATE.replaceAll("\n", "\n").trim());
|
assertEquals(encoded, CERTIFICATE.replaceAll("\n", "\n").trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue