diff options
Diffstat (limited to 'auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java')
-rw-r--r-- | auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java new file mode 100644 index 00000000..ae4e21aa --- /dev/null +++ b/auth/auth-certman/src/main/java/org/onap/aaf/auth/cm/ca/JscepCA.java @@ -0,0 +1,268 @@ +/** + * ============LICENSE_START==================================================== + * org.onap.aaf + * =========================================================================== + * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + * + */ +package org.onap.aaf.auth.cm.ca; + +import java.io.FileReader; +import java.io.IOException; +import java.net.Authenticator; +import java.net.MalformedURLException; +import java.net.PasswordAuthentication; +import java.net.URL; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.jscep.client.Client; +import org.jscep.client.ClientException; +import org.jscep.client.EnrollmentResponse; +import org.jscep.client.verification.CertificateVerifier; +import org.jscep.transaction.TransactionException; +import org.onap.aaf.auth.cm.cert.BCFactory; +import org.onap.aaf.auth.cm.cert.CSRMeta; +import org.onap.aaf.cadi.Access; +import org.onap.aaf.cadi.LocatorException; +import org.onap.aaf.cadi.Access.Level; +import org.onap.aaf.cadi.Locator.Item; +import org.onap.aaf.cadi.cm.CertException; +import org.onap.aaf.cadi.locator.HotPeerLocator; +import org.onap.aaf.misc.env.Env; +import org.onap.aaf.misc.env.TimeTaken; +import org.onap.aaf.misc.env.Trans; +import org.onap.aaf.misc.env.util.Split; + +public class JscepCA extends CA { + static final String CA_PREFIX = "http://"; + static final String CA_POSTFIX="/certsrv/mscep_admin/mscep.dll"; + + private final static String MS_PROFILE="1"; + private final static int MAX_RETRY=3; + public static final long INVALIDATE_TIME = 1000*60*10; // 10 mins + + // package on purpose + private Map<String,X509ChainWithIssuer> mxcwi_s; + private Map<Client,X509ChainWithIssuer> mxcwi_c; + + + private JscepClientLocator clients; + + public JscepCA(final Access access, final String name, final String env, String [][] params) throws IOException, CertException, LocatorException { + super(access, name, env); + mxcwi_s = new ConcurrentHashMap<String,X509ChainWithIssuer>(); + mxcwi_c = new ConcurrentHashMap<Client,X509ChainWithIssuer>(); + + if(params.length<2) { + throw new CertException("No Trust Chain parameters are included"); + } + if(params[0].length<2) { + throw new CertException("User/Password required for JSCEP"); + } + final String id = params[0][0]; + final String pw = params[0][1]; + + // Set this for NTLM password Microsoft + Authenticator.setDefault(new Authenticator() { + public PasswordAuthentication getPasswordAuthentication () { + try { + return new PasswordAuthentication (id,access.decrypt(pw,true).toCharArray()); + } catch (IOException e) { + access.log(e); + } + return null; + } + }); + + StringBuilder urlstr = new StringBuilder(); + + for(int i=1;i<params.length;++i) { // skip first section, which is user/pass + // Work + if(i>1) { + urlstr.append(','); // delimiter + } + urlstr.append(params[i][0]); + + String dir = access.getProperty(CM_PUBLIC_DIR, ""); + if(!"".equals(dir) && !dir.endsWith("/")) { + dir = dir + '/'; + } + String path; + List<FileReader> frs = new ArrayList<FileReader>(params.length-1); + try { + for(int j=1; j<params[i].length; ++j) { // first 3 taken up, see above + path = !params[i][j].contains("/")?dir+params[i][j]:params[i][j]; + access.printf(Level.INIT, "Loading a TrustChain Member for %s from %s",name, path); + frs.add(new FileReader(path)); + } + X509ChainWithIssuer xcwi = new X509ChainWithIssuer(frs); + addCaIssuerDN(xcwi.getIssuerDN()); + mxcwi_s.put(params[i][0],xcwi); + } finally { + for(FileReader fr : frs) { + if(fr!=null) { + fr.close(); + } + } + } + } + clients = new JscepClientLocator(access,urlstr.toString()); + } + + // package on purpose + + @Override + public X509ChainWithIssuer sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException { + TimeTaken tt = trans.start("Generating CSR and Keys for New Certificate", Env.SUB); + PKCS10CertificationRequest csr; + try { + csr = csrmeta.generateCSR(trans); + if(trans.info().isLoggable()) { + trans.info().log(BCFactory.toString(csr)); + } + if(trans.info().isLoggable()) { + trans.info().log(csr); + } + } finally { + tt.done(); + } + + tt = trans.start("Enroll CSR", Env.SUB); + Client client = null; + Item item = null; + for(int i=0; i<MAX_RETRY;++i) { + try { + item = clients.best(); + client = clients.get(item); + + EnrollmentResponse er = client.enrol( + csrmeta.initialConversationCert(trans), + csrmeta.keypair(trans).getPrivate(), + csr, + MS_PROFILE /* profile... MS can't deal with blanks*/); + + while(true) { + if(er.isSuccess()) { + trans.checkpoint("Cert from " + clients.info(item)); + X509Certificate x509 = null; + for( Certificate cert : er.getCertStore().getCertificates(null)) { + if(x509==null) { + x509 = (X509Certificate)cert; + break; + } + } + X509ChainWithIssuer mxcwi = mxcwi_c.get(client); + return new X509ChainWithIssuer(mxcwi,x509); +// break; + } else if (er.isPending()) { + trans.checkpoint("Polling, waiting on CA to complete"); + Thread.sleep(3000); + } else if (er.isFailure()) { +// switch(er.getFailInfo()) { +// case badMessageCheck: +// throw new ClientException("Received BadMessageCheck from Jscep"); +// case badAlg: +// case badCertId: +// case badRequest: +// case badTime: +// default: +// } + throw new CertException(clients.info(item)+':'+er.getFailInfo().toString()); + } + } + //i=MAX_RETRY; + } catch(LocatorException e) { + trans.error().log(e); + i=MAX_RETRY; + } catch (ClientException e) { + trans.error().log(e,"SCEP Client Error, Temporarily Invalidating Client: " + clients.info(item)); + try { + clients.invalidate(client); + if(!clients.hasItems()) { + clients.refresh(); + } + } catch (LocatorException e1) { + trans.error().log(e,clients.info(item)); + i=MAX_RETRY; // can't go any further + } + } catch (InterruptedException|TransactionException|CertificateException|OperatorCreationException | CertStoreException e) { + trans.error().log(e); + i=MAX_RETRY; + } finally { + tt.done(); + } + } + + return null; + } + + /** + * Locator specifically for Jscep Clients. + * + * Class based client for access to common Map + */ + private class JscepClientLocator extends HotPeerLocator<Client> { + + protected JscepClientLocator(Access access, String urlstr)throws LocatorException { + super(access, urlstr, JscepCA.INVALIDATE_TIME, + access.getProperty("cadi_latitude","39.833333"), //Note: Defaulting to GEO center of US + access.getProperty("cadi_longitude","-98.583333") + ); + } + + @Override + protected Client _newClient(String urlinfo) throws LocatorException { + try { + String[] info = Split.split('/', urlinfo); + Client c = new Client(new URL(JscepCA.CA_PREFIX + info[0] + JscepCA.CA_POSTFIX), + new CertificateVerifier() { + @Override + public boolean verify(X509Certificate cert) { + //TODO checkIssuer + return true; + } + } + ); + // Map URL to Client, because Client doesn't expose Connection + mxcwi_c.put(c,mxcwi_s.get(urlinfo)); + return c; + } catch (MalformedURLException e) { + throw new LocatorException(e); + } + } + + @Override + protected Client _invalidate(Client client) { + return null; + } + + @Override + protected void _destroy(Client client) { + mxcwi_c.remove(client); + } + + + } +} |