EMMA Coverage Report (generated Wed Oct 26 13:47:17 EDT 2011)
[all classes][org.jclouds.crypto]

COVERAGE SUMMARY FOR SOURCE FILE [Pems.java]

nameclass, %method, %block, %line, %
Pems.java100% (7/7)81%  (22/27)73%  (261/357)61%  (38.7/63)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Pems$3100% (1/1)50%  (1/2)33%  (3/9)50%  (1/2)
parseResult (byte []): KeySpec 0%   (0/1)0%   (0/6)0%   (0/1)
Pems$3 (): void 100% (1/1)100% (3/3)100% (1/1)
     
class Pems$2100% (1/1)50%  (1/2)38%  (3/8)50%  (1/2)
parseResult (byte []): KeySpec 0%   (0/1)0%   (0/5)0%   (0/1)
Pems$2 (): void 100% (1/1)100% (3/3)100% (1/1)
     
class Pems$PemProcessor100% (1/1)100% (3/3)65%  (47/72)77%  (10/13)
getResult (): Object 100% (1/1)50%  (25/50)57%  (4/7)
Pems$PemProcessor (Map): void 100% (1/1)100% (14/14)100% (4/4)
processBytes (byte [], int, int): boolean 100% (1/1)100% (8/8)100% (2/2)
     
class Pems$5100% (1/1)100% (2/2)71%  (15/21)50%  (2/4)
parseResult (byte []): X509Certificate 100% (1/1)60%  (9/15)33%  (1/3)
Pems$5 (CertificateFactory): void 100% (1/1)100% (6/6)100% (1/1)
     
class Pems100% (1/1)79%  (11/14)77%  (176/230)54%  (20.7/38)
Pems (): void 0%   (0/1)0%   (0/3)0%   (0/2)
publicKeySpec (String): KeySpec 0%   (0/1)0%   (0/4)0%   (0/1)
x509Certificate (String): X509Certificate 0%   (0/1)0%   (0/5)0%   (0/1)
fromPem (InputSupplier, Pems$PemProcessor): Object 100% (1/1)22%  (4/18)20%  (1/5)
privateKeySpec (String): KeySpec 100% (1/1)40%  (4/10)25%  (1/4)
x509Certificate (InputSupplier, CertificateFactory): X509Certificate 100% (1/1)59%  (20/34)33%  (2/6)
pem (PrivateKey): String 100% (1/1)86%  (18/21)88%  (1.8/2)
getEncoded (RSAPrivateCrtKey): byte [] 100% (1/1)90%  (38/42)78%  (7/9)
pem (PublicKey): String 100% (1/1)92%  (11/12)96%  (1.9/2)
pem (X509Certificate): String 100% (1/1)100% (7/7)100% (2/2)
pem (byte [], String): String 100% (1/1)100% (5/5)100% (1/1)
pem (byte [], String, int): String 100% (1/1)100% (37/37)100% (1/1)
privateKeySpec (InputSupplier): KeySpec 100% (1/1)100% (16/16)100% (1/1)
publicKeySpec (InputSupplier): KeySpec 100% (1/1)100% (16/16)100% (1/1)
     
class Pems$1100% (1/1)100% (2/2)100% (9/9)100% (2/2)
Pems$1 (): void 100% (1/1)100% (3/3)100% (1/1)
parseResult (byte []): KeySpec 100% (1/1)100% (6/6)100% (1/1)
     
class Pems$4100% (1/1)100% (2/2)100% (8/8)100% (2/2)
Pems$4 (): void 100% (1/1)100% (3/3)100% (1/1)
parseResult (byte []): X509EncodedKeySpec 100% (1/1)100% (5/5)100% (1/1)

