2 * ============LICENSE_START====================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
21 package org.onap.aaf.auth.cm.ca;
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;
33 import java.util.regex.Pattern;
35 import org.bouncycastle.asn1.x500.style.BCStyle;
36 import org.onap.aaf.auth.cm.cert.CSRMeta;
37 import org.onap.aaf.auth.cm.cert.RDN;
38 import org.onap.aaf.cadi.Access;
39 import org.onap.aaf.cadi.Access.Level;
40 import org.onap.aaf.cadi.config.Config;
41 import org.onap.aaf.cadi.configure.CertException;
42 import org.onap.aaf.misc.env.Trans;
43 import org.onap.aaf.misc.env.util.Split;
45 public abstract class CA {
46 public static final Pattern IPV4_PATTERN = Pattern.compile("\\A(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\z");
47 public static final Pattern IPV6_PATTERN = Pattern.compile("\\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\z");
50 private static final String MUST_EXIST_TO_CREATE_CSRS_FOR = " must exist to create CSRs for ";
51 //TODO figuring out what is an Issuing CA is a matter of convention. Consider SubClassing for Open Source
52 public static final String ISSUING_CA = "Issuing CA";
53 public static final String CM_CA_PREFIX = "cm_ca.";
54 public static final String CM_CA_BASE_SUBJECT = ".baseSubject";
55 public static final String CM_CA_ENV_TAG = ".env_tag";
56 protected static final String CM_PUBLIC_DIR = "cm_public_dir";
57 private static final String CM_TRUST_CAS = "cm_trust_cas";
58 protected static final String CM_BACKUP_CAS = "cm_backup_cas";
60 public static final Set<String> EMPTY = Collections.unmodifiableSet(new HashSet<>());
63 private final String name;
64 private final String env;
65 private MessageDigest messageDigest;
66 private final String permNS;
67 private final String permType;
68 private final ArrayList<String> idDomains;
69 private String[] trustedCAs;
70 private String[] caIssuerDNs;
71 private List<RDN> rdns;
72 private final boolean env_tag;
75 protected CA(Access access, String caName, String env) throws IOException, CertException {
76 trustedCAs = new String[4]; // starting array
79 this.env_tag = env==null || env.isEmpty()?false:
80 Boolean.parseBoolean(access.getProperty(CM_CA_ENV_TAG, Boolean.FALSE.toString()));
82 String prefix = CM_CA_PREFIX + name;
83 permType = access.getProperty(prefix + ".perm_type",null);
85 throw new CertException(prefix + ".perm_type" + MUST_EXIST_TO_CREATE_CSRS_FOR + caName);
87 caIssuerDNs = Split.splitTrim(':', access.getProperty(Config.CADI_X509_ISSUERS, null));
89 String tag = CA.CM_CA_PREFIX+caName+CA.CM_CA_BASE_SUBJECT;
91 String fields = access.getProperty(tag, null);
93 throw new CertException(tag + MUST_EXIST_TO_CREATE_CSRS_FOR + caName);
95 access.log(Level.INFO, tag, "=",fields);
96 rdns = RDN.parse('/',fields);
97 for (RDN rdn : rdns) {
98 if (rdn.aoi==BCStyle.EmailAddress) { // Cert Specs say Emails belong in Subject
99 throw new CertException("email address is not allowed in " + CM_CA_BASE_SUBJECT);
103 idDomains = new ArrayList<>();
104 StringBuilder sb = null;
105 for (String s : Split.splitTrim(',', access.getProperty(CA.CM_CA_PREFIX+caName+".idDomains", ""))) {
108 sb = new StringBuilder();
117 access.printf(Level.INIT, "CA '%s' supports Personal Certificates for %s", caName, sb);
120 String dataDir = access.getProperty(CM_PUBLIC_DIR,null);
122 File data = new File(dataDir);
125 String trustCas = access.getProperty(CM_TRUST_CAS,null);
126 if (trustCas!=null) {
127 for (String fname : Split.splitTrim(',', trustCas)) {
129 if (fname.contains("/")) {
130 crt = new File(fname);
132 crt = new File(data,fname);
135 access.printf(Level.INIT, "Loading CA Cert from %s", crt.getAbsolutePath());
136 bytes = new byte[(int)crt.length()];
137 FileInputStream fis = new FileInputStream(crt);
139 int read = fis.read(bytes);
141 addTrustedCA(new String(bytes));
147 access.printf(Level.INIT, "FAILED to Load CA Cert from %s", crt.getAbsolutePath());
151 access.printf(Level.INIT, "Cannot load external TRUST CAs: No property %s",CM_TRUST_CAS);
154 access.printf(Level.INIT, "Cannot load external TRUST CAs: %s doesn't exist, or is not accessible",data.getAbsolutePath());
159 protected void addCaIssuerDN(String issuerDN) {
160 boolean changed = true;
161 for (String id : caIssuerDNs) {
162 if (id.equals(issuerDN)) {
168 String[] newsa = new String[caIssuerDNs.length+1];
170 System.arraycopy(caIssuerDNs, 0, newsa, 1, caIssuerDNs.length);
175 protected synchronized void addTrustedCA(final String crtString) {
177 if (crtString.endsWith("\n")) {
180 crt = crtString + '\n';
182 for (int i=0;i<trustedCAs.length;++i) {
183 if (trustedCAs[i]==null) {
188 String[] temp = new String[trustedCAs.length+5];
189 System.arraycopy(trustedCAs,0,temp, 0, trustedCAs.length);
190 temp[trustedCAs.length]=crt;
194 public String[] getCaIssuerDNs() {
198 public String[] getTrustedCAs() {
202 public boolean shouldAddEnvTag() {
206 public String getEnv() {
210 protected void setMessageDigest(MessageDigest md) {
215 * End Required Constructor calls
218 public String getName() {
223 public String getPermNS() {
227 public String getPermType() {
231 public abstract X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException;
234 * @see org.onap.aaf.auth.cm.ca.CA#inPersonalDomains(java.security.Principal)
236 public boolean inPersonalDomains(Principal p) {
237 int at = p.getName().indexOf('@');
239 return idDomains.contains(p.getName().substring(at+1));
245 public MessageDigest messageDigest() {
246 return messageDigest;
249 public CSRMeta newCSRMeta() {
250 return new CSRMeta(rdns);