Merge "Fixes sonar issues in API_Artifact"
[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.client.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 }