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.KeyStore;
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  import java.util.Objects;
38  
39  import org.apache.directory.api.ldap.model.entry.Entry;
40  import org.apache.directory.api.ldap.model.exception.LdapException;
41  import org.apache.directory.api.ldap.model.name.Dn;
42  import org.apache.directory.api.util.SingletonEnumeration;
43  import org.apache.directory.api.util.exception.NotImplementedException;
44  import org.apache.directory.server.constants.ServerDNConstants;
45  import org.apache.directory.server.core.api.DirectoryService;
46  import org.apache.directory.server.i18n.I18n;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  
51  /**
52   * A read only key store facility designed specifically for TLS/CA operations.
53   * It is only intended for accessing the 'apacheds' private/public key pairs
54   * as well as the self signed certificate.
55   *
56   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
57   */
58  public class CoreKeyStoreSpi extends KeyStoreSpi
59  {
60      private static final String APACHEDS_ALIAS = "apacheds";
61  
62      private static final Logger LOG = LoggerFactory.getLogger( CoreKeyStoreSpi.class );
63  
64      private DirectoryService directoryService;
65      private KeyStore keyStore;
66  
67  
68      /**
69       * Creates a new instance of LocalKeyStore.
70       * @param directoryService The DirectoryService instance
71       */
72      public CoreKeyStoreSpi( DirectoryService directoryService )
73      {
74          LOG.debug( "Constructor called." );
75          this.directoryService = directoryService;
76      }
77      
78      
79      public void setKeyStore( KeyStore keyStore )
80      {
81          this.keyStore = keyStore;
82      }
83  
84  
85      private Entry getTlsEntry() throws LdapException
86      {
87          Dn adminDn = directoryService.getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
88  
89          return directoryService.getAdminSession().lookup( adminDn );
90      }
91  
92  
93      /* (non-Javadoc)
94       * @see java.security.KeyStoreSpi#engineAliases()
95       */
96      @Override
97      public Enumeration<String> engineAliases()
98      {
99          LOG.debug( "engineAliases() called." );
100         return new SingletonEnumeration<>( APACHEDS_ALIAS );
101     }
102 
103 
104     /* (non-Javadoc)
105      * @see java.security.KeyStoreSpi#engineContainsAlias(java.lang.String)
106      */
107     @Override
108     public boolean engineContainsAlias( String alias )
109     {
110         LOG.debug( "engineContainsAlias({}) called.", alias );
111 
112         return alias.equalsIgnoreCase( APACHEDS_ALIAS );
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                 return keyStore.getCertificate( alias );
139                 //Entry entry = getTlsEntry();
140                 //return TlsKeyGenerator.getCertificate( entry );
141             }
142             catch ( Exception e )
143             {
144                 LOG.error( I18n.err( I18n.ERR_65 ), e );
145             }
146         }
147 
148         return null;
149     }
150 
151 
152     /* (non-Javadoc)
153      * @see java.security.KeyStoreSpi#engineGetCertificateAlias(java.security.cert.Certificate)
154      */
155     @Override
156     public String engineGetCertificateAlias( Certificate cert )
157     {
158         LOG.debug( "engineGetCertificateAlias({}) called.", cert );
159 
160         if ( cert instanceof X509Certificate )
161         {
162             LOG.debug( "Certificate in alias request is X.509 based." );
163             X509Certificate xcert = ( X509Certificate ) cert;
164             
165             if ( xcert.getIssuerDN().toString().equals( TlsKeyGenerator.CERTIFICATE_PRINCIPAL_DN ) )
166             {
167                 return APACHEDS_ALIAS;
168             }
169         }
170 
171         try
172         {
173             Certificate certificate = keyStore.getCertificate( APACHEDS_ALIAS );
174             
175             if ( Objects.deepEquals( cert.getEncoded(), certificate.getEncoded() ) )
176             {
177                 return APACHEDS_ALIAS;
178             }
179             /*
180             Entry entry = getTlsEntry();
181 
182             if ( Objects.deepEquals( cert.getEncoded(), entry.get( TlsKeyGenerator.USER_CERTIFICATE_AT ).getBytes() ) )
183             {
184                 return APACHEDS_ALIAS;
185             }
186             */
187         }
188         catch ( Exception e )
189         {
190             LOG.error( I18n.err( I18n.ERR_66 ), e );
191         }
192 
193         return null;
194     }
195 
196 
197     /* (non-Javadoc)
198      * @see java.security.KeyStoreSpi#engineGetCertificateChain(java.lang.String)
199      */
200     @Override
201     public Certificate[] engineGetCertificateChain( String alias )
202     {
203         LOG.debug( "engineGetCertificateChain({}) called.", alias );
204         try
205         {
206             Entry entry = getTlsEntry();
207             LOG.debug( "Entry:\n{}", entry );
208             return new Certificate[]
209                 {
210                     keyStore.getCertificate( alias )
211                 };
212                 //{ TlsKeyGenerator.getCertificate( entry ) };
213         }
214         catch ( Exception e )
215         {
216             LOG.error( I18n.err( I18n.ERR_66 ), e );
217         }
218 
219         return new Certificate[0];
220     }
221 
222 
223     /* (non-Javadoc)
224      * @see java.security.KeyStoreSpi#engineGetCreationDate(java.lang.String)
225      */
226     @Override
227     public Date engineGetCreationDate( String alias )
228     {
229         LOG.debug( "engineGetCreationDate({}) called.", alias );
230         return new Date();
231     }
232 
233 
234     /* (non-Javadoc)
235      * @see java.security.KeyStoreSpi#engineGetKey(java.lang.String, char[])
236      */
237     @Override
238     public Key engineGetKey( String alias, char[] password ) throws NoSuchAlgorithmException, UnrecoverableKeyException
239     {
240         LOG.debug( "engineGetKey({}, {}) called.", alias, password );
241 
242         try
243         {
244             return keyStore.getKey( alias, password );
245             /*
246             Entry entry = getTlsEntry();
247             KeyPair keyPair = TlsKeyGenerator.getKeyPair( entry );
248             return keyPair.getPrivate();
249             */
250         }
251         catch ( Exception e )
252         {
253             LOG.error( I18n.err( I18n.ERR_68 ), e );
254         }
255 
256         return null;
257     }
258 
259 
260     /* (non-Javadoc)
261      * @see java.security.KeyStoreSpi#engineIsCertificateEntry(java.lang.String)
262      */
263     @Override
264     public boolean engineIsCertificateEntry( String alias )
265     {
266         LOG.debug( "engineIsCertificateEntry({}) called.", alias );
267         return false;
268     }
269 
270 
271     /* (non-Javadoc)
272      * @see java.security.KeyStoreSpi#engineIsKeyEntry(java.lang.String)
273      */
274     @Override
275     public boolean engineIsKeyEntry( String alias )
276     {
277         LOG.debug( "engineIsKeyEntry({}) called.", alias );
278         return true;
279     }
280 
281 
282     /* (non-Javadoc)
283      * @see java.security.KeyStoreSpi#engineLoad(java.io.InputStream, char[])
284      */
285     @Override
286     public void engineLoad( InputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException,
287         CertificateException
288     {
289         LOG.debug( "engineLoad({}, {}) called.", stream, password );
290     }
291 
292 
293     /* (non-Javadoc)
294      * @see java.security.KeyStoreSpi#engineSetCertificateEntry(java.lang.String, java.security.cert.Certificate)
295      */
296     @Override
297     public void engineSetCertificateEntry( String alias, Certificate cert ) throws KeyStoreException
298     {
299         LOG.debug( "engineSetCertificateEntry({}, {}) called.", alias, cert );
300         throw new NotImplementedException();
301     }
302 
303 
304     /* (non-Javadoc)
305      * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, byte[], java.security.cert.Certificate[])
306      */
307     @Override
308     public void engineSetKeyEntry( String alias, byte[] key, Certificate[] chain ) throws KeyStoreException
309     {
310         LOG.debug( "engineSetKeyEntry({}, key, {}) called.", alias, chain );
311         throw new NotImplementedException();
312     }
313 
314 
315     /* (non-Javadoc)
316      * @see java.security.KeyStoreSpi#engineSetKeyEntry(java.lang.String, java.security.Key, char[], java.security.cert.Certificate[])
317      */
318     @Override
319     public void engineSetKeyEntry( String alias, Key key, char[] password, Certificate[] chain )
320         throws KeyStoreException
321     {
322         if ( LOG.isDebugEnabled() )
323         {
324             LOG.debug( "engineSetKeyEntry({}, key, {}, chain) called.", alias, new String( password ) );
325         }
326 
327         throw new NotImplementedException();
328     }
329 
330 
331     /* (non-Javadoc)
332      * @see java.security.KeyStoreSpi#engineSize()
333      */
334     @Override
335     public int engineSize()
336     {
337         if ( LOG.isDebugEnabled() )
338         {
339             LOG.debug( "engineSize() called." );
340         }
341 
342         return 1;
343     }
344 
345 
346     /* (non-Javadoc)
347      * @see java.security.KeyStoreSpi#engineStore(java.io.OutputStream, char[])
348      */
349     @Override
350     public void engineStore( OutputStream stream, char[] password ) throws IOException, NoSuchAlgorithmException,
351         CertificateException
352     {
353         if ( LOG.isDebugEnabled() )
354         {
355             LOG.debug( "engineStore(stream, {}) called.", new String( password ) );
356         }
357     }
358 }