Home | History | Annotate | Download | only in support
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 /**
     19 * @author Alexander V. Astapchuk
     20 * @version $Revision$
     21 */
     22 
     23 package org.apache.harmony.security.tests.support;
     24 
     25 import java.io.IOException;
     26 import java.io.InputStream;
     27 import java.io.ObjectInputStream;
     28 import java.io.ObjectOutputStream;
     29 import java.io.Serializable;
     30 import java.io.StreamCorruptedException;
     31 import java.math.BigInteger;
     32 
     33 import java.security.InvalidKeyException;
     34 import java.security.NoSuchAlgorithmException;
     35 import java.security.NoSuchProviderException;
     36 import java.security.Principal;
     37 import java.security.Provider;
     38 import java.security.PublicKey;
     39 import java.security.Security;
     40 import java.security.SignatureException;
     41 
     42 import java.security.cert.*;
     43 import java.util.*;
     44 
     45 import javax.security.auth.x500.X500Principal;
     46 
     47 /**
     48  * The class contains various utility methods used during the java.security
     49  * classes testing.
     50  *
     51  */
     52 
     53 public final class TestCertUtils {
     54 
     55     private TestCertUtils() {
     56         throw new Error("statics only");
     57     }
     58 
     59     /**
     60      * Returns new instance of test certificate each time the method is called.
     61      *
     62      * @return test certificate
     63      */
     64     public static Certificate getCert() {
     65         return new TestCertificate();
     66     }
     67 
     68     /**
     69      * Returns an array of 3 test certificates. IMP: The array returned is not
     70      * real chain of certificates, it's just an array of 3 certs. The method
     71      * returns new array each time it's called. The number of 3 was chosen
     72      * arbitrarily and is subject to change.
     73      *
     74      * @return an array of 3 certificates
     75      */
     76     public static Certificate[] getCertChain() {
     77         Certificate[] chain = { new TestCertificate(), new TestCertificate(),
     78                 new TestCertificate() };
     79         return chain;
     80     }
     81 
     82     /**
     83      * Returns a test CertPath, which uses getCertChain() to obtain a list of
     84      * certificates to store.
     85      *
     86      * @return test cert path
     87      */
     88     public static CertPath getCertPath() {
     89         return new TestCertPath();
     90     }
     91 
     92     /**
     93      * Generates and returns an instance of TestCertPath.<br>
     94      * TestCertificate-s included in the CertPath will be uniq (will have
     95      * different numbers passed to their ctor-s).<br>
     96      * The second arguments shows which number will have the first Certificate
     97      * in the CertPath. The second certificate will have (startID+1) number
     98      * and so on.
     99      *
    100      * @param howMany - shows how many TestCerts must contain the CertPath generated
    101      * @param startID - specifies the starting ID which the first certificate will have
    102      * @return TestCertPath
    103      */
    104     public static CertPath genCertPath(int howMany, int startID) {
    105         Certificate[] certs = new Certificate[howMany];
    106         for (int i = 0; i < howMany; i++) {
    107             certs[i] = new TestCertificate(Integer.toString(startID + i));
    108         }
    109         return new TestCertPath(certs);
    110     }
    111 
    112     private static Provider provider = null;
    113 
    114     private static final String providerName = "TstPrvdr";
    115 
    116     /**
    117      * A Principal used to form rootCA's certificate
    118      */
    119     public static final X500Principal rootPrincipal = new X500Principal(
    120             UniGen.rootName);
    121 
    122     /**
    123      * Some fake rootCA's certificate.
    124      */
    125     public static final X509Certificate rootCA = new TestX509Certificate(
    126             rootPrincipal, rootPrincipal);
    127 
    128     public static void install_test_x509_factory() {
    129         if (provider == null) {
    130             provider = new TestProvider(providerName, 0.01,
    131                     "Test provider for serialization testing");
    132             Security.insertProviderAt(provider, 1);
    133         }
    134     }
    135 
    136     public static void uninstall_test_x509_factory() {
    137         if (provider != null) {
    138             Security.removeProvider(providerName);
    139             provider = null;
    140         }
    141     }
    142 
    143     /**
    144      * The class represents test certificate path.
    145      *
    146      */
    147 
    148     public static final class TestCertPath extends CertPath implements
    149             Serializable {
    150 
    151         private static final byte[] encoded = new byte[] { 1, 2, 3, 4, 5, 6, 7,
    152                 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
    153 
    154         private static final String serializedData = "Just a dummy string to be serialized instead of real data";
    155 
    156         private Certificate[] certs;
    157 
    158         /**
    159          * Default ctor for TestCertPath. Uses {@link TestCertUtils#getCertChain()}
    160          * to obtain list of certificates.<br>
    161          * All TestCertPath-s constructed via this ctor will be equals() to each
    162          * other.
    163          */
    164         public TestCertPath() {
    165             super("testCertPath");
    166             certs = getCertChain();
    167         }
    168 
    169         /**
    170          * Constructs TestCertPath and keeps the given array of certificates.<br>
    171          * The TestCertPaths constructed via this ctor may be different (if they
    172          * have different set of certificates)<br>
    173          * @see TestCertUtils#genCertPath(int, int)
    174          * @param certs
    175          */
    176         public TestCertPath(Certificate[] certs) {
    177             super("testCertPath");
    178             this.certs = certs;
    179         }
    180 
    181         /**
    182          * @see java.security.cert.CertPath#getCertificates()
    183          */
    184         public List<Certificate> getCertificates() {
    185             return Arrays.asList(certs);
    186         }
    187 
    188         /**
    189          * @see java.security.cert.CertPath#getEncoded()
    190          */
    191         public byte[] getEncoded() throws CertificateEncodingException {
    192             return encoded.clone();
    193         }
    194 
    195         /**
    196          * @see java.security.cert.CertPath#getEncoded(java.lang.String)
    197          */
    198         public byte[] getEncoded(String encoding)
    199                 throws CertificateEncodingException {
    200             return encoded.clone();
    201         }
    202 
    203         /**
    204          * @see java.security.cert.CertPath#getEncodings()
    205          */
    206         public Iterator<String> getEncodings() {
    207             Vector<String> v = new Vector<String>();
    208             v.add("myTestEncoding");
    209             return v.iterator();
    210         }
    211 
    212         public String toString() {
    213             StringBuffer buf = new StringBuffer(200);
    214             buf.append("TestCertPath. certs count=");
    215             if( certs == null ) {
    216                 buf.append("0\n");
    217             }
    218             else {
    219                 buf.append(certs.length).append("\n");
    220                 for( int i=0; i<certs.length; i++) {
    221                     buf.append("\t").append(i).append(" ");
    222                     buf.append(certs[i]).append("\n");
    223                 }
    224             }
    225             return buf.toString();
    226         }
    227 
    228         /**
    229          * Writes<br>
    230          * (String) serializedData<br>
    231          * (int) number of certificates in this CertPath<br>
    232          * <array of certificates>
    233          *
    234          * @param out
    235          * @throws IOException
    236          */
    237         private void writeObject(ObjectOutputStream out) throws IOException {
    238             out.writeUTF(serializedData);
    239             if (certs == null) {
    240                 out.writeInt(0);
    241             } else {
    242                 out.writeInt(certs.length);
    243                 for (int i = 0; i < certs.length; i++) {
    244                     out.writeObject(certs[i]);
    245                 }
    246             }
    247         }
    248 
    249         private void readObject(ObjectInputStream in) throws IOException,
    250                 ClassNotFoundException {
    251             String s = in.readUTF();
    252             if (!serializedData.equals(s)) {
    253                 throw new StreamCorruptedException("expect [" + serializedData
    254                         + "] got [" + s + "]");
    255             }
    256             int count = in.readInt();
    257             certs = new Certificate[count];
    258             for (int i = 0; i < count; i++) {
    259                 certs[i] = (Certificate) in.readObject();
    260             }
    261         }
    262 
    263         protected Object writeReplace() {
    264             return this;
    265         }
    266 
    267         protected Object readResolve() {
    268             return this;
    269         }
    270     }
    271 
    272     /**
    273      * The class represents empty PublicKey.
    274      *
    275      */
    276 
    277     public static final class TestPublicKey implements PublicKey {
    278         private static final String algo = "testPublicKeyAlgorithm";
    279 
    280         private static final byte[] encoded = new byte[] { 1, 2, 3, 4, 5, 6, 7,
    281                 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
    282 
    283         private static final String format = "testPublicKeyFormat";
    284 
    285         public String getAlgorithm() {
    286             return algo;
    287         }
    288 
    289         public byte[] getEncoded() {
    290             return encoded.clone();
    291         }
    292 
    293         public String getFormat() {
    294             return format;
    295         }
    296     }
    297 
    298     /**
    299      * The class represents test certificate.
    300      *
    301      */
    302 
    303     public static class TestCertificate extends Certificate implements
    304             Serializable {
    305 
    306         private static final byte[] encoded = new byte[] { 1, 2, 3, 4, 5, 6, 7,
    307                 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF };
    308 
    309         public static final String TYPE = "Test";
    310 
    311         //
    312         // A String that makes different TestCertificates to be different.
    313         //
    314         private String diff = null;
    315 
    316         /**
    317          * Default ctor. All the TestCertificate-s created with this ctor are equals() to each other.
    318          * Use TestCertificate(String) if you need non equal TestCertificate-s.
    319          */
    320         public TestCertificate() {
    321             super(TYPE);
    322         }
    323 
    324         /**
    325          * A special purpose ctor. Pass different String-s to have different TestCertificates.
    326          * TestCertificate-s with the same String passed to this ctor are considered equal.
    327          */
    328         public TestCertificate(String diff) {
    329             super(TYPE);
    330             this.diff = diff;
    331         }
    332 
    333         /**
    334          * A ctor that allows to specify both the TYPE of certificate and the
    335          * diff. Leave the <code>diff</code> null when no difference needed.
    336          *
    337          * @param diff
    338          * @param type
    339          */
    340         public TestCertificate(String diff, String type) {
    341             super(type);
    342             this.diff = diff;
    343         }
    344 
    345         public byte[] getEncoded() throws CertificateEncodingException {
    346             return encoded.clone();
    347         }
    348 
    349         public void verify(PublicKey key) throws CertificateException,
    350                 NoSuchAlgorithmException, InvalidKeyException,
    351                 NoSuchProviderException, SignatureException {
    352             // do nothing
    353         }
    354 
    355         public void verify(PublicKey key, String sigProvider)
    356                 throws CertificateException, NoSuchAlgorithmException,
    357                 InvalidKeyException, NoSuchProviderException,
    358                 SignatureException {
    359             // do nothing
    360 
    361         }
    362 
    363         public String toString() {
    364             return "Test certificate - for unit testing only";
    365         }
    366 
    367         public boolean equals(Object obj) {
    368             if (obj == null || !(obj instanceof TestCertificate)) {
    369                 return false;
    370             }
    371             TestCertificate that = (TestCertificate) obj;
    372             if (this == that) {
    373                 return true;
    374             }
    375             if (this.diff == null) {
    376                 return that.diff == null;
    377             }
    378             return this.diff.equals(that.diff);
    379         }
    380 
    381         public PublicKey getPublicKey() {
    382             return new TestPublicKey();
    383         }
    384 
    385         /**
    386          * Writes:<br>
    387          * boolean - true if this certificate has a diff string,
    388          * false otherwise, followed by <br>
    389          * writeUTF() of string (if presented)
    390          *
    391          * @param out
    392          * @throws IOException
    393          */
    394         private void writeObject(ObjectOutputStream out) throws IOException {
    395             if (diff == null) {
    396                 out.writeBoolean(false);
    397             } else {
    398                 out.writeBoolean(false);
    399                 out.writeUTF(diff);
    400             }
    401         }
    402 
    403         private void readObject(ObjectInputStream in) throws IOException,
    404                 ClassNotFoundException {
    405             boolean hasDiffString = in.readBoolean();
    406             if (hasDiffString) {
    407                 diff = in.readUTF();
    408             }
    409         }
    410 
    411         protected Object writeReplace() {
    412             return this;
    413         }
    414 
    415         protected Object readResolve() {
    416             return this;
    417         }
    418     }
    419 
    420     public static class TestInvalidX509Certificate extends TestX509Certificate {
    421         public TestInvalidX509Certificate(X500Principal subj,
    422                 X500Principal issuer) {
    423             super(subj, issuer);
    424         }
    425     }
    426 
    427     /**
    428      *
    429      * TestX509CErtificate.<br>
    430      * Does nothing interesting, but<br>
    431      * a) is not abstract, so it can be instantiated<br>
    432      * b) returns Encoded form<br>
    433      *
    434      */
    435     public static class TestX509Certificate extends X509Certificate {
    436         private X500Principal subject;
    437 
    438         private X500Principal issuer;
    439 
    440         public TestX509Certificate(X500Principal subj, X500Principal issuer) {
    441             this.subject = subj;
    442             this.issuer = issuer;
    443         }
    444 
    445         public X500Principal getIssuerX500Principal() {
    446             return issuer;
    447         }
    448 
    449         public X500Principal getSubjectX500Principal() {
    450             return subject;
    451         }
    452 
    453         /**
    454          * The encoded for of this X509Certificate is a byte array where
    455          * first are bytes of encoded form of Subject (as X500Principal),
    456          * followed by one zero byte
    457          * and followed by the encoded form of Issuer (as X500Principal)
    458          *
    459          */
    460         public byte[] getEncoded() throws CertificateEncodingException {
    461             byte[] asubj = subject.getEncoded();
    462             byte[] aissuer = issuer.getEncoded();
    463             byte[] data = new byte[asubj.length + aissuer.length + 1];
    464 
    465             System.arraycopy(asubj, 0, data, 0, asubj.length);
    466             //data[asubj.length] = 0;
    467             System
    468                     .arraycopy(aissuer, 0, data, asubj.length + 1,
    469                             aissuer.length);
    470             return data;
    471         }
    472 
    473         public void checkValidity() throws CertificateExpiredException,
    474                 CertificateNotYetValidException {
    475         }
    476 
    477         public void checkValidity(Date date)
    478                 throws CertificateExpiredException,
    479                 CertificateNotYetValidException {
    480         }
    481 
    482         public int getBasicConstraints() {
    483             return 0;
    484         }
    485 
    486         public Principal getIssuerDN() {
    487             return null;
    488         }
    489 
    490         public boolean[] getIssuerUniqueID() {
    491             return null;
    492         }
    493 
    494         public boolean[] getKeyUsage() {
    495             return null;
    496         }
    497 
    498         public Date getNotAfter() {
    499             return null;
    500         }
    501 
    502         public Date getNotBefore() {
    503             return null;
    504         }
    505 
    506         public BigInteger getSerialNumber() {
    507             return null;
    508         }
    509 
    510         public String getSigAlgName() {
    511             return null;
    512         }
    513 
    514         public String getSigAlgOID() {
    515             return null;
    516         }
    517 
    518         public byte[] getSigAlgParams() {
    519             return null;
    520         }
    521 
    522         public byte[] getSignature() {
    523             return null;
    524         }
    525 
    526         public Principal getSubjectDN() {
    527             return null;
    528         }
    529 
    530         public boolean[] getSubjectUniqueID() {
    531             return null;
    532         }
    533 
    534         public byte[] getTBSCertificate() throws CertificateEncodingException {
    535             return null;
    536         }
    537 
    538         public int getVersion() {
    539             return 0;
    540         }
    541 
    542         public Set getCriticalExtensionOIDs() {
    543             return null;
    544         }
    545 
    546         public byte[] getExtensionValue(String oid) {
    547             return null;
    548         }
    549 
    550         public Set getNonCriticalExtensionOIDs() {
    551             return null;
    552         }
    553 
    554         public boolean hasUnsupportedCriticalExtension() {
    555             return false;
    556         }
    557 
    558         public PublicKey getPublicKey() {
    559             return null;
    560         }
    561 
    562         public String toString() {
    563             return null;
    564         }
    565 
    566         public void verify(PublicKey key, String sigProvider)
    567                 throws CertificateException, NoSuchAlgorithmException,
    568                 InvalidKeyException, NoSuchProviderException,
    569                 SignatureException {
    570 
    571         }
    572 
    573         public void verify(PublicKey key) throws CertificateException,
    574                 NoSuchAlgorithmException, InvalidKeyException,
    575                 NoSuchProviderException, SignatureException {
    576 
    577         }
    578     }
    579 
    580     /**
    581      * TestProvider. Does nothing, but pretends to
    582      * implement X.509 CertificateFactory.
    583      */
    584     public static class TestProvider extends Provider {
    585 
    586         private Provider.Service serv;
    587 
    588         public TestProvider(String name, double version, String info) {
    589             super(name, version, info);
    590             serv = new Provider.Service(this, "CertificateFactory", "X.509",
    591                     TestFactorySpi.class.getName(), new ArrayList<String>(), null);
    592         }
    593 
    594         public synchronized Set<Provider.Service> getServices() {
    595             HashSet<Provider.Service> s = new HashSet<Service>();
    596             s.add(serv);
    597             return s;
    598         }
    599     }
    600 
    601     /**
    602      * Some kind of Certificate Factory, used during unit testing.
    603      *
    604      *
    605      */
    606     public static class TestFactorySpi extends CertificateFactorySpi {
    607 
    608         /**
    609          * Tries to create an instance of TestX509Certificate, basing
    610          * on the presumption that its {@link TestX509Certificate#getEncoded()
    611          * encoded} form is stored.<br>
    612          * @throws CertificateException is the presumption is not met or if
    613          * any IO problem occurs.
    614          */
    615         public Certificate engineGenerateCertificate(InputStream is)
    616                 throws CertificateException {
    617             byte[] data = new byte[0];
    618             byte[] chunk = new byte[1024];
    619             int len;
    620             try {
    621                 while ((len = is.read(chunk)) > 0) {
    622                     byte[] tmp = new byte[data.length + len];
    623                     System.arraycopy(data, 0, tmp, 0, data.length);
    624                     System.arraycopy(chunk, 0, tmp, data.length, len);
    625                     data = tmp;
    626                 }
    627             } catch (IOException ex) {
    628                 throw new CertificateException("IO problem", ex);
    629             }
    630             int pos = Arrays.binarySearch(data, (byte) 0);
    631             if (pos < 0) {
    632                 throw new CertificateException("invalid format");
    633             }
    634             byte[] subjNameData = new byte[pos];
    635             System.arraycopy(data, 0, subjNameData, 0, subjNameData.length);
    636             byte[] issNameData = new byte[data.length - pos - 1];
    637             System.arraycopy(data, pos + 1, issNameData, 0, issNameData.length);
    638             X500Principal subjName = new X500Principal(subjNameData);
    639             X500Principal issName = new X500Principal(issNameData);
    640             return new TestX509Certificate(subjName, issName);
    641         }
    642 
    643         /**
    644          * Not supported yet.
    645          * @throws UnsupportedOperationException
    646          */
    647         public Collection engineGenerateCertificates(InputStream inStream)
    648                 throws CertificateException {
    649             throw new UnsupportedOperationException("not yet.");
    650         }
    651 
    652         /**
    653          * Not supported yet.
    654          * @throws UnsupportedOperationException
    655          */
    656         public CRL engineGenerateCRL(InputStream inStream) throws CRLException {
    657             throw new UnsupportedOperationException("not yet.");
    658         }
    659 
    660         /**
    661          * Not supported yet.
    662          * @throws UnsupportedOperationException
    663          */
    664         public Collection engineGenerateCRLs(InputStream inStream)
    665                 throws CRLException {
    666             throw new UnsupportedOperationException("not yet.");
    667         }
    668 
    669         /**
    670          * Returns an instance of TestCertPath.<br>
    671          * @throws CertificateException if
    672          * a) any of Certificates passed is not an instance of X509Certificate
    673          * b) any of Certificates passed is an instance of TestInvalidX509Certificate
    674          */
    675         public CertPath engineGenerateCertPath(List certs)
    676                 throws CertificateException {
    677             ArrayList<Certificate> validCerts = new ArrayList<Certificate>();
    678             for (Iterator i = certs.iterator(); i.hasNext();) {
    679                 Certificate c = (Certificate) i.next();
    680                 if (!(c instanceof X509Certificate)) {
    681                     throw new CertificateException("Not X509: " + c);
    682                 }
    683                 if (c instanceof TestInvalidX509Certificate) {
    684                     throw new CertificateException("Invalid (test) X509: " + c);
    685                 }
    686                 validCerts.add(c);
    687             }
    688             Certificate[] acerts = new Certificate[validCerts.size()];
    689             validCerts.toArray(acerts);
    690             return new TestCertPath(acerts);
    691         }
    692     }
    693 
    694     /**
    695      * Utility class used to generate some amount of uniq names.
    696      */
    697     public static class UniGen {
    698         public static final String rootName = "CN=Alex Astapchuk, OU=SSG, O=Intel ZAO, C=RU";
    699 
    700         private static final String datasNames[] = { "CN", "OU", "O", "C" };
    701 
    702         private static final String datas[][] = {
    703         // Names database
    704                 { "Alex Astapchuk", null, null, null },
    705                 { "John Doe", null, null, null },
    706                 // 'organisation unit'-s
    707                 { null, "SSG", null, null }, { null, "SSG/DRL", null, null },
    708                 // organizations
    709                 { null, null, "Intel ZAO", null },
    710                 { null, null, "Intel Inc", null },
    711                 // countries
    712                 { null, null, null, "RU" }, { null, null, null, "US" },
    713                 { null, null, null, "GB" }, { null, null, null, "JA" },
    714                 { null, null, null, "KO" }, { null, null, null, "TW" }, };
    715 
    716         //
    717         // Returns a string from <code>data</code> from a given column and
    718         // position. The positions are looked for first non-null entry. If there
    719         // are no non empty items left, then it scans column starting from the
    720         // beginning.
    721         //
    722         // @param col
    723         // @param startRow
    724         // @return
    725         //
    726         private static String getData(int col, int startRow) {
    727             startRow = startRow % datas.length;
    728             for (int i = startRow; i < datas.length; i++) {
    729                 if (datas[i][col] != null) {
    730                     return datas[i][col];
    731                 }
    732             }
    733             // no non-null entries left, check from the beginning
    734             for (int i = 0; i < datas.length; i++) {
    735                 if (datas[i][col] != null) {
    736                     return datas[i][col];
    737                 }
    738             }
    739             // can't be
    740             throw new Error();
    741         }
    742 
    743         //
    744         // Increments a num.<br>
    745         // <code>num</code> is interpreted as a number with a base of
    746         // <code>base</code> and each digit of this number is stored as a
    747         // separate num's element.
    748         //
    749         // @param num
    750         // @param base
    751         // @return <b>true</b> if overflow happened
    752         //
    753         private static boolean inc(int[] num, int base) {
    754             for (int i = 0; i < num.length; i++) {
    755                 if ((++num[i]) >= base) {
    756                     num[i] = 0;
    757                 } else {
    758                     return false;
    759                 }
    760             }
    761             return true;
    762         }
    763 
    764         /**
    765          * Generates some amount of uniq names, none of which is equals to
    766          * {@link #rootName}.
    767          * @param howMany
    768          * @return
    769          */
    770         public static String[] genNames(int howMany) {
    771             int counts[] = new int[datasNames.length];
    772             ArrayList<String> al = new ArrayList<String>();
    773 
    774             // not really the thrifty algorithm...
    775             for (int i = 0; i < howMany;) {
    776 
    777                 //                System.out.print("#"+i+": ");
    778                 //                for( int j=0; j<counts.length; j++) {
    779                 //                    System.out.print(""+counts[j]+"|");
    780                 //                }
    781                 //                System.out.println();
    782 
    783                 StringBuffer buf = new StringBuffer();
    784                 int j = 0;
    785                 for (; j < datasNames.length - 1; j++) {
    786                     String name = datasNames[j];
    787                     String val = getData(j, counts[j]);
    788                     buf.append(name).append('=').append(val).append(",");
    789                 }
    790                 String name = datasNames[j];
    791                 String val = getData(j, counts[j]);
    792                 buf.append(name).append('=').append(val);
    793 
    794                 name = buf.toString();
    795 
    796                 if (!(rootName.equals(name) || al.contains(name))) {
    797                     ++i;
    798                     al.add(name);
    799                     //                    System.out.println("generated: "+name);
    800                 } else {
    801                     //                    System.out.println("rejected: "+name);
    802                 }
    803 
    804                 if (inc(counts, datas.length)) {
    805                     // if this happened, then just add some data into 'datas'
    806                     throw new Error(
    807                             "cant generate so many uniq names. sorry. add some more data.");
    808                 }
    809             }
    810             return (String[]) al.toArray(new String[al.size()]);
    811         }
    812 
    813         /**
    814          * Generates some amount of uniq X500Principals, none of which is equals
    815          * has a string equals to {@link #rootName}.
    816          * @param howMany
    817          * @return
    818          */
    819         public static X500Principal[] genX500s(int howMany) {
    820             String names[] = genNames(howMany);
    821             X500Principal[] ps = new X500Principal[howMany];
    822             for (int i = 0; i < howMany; i++) {
    823                 ps[i] = new X500Principal(names[i]);
    824             }
    825             return ps;
    826         }
    827 
    828     }
    829 
    830 }
    831 
    832