All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.globus.gsi.bc.BouncyCastleUtil Maven / Gradle / Ivy

/*
 * Copyright 1999-2010 University of Chicago
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 *
 * See the License for the specific language governing permissions and limitations under the License.
 */
package org.globus.gsi.bc;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;

import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.security.auth.x500.X500Principal;

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERBoolean;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.DERString;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.TBSCertificateStructure;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.globus.gsi.GSIConstants;
import org.globus.gsi.TrustedCertificates;
import org.globus.gsi.TrustedCertificatesUtil;
import org.globus.gsi.proxy.ext.ProxyCertInfo;
import org.globus.gsi.proxy.ext.ProxyPolicy;
import org.globus.gsi.util.ProxyCertificateUtil;
import org.globus.util.I18n;

// COMMENT: BCB: removed methods createCertificateType(...) that took a TBSCertificateStructure as parameter
/**
 * A collection of various utility functions.
 */
public class BouncyCastleUtil {

    static {
	Security.addProvider(new BouncyCastleProvider());
    } 

    private static I18n i18n =
        I18n.getI18n("org.globus.gsi.errors",
                     BouncyCastleUtil.class.getClassLoader());

    /**
     * Converts given DERObject into
     * a DER-encoded byte array.
     *
     * @param obj DERObject to convert.
     * @return the DER-encoded byte array
     * @exception IOException if conversion fails
     */
    public static byte[] toByteArray(DERObject obj) 
	throws IOException {
	ByteArrayOutputStream bout = new ByteArrayOutputStream();
	DEROutputStream der = new DEROutputStream(bout);
	der.writeObject(obj);
	return bout.toByteArray();
    }
    
    /**
     * Converts the DER-encoded byte array into a 
     * DERObject.
     *
     * @param data the DER-encoded byte array to convert.
     * @return the DERObject.
     * @exception IOException if conversion fails
     */
    public static DERObject toDERObject(byte[] data) 
	throws IOException {
        ByteArrayInputStream inStream = new ByteArrayInputStream(data);
        ASN1InputStream derInputStream = new ASN1InputStream(inStream);
        return derInputStream.readObject();
    }
    
    

    /**
     * Replicates a given DERObject.
     *
     * @param obj the DERObject to replicate.
     * @return a copy of the DERObject.
     * @exception IOException if replication fails
     */
    public static DERObject duplicate(DERObject obj) 
	throws IOException {
	return toDERObject(toByteArray(obj));
    }

    /**
     * Extracts the TBS certificate from the given certificate.
     *
     * @param cert the X.509 certificate to extract the TBS certificate from.
     * @return the TBS certificate
     * @exception IOException if extraction fails.
     * @exception CertificateEncodingException if extraction fails.
     */
    public static TBSCertificateStructure getTBSCertificateStructure(X509Certificate cert)
	throws CertificateEncodingException, IOException {
	DERObject obj = BouncyCastleUtil.toDERObject(cert.getTBSCertificate());
	return TBSCertificateStructure.getInstance(obj);
    }

    /**
     * Extracts the value of a certificate extension.
     * 
     * @param ext the certificate extension to extract the value from.
     * @exception IOException if extraction fails.
     */
    public static DERObject getExtensionObject(X509Extension ext) 
	throws IOException {
	return toDERObject(ext.getValue().getOctets());
    }

    /**
     * Returns certificate type of the given certificate. 
     * Please see {@link #getCertificateType(TBSCertificateStructure,
     * TrustedCertificates) getCertificateType} for details for 
     * determining the certificate type.
     *
     * @param cert the certificate to get the type of.
     * @param trustedCerts the trusted certificates to double check the 
     *                     {@link GSIConstants#EEC GSIConstants.EEC} 
     *                     certificate against.
     * @return the certificate type as determined by 
     *             {@link #getCertificateType(TBSCertificateStructure, 
     *              TrustedCertificates) getCertificateType}.
     * @exception CertificateException if something goes wrong.
     * @deprecated
     */
    public static GSIConstants.CertificateType getCertificateType(X509Certificate cert,
					 TrustedCertificates trustedCerts)
	throws CertificateException {
        try {
            return getCertificateType(cert, TrustedCertificatesUtil.createCertStore(trustedCerts));
	} catch (Exception e) {
	    throw new CertificateException("", e);
	}
    }

