001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *  
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *  
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License. 
018 *  
019 */
020package org.apache.directory.shared.ldap.extras.extended.ads_impl.certGeneration;
021
022
023import org.apache.directory.shared.asn1.ber.grammar.AbstractGrammar;
024import org.apache.directory.shared.asn1.ber.grammar.Grammar;
025import org.apache.directory.shared.asn1.ber.grammar.GrammarAction;
026import org.apache.directory.shared.asn1.ber.grammar.GrammarTransition;
027import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
028import org.apache.directory.shared.asn1.ber.tlv.Value;
029import org.apache.directory.shared.asn1.DecoderException;
030import org.apache.directory.shared.i18n.I18n;
031import org.apache.directory.shared.ldap.codec.api.LdapApiServiceFactory;
032import org.apache.directory.shared.ldap.extras.extended.CertGenerationRequestImpl;
033import org.apache.directory.shared.ldap.model.name.Dn;
034import org.apache.directory.shared.util.Strings;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038
039/**
040 * This class implements the Certificate generation extended operation's ASN.1 grammer. 
041 * All the actions are declared in this class. As it is a singleton, 
042 * these declaration are only done once. The grammar is :
043 * 
044 * <pre>
045 *   CertGenerateObject ::= SEQUENCE 
046 *   {
047 *      targetDN        IA5String,
048 *      issuerDN        IA5String,
049 *      subjectDN       IA5String,
050 *      keyAlgorithm    IA5String
051 *   }
052 * </pre>
053 * 
054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
055 */
056
057public class CertGenerationGrammar extends AbstractGrammar<CertGenerationContainer>
058{
059
060    /** logger */
061    private static final Logger LOG = LoggerFactory.getLogger( CertGenerationGrammar.class );
062
063    /** Speedup for logs */
064    static final boolean IS_DEBUG = LOG.isDebugEnabled();
065
066    /** The instance of grammar. CertGenerationObjectGrammar is a singleton */
067    private static Grammar<CertGenerationContainer> instance = new CertGenerationGrammar();
068
069
070    @SuppressWarnings("unchecked")
071    public CertGenerationGrammar()
072    {
073        setName( CertGenerationGrammar.class.getName() );
074
075        // Create the transitions table
076        super.transitions = new GrammarTransition[CertGenerationStatesEnum.LAST_CERT_GENERATION_STATE.ordinal()][256];
077
078        /**
079         * Transition from init state to certificate generation
080         * 
081         * CertGenerationObject ::= SEQUENCE {
082         *     ...
083         *     
084         * Creates the CertGenerationObject object
085         */
086        super.transitions[CertGenerationStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] = 
087            new GrammarTransition<CertGenerationContainer>(
088            CertGenerationStatesEnum.START_STATE, CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE,
089            UniversalTag.SEQUENCE.getValue(), new GrammarAction<CertGenerationContainer>( "Init CertGenerationObject" )
090            {
091                public void action( CertGenerationContainer container )
092                {
093                    CertGenerationRequestDecorator certGenerationObject = new CertGenerationRequestDecorator( 
094                        LdapApiServiceFactory.getSingleton(), new CertGenerationRequestImpl() );
095                    container.setCertGenerationObject( certGenerationObject );
096                }
097            } );
098
099        /**
100         * Transition from certificate generation request to targetDN
101         *
102         * CertGenerationObject ::= SEQUENCE { 
103         *     targetDN IA5String,
104         *     ...
105         *     
106         * Set the targetDN value into the CertGenerationObject instance.
107         */
108        super.transitions[CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
109            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE, 
110                CertGenerationStatesEnum.TARGETDN_STATE, UniversalTag.OCTET_STRING.getValue(), 
111                new GrammarAction<CertGenerationContainer>( "Set Cert Generation target Dn value" )
112            {
113                public void action( CertGenerationContainer container ) throws DecoderException
114                {
115                    Value value = container.getCurrentTLV().getValue();
116
117                    String targetDN = Strings.utf8ToString(value.getData());
118
119                    if ( IS_DEBUG )
120                    {
121                        LOG.debug( "Target Dn = " + targetDN );
122                    }
123
124                    if ( ( targetDN != null ) && ( targetDN.trim().length() > 0 ) )
125                    {
126                        if( !Dn.isValid(targetDN) )
127                        {
128                            String msg = I18n.err( I18n.ERR_04032, targetDN );
129                            LOG.error( msg );
130                            throw new DecoderException( msg );
131                        }
132                        
133                        container.getCertGenerationObject().setTargetDN( targetDN );
134                    }
135                    else
136                    {
137                        String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes(value.getData()) );
138                        LOG.error( msg );
139                        throw new DecoderException( msg );
140                    }
141                }
142            } );
143
144        /**
145         * Transition from targetDN state to issuerDN
146         *
147         * CertGenerationObject ::= SEQUENCE { 
148         *     ...
149         *     issuerDN IA5String,
150         *     ...
151         *     
152         * Set the issuerDN value into the CertGenerationObject instance.
153         */
154        super.transitions[CertGenerationStatesEnum.TARGETDN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
155            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.TARGETDN_STATE, 
156                CertGenerationStatesEnum.ISSUER_STATE, UniversalTag.OCTET_STRING.getValue(),
157                new GrammarAction<CertGenerationContainer>( "Set Cert Generation issuer Dn value" )
158            {
159                public void action( CertGenerationContainer container ) throws DecoderException
160                {
161                    Value value = container.getCurrentTLV().getValue();
162
163                    String issuerDN = Strings.utf8ToString(value.getData());
164
165                    if ( IS_DEBUG )
166                    {
167                        LOG.debug( "Issuer Dn = " + issuerDN );
168                    }
169
170                    if ( ( issuerDN != null ) && ( issuerDN.trim().length() > 0 ) )
171                    {
172                        if( !Dn.isValid(issuerDN) )
173                        {
174                            String msg = I18n.err( I18n.ERR_04034, issuerDN );
175                            LOG.error( msg );
176                            throw new DecoderException( msg );
177                        }
178                        
179                        container.getCertGenerationObject().setIssuerDN( issuerDN );
180                    }
181                }
182            } );
183
184        /**
185         * Transition from issuerDN state to subjectDN
186         *
187         * CertGenerationObject ::= SEQUENCE {
188         *     ... 
189         *     subjectDN IA5String,
190         *     ...
191         *     
192         * Set the subjectDN value into the CertGenerationObject instance.
193         */
194        super.transitions[CertGenerationStatesEnum.ISSUER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
195            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.ISSUER_STATE, 
196                CertGenerationStatesEnum.SUBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
197            new GrammarAction<CertGenerationContainer>( "Set Cert Generation subject Dn value" )
198            {
199                public void action( CertGenerationContainer container ) throws DecoderException
200                {
201                    Value value = container.getCurrentTLV().getValue();
202
203                    String subjectDN = Strings.utf8ToString(value.getData());
204
205                    if ( IS_DEBUG )
206                    {
207                        LOG.debug( "subject Dn = " + subjectDN );
208                    }
209
210                    if ( ( subjectDN != null ) && ( subjectDN.trim().length() > 0 ) )
211                    {
212                        if( !Dn.isValid(subjectDN) )
213                        {
214                            String msg = I18n.err( I18n.ERR_04035, subjectDN );
215                            LOG.error( msg );
216                            throw new DecoderException( msg );
217                        }
218
219                        container.getCertGenerationObject().setSubjectDN( subjectDN );
220                    }
221                    else
222                    {
223                        String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes(value.getData()) );
224                        LOG.error( msg );
225                        throw new DecoderException( msg );
226                    }
227                }
228            } );
229
230        /**
231         * Transition from subjectDN state to keyAlgo
232         *
233         * CertGenerationObject ::= SEQUENCE { 
234         *     ...
235         *     keyAlgorithm IA5String
236         *     
237         * Set the key algorithm value into the CertGenerationObject instance.
238         */
239        super.transitions[CertGenerationStatesEnum.SUBJECT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] = 
240            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.SUBJECT_STATE, 
241                CertGenerationStatesEnum.KEY_ALGORITHM_STATE,
242                UniversalTag.OCTET_STRING.getValue(), 
243                new GrammarAction<CertGenerationContainer>( "Set Cert Generation key algorithm value" )
244            {
245                public void action( CertGenerationContainer container ) throws DecoderException
246                {
247                    Value value = container.getCurrentTLV().getValue();
248
249                    String keyAlgorithm = Strings.utf8ToString(value.getData());
250
251                    if ( IS_DEBUG )
252                    {
253                        LOG.debug( "key algorithm = " + keyAlgorithm );
254                    }
255
256                    if ( keyAlgorithm != null && ( keyAlgorithm.trim().length() > 0 ) )
257                    {
258                        container.getCertGenerationObject().setKeyAlgorithm( keyAlgorithm );
259                    }
260
261                    container.setGrammarEndAllowed( true );
262                }
263            } );
264
265    }
266
267
268    /**
269     * This class is a singleton.
270     * 
271     * @return An instance on this grammar
272     */
273    public static Grammar<CertGenerationContainer> getInstance()
274    {
275        return instance;
276    }
277}