diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-24 02:27:47 -0500 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-26 11:43:54 -0500 |
commit | 621d9e5c413e561293d7484b93882d985b3fe15f (patch) | |
tree | 638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/common/src/com/netscape/cmscore/cert | |
parent | 40d3643b8d91886bf210aa27f711731c81a11e49 (diff) | |
download | pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip |
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder.
This folder was created during svn migration and is no longer
needed. This folder has now been removed and the contents have
been moved up one level.
Ticket #131
Diffstat (limited to 'base/common/src/com/netscape/cmscore/cert')
13 files changed, 3278 insertions, 0 deletions
diff --git a/base/common/src/com/netscape/cmscore/cert/CertDateCompare.java b/base/common/src/com/netscape/cmscore/cert/CertDateCompare.java new file mode 100644 index 000000000..7078c3440 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CertDateCompare.java @@ -0,0 +1,52 @@ +// --- 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.cmscore.cert; + +import java.util.Comparator; +import java.util.Date; + +import netscape.security.x509.X509CertImpl; + +/** + * Compares validity dates for use in sorting. + * + * @author kanda + * @version $Revision$, $Date$ + */ +public class CertDateCompare implements Comparator<X509CertImpl> { + public CertDateCompare() { + } + + public int compare(X509CertImpl cert1, X509CertImpl cert2) { + Date d1 = null; + Date d2 = null; + + try { + d1 = cert1.getNotAfter(); + d2 = cert2.getNotAfter(); + } catch (Exception e) { + e.printStackTrace(); + } + if (d1 == d2) + return 0; + if (d1.after(d2)) + return 1; + else + return -1; + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/CertPrettyPrint.java b/base/common/src/com/netscape/cmscore/cert/CertPrettyPrint.java new file mode 100644 index 000000000..726fa5e14 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CertPrettyPrint.java @@ -0,0 +1,36 @@ +// --- 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.cmscore.cert; + +import java.security.cert.Certificate; + +import com.netscape.certsrv.base.ICertPrettyPrint; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + */ +public class CertPrettyPrint extends netscape.security.util.CertPrettyPrint implements ICertPrettyPrint { + + public CertPrettyPrint(Certificate cert) { + super(cert); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/CertUtils.java b/base/common/src/com/netscape/cmscore/cert/CertUtils.java new file mode 100644 index 000000000..9710d63f5 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CertUtils.java @@ -0,0 +1,1103 @@ +// --- 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.cmscore.cert; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Date; +import java.util.StringTokenizer; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.pkcs.PKCS10; +import netscape.security.pkcs.PKCS7; +import netscape.security.util.DerInputStream; +import netscape.security.util.DerOutputStream; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateAlgorithmId; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateIssuerName; +import netscape.security.x509.CertificateSerialNumber; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.CryptoManager.CertificateUsage; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmsutil.util.Utils; + +/** + * Utility class with assorted methods to check for + * smime pairs, determining the type of cert - signature + * or encryption ..etc. + * + * @author kanda + * @version $Revision$, $Date$ + */ +public class CertUtils { + public static final String CERT_NEW_REQUEST_HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----"; + public static final String CERT_NEW_REQUEST_TRAILER = "-----END NEW CERTIFICATE REQUEST-----"; + public static final String CERT_REQUEST_HEADER = "-----BEGIN CERTIFICATE REQUEST-----"; + public static final String CERT_REQUEST_TRAILER = "-----END CERTIFICATE REQUEST-----"; + public static final String CERT_RENEWAL_HEADER = "-----BEGIN RENEWAL CERTIFICATE REQUEST-----"; + public static final String CERT_RENEWAL_TRAILER = "-----END RENEWAL CERTIFICATE REQUEST-----"; + public static final String BEGIN_CRL_HEADER = + "-----BEGIN CERTIFICATE REVOCATION LIST-----"; + public static final String END_CRL_HEADER = + "-----END CERTIFICATE REVOCATION LIST-----"; + + protected static ILogger mSignedAuditLogger = CMS.getSignedAuditLogger(); + private final static String LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION = + "LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION_3"; + + /** + * Remove the header and footer in the PKCS10 request. + */ + public static String unwrapPKCS10(String request, boolean checkHeader) + throws EBaseException { + String unwrapped; + String header = null; + int head = -1; + int trail = -1; + + // check for "-----BEGIN NEW CERTIFICATE REQUEST-----"; + if (header == null) { + head = request.indexOf(CERT_NEW_REQUEST_HEADER); + trail = request.indexOf(CERT_NEW_REQUEST_TRAILER); + + if (!(head == -1 && trail == -1)) { + header = CERT_NEW_REQUEST_HEADER; + } + } + + // check for "-----BEGIN CERTIFICATE REQUEST-----"; + if (header == null) { + head = request.indexOf(CERT_REQUEST_HEADER); + trail = request.indexOf(CERT_REQUEST_TRAILER); + + // If this is not a request header, check if this is a renewal header. + if (!(head == -1 && trail == -1)) { + header = CERT_REQUEST_HEADER; + + } + } + + // check for "-----BEGIN RENEWAL CERTIFICATE REQUEST-----"; + if (header == null) { + head = request.indexOf(CERT_RENEWAL_HEADER); + trail = request.indexOf(CERT_RENEWAL_TRAILER); + if (!(head == -1 && trail == -1)) { + header = CERT_RENEWAL_HEADER; + } + } + + // Now validate if any headers or trailers are in place + if (head == -1 && checkHeader) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_MISSING_PKCS10_HEADER")); + } + if (trail == -1 && checkHeader) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_MISSING_PKCS10_TRAILER")); + } + + if (header != null) { + unwrapped = request.substring(head + header.length(), trail); + } else { + unwrapped = request; + } + + // strip all the crtl-characters (i.e. \r\n) + StringTokenizer st = new StringTokenizer(unwrapped, "\t\r\n "); + StringBuffer stripped = new StringBuffer(); + + while (st.hasMoreTokens()) { + stripped.append(st.nextToken()); + } + + return stripped.toString(); + } + + public static PKCS10 decodePKCS10(String req) throws EBaseException { + String normalized = unwrapPKCS10(req, true); + PKCS10 pkcs10 = null; + + try { + byte[] decodedBytes = Utils.base64decode(normalized); + + pkcs10 = new PKCS10(decodedBytes); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString())); + } + return pkcs10; + } + + public static void setRSAKeyToCertInfo(X509CertInfo info, + byte encoded[]) throws EBaseException { + try { + if (info == null) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")); + } + X509Key key = new X509Key(AlgorithmId.getAlgorithmId( + "RSAEncryption"), encoded); + + info.set(X509CertInfo.KEY, key); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")); + } + } + + public static X509CertInfo createCertInfo(int ver, + BigInteger serialno, String alg, String issuerName, + Date notBefore, Date notAfter) throws EBaseException { + try { + X509CertInfo info = new X509CertInfo(); + + info.set(X509CertInfo.VERSION, new CertificateVersion(ver)); + info.set(X509CertInfo.SERIAL_NUMBER, new + CertificateSerialNumber(serialno)); + info.set(X509CertInfo.ALGORITHM_ID, new + CertificateAlgorithmId(AlgorithmId.getAlgorithmId(alg))); + info.set(X509CertInfo.ISSUER, new + CertificateIssuerName(new X500Name(issuerName))); + info.set(X509CertInfo.VALIDITY, new + CertificateValidity(notBefore, notAfter)); + return info; + } catch (Exception e) { + System.out.println(e.toString()); + return null; + } + } + + public static void sortCerts(X509CertImpl[] arr) { + Arrays.sort(arr, new CertDateCompare()); + } + + public static boolean isSigningCert(X509CertImpl cert) { + boolean[] keyUsage = null; + + try { + keyUsage = cert.getKeyUsage(); + } catch (Exception e) { + e.printStackTrace(); + } + return (keyUsage == null) ? false : keyUsage[0]; + } + + public static boolean isEncryptionCert(X509CertImpl cert) { + boolean[] keyUsage = null; + + try { + keyUsage = cert.getKeyUsage(); + } catch (Exception e) { + e.printStackTrace(); + } + if (keyUsage == null) + return false; + if (keyUsage.length < 3) + return false; + else if (keyUsage.length == 3) + return keyUsage[2]; + else + return keyUsage[2] || keyUsage[3]; + } + + public static boolean haveSameValidityPeriod(X509CertImpl cert1, + X509CertImpl cert2) { + long notBefDiff = 0; + long notAfterDiff = 0; + + try { + notBefDiff = Math.abs(cert1.getNotBefore().getTime() - + cert2.getNotBefore().getTime()); + notAfterDiff = Math.abs(cert1.getNotAfter().getTime() - + cert2.getNotAfter().getTime()); + } catch (Exception e) { + e.printStackTrace(); + } + if (notBefDiff > 1000 || notAfterDiff > 1000) + return false; + else + return true; + } + + public static boolean isSmimePair(X509CertImpl cert1, X509CertImpl cert2, boolean matchSubjectDN) { + // Check for subjectDN equality. + if (matchSubjectDN) { + String dn1 = cert1.getSubjectDN().toString(); + String dn2 = cert2.getSubjectDN().toString(); + + if (!sameSubjectDN(dn1, dn2)) + return false; + } + + // Check for the presence of signing and encryption certs. + boolean hasSigningCert = isSigningCert(cert1) || isSigningCert(cert2); + + if (!hasSigningCert) + return false; + + boolean hasEncryptionCert = isEncryptionCert(cert1) || isEncryptionCert(cert2); + + if (!hasEncryptionCert) + return false; + + // If both certs have signing & encryption usage set, they are + // not really pairs. + if ((isSigningCert(cert1) && isEncryptionCert(cert1)) || + (isSigningCert(cert2) && isEncryptionCert(cert2))) + return false; + + // See if the certs have the same validity. + boolean haveSameValidity = + haveSameValidityPeriod(cert1, cert2); + + return haveSameValidity; + } + + public static boolean isNotYetValidCert(X509CertImpl cert) { + boolean ret = false; + + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + } catch (CertificateNotYetValidException e) { + ret = true; + } catch (Exception e) { + } + return ret; + } + + public static boolean isValidCert(X509CertImpl cert) { + boolean ret = true; + + try { + cert.checkValidity(); + } catch (Exception e) { + ret = false; + } + return ret; + } + + public static boolean isExpiredCert(X509CertImpl cert) { + boolean ret = false; + + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + ret = true; + } catch (Exception e) { + } + return ret; + } + + public static boolean sameSubjectDN(String dn1, String dn2) { + boolean ret = false; + + // The dn cannot be null. + if (dn1 == null || dn2 == null) + return false; + try { + X500Name n1 = new X500Name(dn1); + X500Name n2 = new X500Name(dn2); + + ret = n1.equals(n2); + } catch (Exception e) { + } + return ret; + } + + public static String getValidCertsDisplayInfo(String cn, X509CertImpl[] validCerts) { + StringBuffer sb = new StringBuffer(1024); + + sb.append(cn + "'s Currently Valid Certificates\n\n"); + sb.append(getCertsDisplayInfo(validCerts)); + return new String(sb); + } + + public static String getExpiredCertsDisplayInfo(String cn, X509CertImpl[] expiredCerts) { + StringBuffer sb = new StringBuffer(1024); + + sb.append(cn + "'s Expired Certificates\n\n"); + sb.append(getCertsDisplayInfo(expiredCerts)); + return new String(sb); + } + + public static String getRenewedCertsDisplayInfo(String cn, + X509CertImpl[] validCerts, X509CertImpl[] renewedCerts) { + StringBuffer sb = new StringBuffer(1024); + + if (validCerts != null) { + sb.append(cn + "'s Currently Valid Certificates\n\n"); + sb.append(getCertsDisplayInfo(validCerts)); + sb.append("\n\nRenewed Certificates\n\n\n"); + } else + sb.append(cn + "'s Renewed Certificates\n\n"); + sb.append(getCertsDisplayInfo(renewedCerts)); + return new String(sb); + } + + public static String getCertsDisplayInfo(X509CertImpl[] validCerts) { + // We assume that the given pair is a valid S/MIME pair. + StringBuffer sb = new StringBuffer(1024); + + sb.append("Subject DN: " + validCerts[0].getSubjectDN().toString()); + sb.append("\n"); + X509CertImpl signingCert, encryptionCert; + + if (isSigningCert(validCerts[0])) { + signingCert = validCerts[0]; + encryptionCert = validCerts[1]; + } else { + signingCert = validCerts[1]; + encryptionCert = validCerts[0]; + } + sb.append("Signing Certificate Serial No: " + signingCert.getSerialNumber().toString(16).toUpperCase()); + sb.append("\n"); + sb.append("Encryption Certificate Serial No: " + encryptionCert.getSerialNumber().toString(16).toUpperCase()); + sb.append("\n"); + sb.append("Validity: From: " + + signingCert.getNotBefore().toString() + " To: " + signingCert.getNotAfter().toString()); + sb.append("\n"); + return new String(sb); + } + + /** + * Returns the index of the given cert in an array of certs. + * + * Assumptions: The certs are issued by the same CA + * + * @param certArray The array of certs. + * @param givenCert The certificate we are lokking for in the array. + * @return -1 if not found or the index of the given cert in the array. + */ + public static int getCertIndex(X509CertImpl[] certArray, X509CertImpl givenCert) { + int i = 0; + + for (; i < certArray.length; i++) { + if (certArray[i].getSerialNumber().equals( + givenCert.getSerialNumber())) { + break; + } + } + + return ((i == certArray.length) ? -1 : i); + } + + /** + * Returns the most recently issued signing certificate from an + * an array of certs. + * + * Assumptions: The certs are issued by the same CA + * + * @param certArray The array of certs. + * @param givenCert The certificate we are lokking for in the array. + * @return null if there is no recent cert or the most recent cert. + */ + public static X509CertImpl getRecentSigningCert(X509CertImpl[] certArray, + X509CertImpl currentCert) { + if (certArray == null || currentCert == null) + return null; + + // Sort the certificate array. + Arrays.sort(certArray, new CertDateCompare()); + + // Get the index of the current cert in the array. + int i = getCertIndex(certArray, currentCert); + + if (i < 0) + return null; + + X509CertImpl recentCert = currentCert; + + for (; i < certArray.length; i++) { + // Check if it is a signing cert and has its + // NotAfter later than the current cert. + if (isSigningCert(certArray[i]) && + certArray[i].getNotAfter().after(recentCert.getNotAfter())) + recentCert = certArray[i]; + } + return ((recentCert == currentCert) ? null : recentCert); + } + + public static String getCertType(X509CertImpl cert) { + StringBuffer sb = new StringBuffer(); + + if (isSigningCert(cert)) + sb.append("signing"); + if (isEncryptionCert(cert)) { + if (sb.length() > 0) + sb.append(" "); + sb.append("encryption"); + } + + // Is is object signing cert? + try { + CertificateExtensions extns = (CertificateExtensions) + cert.get(X509CertImpl.NAME + "." + + X509CertImpl.INFO + "." + + X509CertInfo.EXTENSIONS); + + if (extns != null) { + NSCertTypeExtension nsExtn = (NSCertTypeExtension) + extns.get(NSCertTypeExtension.NAME); + + if (nsExtn != null) { + String nsType = getNSExtensionInfo(nsExtn); + + if (nsType != null) { + if (sb.length() > 0) + sb.append(" "); + sb.append(nsType); + } + } + } + } catch (Exception e) { + } + return (sb.length() > 0) ? sb.toString() : null; + } + + public static String getNSExtensionInfo(NSCertTypeExtension nsExtn) { + StringBuffer sb = new StringBuffer(); + + try { + Boolean res; + + res = (Boolean) nsExtn.get(NSCertTypeExtension.SSL_CLIENT); + if (res.equals(Boolean.TRUE)) + sb.append(" ssl_client"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.SSL_SERVER); + if (res.equals(Boolean.TRUE)) + sb.append(" ssl_server"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.EMAIL); + if (res.equals(Boolean.TRUE)) + sb.append(" email"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.OBJECT_SIGNING); + if (res.equals(Boolean.TRUE)) + sb.append(" object_signing"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.SSL_CA); + if (res.equals(Boolean.TRUE)) + sb.append(" ssl_CA"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.EMAIL_CA); + if (res.equals(Boolean.TRUE)) + sb.append(" email_CA"); + res = (Boolean) nsExtn.get(NSCertTypeExtension.OBJECT_SIGNING_CA); + if (res.equals(Boolean.TRUE)) + sb.append(" object_signing_CA"); + } catch (Exception e) { + } + + return (sb.length() > 0) ? sb.toString() : null; + } + + public static byte[] readFromFile(String fileName) + throws IOException { + FileInputStream fin = new FileInputStream(fileName); + int available = fin.available(); + byte[] ba = new byte[available]; + int nRead = fin.read(ba); + + if (nRead != available) + throw new IOException("Error reading data from file: " + fileName); + fin.close(); + return ba; + } + + public static void storeInFile(String fileName, byte[] ba) + throws IOException { + FileOutputStream fout = new FileOutputStream(fileName); + + fout.write(ba); + fout.close(); + } + + public static String toMIME64(X509CertImpl cert) { + try { + return "-----BEGIN CERTIFICATE-----\n" + + Utils.base64encode(cert.getEncoded()) + + "-----END CERTIFICATE-----\n"; + } catch (CertificateException e) { + } + return null; + } + + public static X509Certificate mapCert(String mime64) + throws IOException { + mime64 = stripCertBrackets(mime64.trim()); + String newval = normalizeCertStr(mime64); + byte rawPub[] = Utils.base64decode(newval); + X509Certificate cert = null; + + try { + cert = new X509CertImpl(rawPub); + } catch (CertificateException e) { + } + return cert; + } + + public static X509Certificate[] mapCertFromPKCS7(String mime64) + throws IOException { + mime64 = stripCertBrackets(mime64.trim()); + String newval = normalizeCertStr(mime64); + byte rawPub[] = Utils.base64decode(newval); + PKCS7 p7 = null; + + try { + p7 = new PKCS7(rawPub); + return p7.getCertificates(); + } catch (Exception e) { + throw new IOException(e.toString()); + } + } + + public static X509CRL mapCRL(String mime64) + throws IOException { + mime64 = stripCRLBrackets(mime64.trim()); + String newval = normalizeCertStr(mime64); + byte rawPub[] = Utils.base64decode(newval); + X509CRL crl = null; + + try { + crl = new X509CRLImpl(rawPub); + } catch (Exception e) { + } + return crl; + } + + public static X509CRL mapCRL1(String mime64) + throws IOException { + mime64 = stripCRLBrackets(mime64.trim()); + byte rawPub[] = Utils.base64decode(mime64); + X509CRL crl = null; + + try { + crl = new X509CRLImpl(rawPub); + } catch (Exception e) { + throw new IOException(e.toString()); + } + return crl; + } + + public static String normalizeCertStr(String s) { + String val = ""; + + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '\n') { + continue; + } else if (s.charAt(i) == '\r') { + continue; + } else if (s.charAt(i) == '"') { + continue; + } else if (s.charAt(i) == ' ') { + continue; + } + val += s.charAt(i); + } + return val; + } + + public static String stripCRLBrackets(String s) { + if (s == null) { + return s; + } + if ((s.startsWith("-----BEGIN CERTIFICATE REVOCATION LIST-----")) && + (s.endsWith("-----END CERTIFICATE REVOCATION LIST-----"))) { + return (s.substring(43, (s.length() - 41))); + } + return s; + } + + /** + * strips out the begin and end certificate brackets + * + * @param s the string potentially bracketed with + * "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" + * @return string without the brackets + */ + public static String stripCertBrackets(String s) { + if (s == null) { + return s; + } + + if ((s.startsWith("-----BEGIN CERTIFICATE-----")) && + (s.endsWith("-----END CERTIFICATE-----"))) { + return (s.substring(27, (s.length() - 25))); + } + + // To support Thawte's header and footer + if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----")) && + (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) { + return (s.substring(35, (s.length() - 33))); + } + + return s; + } + + /** + * Returns a string that represents a cert's fingerprint. + * The fingerprint is a MD5 digest of the DER encoded certificate. + * + * @param cert Certificate to get the fingerprint of. + * @return a String that represents the cert's fingerprint. + */ + public static String getFingerPrint(Certificate cert) + throws CertificateEncodingException, NoSuchAlgorithmException { + byte certDer[] = cert.getEncoded(); + MessageDigest md = MessageDigest.getInstance("MD5"); + + md.update(certDer); + byte digestedCert[] = md.digest(); + PrettyPrintFormat pp = new PrettyPrintFormat(":"); + StringBuffer sb = new StringBuffer(); + + sb.append(pp.toHexString(digestedCert, 4, 20)); + return sb.toString(); + } + + /** + * Returns a string that has the certificate's fingerprint using + * MD5, MD2 and SHA1 hashes. + * A certificate's fingerprint is a hash digest of the DER encoded + * certificate. + * + * @param cert Certificate to get the fingerprints of. + * @return a String with fingerprints using the MD5, MD2 and SHA1 hashes. + * For example, + * + * <pre> + * MD2: 78:7E:D1:F9:3E:AF:50:18:68:A7:29:50:C3:21:1F:71 + * + * MD5: 0E:89:91:AC:40:50:F7:BE:6E:7B:39:4F:56:73:75:75 + * + * SHA1: DC:D9:F7:AF:E2:83:10:B2:F7:0A:77:E8:50:E2:F7:D1:15:9A:9D:00 + * </pre> + */ + public static String getFingerPrints(Certificate cert) + throws NoSuchAlgorithmException, CertificateEncodingException { + byte certDer[] = cert.getEncoded(); + /* + String[] hashes = new String[] {"MD2", "MD5", "SHA1"}; + String certFingerprints = ""; + PrettyPrintFormat pp = new PrettyPrintFormat(":"); + + for (int i = 0; i < hashes.length; i++) { + MessageDigest md = MessageDigest.getInstance(hashes[i]); + + md.update(certDer); + certFingerprints += " " + hashes[i] + ":" + + pp.toHexString(md.digest(), 6 - hashes[i].length()); + } + return certFingerprints; + */ + return getFingerPrints(certDer); + } + + /** + * Returns a string that has the certificate's fingerprint using + * MD5, MD2 and SHA1 hashes. + * A certificate's fingerprint is a hash digest of the DER encoded + * certificate. + * + * @param cert Certificate to get the fingerprints of. + * @return a String with fingerprints using the MD5, MD2 and SHA1 hashes. + * For example, + * + * <pre> + * MD2: 78:7E:D1:F9:3E:AF:50:18:68:A7:29:50:C3:21:1F:71 + * + * MD5: 0E:89:91:AC:40:50:F7:BE:6E:7B:39:4F:56:73:75:75 + * + * SHA1: DC:D9:F7:AF:E2:83:10:B2:F7:0A:77:E8:50:E2:F7:D1:15:9A:9D:00 + * </pre> + */ + public static String getFingerPrints(byte[] certDer) + throws NoSuchAlgorithmException/*, CertificateEncodingException*/{ + // byte certDer[] = cert.getEncoded(); + String[] hashes = new String[] { "MD2", "MD5", "SHA1", "SHA256", "SHA512" }; + String certFingerprints = ""; + PrettyPrintFormat pp = new PrettyPrintFormat(":"); + + for (int i = 0; i < hashes.length; i++) { + MessageDigest md = MessageDigest.getInstance(hashes[i]); + + md.update(certDer); + certFingerprints += hashes[i] + ":\n" + + pp.toHexString(md.digest(), 8, 16); + } + return certFingerprints; + } + + /** + * Check if a object identifier in string form is valid, + * that is a string in the form n.n.n.n and der encode and decode-able. + * + * @param attrName attribute name (from the configuration file) + * @param value object identifier string. + */ + public static ObjectIdentifier checkOID(String attrName, String value) + throws EBaseException { + String msg = "value must be a object identifier in the form n.n.n.n"; + String msg1 = "not a valid object identifier."; + ObjectIdentifier oid; + + try { + oid = ObjectIdentifier.getObjectIdentifier(value); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + attrName, msg)); + } + + // if the OID isn't valid (ex. n.n) the error isn't caught til + // encoding time leaving a bad request in the request queue. + try { + DerOutputStream derOut = new DerOutputStream(); + + derOut.putOID(oid); + new ObjectIdentifier(new DerInputStream(derOut.toByteArray())); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + attrName, msg1)); + } + return oid; + } + + public static String trimB64E(String b64e) { + StringBuffer tmp = new StringBuffer(""); + String line = null; + StringTokenizer tokens = new StringTokenizer(b64e, "\n"); + + while (tokens.hasMoreTokens()) { + line = tokens.nextToken(); + line = line.trim(); + tmp.append(line.trim()); + if (tokens.hasMoreTokens()) + tmp.append("\n"); + } + + return tmp.toString(); + } + + /* + * verify a certificate by its nickname + * returns true if it verifies; false if any not + */ + public static boolean verifySystemCertByNickname(String nickname, String certusage) { + boolean r = true; + CertificateUsage cu = null; + cu = getCertificateUsage(certusage); + int ccu = 0; + + if (cu == null) { + CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + + nickname + " with unsupported certusage =" + certusage); + return false; + } + + if (certusage == "") + CMS.debug("CertUtils: verifySystemCertByNickname(): required certusage not defined, getting current certusage"); + CMS.debug("CertUtils: verifySystemCertByNickname(): calling isCertValid()"); + try { + CryptoManager cm = CryptoManager.getInstance(); + if (cu.getUsage() != CryptoManager.CertificateUsage.CheckAllUsages.getUsage()) { + if (cm.isCertValid(nickname, true, cu)) { + r = true; + CMS.debug("CertUtils: verifySystemCertByNickname() passed:" + nickname); + } else { + CMS.debug("CertUtils: verifySystemCertByNickname() failed:" + nickname); + r = false; + } + } else { + // find out about current cert usage + ccu = cm.isCertValid(nickname, true); + if (ccu == CertificateUsage.basicCertificateUsages) { + /* cert is good for nothing */ + r = false; + CMS.debug("CertUtils: verifySystemCertByNickname() failed: cert is good for nothing:" + nickname); + } else { + r = true; + CMS.debug("CertUtils: verifySystemCertByNickname() passed:" + nickname); + + if ((ccu & CryptoManager.CertificateUsage.SSLServer.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is SSLServer"); + if ((ccu & CryptoManager.CertificateUsage.SSLClient.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is SSLClient"); + if ((ccu & CryptoManager.CertificateUsage.SSLServerWithStepUp.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is SSLServerWithStepUp"); + if ((ccu & CryptoManager.CertificateUsage.SSLCA.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is SSLCA"); + if ((ccu & CryptoManager.CertificateUsage.EmailSigner.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is EmailSigner"); + if ((ccu & CryptoManager.CertificateUsage.EmailRecipient.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is EmailRecipient"); + if ((ccu & CryptoManager.CertificateUsage.ObjectSigner.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is ObjectSigner"); + if ((ccu & CryptoManager.CertificateUsage.UserCertImport.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is UserCertImport"); + if ((ccu & CryptoManager.CertificateUsage.VerifyCA.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is VerifyCA"); + if ((ccu & CryptoManager.CertificateUsage.ProtectedObjectSigner.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is ProtectedObjectSigner"); + if ((ccu & CryptoManager.CertificateUsage.StatusResponder.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is StatusResponder"); + if ((ccu & CryptoManager.CertificateUsage.AnyCA.getUsage()) != 0) + CMS.debug("CertUtils: verifySystemCertByNickname(): cert is AnyCA"); + } + } + } catch (Exception e) { + CMS.debug("CertUtils: verifySystemCertByNickname() failed: " + + e.toString()); + r = false; + } + return r; + } + + /* + * verify a certificate by its tag name + * returns true if it verifies; false if any not + */ + public static boolean verifySystemCertByTag(String tag) { + String auditMessage = null; + IConfigStore config = CMS.getConfigStore(); + boolean r = true; + try { + String subsysType = config.getString("cs.type", ""); + if (subsysType.equals("")) { + CMS.debug("CertUtils: verifySystemCertByTag() cs.type not defined in CS.cfg. System certificates verification not done"); + r = false; + } + subsysType = toLowerCaseSubsystemType(subsysType); + if (subsysType == null) { + CMS.debug("CertUtils: verifySystemCerts() invalid cs.type in CS.cfg. System certificates verification not done"); + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + r = false; + return r; + } + String nickname = config.getString(subsysType + ".cert." + tag + ".nickname", ""); + if (nickname.equals("")) { + CMS.debug("CertUtils: verifySystemCertByTag() nickname for cert tag " + tag + " undefined in CS.cfg"); + r = false; + } + String certusage = config.getString(subsysType + ".cert." + tag + ".certusage", ""); + if (certusage.equals("")) { + CMS.debug("CertUtils: verifySystemCertByTag() certusage for cert tag " + + tag + " undefined in CS.cfg, getting current certificate usage"); + } + r = verifySystemCertByNickname(nickname, certusage); + if (r == true) { + // audit here + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.SUCCESS, + nickname); + + audit(auditMessage); + } else { + // audit here + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + nickname); + + audit(auditMessage); + } + } catch (Exception e) { + CMS.debug("CertUtils: verifySystemCertsByTag() failed: " + + e.toString()); + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + r = false; + } + + return r; + } + + /* + * returns CertificateUsage mapping to JSS + */ + public static CertificateUsage getCertificateUsage(String certusage) { + CertificateUsage cu = null; + if ((certusage == null) || certusage.equals("")) + cu = CryptoManager.CertificateUsage.CheckAllUsages; + else if (certusage.equalsIgnoreCase("CheckAllUsages")) + cu = CryptoManager.CertificateUsage.CheckAllUsages; + else if (certusage.equalsIgnoreCase("SSLServer")) + cu = CryptoManager.CertificateUsage.SSLServer; + else if (certusage.equalsIgnoreCase("SSLServerWithStepUp")) + cu = CryptoManager.CertificateUsage.SSLServerWithStepUp; + else if (certusage.equalsIgnoreCase("SSLClient")) + cu = CryptoManager.CertificateUsage.SSLClient; + else if (certusage.equalsIgnoreCase("SSLCA")) + cu = CryptoManager.CertificateUsage.SSLCA; + else if (certusage.equalsIgnoreCase("AnyCA")) + cu = CryptoManager.CertificateUsage.AnyCA; + else if (certusage.equalsIgnoreCase("StatusResponder")) + cu = CryptoManager.CertificateUsage.StatusResponder; + else if (certusage.equalsIgnoreCase("ObjectSigner")) + cu = CryptoManager.CertificateUsage.ObjectSigner; + else if (certusage.equalsIgnoreCase("UserCertImport")) + cu = CryptoManager.CertificateUsage.UserCertImport; + else if (certusage.equalsIgnoreCase("ProtectedObjectSigner")) + cu = CryptoManager.CertificateUsage.ProtectedObjectSigner; + else if (certusage.equalsIgnoreCase("VerifyCA")) + cu = CryptoManager.CertificateUsage.VerifyCA; + else if (certusage.equalsIgnoreCase("EmailSigner")) + cu = CryptoManager.CertificateUsage.EmailSigner; + + return cu; + } + + /* + * goes through all system certs and check to see if they are good + * and audit the result + * returns true if all verifies; false if any not + */ + public static boolean verifySystemCerts() { + String auditMessage = null; + IConfigStore config = CMS.getConfigStore(); + boolean verifyResult = true; + boolean r = true; /* the final return value */ + try { + String subsysType = config.getString("cs.type", ""); + if (subsysType.equals("")) { + CMS.debug("CertUtils: verifySystemCerts() cs.type not defined in CS.cfg. System certificates verification not done"); + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + return false; + } + subsysType = toLowerCaseSubsystemType(subsysType); + if (subsysType == null) { + CMS.debug("CertUtils: verifySystemCerts() invalid cs.type in CS.cfg. System certificates verification not done"); + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + return false; + } + String certlist = config.getString(subsysType + ".cert.list", ""); + if (certlist.equals("")) { + CMS.debug("CertUtils: verifySystemCerts() " + + subsysType + ".cert.list not defined in CS.cfg. System certificates verification not done"); + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + return false; + } + StringTokenizer tokenizer = new StringTokenizer(certlist, ","); + while (tokenizer.hasMoreTokens()) { + String tag = tokenizer.nextToken(); + tag = tag.trim(); + CMS.debug("CertUtils: verifySystemCerts() cert tag=" + tag); + verifyResult = verifySystemCertByTag(tag); + if (verifyResult == false) + r = false; //r captures the value for final return + } + } catch (Exception e) { + // audit here + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_CIMC_CERT_VERIFICATION, + ILogger.SYSTEM_UID, + ILogger.FAILURE, + ""); + + audit(auditMessage); + r = false; + CMS.debug("CertUtils: verifySystemCerts():" + e.toString()); + } + return r; + } + + public static String toLowerCaseSubsystemType(String s) { + String x = null; + if (s.equalsIgnoreCase("CA")) { + x = "ca"; + } else if (s.equalsIgnoreCase("KRA")) { + x = "kra"; + } else if (s.equalsIgnoreCase("OCSP")) { + x = "ocsp"; + } else if (s.equalsIgnoreCase("TKS")) { + x = "tks"; + } + + return x; + } + + /** + * Signed Audit Log + * This method is called to store messages to the signed audit log. + * + * @param msg signed audit log message + */ + private static void audit(String msg) { + // in this case, do NOT strip preceding/trailing whitespace + // from passed-in String parameters + if (mSignedAuditLogger == null) { + return; + } + + mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, + ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, + msg); + } + +} diff --git a/base/common/src/com/netscape/cmscore/cert/CertificatePair.java b/base/common/src/com/netscape/cmscore/cert/CertificatePair.java new file mode 100644 index 000000000..b8f958be5 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CertificatePair.java @@ -0,0 +1,281 @@ +// --- 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.cmscore.cert; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import org.mozilla.jss.asn1.ANY; +import org.mozilla.jss.asn1.ASN1Value; +import org.mozilla.jss.asn1.InvalidBERException; +import org.mozilla.jss.asn1.SEQUENCE; +import org.mozilla.jss.asn1.Tag; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.cert.ICrossCertPairSubsystem; + +/** + * This class implements CertificatePair used for Cross Certification + * + * @author cfu + * @version $Revision$, $Date$ + */ +public class CertificatePair implements ASN1Value { + private byte[] mForward; // cert cross-siged by another CA + private byte[] mReverse; // subordinate cert signed by this CA + private static final Tag TAG = SEQUENCE.TAG; + + /** + * construct a CertificatePair. It doesn't matter which is + * forward and which is reverse in the parameters. It will figure + * it out + * + * @param cert1 one X509Certificate + * @param cert2 one X509Certificate + */ + public CertificatePair(X509Certificate cert1, X509Certificate cert2) + throws EBaseException { + if ((cert1 == null) || (cert2 == null)) + throw new EBaseException("CertificatePair: both certs can not be null"); + debug("in CertificatePair()"); + boolean rightOrder = certOrders(cert1, cert2); + + try { + if (rightOrder == false) { + mForward = cert2.getEncoded(); + mReverse = cert1.getEncoded(); + } else { + mForward = cert1.getEncoded(); + mReverse = cert2.getEncoded(); + } + } catch (CertificateException e) { + throw new EBaseException("CertificatePair: constructor failed:" + e.toString()); + } + } + + /** + * construct a CertificatePair. It doesn't matter which is + * forward and which is reverse in the parameters. It will figure + * it out + * + * @param cert1 one certificate byte array + * @param cert2 one certificate byte array + */ + public CertificatePair(byte[] cert1, byte[] cert2) + throws EBaseException { + if ((cert1 == null) || (cert2 == null)) + throw new EBaseException("CertificatePair: both certs can not be null"); + boolean rightOrder = certOrders(cert1, cert2); + + if (rightOrder == false) { + mForward = cert2; + mReverse = cert1; + } else { + mForward = cert1; + mReverse = cert2; + } + } + + /* + * returns true if c1 is forward and cert2 is reverse + * returns false if c2 is forward and cert1 is reverse + */ + private boolean certOrders(X509Certificate c1, X509Certificate c2) + throws EBaseException { + debug("in certOrders() with X509Cert"); + + ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem("ca"); + X509Certificate caCert = (X509Certificate) ca.getCACert(); + + debug("got this caCert"); + // reverse cert is the one signed by this ca + // more check really should be done here regarding the + // validity of the two certs...later + + /* It looks the DN's returned are not normalized and fail + * comparison + + if ((c1.getIssuerDN().equals((Object) caCert.getSubjectDN()))) + debug("myCA signed c1"); + else { + debug("c1 issuerDN="+c1.getIssuerDN().toString()); + debug("myCA subjectDN="+caCert.getSubjectDN().toString()); + } + + if(caCert.getSubjectDN().equals((Object) c2.getSubjectDN())) + debug("myCA subject == c2 subject"); + else { + debug("caCert subjectDN="+caCert.getSubjectDN().toString()); + debug("c2 subjectDN="+c2.getSubjectDN().toString()); + } + + if ((c2.getIssuerDN().equals((Object) caCert.getSubjectDN()))) + debug("myCA signed c2"); + else { + debug("c2 issuerDN="+c1.getIssuerDN().toString()); + debug("myCA subjectDN="+caCert.getSubjectDN().toString()); + } + + if(caCert.getSubjectDN().equals((Object) c1.getSubjectDN())) + debug("myCA subject == c1 subject"); + else { + debug("caCert subjectDN="+caCert.getSubjectDN().toString()); + debug("c1 subjectDN="+c1.getSubjectDN().toString()); + } + + if ((c1.getIssuerDN().equals((Object) caCert.getSubjectDN())) + && (caCert.getSubjectDN().equals((Object) c2.getSubjectDN()))) + + { + return false; + } else if ((c2.getIssuerDN().equals((Object) caCert.getSubjectDN())) + && (caCert.getSubjectDN().equals((Object) c1.getSubjectDN()))) + { + return true; + } else { + throw new EBaseException("CertificatePair: need correct forward and reverse relationship to construct CertificatePair"); + } + */ + + /* + * my other attempt: + * one of the certs has to share the same public key as this + * CA, and that will be the "forward" cert; the other one is + * assumed to be the "reverse" cert + */ + byte[] caCertBytes = caCert.getPublicKey().getEncoded(); + + if (caCertBytes != null) + debug("got cacert public key bytes length=" + caCertBytes.length); + else { + debug("cacert public key bytes null"); + throw new EBaseException( + "CertificatePair: certOrders() fails to get this CA's signing certificate public key encoded"); + } + + byte[] c1Bytes = c1.getPublicKey().getEncoded(); + + if (c1Bytes != null) + debug("got c1 public key bytes length=" + c1Bytes.length); + else { + debug("c1 cert public key bytes length null"); + throw new EBaseException("CertificatePair::certOrders() public key bytes are of length null"); + } + + byte[] c2Bytes = c2.getPublicKey().getEncoded(); + + if (c2Bytes != null) + debug("got c2 public key bytes length=" + c2Bytes.length); + else + debug("c2 cert public key bytes length null"); + + if (byteArraysAreEqual(c1Bytes, caCertBytes)) { + debug("c1 has same public key as this ca"); + return true; + } else if (byteArraysAreEqual(c2Bytes, caCertBytes)) { + debug("c2 has same public key as this ca"); + + return false; + } else { + debug("neither c1 nor c2 public key matches with this ca"); + throw new EBaseException( + "CertificatePair: need correct forward and reverse relationship to construct CertificatePair"); + } + } + + /** + * compares contents two byte arrays returning true if exactly same. + */ + public boolean byteArraysAreEqual(byte[] a, byte[] b) { + debug("in byteArraysAreEqual()"); + if (a.length != b.length) { + debug("exiting byteArraysAreEqual(): false"); + return false; + } + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + debug("exiting byteArraysAreEqual(): false"); + return false; + } + } + debug("exiting byteArraysAreEqual(): true"); + return true; + } + + /* + * returns true if cert1 is forward and cert2 is reverse + * returns false if cert2 is forward and cert1 is reverse + */ + private boolean certOrders(byte[] cert1, byte[] cert2) + throws EBaseException { + debug("in certOrders() with byte[]"); + ICrossCertPairSubsystem ccps = + (ICrossCertPairSubsystem) CMS.getSubsystem("CrossCertPair"); + X509Certificate c1 = null; + X509Certificate c2 = null; + + try { + c1 = ccps.byteArray2X509Cert(cert1); + c2 = ccps.byteArray2X509Cert(cert2); + } catch (CertificateException e) { + throw new EBaseException("CertificatePair: certOrders() failed:" + e.toString()); + } + return certOrders(c1, c2); + } + + public void encode(OutputStream os) throws IOException { + encode(TAG, os); + } + + public void encode(Tag implicitTag, OutputStream os) throws IOException { + SEQUENCE seq = new SEQUENCE(); + + if (mForward != null) { + try { + ANY any = new ANY(mForward); + + seq.addElement(any); + } catch (InvalidBERException e) { + debug("encode error:" + e.toString()); + } + } + if (mReverse != null) { + try { + ANY any = new ANY(mReverse); + + seq.addElement(any); + } catch (InvalidBERException e) { + debug("encode error:" + e.toString()); + } + } + + seq.encode(implicitTag, os); + } + + public Tag getTag() { + return TAG; + } + + private void debug(String msg) { + CMS.debug("CertifiatePair: " + msg); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/CrlCachePrettyPrint.java b/base/common/src/com/netscape/cmscore/cert/CrlCachePrettyPrint.java new file mode 100644 index 000000000..6d838b70d --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CrlCachePrettyPrint.java @@ -0,0 +1,262 @@ +// --- 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.cmscore.cert; + +import java.text.DateFormat; +import java.util.Iterator; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TimeZone; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.Extension; +import netscape.security.x509.RevokedCertificate; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.ICRLPrettyPrint; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Andrew Wnuk + * @version $Revision$, $Date$ + */ +public class CrlCachePrettyPrint implements ICRLPrettyPrint { + + /*========================================================== + * constants + *==========================================================*/ + private final static String CUSTOM_LOCALE = "Custom"; + + /*========================================================== + * variables + *==========================================================*/ + private ICRLIssuingPoint mIP = null; + private PrettyPrintFormat pp = null; + + /*========================================================== + * constructors + *==========================================================*/ + + public CrlCachePrettyPrint(ICRLIssuingPoint ip) { + mIP = ip; + pp = new PrettyPrintFormat(":"); + } + + /*========================================================== + * public methods + *==========================================================*/ + + /** + * This method return string representation of the certificate + * revocation list in predefined format using specified client + * local. I18N Support. + * + * @param clientLocale Locale to be used for localization + * @return string representation of the certificate + */ + public String toString(Locale clientLocale) { + return toString(clientLocale, 0, 0, 0); + } + + public String toString(Locale clientLocale, long crlSize, long pageStart, long pageSize) { + + //get I18N resources + ResourceBundle resource = ResourceBundle.getBundle( + PrettyPrintResources.class.getName()); + DateFormat dateFormater = DateFormat.getDateTimeInstance( + DateFormat.FULL, DateFormat.FULL, clientLocale); + //get timezone and timezone ID + String tz = " "; + String tzid = " "; + + StringBuffer sb = new StringBuffer(); + + try { + sb.append(pp.indent(4) + resource.getString( + PrettyPrintResources.TOKEN_CRL) + "\n"); + sb.append(pp.indent(8) + resource.getString( + PrettyPrintResources.TOKEN_DATA) + "\n"); + + String signingAlgorithm = mIP.getLastSigningAlgorithm(); + if (signingAlgorithm != null) { + sb.append(pp.indent(12) + resource.getString( + PrettyPrintResources.TOKEN_SIGALG) + + signingAlgorithm + "\n"); + } + sb.append(pp.indent(12) + resource.getString( + PrettyPrintResources.TOKEN_ISSUER) + + ((ICertificateAuthority) (mIP.getCertificateAuthority())) + .getCRLX500Name().toString() + "\n"); + // Format thisUpdate + String thisUpdate = dateFormater.format(mIP.getLastUpdate()); + + // get timezone and timezone ID + if (TimeZone.getDefault() != null) { + tz = TimeZone.getDefault().getDisplayName( + TimeZone.getDefault().inDaylightTime(mIP.getLastUpdate()), + TimeZone.SHORT, + clientLocale); + tzid = TimeZone.getDefault().getID(); + } + // Specify ThisUpdate + if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { + // Do NOT append timezone ID + sb.append(pp.indent(12) + + resource.getString( + PrettyPrintResources.TOKEN_THIS_UPDATE) + + thisUpdate + + "\n"); + } else { + // Append timezone ID + sb.append(pp.indent(12) + + resource.getString( + PrettyPrintResources.TOKEN_THIS_UPDATE) + + thisUpdate + + " " + tzid + "\n"); + } + // Check for presence of NextUpdate + if (mIP.getNextUpdate() != null) { + // Format nextUpdate + String nextUpdate = dateFormater.format(mIP.getNextUpdate()); + + // re-get timezone (just in case it is different . . .) + if (TimeZone.getDefault() != null) { + tz = TimeZone.getDefault().getDisplayName( + TimeZone.getDefault().inDaylightTime(mIP.getNextUpdate()), + TimeZone.SHORT, + clientLocale); + } + // Specify NextUpdate + if (tz.equals(tzid) || tzid.equals(CUSTOM_LOCALE)) { + // Do NOT append timezone ID + sb.append(pp.indent(12) + + resource.getString( + PrettyPrintResources.TOKEN_NEXT_UPDATE) + + nextUpdate + + "\n"); + } else { + // Append timezone ID + sb.append(pp.indent(12) + + resource.getString( + PrettyPrintResources.TOKEN_NEXT_UPDATE) + + nextUpdate + + " " + tzid + "\n"); + } + } + + if (crlSize > 0 && pageStart == 0 && pageSize == 0) { + sb.append(pp.indent(12) + resource.getString( + PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES) + crlSize + "\n"); + } else if ((crlSize == 0 && pageStart == 0 && pageSize == 0) || + (crlSize > 0 && pageStart > 0 && pageSize > 0)) { + sb.append(pp.indent(12) + resource.getString( + PrettyPrintResources.TOKEN_REVOKED_CERTIFICATES)); + long upperLimit = crlSize; + if (crlSize > 0 && pageStart > 0 && pageSize > 0) { + upperLimit = (pageStart + pageSize - 1 > crlSize) ? crlSize : pageStart + pageSize - 1; + sb.append("" + pageStart + "-" + upperLimit + " of " + crlSize); + } else { + pageStart = 1; + sb.append("" + crlSize); + } + sb.append("\n"); + + Set<RevokedCertificate> revokedCerts = + mIP.getRevokedCertificates((int) (pageStart - 1), (int) upperLimit); + + if (revokedCerts != null) { + Iterator<RevokedCertificate> i = revokedCerts.iterator(); + long l = 1; + + while ((i.hasNext()) && ((crlSize == 0) || (upperLimit - pageStart + 1 >= l))) { + RevokedCertificate revokedCert = i.next(); + + if ((crlSize == 0) || (upperLimit - pageStart + 1 >= l)) { + sb.append(pp.indent(16) + resource.getString( + PrettyPrintResources.TOKEN_SERIAL) + "0x" + + revokedCert.getSerialNumber().toString(16).toUpperCase() + "\n"); + String revocationDate = + dateFormater.format(revokedCert.getRevocationDate()); + + // re-get timezone + // (just in case it is different . . .) + if (TimeZone.getDefault() != null) { + tz = TimeZone.getDefault().getDisplayName( + TimeZone.getDefault().inDaylightTime( + revokedCert.getRevocationDate()), + TimeZone.SHORT, + clientLocale); + } + // Specify revocationDate + if (tz.equals(tzid) || + tzid.equals(CUSTOM_LOCALE)) { + // Do NOT append timezone ID + sb.append(pp.indent(16) + + resource.getString( + PrettyPrintResources.TOKEN_REVOCATION_DATE) + + revocationDate + + "\n"); + } else { + // Append timezone ID + sb.append(pp.indent(16) + + resource.getString( + PrettyPrintResources.TOKEN_REVOCATION_DATE) + + revocationDate + + " " + tzid + "\n"); + } + if (revokedCert.hasExtensions()) { + sb.append(pp.indent(16) + resource.getString( + PrettyPrintResources.TOKEN_EXTENSIONS) + "\n"); + CRLExtensions crlExtensions = revokedCert.getExtensions(); + + if (crlExtensions != null) { + for (int k = 0; k < crlExtensions.size(); k++) { + Extension ext = (Extension) crlExtensions.elementAt(k); + ExtPrettyPrint extpp = new ExtPrettyPrint(ext, 20); + + sb.append(extpp.toString()); + } + } + } + } + l++; + } + } else if (mIP.isCRLCacheEnabled() && mIP.isCRLCacheEmpty()) { + sb.append("\n" + pp.indent(16) + resource.getString( + PrettyPrintResources.TOKEN_CACHE_IS_EMPTY) + "\n\n"); + } else { + sb.append("\n" + pp.indent(16) + resource.getString( + PrettyPrintResources.TOKEN_CACHE_NOT_AVAILABLE) + "\n\n"); + } + } + + } catch (Exception e) { + sb.append("\n\n" + pp.indent(4) + resource.getString( + PrettyPrintResources.TOKEN_DECODING_ERROR) + "\n\n"); + CMS.debug("Exception=" + e.toString()); + CMS.debugStackTrace(); + } + + return sb.toString(); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/CrlPrettyPrint.java b/base/common/src/com/netscape/cmscore/cert/CrlPrettyPrint.java new file mode 100644 index 000000000..1d6048c8d --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CrlPrettyPrint.java @@ -0,0 +1,36 @@ +// --- 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.cmscore.cert; + +import netscape.security.x509.X509CRLImpl; + +import com.netscape.certsrv.base.ICRLPrettyPrint; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Andrew Wnuk + * @version $Revision$, $Date$ + */ +public class CrlPrettyPrint extends netscape.security.util.CrlPrettyPrint implements ICRLPrettyPrint { + + public CrlPrettyPrint(X509CRLImpl crl) { + super(crl); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/CrossCertPairSubsystem.java b/base/common/src/com/netscape/cmscore/cert/CrossCertPairSubsystem.java new file mode 100644 index 000000000..8d8a337c5 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/CrossCertPairSubsystem.java @@ -0,0 +1,505 @@ +// --- 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.cmscore.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Enumeration; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPModification; +import netscape.ldap.LDAPModificationSet; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPv2; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.cert.ICrossCertPairSubsystem; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.publish.IXcertPublisherProcessor; +import com.netscape.cmscore.ldapconn.LdapBoundConnFactory; + +/** + * Subsystem for handling cross certificate pairing and publishing + * Intended use: + * <ul> + * <li>when signing a subordinate CA cert which is intended to be part of the crossCertificatePair + * <li>when this ca submits a request (with existing CA signing key material to another ca for cross-signing + * </ul> + * In both cases, administrator needs to "import" the crossSigned + * certificates via the admin console. When importCert() is called, + * the imported cert will be stored in the internal db + * first until it's pairing cert shows up. + * If it happens that the above two cases finds its pairing + * cert already there, then a CertifiatePair is created and put + * in the internal db "crosscertificatepair;binary" attribute + * + * @author cfu + * @version $Revision$, $Date$ + */ +public class CrossCertPairSubsystem implements ICrossCertPairSubsystem { + + public static final String ID = "CrossCertPair"; + public static final String DN_XCERTS = "cn=crossCerts"; + public static final String LDAP_ATTR_CA_CERT = "caCertificate;binary"; + public static final String LDAP_ATTR_XCERT_PAIR = "crossCertificatePair;binary"; + protected static final String PROP_LDAP = "ldap"; + protected static final String PROP_BASEDN = "basedn"; + + protected IConfigStore mConfig = null; + protected LdapBoundConnFactory mLdapConnFactory = null; + protected String mBaseDN = null; + protected ICertificateAuthority mCa = null; + protected IPublisherProcessor mPublisherProcessor = null; + + private String mId = ID; + private ILogger mLogger = null; + + public CrossCertPairSubsystem() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return mId; + } + + public void setId(String id) throws EBaseException { + mId = id; + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + try { + mConfig = config; + mLogger = CMS.getLogger(); + mCa = (ICertificateAuthority) CMS.getSubsystem("ca"); + mPublisherProcessor = mCa.getPublisherProcessor(); + + // initialize LDAP connection factory + IConfigStore ldapConfig = mConfig.getSubStore(PROP_LDAP); + + if (ldapConfig == null) { + log(ILogger.LL_MISCONF, + CMS.getLogMessage("CMSCORE_DBS_CONF_ERROR", + PROP_LDAP)); + return; + } + + mBaseDN = ldapConfig.getString(PROP_BASEDN, null); + + mLdapConnFactory = new LdapBoundConnFactory(); + + if (mLdapConnFactory != null) + mLdapConnFactory.init(ldapConfig); + else { + log(ILogger.LL_MISCONF, + CMS.getLogMessage("CMSCORE_DBS_CONF_ERROR", + PROP_LDAP)); + return; + } + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + return; + throw e; + } + } + + /** + * "import" the CA cert cross-signed by another CA (potentially a + * bridge CA) into internal ldap db. + * the imported cert will be stored in the internal db + * first until it's pairing cert shows up. + * If it happens that it finds its pairing + * cert already there, then a CertifiatePair is created and put + * in the internal db "crosscertificatepair;binary" attribute + * + * @param certBytes cert in byte array to be imported + */ + public void importCert(byte[] certBytes) throws EBaseException { + debug("importCert(byte[])"); + X509Certificate cert = null; + + try { + cert = byteArray2X509Cert(certBytes); + } catch (CertificateException e) { + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + + } + + importCert((Object) cert); + } + + /** + * "import" the CA cert cross-signed by another CA (potentially a + * bridge CA) into internal ldap db. + * the imported cert will be stored in the internal db + * first until it's pairing cert shows up. + * If it happens that it finds its pairing + * cert already there, then a CertifiatePair is created and put + * in the internal db "crosscertificatepair;binary" attribute + * + * @param certBytes cert in byte array to be imported + */ + public synchronized void importCert(Object certObj) throws EBaseException { + if (!(certObj instanceof X509Certificate)) + throw new IllegalArgumentException("Illegal arg to publish"); + + debug("in importCert(Object)"); + X509Certificate cert = (X509Certificate) certObj; + // check to see if this is a valid cross-signed ca cert: + // 1. does cert2 share the same key pair as this CA's signing + // cert + // 2. does cert2's subject match this CA's subject? + // 3. other valididity checks: is this a ca cert? Is this + // cert still valid? If the issuer is not yet trusted, let it + // be. + + // get certs from internal db to see if we find a pair + LDAPConnection conn = null; + + try { + conn = getConn(); + LDAPSearchResults res = conn.search(mBaseDN, LDAPv2.SCOPE_SUB, + DN_XCERTS, null, false); + + if (res.hasMoreElements()) { + log(ILogger.LL_INFO, "ldap search found " + DN_XCERTS); + + LDAPEntry entry = (LDAPEntry) res.nextElement(); + LDAPAttribute caCerts = entry.getAttribute(LDAP_ATTR_CA_CERT); + LDAPAttribute certPairs = entry.getAttribute(LDAP_ATTR_XCERT_PAIR); + + if (caCerts == null) { + debug("no existing ca certs, just import"); + addCAcert(conn, cert.getEncoded()); + return; + } + + @SuppressWarnings("unchecked") + Enumeration<byte[]> en = caCerts.getByteValues(); + + if ((en == null) || (en.hasMoreElements() == false)) { + debug("1st potential xcert"); + addCAcert(conn, cert.getEncoded()); + debug("potential cross ca cert added to crossCerts entry successfully"); + return; + } + byte[] val = null; + boolean match = false; + + while (en.hasMoreElements()) { + val = en.nextElement(); + debug("val =" + val.length); + if (val.length == 0) { + continue; + } else { + X509Certificate inCert = byteArray2X509Cert(val); + + if (arePair(inCert, cert)) { + // found a pair,form xcert, write to + // crossCertificatePair attr, remove from + // caCertificate attr, and publish if so configured + debug("found a pair!"); + CertificatePair cp = new + // CertificatePair(inCert.getEncoded(), cert.getEncoded()); + CertificatePair(inCert, cert); + + addXCertPair(conn, certPairs, cp); + deleteCAcert(conn, inCert.getEncoded()); + // found a match, get out + match = true; + break; + } + } + } //while + if (match == false) { + // don't find a pair, add it into + // caCertificate attr for later pairing + // opportunities + debug("didn't find a pair!"); + addCAcert(conn, cert.getEncoded()); + debug("potential cross ca cert added to crossCerts entry successfully"); + } + + } else { + log(ILogger.LL_INFO, "ldap search found no " + DN_XCERTS); + } + } catch (IOException e) { + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + } catch (LDAPException e) { + log(ILogger.LL_FAILURE, "exception: " + e.toString()); + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + } catch (ELdapException e) { + log(ILogger.LL_FAILURE, "exception: " + e.toString()); + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, "exception: " + e.toString()); + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + } finally { + try { + returnConn(conn); + } catch (ELdapException e) { + log(ILogger.LL_FAILURE, "exception: " + e.toString()); + throw new EBaseException("CrossCertPairSubsystem: importCert() failed:" + e.toString()); + } + } + debug("importCert(Object) completed"); + } + + /** + * are cert1 and cert2 cross-signed certs? + * + * @param cert1 the cert for comparison in our internal db + * @param cert2 the cert that's being considered + */ + protected boolean arePair(X509Certificate cert1, X509Certificate cert2) { + // 1. does cert1's issuer match cert2's subject? + // 2. does cert2's issuer match cert1's subject? + if ((cert1.getIssuerDN().equals((Object) cert2.getSubjectDN())) + && (cert2.getIssuerDN().equals((Object) cert1.getSubjectDN()))) + return true; + else + return false; + } + + public X509Certificate byteArray2X509Cert(byte[] certBytes) + throws CertificateException { + debug("in bytearray2X509Cert()"); + ByteArrayInputStream inStream = new + ByteArrayInputStream(certBytes); + + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + + X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream); + + debug("done bytearray2X509Cert()"); + return cert; + } + + public synchronized void addXCertPair(LDAPConnection conn, + LDAPAttribute certPairs, CertificatePair pair) + throws LDAPException, IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + pair.encode(bos); + + if (ByteValueExists(certPairs, bos.toByteArray()) == true) { + debug("cross cert pair exists in internal db, don't add again"); + return; + } + + // add certificatePair + LDAPModificationSet modSet = new LDAPModificationSet(); + + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_ATTR_XCERT_PAIR, bos.toByteArray())); + conn.modify(DN_XCERTS + "," + mBaseDN, modSet); + } + + /** + * checks if a byte attribute has a certain value. + */ + public static boolean ByteValueExists(LDAPAttribute attr, byte[] bval) { + if (attr == null) { + return false; + } + @SuppressWarnings("unchecked") + Enumeration<byte[]> vals = attr.getByteValues(); + byte[] val = null; + + while (vals.hasMoreElements()) { + val = vals.nextElement(); + if (val.length == 0) + continue; + if (byteArraysAreEqual(val, bval)) { + return true; + } + } + return false; + } + + /** + * compares contents two byte arrays returning true if exactly same. + */ + static public boolean byteArraysAreEqual(byte[] a, byte[] b) { + debug("in byteArraysAreEqual()"); + if (a.length != b.length) { + debug("exiting byteArraysAreEqual(): false"); + return false; + } + for (int i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + debug("exiting byteArraysAreEqual(): false"); + return false; + } + } + debug("exiting byteArraysAreEqual(): true"); + return true; + } + + public synchronized void addCAcert(LDAPConnection conn, byte[] certEnc) + throws LDAPException { + LDAPModificationSet modSet = new + LDAPModificationSet(); + + modSet.add(LDAPModification.ADD, + new LDAPAttribute(LDAP_ATTR_CA_CERT, certEnc)); + conn.modify(DN_XCERTS + "," + mBaseDN, modSet); + } + + public synchronized void deleteCAcert(LDAPConnection conn, byte[] certEnc) + throws LDAPException { + LDAPModificationSet modSet = new + LDAPModificationSet(); + + modSet.add(LDAPModification.DELETE, + new LDAPAttribute(LDAP_ATTR_CA_CERT, certEnc)); + conn.modify(DN_XCERTS + "," + mBaseDN, modSet); + } + + /** + * publish all cert pairs, if publisher is on + */ + public synchronized void publishCertPairs() throws EBaseException { + LDAPConnection conn = null; + + if ((mPublisherProcessor == null) || + !mPublisherProcessor.enabled()) + return; + + try { + conn = getConn(); + // search in internal db for xcerts + LDAPSearchResults res = conn.search(mBaseDN, LDAPv2.SCOPE_SUB, + DN_XCERTS, null, false); + + debug("trying to publish cert pairs, if any"); + if ((res == null) || (res.hasMoreElements() == false)) { + debug("no cross cert pairs to publish"); + return; + } + + if (res.hasMoreElements()) { + log(ILogger.LL_INFO, "ldap search found " + DN_XCERTS); + + LDAPEntry entry = (LDAPEntry) res.nextElement(); + LDAPAttribute xcerts = entry.getAttribute(LDAP_ATTR_XCERT_PAIR); + + if (xcerts == null) { + debug("no cross cert pairs to publish"); + return; + } + + @SuppressWarnings("unchecked") + Enumeration<byte[]> en = xcerts.getByteValues(); + + if ((en == null) || (en.hasMoreElements() == false)) { + debug("publishCertPair found no pairs in internal db"); + return; + } + byte[] val = null; + + while (en.hasMoreElements()) { + val = en.nextElement(); + debug("val =" + val.length); + if (val.length == 0) { + continue; + } else { + try { + //found a cross cert pair, publish if we could + IXcertPublisherProcessor xp = null; + + xp = (IXcertPublisherProcessor) mPublisherProcessor; + xp.publishXCertPair(val); + } catch (Exception e) { + throw new EBaseException("CrossCertPairSubsystem: publishCertPairs() failed:" + + e.toString()); + } + } + }// while + }//if + } catch (Exception e) { + throw new EBaseException("CrossCertPairSubsystem: publishCertPairs() failed:" + e.toString()); + } + } + + protected LDAPConnection getConn() throws ELdapException { + if (mLdapConnFactory != null) + return mLdapConnFactory.getConn(); + + return null; + } + + protected void returnConn(LDAPConnection conn) throws ELdapException { + if (mLdapConnFactory != null) + mLdapConnFactory.returnConn(conn); + } + + public void startup() throws EBaseException { + } + + /** + * Stops this system. + */ + public synchronized void shutdown() { + mCa = null; + mPublisherProcessor = null; + if (mLdapConnFactory != null) { + try { + mLdapConnFactory.reset(); + } catch (ELdapException e) { + CMS.debug("CrossCertPairSubsystem shutdown exception: " + e.toString()); + } + } + mLdapConnFactory = null; + } + + /* + * Returns the root configuration storage of this system. + * <P> + * + * @return configuration store of this subsystem + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + protected void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, + ILogger.S_XCERT, level, msg); + } + + private static void debug(String msg) { + CMS.debug("CrossCertPairSubsystem: " + msg); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/ExtPrettyPrint.java b/base/common/src/com/netscape/cmscore/cert/ExtPrettyPrint.java new file mode 100644 index 000000000..5f5c66a48 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/ExtPrettyPrint.java @@ -0,0 +1,36 @@ +// --- 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.cmscore.cert; + +import netscape.security.x509.Extension; + +import com.netscape.certsrv.base.IExtPrettyPrint; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Andrew Wnuk + * @version $Revision$, $Date$ + */ +public class ExtPrettyPrint extends netscape.security.util.ExtPrettyPrint implements IExtPrettyPrint { + + public ExtPrettyPrint(Extension ext, int indentSize) { + super(ext, indentSize); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/OidLoaderSubsystem.java b/base/common/src/com/netscape/cmscore/cert/OidLoaderSubsystem.java new file mode 100644 index 000000000..dfd7dbab8 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/OidLoaderSubsystem.java @@ -0,0 +1,189 @@ +// --- 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.cmscore.cert; + +import java.security.cert.CertificateException; +import java.util.Enumeration; + +import netscape.security.extensions.CertificateRenewalWindowExtension; +import netscape.security.extensions.CertificateScopeOfUseExtension; +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.DeltaCRLIndicatorExtension; +import netscape.security.x509.FreshestCRLExtension; +import netscape.security.x509.HoldInstructionExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.IssuingDistributionPointExtension; +import netscape.security.x509.OIDMap; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.cmscore.util.Debug; + +/** + * + * @author stevep + * @version $Revision + */ +public class OidLoaderSubsystem implements ISubsystem { + + private IConfigStore mConfig = null; + public static final String ID = "oidmap"; + private String mId = ID; + + private static final String PROP_OID = "oid"; + private static final String PROP_CLASS = "class"; + + /** + * + */ + private OidLoaderSubsystem() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return mId; + } + + public void setId(String id) throws EBaseException { + mId = id; + } + + // singleton enforcement + + private static OidLoaderSubsystem mInstance = new OidLoaderSubsystem(); + + public static OidLoaderSubsystem getInstance() { + return mInstance; + } + + private static final int CertType_data[] = { 2, 16, 840, 1, 113730, 1, 1 }; + + /** + * Identifies the particular public key used to sign the certificate. + */ + public static final ObjectIdentifier CertType_Id = new + ObjectIdentifier(CertType_data); + + private static final String[][] oidMapEntries = new String[][] { + { NSCertTypeExtension.class.getName(), + CertType_Id.toString(), + NSCertTypeExtension.NAME }, + { CertificateRenewalWindowExtension.class.getName(), + CertificateRenewalWindowExtension.ID.toString(), + CertificateRenewalWindowExtension.NAME }, + { CertificateScopeOfUseExtension.class.getName(), + CertificateScopeOfUseExtension.ID.toString(), + CertificateScopeOfUseExtension.NAME }, + { DeltaCRLIndicatorExtension.class.getName(), + DeltaCRLIndicatorExtension.OID, + DeltaCRLIndicatorExtension.NAME }, + { HoldInstructionExtension.class.getName(), + HoldInstructionExtension.OID, + HoldInstructionExtension.NAME }, + { InvalidityDateExtension.class.getName(), + InvalidityDateExtension.OID, + InvalidityDateExtension.NAME }, + { IssuingDistributionPointExtension.class.getName(), + IssuingDistributionPointExtension.OID, + IssuingDistributionPointExtension.NAME }, + { FreshestCRLExtension.class.getName(), + FreshestCRLExtension.OID, + FreshestCRLExtension.NAME }, + }; + + /** + * Initializes this subsystem with the given + * configuration store. + * It first initializes resident subsystems, + * and it loads and initializes loadable + * subsystem specified in the configuration + * store. + * <P> + * Note that individual subsystem should be initialized in a separated thread if it has dependency on the + * initialization of other subsystems. + * <P> + * + * @param owner owner of this subsystem + * @param config configuration store + */ + public synchronized void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + if (Debug.ON) { + Debug.trace("OIDLoaderSubsystem started"); + } + mConfig = config; + + Enumeration<String> names = mConfig.getSubStoreNames(); + + // load static (build-in) extensions + + for (int i = 0; i < oidMapEntries.length; i++) { + try { + OIDMap.addAttribute(oidMapEntries[i][0], + oidMapEntries[i][1], + oidMapEntries[i][2]); + } catch (Exception e) { + } + } + + // load dynamic extensions + + while (names.hasMoreElements()) { + String substorename = (String) names.nextElement(); + IConfigStore substore = mConfig.getSubStore(substorename); + + try { + String oidname = substore.getString(PROP_OID); + String classname = substore.getString(PROP_CLASS); + + OIDMap.addAttribute(classname, + oidname, + substorename); + } catch (EPropertyNotFound e) { + // Log error + } catch (CertificateException e) { + // log error + } + } + } + + public void startup() throws EBaseException { + } + + /** + * Stops this system. + */ + public synchronized void shutdown() { + } + + /* + * Returns the root configuration storage of this system. + * <P> + * + * @return configuration store of this subsystem + */ + public IConfigStore getConfigStore() { + return mConfig; + } + +} diff --git a/base/common/src/com/netscape/cmscore/cert/PrettyPrintFormat.java b/base/common/src/com/netscape/cmscore/cert/PrettyPrintFormat.java new file mode 100644 index 000000000..669200575 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/PrettyPrintFormat.java @@ -0,0 +1,165 @@ +// --- 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.cmscore.cert; + +import com.netscape.certsrv.base.IPrettyPrintFormat; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Andrew Wnuk + * @version $Revision$, $Date$ + */ +public class PrettyPrintFormat implements IPrettyPrintFormat { + + /*========================================================== + * variables + *==========================================================*/ + private String mSeparator = ""; + private int mIndentSize = 0; + private int mLineLen = 0; + + /*========================================================== + * constants + * + *==========================================================*/ + private final static String spaces = + " " + + " " + + " " + + " " + + " "; + + /*========================================================== + * constructors + *==========================================================*/ + + public PrettyPrintFormat(String separator) { + mSeparator = separator; + } + + public PrettyPrintFormat(String separator, int lineLen) { + mSeparator = separator; + mLineLen = lineLen; + } + + public PrettyPrintFormat(String separator, int lineLen, int indentSize) { + mSeparator = separator; + mLineLen = lineLen; + mIndentSize = indentSize; + } + + /*========================================================== + * Private methods + *==========================================================*/ + + /*========================================================== + * public methods + *==========================================================*/ + + /** + * Provide white space indention + * stevep - speed improvements. Factor of 10 improvement + * + * @param numSpace number of white space to be returned + * @return white spaces + */ + public String indent(int size) { + return spaces.substring(0, size); + } + + private static final char[] hexdigits = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' + }; + + /** + * Convert Byte Array to Hex String Format + * stevep - speedup by factor of 8 + * + * @param byte array of data to hexify + * @param indentSize number of spaces to prepend before each line + * @param lineLen number of bytes to output on each line (0 + * means: put everything on one line + * @param separator the first character of this string will be used as + * the separator between bytes. + * @return string representation + */ + + public String toHexString(byte[] in, int indentSize, + int lineLen, String separator) { + + if (in == null) return ""; + + StringBuffer sb = new StringBuffer(); + int hexCount = 0; + char c[]; + int j = 0; + + if (lineLen == 0) { + c = new char[in.length * 3 + 1]; + } else { + c = new char[lineLen * 3 + 1]; + } + + char sep = separator.charAt(0); + + sb.append(indent(indentSize)); + for (int i = 0; i < in.length; i++) { + if (lineLen > 0 && hexCount == lineLen) { + c[j++] = '\n'; + sb.append(c, 0, j); + sb.append(indent(indentSize)); + hexCount = 0; + j = 0; + } + byte x = in[i]; + + // output hex digits to buffer + c[j++] = hexdigits[(char) ((x >> 4) & 0xf)]; + c[j++] = hexdigits[(char) (x & 0xf)]; + + // if not last char, output separator + if (i != in.length - 1) { + c[j++] = sep; + } + + hexCount++; + } + if (j > 0) { + c[j++] = '\n'; + sb.append(c, 0, j); + } + // sb.append("\n"); + + return sb.toString(); + } + + public String toHexString(byte[] in, int indentSize, int lineLen) { + return toHexString(in, indentSize, lineLen, mSeparator); + } + + public String toHexString(byte[] in, int indentSize) { + return toHexString(in, indentSize, mLineLen); + } + + public String toHexString(byte[] in) { + return toHexString(in, mIndentSize); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/PrettyPrintResources.java b/base/common/src/com/netscape/cmscore/cert/PrettyPrintResources.java new file mode 100644 index 000000000..361f50b47 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/PrettyPrintResources.java @@ -0,0 +1,293 @@ +// --- 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.cmscore.cert; + +import java.util.ListResourceBundle; + +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.x509.KeyUsageExtension; + +/** + * Resource Boundle for the Pretty Print + * + * @author Jack Pan-Chen + * @version $Revision$, $Date$ + */ + +public class PrettyPrintResources extends ListResourceBundle { + + /** + * Returns content + */ + public Object[][] getContents() { + return contents; + } + + /** + * Constants. The suffix represents the number of + * possible parameters. + */ + + //certificate pretty print + public final static String TOKEN_CERTIFICATE = "tokenCertificate"; + public final static String TOKEN_DATA = "tokenData"; + public final static String TOKEN_VERSION = "tokenVersion"; + public final static String TOKEN_SERIAL = "tokenSerial"; + public final static String TOKEN_SIGALG = "tokenSignatureAlgorithm"; + public final static String TOKEN_ISSUER = "tokenIssuer"; + public final static String TOKEN_VALIDITY = "tokenValidity"; + public final static String TOKEN_NOT_BEFORE = "tokenNotBefore"; + public final static String TOKEN_NOT_AFTER = "tokenNotAfter"; + public final static String TOKEN_SUBJECT = "tokenSubject"; + public final static String TOKEN_SPKI = "tokenSPKI"; + public final static String TOKEN_ALGORITHM = "tokenAlgorithm"; + public final static String TOKEN_PUBLIC_KEY = "tokenPublicKey"; + public final static String TOKEN_PUBLIC_KEY_MODULUS = "tokenPublicKeyModulus"; + public final static String TOKEN_PUBLIC_KEY_EXPONENT = "tokenPublicKeyExponent"; + public final static String TOKEN_EXTENSIONS = "tokenExtensions"; + public final static String TOKEN_SIGNATURE = "tokenSignature"; + + //extension pretty print + public final static String TOKEN_YES = "tokenYes"; + public final static String TOKEN_NO = "tokenNo"; + public final static String TOKEN_IDENTIFIER = "tokenIdentifier"; + public final static String TOKEN_CRITICAL = "tokenCritical"; + public final static String TOKEN_VALUE = "tokenValue"; + + //specific extension token + public final static String TOKEN_KEY_TYPE = "tokenKeyType"; + public final static String TOKEN_CERT_TYPE = "tokenCertType"; + public final static String TOKEN_SKI = "tokenSKI"; + public final static String TOKEN_AKI = "tokenAKI"; + public final static String TOKEN_ACCESS_DESC = "tokenAccessDesc"; + public final static String TOKEN_OCSP_NOCHECK = "tokenOcspNoCheck"; + public final static String TOKEN_EXTENDED_KEY_USAGE = "tokenExtendedKeyUsage"; + public final static String TOKEN_PRIVATE_KEY_USAGE = "tokenPrivateKeyUsage"; + public final static String TOKEN_PRESENCE_SERVER = "tokenPresenceServer"; + public final static String TOKEN_AIA = "tokenAIA"; + public final static String TOKEN_KEY_USAGE = "tokenKeyUsage"; + public final static String TOKEN_CERT_USAGE = "tokenCertUsage"; + public final static String TOKEN_KEY_ID = "tokenKeyId"; + public final static String TOKEN_AUTH_NAME = "tokenAuthName"; + + public final static String TOKEN_CRL = "tokenCRL"; + public final static String TOKEN_THIS_UPDATE = "tokenThisUpdate"; + public final static String TOKEN_NEXT_UPDATE = "tokenNextUpdate"; + public final static String TOKEN_REVOKED_CERTIFICATES = "revokedCerts"; + public final static String TOKEN_REVOCATION_DATE = "revocationDate"; + + public final static String TOKEN_REVOCATION_REASON = "revocationReason"; + public final static String TOKEN_REASON = "reason"; + + public final static String TOKEN_BASIC_CONSTRAINTS = "basicConstraints"; + public final static String TOKEN_NAME_CONSTRAINTS = "tokenNameConstraints"; + public final static String TOKEN_NSC_COMMENT = "tokenNSCComment"; + public final static String TOKEN_IS_CA = "isCA"; + public final static String TOKEN_PATH_LEN = "pathLen"; + public final static String TOKEN_PATH_LEN_UNLIMITED = "pathLenUnlimited"; + public final static String TOKEN_PATH_LEN_UNDEFINED = "pathLenUndefined"; + public final static String TOKEN_PATH_LEN_INVALID = "pathLenInvalid"; + + public final static String TOKEN_CRL_NUMBER = "CRLNumber"; + public final static String TOKEN_NUMBER = "Number"; + + public final static String TOKEN_DELTA_CRL_INDICATOR = "DeltaCRLIndicator"; + public final static String TOKEN_BASE_CRL_NUMBER = "BaseCRLNumber"; + + public final static String TOKEN_CERT_SCOPE_OF_USE = "CertificateScopeOfUse"; + public final static String TOKEN_SCOPE_OF_USE = "ScopeOfUse"; + public final static String TOKEN_PORT = "Port"; + + public final static String TOKEN_ISSUER_ALT_NAME = "IssuerAlternativeName"; + public final static String TOKEN_ISSUER_NAMES = "IssuerNames"; + + public final static String TOKEN_SUBJECT_ALT_NAME = "SubjectAlternativeName"; + public final static String TOKEN_SUBJECT_NAME = "SubjectName"; + + public final static String TOKEN_DECODING_ERROR = "decodingError"; + + public final static String TOKEN_FRESHEST_CRL_EXT = "FreshestCRL"; + + public final static String TOKEN_CRL_DP_EXT = "CRLDistributionPoints"; + public final static String TOKEN_CRLDP_NUMPOINTS = "CRLDP_NUMPOINTS"; + public final static String TOKEN_CRLDP_POINTN = "CRLDP_POINTN"; + public final static String TOKEN_CRLDP_DISTPOINT = "CRLDP_DISTPOINT"; + public final static String TOKEN_CRLDP_REASONS = "CRLDP_REASONS"; + public final static String TOKEN_CRLDP_CRLISSUER = "CRLDP_CRLISSUER"; + + public final static String TOKEN_ISSUING_DIST_POINT = "IssuingDistributionPoint"; + public final static String TOKEN_DIST_POINT_NAME = "DistributionPointName"; + public final static String TOKEN_FULL_NAME = "FullName"; + public final static String TOKEN_RELATIVE_NAME = "NameRelativeToCRLIssuer"; + public final static String TOKEN_ONLY_USER_CERTS = "OnlyContainsUserCerts"; + public final static String TOKEN_ONLY_CA_CERTS = "OnlyContainsCACerts"; + public final static String TOKEN_ONLY_SOME_REASONS = "OnlySomeReasons"; + public final static String TOKEN_INDIRECT_CRL = "IndirectCRL"; + + public final static String TOKEN_INVALIDITY_DATE = "invalidityDate"; + public final static String TOKEN_DATE_OF_INVALIDITY = "dateOfInvalidity"; + + public final static String TOKEN_CERTIFICATE_ISSUER = "CertificateIssuer"; + + public final static String TOKEN_HOLD_INSTRUCTION = "HoldInstruction"; + public final static String TOKEN_HOLD_INSTRUCTION_CODE = "HoldInstructionCode"; + public final static String TOKEN_POLICY_CONSTRAINTS = "PolicyConstraints"; + public final static String TOKEN_POLICY_MAPPINGS = "PolicyMappings"; + public final static String TOKEN_SUBJECT_DIR_ATTR = "SubjectDirectoryAttributes"; + + // policy constriants extension fields + public final static String TOKEN_INHIBIT_POLICY_MAPPING = "inhibitPolicyMapping"; + public final static String TOKEN_REQUIRE_EXPLICIT_POLICY = "requireExplicitPolicy"; + + // policy mappings extension fields + public final static String TOKEN_MAPPINGS = "mappings"; + public final static String TOKEN_MAP = "map"; + public final static String TOKEN_ISSUER_DOMAIN_POLICY = "issuerDomainPolicy"; + public final static String TOKEN_SUBJECT_DOMAIN_POLICY = "subjectDomainPolicy"; + + // subject directory attribute fields + public final static String TOKEN_ATTRIBUTES = "Attributes"; + public final static String TOKEN_ATTRIBUTE = "Attribute"; + public final static String TOKEN_VALUES = "Values"; + + // field values + public final static String TOKEN_NOT_SET = "notSet"; + public final static String TOKEN_NONE = "none"; + + public final static String TOKEN_CACHE_NOT_AVAILABLE = "cacheNotAvailable"; + public final static String TOKEN_CACHE_IS_EMPTY = "cacheIsEmpty"; + + //Tokens should have blank_space as trailer + static final Object[][] contents = { + { TOKEN_CERTIFICATE, "Certificate: " }, + { TOKEN_DATA, "Data: " }, + { TOKEN_VERSION, "Version: " }, + { TOKEN_SERIAL, "Serial Number: " }, + { TOKEN_SIGALG, "Signature Algorithm: " }, + { TOKEN_ISSUER, "Issuer: " }, + { TOKEN_VALIDITY, "Validity: " }, + { TOKEN_NOT_BEFORE, "Not Before: " }, + { TOKEN_NOT_AFTER, "Not After: " }, + { TOKEN_SUBJECT, "Subject: " }, + { TOKEN_SPKI, "Subject Public Key Info: " }, + { TOKEN_ALGORITHM, "Algorithm: " }, + { TOKEN_PUBLIC_KEY, "Public Key: " }, + { TOKEN_PUBLIC_KEY_MODULUS, "Public Key Modulus: " }, + { TOKEN_PUBLIC_KEY_EXPONENT, "Exponent: " }, + { TOKEN_EXTENSIONS, "Extensions: " }, + { TOKEN_SIGNATURE, "Signature: " }, + { TOKEN_YES, "yes " }, + { TOKEN_NO, "no " }, + { TOKEN_IDENTIFIER, "Identifier: " }, + { TOKEN_CRITICAL, "Critical: " }, + { TOKEN_VALUE, "Value: " }, + { TOKEN_KEY_TYPE, "Key Type " }, + { TOKEN_CERT_TYPE, "Netscape Certificate Type " }, + { TOKEN_SKI, "Subject Key Identifier " }, + { TOKEN_AKI, "Authority Key Identifier " }, + { TOKEN_ACCESS_DESC, "Access Description: " }, + { TOKEN_OCSP_NOCHECK, "OCSP NoCheck: " }, + { TOKEN_EXTENDED_KEY_USAGE, "Extended Key Usage: " }, + { TOKEN_PRIVATE_KEY_USAGE, "Private Key Usage: " }, + { TOKEN_PRESENCE_SERVER, "Presence Server: " }, + { TOKEN_AIA, "Authority Info Access: " }, + { TOKEN_KEY_USAGE, "Key Usage: " }, + { KeyUsageExtension.DIGITAL_SIGNATURE, "Digital Signature " }, + { KeyUsageExtension.NON_REPUDIATION, "Non Repudiation " }, + { KeyUsageExtension.KEY_ENCIPHERMENT, "Key Encipherment " }, + { KeyUsageExtension.DATA_ENCIPHERMENT, "Data Encipherment " }, + { KeyUsageExtension.KEY_AGREEMENT, "Key Agreement " }, + { KeyUsageExtension.KEY_CERTSIGN, "Key CertSign " }, + { KeyUsageExtension.CRL_SIGN, "Crl Sign " }, + { KeyUsageExtension.ENCIPHER_ONLY, "Encipher Only " }, + { KeyUsageExtension.DECIPHER_ONLY, "Decipher Only " }, + { TOKEN_CERT_USAGE, "Certificate Usage: " }, + { NSCertTypeExtension.SSL_CLIENT, "SSL Client " }, + { NSCertTypeExtension.SSL_SERVER, "SSL Server " }, + { NSCertTypeExtension.EMAIL, "Secure Email " }, + { NSCertTypeExtension.OBJECT_SIGNING, "Object Signing " }, + { NSCertTypeExtension.SSL_CA, "SSL CA " }, + { NSCertTypeExtension.EMAIL_CA, "Secure Email CA " }, + { NSCertTypeExtension.OBJECT_SIGNING_CA, "ObjectSigning CA " }, + { TOKEN_KEY_ID, "Key Identifier: " }, + { TOKEN_AUTH_NAME, "Authority Name: " }, + { TOKEN_CRL, "Certificate Revocation List: " }, + { TOKEN_THIS_UPDATE, "This Update: " }, + { TOKEN_NEXT_UPDATE, "Next Update: " }, + { TOKEN_REVOKED_CERTIFICATES, "Revoked Certificates: " }, + { TOKEN_REVOCATION_DATE, "Revocation Date: " }, + { TOKEN_REVOCATION_REASON, "Revocation Reason " }, + { TOKEN_REASON, "Reason: " }, + { TOKEN_BASIC_CONSTRAINTS, "Basic Constraints " }, + { TOKEN_NAME_CONSTRAINTS, "Name Constraints " }, + { TOKEN_NSC_COMMENT, "Netscape Comment " }, + { TOKEN_IS_CA, "Is CA: " }, + { TOKEN_PATH_LEN, "Path Length Constraint: " }, + { TOKEN_PATH_LEN_UNLIMITED, "UNLIMITED" }, + { TOKEN_PATH_LEN_UNDEFINED, "UNDEFINED" }, + { TOKEN_PATH_LEN_INVALID, "INVALID" }, + { TOKEN_CRL_NUMBER, "CRL Number " }, + { TOKEN_NUMBER, "Number: " }, + { TOKEN_DELTA_CRL_INDICATOR, "Delta CRL Indicator " }, + { TOKEN_BASE_CRL_NUMBER, "Base CRL Number: " }, + { TOKEN_CERT_SCOPE_OF_USE, "Certificate Scope of Use " }, + { TOKEN_SCOPE_OF_USE, "Scope of Use: " }, + { TOKEN_PORT, "Port: " }, + { TOKEN_ISSUER_ALT_NAME, "Issuer Alternative Name " }, + { TOKEN_ISSUER_NAMES, "Issuer Names: " }, + { TOKEN_SUBJECT_ALT_NAME, "Subject Alternative Name " }, + { TOKEN_DECODING_ERROR, "Decoding Error" }, + { TOKEN_FRESHEST_CRL_EXT, "Freshest CRL " }, + { TOKEN_CRL_DP_EXT, "CRL Distribution Points " }, + { TOKEN_CRLDP_NUMPOINTS, "Number of Points: " }, + { TOKEN_CRLDP_POINTN, "Point " }, + { TOKEN_CRLDP_DISTPOINT, "Distribution Point: " }, + { TOKEN_CRLDP_REASONS, "Reason Flags: " }, + { TOKEN_CRLDP_CRLISSUER, "CRL Issuer: " }, + { TOKEN_ISSUING_DIST_POINT, "Issuing Distribution Point " }, + { TOKEN_DIST_POINT_NAME, "Distribution Point: " }, + { TOKEN_FULL_NAME, "Full Name: " }, + { TOKEN_RELATIVE_NAME, "Name Relative To CRL Issuer: " }, + { TOKEN_ONLY_USER_CERTS, "Only Contains User Certificates: " }, + { TOKEN_ONLY_CA_CERTS, "Only Contains CA Certificates: " }, + { TOKEN_ONLY_SOME_REASONS, "Only Some Reasons: " }, + { TOKEN_INDIRECT_CRL, "Indirect CRL: " }, + { TOKEN_INVALIDITY_DATE, "Invalidity Date " }, + { TOKEN_DATE_OF_INVALIDITY, "Invalidity Date: " }, + { TOKEN_CERTIFICATE_ISSUER, "Certificate Issuer " }, + { TOKEN_HOLD_INSTRUCTION, "Hold Instruction Code " }, + { TOKEN_HOLD_INSTRUCTION_CODE, "Hold Instruction Code: " }, + { TOKEN_POLICY_CONSTRAINTS, "Policy Constraints " }, + { TOKEN_INHIBIT_POLICY_MAPPING, "Inhibit Policy Mapping: " }, + { TOKEN_REQUIRE_EXPLICIT_POLICY, "Require Explicit Policy: " }, + { TOKEN_POLICY_MAPPINGS, "Policy Mappings " }, + { TOKEN_MAPPINGS, "Mappings: " }, + { TOKEN_MAP, "Map " }, + { TOKEN_ISSUER_DOMAIN_POLICY, "Issuer Domain Policy: " }, + { TOKEN_SUBJECT_DOMAIN_POLICY, "Subject Domain Policy: " }, + { TOKEN_SUBJECT_DIR_ATTR, "Subject Directory Attributes " }, + { TOKEN_ATTRIBUTES, "Attributes:" }, + { TOKEN_ATTRIBUTE, "Attribute " }, + { TOKEN_VALUES, "Values: " }, + { TOKEN_NOT_SET, "not set" }, + { TOKEN_NONE, "none" }, + { TOKEN_CACHE_NOT_AVAILABLE, "CRL cache is not available. " }, + { TOKEN_CACHE_IS_EMPTY, "CRL cache is empty. " }, + }; + +} diff --git a/base/common/src/com/netscape/cmscore/cert/PubKeyPrettyPrint.java b/base/common/src/com/netscape/cmscore/cert/PubKeyPrettyPrint.java new file mode 100644 index 000000000..9ea581812 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/PubKeyPrettyPrint.java @@ -0,0 +1,35 @@ +// --- 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.cmscore.cert; + +import java.security.PublicKey; + +/** + * This class will display the certificate content in predefined + * format. + * + * @author Jack Pan-Chen + * @author Andrew Wnuk + * @version $Revision$, $Date$ + */ +public class PubKeyPrettyPrint extends netscape.security.util.PubKeyPrettyPrint { + + public PubKeyPrettyPrint(PublicKey key) { + super(key); + } +} diff --git a/base/common/src/com/netscape/cmscore/cert/X500NameSubsystem.java b/base/common/src/com/netscape/cmscore/cert/X500NameSubsystem.java new file mode 100644 index 000000000..de5e233c9 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/cert/X500NameSubsystem.java @@ -0,0 +1,285 @@ +// --- 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.cmscore.cert; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; + +import netscape.security.util.DerValue; +import netscape.security.util.ObjectIdentifier; +import netscape.security.x509.AVAValueConverter; +import netscape.security.x509.DirStrConverter; +import netscape.security.x509.X500NameAttrMap; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmscore.util.Debug; + +/** + * Subsystem for configuring X500Name related things. + * It is used for the following. + * <ul> + * <li>Add X500Name (string to oid) maps for attributes that are not supported by default. + * <li>Specify an order for encoding Directory Strings other than the default. + * </ul> + * + * @author lhsiao + * @version $Revision$ + */ +public class X500NameSubsystem implements ISubsystem { + + private IConfigStore mConfig = null; + public static final String ID = "X500Name"; + private String mId = ID; + + private static final String PROP_DIR_STR_ENCODING_ORDER = "directoryStringEncodingOrder"; + + private static final String PROP_ATTR = "attr"; + private static final String PROP_OID = "oid"; + private static final String PROP_CLASS = "class"; + + private X500NameSubsystem() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return mId; + } + + public void setId(String id) throws EBaseException { + mId = id; + } + + // singleton enforcement + + private static X500NameSubsystem mInstance = new X500NameSubsystem(); + + public static X500NameSubsystem getInstance() { + return mInstance; + } + + /** + * Initializes this subsystem with the given configuration store. + * All paramters are optional. + * <ul> + * <li>Change encoding order of Directory Strings: + * + * <pre> + * X500Name.directoryStringEncodingOrder=order seperated by commas + * For example: Printable,BMPString,UniversalString. + * </pre> + * + * Possible values are: + * <ul> + * <li>Printable + * <li>IA5String + * <li>UniversalString + * <li>BMPString + * <li>UTF8String + * </ul> + * <p> + * <li>Add X500Name attributes: + * + * <pre> + * X500Name.attr.attribute-name.oid=n.n.n.n + * X500Name.attr.attribute-name.class=value converter class + * </pre> + * + * The value converter class converts a string to a ASN.1 value. It must implement + * netscape.security.x509.AVAValueConverter interface. Converter classes provided in CMS are: + * + * <pre> + * netscape.security.x509.PrintableConverter - + * Converts to a Printable String value. String must have only + * printable characters. + * netscape.security.x509.IA5StringConverter - + * Converts to a IA5String value. String must have only IA5String + * characters. + * netscape.security.x509.DirStrConverter - + * Converts to a Directory (v3) String. String is expected to + * be in Directory String format according to rfc2253. + * netscape.security.x509.GenericValueConverter - + * Converts string character by character in the following order + * from smaller character sets to broadest character set. + * Printable, IA5String, BMPString, Universal String. + * </pre> + * + * </ul> + * <P> + * + * @param owner owner of this subsystem + * @param config configuration store + */ + public synchronized void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mLogger = CMS.getLogger(); + if (Debug.ON) { + Debug.trace(ID + " started"); + } + mConfig = config; + + // get order for encoding directory strings if any. + setDirStrEncodingOrder(); + + // load x500 name maps + loadX500NameAttrMaps(); + } + + /** + * Loads X500Name String to attribute maps. + * Called from init. + */ + private void loadX500NameAttrMaps() + throws EBaseException { + X500NameAttrMap globalMap = X500NameAttrMap.getDefault(); + IConfigStore attrSubStore = mConfig.getSubStore(PROP_ATTR); + Enumeration<String> attrNames = attrSubStore.getSubStoreNames(); + + while (attrNames.hasMoreElements()) { + String name = (String) attrNames.nextElement(); + IConfigStore substore = attrSubStore.getSubStore(name); + String oidString = substore.getString(PROP_OID); + ObjectIdentifier oid = CertUtils.checkOID(name, oidString); + String className = substore.getString(PROP_CLASS); + + AVAValueConverter convClass = null; + + try { + convClass = (AVAValueConverter) + Class.forName(className).newInstance(); + } catch (Exception e) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_LOAD_CLASS_FAILED", className, e.toString())); + } + globalMap.addNameOID(name, oid, convClass); + if (Debug.ON) { + Debug.trace(ID + ": Loaded " + name + " " + oid + " " + className); + } + } + } + + /** + * Set directory string encoding order. + * Called from init(). + */ + private void setDirStrEncodingOrder() + throws EBaseException { + String order = mConfig.getString(PROP_DIR_STR_ENCODING_ORDER, null); + + if (order == null || order.length() == 0) // nothing. + return; + StringTokenizer toker = new StringTokenizer(order, ", \t"); + int numTokens = toker.countTokens(); + + if (numTokens == 0) { + String msg = "must be a list of DER tag names seperated by commas."; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CERT_DIR_STRING", PROP_DIR_STR_ENCODING_ORDER)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_DIR_STR_ENCODING_ORDER, msg)); + } + + byte[] tags = new byte[numTokens]; + + for (int i = 0; toker.hasMoreTokens(); i++) { + String nextTag = (String) toker.nextToken(); + + try { + tags[i] = derStr2Tag(nextTag); + } catch (IllegalArgumentException e) { + String msg = "unknown DER tag '" + nextTag + "'."; + + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CERT_UNKNOWN_TAG", PROP_DIR_STR_ENCODING_ORDER, nextTag)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTR_VALUE", + PROP_DIR_STR_ENCODING_ORDER, msg)); + } + } + + DirStrConverter.setDefEncodingOrder(tags); + } + + private static String PRINTABLESTRING = "PrintableString"; + private static String IA5STRING = "IA5String"; + private static String VISIBLESTRING = "VisibleString"; + private static String T61STRING = "T61String"; + private static String BMPSTRING = "BMPString"; + private static String UNIVERSALSTRING = "UniversalString"; + private static String UFT8STRING = "UTF8String"; + private static Hashtable<String, Byte> mDerStr2TagHash = new Hashtable<String, Byte>(); + + static { + mDerStr2TagHash.put( + PRINTABLESTRING, Byte.valueOf(DerValue.tag_PrintableString)); + mDerStr2TagHash.put( + IA5STRING, Byte.valueOf(DerValue.tag_IA5String)); + mDerStr2TagHash.put( + VISIBLESTRING, Byte.valueOf(DerValue.tag_VisibleString)); + mDerStr2TagHash.put( + T61STRING, Byte.valueOf(DerValue.tag_T61String)); + mDerStr2TagHash.put( + BMPSTRING, Byte.valueOf(DerValue.tag_BMPString)); + mDerStr2TagHash.put( + UNIVERSALSTRING, Byte.valueOf(DerValue.tag_UniversalString)); + mDerStr2TagHash.put( + UFT8STRING, Byte.valueOf(DerValue.tag_UTF8String)); + } + + private byte derStr2Tag(String s) { + if (s == null || s.length() == 0) + throw new IllegalArgumentException(); + Byte tag = mDerStr2TagHash.get(s); + + if (tag == null) + throw new IllegalArgumentException(); + return tag.byteValue(); + } + + public void startup() throws EBaseException { + } + + /** + * Stops this system. + */ + public synchronized void shutdown() { + } + + /* + * Returns the root configuration storage of this system. + * <P> + * + * @return configuration store of this subsystem + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + protected ILogger mLogger = null; + + protected void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, + ILogger.S_ADMIN, level, msg); + } + +} |