1/**
2 * Licensed to jclouds, Inc. (jclouds) under one or more
3 * contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  jclouds licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.jclouds.crypto;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22 
23import java.io.ByteArrayInputStream;
24import java.io.ByteArrayOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.security.PrivateKey;
28import java.security.PublicKey;
29import java.security.cert.CertificateEncodingException;
30import java.security.cert.CertificateException;
31import java.security.cert.CertificateFactory;
32import java.security.cert.X509Certificate;
33import java.security.interfaces.RSAPrivateCrtKey;
34import java.security.interfaces.RSAPublicKey;
35import java.security.spec.KeySpec;
36import java.security.spec.PKCS8EncodedKeySpec;
37import java.security.spec.RSAPrivateKeySpec;
38import java.security.spec.X509EncodedKeySpec;
39import java.util.Map;
40 
41import org.jclouds.javax.annotation.Nullable;
42 
43import net.oauth.signature.pem.PEMReader;
44import net.oauth.signature.pem.PKCS1EncodedKeySpec;
45import net.oauth.signature.pem.PKCS1EncodedPublicKeySpec;
46 
47import org.bouncycastle.asn1.ASN1OutputStream;
48import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
49import org.jclouds.crypto.Pems.PemProcessor.ResultParser;
50import org.jclouds.io.InputSuppliers;
51 
52import com.google.common.annotations.Beta;
53import com.google.common.base.Joiner;
54import com.google.common.base.Splitter;
55import com.google.common.base.Throwables;
56import com.google.common.collect.ImmutableMap;
57import com.google.common.io.InputSupplier;
58 
59/**
60 * Reads and writes PEM encoded Strings and Streams
61 * 
62 * @author Adrian Cole
63 */
64@Beta
65public class Pems {
66   public static final String PRIVATE_PKCS1_MARKER = "-----BEGIN RSA PRIVATE KEY-----";
67   public static final String PRIVATE_PKCS8_MARKER = "-----BEGIN PRIVATE KEY-----";
68   public static final String CERTIFICATE_X509_MARKER = "-----BEGIN CERTIFICATE-----";
69   public static final String PUBLIC_X509_MARKER = "-----BEGIN PUBLIC KEY-----";
70   public static final String PUBLIC_PKCS1_MARKER = "-----BEGIN RSA PUBLIC KEY-----";
71 
72   public static class PemProcessor<T> implements com.google.common.io.ByteProcessor<T> {
73      public interface ResultParser<T> {
74         T parseResult(byte[] bytes) throws IOException;
75      }
76 
77      private final ByteArrayOutputStream out = new ByteArrayOutputStream();
78      private final Map<String, ResultParser<T>> parsers;
79 
80      public PemProcessor(Map<String, ResultParser<T>> parsers) {
81         this.parsers = checkNotNull(parsers, "parsers");
82      }
83 
84      public boolean processBytes(byte[] buf, int off, int len) {
85         out.write(buf, off, len);
86         return true;
87      }
88 
89      public T getResult() {
90         try {
91            PEMReader reader = new PEMReader(out.toByteArray());
92            byte[] bytes = reader.getDerBytes();
93            if (parsers.containsKey(reader.getBeginMarker())) {
94               return parsers.get(reader.getBeginMarker()).parseResult(bytes);
95            } else {
96               throw new IOException(String.format("Invalid PEM file: no parsers for marker %s in %s",
97                     reader.getBeginMarker(), parsers.keySet()));
98            }
99         } catch (IOException e) {
100            throw new RuntimeException(e);
101         }
102      }
103   }
104 
105   /**
106    * Returns the object of generic type {@code T} that is pem encoded in the
107    * supplier.
108    * 
109    * @param supplier
110    *           the input stream factory
111    * @param marker
112    *           header that begins the PEM block
113    * @param processor
114    *           how to parser the object from a byte array
115    * @return the object of generic type {@code T} which was PEM encoded in the
116    *         stream
117    * @throws IOException
118    *            if an I/O error occurs
119    */
120   public static <T> T fromPem(InputSupplier<? extends InputStream> supplier, PemProcessor<T> processor)
121         throws IOException {
122      try {
123         return com.google.common.io.ByteStreams.readBytes(supplier, processor);
124      } catch (RuntimeException e) {
125         if (e.getCause() != null && e.getCause() instanceof IOException) {
126            throw (IOException) e.getCause();
127         }
128         throw e;
129      }
130   }
131 
132   /**
133    * Returns the {@link RSAPrivateKeySpec} that is pem encoded in the supplier.
134    * 
135    * @param supplier
136    *           the input stream factory
137    * 
138    * @return the {@link RSAPrivateKeySpec} which was PEM encoded in the stream
139    * @throws IOException
140    *            if an I/O error occurs
141    */
142   public static KeySpec privateKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException {
143      return fromPem(
144            supplier,
145            new PemProcessor<KeySpec>(ImmutableMap.<String, ResultParser<KeySpec>> of(PRIVATE_PKCS1_MARKER,
146                  new ResultParser<KeySpec>() {
147 
148                     public KeySpec parseResult(byte[] bytes) throws IOException {
149                        return (new PKCS1EncodedKeySpec(bytes)).getKeySpec();
150                     }
151 
152                  }, PRIVATE_PKCS8_MARKER, new ResultParser<KeySpec>() {
153 
154                     public KeySpec parseResult(byte[] bytes) throws IOException {
155                        return new PKCS8EncodedKeySpec(bytes);
156                     }
157 
158                  })));
159   }
160 
161   /**
162    * Executes {@link Pems#privateKeySpec(InputSupplier)} on the string which
163    * contains an encoded private key in PEM format.
164    * 
165    * @param pem
166    *           private key in pem encoded format.
167    * @see Pems#privateKeySpec(InputSupplier)
168    */
169   public static KeySpec privateKeySpec(String pem) {
170      try {
171         return privateKeySpec(InputSuppliers.of(pem));
172      } catch (IOException e) {
173         Throwables.propagate(e);
174         return null;
175      }
176   }
177 
178   /**
179    * Returns the {@link KeySpec} that is pem encoded in the supplier.
180    * 
181    * @param supplier
182    *           the input stream factory
183    * 
184    * @return the {@link KeySpec} which was PEM encoded in the stream
185    * @throws IOException
186    *            if an I/O error occurs
187    */
188   public static KeySpec publicKeySpec(InputSupplier<? extends InputStream> supplier) throws IOException {
189      return fromPem(
190            supplier,
191            new PemProcessor<KeySpec>(ImmutableMap.<String, ResultParser<KeySpec>> of(PUBLIC_PKCS1_MARKER,
192                  new ResultParser<KeySpec>() {
193 
194                     public KeySpec parseResult(byte[] bytes) throws IOException {
195                        return (new PKCS1EncodedPublicKeySpec(bytes)).getKeySpec();
196                     }
197 
198                  }, PUBLIC_X509_MARKER, new ResultParser<KeySpec>() {
199 
200                     public X509EncodedKeySpec parseResult(byte[] bytes) throws IOException {
201                        return new X509EncodedKeySpec(bytes);
202                     }
203 
204                  })));
205   }
206 
207   /**
208    * Executes {@link Pems#publicKeySpec(InputSupplier)} on the string which
209    * contains an encoded public key in PEM format.
210    * 
211    * @param pem
212    *           public key in pem encoded format.
213    * @see Pems#publicKeySpec(InputSupplier)
214    */
215   public static KeySpec publicKeySpec(String pem) throws IOException {
216      return publicKeySpec(InputSuppliers.of(pem));
217   }
218 
219   /**
220    * Returns the {@link X509EncodedKeySpec} that is pem encoded in the
221    * supplier.
222    * 
223    * @param supplier
224    *           the input stream factory
225    * @param certFactory
226    *           or null to use default
227    * 
228    * @return the {@link X509EncodedKeySpec} which was PEM encoded in the stream
229    * @throws IOException
230    *            if an I/O error occurs
231    * @throws CertificateException
232    */
233   public static X509Certificate x509Certificate(InputSupplier<? extends InputStream> supplier,
234         @Nullable CertificateFactory certFactory) throws IOException, CertificateException {
235      final CertificateFactory finalCertFactory = certFactory != null ? certFactory : CertificateFactory
236            .getInstance("X.509");
237      try {
238         return fromPem(
239               supplier,
240               new PemProcessor<X509Certificate>(ImmutableMap.<String, ResultParser<X509Certificate>> of(
241                     CERTIFICATE_X509_MARKER, new ResultParser<X509Certificate>() {
242 
243                        public X509Certificate parseResult(byte[] bytes) throws IOException {
244                           try {
245                              return (X509Certificate) finalCertFactory.generateCertificate(new ByteArrayInputStream(
246                                    bytes));
247                           } catch (CertificateException e) {
248                              throw new RuntimeException(e);
249                           }
250                        }
251 
252                     })));
253      } catch (RuntimeException e) {
254         if (e.getCause() != null && e.getCause() instanceof CertificateException) {
255            throw (CertificateException) e.getCause();
256         }
257         throw e;
258      }
259   }
260 
261   /**
262    * Executes {@link Pems#x509Certificate(InputSupplier, CertificateFactory)}
263    * on the string which contains an X.509 certificate in PEM format.
264    * 
265    * @param pem
266    *           certificate in pem encoded format.
267    * @see Pems#x509Certificate(InputSupplier, CertificateFactory)
268    */
269   public static X509Certificate x509Certificate(String pem) throws IOException, CertificateException {
270      return x509Certificate(InputSuppliers.of(pem), null);
271   }
272 
273   /**
274    * encodes the {@link X509Certificate} to PEM format.
275    * 
276    * @param cert
277    *           what to encode
278    * @return the PEM encoded certificate
279    * @throws IOException
280    * @throws CertificateEncodingException
281    */
282   public static String pem(X509Certificate cert) throws CertificateEncodingException {
283      String marker = CERTIFICATE_X509_MARKER;
284      return pem(cert.getEncoded(), marker);
285   }
286 
287   /**
288    * encodes the {@link PublicKey} to PEM format.
289    * 
290    * @param cert
291    *           what to encode
292    * @return the PEM encoded public key
293    * @throws IOException
294    * @throws CertificateEncodingException
295    */
296   public static String pem(PublicKey key) {
297      String marker = key instanceof RSAPublicKey ? PUBLIC_PKCS1_MARKER : PUBLIC_X509_MARKER;
298      return pem(key.getEncoded(), marker);
299   }
300 
301   /**
302    * encodes the {@link PrivateKey} to PEM format. Note
303    * 
304    * @param cert
305    *           what to encode
306    * @return the PEM encoded private key
307    * @throws IOException
308    * @throws CertificateEncodingException
309    */
310   // TODO: understand why pem isn't passing SshKeysTest.testCanGenerate where
311   // keys are checked to match.
312   public static String pem(PrivateKey key) {
313      String marker = key instanceof RSAPrivateCrtKey ? PRIVATE_PKCS1_MARKER : PRIVATE_PKCS8_MARKER;
314      return pem(key instanceof RSAPrivateCrtKey ? getEncoded(RSAPrivateCrtKey.class.cast(key)) : key.getEncoded(),
315            marker);
316   }
317 
318   // TODO find a way to do this without using bouncycastle
319   public static byte[] getEncoded(RSAPrivateCrtKey key) {
320      RSAPrivateKeyStructure keyStruct = new RSAPrivateKeyStructure(key.getModulus(), key.getPublicExponent(),
321            key.getPrivateExponent(), key.getPrimeP(), key.getPrimeQ(), key.getPrimeExponentP(),
322            key.getPrimeExponentQ(), key.getCrtCoefficient());
323 
324      ByteArrayOutputStream bOut = new ByteArrayOutputStream();
325      ASN1OutputStream aOut = new ASN1OutputStream(bOut);
326 
327      try {
328         aOut.writeObject(keyStruct);
329         aOut.close();
330      } catch (IOException e) {
331         Throwables.propagate(e);
332      }
333 
334      return bOut.toByteArray();
335   }
336 
337   private static String pem(byte[] key, String marker) {
338      return pem(key, marker, 64);
339   }
340 
341   static String pem(byte[] key, String marker, int length) {
342      return new StringBuilder(marker + "\n")
343            .append(Joiner.on('\n').join(Splitter.fixedLength(length).split(CryptoStreams.base64(key))))
344            .append("\n" + marker.replace("BEGIN", "END") + "\n").toString().trim();
345   }
346 
347}

[all classes][org.jclouds.crypto]
EMMA 2.0.5312 (C) Vladimir Roubtsov