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.api.ldap.extras.extended.ads_impl.certGeneration;
021
022
023import org.apache.directory.api.asn1.DecoderException;
024import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
025import org.apache.directory.api.asn1.ber.grammar.Grammar;
026import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
027import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
028import org.apache.directory.api.asn1.ber.tlv.BerValue;
029import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
030import org.apache.directory.api.i18n.I18n;
031import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
032import org.apache.directory.api.ldap.extras.extended.certGeneration.CertGenerationRequestImpl;
033import org.apache.directory.api.ldap.model.name.Dn;
034import org.apache.directory.api.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    /**
071     * Creates a new CertGenerationGrammar object.
072     */
073    @SuppressWarnings("unchecked")
074    public CertGenerationGrammar()
075    {
076        setName( CertGenerationGrammar.class.getName() );
077
078        // Create the transitions table
079        super.transitions = new GrammarTransition[CertGenerationStatesEnum.LAST_CERT_GENERATION_STATE.ordinal()][256];
080
081        /**
082         * Transition from init state to certificate generation
083         * 
084         * CertGenerationObject ::= SEQUENCE {
085         *     ...
086         *     
087         * Creates the CertGenerationObject object
088         */
089        super.transitions[CertGenerationStatesEnum.START_STATE.ordinal()][UniversalTag.SEQUENCE.getValue()] =
090            new GrammarTransition<CertGenerationContainer>(
091                CertGenerationStatesEnum.START_STATE, CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE,
092                UniversalTag.SEQUENCE.getValue(), new GrammarAction<CertGenerationContainer>(
093                    "Init CertGenerationObject" )
094                {
095                    public void action( CertGenerationContainer container )
096                    {
097                        CertGenerationRequestDecorator certGenerationRequest = new CertGenerationRequestDecorator(
098                            LdapApiServiceFactory.getSingleton(), new CertGenerationRequestImpl() );
099                        container.setCertGenerationRequest( certGenerationRequest );
100                    }
101                } );
102
103        /**
104         * Transition from certificate generation request to targetDN
105         *
106         * CertGenerationObject ::= SEQUENCE { 
107         *     targetDN IA5String,
108         *     ...
109         *     
110         * Set the targetDN value into the CertGenerationObject instance.
111         */
112        super.transitions[CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE.ordinal()][UniversalTag.OCTET_STRING
113            .getValue()] =
114            new GrammarTransition<CertGenerationContainer>(
115                CertGenerationStatesEnum.CERT_GENERATION_REQUEST_SEQUENCE_STATE,
116                CertGenerationStatesEnum.TARGETDN_STATE, UniversalTag.OCTET_STRING.getValue(),
117                new GrammarAction<CertGenerationContainer>( "Set Cert Generation target Dn value" )
118                {
119                    public void action( CertGenerationContainer container ) throws DecoderException
120                    {
121                        BerValue value = container.getCurrentTLV().getValue();
122
123                        String targetDN = Strings.utf8ToString( value.getData() );
124
125                        if ( IS_DEBUG )
126                        {
127                            LOG.debug( "Target Dn = " + targetDN );
128                        }
129
130                        if ( ( targetDN != null ) && ( targetDN.trim().length() > 0 ) )
131                        {
132                            if ( !Dn.isValid( targetDN ) )
133                            {
134                                String msg = I18n.err( I18n.ERR_04032, targetDN );
135                                LOG.error( msg );
136                                throw new DecoderException( msg );
137                            }
138
139                            container.getCertGenerationRequest().setTargetDN( targetDN );
140                        }
141                        else
142                        {
143                            String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes( value.getData() ) );
144                            LOG.error( msg );
145                            throw new DecoderException( msg );
146                        }
147                    }
148                } );
149
150        /**
151         * Transition from targetDN state to issuerDN
152         *
153         * CertGenerationObject ::= SEQUENCE { 
154         *     ...
155         *     issuerDN IA5String,
156         *     ...
157         *     
158         * Set the issuerDN value into the CertGenerationObject instance.
159         */
160        super.transitions[CertGenerationStatesEnum.TARGETDN_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
161            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.TARGETDN_STATE,
162                CertGenerationStatesEnum.ISSUER_STATE, UniversalTag.OCTET_STRING.getValue(),
163                new GrammarAction<CertGenerationContainer>( "Set Cert Generation issuer Dn value" )
164                {
165                    public void action( CertGenerationContainer container ) throws DecoderException
166                    {
167                        BerValue value = container.getCurrentTLV().getValue();
168
169                        String issuerDN = Strings.utf8ToString( value.getData() );
170
171                        if ( IS_DEBUG )
172                        {
173                            LOG.debug( "Issuer Dn = " + issuerDN );
174                        }
175
176                        if ( ( issuerDN != null ) && ( issuerDN.trim().length() > 0 ) )
177                        {
178                            if ( !Dn.isValid( issuerDN ) )
179                            {
180                                String msg = I18n.err( I18n.ERR_04034, issuerDN );
181                                LOG.error( msg );
182                                throw new DecoderException( msg );
183                            }
184
185                            container.getCertGenerationRequest().setIssuerDN( issuerDN );
186                        }
187                    }
188                } );
189
190        /**
191         * Transition from issuerDN state to subjectDN
192         *
193         * CertGenerationObject ::= SEQUENCE {
194         *     ... 
195         *     subjectDN IA5String,
196         *     ...
197         *     
198         * Set the subjectDN value into the CertGenerationObject instance.
199         */
200        super.transitions[CertGenerationStatesEnum.ISSUER_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
201            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.ISSUER_STATE,
202                CertGenerationStatesEnum.SUBJECT_STATE, UniversalTag.OCTET_STRING.getValue(),
203                new GrammarAction<CertGenerationContainer>( "Set Cert Generation subject Dn value" )
204                {
205                    public void action( CertGenerationContainer container ) throws DecoderException
206                    {
207                        BerValue value = container.getCurrentTLV().getValue();
208
209                        String subjectDN = Strings.utf8ToString( value.getData() );
210
211                        if ( IS_DEBUG )
212                        {
213                            LOG.debug( "subject Dn = " + subjectDN );
214                        }
215
216                        if ( ( subjectDN != null ) && ( subjectDN.trim().length() > 0 ) )
217                        {
218                            if ( !Dn.isValid( subjectDN ) )
219                            {
220                                String msg = I18n.err( I18n.ERR_04035, subjectDN );
221                                LOG.error( msg );
222                                throw new DecoderException( msg );
223                            }
224
225                            container.getCertGenerationRequest().setSubjectDN( subjectDN );
226                        }
227                        else
228                        {
229                            String msg = I18n.err( I18n.ERR_04033, Strings.dumpBytes( value.getData() ) );
230                            LOG.error( msg );
231                            throw new DecoderException( msg );
232                        }
233                    }
234                } );
235
236        /**
237         * Transition from subjectDN state to keyAlgo
238         *
239         * CertGenerationObject ::= SEQUENCE { 
240         *     ...
241         *     keyAlgorithm IA5String
242         *     
243         * Set the key algorithm value into the CertGenerationObject instance.
244         */
245        super.transitions[CertGenerationStatesEnum.SUBJECT_STATE.ordinal()][UniversalTag.OCTET_STRING.getValue()] =
246            new GrammarTransition<CertGenerationContainer>( CertGenerationStatesEnum.SUBJECT_STATE,
247                CertGenerationStatesEnum.KEY_ALGORITHM_STATE,
248                UniversalTag.OCTET_STRING.getValue(),
249                new GrammarAction<CertGenerationContainer>( "Set Cert Generation key algorithm value" )
250                {
251                    public void action( CertGenerationContainer container ) throws DecoderException
252                    {
253                        BerValue value = container.getCurrentTLV().getValue();
254
255                        String keyAlgorithm = Strings.utf8ToString( value.getData() );
256
257                        if ( IS_DEBUG )
258                        {
259                            LOG.debug( "key algorithm = " + keyAlgorithm );
260                        }
261
262                        if ( keyAlgorithm != null && ( keyAlgorithm.trim().length() > 0 ) )
263                        {
264                            container.getCertGenerationRequest().setKeyAlgorithm( keyAlgorithm );
265                        }
266
267                        container.setGrammarEndAllowed( true );
268                    }
269                } );
270
271    }
272
273
274    /**
275     * This class is a singleton.
276     * 
277     * @return An instance on this grammar
278     */
279    public static Grammar<CertGenerationContainer> getInstance()
280    {
281        return instance;
282    }
283}