Changes from Onsite Tests
[aaf/authz.git] / auth / auth-certman / src / main / java / org / onap / aaf / auth / cm / ca / CA.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 package org.onap.aaf.auth.cm.ca;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.security.MessageDigest;
27 import java.security.Principal;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33
34 import org.bouncycastle.asn1.x500.style.BCStyle;
35 import org.onap.aaf.auth.cm.cert.CSRMeta;
36 import org.onap.aaf.auth.cm.cert.RDN;
37 import org.onap.aaf.cadi.Access;
38 import org.onap.aaf.cadi.Access.Level;
39 import org.onap.aaf.cadi.config.Config;
40 import org.onap.aaf.cadi.configure.CertException;
41 import org.onap.aaf.misc.env.Trans;
42 import org.onap.aaf.misc.env.util.Split;
43
44 public abstract class CA {
45     private static final String MUST_EXIST_TO_CREATE_CSRS_FOR = " must exist to create CSRs for ";
46     //TODO figuring out what is an Issuing CA is a matter of convention.  Consider SubClassing for Open Source
47     public static final String ISSUING_CA = "Issuing CA";
48     public static final String CM_CA_PREFIX = "cm_ca.";
49     public static final String CM_CA_BASE_SUBJECT = ".baseSubject";
50     public static final String CM_CA_ENV_TAG = ".env_tag";
51     protected static final String CM_PUBLIC_DIR = "cm_public_dir";
52     private static final String CM_TRUST_CAS = "cm_trust_cas";
53     protected static final String CM_BACKUP_CAS = "cm_backup_cas";
54
55     public static final Set<String> EMPTY = Collections.unmodifiableSet(new HashSet<>());
56
57     
58     private final String name;
59     private final String env;
60     private MessageDigest messageDigest;
61     private final String permNS; 
62     private final String permType;
63     private final ArrayList<String> idDomains;
64     private String[] trustedCAs;
65     private String[] caIssuerDNs;
66     private List<RDN> rdns;
67     private final boolean env_tag;
68
69
70     protected CA(Access access, String caName, String env) throws IOException, CertException {
71         trustedCAs = new String[4]; // starting array
72         this.name = caName;
73         this.env = env;
74         this.env_tag = env==null || env.isEmpty()?false: 
75                         Boolean.parseBoolean(access.getProperty(CM_CA_ENV_TAG, Boolean.FALSE.toString()));
76         permNS = CM_CA_PREFIX + name;
77         permType = access.getProperty(permNS + ".perm_type",null);
78         if (permType==null) {
79             throw new CertException(permNS + ".perm_type" + MUST_EXIST_TO_CREATE_CSRS_FOR + caName);
80         }
81         caIssuerDNs = Split.splitTrim(':', access.getProperty(Config.CADI_X509_ISSUERS, null));
82         
83         String tag = CA.CM_CA_PREFIX+caName+CA.CM_CA_BASE_SUBJECT;
84         
85         String fields = access.getProperty(tag, null);
86         if (fields==null) {
87             throw new CertException(tag + MUST_EXIST_TO_CREATE_CSRS_FOR + caName);
88         }
89         access.log(Level.INFO, tag, "=",fields);
90         rdns = RDN.parse('/',fields);
91         for (RDN rdn : rdns) {
92             if (rdn.aoi==BCStyle.EmailAddress) { // Cert Specs say Emails belong in Subject
93                 throw new CertException("email address is not allowed in " + CM_CA_BASE_SUBJECT);
94             }
95         }
96         
97         idDomains = new ArrayList<>();
98         StringBuilder sb = null;
99         for (String s : Split.splitTrim(',', access.getProperty(CA.CM_CA_PREFIX+caName+".idDomains", ""))) {
100             if (s.length()>0) {
101                 if (sb==null) {
102                     sb = new StringBuilder();
103                 } else {
104                     sb.append(", ");
105                 }
106                 idDomains.add(s);
107                 sb.append(s);
108             }
109         }
110         if (sb!=null) {
111             access.printf(Level.INIT, "CA '%s' supports Personal Certificates for %s", caName, sb);
112         }
113         
114         String dataDir = access.getProperty(CM_PUBLIC_DIR,null);
115         if (dataDir!=null) {
116             File data = new File(dataDir);
117             byte[] bytes;
118             if (data.exists()) {
119                 String trustCas = access.getProperty(CM_TRUST_CAS,null);
120                 if (trustCas!=null) {
121                     for (String fname : Split.splitTrim(',', trustCas)) {
122                         File crt;
123                         if (fname.contains("/")) {
124                             crt = new File(fname);
125                         } else {
126                             crt = new File(data,fname);
127                         }
128                         if (crt.exists()) {
129                             access.printf(Level.INIT, "Loading CA Cert from %s", crt.getAbsolutePath());
130                             bytes = new byte[(int)crt.length()];
131                             FileInputStream fis = new FileInputStream(crt);
132                             try {
133                                 int read = fis.read(bytes);
134                                 if (read>0) {    
135                                     addTrustedCA(new String(bytes));
136                                 }
137                             } finally {
138                                 fis.close();
139                             }
140                         } else {
141                             access.printf(Level.INIT, "FAILED to Load CA Cert from %s", crt.getAbsolutePath());
142                         }
143                     }
144                 } else {
145                     access.printf(Level.INIT, "Cannot load external TRUST CAs: No property %s",CM_TRUST_CAS);
146                 }
147             } else {
148                 access.printf(Level.INIT, "Cannot load external TRUST CAs: %s doesn't exist, or is not accessible",data.getAbsolutePath());
149             }
150         }
151     }
152
153     protected void addCaIssuerDN(String issuerDN) {
154         boolean changed = true;
155         for (String id : caIssuerDNs) {
156             if (id.equals(issuerDN)) {
157                 changed = false;
158                 break;
159             }
160         }
161         if (changed) {
162             String[] newsa = new String[caIssuerDNs.length+1];
163             newsa[0]=issuerDN;
164             System.arraycopy(caIssuerDNs, 0, newsa, 1, caIssuerDNs.length);
165             caIssuerDNs = newsa;
166         }
167     }
168     
169     protected synchronized void addTrustedCA(final String crtString) {
170         String crt;
171         if (crtString.endsWith("\n")) {
172             crt = crtString;
173         } else {
174             crt = crtString + '\n';
175         }
176         for (int i=0;i<trustedCAs.length;++i) {
177             if (trustedCAs[i]==null) {
178                 trustedCAs[i]=crt;
179                 return;
180             }
181         }
182         String[] temp = new String[trustedCAs.length+5];
183         System.arraycopy(trustedCAs,0,temp, 0, trustedCAs.length);
184         temp[trustedCAs.length]=crt;
185         trustedCAs = temp;
186     }
187     
188     public String[] getCaIssuerDNs() {
189         return caIssuerDNs;
190     }
191     
192     public String[] getTrustedCAs() {
193         return trustedCAs;
194     }
195     
196     public boolean shouldAddEnvTag() {
197         return env_tag; 
198     }
199     
200     public String getEnv() {
201         return env;
202     }
203
204     protected void setMessageDigest(MessageDigest md) {
205         messageDigest = md;
206     }
207
208     /*
209      * End Required Constructor calls
210      */
211
212     public String getName() {
213         return name;
214     }
215     
216     
217     public String getPermNS() {
218         return permNS;
219     }
220     
221     public String getPermType() {
222         return permType;
223     }
224     
225     public abstract X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException;
226
227     /* (non-Javadoc)
228      * @see org.onap.aaf.auth.cm.ca.CA#inPersonalDomains(java.security.Principal)
229      */
230     public boolean inPersonalDomains(Principal p) {
231         int at = p.getName().indexOf('@');
232         if (at>=0) {
233             return idDomains.contains(p.getName().substring(at+1));
234         } else {
235             return false;
236         }
237     }
238
239     public MessageDigest messageDigest() {
240         return messageDigest;
241     }
242
243     public CSRMeta newCSRMeta() {
244         return new CSRMeta(rdns);
245     }
246
247 }