    /**
     * Returns the certificate type of the given certificate. 
     * Please see {@link #getCertificateType(TBSCertificateStructure,
     * TrustedCertificates) getCertificateType} for details for 
     * determining the certificate type.
     *
     * @param cert the certificate to get the type of.
     * @param trustedCerts the trusted certificates to double check the 
     *                     {@link GSIConstants#EEC GSIConstants.EEC} 
     *                     certificate against.
     * @return the certificate type as determined by 
     *             {@link #getCertificateType(TBSCertificateStructure, 
     *              TrustedCertificates) getCertificateType}.
     * @exception CertificateException if something goes wrong.
     */
    public static GSIConstants.CertificateType getCertificateType(X509Certificate cert, CertStore trustedCerts)
    throws CertificateException {
        try {
            TBSCertificateStructure crt = getTBSCertificateStructure(cert);
            GSIConstants.CertificateType type = getCertificateType(crt);

            // check subject of the cert in trusted cert list
            // to make sure the cert is not a ca cert
            if (type == GSIConstants.CertificateType.EEC) {
                X509CertSelector selector = new X509CertSelector();
                selector.setSubject(cert.getSubjectX500Principal());
                Collection c = trustedCerts.getCertificates(selector);
                if (c != null && c.size() > 0) {
                    type = GSIConstants.CertificateType.CA;
                }
            }
            return type;
        } catch (Exception e) {
            // but this should not happen
            throw new CertificateException("", e);
        }
    }
    
    /**
     * Returns certificate type of the given certificate. 
     * Please see {@link #getCertificateType(TBSCertificateStructure) 
     * getCertificateType} for details for determining the certificate type.
     *
     * @param cert the certificate to get the type of.
     * @return the certificate type as determined by 
     *             {@link #getCertificateType(TBSCertificateStructure) 
     *              getCertificateType}.
     * @exception CertificateException if something goes wrong.
     */
    public static GSIConstants.CertificateType getCertificateType(X509Certificate cert) 
    throws CertificateException {
    try {
        TBSCertificateStructure crt = getTBSCertificateStructure(cert);
        return getCertificateType(crt);
    } catch (IOException e) {
        // but this should not happen
        throw new CertificateException("", e);
    }
    }

	public static GSIConstants.CertificateType getCertificateType(TBSCertificateStructure crt, TrustedCertificates trustedCerts)
			throws CertificateException, IOException {
		GSIConstants.CertificateType type = getCertificateType(crt);

		// check subject of the cert in trusted cert list
		// to make sure the cert is not a ca cert
		if (type == GSIConstants.CertificateType.EEC) {
			if (trustedCerts == null) {
				trustedCerts = TrustedCertificates.getDefaultTrustedCertificates();
			}
			if (trustedCerts != null && trustedCerts.getCertificate(crt.getSubject().toString()) != null) {
				type = GSIConstants.CertificateType.CA;
			}
		}

		return type;
	}
    
