View Javadoc

1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.server.core.security;
21  
22  
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.security.Key;
27  import java.security.KeyPair;
28  import java.security.KeyStoreException;
29  import java.security.KeyStoreSpi;
30  import java.security.NoSuchAlgorithmException;
31  import java.security.UnrecoverableKeyException;
32  import java.security.cert.Certificate;
33  import java.security.cert.CertificateException;
34  import java.security.cert.X509Certificate;
35  import java.util.Date;
36  import java.util.Enumeration;
37  
38  import org.apache.commons.lang.ArrayUtils;
39  import org.apache.commons.lang.NotImplementedException;
40  import org.apache.directory.server.core.CoreSession;
41  import org.apache.directory.server.core.DirectoryService;
42  import org.apache.directory.server.core.authn.LdapPrincipal;
43  import org.apache.directory.server.core.entry.ServerEntry;
44  import org.apache.directory.server.core.partition.PartitionNexus;
45  import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
46  import org.apache.directory.shared.ldap.name.LdapDN;
47  import org.apache.directory.shared.ldap.util.SingletonEnumeration;
48  import org.slf4j.Logger;
49  import org.slf4j.LoggerFactory;
50  
51  
52  /**
53   * A read only key store facility designed specifically for TLS/CA operations.
54   * It is only intended for accessing the 'apacheds' private/public key pairs
55   * as well as the self signed certificate.
56   *
57   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
58   * @version $Rev$, $Date$
59   */
60  public class CoreKeyStoreSpi extends KeyStoreSpi
61  {
62      private static final String APACHEDS_ALIAS = "apacheds";
63  
64      private static final Logger LOG = LoggerFactory.getLogger( CoreKeyStoreSpi.class );
65      
66      private DirectoryService directoryService;
67      
68  
69      /**
70       * Creates a new instance of LocalKeyStore.
71       */
72      public CoreKeyStoreSpi( DirectoryService directoryService )
73      {
74          LOG.debug( "Constructor called." );
75          this.directoryService = directoryService;
76      }
77  
78  
79      private ServerEntry getTlsEntry() throws Exception
80      {
81          LdapDN adminDn = PartitionNexus.getAdminName();
82          LdapPrincipal principal = new LdapPrincipal( adminDn, AuthenticationLevel.SIMPLE );
83          CoreSession session = directoryService.getSession( principal );
84          return session.lookup( adminDn );
85      }
86      
87      
88      /* (non-Javadoc)
89       * @see java.security.KeyStoreSpi#engineAliases()
90       */
91      @Override
92      public Enumeration<String> engineAliases()
93      {
94          LOG.debug( "engineAliases() called." );
95          return new SingletonEnumeration<String>( APACHEDS_ALIAS );
96      }
97  
98  
99      /* (non-Javadoc)
100      * @see java.security.KeyStoreSpi#engineContainsAlias(java.lang.String)
101      */
102     @Override
103     public boolean engineContainsAlias( String alias )
104     {
105         LOG.debug( "engineContainsAlias({}) called.", alias );
106         
107         if ( alias.equalsIgnoreCase( APACHEDS_ALIAS ) )
108         {
109             return true;
110         }
111         
112         return false;
113     }
114 
115 
116     /* (non-Javadoc)
117      * @see java.security.KeyStoreSpi#engineDeleteEntry(java.lang.String)
118      */
119     @Override
120     public void engineDeleteEntry( String alias ) throws KeyStoreException
121     {
122         LOG.debug( "engineDeleteEntry({}) called.", alias );
123         throw new UnsupportedOperationException();
124     }
125 
126 
127     /* (non-Javadoc)
128      * @see java.security.KeyStoreSpi#engineGetCertificate(java.lang.String)
129      */
130     @Override
131     public Certificate engineGetCertificate( String alias )
132     {
133         LOG.debug( "engineGetCertificate({}) called.", alias );
134         if ( alias.equalsIgnoreCase( APACHEDS_ALIAS ) )
135         {
136             try
137             {
138                 ServerEntry entry = getTlsEntry();
139                 return TlsKeyGenerator.getCertificate( entry );
140             }
141             catch ( Exception e )
142             {
143                 LOG.error( "Failed to access certificate in DIT.", e );
144             }
145         }
146         
147         return null;
148     }
149 
150 
151     /* (non-Javadoc)
152      * @see java.security.KeyStoreSpi#engineGetCertificateAlias(java.security.cert.Certificate)
153      */
154     @Override
155     public String engineGetCertificateAlias( Certificate cert )
156     {
157         LOG.debug( "engineGetCertificateAlias({}) called.", cert );
158         
159         if ( cert instanceof X509Certificate )
160         {
161             LOG.debug( "Certificate in alias request is X.509 based." );
162             X509Certificate xcert = ( X509Certificate ) cert;
163             if ( xcert.getSubjectDN().toString().equals( TlsKeyGenerator.CERTIFICATE_PRINCIPAL_DN ) )
164             {
165                 return APACHEDS_ALIAS;
166             }
167         }
168         
169         try
170         {
171             ServerEntry entry = getTlsEntry();
172             if ( ArrayUtils.isEquals( cert.getEncoded(), entry.get( TlsKeyGenerator.USER_CERTIFICATE_AT ).getBytes() ) )
173             {
174                 return APACHEDS_ALIAS;
175             }
176         }
177         catch ( Exception e )
178         {
179             LOG.error( "Failed on attempt to compare certificate bytes to determine alias.", e );
180         }
181         
182         return null;
183     }
184 
185 
186     /* (non-Javadoc)
187      * @see java.security.KeyStoreSpi#engineGetCertificateChain(java.lang.String)
188      */
189     @Override
190     public Certificate[] engineGetCertificateChain( String alias )
191     {
192         LOG.debug( "engineGetCertificateChain({}) called.", alias );
193         try
194         {
195             ServerEntry entry = getTlsEntry();
196             LOG.debug( "Entry:\n{}", entry );
197             return new Certificate[] { TlsKeyGenerator.getCertificate( entry ) };
198         }
199         catch ( Exception e )
200         {
201             LOG.error( "Failed on attempt to compare certificate bytes to determine alias.", e );
202         }
203         
204         return new Certificate[0];
205     }
206 
207 
208     /* (non-Javadoc)
209      * @see java.security.KeyStoreSpi#engineGetCreationDate(java.lang.String)
210      */
211     @Override
212     public Date engineGetCreationDate( String alias )
213     {
214         LOG.debug( "engineGetCreationDate({}) called.", alias );
215         return new Date();
216     }
217 
218 
219     /* (non-Javadoc)
220      * @see java.security.KeyStoreSpi#engineGetKey(java.lang.String, char[])
221      */
222     @Override
223     public Key engineGetKey( String alias, char[] password ) throws NoSuchAlgorithmException, UnrecoverableKeyException
224     {
225         LOG.debug( "engineGetKey({}, {}) called.", alias, password );
226         
227         try
228         {
229             ServerEntry entry = getTlsEntry();
230             KeyPair keyPair = TlsKeyGenerator.getKeyPair( entry );
231             return keyPair.getPrivate();
232         }
233         catch ( Exception e )
234         {
235             LOG.error( "Failed on attempt to extract key.", e );
236         }
237         
238         return null;
239     }
240 
241 
242     /* (non-Javadoc)
243      * @see java.security.KeyStoreSpi#engineIsCertificateEntry(java.lang.String)
244      */
245     @Override
246     public boolean engineIsCertificateEntry( String alias )
247     {
248         LOG.debug( "engineIsCertificateEntry({}) called.", alias );
249         return false;
250     }
251 
252 
253     /* (non-Javadoc)
254      * @see java.security.KeyStoreSpi#engineIsKeyEntry(java.lang.String)
255      */
256     @Override
257     public boolean engineIsKeyEntry( String alias )
258     {
259         LOG.debug( "engineIsKeyEntry({}) called.", alias );
260         return true;
261     }
262 
263 
264     /* (non-Javadoc)
265      * @see java.security.KeyStoreSpi#engineLoad(java.io.InputStream, char[])
266      */
267     @Override
268     public void engineLoad( InputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException,
269         CertificateException
270     {
271         LOG.debug( "engineLoad({}, {}) called.", stream, password );
272     }
273 
274 
275     /* (non-Javadoc)
276      * @see java.security.KeyStoreSpi#engineSetCertificateEntry(java.lang.String, java.security.cert.Certificate)
277      */
278     @Override
279     public void engineSetCertificateEntry( String alias, Certificate cert ) throws KeyStoreException
280     {
281         LOG.debug( "engineSetCertificateEntry({}, {}) called.", alias, cert );
282         throw new NotImplementedException();
283     }
284 
285 
286     /* (non-Javadoc)
287      * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, byte[], java.security.cert.Certificate[])
288      */
289     @Override
290     public void engineSetKeyEntry( String alias, byte[] key, Certificate[] chain ) throws KeyStoreException
291     {
292         LOG.debug( "engineSetKeyEntry({}, key, {}) called.", alias, chain );
293         throw new NotImplementedException();
294     }
295 
296 
297     /* (non-Javadoc)
298      * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, java.security.Key, char[], java.security.cert.Certificate[])
299      */
300     @Override
301     public void engineSetKeyEntry( String alias, Key key, char[] password, Certificate[] chain )
302         throws KeyStoreException
303     {
304         LOG.debug( "engineSetKeyEntry({}, key, {}, chain) called.", alias, new String( password ) );
305         throw new NotImplementedException();
306     }
307 
308 
309     /* (non-Javadoc)
310      * @see java.security.KeyStoreSpi#engineSize()
311      */
312     @Override
313     public int engineSize()
314     {
315         LOG.debug( "engineSize() called." );
316         return 1;
317     }
318 
319 
320     /* (non-Javadoc)
321      * @see java.security.KeyStoreSpi#engineStore(java.io.OutputStream, char[])
322      */
323     @Override
324     public void engineStore( OutputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException,
325         CertificateException
326     {
327         LOG.debug( "engineStore(stream, {}) called.", new String( password ) );
328     }
329 }