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.FileReader;
25 import java.io.IOException;
26 import java.math.BigInteger;
27 import java.security.GeneralSecurityException;
28 import java.security.SecureRandom;
29 import java.security.cert.X509Certificate;
30 import java.security.interfaces.RSAPrivateKey;
31 import java.security.interfaces.RSAPublicKey;
32 import java.util.ArrayList;
33 import java.util.Date;
34 import java.util.GregorianCalendar;
35 import java.util.List;
37 import org.bouncycastle.asn1.x500.X500Name;
38 import org.bouncycastle.asn1.x500.X500NameBuilder;
39 import org.bouncycastle.asn1.x509.BasicConstraints;
40 import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
41 import org.bouncycastle.asn1.x509.Extension;
42 import org.bouncycastle.asn1.x509.GeneralName;
43 import org.bouncycastle.asn1.x509.GeneralNames;
44 import org.bouncycastle.asn1.x509.KeyPurposeId;
45 import org.bouncycastle.asn1.x509.KeyUsage;
46 import org.bouncycastle.cert.X509v3CertificateBuilder;
47 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
48 import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
49 import org.bouncycastle.crypto.params.RSAKeyParameters;
50 import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
51 import org.bouncycastle.operator.OperatorCreationException;
52 import org.onap.aaf.auth.cm.cert.BCFactory;
53 import org.onap.aaf.auth.cm.cert.CSRMeta;
54 import org.onap.aaf.auth.cm.cert.RDN;
55 import org.onap.aaf.auth.env.NullTrans;
56 import org.onap.aaf.cadi.Access;
57 import org.onap.aaf.cadi.Access.Level;
58 import org.onap.aaf.cadi.cm.CertException;
59 import org.onap.aaf.cadi.cm.Factory;
60 import org.onap.aaf.misc.env.Env;
61 import org.onap.aaf.misc.env.TimeTaken;
62 import org.onap.aaf.misc.env.Trans;
64 public class LocalCA extends CA {
67 private static final KeyPurposeId[] ASN_WebUsage = new KeyPurposeId[] {
68 KeyPurposeId.id_kp_serverAuth, // WebServer
69 KeyPurposeId.id_kp_clientAuth};// WebClient
71 private final RSAPrivateKey caKey;
72 private final X500Name issuer;
73 private final SecureRandom random = new SecureRandom();
74 private byte[] serialish;
75 private final X509ChainWithIssuer x509cwi; // "Cert" is CACert
77 public LocalCA(Access access, final String name, final String env, final String[][] params) throws IOException, CertException {
78 super(access, name, env);
79 serialish = new byte[24];
80 if(params.length<1 || params[0].length<2) {
81 throw new IOException("LocalCA expects cm_ca.<ca name>=org.onap.aaf.auth.cm.ca.LocalCA,<full path to key file>[;<Full Path to Trust Chain, ending with actual CA>]+");
84 // Read in the Private Key
85 File f = new File(params[0][0]); // key
87 caKey = (RSAPrivateKey)Factory.toPrivateKey(NullTrans.singleton(),f);
89 throw new CertException("Private Key, " + f.getPath() + ", does not exist");
92 String dir = access.getProperty(CM_PUBLIC_DIR, "");
93 if(!"".equals(dir) && !dir.endsWith("/")) {
96 List<FileReader> frs = new ArrayList<FileReader>(params.length-1);
99 for(int i=1; i<params[0].length; ++i) { // first param is Private Key, remainder are TrustChain
100 path = !params[0][i].contains("/")?dir+params[0][i]:params[0][i];
101 access.printf(Level.INIT, "Loading a TrustChain Member for %s from %s\n",name, path);
102 frs.add(new FileReader(path));
104 x509cwi = new X509ChainWithIssuer(frs);
105 X500NameBuilder xnb = new X500NameBuilder();
106 for(RDN rnd : RDN.parse(',', x509cwi.getIssuerDN())) {
107 xnb.addRDN(rnd.aoi,rnd.value);
109 issuer = xnb.build();
111 for(FileReader fr : frs) {
120 * @see org.onap.aaf.auth.cm.service.CA#sign(org.bouncycastle.pkcs.PKCS10CertificationRequest)
123 public X509andChain sign(Trans trans, CSRMeta csrmeta) throws IOException, CertException {
124 GregorianCalendar gc = new GregorianCalendar();
125 Date start = gc.getTime();
126 gc.add(GregorianCalendar.MONTH, 2);
127 Date end = gc.getTime();
128 X509Certificate x509;
129 TimeTaken tt = trans.start("Create/Sign Cert",Env.SUB);
132 synchronized(serialish) {
133 random.nextBytes(serialish);
134 bi = new BigInteger(serialish);
137 RSAPublicKey rpk = (RSAPublicKey)csrmeta.keypair(trans).getPublic();
138 X509v3CertificateBuilder xcb = new X509v3CertificateBuilder(
140 bi, // replace with Serialnumber scheme
144 SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new RSAKeyParameters(false,rpk.getModulus(),rpk.getPublicExponent()))
145 // new SubjectPublicKeyInfo(ASN1Sequence.getInstance(caCert.getPublicKey().getEncoded()))
147 List<GeneralName> lsan = new ArrayList<GeneralName>();
148 for(String s : csrmeta.sans()) {
149 lsan.add(new GeneralName(GeneralName.dNSName,s));
151 GeneralName[] sans = new GeneralName[lsan.size()];
154 JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
155 xcb.addExtension(Extension.basicConstraints,
156 false, new BasicConstraints(false))
157 .addExtension(Extension.keyUsage,
158 true, new KeyUsage(KeyUsage.digitalSignature
159 | KeyUsage.keyEncipherment))
160 .addExtension(Extension.extendedKeyUsage,
161 true, new ExtendedKeyUsage(ASN_WebUsage))
163 .addExtension(Extension.authorityKeyIdentifier,
164 false, extUtils.createAuthorityKeyIdentifier(x509cwi.cert))
165 .addExtension(Extension.subjectKeyIdentifier,
166 false, extUtils.createSubjectKeyIdentifier(x509cwi.cert.getPublicKey()))
167 .addExtension(Extension.subjectAlternativeName,
168 false, new GeneralNames(sans))
171 x509 = new JcaX509CertificateConverter().getCertificate(
172 xcb.build(BCFactory.contentSigner(caKey)));
173 } catch (GeneralSecurityException|OperatorCreationException e) {
174 throw new CertException(e);
179 return new X509ChainWithIssuer(x509cwi,x509);