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

sun.security.mscapi.KeyStoreAddressBook Maven / Gradle / Ivy

Go to download

Modulo el acceso al almacen de certificados de terceros (Libreta de direcciones) de Windows

There is a newer version: 1.7.2
Show newest version
/*
 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.mscapi;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.SecurityPermission;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Logger;

/** sun.security.mscapi.KeyStore modificada para acceder a los
 * almacenes de CAPI ADDRESSBOOK y CA.
 * @author Tomás García-Merás */
public abstract class KeyStoreAddressBook extends KeyStoreSpi {

    /** KeyStore CA de CAPI. */
    public static final class CA extends KeyStoreAddressBook {

        /** Construye el SPI del KeyStore CA de CAPI. */
        public CA() {
            super("CA"); //$NON-NLS-1$
        }
    }

    /** KeyStore ADDRESSBOOK de CAPI. */
    public static final class ADDRESSBOOK extends KeyStoreAddressBook {
        /** Construye el SPI del KeyStore ADDRESSBOOK de
         * CAPI. */
        public ADDRESSBOOK() {
            super("ADDRESSBOOK"); //$NON-NLS-1$
        }
    }

    final class KeyEntry {

        private final X509Certificate certChain[];
        private String alias;

        X509Certificate[] getCertChain() {
            return this.certChain.clone();
        }

        KeyEntry(final X509Certificate[] chain) {
            this((String) null, chain);
        }

        KeyEntry(final String alias, final X509Certificate[] chain) {

            this.certChain = chain.clone();
            /*
             * The default alias for both entry types is derived from a hash
             * value intrinsic to the first certificate in the chain.
             */
            if (alias == null) {
                this.alias = Integer.toString(this.certChain[0].hashCode());
            }
            else {
                this.alias = alias;
            }
        }

        /** Gets the alias for the keystore entry.
         * @return Alias para la entrada de almacén. */
        String getAlias() {
            return this.alias;
        }

        /** Gets the certificate chain for the keystore entry.
         * @return cadena de certificados para la entrada de almacén. */
        X509Certificate[] getCertificateChain() {
            return this.certChain;
        }

    }

    /** The keystore entries. */
    private final Collection entries = new ArrayList<>();

    /** The keystore name. Case is not significant. */
    private final String storeName;

    private java.lang.reflect.Method loadKeysOrCertificateChains;

    private final Object nativeWrapper;

    KeyStoreAddressBook(final String storeName) {

    	try {
	    	final Class keyStoreMyClass = Class.forName("sun.security.mscapi.KeyStore$MY"); //$NON-NLS-1$

	    	// Esto equivale a {@code new KeyStore.MY()}.
	    	this.nativeWrapper = keyStoreMyClass.getConstructor().newInstance();
    	}
    	catch (final Exception e) {
    		 Logger.getLogger("es.gob.afirma").severe("No se han encontrado las clases de SunMSCapi: " + e); //$NON-NLS-1$ //$NON-NLS-2$
    		 throw new RuntimeException("No se han encontrado las clases de SunMSCapi", e); //$NON-NLS-1$
		}

        try {
            this.nativeWrapper.getClass();
            for (final java.lang.reflect.Method m : this.nativeWrapper.getClass().getDeclaredMethods()) {
                m.setAccessible(true);
            }
            for (final java.lang.reflect.Method m : this.nativeWrapper.getClass().getSuperclass().getDeclaredMethods()) {
                m.setAccessible(true);
                if (m.getName().equals("loadKeysOrCertificateChains")) { //$NON-NLS-1$
                    this.loadKeysOrCertificateChains = m;
                }
            }
        }
        catch (final Exception e) {
            Logger.getLogger("es.gob.afirma").severe("No se han podido obtener los metodos de acceso a sunmscapi.dll: " + e); //$NON-NLS-1$ //$NON-NLS-2$
        }

        this.storeName = storeName;
    }

