View Javadoc

1   /*
2    * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.xml.security.x509;
18  
19  import java.security.cert.CRLException;
20  import java.security.cert.CertificateEncodingException;
21  import java.util.List;
22  import java.util.Set;
23  
24  import javax.security.auth.x500.X500Principal;
25  
26  import org.opensaml.xml.Configuration;
27  import org.opensaml.xml.XMLObject;
28  import org.opensaml.xml.security.SecurityException;
29  import org.opensaml.xml.security.credential.BasicKeyInfoGeneratorFactory;
30  import org.opensaml.xml.security.credential.Credential;
31  import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
32  import org.opensaml.xml.security.keyinfo.KeyInfoHelper;
33  import org.opensaml.xml.signature.KeyInfo;
34  import org.opensaml.xml.signature.X509CRL;
35  import org.opensaml.xml.signature.X509Certificate;
36  import org.opensaml.xml.signature.X509Data;
37  import org.opensaml.xml.signature.X509SKI;
38  import org.opensaml.xml.signature.impl.KeyInfoBuilder;
39  import org.opensaml.xml.signature.impl.X509DataBuilder;
40  import org.opensaml.xml.util.DatatypeHelper;
41  import org.opensaml.xml.util.LazySet;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  /**
46   * A factory implementation which produces instances of {@link KeyInfoGenerator} capable of 
47   * handling the information contained within an {@link X509Credential}.
48   * 
49   * All boolean options default to false.  The default implementation of {@link X500DNHandler} used is
50   * {@link InternalX500DNHandler}.  The default output format for subject and issuer DN's is RFC2253.
51   * The default set of subject alternative names to process is empty.
52   */
53  public class X509KeyInfoGeneratorFactory extends BasicKeyInfoGeneratorFactory {
54      
55      /** The set of options configured for the factory. */
56      private X509Options options;
57      
58      /** Constructor. */
59      public X509KeyInfoGeneratorFactory() {
60          super();
61          options = (X509Options) super.getOptions();
62      }
63      
64      /** {@inheritDoc} */
65      public Class<? extends Credential> getCredentialType() {
66          return X509Credential.class;
67      }
68  
69      /** {@inheritDoc} */
70      public boolean handles(Credential credential) {
71          return credential instanceof X509Credential;
72      }
73  
74      /** {@inheritDoc} */
75      public KeyInfoGenerator newInstance() {
76          //TODO lock options during cloning ?
77          X509Options newOptions = options.clone();
78          return new X509KeyInfoGenerator(newOptions);
79      }
80      
81      /**
82       * Get the option to emit the CRL list as sequence of X509CRL elements within X509Data.
83       * 
84       * @return the option value
85       */
86      public boolean emitCRLs() {
87          return options.emitCRLs;
88      }
89  
90      /**
91       * Set the option to emit the CRL list as sequence of X509CRL elements within X509Data.
92       * 
93       * @param newValue the new option value
94       */
95      public void setEmitCRLs(boolean newValue) {
96          options.emitCRLs = newValue;
97      }
98  
99      /**
100      * Get the option to emit the entity certificate as an X509Certificate element within X509Data. 
101      *
102      * @return the option value
103      */
104     public boolean emitEntityCertificate() {
105         return options.emitEntityCertificate;
106     }
107 
108     /**
109      * Set the option to emit the entity certificate as an X509Certificate element within X509Data. 
110      *
111      * @param newValue the new option value
112      */
113     public void setEmitEntityCertificate(boolean newValue) {
114         options.emitEntityCertificate = newValue;
115     }
116 
117     /**
118      * Get the option to emit the entity certificate chain as sequence of X509Certificate elements within X509Data.
119      * 
120      * @return the option value
121      */
122     public boolean emitEntityCertificateChain() {
123         return options.emitEntityCertificateChain;
124     }
125 
126     /**
127      * Set the option to emit the entity certificate chain as sequence of X509Certificate elements within X509Data.
128      * 
129      * @param newValue the new option value
130      */
131     public void setEmitEntityCertificateChain(boolean newValue) {
132         options.emitEntityCertificateChain = newValue;
133     }
134 
135     /**
136      * Get the option to emit the entity certificate subject alternative name extension values as KeyName elements.
137      * 
138      * @return the option value
139      */
140     public boolean emitSubjectAltNamesAsKeyNames() {
141         return options.emitSubjectAltNamesAsKeyNames;
142     }
143 
144     /**
145      * Set the option to emit the entity certificate subject alternative name extension values as KeyName elements.
146      * 
147      * @param newValue the new option value
148      */
149     public void setEmitSubjectAltNamesAsKeyNames(boolean newValue) {
150         options.emitSubjectAltNamesAsKeyNames = newValue;
151     }
152 
153     /**
154      * Get the option to emit the entity certificate subject DN common name (CN) fields as KeyName elements.
155      * 
156      * @return the option value
157      */
158     public boolean emitSubjectCNAsKeyName() {
159         return options.emitSubjectCNAsKeyName;
160     }
161 
162     /**
163      * Set the option to emit the entity certificate subject DN common name (CN) fields as KeyName elements.
164      * 
165      * @param newValue the new option value
166      */
167     public void setEmitSubjectCNAsKeyName(boolean newValue) {
168         options.emitSubjectCNAsKeyName = newValue;
169     }
170 
171     /**
172      * Get the option to emit the entity certificate subject DN as a KeyName element.
173      * 
174      * @return the option value
175      */
176     public boolean emitSubjectDNAsKeyName() {
177         return options.emitSubjectDNAsKeyName;
178     }
179 
180     /**
181      * Set the option to emit the entity certificate subject DN as a KeyName element.
182      * 
183      * @param newValue the new option value
184      */
185     public void setEmitSubjectDNAsKeyName(boolean newValue) {
186         options.emitSubjectDNAsKeyName = newValue;
187     }
188 
189     /**
190      * Get the option to emit the entity certificate issuer name and serial number as 
191      * an X509IssuerSerial element within X509Data.
192      * 
193      * @return the option value
194      */
195     public boolean emitX509IssuerSerial() {
196         return options.emitX509IssuerSerial;
197     }
198 
199     /**
200      * Set the option to emit the entity certificate issuer name and serial number as 
201      * an X509IssuerSerial element within X509Data.
202      * 
203      * @param newValue the new option value
204      */
205     public void setEmitX509IssuerSerial(boolean newValue) {
206         options.emitX509IssuerSerial = newValue;
207     }
208 
209     /**
210      * Get the option to emit the entity certificate subject key identifier as an X509SKI element within X509Data.
211      * 
212      * @return the option value
213      */
214     public boolean emitX509SKI() {
215         return options.emitX509SKI;
216     }
217 
218     /**
219      * Set the option to emit the entity certificate subject key identifier as an X509SKI element within X509Data.
220      * 
221      * @param newValue the new option value
222      */
223     public void setEmitX509SKI(boolean newValue) {
224         options.emitX509SKI = newValue;
225     }
226 
227     /**
228      * Get the option to emit the entity certificate subject DN as an X509SubjectName element within X509Data.
229      * 
230      * @return the option value
231      */
232     public boolean emitX509SubjectName() {
233         return options.emitX509SubjectName;
234     }
235 
236     /**
237      * Set the option to emit the entity certificate subject DN as an X509SubjectName element within X509Data.
238      * 
239      * @param newValue the new option value
240      */
241     public void setEmitX509SubjectName(boolean newValue) {
242         options.emitX509SubjectName = newValue;
243     }
244 
245     /**
246      * The set of types of subject alternative names to process.
247      * 
248      * Name types are represented using the constant OID tag name values defined 
249      * in {@link X509Util}.
250      * 
251      * 
252      * @return the modifiable set of alt name identifiers
253      */
254     public Set<Integer> getSubjectAltNames() {
255         return options.subjectAltNames;
256     }
257     
258     /**
259      * Get the handler which process X.500 distinguished names.
260      * 
261      * Defaults to {@link InternalX500DNHandler}.
262      * 
263      * @return returns the X500DNHandler instance
264      */
265     public X500DNHandler getX500DNHandler() {
266         return options.x500DNHandler;
267     }
268 
269     /**
270      * Set the handler which process X.500 distinguished names.
271      * 
272      * Defaults to {@link InternalX500DNHandler}.
273      * 
274      * @param handler the new X500DNHandler instance
275      */
276     public void setX500DNHandler(X500DNHandler handler) {
277         if (handler == null) {
278             throw new IllegalArgumentException("X500DNHandler may not be null");
279         }
280         options.x500DNHandler = handler;
281     }
282     
283     /**
284      * Get the output format specifier for X.500 subject names.
285      * 
286      * Defaults to RFC2253 format. The meaning of this format specifier value
287      * is dependent upon the implementation of {@link X500DNHandler} which is used.
288      * 
289      * @return returns the format specifier
290      */
291     public String getX500SubjectDNFormat() {
292         return options.x500SubjectDNFormat;
293     }
294 
295     /**
296      * Set the output format specifier for X.500 subject names.
297      * 
298      * Defaults to RFC2253 format. The meaning of this format specifier value
299      * is dependent upon the implementation of {@link X500DNHandler} which is used.
300      * 
301      * @param format the new X500DNHandler instance
302      */
303     public void setX500SubjectDNFormat(String format) {
304         options.x500SubjectDNFormat = format;
305     }
306     
307     /**
308      * Get the output format specifier for X.500 issuer names.
309      * 
310      * Defaults to RFC2253 format. The meaning of this format specifier value
311      * is dependent upon the implementation of {@link X500DNHandler} which is used.
312      * 
313      * @return returns the format specifier
314      */
315     public String getX500IssuerDNFormat() {
316         return options.x500IssuerDNFormat;
317     }
318 
319     /**
320      * Set the output format specifier for X.500 issuer names.
321      * 
322      * Defaults to RFC2253 format. The meaning of this format specifier value
323      * is dependent upon the implementation of {@link X500DNHandler} which is used.
324      * 
325      * @param format the new X500DNHandler instance
326      */
327     public void setX500IssuerDNFormat(String format) {
328         options.x500IssuerDNFormat = format;
329     }
330 
331     /** {@inheritDoc} */
332     protected X509Options getOptions() {
333         return options;
334     }
335 
336     /** {@inheritDoc} */
337     protected X509Options newOptions() {
338         return new X509Options();
339     }
340 
341     /**
342      * An implementation of {@link KeyInfoGenerator} capable of  handling the information 
343      * contained within a {@link X509Credential}.
344      */
345     public class X509KeyInfoGenerator extends BasicKeyInfoGenerator {
346 
347         /** Class logger. */
348         private final Logger log = LoggerFactory.getLogger(X509KeyInfoGenerator.class);
349         
350         /** The set of options to be used by the generator.*/
351         private X509Options options;
352        
353         /** Builder for KeyInfo objects. */
354         private KeyInfoBuilder keyInfoBuilder;
355         
356         /** Builder for X509Data objects. */
357         private X509DataBuilder x509DataBuilder;
358        
359         /**
360          * Constructor.
361          * 
362          * @param newOptions the options to be used by the generator
363          */
364         protected X509KeyInfoGenerator(X509Options newOptions) {
365             super(newOptions);
366             options = newOptions;
367             
368             keyInfoBuilder = 
369                 (KeyInfoBuilder) Configuration.getBuilderFactory().getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME);
370             x509DataBuilder = 
371                 (X509DataBuilder) Configuration.getBuilderFactory().getBuilder(X509Data.DEFAULT_ELEMENT_NAME);
372         }
373 
374         /** {@inheritDoc} */
375         public KeyInfo generate(Credential credential) throws SecurityException {
376             if ( ! (credential instanceof X509Credential) ) {
377                 log.warn("X509KeyInfoGenerator was passed a credential that was not an instance of X509Credential: {}",
378                         credential.getClass().getName());
379                 return null;
380             }
381             X509Credential x509Credential = (X509Credential) credential;
382             
383             KeyInfo keyInfo =  super.generate(credential);
384             if (keyInfo == null) {
385                 keyInfo = keyInfoBuilder.buildObject();
386             }
387             X509Data x509Data = x509DataBuilder.buildObject();
388             
389             processEntityCertificate(keyInfo, x509Data, x509Credential);
390             processEntityCertificateChain(keyInfo, x509Data, x509Credential);
391             processCRLs(keyInfo, x509Data, x509Credential);
392             
393             List<XMLObject> x509DataChildren = x509Data.getOrderedChildren();
394             if (x509DataChildren != null && x509DataChildren.size() > 0) {
395                 keyInfo.getX509Datas().add(x509Data);
396             }
397             
398             List<XMLObject> keyInfoChildren = keyInfo.getOrderedChildren();
399             if (keyInfoChildren != null && keyInfoChildren.size() > 0) {
400                 return keyInfo;
401             } else {
402                 return null;
403             }
404         }
405         
406         /** Process the value of {@link X509Credential#getEntityCertificate()}.
407          * 
408          * @param keyInfo the KeyInfo that is being built
409          * @param x509Data the X509Data that is being built
410          * @param credential the Credential that is being processed
411          * @throws SecurityException thrown if the certificate data can not be encoded from the Java certificate object
412          */
413         protected void processEntityCertificate(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) 
414                 throws SecurityException {
415             
416             if (credential.getEntityCertificate() == null) {
417                 return;
418             }
419             
420             java.security.cert.X509Certificate javaCert = credential.getEntityCertificate();
421             
422             processCertX509DataOptions(x509Data, javaCert);
423             processCertKeyNameOptions(keyInfo, javaCert);
424             
425             // The cert chain includes the entity cert, so don't add a duplicate
426             if (options.emitEntityCertificate && ! options.emitEntityCertificateChain) {
427                 try {
428                     X509Certificate xmlCert = KeyInfoHelper.buildX509Certificate(javaCert);
429                     x509Data.getX509Certificates().add(xmlCert);
430                 } catch (CertificateEncodingException e) {
431                     throw new SecurityException("Error generating X509Certificate element " 
432                             + "from credential's end-entity certificate", e);
433                 }
434             }
435             
436         }
437         
438         /**
439          * Process the options related to generation of child elements of X509Data based on certificate data.
440          * 
441          * @param x509Data the X509Data element being processed.
442          * @param cert the certificate being processed
443          */
444         protected void processCertX509DataOptions(X509Data x509Data, java.security.cert.X509Certificate cert) {
445             processCertX509SubjectName(x509Data, cert);
446             processCertX509IssuerSerial(x509Data, cert);
447             processCertX509SKI(x509Data, cert);
448         }
449         
450         /**
451          * Process the options related to generation of KeyName elements based on certificate data.
452          * 
453          * @param keyInfo the KeyInfo element being processed.
454          * @param cert the certificate being processed
455          */
456         protected void processCertKeyNameOptions(KeyInfo keyInfo, java.security.cert.X509Certificate cert) {
457             processSubjectDNKeyName(keyInfo, cert);
458             processSubjectCNKeyName(keyInfo, cert);
459             processSubjectAltNameKeyNames(keyInfo, cert);
460         }
461         
462         /**
463          * Process the options related to generation of the X509SubjectDN child element of X509Data 
464          * based on certificate data.
465          * 
466          * @param x509Data the X509Data element being processed.
467          * @param cert the certificate being processed
468          */
469         protected void processCertX509SubjectName(X509Data x509Data, java.security.cert.X509Certificate cert) {
470             if (options.emitX509SubjectName) {
471                 String subjectNameValue = getSubjectName(cert);
472                 if (! DatatypeHelper.isEmpty(subjectNameValue)) {
473                     x509Data.getX509SubjectNames().add( KeyInfoHelper.buildX509SubjectName(subjectNameValue));
474                 }
475             }
476         }
477         
478         /**
479          * Process the options related to generation of the X509IssuerSerial child element of X509Data 
480          * based on certificate data.
481          * 
482          * @param x509Data the X509Data element being processed.
483          * @param cert the certificate being processed
484          */ 
485         protected void processCertX509IssuerSerial(X509Data x509Data, java.security.cert.X509Certificate cert) {
486             if (options.emitX509IssuerSerial) {
487                 String issuerNameValue = getIssuerName(cert);
488                 if (! DatatypeHelper.isEmpty(issuerNameValue)) {
489                     x509Data.getX509IssuerSerials().add( 
490                             KeyInfoHelper.buildX509IssuerSerial(issuerNameValue, cert.getSerialNumber()) );
491                 }
492             }
493         }
494         
495         /**
496          * Process the options related to generation of the X509SKI child element of X509Data 
497          * based on certificate data.
498          * 
499          * @param x509Data the X509Data element being processed.
500          * @param cert the certificate being processed
501          */ 
502         protected void processCertX509SKI(X509Data x509Data, java.security.cert.X509Certificate cert) {
503             if (options.emitX509SKI) {
504                 X509SKI xmlSKI = KeyInfoHelper.buildX509SKI(cert);
505                 if (xmlSKI != null) {
506                     x509Data.getX509SKIs().add(xmlSKI);
507                 }
508             }
509         }
510         
511         /**
512          * Get subject name from a certificate, using the currently configured X500DNHandler
513          * and subject DN output format.
514          * 
515          * @param cert the certificate being processed
516          * @return the subject name
517          */
518         protected String getSubjectName(java.security.cert.X509Certificate cert) {
519             if (cert == null) {
520                 return null;
521             }
522             if (! DatatypeHelper.isEmpty(options.x500SubjectDNFormat)) {
523                 return options.x500DNHandler.getName(cert.getSubjectX500Principal(), options.x500SubjectDNFormat);
524             } else {
525                 return options.x500DNHandler.getName(cert.getSubjectX500Principal());
526             }
527         }
528         
529         /**
530          * Get issuer name from a certificate, using the currently configured X500DNHandler
531          * and issuer DN output format.
532          * 
533          * @param cert the certificate being processed
534          * @return the issuer name
535          */
536         protected String getIssuerName(java.security.cert.X509Certificate cert) {
537             if (cert == null) {
538                 return null;
539             }
540             if (! DatatypeHelper.isEmpty(options.x500IssuerDNFormat)) {
541                 return options.x500DNHandler.getName(cert.getIssuerX500Principal(), options.x500IssuerDNFormat);
542             } else {
543                 return options.x500DNHandler.getName(cert.getIssuerX500Principal());
544             }
545         }
546 
547         /**
548          * Process the options related to generation of KeyName elements based on the certificate's
549          * subject DN value.
550          * 
551          * @param keyInfo the KeyInfo element being processed.
552          * @param cert the certificate being processed
553          */
554         protected void processSubjectDNKeyName(KeyInfo keyInfo, java.security.cert.X509Certificate cert) {
555             if (options.emitSubjectDNAsKeyName) {
556                 String subjectNameValue = getSubjectName(cert);
557                 if (! DatatypeHelper.isEmpty(subjectNameValue)) {
558                    KeyInfoHelper.addKeyName(keyInfo, subjectNameValue); 
559                 }
560             }
561         }
562         
563         /**
564          * Process the options related to generation of KeyName elements based on the
565          * the common name field(s) of the certificate's subject DN.
566          * 
567          * @param keyInfo the KeyInfo element being processed.
568          * @param cert the certificate being processed
569          */
570         protected void processSubjectCNKeyName(KeyInfo keyInfo, java.security.cert.X509Certificate cert) {
571             if (options.emitSubjectCNAsKeyName) {
572                 for (String name : X509Util.getCommonNames(cert.getSubjectX500Principal())) {
573                     if (! DatatypeHelper.isEmpty(name)) {
574                         KeyInfoHelper.addKeyName(keyInfo, name);
575                     }
576                 }
577             }
578         }
579         
580         /**
581          * Process the options related to generation of KeyName elements based on subject
582          * alternative name information within the certificate data.
583          * 
584          * @param keyInfo the KeyInfo element being processed.
585          * @param cert the certificate being processed
586          */
587         protected void processSubjectAltNameKeyNames(KeyInfo keyInfo, java.security.cert.X509Certificate cert) {
588             if (options.emitSubjectAltNamesAsKeyNames && options.subjectAltNames.size() > 0) {
589                 Integer[] nameTypes = new Integer[ options.subjectAltNames.size() ];
590                 options.subjectAltNames.toArray(nameTypes);
591                 for (Object altNameValue : X509Util.getAltNames(cert, nameTypes)) {
592                     // Each returned value should either be a String or a DER-encoded byte array.
593                     // See X509Certificate#getSubjectAlternativeNames for the type rules.
594                     if (altNameValue instanceof String) {
595                         KeyInfoHelper.addKeyName(keyInfo, (String) altNameValue);
596                     } else if (altNameValue instanceof byte[]){
597                         log.warn("Certificate contained an alt name value as a DER-encoded byte[] (not supported)");
598                     } else {
599                         log.warn("Certificate contained an alt name value with an unexpected type: {}",
600                                 altNameValue.getClass().getName());
601                     }
602                 }
603             }
604         }
605         
606         /** Process the value of {@link X509Credential#getEntityCertificateChain()}.
607          * 
608          * @param keyInfo the KeyInfo that is being built
609          * @param x509Data the X509Data that is being built
610          * @param credential the Credential that is being processed
611          * @throws SecurityException thrown if the certificate data can not be encoded from the Java certificate object
612          */
613         protected void processEntityCertificateChain(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) 
614                 throws SecurityException {
615             
616             if (options.emitEntityCertificateChain && credential.getEntityCertificateChain() != null) {
617                 for (java.security.cert.X509Certificate javaCert : credential.getEntityCertificateChain()) {
618                     try {
619                         X509Certificate xmlCert = KeyInfoHelper.buildX509Certificate(javaCert);
620                         x509Data.getX509Certificates().add(xmlCert);
621                     } catch (CertificateEncodingException e) {
622                         throw new SecurityException("Error generating X509Certificate element " 
623                                 + "from a certificate in credential's certificate chain", e);
624                     }
625                 }
626             }
627         }
628 
629         /** Process the value of {@link X509Credential#getCRLs()}.
630          * 
631          * @param keyInfo the KeyInfo that is being built
632          * @param x509Data the X509Data that is being built
633          * @param credential the Credential that is being processed
634          * @throws SecurityException thrown if the CRL data can not be encoded from the Java certificate object
635          */
636         protected void processCRLs(KeyInfo keyInfo, X509Data x509Data, X509Credential credential) 
637                 throws SecurityException {
638             
639             if (options.emitCRLs && credential.getCRLs() != null) {
640                 for (java.security.cert.X509CRL javaCRL : credential.getCRLs()) {
641                     try {
642                         X509CRL xmlCRL = KeyInfoHelper.buildX509CRL(javaCRL);
643                         x509Data.getX509CRLs().add(xmlCRL);
644                     } catch (CRLException e) {
645                         throw new SecurityException("Error generating X509CRL element " 
646                                 + "from a CRL in credential's CRL list", e);
647                     }
648                 }
649             }
650         }
651         
652     }
653     
654     /**
655     * Options to be used in the production of a {@link KeyInfo} from an {@link X509Credential}.
656     */
657    protected class X509Options extends BasicOptions {
658        
659        /** Emit the entity certificate as an X509Certificate element within X509Data. */
660        private  boolean emitEntityCertificate;
661        
662        /** Emit the entity certificate chain as sequence of X509Certificate elements within X509Data. */
663        private boolean emitEntityCertificateChain;
664        
665        /** Emit the CRL list as sequence of X509CRL elements within X509Data. */
666        private boolean emitCRLs;
667        
668        /** Emit the entity certificate subject DN as an X509SubjectName element within X509Data. */
669        private boolean emitX509SubjectName;
670        
671        /** Emit the entity certificate issuer name and serial number as an X509IssuerSerial element within X509Data. */
672        private boolean emitX509IssuerSerial;
673        
674        /** Emit the entity certificate subject key identifier as an X509SKI element within X509Data. */
675        private boolean emitX509SKI;
676        
677        /** Emit the entity certificate subject DN as a KeyName element. */
678        private boolean emitSubjectDNAsKeyName;
679        
680        /** Emit the entity certificate subject DN common name (CN) fields as KeyName elements. */
681        private boolean emitSubjectCNAsKeyName;
682        
683        /** Emit the entity certificate subject alternative name extension values as KeyName elements. */
684        private boolean emitSubjectAltNamesAsKeyNames;
685        
686        /** The set of types of subject alternative names to process. */
687        private Set<Integer> subjectAltNames;
688        
689        /** Responsible for parsing and serializing X.500 names to/from {@link X500Principal} instances. */
690        private X500DNHandler x500DNHandler;
691        
692        /** The format specifier for outputting X.500 subject names. */
693        private String x500SubjectDNFormat;
694        
695        /** The format specifier for outputting X.500 issuer names. */
696        private String x500IssuerDNFormat;
697        
698        /** Constructor. */
699        protected X509Options() {
700            subjectAltNames = new LazySet<Integer>();
701            x500DNHandler = new InternalX500DNHandler();
702            x500SubjectDNFormat = X500DNHandler.FORMAT_RFC2253;
703            x500IssuerDNFormat = X500DNHandler.FORMAT_RFC2253;
704        }
705        
706        /** {@inheritDoc} */
707        protected X509Options clone() {
708            X509Options clonedOptions = (X509Options) super.clone();
709            
710            clonedOptions.subjectAltNames = new LazySet<Integer>();
711            clonedOptions.subjectAltNames.addAll(this.subjectAltNames);
712            
713            clonedOptions.x500DNHandler = this.x500DNHandler.clone();
714            
715            return clonedOptions;
716        }
717        
718    }
719 
720 }