b6a2a0a980b081b80762b8bad64c8637a63519c1
[aaf/authz.git] / auth / auth-certman / src / main / java / org / onap / aaf / auth / cm / ca / LocalCA.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.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;
36
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;
63
64 public class LocalCA extends CA {
65
66         // Extensions
67         private static final KeyPurposeId[] ASN_WebUsage = new KeyPurposeId[] {
68                                 KeyPurposeId.id_kp_serverAuth, // WebServer
69                                 KeyPurposeId.id_kp_clientAuth};// WebClient
70                                 
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
76
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>]+");
82                 }
83                 
84                 // Read in the Private Key
85                 File f = new File(params[0][0]); // key
86                 if(f.exists()) {
87                         caKey = (RSAPrivateKey)Factory.toPrivateKey(NullTrans.singleton(),f);
88                 } else {
89                         throw new CertException("Private Key, " + f.getPath() + ", does not exist");
90                 }
91
92                 String dir = access.getProperty(CM_PUBLIC_DIR, "");
93                 if(!"".equals(dir) && !dir.endsWith("/")) {
94                         dir = dir + '/';
95                 }
96                 List<FileReader> frs = new ArrayList<FileReader>(params.length-1);
97                 try {
98                         String path;
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));
103                         }
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);
108                         }
109                         issuer = xnb.build();
110                 } finally {
111                         for(FileReader fr : frs) {
112                                 if(fr!=null) {
113                                         fr.close();
114                                 }
115                         }
116                 }
117         }
118
119         /* (non-Javadoc)
120          * @see org.onap.aaf.auth.cm.service.CA#sign(org.bouncycastle.pkcs.PKCS10CertificationRequest)
121          */
122         @Override
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);
130                 try {
131                         BigInteger bi;
132                         synchronized(serialish) {
133                                 random.nextBytes(serialish);
134                                 bi = new BigInteger(serialish);
135                         }
136                                 
137                         RSAPublicKey rpk = (RSAPublicKey)csrmeta.keypair(trans).getPublic();
138                         X509v3CertificateBuilder xcb = new X509v3CertificateBuilder(
139                                         issuer,
140                                         bi, // replace with Serialnumber scheme
141                                         start,
142                                         end,
143                                         csrmeta.x500Name(),
144                                         SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new RSAKeyParameters(false,rpk.getModulus(),rpk.getPublicExponent()))
145 //                                      new SubjectPublicKeyInfo(ASN1Sequence.getInstance(caCert.getPublicKey().getEncoded()))
146                                         );
147                         List<GeneralName> lsan = new ArrayList<GeneralName>();
148                         for(String s : csrmeta.sans()) {
149                                 lsan.add(new GeneralName(GeneralName.dNSName,s));
150                         }
151                         GeneralName[] sans = new GeneralName[lsan.size()];
152                         lsan.toArray(sans);
153
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))
162
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))
169                                                            ;
170         
171                         x509 = new JcaX509CertificateConverter().getCertificate(
172                                         xcb.build(BCFactory.contentSigner(caKey)));
173                 } catch (GeneralSecurityException|OperatorCreationException e) {
174                         throw new CertException(e);
175                 } finally {
176                         tt.done();
177                 }
178                 
179                 return new X509ChainWithIssuer(x509cwi,x509);
180         }
181
182 }