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