// --- BEGIN COPYRIGHT BLOCK --- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; version 2 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // (C) 2007 Red Hat, Inc. // All rights reserved. // --- END COPYRIGHT BLOCK --- package com.netscape.cms.servlet.csadmin; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigInteger; import java.util.Date; import javax.servlet.http.HttpServletResponse; import netscape.ldap.LDAPException; import netscape.security.pkcs.PKCS10; import netscape.security.x509.CertificateExtensions; import netscape.security.x509.X500Name; import netscape.security.x509.X509CertImpl; import netscape.security.x509.X509CertInfo; import netscape.security.x509.X509Key; import org.apache.velocity.context.Context; import org.mozilla.jss.CryptoManager; import org.mozilla.jss.crypto.PrivateKey; import org.mozilla.jss.crypto.X509Certificate; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.MetaInfo; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.dbs.certdb.ICertRecord; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; import com.netscape.certsrv.profile.CertInfoProfile; import com.netscape.certsrv.profile.IEnrollProfile; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IRequestQueue; import com.netscape.certsrv.request.RequestId; import com.netscape.certsrv.request.RequestStatus; import com.netscape.certsrv.usrgrp.IGroup; import com.netscape.certsrv.usrgrp.IUGSubsystem; import com.netscape.certsrv.usrgrp.IUser; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.http.HttpClient; import com.netscape.cmsutil.http.HttpRequest; import com.netscape.cmsutil.http.HttpResponse; import com.netscape.cmsutil.http.JssSSLSocketFactory; import com.netscape.cmsutil.xml.XMLObject; public class CertUtil { static final int LINE_COUNT = 76; public static X509CertImpl createRemoteCert(String hostname, int port, String content, HttpServletResponse response, WizardPanelBase panel) throws IOException { HttpClient httpclient = new HttpClient(); String c = null; CMS.debug("CertUtil createRemoteCert: content " + content); try { JssSSLSocketFactory factory = new JssSSLSocketFactory(); httpclient = new HttpClient(factory); httpclient.connect(hostname, port); HttpRequest httprequest = new HttpRequest(); httprequest.setMethod(HttpRequest.POST); httprequest.setURI("/ca/ee/ca/profileSubmit"); httprequest.setHeader("user-agent", "HTTPTool/1.0"); httprequest.setHeader("content-length", "" + content.length()); httprequest.setHeader("content-type", "application/x-www-form-urlencoded"); httprequest.setContent(content); HttpResponse httpresponse = httpclient.send(httprequest); c = httpresponse.getContent(); } catch (Exception e) { CMS.debug("CertUtil createRemoteCert: " + e.toString()); throw new IOException(e.toString()); } if (c != null) { try { ByteArrayInputStream bis = new ByteArrayInputStream(c.getBytes()); XMLObject parser = null; try { parser = new XMLObject(bis); } catch (Exception e) { CMS.debug("CertUtil::createRemoteCert() - " + "Exception=" + e.toString()); throw new IOException(e.toString()); } String status = parser.getValue("Status"); CMS.debug("CertUtil createRemoteCert: status=" + status); if (status.equals("2")) { //relogin to the security domain panel.reloginSecurityDomain(response); return null; } else if (!status.equals("0")) { String error = parser.getValue("Error"); throw new IOException(error); } String b64 = parser.getValue("b64"); CMS.debug("CertUtil createRemoteCert: " + b64); b64 = CryptoUtil.normalizeCertAndReq(b64); byte[] b = CryptoUtil.base64Decode(b64); return new X509CertImpl(b); } catch (Exception e) { CMS.debug("CertUtil createRemoteCert: " + e.toString()); throw new IOException(e.toString()); } } return null; } public static String getPKCS10(IConfigStore config, String prefix, Cert certObj, Context context) throws IOException { String certTag = certObj.getCertTag(); X509Key pubk = null; try { String pubKeyType = config.getString( prefix + certTag + ".keytype"); String algorithm = config.getString( prefix + certTag + ".keyalgorithm"); if (pubKeyType.equals("rsa")) { String pubKeyModulus = config.getString( prefix + certTag + ".pubkey.modulus"); String pubKeyPublicExponent = config.getString( prefix + certTag + ".pubkey.exponent"); pubk = CryptoUtil.getPublicX509Key( CryptoUtil.string2byte(pubKeyModulus), CryptoUtil.string2byte(pubKeyPublicExponent)); } else if (pubKeyType.equals("ecc")) { String pubKeyEncoded = config.getString( prefix + certTag + ".pubkey.encoded"); pubk = CryptoUtil.getPublicX509ECCKey( CryptoUtil.string2byte(pubKeyEncoded)); } else { CMS.debug("CertRequestPanel::getPKCS10() - " + "public key type is unsupported!"); throw new IOException("public key type is unsupported"); } if (pubk != null) { CMS.debug("CertRequestPanel: got public key"); } else { CMS.debug("CertRequestPanel: error getting public key null"); throw new IOException("public key is null"); } // get private key String privKeyID = config.getString(prefix + certTag + ".privkey.id"); byte[] keyIDb = CryptoUtil.string2byte(privKeyID); PrivateKey privk = CryptoUtil.findPrivateKeyFromID(keyIDb); if (privk != null) { CMS.debug("CertRequestPanel: got private key"); } else { CMS.debug("CertRequestPanel: error getting private key null"); } // construct cert request String dn = config.getString(prefix + certTag + ".dn"); PKCS10 certReq = null; certReq = CryptoUtil.createCertificationRequest(dn, pubk, privk, algorithm); byte[] certReqb = certReq.toByteArray(); String certReqs = CryptoUtil.base64Encode(certReqb); return certReqs; } catch (Throwable e) { CMS.debug(e); if (context != null) { context.put("errorString", e.toString()); } CMS.debug("CertUtil getPKCS10: " + e.toString()); throw new IOException(e.toString()); } } /* * create requests so renewal can work on these initial certs */ public static IRequest createLocalRequest(IRequestQueue queue, String serialNum, X509CertInfo info) throws EBaseException { // RequestId rid = new RequestId(serialNum); // just need a request, no need to get into a queue // IRequest r = new EnrollmentRequest(rid); CMS.debug("CertUtil: createLocalRequest for serial: " + serialNum); IRequest req = queue.newRequest("enrollment"); CMS.debug("certUtil: newRequest called"); req.setExtData("profile", "true"); req.setExtData("requestversion", "1.0.0"); req.setExtData("req_seq_num", "0"); req.setExtData(IEnrollProfile.REQUEST_CERTINFO, info); req.setExtData(IEnrollProfile.REQUEST_EXTENSIONS, new CertificateExtensions()); req.setExtData("requesttype", "enrollment"); req.setExtData("requestor_name", ""); req.setExtData("requestor_email", ""); req.setExtData("requestor_phone", ""); req.setExtData("profileRemoteHost", ""); req.setExtData("profileRemoteAddr", ""); req.setExtData("requestnotes", ""); req.setExtData("isencryptioncert", "false"); req.setExtData("profileapprovedby", "system"); // mark request as complete CMS.debug("certUtil: calling setRequestStatus"); req.setRequestStatus(RequestStatus.COMPLETE); return req; } /** * update local cert request with the actual request * called from CertRequestPanel.java */ public static void updateLocalRequest(IConfigStore config, String certTag, String certReq, String reqType, String subjectName) { try { CMS.debug("Updating local request... certTag=" + certTag); RequestId rid = new RequestId(config.getString("preop.cert." + certTag + ".reqId")); ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem( ICertificateAuthority.ID); IRequestQueue queue = ca.getRequestQueue(); if (queue != null) { IRequest req = queue.findRequest(rid); if (req != null) { if (!certReq.equals("")) req.setExtData("cert_request", certReq); req.setExtData("cert_request_type", reqType); if (subjectName != null) { req.setExtData("subject", subjectName); new X500Name(subjectName); // check for errors } } queue.updateRequest(req); } else { CMS.debug("CertUtil:updateLocalRequest - request queue = null"); } } catch (Exception e) { CMS.debug("CertUtil:updateLocalRequest - Exception:" + e.toString()); } } /** * reads from the admin cert profile caAdminCert.profile and takes the first * entry in the list of allowed algorithms. Users that wish a different algorithm * can specify it in the profile using default.params.signingAlg */ public static String getAdminProfileAlgorithm(IConfigStore config) { String algorithm = "SHA256withRSA"; try { String caSigningKeyType = config.getString("preop.cert.signing.keytype", "rsa"); String pfile = config.getString("profile.caAdminCert.config"); FileInputStream fis = new FileInputStream(pfile); DataInputStream in = new DataInputStream(fis); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine; while ((strLine = br.readLine()) != null) { String marker2 = "default.params.signingAlg="; int indx = strLine.indexOf(marker2); if (indx != -1) { String alg = strLine.substring(indx + marker2.length()); if ((alg.length() > 0) && (!alg.equals("-"))) { algorithm = alg; break; } ; } ; String marker = "signingAlgsAllowed="; indx = strLine.indexOf(marker); if (indx != -1) { String[] algs = strLine.substring(indx + marker.length()).split(","); for (int i = 0; i < algs.length; i++) { if ((caSigningKeyType.equals("rsa") && (algs[i].indexOf("RSA") != -1)) || (caSigningKeyType.equals("ecc") && (algs[i].indexOf("EC") != -1))) { algorithm = algs[i]; break; } } } } in.close(); } catch (Exception e) { CMS.debug("getAdminProfleAlgorithm: exception: " + e); } return algorithm; } public static X509CertImpl createLocalCert(IConfigStore config, X509Key x509key, String prefix, String certTag, String type, Context context) throws IOException { CMS.debug("Creating local certificate... certTag=" + certTag); String profile = null; try { profile = config.getString(prefix + certTag + ".profile"); } catch (Exception e) { } X509CertImpl cert = null; ICertificateAuthority ca = null; ICertificateRepository cr = null; RequestId reqId = null; String profileId = null; IRequestQueue queue = null; IRequest req = null; try { String dn = config.getString(prefix + certTag + ".dn"); String keyAlgorithm = null; Date date = new Date(); X509CertInfo info = null; if (certTag.equals("admin")) { keyAlgorithm = getAdminProfileAlgorithm(config); } else { keyAlgorithm = config.getString(prefix + certTag + ".keyalgorithm"); } ca = (ICertificateAuthority) CMS.getSubsystem( ICertificateAuthority.ID); cr = ca.getCertificateRepository(); BigInteger serialNo = cr.getNextSerialNumber(); if (type.equals("selfsign")) { CMS.debug("Creating local certificate... issuerdn=" + dn); CMS.debug("Creating local certificate... dn=" + dn); info = CryptoUtil.createX509CertInfo(x509key, serialNo.intValue(), dn, dn, date, date, keyAlgorithm); } else { String issuerdn = config.getString("preop.cert.signing.dn", ""); CMS.debug("Creating local certificate... issuerdn=" + issuerdn); CMS.debug("Creating local certificate... dn=" + dn); info = CryptoUtil.createX509CertInfo(x509key, serialNo.intValue(), issuerdn, dn, date, date, keyAlgorithm); } CMS.debug("Cert Template: " + info.toString()); String instanceRoot = config.getString("instanceRoot"); CertInfoProfile processor = new CertInfoProfile( instanceRoot + "/conf/" + profile); // cfu - create request to enable renewal try { queue = ca.getRequestQueue(); if (queue != null) { req = createLocalRequest(queue, serialNo.toString(), info); CMS.debug("CertUtil profile name= " + profile); req.setExtData("req_key", x509key.toString()); // store original profile id in cert request int idx = profile.lastIndexOf('.'); if (idx == -1) { CMS.debug("CertUtil profileName contains no ."); req.setExtData("origprofileid", profile); } else { String name = profile.substring(0, idx); req.setExtData("origprofileid", name); } // store mapped profile ID for use in renewal profileId = processor.getProfileIDMapping(); req.setExtData("profileid", profileId); req.setExtData("profilesetid", processor.getProfileSetIDMapping()); reqId = req.getRequestId(); config.putString("preop.cert." + certTag + ".reqId", reqId.toString()); } else { CMS.debug("certUtil: requestQueue null"); } } catch (Exception e) { CMS.debug("Creating local request exception:" + e.toString()); } processor.populate(info); String caPriKeyID = config.getString( prefix + "signing" + ".privkey.id"); byte[] keyIDb = CryptoUtil.string2byte(caPriKeyID); PrivateKey caPrik = CryptoUtil.findPrivateKeyFromID( keyIDb); if (caPrik == null) { CMS.debug("CertUtil::createSelfSignedCert() - " + "CA private key is null!"); throw new IOException("CA private key is null"); } else { CMS.debug("CertUtil createSelfSignedCert: got CA private key"); } String keyAlgo = x509key.getAlgorithm(); CMS.debug("key algorithm is " + keyAlgo); String caSigningKeyType = config.getString("preop.cert.signing.keytype", "rsa"); String caSigningKeyAlgo = ""; if (type.equals("selfsign")) { caSigningKeyAlgo = config.getString("preop.cert.signing.keyalgorithm", "SHA256withRSA"); } else { caSigningKeyAlgo = config.getString("preop.cert.signing.signingalgorithm", "SHA256withRSA"); } CMS.debug("CA Signing Key type " + caSigningKeyType); CMS.debug("CA Signing Key algorithm " + caSigningKeyAlgo); if (caSigningKeyType.equals("ecc")) { CMS.debug("CA signing cert is ECC"); cert = CryptoUtil.signECCCert(caPrik, info, caSigningKeyAlgo); } else { CMS.debug("CA signing cert is not ecc"); cert = CryptoUtil.signCert(caPrik, info, caSigningKeyAlgo); } if (cert != null) { CMS.debug("CertUtil createSelfSignedCert: got cert signed"); } } catch (Exception e) { CMS.debug(e); CMS.debug("NamePanel configCert() exception caught:" + e.toString()); } if (cr == null) { if (context != null) { context.put("errorString", "Ceritifcate Authority is not ready to serve."); } throw new IOException("Ceritifcate Authority is not ready to serve."); } ICertRecord record = null; try { MetaInfo meta = new MetaInfo(); if (reqId != null) { meta.set(ICertRecord.META_REQUEST_ID, reqId.toString()); } meta.set(ICertRecord.META_PROFILE_ID, profileId); record = cr.createCertRecord( cert.getSerialNumber(), cert, meta); } catch (Exception e) { CMS.debug( "NamePanel configCert: failed to add metainfo. Exception: " + e.toString()); } try { cr.addCertificateRecord(record); CMS.debug( "NamePanel configCert: finished adding certificate record."); } catch (Exception e) { CMS.debug( "NamePanel configCert: failed to add certificate record. Exception: " + e.toString()); try { cr.deleteCertificateRecord(record.getSerialNumber()); cr.addCertificateRecord(record); } catch (Exception ee) { CMS.debug("NamePanel update: Exception: " + ee.toString()); } } if (req != null) { // update request with cert req.setExtData(IEnrollProfile.REQUEST_ISSUED_CERT, cert); // store request in db try { CMS.debug("certUtil: before updateRequest"); if (queue != null) { queue.updateRequest(req); } } catch (Exception e) { CMS.debug("Exception in updateRequest" + e); } } return cert; } public static void addUserCertificate(X509CertImpl cert) { IConfigStore cs = CMS.getConfigStore(); int num = 0; try { num = cs.getInteger("preop.subsystem.count", 0); } catch (Exception e) { } IUGSubsystem system = (IUGSubsystem) (CMS.getSubsystem(IUGSubsystem.ID)); String id = "user" + num; try { String sysType = cs.getString("cs.type", ""); String machineName = cs.getString("machineName", ""); String securePort = cs.getString("service.securePort", ""); id = sysType + "-" + machineName + "-" + securePort; } catch (Exception e1) { // ignore } num++; cs.putInteger("preop.subsystem.count", num); cs.putInteger("subsystem.count", num); try { cs.commit(false); } catch (Exception e) { } IUser user = null; X509CertImpl[] certs = new X509CertImpl[1]; CMS.debug("CertUtil addUserCertificate starts"); try { user = system.createUser(id); user.setFullName(id); user.setEmail(""); user.setPassword(""); user.setUserType("agentType"); user.setState("1"); user.setPhone(""); certs[0] = cert; user.setX509Certificates(certs); system.addUser(user); CMS.debug("CertUtil addUserCertificate: successfully add the user"); } catch (LDAPException e) { CMS.debug("CertUtil addUserCertificate" + e.toString()); if (e.getLDAPResultCode() != LDAPException.ENTRY_ALREADY_EXISTS) { try { user = system.getUser(id); user.setX509Certificates(certs); } catch (Exception ee) { CMS.debug("CertUtil addUserCertificate: successfully find the user"); } } } catch (Exception e) { CMS.debug("CertUtil addUserCertificate addUser " + e.toString()); } try { system.addUserCert(user); CMS.debug("CertUtil addUserCertificate: successfully add the user certificate"); } catch (Exception e) { CMS.debug("CertUtil addUserCertificate exception=" + e.toString()); } IGroup group = null; String groupName = "Subsystem Group"; try { group = system.getGroupFromName(groupName); if (!group.isMember(id)) { group.addMemberName(id); system.modifyGroup(group); CMS.debug("CertUtil addUserCertificate: update: successfully added the user to the group."); } } catch (Exception e) { CMS.debug("CertUtil addUserCertificate update: modifyGroup " + e.toString()); } } /* * formats a cert fingerprints */ public static String fingerPrintFormat(String content) { if (content == null || content.length() == 0) { return ""; } StringBuffer result = new StringBuffer(); result.append("Fingerprints:\n"); while (content.length() >= LINE_COUNT) { result.append(content.substring(0, LINE_COUNT)); result.append("\n"); content = content.substring(LINE_COUNT); } if (content.length() > 0) result.append(content); result.append("\n"); return result.toString(); } public static boolean privateKeyExistsOnToken(String certTag, String tokenname, String nickname) { IConfigStore cs = CMS.getConfigStore(); String givenid = ""; try { givenid = cs.getString("preop.cert." + certTag + ".privkey.id"); } catch (Exception e) { CMS.debug("CertUtil privateKeyExistsOnToken: we did not generate private key yet."); return false; } String fullnickname = nickname; if (!tokenname.equals("internal") && !tokenname.equals("Internal Key Storage Token")) { fullnickname = tokenname + ":" + nickname; } X509Certificate cert = null; CryptoManager cm = null; try { cm = CryptoManager.getInstance(); cert = cm.findCertByNickname(fullnickname); } catch (Exception e) { CMS.debug("CertUtil privateKeyExistsOnToken: nickname=" + fullnickname + " Exception:" + e.toString()); return false; } PrivateKey privKey = null; try { privKey = cm.findPrivKeyByCert(cert); } catch (Exception e) { CMS.debug("CertUtil privateKeyExistsOnToken: cant find private key (" + fullnickname + ") exception: " + e.toString()); return false; } if (privKey == null) { CMS.debug("CertUtil privateKeyExistsOnToken: cant find private key (" + fullnickname + ")"); return false; } else { String str = ""; try { str = CryptoUtil.byte2string(privKey.getUniqueID()); } catch (Exception e) { CMS.debug("CertUtil privateKeyExistsOnToken: encode string Exception: " + e.toString()); } if (str.equals(givenid)) { CMS.debug("CertUtil privateKeyExistsOnToken: find the private key on the token."); return true; } } return false; } }