1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.crypto.store.filesystem.internal

File AbstractX509FileSystemStore.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

16
38
11
1
263
114
19
0.5
3.45
11
1.73

Classes

Class Line # Actions
AbstractX509FileSystemStore 45 38 0% 19 11
0.8307692483.1%
 

Contributing tests

This file is covered by 13 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20   
21    package org.xwiki.crypto.store.filesystem.internal;
22   
23    import java.io.BufferedReader;
24    import java.io.BufferedWriter;
25    import java.io.File;
26    import java.io.IOException;
27    import java.security.GeneralSecurityException;
28   
29    import javax.inject.Inject;
30    import javax.inject.Named;
31   
32    import org.xwiki.crypto.BinaryStringEncoder;
33    import org.xwiki.crypto.pkix.CertificateFactory;
34    import org.xwiki.crypto.pkix.params.CertifiedPublicKey;
35    import org.xwiki.crypto.pkix.params.x509certificate.X509CertifiedPublicKey;
36    import org.xwiki.crypto.store.FileStoreReference;
37    import org.xwiki.crypto.store.StoreReference;
38   
39    /**
40    * Abstract base class for X.509 file system based store.
41    *
42    * @version $Id: 19c1d83275e023e36b717730021b180b46dbedb2 $
43    * @since 6.1M2
44    */
 