    /** Returns the key associated with the given alias.
     * 

* A compatibility mode is supported for applications that assume a password must be supplied. It permits (but ignores) a non-null * password. The mode is enabled by default. Set the sun.security.mscapi.keyStoreCompatibilityMode system property to * false to disable compatibility mode and reject a non-null password. * @param alias * the alias name * @param password * the password, which should be null * @return the requested key, or null if the given alias does not exist or * does not identify a key entry. */ @Override public final java.security.Key engineGetKey(final String alias, final char[] password) { throw new UnsupportedOperationException(); } /** Returns the certificate chain associated with the given alias. * @param alias * the alias name * @return the certificate chain (ordered with the user's certificate first * and the root certificate authority last), or null if the given * alias does not exist or does not contain a certificate chain * (i.e., the given alias identifies either a trusted certificate * entry or a key entry without a certificate chain). */ @Override public final Certificate[] engineGetCertificateChain(final String alias) { if (alias == null) { return null; } // Se usan los KeyEntry por reflexion porque se han detectado casos en los que son del // tipo del almacen de windows en lugar de la libreta de direcciones try { for (final Object entry : this.entries.toArray()) { final Method getAliasMethod = entry.getClass().getDeclaredMethod("getAlias"); //$NON-NLS-1$ getAliasMethod.setAccessible(true); if (alias.equals(getAliasMethod.invoke(entry))) { final Method getCertificateChainMethod = entry.getClass().getDeclaredMethod("getCertificateChain"); //$NON-NLS-1$ getCertificateChainMethod.setAccessible(true); return (Certificate[]) getCertificateChainMethod.invoke(entry); } } } catch (final Exception e) { Logger.getLogger("es.gob.afirma").warning("Error tratando de obtener la cadena de certificacion: " + e); //$NON-NLS-1$ //$NON-NLS-2$ } return null; } /** Returns the certificate associated with the given alias. *

* If the given alias name identifies a trusted certificate entry, the certificate associated with that entry is returned. If the given * alias name identifies a key entry, the first element of the certificate chain of that entry is returned, or null if that entry does not * have a certificate chain. * @param alias * the alias name * @return the certificate, or null if the given alias does not exist or * does not contain a certificate. */ @Override public final Certificate engineGetCertificate(final String alias) { if (alias == null) { return null; } java.lang.reflect.Method getAlias = null; java.lang.reflect.Method getCertificateChain = null; for (final Object o : this.entries) { for (final java.lang.reflect.Method m : o.getClass().getDeclaredMethods()) { if (m.getName().equals("getAlias")) { //$NON-NLS-1$ m.setAccessible(true); getAlias = m; } else if (m.getName().equals("getCertificateChain")) { //$NON-NLS-1$ m.setAccessible(true); getCertificateChain = m; } if (getAlias != null) { try { if (alias.equals(getAlias.invoke(o, new Object[0])) && getCertificateChain != null) { final X509Certificate[] certChain = (X509Certificate[]) getCertificateChain.invoke(o, new Object[0]); return certChain[0]; } } catch (final Exception e) { Logger.getLogger("es.gob.afirma").warning("Error obteniendo el certificado para el alias '" + alias + "', se devolvera null: " + e); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } } return null; } /** Returns the creation date of the entry identified by the given alias. * @param alias * the alias name * @return the creation date of this entry, or null if the given alias does * not exist */ @Override public final Date engineGetCreationDate(final String alias) { if (alias == null) { return null; } return new Date(); } /** Stores the given private key and associated certificate chain in the * keystore. *

* The given java.security.PrivateKey key must be accompanied by a certificate chain certifying the corresponding public key. *

* If the given alias already exists, the keystore information associated with it is overridden by the given key and certificate chain. Otherwise, * a new entry is created. *

* A compatibility mode is supported for applications that assume a password must be supplied. It permits (but ignores) a non-null * password. The mode is enabled by default. Set the sun.security.mscapi.keyStoreCompatibilityMode system property to * false to disable compatibility mode and reject a non-null password. * @param alias * the alias name * @param key * the private key to be associated with the alias * @param password * the password, which should be null * @param chain * the certificate chain for the corresponding public key (only * required if the given key is of type java.security.PrivateKey). */ @Override public final void engineSetKeyEntry(final String alias, final java.security.Key key, final char[] password, final Certificate[] chain) { throw new UnsupportedOperationException(); } /** Assigns the given key (that has already been protected) to the given * alias. *

* If the protected key is of type java.security.PrivateKey, it must be accompanied by a certificate chain certifying the * corresponding public key. If the underlying keystore implementation is of type jks, key must be encoded as an * EncryptedPrivateKeyInfo as defined in the PKCS #8 standard. *

* If the given alias already exists, the keystore information associated with it is overridden by the given key (and possibly certificate chain). * @param alias * the alias name * @param key * the key (in protected format) to be associated with the alias * @param chain * the certificate chain for the corresponding public key (only * useful if the protected key is of type java.security.PrivateKey). */ @Override public final void engineSetKeyEntry(final String alias, final byte[] key, final Certificate[] chain) { throw new UnsupportedOperationException("Cannot assign the encoded key to the given alias."); //$NON-NLS-1$ } /** Assigns the given certificate to the given alias. *

* If the given alias already exists in this keystore and identifies a trusted certificate entry, the certificate associated with it is * overridden by the given certificate. * @param alias * the alias name * @param cert * the certificate. */ @Override public final void engineSetCertificateEntry(final String alias, final Certificate cert) { throw new UnsupportedOperationException(); } /** Deletes the entry identified by the given alias from this keystore. * @param alias * the alias name. */ @Override public final void engineDeleteEntry(final String alias) { throw new UnsupportedOperationException(); } /** Lists all the alias names of this keystore. * @return enumeration of the alias names */ @Override public final Enumeration engineAliases() { final Iterator iter = this.entries.iterator(); return new Enumeration() { /** {@inheritDoc} */ @Override public boolean hasMoreElements() { return iter.hasNext(); } /** {@inheritDoc} */ @Override public String nextElement() { final Object o = iter.next(); for (final java.lang.reflect.Method m : o.getClass().getDeclaredMethods()) { if (m.getName().equals("getAlias")) { //$NON-NLS-1$ m.setAccessible(true); try { return m.invoke(o, new Object[0]).toString(); } catch (final Exception e) { Logger.getLogger("es.gob.afirma").severe("No se ha podido invocar a sunmscapi.dll para obtener los alias: " + e); //$NON-NLS-1$//$NON-NLS-2$ return null; } } } return null; } }; } /** Checks if the given alias exists in this keystore. * @param alias * the alias name * @return true if the alias exists, false otherwise */ @Override public final boolean engineContainsAlias(final String alias) { for (final Enumeration enumerator = engineAliases(); enumerator.hasMoreElements();) { final String a = (String) enumerator.nextElement(); if (a.equals(alias)) { return true; } } return false; } /** Retrieves the number of entries in this keystore. * @return the number of entries in this keystore */ @Override public final int engineSize() { return this.entries.size(); } /** Returns true if the entry identified by the given alias is a key * entry, and false otherwise. * @return true if the entry identified by the given alias is a key * entry, false otherwise. */ @Override public final boolean engineIsKeyEntry(final String alias) { throw new UnsupportedOperationException(); } /** Returns true if the entry identified by the given alias is a trusted * certificate entry, and false otherwise. * @return true if the entry identified by the given alias is a trusted * certificate entry, false otherwise. */ @Override public final boolean engineIsCertificateEntry(final String alias) { throw new UnsupportedOperationException(); } /** Returns the (alias) name of the first keystore entry whose certificate * matches the given certificate. *

* This method attempts to match the given certificate with each keystore entry. If the entry being considered is a trusted certificate * entry, the given certificate is compared to that entry's certificate. If the entry being considered is a key entry, the given * certificate is compared to the first element of that entry's certificate chain (if a chain exists). * @param cert * the certificate to match with. * @return the (alias) name of the first entry with matching certificate, or * null if no such entry exists in this keystore. */ @Override public final String engineGetCertificateAlias(final Certificate cert) { for (final KeyEntry entry : this.entries) { if (entry.getCertChain() != null && entry.getCertChain()[0].equals(cert)) { return entry.getAlias(); } } return null; } /** engineStore is currently a no-op. Entries are stored during * engineSetEntry. * @param stream * the output stream, which should be null * @param password * the password, which should be null. */ @Override public final void engineStore(final OutputStream stream, final char[] password) { // No es necesario hacer nada, se almacena en engineSetEntry() } /** Loads the keystore. * A compatibility mode is supported for applications that assume keystores * are stream-based. It permits (but ignores) a non-null stream or password. The mode is enabled by default. Set the * sun.security.mscapi.keyStoreCompatibilityMode system * property to false to disable compatibility mode and reject a * non-null stream or password. * @param stream * the input stream, which should be null. * @param password * the password, which should be null. * @exception IOException * if there is an I/O or format problem with the keystore * data. Or if compatibility mode is disabled and either * parameter is non-null. * @exception SecurityException * if the security check for SecurityPermission("authProvider.name") does not pass, where name is the value * returned by * this provider's getName method. */ @Override public final void engineLoad(final InputStream stream, final char[] password) throws IOException { /* * Use the same security check as AuthProvider.login */ final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new SecurityPermission("authProvider.SunMSCAPI")); //$NON-NLS-1$ } // Clear all key entries this.entries.clear(); try { // Load keys and/or certificate chains loadKeysOrCertificateChains(getName(), this.entries); } catch (final KeyStoreException kse) { // Wrap the JNI exception in an IOException throw new IOException(kse.toString(), kse); } } /** Devuelve el nombre del almacén. * @return Nombre del almacén. */ private String getName() { return this.storeName; } /** Load keys and/or certificates from keystore into Collection. * @param name Name of keystore. * @param ntries Collection of key/certificate. * @throws KeyStoreException Si hay problemas tratando el almacén. */ private void loadKeysOrCertificateChains(final String name, final Collection ntries) throws KeyStoreException { try { // Los ultimos MSCapi no incluyen este metodo, asi que en caso de error // acudimos a un modo alternativo this.loadKeysOrCertificateChains.invoke(this.nativeWrapper, name, ntries); } catch (final Exception e) { try { // Cargamos las entradas, accedemos al campo que las contiene y componemos // el objeto resultado con sus valores this.loadKeysOrCertificateChains.invoke(this.nativeWrapper, name); final java.lang.reflect.Field entriesField = this.nativeWrapper.getClass(). getSuperclass().getDeclaredField("entries"); //$NON-NLS-1$ entriesField.setAccessible(true); final HashMap coll = (HashMap) entriesField.get(this.nativeWrapper); final Iterator it = coll.keySet().iterator(); while (it.hasNext()) { final String alias = it.next(); final Object keyEntryObject = coll.get(alias); final Method getCertificateChainMethod = keyEntryObject.getClass().getDeclaredMethod("getCertificateChain"); //$NON-NLS-1$ getCertificateChainMethod.setAccessible(true); ntries.add(new KeyEntry(alias, (X509Certificate[]) getCertificateChainMethod.invoke(keyEntryObject))); } } catch (final Exception e2) { throw new KeyStoreException(e); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy