addded shortcuts for Stringified certificates and keys

This commit is contained in:
Adrian Cole 2010-08-03 14:32:29 -04:00
parent 0f60364ba7
commit c2c15ce633
2 changed files with 188 additions and 43 deletions

View File

@ -0,0 +1,94 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package net.oauth.signature.pem;
import java.io.IOException;
import java.math.BigInteger;
import java.security.spec.RSAPublicKeySpec;
/**
* PKCS#1 encoded public key spec. In oauth package as they made all classes
* package visible.
*
*
* @author Adrian Cole
*/
public class PKCS1EncodedPublicKeySpec {
private RSAPublicKeySpec keySpec;
/**
* Create a PKCS#1 keyspec from DER encoded buffer
*
* @param keyBytes
* DER encoded octet stream
* @throws IOException
*/
public PKCS1EncodedPublicKeySpec(byte[] keyBytes) throws IOException {
decode(keyBytes);
}
/**
* Get the key spec that JCE understands.
*
* @return CRT keyspec defined by JCE
*/
public RSAPublicKeySpec getKeySpec() {
return keySpec;
}
/**
* Decode PKCS#1 encoded private key into RSAPublicKeySpec.
*
* <p/>
* The ASN.1 syntax for the private key with CRT is
*
* <pre>
* --
* -- Representation of RSA private key with information for the CRT algorithm.
* --
* RSAPrivateKey ::= SEQUENCE {
* version Version,
* modulus INTEGER, -- n
* publicExponent INTEGER, -- e
* }
* </pre>
*
* @param keyBytes
* PKCS#1 encoded key
* @throws IOException
*/
private void decode(byte[] keyBytes) throws IOException {
DerParser parser = new DerParser(keyBytes);
Asn1Object sequence = parser.read();
if (sequence.getType() != DerParser.SEQUENCE)
throw new IOException("Invalid DER: not a sequence"); //$NON-NLS-1$
// Parse inside the sequence
parser = sequence.getParser();
BigInteger modulus = parser.read().getInteger();
BigInteger publicExp = parser.read().getInteger();
keySpec = new RSAPublicKeySpec(modulus, publicExp);
}
}

View File

@ -40,8 +40,10 @@ import javax.annotation.Nullable;
import net.oauth.signature.pem.PEMReader; import net.oauth.signature.pem.PEMReader;
import net.oauth.signature.pem.PKCS1EncodedKeySpec; import net.oauth.signature.pem.PKCS1EncodedKeySpec;
import net.oauth.signature.pem.PKCS1EncodedPublicKeySpec;
import org.jclouds.crypto.Pems.PemProcessor.ResultParser; import org.jclouds.crypto.Pems.PemProcessor.ResultParser;
import org.jclouds.io.InputSuppliers;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -55,6 +57,11 @@ import com.google.common.io.InputSupplier;
*/ */
@Beta @Beta
public class Pems { public class Pems {
public static final String PRIVATE_PKCS1_MARKER = "-----BEGIN RSA PRIVATE KEY-----";
public static final String PRIVATE_PKCS8_MARKER = "-----BEGIN PRIVATE KEY-----";
public static final String CERTIFICATE_X509_MARKER = "-----BEGIN CERTIFICATE-----";
public static final String PUBLIC_X509_MARKER = "-----BEGIN PUBLIC KEY-----";
public static final String PUBLIC_PKCS1_MARKER = "-----BEGIN RSA PUBLIC KEY-----";
public static class PemProcessor<T> implements com.google.common.io.ByteProcessor<T> { public static class PemProcessor<T> implements com.google.common.io.ByteProcessor<T> {
public interface ResultParser<T> { public interface ResultParser<T> {
@ -81,7 +88,7 @@ public class Pems {
return parsers.get(reader.getBeginMarker()).parseResult(bytes); return parsers.get(reader.getBeginMarker()).parseResult(bytes);
} else { } else {
throw new IOException(String.format("Invalid PEM file: no parsers for marker %s in %s", reader throw new IOException(String.format("Invalid PEM file: no parsers for marker %s in %s", reader
.getBeginMarker(), parsers.keySet())); .getBeginMarker(), parsers.keySet()));
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -90,7 +97,8 @@ public class Pems {
} }
/** /**
* Returns the object of generic type {@code T} that is pem encoded in the supplier. * Returns the object of generic type {@code T} that is pem encoded in the
* supplier.
* *
* @param supplier * @param supplier
* the input stream factory * the input stream factory
@ -98,12 +106,13 @@ public class Pems {
* header that begins the PEM block * header that begins the PEM block
* @param processor * @param processor
* how to parser the object from a byte array * how to parser the object from a byte array
* @return the object of generic type {@code T} which was PEM encoded in the stream * @return the object of generic type {@code T} which was PEM encoded in the
* stream
* @throws IOException * @throws IOException
* if an I/O error occurs * if an I/O error occurs
*/ */
public static <T> T fromPem(InputSupplier<? extends InputStream> supplier, PemProcessor<T> processor) public static <T> T fromPem(InputSupplier<? extends InputStream> supplier, PemProcessor<T> processor)
throws IOException { throws IOException {
try { try {
return com.google.common.io.ByteStreams.readBytes(supplier, processor); return com.google.common.io.ByteStreams.readBytes(supplier, processor);
} catch (RuntimeException e) { } catch (RuntimeException e) {
@ -126,45 +135,75 @@ public class Pems {
*/ */
public static KeySpec privateKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException { public static KeySpec privateKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException {
return fromPem(supplier, new PemProcessor<KeySpec>(ImmutableMap.<String, ResultParser<KeySpec>> of( return fromPem(supplier, new PemProcessor<KeySpec>(ImmutableMap.<String, ResultParser<KeySpec>> of(
PEMReader.PRIVATE_PKCS1_MARKER, new ResultParser<KeySpec>() { PRIVATE_PKCS1_MARKER, new ResultParser<KeySpec>() {
public KeySpec parseResult(byte[] bytes) throws IOException { public KeySpec parseResult(byte[] bytes) throws IOException {
return (new PKCS1EncodedKeySpec(bytes)).getKeySpec(); return (new PKCS1EncodedKeySpec(bytes)).getKeySpec();
} }
}, PEMReader.PRIVATE_PKCS8_MARKER, new ResultParser<KeySpec>() { }, PRIVATE_PKCS8_MARKER, new ResultParser<KeySpec>() {
public KeySpec parseResult(byte[] bytes) throws IOException { public KeySpec parseResult(byte[] bytes) throws IOException {
return new PKCS8EncodedKeySpec(bytes); return new PKCS8EncodedKeySpec(bytes);
} }
}))); })));
} }
/** /**
* Returns the {@link X509EncodedKeySpec} that is pem encoded in the supplier. * Executes {@link Pems#privateKeySpec(InputSupplier)} on the string which
* contains an encoded private key in PEM format.
*
* @param pem
* private key in pem encoded format.
* @see Pems#privateKeySpec(InputSupplier)
*/
public static KeySpec privateKeySpec(String pem) throws IOException {
return privateKeySpec(InputSuppliers.of(pem));
}
/**
* Returns the {@link KeySpec} that is pem encoded in the supplier.
* *
* @param supplier * @param supplier
* the input stream factory * the input stream factory
* *
* @return the {@link X509EncodedKeySpec} which was PEM encoded in the stream * @return the {@link KeySpec} which was PEM encoded in the stream
* @throws IOException * @throws IOException
* if an I/O error occurs * if an I/O error occurs
*/ */
public static X509EncodedKeySpec publicKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException { public static KeySpec publicKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException {
return fromPem(supplier, new PemProcessor<X509EncodedKeySpec>(ImmutableMap return fromPem(supplier, new PemProcessor<KeySpec>(ImmutableMap.<String, ResultParser<KeySpec>> of(
.<String, ResultParser<X509EncodedKeySpec>> of(PEMReader.PUBLIC_X509_MARKER, PUBLIC_PKCS1_MARKER, new ResultParser<KeySpec>() {
new ResultParser<X509EncodedKeySpec>() {
public X509EncodedKeySpec parseResult(byte[] bytes) throws IOException { public KeySpec parseResult(byte[] bytes) throws IOException {
return new X509EncodedKeySpec(bytes); return (new PKCS1EncodedPublicKeySpec(bytes)).getKeySpec();
} }
}))); }, PUBLIC_X509_MARKER, new ResultParser<KeySpec>() {
public X509EncodedKeySpec parseResult(byte[] bytes) throws IOException {
return new X509EncodedKeySpec(bytes);
}
})));
} }
/** /**
* Returns the {@link X509EncodedKeySpec} that is pem encoded in the supplier. * Executes {@link Pems#publicKeySpec(InputSupplier)} on the string which
* contains an encoded public key in PEM format.
*
* @param pem
* public key in pem encoded format.
* @see Pems#publicKeySpec(InputSupplier)
*/
public static KeySpec publicKeySpec(String pem) throws IOException {
return publicKeySpec(InputSuppliers.of(pem));
}
/**
* Returns the {@link X509EncodedKeySpec} that is pem encoded in the
* supplier.
* *
* @param supplier * @param supplier
* the input stream factory * the input stream factory
@ -177,24 +216,24 @@ public class Pems {
* @throws CertificateException * @throws CertificateException
*/ */
public static X509Certificate x509Certificate(InputSupplier<? extends InputStream> supplier, public static X509Certificate x509Certificate(InputSupplier<? extends InputStream> supplier,
@Nullable CertificateFactory certFactory) throws IOException, CertificateException { @Nullable CertificateFactory certFactory) throws IOException, CertificateException {
final CertificateFactory finalCertFactory = certFactory != null ? certFactory : CertificateFactory final CertificateFactory finalCertFactory = certFactory != null ? certFactory : CertificateFactory
.getInstance("X.509"); .getInstance("X.509");
try { try {
return fromPem(supplier, new PemProcessor<X509Certificate>(ImmutableMap return fromPem(supplier, new PemProcessor<X509Certificate>(ImmutableMap
.<String, ResultParser<X509Certificate>> of(PEMReader.CERTIFICATE_X509_MARKER, .<String, ResultParser<X509Certificate>> of(CERTIFICATE_X509_MARKER,
new ResultParser<X509Certificate>() { new ResultParser<X509Certificate>() {
public X509Certificate parseResult(byte[] bytes) throws IOException { public X509Certificate parseResult(byte[] bytes) throws IOException {
try { try {
return (X509Certificate) finalCertFactory return (X509Certificate) finalCertFactory.generateCertificate(new ByteArrayInputStream(
.generateCertificate(new ByteArrayInputStream(bytes)); bytes));
} catch (CertificateException e) { } catch (CertificateException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
}))); })));
} catch (RuntimeException e) { } catch (RuntimeException e) {
if (e.getCause() != null && e.getCause() instanceof CertificateException) { if (e.getCause() != null && e.getCause() instanceof CertificateException) {
throw (CertificateException) e.getCause(); throw (CertificateException) e.getCause();
@ -203,6 +242,18 @@ public class Pems {
} }
} }
/**
* Executes {@link Pems#x509Certificate(InputSupplier, CertificateFactory)}
* on the string which contains an X.509 certificate in PEM format.
*
* @param pem
* certificate in pem encoded format.
* @see Pems#x509Certificate(InputSupplier, CertificateFactory)
*/
public static X509Certificate x509Certificate(String pem) throws IOException, CertificateException {
return x509Certificate(InputSuppliers.of(pem), null);
}
/** /**
* encodes the {@link X509Certificate} to PEM format. * encodes the {@link X509Certificate} to PEM format.
* *
@ -214,8 +265,8 @@ public class Pems {
*/ */
public static String pem(X509Certificate cert) throws IOException, CertificateEncodingException { public static String pem(X509Certificate cert) throws IOException, CertificateEncodingException {
return new StringBuilder("-----BEGIN CERTIFICATE-----\n").append( return new StringBuilder("-----BEGIN CERTIFICATE-----\n").append(
CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(cert.getEncoded()))).append( CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(cert.getEncoded()))).append(
"\n-----END CERTIFICATE-----\n").toString(); "\n-----END CERTIFICATE-----\n").toString();
} }
/** /**
@ -229,8 +280,8 @@ public class Pems {
*/ */
public static String pem(PublicKey key) throws IOException { public static String pem(PublicKey key) throws IOException {
return new StringBuilder("-----BEGIN PUBLIC KEY-----\n").append( return new StringBuilder("-----BEGIN PUBLIC KEY-----\n").append(
CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(key.getEncoded()))).append( CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(key.getEncoded()))).append(
"\n-----END PUBLIC KEY-----\n").toString(); "\n-----END PUBLIC KEY-----\n").toString();
} }
/** /**
@ -244,8 +295,8 @@ public class Pems {
*/ */
public static String pem(PrivateKey key) throws IOException { public static String pem(PrivateKey key) throws IOException {
return new StringBuilder("-----BEGIN PRIVATE KEY-----\n").append( return new StringBuilder("-----BEGIN PRIVATE KEY-----\n").append(
CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(key.getEncoded()))).append( CryptoStreams.base64Encode(ByteStreams.newInputStreamSupplier(key.getEncoded()))).append(
"\n-----END PRIVATE KEY-----\n").toString(); "\n-----END PRIVATE KEY-----\n").toString();
} }
} }