45    public abstract class AbstractX509FileSystemStore
46    {
47    protected static final String CERTIFICATE = "CERTIFICATE";
48   
49    protected static final String DASHES = "-----";
50   
51    protected static final String PEM_BEGIN = DASHES + "BEGIN ";
52   
53    protected static final String PEM_END = DASHES + "END ";
54   
55    protected static final String KEY_FILE_EXTENSION = ".key";
56   
57    protected static final String CERTIFICATE_FILE_EXTENSION = ".cert";
58   
59    /**
60    * Used to encode/decode certificates, private keys and subject keys.
61    */
62    @Inject
63    @Named("Base64")
64    private BinaryStringEncoder base64;
65   
66    /**
67    * Used to encode/decode certificates, private keys and subject keys.
68    */
69    @Inject
70    @Named("Hex")
71    private BinaryStringEncoder hex;
72   
73    /**
74    * Used to create certificate from encoded bytes.
75    */
76    @Inject
77    @Named("X509")
78    private CertificateFactory certificateFactory;
79   
80    /**
81    * Write data encoded based64 between PEM line headers and close the writer.
82    *
83    * @param out the output buffered writer to write to.
84    * @param type the type to be put in the header.
85    * @param data the bytes data to store encoded.
86    * @throws IOException on error.
87    */
 
88  8 toggle protected void store(BufferedWriter out, String type, byte[] data) throws IOException
89    {
90  8 write(out, type, data);
91  8 out.close();
92    }
93   
94    /**
95    * Write data encoded based64 between PEM line headers.
96    *
97    * @param out the output buffered writer to write to.
98    * @param type the type to be written in the header.
99    * @param data the bytes data to store encoded.
100    * @throws IOException on error.
101    */
 
102  10 toggle protected void write(BufferedWriter out, String type, byte[] data) throws IOException
103    {
104  10 writeHeader(out, type);
105  10 out.write(this.base64.encode(data, 64));
106  10 out.newLine();
107  10 writeFooter(out, type);
108    }
109   
110    /**
111    * Write a PEM like header.
112    *
113    * @param out the output buffered writer to write to.
114    * @param type the type to be written in the header.
115    * @throws IOException on error.
116    */
 
117  10 toggle private static void writeHeader(BufferedWriter out, String type) throws IOException
118    {
119  10 out.write(PEM_BEGIN + type + DASHES);
120  10 out.newLine();
121    }
122   
123    /**
124    * Write a PEM like footer.
125    *
126    * @param out the output buffered writer to write to.
127    * @param type the type to be written in the footer.
128    * @throws IOException on error.
129    */
 
130  10 toggle private static void writeFooter(BufferedWriter out, String type) throws IOException
131    {
132  10 out.write(PEM_END + type + DASHES);
133  10 out.newLine();
134    }
135   
136    /**
137    * Return the file corresponding to the given store reference.
138    *
139    * @param store the store reference.
140    * @return a file or folder for storage.
141    * @throws java.lang.IllegalArgumentException if the reference is not appropriate for a filesystem storage.
142    */
 
143  13 toggle protected File getStoreFile(StoreReference store)
144    {
145  13 if (store instanceof FileStoreReference) {
146  13 return ((FileStoreReference) store).getFile();
147    }
148  0 throw new IllegalArgumentException(String.format("Unsupported store reference [%s] for this implementation.",
149    store.getClass().getName()));
150    }
151   
152    /**
153    * Return true if the store is a multi key store.
154    *
155    * @param store the store reference.
156    * @return true if the store is a multi key store.
157    */
 
158  13 toggle protected boolean isMulti(StoreReference store)
159    {
160  13 return !(store instanceof FileStoreReference) || ((FileStoreReference) store).isMulti();
161    }
162   
163    /**
164    * Return the X.509 certificate.
165    *
166    * @param publicKey the certified public key.
167    * @return the cast to an X.509 certificate.
168    * @throws java.lang.IllegalArgumentException if the certified key is not an X.509 one.
169    */
 
170  9 toggle protected X509CertifiedPublicKey getPublicKey(CertifiedPublicKey publicKey)
171    {
172  9 if (publicKey instanceof X509CertifiedPublicKey) {
173  9 return (X509CertifiedPublicKey) publicKey;
174    }
175   
176  0 throw new IllegalArgumentException(String.format("Unsupported certificate [%s], expecting X509 certificates.",
177    publicKey.getClass().getName()));
178    }
179   
180    /**
181    * Return a unique identifier appropriate for a file name. If the certificate as a subject key identifier, the
182    * result is this encoded identifier. Else, use the concatenation of the certificate serial number and the issuer
183    * name.
184    *
185    * @param publicKey the certificate.
186    * @return a unique identifier.
187    * @throws java.io.IOException on error.
188    */
 
189  7 toggle protected String getCertIdentifier(X509CertifiedPublicKey publicKey) throws IOException
190    {
191  7 byte[] keyId = publicKey.getSubjectKeyIdentifier();
192  7 if (keyId != null) {
193  6 return this.hex.encode(keyId);
194    }
195  1 return publicKey.getSerialNumber().toString() + ", " + publicKey.getIssuer().getName();
196    }
197   
198    /**
199    * Read an object from a PEM like file.
200    *
201    * @param in the input reader to read from.
202    * @param password a password to decrypt encrypted objects. May be null if the object is not encrypted.
203    * @return the object read.
204    * @throws IOException on I/O error.
205    * @throws GeneralSecurityException on decryption error.
206    */
 
207  13 toggle protected Object readObject(BufferedReader in, byte[] password) throws IOException, GeneralSecurityException
208    {
209  13 String line;
210  13 Object obj = null;
211   
212  ? while ((line = in.readLine()) != null) {
213  9 obj = processObject(in, line, password);
214  9 if (obj != null) {
215  9 break;
216    }
217    }
218   
219  13 return obj;
220    }
221   
222    /**
223    * Process an object from a PEM like file.
224    *
225    * @param in the input reader to read from.
226    * @param line the last read line.
227    * @param password a password to decrypt encrypted objects. May be null if the object is not encrypted.
228    * @return the object read, or null if the line was not a recognized PEM header.
229    * @throws IOException on I/O error.
230    * @throws GeneralSecurityException on decryption error.
231    */
 
232  3 toggle protected Object processObject(BufferedReader in, String line, byte[] password)
233    throws IOException, GeneralSecurityException
234    {
235  3 if (line.contains(PEM_BEGIN + CERTIFICATE + DASHES)) {
236  3 return this.certificateFactory.decode(readBytes(in, PEM_END + CERTIFICATE + DASHES));
237    }
238  0 return null;
239    }
240   
241    /**
242    * Read base64 data up to an end marker and decode them.
243    *
244    * @param in the input reader to read from.
245    * @param endMarker the end marker.
246    * @return the data read.
247    * @throws IOException on error.
248    */
 
249  9 toggle protected byte[] readBytes(BufferedReader in, String endMarker) throws IOException
250    {
251  9 String line;
252  9 StringBuilder buf = new StringBuilder();
253   
254  ? while ((line = in.readLine()) != null) {
255  18 if (line.contains(endMarker)) {
256  9 break;
257    }
258  9 buf.append(line.trim());
259    }
260   
261  9 return this.base64.decode(buf.toString());
262    }
263    }