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