    /**
     * Returns certificate type of the given TBS certificate. 
* The certificate type is {@link GSIConstants#CA GSIConstants.CA} * only if the certificate contains a * BasicConstraints extension and it is marked as CA.
* A certificate is a GSI-2 proxy when the subject DN of the certificate * ends with "CN=proxy" (certificate type {@link * GSIConstants#GSI_2_PROXY GSIConstants.GSI_2_PROXY}) or * "CN=limited proxy" (certificate type {@link * GSIConstants#GSI_2_LIMITED_PROXY GSIConstants.LIMITED_PROXY}) component * and the issuer DN of the certificate matches the subject DN without * the last proxy CN component.
* A certificate is a GSI-3 proxy when the subject DN of the certificate * ends with a CN component, the issuer DN of the certificate * matches the subject DN without the last CN component and * the certificate contains {@link ProxyCertInfo ProxyCertInfo} critical * extension. * The certificate type is {@link GSIConstants#GSI_3_IMPERSONATION_PROXY * GSIConstants.GSI_3_IMPERSONATION_PROXY} if the policy language of * the {@link ProxyCertInfo ProxyCertInfo} extension is set to * {@link ProxyPolicy#IMPERSONATION ProxyPolicy.IMPERSONATION} OID. * The certificate type is {@link GSIConstants#GSI_3_LIMITED_PROXY * GSIConstants.GSI_3_LIMITED_PROXY} if the policy language of * the {@link ProxyCertInfo ProxyCertInfo} extension is set to * {@link ProxyPolicy#LIMITED ProxyPolicy.LIMITED} OID. * The certificate type is {@link GSIConstants#GSI_3_INDEPENDENT_PROXY * GSIConstants.GSI_3_INDEPENDENT_PROXY} if the policy language of * the {@link ProxyCertInfo ProxyCertInfo} extension is set to * {@link ProxyPolicy#INDEPENDENT ProxyPolicy.INDEPENDENT} OID. * The certificate type is {@link GSIConstants#GSI_3_RESTRICTED_PROXY * GSIConstants.GSI_3_RESTRICTED_PROXY} if the policy language of * the {@link ProxyCertInfo ProxyCertInfo} extension is set to * any other OID then the above.
* The certificate type is {@link GSIConstants#EEC GSIConstants.EEC} * if the certificate is not a CA certificate or a GSI-2 or GSI-3 proxy. * * @param crt the TBS certificate to get the type of. * @return the certificate type. The certificate type is determined * by rules described above. * @exception IOException if something goes wrong. * @exception CertificateException for proxy certificates, if * the issuer DN of the certificate does not match * the subject DN of the certificate without the * last CN component. Also, for GSI-3 proxies * when the ProxyCertInfo extension is * not marked as critical. */ private static GSIConstants.CertificateType getCertificateType(TBSCertificateStructure crt) throws CertificateException, IOException { X509Extensions extensions = crt.getExtensions(); X509Extension ext = null; if (extensions != null) { ext = extensions.getExtension(X509Extensions.BasicConstraints); if (ext != null) { BasicConstraints basicExt = getBasicConstraints(ext); if (basicExt.isCA()) { return GSIConstants.CertificateType.CA; } } } GSIConstants.CertificateType type = GSIConstants.CertificateType.EEC; // does not handle multiple AVAs X509Name subject = crt.getSubject(); ASN1Set entry = X509NameHelper.getLastNameEntry(subject); ASN1Sequence ava = (ASN1Sequence)entry.getObjectAt(0); if (X509Name.CN.equals(ava.getObjectAt(0))) { String value = ((DERString)ava.getObjectAt(1)).getString(); if (value.equalsIgnoreCase("proxy")) { type = GSIConstants.CertificateType.GSI_2_PROXY; } else if (value.equalsIgnoreCase("limited proxy")) { type = GSIConstants.CertificateType.GSI_2_LIMITED_PROXY; } else if (extensions != null) { boolean gsi4 = true; // GSI_4 ext = extensions.getExtension(ProxyCertInfo.OID); if (ext == null) { // GSI_3 ext = extensions.getExtension(ProxyCertInfo.OLD_OID); gsi4 = false; } if (ext != null) { if (ext.isCritical()) { ProxyCertInfo proxyCertExt = getProxyCertInfo(ext); ProxyPolicy proxyPolicy = proxyCertExt.getProxyPolicy(); DERObjectIdentifier oid = proxyPolicy.getPolicyLanguage(); if (ProxyPolicy.IMPERSONATION.equals(oid)) { if (gsi4) { type = GSIConstants.CertificateType.GSI_4_IMPERSONATION_PROXY; } else { type = GSIConstants.CertificateType.GSI_3_IMPERSONATION_PROXY; } } else if (ProxyPolicy.INDEPENDENT.equals(oid)) { if (gsi4) { type = GSIConstants.CertificateType.GSI_4_INDEPENDENT_PROXY; } else { type = GSIConstants.CertificateType.GSI_3_INDEPENDENT_PROXY; } } else if (ProxyPolicy.LIMITED.equals(oid)) { if (gsi4) { type = GSIConstants.CertificateType.GSI_4_LIMITED_PROXY; } else { type = GSIConstants.CertificateType.GSI_3_LIMITED_PROXY; } } else { if (gsi4) { type = GSIConstants.CertificateType.GSI_4_RESTRICTED_PROXY; } else { type = GSIConstants.CertificateType.GSI_3_RESTRICTED_PROXY; } } } else { String err = i18n.getMessage("proxyCertCritical"); throw new CertificateException(err); } } } if (ProxyCertificateUtil.isProxy(type)) { X509NameHelper iss = new X509NameHelper(crt.getIssuer()); iss.add((ASN1Set)BouncyCastleUtil.duplicate(entry)); X509Name issuer = iss.getAsName(); if (!issuer.equals(subject)) { String err = i18n.getMessage("proxyDNErr"); throw new CertificateException(err); } } } return type; } /** * Gets a boolean array representing bits of the KeyUsage extension. * * @see java.security.cert.X509Certificate#getKeyUsage * @exception IOException if failed to extract the KeyUsage extension value. */ public static boolean[] getKeyUsage(X509Extension ext) throws IOException { DERBitString bits = (DERBitString)getExtensionObject(ext); // copied from X509CertificateObject byte [] bytes = bits.getBytes(); int length = (bytes.length * 8) - bits.getPadBits(); boolean[] keyUsage = new boolean[(length < 9) ? 9 : length]; for (int i = 0; i != length; i++) { keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; } return keyUsage; } /** * Creates a BasicConstraints object from given * extension. * * @param ext the extension. * @return the BasicConstraints object. * @exception IOException if something fails. */ public static BasicConstraints getBasicConstraints(X509Extension ext) throws IOException { DERObject obj = BouncyCastleUtil.getExtensionObject(ext); if (obj instanceof ASN1Sequence) { ASN1Sequence seq = (ASN1Sequence)obj; int size = seq.size(); if (size == 0) { return new BasicConstraints(false); } else if (size == 1) { DEREncodable value = seq.getObjectAt(0); if (value instanceof DERInteger) { int length = ((DERInteger)value).getValue().intValue(); return new BasicConstraints(false, length); } else if (value instanceof DERBoolean) { boolean ca = ((DERBoolean)value).isTrue(); return new BasicConstraints(ca); } } } return BasicConstraints.getInstance(obj); } /** * Creates a ProxyCertInfo object from given * extension. * * @param ext the extension. * @return the ProxyCertInfo object. * @exception IOException if something fails. */ public static ProxyCertInfo getProxyCertInfo(X509Extension ext) throws IOException { return ProxyCertInfo.getInstance(BouncyCastleUtil.getExtensionObject(ext)); } /** * Returns the subject DN of the given certificate in the Globus format. * * @param cert the certificate to get the subject of. The certificate * must be of X509CertificateObject type. * @return the subject DN of the certificate in the Globus format. */ public static String getIdentity(X509Certificate cert) { if (cert == null) { return null; } String subjectDN = cert.getSubjectX500Principal().getName(X500Principal.RFC2253); X509Name name = new X509Name(true, subjectDN); return X509NameHelper.toString(name); } public static String getIdentityPrefix(X509Certificate cert) { if (cert == null) { return null; } String subjectDN = cert.getSubjectX500Principal().getName(X500Principal.RFC2253); LdapName ldapname = null; try { ldapname = new LdapName(subjectDN); ldapname.remove(ldapname.size() - 1); } catch (InvalidNameException e) { return null; } X509Name name = new X509Name(true, ldapname.toString()); return X509NameHelper.toString(name); } /** * Finds the identity certificate in the given chain and * returns the subject DN of that certificate in the Globus format. * * @param chain the certificate chain to find the identity * certificate in. The certificates must be * of X509CertificateObject type. * @return the subject DN of the identity certificate in * the Globus format. * @exception CertificateException if something goes wrong. */ public static String getIdentity(X509Certificate [] chain) throws CertificateException { return getIdentity(getIdentityCertificate(chain)); } /** * Finds the identity certificate in the given chain. * The identity certificate is the first certificate in the * chain that is not an impersonation proxy (full or limited) * * @param chain the certificate chain to find the identity * certificate in. * @return the identity certificate. * @exception CertificateException if something goes wrong. */ public static X509Certificate getIdentityCertificate(X509Certificate [] chain) throws CertificateException { if (chain == null) { throw new IllegalArgumentException(i18n.getMessage("certChainNull")); } GSIConstants.CertificateType certType; for (int i=0;i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy