Add a MassMail Batch Program
[aaf/authz.git] / cadi / aaf / src / main / java / org / onap / aaf / cadi / configure / Factory.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.configure;
23
24 import java.io.BufferedReader;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.DataInputStream;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.FileNotFoundException;
31 import java.io.FileReader;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.InputStreamReader;
35 import java.io.Reader;
36 import java.io.StringReader;
37 import java.lang.reflect.Constructor;
38 import java.lang.reflect.InvocationTargetException;
39 import java.security.InvalidKeyException;
40 import java.security.Key;
41 import java.security.KeyFactory;
42 import java.security.KeyPair;
43 import java.security.KeyPairGenerator;
44 import java.security.NoSuchAlgorithmException;
45 import java.security.PrivateKey;
46 import java.security.Provider;
47 import java.security.PublicKey;
48 import java.security.SecureRandom;
49 import java.security.Security;
50 import java.security.Signature;
51 import java.security.SignatureException;
52 import java.security.cert.Certificate;
53 import java.security.cert.CertificateEncodingException;
54 import java.security.cert.CertificateException;
55 import java.security.cert.CertificateFactory;
56 import java.security.cert.X509Certificate;
57 import java.security.spec.InvalidKeySpecException;
58 import java.security.spec.PKCS8EncodedKeySpec;
59 import java.security.spec.X509EncodedKeySpec;
60 import java.util.Collection;
61 import java.util.List;
62
63 import javax.crypto.Cipher;
64 import javax.crypto.NoSuchPaddingException;
65
66 import org.onap.aaf.cadi.Symm;
67 import org.onap.aaf.cadi.util.Holder;
68 import org.onap.aaf.misc.env.Env;
69 import org.onap.aaf.misc.env.TimeTaken;
70 import org.onap.aaf.misc.env.Trans;
71
72 public class Factory {
73     private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";
74     public static final String KEY_ALGO = "RSA";
75     public static final String SIG_ALGO = "SHA256withRSA";
76
77     public  static final int KEY_LENGTH = 2048;
78     private static final KeyPairGenerator keygen;
79     private static final KeyFactory keyFactory;
80     private static final CertificateFactory certificateFactory;
81     private static final SecureRandom random;
82
83
84     private static final Symm base64 = Symm.base64.copy(64);
85
86     static {
87             random = new SecureRandom();
88             KeyPairGenerator tempKeygen;
89             try {
90                 tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");
91                 tempKeygen.initialize(KEY_LENGTH, random);
92             } catch (NoSuchAlgorithmException e) {
93                 tempKeygen = null;
94                 e.printStackTrace(System.err);
95             }
96             keygen = tempKeygen;
97
98             KeyFactory tempKeyFactory;
99             try {
100                 tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"
101             } catch (NoSuchAlgorithmException e) {
102                 tempKeyFactory = null;
103                 e.printStackTrace(System.err);
104             };
105             keyFactory = tempKeyFactory;
106
107             CertificateFactory tempCertificateFactory;
108             try {
109                 tempCertificateFactory = CertificateFactory.getInstance("X.509");
110             } catch (CertificateException e) {
111                 tempCertificateFactory = null;
112                 e.printStackTrace(System.err);
113             }
114             certificateFactory = tempCertificateFactory;
115
116
117     }
118
119
120     public static KeyPair generateKeyPair(Trans trans) {
121         TimeTaken tt;
122         if (trans!=null) {
123             tt = trans.start("Generate KeyPair", Env.SUB);
124         } else {
125             tt = null;
126         }
127         try {
128             return keygen.generateKeyPair();
129         } finally {
130             if (tt!=null) {
131                 tt.done();
132             }
133         }
134     }
135
136     private static final String LINE_END = "-----\n";
137
138     protected static String textBuilder(String kind, byte[] bytes) throws IOException {
139         StringBuilder sb = new StringBuilder();
140         sb.append("-----BEGIN ");
141         sb.append(kind);
142         sb.append(LINE_END);
143
144         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
145         ByteArrayOutputStream baos = new ByteArrayOutputStream();
146         base64.encode(bais, baos);
147         sb.append(new String(baos.toByteArray()));
148
149         if (sb.charAt(sb.length()-1)!='\n') {
150             sb.append('\n');
151         }
152         sb.append("-----END ");
153         sb.append(kind);
154         sb.append(LINE_END);
155         return sb.toString();
156     }
157
158     public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {
159         byte[] bytes = decode(new StringReader(pk), null);
160         return toPrivateKey(trans, bytes);
161     }
162
163     public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {
164         TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);
165         try {
166             return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
167         } catch (InvalidKeySpecException e) {
168             throw new CertException("Translating Private Key from PKCS8 KeySpec",e);
169         } finally {
170             tt.done();
171         }
172     }
173
174     public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {
175         TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);
176         try {
177             Holder<String> firstLine = new Holder<String>(null);
178             return toPrivateKey(trans,decode(file,firstLine));
179         }finally {
180             tt.done();
181         }
182     }
183
184     public static String toString(Trans trans, PrivateKey pk) throws IOException {
185 //        PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());
186         trans.debug().log("Private Key to String");
187         return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());
188     }
189
190     public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {
191         TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);
192         try {
193             ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());
194             ByteArrayOutputStream baos = new ByteArrayOutputStream();
195             Symm.base64noSplit.decode(new StripperInputStream(bais), baos);
196
197             return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));
198         } catch (InvalidKeySpecException e) {
199             trans.error().log(e,"Translating Public Key from X509 KeySpec");
200             return null;
201         } finally {
202             tt.done();
203         }
204     }
205
206     public static String toString(Trans trans, PublicKey pk) throws IOException {
207         trans.debug().log("Public Key to String");
208         return textBuilder("PUBLIC KEY",pk.getEncoded());
209     }
210
211     public static Collection<? extends Certificate> toX509Certificate(String x509) throws CertificateException {
212         return toX509Certificate(x509.getBytes());
213     }
214
215     public static Collection<? extends Certificate> toX509Certificate(List<String> x509s) throws CertificateException {
216         ByteArrayOutputStream baos = new ByteArrayOutputStream();
217         try {
218             for (String x509 : x509s) {
219                 baos.write(x509.getBytes());
220             }
221         } catch (IOException e) {
222             throw new CertificateException(e);
223         }
224         return toX509Certificate(new ByteArrayInputStream(baos.toByteArray()));
225     }
226
227     public static Collection<? extends Certificate> toX509Certificate(byte[] x509) throws CertificateException {
228         return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));
229     }
230
231     public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {
232         FileInputStream fis = new FileInputStream(file);
233         try {
234             try {
235                 return toX509Certificate(fis);
236             } finally {
237                     fis.close();
238             }
239         } catch (IOException e) {
240             throw new CertificateException(e);
241         }
242     }
243
244     public static Collection<? extends Certificate> toX509Certificate(InputStream is) throws CertificateException {
245         return certificateFactory.generateCertificates(is);
246     }
247
248     public static String toString(Trans trans, Certificate cert) throws IOException, CertException {
249         if (trans.debug().isLoggable()) {
250             StringBuilder sb = new StringBuilder("Certificate to String");
251             if (cert instanceof X509Certificate) {
252                 sb.append(" - ");
253                 sb.append(((X509Certificate)cert).getSubjectDN());
254             }
255             trans.debug().log(sb);
256         }
257         try {
258             if (cert==null) {
259                 throw new CertException("Certificate not built");
260             }
261             return textBuilder("CERTIFICATE",cert.getEncoded());
262         } catch (CertificateEncodingException e) {
263             throw new CertException(e);
264         }
265     }
266
267     public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
268         return Cipher.getInstance(KEY_ALGO);
269     }
270
271     public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
272         Cipher cipher = Cipher.getInstance(KEY_ALGO);
273         cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);
274         return cipher;
275     }
276
277     public static byte[] strip(Reader rdr) throws IOException {
278         return strip(rdr,null);
279     }
280
281     public static byte[] strip(Reader rdr, Holder<String> hs) throws IOException {
282         BufferedReader br = new BufferedReader(rdr);
283         ByteArrayOutputStream baos = new ByteArrayOutputStream();
284         String line;
285         boolean notStarted = true;
286         while ((line=br.readLine())!=null) {
287             if (notStarted) {
288                 if (line.startsWith("-----")) {
289                     notStarted = false;
290                     if (hs!=null) {
291                         hs.set(line);
292                     }
293                 } else {
294                     continue;
295                 }
296             }
297             if (line.length()>0 &&
298                !line.startsWith("-----") &&
299                line.indexOf(':')<0) {  // Header elements
300                 baos.write(line.getBytes());
301             }
302         }
303         return baos.toByteArray();
304     }
305
306     public static class StripperInputStream extends InputStream {
307         private Reader created;
308         private BufferedReader br;
309         private int idx;
310         private String line;
311
312         public StripperInputStream(Reader rdr) {
313             if (rdr instanceof BufferedReader) {
314                 br = (BufferedReader)rdr;
315             } else {
316                 br = new BufferedReader(rdr);
317             }
318             created = null;
319         }
320
321         public StripperInputStream(File file) throws FileNotFoundException {
322             this(new FileReader(file));
323             created = br;
324         }
325
326         public StripperInputStream(InputStream is) throws FileNotFoundException {
327             this(new InputStreamReader(is));
328             created = br;
329         }
330
331         @Override
332         public int read() throws IOException {
333             if (line==null || idx>=line.length()) {
334                 while ((line=br.readLine())!=null) {
335                     if (line.length()>0 &&
336                        !line.startsWith("-----") &&
337                        line.indexOf(':')<0) {  // Header elements
338                         break;
339                     }
340                 }
341
342                 if (line==null) {
343                     return -1;
344                 }
345                 idx = 0;
346             }
347             return line.charAt(idx++);
348         }
349
350         /* (non-Javadoc)
351          * @see java.io.InputStream#close()
352          */
353         @Override
354         public void close() throws IOException {
355             if (created!=null) {
356                 created.close();
357             }
358         }
359     }
360
361     public static class Base64InputStream extends InputStream {
362         private InputStream created;
363         private InputStream is;
364         private byte trio[];
365         private byte duo[];
366         private int idx;
367
368
369         public Base64InputStream(File file) throws FileNotFoundException {
370             this(new FileInputStream(file));
371             created = is;
372         }
373
374         public Base64InputStream(InputStream is) throws FileNotFoundException {
375             this.is = is;
376             trio = new byte[3];
377             idx = 4;
378         }
379
380         @Override
381         public int read() throws IOException {
382             if (duo==null || idx>=duo.length) {
383                 int read = is.read(trio);
384                 if (read==-1) {
385                     return -1;
386                 }
387                 duo = Symm.base64.decode(trio);
388                 if (duo==null || duo.length==0) {
389                     return -1;
390                 }
391                 idx=0;
392             }
393
394             return duo[idx++];
395         }
396
397         /* (non-Javadoc)
398          * @see java.io.InputStream#close()
399          */
400         @Override
401         public void close() throws IOException {
402             if (created!=null) {
403                 created.close();
404             }
405         }
406     }
407
408     public static byte[] decode(byte[] bytes) throws IOException {
409         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
410         ByteArrayOutputStream baos = new ByteArrayOutputStream();
411         Symm.base64.decode(bais, baos);
412         return baos.toByteArray();
413     }
414
415     public static byte[] decode(File f, Holder<String> hs) throws IOException {
416         FileReader fr = new FileReader(f);
417         try {
418             return Factory.decode(fr,hs);
419         } finally {
420             fr.close();
421         }
422     }
423
424
425     public static byte[] decode(Reader rdr,Holder<String> hs) throws IOException {
426         return decode(strip(rdr,hs));
427     }
428
429
430     public static byte[] binary(File file) throws IOException {
431         DataInputStream dis = new DataInputStream(new FileInputStream(file));
432         try {
433             byte[] bytes = new byte[(int)file.length()];
434             dis.readFully(bytes);
435             return bytes;
436         } finally {
437             dis.close();
438         }
439     }
440
441
442     public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
443         TimeTaken tt = trans.start("Sign Data", Env.SUB);
444         try {
445             Signature sig = Signature.getInstance(SIG_ALGO);
446             sig.initSign(pk, random);
447             sig.update(bytes);
448             return sig.sign();
449         } finally {
450             tt.done();
451         }
452     }
453
454     public static String toSignatureString(byte[] signed) throws IOException {
455         return textBuilder("SIGNATURE", signed);
456     }
457
458     public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
459         TimeTaken tt = trans.start("Verify Data", Env.SUB);
460         try {
461             Signature sig = Signature.getInstance(SIG_ALGO);
462             sig.initVerify(pk);
463             sig.update(bytes);
464             return sig.verify(signature);
465         } finally {
466             tt.done();
467         }
468     }
469
470     /**
471      * Get the Security Provider, or, if not exists yet, attempt to load
472      *
473      * @param providerType
474      * @param params
475      * @return
476      * @throws CertException
477      */
478     public static synchronized Provider getSecurityProvider(String providerType, String[][] params) throws CertException {
479         Provider p = Security.getProvider(providerType);
480         if (p!=null) {
481             switch(providerType) {
482                 case "PKCS12":
483
484                     break;
485                 case "PKCS11": // PKCS11 only known to be supported by Sun
486                     try {
487                         Class<?> clsSunPKCS11 = Class.forName("sun.security.pkcs11.SunPKCS11");
488                         Constructor<?> cnst = clsSunPKCS11.getConstructor(String.class);
489                         Object sunPKCS11 = cnst.newInstance(params[0][0]);
490                         if (sunPKCS11==null) {
491                             throw new CertException("SunPKCS11 Provider cannot be constructed for " + params[0][0]);
492                         }
493                         Security.addProvider((Provider)sunPKCS11);
494                     } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
495                         throw new CertException(e);
496                     }
497                     break;
498                 default:
499                     throw new CertException(providerType + " is not a known Security Provider for your JDK.");
500             }
501         }
502         return p;
503     }
504 }