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