Update project structure for aaf/cadi
[aaf/cadi.git] / core / src / main / java / org / onap / aaf / cadi / taf / cert / X509Taf.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package org.onap.aaf.cadi.taf.cert;\r
24 \r
25 import java.io.ByteArrayInputStream;\r
26 import java.io.ByteArrayOutputStream;\r
27 import java.io.IOException;\r
28 import java.security.GeneralSecurityException;\r
29 import java.security.MessageDigest;\r
30 import java.security.NoSuchAlgorithmException;\r
31 import java.security.Principal;\r
32 import java.security.Signature;\r
33 import java.security.cert.CertificateException;\r
34 import java.security.cert.CertificateFactory;\r
35 import java.security.cert.X509Certificate;\r
36 import java.util.ArrayList;\r
37 \r
38 import javax.net.ssl.TrustManagerFactory;\r
39 import javax.servlet.http.HttpServletRequest;\r
40 import javax.servlet.http.HttpServletResponse;\r
41 \r
42 import org.onap.aaf.cadi.Access;\r
43 import org.onap.aaf.cadi.CachedPrincipal;\r
44 import org.onap.aaf.cadi.CadiException;\r
45 import org.onap.aaf.cadi.Lur;\r
46 import org.onap.aaf.cadi.Symm;\r
47 import org.onap.aaf.cadi.Access.Level;\r
48 import org.onap.aaf.cadi.CachedPrincipal.Resp;\r
49 import org.onap.aaf.cadi.Taf.LifeForm;\r
50 import org.onap.aaf.cadi.config.Config;\r
51 import org.onap.aaf.cadi.config.SecurityInfo;\r
52 import org.onap.aaf.cadi.config.SecurityInfoC;\r
53 import org.onap.aaf.cadi.lur.LocalPermission;\r
54 import org.onap.aaf.cadi.principal.TGuardPrincipal;\r
55 import org.onap.aaf.cadi.principal.X509Principal;\r
56 import org.onap.aaf.cadi.taf.HttpTaf;\r
57 import org.onap.aaf.cadi.taf.TafResp;\r
58 import org.onap.aaf.cadi.taf.TafResp.RESP;\r
59 import org.onap.aaf.cadi.util.Split;\r
60 \r
61 public class X509Taf implements HttpTaf {\r
62         \r
63         public static final CertificateFactory certFactory;\r
64         public static final MessageDigest messageDigest;\r
65         public static final TrustManagerFactory tmf;\r
66         private Access access;\r
67         private CertIdentity[] certIdents;\r
68         private Lur lur;\r
69         private ArrayList<String> cadiIssuers;\r
70         private String env;\r
71         private SecurityInfo si;\r
72 \r
73         static {\r
74                 try {\r
75                         certFactory = CertificateFactory.getInstance("X.509");\r
76                         messageDigest = MessageDigest.getInstance("SHA-256"); // use this to clone\r
77                         tmf = TrustManagerFactory.getInstance(SecurityInfoC.SslKeyManagerFactoryAlgorithm);\r
78                 } catch (Exception e) {\r
79                         throw new RuntimeException("X.509 and SHA-256 are required for X509Taf",e);\r
80                 }\r
81         }\r
82         \r
83         public X509Taf(Access access, Lur lur, CertIdentity ... cis) throws CertificateException, NoSuchAlgorithmException, CadiException {\r
84                 this.access = access;\r
85                 env = access.getProperty(Config.AAF_ENV,null);\r
86                 if(env==null) {\r
87                         throw new CadiException("X509Taf requires Environment ("+Config.AAF_ENV+") to be set.");\r
88                 }\r
89                 this.lur = lur;\r
90                 this.cadiIssuers = new ArrayList<String>();\r
91                 for(String ci : access.getProperty(Config.CADI_X509_ISSUERS, "CN=ATT CADI Issuing CA 01, OU=CSO, O=ATT, C=US:CN=ATT CADI Issuing CA 02, OU=CSO, O=ATT, C=US").split(":")) {\r
92                         cadiIssuers.add(ci);\r
93                 }\r
94                 try {\r
95                         Class<?> dci = access.classLoader().loadClass("com.att.authz.cadi.DirectCertIdentity");\r
96                         CertIdentity temp[] = new CertIdentity[cis.length+1];\r
97                         System.arraycopy(cis, 0, temp, 1, cis.length);\r
98                         temp[0] = (CertIdentity) dci.newInstance();\r
99                         certIdents=temp;\r
100                 } catch (Exception e) {\r
101                         certIdents = cis;\r
102                 }\r
103                 \r
104                 try {\r
105                         si = new SecurityInfo(access);\r
106                 } catch (GeneralSecurityException | IOException e1) {\r
107                         throw new CadiException(e1);\r
108                 }\r
109         }\r
110 \r
111         public static final X509Certificate getCert(byte[] certBytes) throws CertificateException {\r
112                 ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);\r
113                 return (X509Certificate)certFactory.generateCertificate(bais);\r
114         }\r
115 \r
116         public static final byte[] getFingerPrint(byte[] ba) {\r
117                 MessageDigest md;\r
118                 try {\r
119                         md = (MessageDigest)messageDigest.clone();\r
120                 } catch (CloneNotSupportedException e) {\r
121                         // should never get here\r
122                         return new byte[0];\r
123                 }\r
124                 md.update(ba);\r
125                 return md.digest();\r
126         }\r
127 \r
128         public TafResp validate(LifeForm reading, HttpServletRequest req, HttpServletResponse resp) {\r
129                 // Check for Mutual SSL\r
130                 try {\r
131                         X509Certificate[] certarr = (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");\r
132                         if(certarr!=null && certarr.length>0) {\r
133                                 si.checkClientTrusted(certarr);\r
134                                 // Note: If the Issuer is not in the TrustStore, it's not added to the Cert list\r
135                                 if(cadiIssuers.contains(certarr[0].getIssuerDN().toString())) {\r
136                                         String x500 = certarr[0].getSubjectDN().getName();\r
137                                         int ou=x500.indexOf("OU=");\r
138                                         if(ou>0) {\r
139                                                 ou+=3;\r
140                                                 int comma = x500.indexOf(',',ou);\r
141                                                 if(comma>0) {\r
142                                                         String id= x500.substring(ou,comma);\r
143                                                         String idenv[] = id.split(":");\r
144                                                         if(idenv.length==1 || (idenv.length>1 && env.equals(idenv[1]))) {\r
145                                                                 return new X509HttpTafResp(access, \r
146                                                                         new X509Principal(idenv[0], certarr[0],null), \r
147                                                                                 id + " validated by CADI x509", RESP.IS_AUTHENTICATED);\r
148                                                         }\r
149                                                 }\r
150                                         }\r
151                                 }\r
152                         }\r
153 \r
154                         byte[] array = null;\r
155                         byte[] certBytes = null;\r
156                         X509Certificate cert=null;\r
157                         String responseText=null;\r
158                         String authHeader = req.getHeader("Authorization");\r
159 \r
160                         if(certarr!=null) {  // If cert !=null, Cert is Tested by Mutual Protocol.\r
161                                 if(authHeader!=null) { // This is only intended to be a Secure Connection, not an Identity\r
162                                         return new X509HttpTafResp(access, null, "Certificate verified, but another Identity is presented", RESP.TRY_ANOTHER_TAF);\r
163                                 }\r
164                                 cert = certarr[0];\r
165                                 responseText = ", validated by Mutual SSL Protocol";\r
166                         } else {                 // If cert == null, Get Declared Cert (in header), but validate by having them sign something\r
167                                 if(authHeader != null && authHeader.startsWith("x509 ")) {\r
168                                         ByteArrayOutputStream baos = new ByteArrayOutputStream(authHeader.length());\r
169                                         try {\r
170                                                 array = authHeader.getBytes();\r
171                                                 ByteArrayInputStream bais = new ByteArrayInputStream(array);\r
172                                                 Symm.base64noSplit.decode(bais, baos, 5);\r
173                                                 certBytes = baos.toByteArray();\r
174                                                 cert = getCert(certBytes);\r
175                                                 \r
176                                                 /** \r
177                                                  * Identity from CERT if well know CA and specific encoded information\r
178                                                  */\r
179                                                 // If found Identity doesn't work, try SignedStuff Protocol\r
180 //                                                                      cert.checkValidity();\r
181 //                                                                      cert.--- GET FINGERPRINT?\r
182                                                 String stuff = req.getHeader("Signature");\r
183                                                 if(stuff==null) \r
184                                                         return new X509HttpTafResp(access, null, "Header entry 'Signature' required to validate One way X509 Certificate", RESP.TRY_ANOTHER_TAF);\r
185                                                 String data = req.getHeader("Data"); \r
186 //                                                                      if(data==null) \r
187 //                                                                              return new X509HttpTafResp(access, null, "No signed Data to validate with X509 Certificate", RESP.TRY_ANOTHER_TAF);\r
188 \r
189                                                 // Note: Data Pos shows is "<signatureType> <data>"\r
190 //                                                                      int dataPos = (stuff.indexOf(' ')); // determine what is Algorithm\r
191                                                 // Get Signature \r
192                                                 bais = new ByteArrayInputStream(stuff.getBytes());\r
193                                                 baos = new ByteArrayOutputStream(stuff.length());\r
194                                                 Symm.base64noSplit.decode(bais, baos);\r
195                                                 array = baos.toByteArray();\r
196 //                                                                      Signature sig = Signature.getInstance(stuff.substring(0, dataPos)); // get Algorithm from first part of Signature\r
197                                                 \r
198                                                 Signature sig = Signature.getInstance(cert.getSigAlgName()); \r
199                                                 sig.initVerify(cert.getPublicKey());\r
200                                                 sig.update(data.getBytes());\r
201                                                 if(!sig.verify(array)) {\r
202                                                         access.log(Level.ERROR, "Signature doesn't Match");\r
203                                                         return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
204                                                 }\r
205                                                 responseText = ", validated by Signed Data";\r
206                                         } catch (Exception e) {\r
207                                                 access.log(e, "Exception while validating Cert");\r
208                                                 return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
209                                         }\r
210                                         \r
211                                 } else {\r
212                                         return new X509HttpTafResp(access, null, "No Certificate Info on Transaction", RESP.TRY_ANOTHER_TAF);\r
213                                 }\r
214                         }\r
215 \r
216                         // A cert has been found, match Identify\r
217                         Principal prin=null;\r
218                         \r
219                         for(int i=0;prin==null && i<certIdents.length;++i) {\r
220                                 if((prin=certIdents[i].identity(req, cert, certBytes))!=null) {\r
221                                         responseText = prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText;\r
222 //                                      xresp = new X509HttpTafResp(\r
223 //                                                              access,\r
224 //                                                              prin,\r
225 //                                                              prin.getName() + " matches Certificate " + cert.getSubjectX500Principal().getName() + responseText,\r
226 //                                                              RESP.IS_AUTHENTICATED);\r
227                                         \r
228                                 }\r
229                         }\r
230 \r
231                         // if Principal is found, check for "AS_USER" and whether this entity is trusted to declare\r
232                         if(prin!=null) {\r
233                                 String as_user=req.getHeader(Config.CADI_USER_CHAIN);\r
234                                 if(as_user!=null) {\r
235                                         if(as_user.startsWith("TGUARD ") && lur.fish(prin, new LocalPermission("com.att.aaf.trust|"+prin.getName()+"|tguard"))) {\r
236                                                 prin = new TGuardPrincipal(as_user.substring(7));\r
237                                                 responseText=prin.getName() + " set via trust of " + responseText;\r
238                                         }\r
239                                 }\r
240                                 return new X509HttpTafResp(\r
241                                         access,\r
242                                         prin,\r
243                                         responseText,\r
244                                         RESP.IS_AUTHENTICATED);\r
245                         }\r
246                 } catch(Exception e) {\r
247                         return new X509HttpTafResp(access, null, e.getMessage(), RESP.TRY_ANOTHER_TAF); \r
248                 }\r
249         \r
250                 return new X509HttpTafResp(access, null, "Certificate NOT verified", RESP.TRY_ANOTHER_TAF);\r
251         }\r
252 \r
253         public Resp revalidate(CachedPrincipal prin) {\r
254                 return null;\r
255         }\r
256 \r
257 }\r