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 Vladimir N. Molotkov 20 * @version $Revision$ 21 */ 22 23 package tests.security.cert; 24 25 26 27 import dalvik.annotation.AndroidOnly; 28 import dalvik.annotation.KnownFailure; 29 import dalvik.annotation.TestLevel; 30 import dalvik.annotation.TestTargetNew; 31 import dalvik.annotation.TestTargetClass; 32 import dalvik.annotation.TestTargets; 33 34 import junit.framework.TestCase; 35 36 import java.io.ByteArrayInputStream; 37 import java.io.IOException; 38 import java.io.ObjectStreamException; 39 import java.security.InvalidAlgorithmParameterException; 40 import java.security.InvalidKeyException; 41 import java.security.NoSuchAlgorithmException; 42 import java.security.NoSuchProviderException; 43 import java.security.Provider; 44 import java.security.PublicKey; 45 import java.security.Security; 46 import java.security.SignatureException; 47 import java.security.cert.Certificate; 48 import java.security.cert.CertificateEncodingException; 49 import java.security.cert.CertificateException; 50 import java.security.cert.CertificateFactory; 51 import java.util.Arrays; 52 53 import org.apache.harmony.security.tests.support.cert.MyCertificate; 54 import org.apache.harmony.security.tests.support.cert.MyFailingCertificate; 55 import org.apache.harmony.security.tests.support.cert.TestUtils; 56 import org.apache.harmony.testframework.serialization.SerializationTest; 57 58 /** 59 * Tests for <code>Certificate</code> fields and methods 60 * 61 */ 62 @TestTargetClass(Certificate.class) 63 public class CertificateTest extends TestCase { 64 /** 65 * Meaningless cert encoding just for testing purposes 66 */ 67 private static final byte[] testEncoding = new byte[] { (byte) 1, (byte) 2, 68 (byte) 3, (byte) 4, (byte) 5 }; 69 70 // 71 // Tests 72 // 73 74 /** 75 * Test for <code>Certificate(String type)</code> method<br> 76 */ 77 @TestTargetNew( 78 level = TestLevel.SUFFICIENT, 79 notes = "", 80 method = "Certificate", 81 args = {java.lang.String.class} 82 ) 83 @AndroidOnly("Gets security providers with specific signature algorithm: " + 84 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 85 public final void testCertificate() { 86 try { 87 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 88 assertTrue(Arrays.equals(testEncoding, c1.getEncoded())); 89 assertEquals("TEST", c1.getPublicKey().getAlgorithm()); 90 assertTrue(Arrays.equals( 91 new byte[] { (byte) 1, (byte) 2, (byte) 3 }, c1 92 .getPublicKey().getEncoded())); 93 assertEquals("TEST_FORMAT", c1.getPublicKey().getFormat()); 94 assertEquals("TEST_TYPE", c1.getType()); 95 } catch (CertificateEncodingException e) { 96 fail("Unexpected CertificateEncodingException " + e.getMessage()); 97 } 98 } 99 100 /** 101 * Test for <code>hashCode()</code> method<br> 102 * Assertion: returns hash of the <code>Certificate</code> instance 103 * @throws CertificateEncodingException 104 */ 105 @TestTargetNew( 106 level = TestLevel.PARTIAL_COMPLETE, 107 notes = "", 108 method = "hashCode", 109 args = {} 110 ) 111 @AndroidOnly("Gets security providers with specific signature algorithm: " + 112 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 113 public final void testHashCode() throws CertificateEncodingException { 114 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 115 Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding); 116 117 assertTrue(c1.hashCode() == c2.hashCode()); 118 119 assertFalse(c1.hashCode() == new MyCertificate("TEST_TYPE", cert 120 .getEncoded()).hashCode()); 121 assertFalse(c1.hashCode() == cert.hashCode()); 122 } 123 124 /** 125 * Test for <code>hashCode()</code> method<br> 126 * Assertion: hash code of equal objects should be the same 127 */ 128 @TestTargetNew( 129 level = TestLevel.PARTIAL_COMPLETE, 130 notes = "", 131 method = "hashCode", 132 args = {} 133 ) 134 @AndroidOnly("Gets security providers with specific signature algorithm: " + 135 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 136 public final void testHashCodeEqualsObject() { 137 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 138 Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding); 139 140 assertTrue((c1.hashCode() == c2.hashCode()) && c1.equals(c2)); 141 assertFalse(cert.equals(c1)); 142 } 143 144 145 /** 146 * Test for <code>getType()</code> method<br> 147 * Assertion: returns this certificate type 148 */ 149 @TestTargetNew( 150 level = TestLevel.COMPLETE, 151 notes = "", 152 method = "getType", 153 args = {} 154 ) 155 @AndroidOnly("Gets security providers with specific signature algorithm: " + 156 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 157 public final void testGetType() { 158 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 159 assertEquals("TEST_TYPE", c1.getType()); 160 } 161 162 /** 163 * Test #1 for <code>equals(Object)</code> method<br> 164 * Assertion: object equals to itself 165 */ 166 @TestTargetNew( 167 level = TestLevel.PARTIAL_COMPLETE, 168 notes = "Verifies positive case.", 169 method = "equals", 170 args = {java.lang.Object.class} 171 ) 172 @AndroidOnly("Gets security providers with specific signature algorithm: " + 173 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 174 public final void testEqualsObject01() { 175 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 176 assertTrue(c1.equals(c1)); 177 } 178 179 /** 180 * Test for <code>equals(Object)</code> method<br> 181 * Assertion: object equals to other <code>Certificate</code> 182 * instance with the same state 183 */ 184 @TestTargetNew( 185 level = TestLevel.PARTIAL_COMPLETE, 186 notes = "Verifies positive case.", 187 method = "equals", 188 args = {java.lang.Object.class} 189 ) 190 @AndroidOnly("Gets security providers with specific signature algorithm: " + 191 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 192 public final void testEqualsObject02() { 193 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 194 Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding); 195 assertTrue(c1.equals(c2) && c2.equals(c1)); 196 } 197 198 /** 199 * Test for <code>equals(Object)</code> method<br> 200 * Assertion: object not equals to <code>null</code> 201 */ 202 @TestTargetNew( 203 level = TestLevel.PARTIAL_COMPLETE, 204 notes = "Verifies equals method with null as a parameter.", 205 method = "equals", 206 args = {java.lang.Object.class} 207 ) 208 @AndroidOnly("Gets security providers with specific signature algorithm: " + 209 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 210 public final void testEqualsObject03() { 211 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 212 assertFalse(c1.equals(null)); 213 } 214 215 /** 216 * Test for <code>equals(Object)</code> method<br> 217 * Assertion: object not equals to other which is not 218 * instance of <code>Certificate</code> 219 */ 220 @TestTargetNew( 221 level = TestLevel.PARTIAL_COMPLETE, 222 notes = "Verifies negative case.", 223 method = "equals", 224 args = {java.lang.Object.class} 225 ) 226 @AndroidOnly("Gets security providers with specific signature algorithm: " + 227 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 228 public final void testEqualsObject04() { 229 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 230 assertFalse(c1.equals("TEST_TYPE")); 231 } 232 233 // 234 // the following tests just call methods 235 // that are abstract in <code>Certificate</code> 236 // (So they just like signature tests) 237 // 238 239 /** 240 * This test just calls <code>getEncoded()</code> method<br> 241 * @throws CertificateException 242 */ 243 @TestTargetNew( 244 level = TestLevel.SUFFICIENT, 245 notes = "Can not verify CertificateEncodingException. indirectly tested", 246 method = "getEncoded", 247 args = {} 248 ) 249 @AndroidOnly("Gets security providers with specific signature algorithm: " + 250 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 251 @KnownFailure("Assertion does not evaluate to true... Works in javax.Certificate") 252 public final void testGetEncoded() throws CertificateException { 253 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 254 assertNotNull(c1.getEncoded()); 255 256 assertTrue(Arrays.equals(TestUtils.rootCert.getBytes(),cert.getEncoded())); 257 258 byte[] b = TestUtils.rootCert.getBytes(); 259 260 b[4] = (byte) 200; 261 262 try { 263 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 264 ByteArrayInputStream stream = new ByteArrayInputStream(b); 265 cert = cf.generateCertificate(stream); 266 } catch (CertificateException e) { 267 //ok 268 } 269 } 270 271 /** 272 * This test just calls <code>verify(PublicKey)</code> method<br> 273 * 274 * @throws InvalidKeyException 275 * @throws CertificateException 276 * @throws NoSuchAlgorithmException 277 * @throws NoSuchProviderException 278 * @throws SignatureException 279 */ 280 @TestTargetNew( 281 level = TestLevel.PARTIAL_COMPLETE, 282 notes = "Verifies only null as a parameter.", 283 method = "verify", 284 args = {java.security.PublicKey.class} 285 ) 286 @AndroidOnly("Gets security providers with specific signature algorithm: " + 287 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 288 public final void testVerifyPublicKey() 289 throws InvalidKeyException, 290 CertificateException, 291 NoSuchAlgorithmException, 292 NoSuchProviderException, 293 SignatureException { 294 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 295 c1.verify(null); 296 } 297 298 /** 299 * This test just calls <code>verify(PublicKey,String)</code> method<br> 300 * 301 * @throws InvalidKeyException 302 * @throws CertificateException 303 * @throws NoSuchAlgorithmException 304 * @throws NoSuchProviderException 305 * @throws SignatureException 306 */ 307 @TestTargetNew( 308 level = TestLevel.PARTIAL_COMPLETE, 309 notes = "Verifies only null as parameters.", 310 method = "verify", 311 args = {java.security.PublicKey.class, java.lang.String.class} 312 ) 313 @AndroidOnly("Gets security providers with specific signature algorithm: " + 314 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 315 public final void testVerifyPublicKeyString() 316 throws InvalidKeyException, 317 CertificateException, 318 NoSuchAlgorithmException, 319 NoSuchProviderException, 320 SignatureException { 321 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 322 c1.verify(null, null); 323 } 324 325 /** 326 * This test just calls <code>toString()</code> method<br> 327 */ 328 @TestTargetNew( 329 level = TestLevel.COMPLETE, 330 notes = "", 331 method = "toString", 332 args = {} 333 ) 334 @AndroidOnly("Gets security providers with specific signature algorithm: " + 335 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 336 public final void testToString() { 337 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 338 c1.toString(); 339 } 340 341 /** 342 * This test just calls <code>testGetPublicKey()</code> method<br> 343 */ 344 @TestTargetNew( 345 level = TestLevel.COMPLETE, 346 notes = "", 347 method = "getPublicKey", 348 args = {} 349 ) 350 @AndroidOnly("Gets security providers with specific signature algorithm: " + 351 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 352 public final void testGetPublicKey() { 353 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 354 c1.getPublicKey(); 355 } 356 357 /** 358 * This test just calls <code>writeReplace()</code> method<br> 359 */ 360 @TestTargetNew( 361 level = TestLevel.PARTIAL_COMPLETE, 362 notes = "Doesn't verify ObjectStreamException.", 363 method = "writeReplace", 364 args = {} 365 ) 366 @AndroidOnly("Gets security providers with specific signature algorithm: " + 367 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 368 public final void testWriteReplace() { 369 MyCertificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 370 371 try { 372 Object obj = c1.writeReplace(); 373 assertTrue(obj.toString().contains( 374 "java.security.cert.Certificate$CertificateRep")); 375 } catch (ObjectStreamException e) { 376 fail("Unexpected ObjectStreamException " + e.getMessage()); 377 } 378 } 379 380 public class MyModifiablePublicKey implements PublicKey { 381 382 private PublicKey key; 383 private boolean modifiedAlgo; 384 private String algo; 385 private String format; 386 private boolean modifiedFormat; 387 private boolean modifiedEncoding; 388 private byte[] encoding; 389 390 public MyModifiablePublicKey(PublicKey k) { 391 super(); 392 this.key = k; 393 } 394 395 public String getAlgorithm() { 396 if (modifiedAlgo) { 397 return algo; 398 } else { 399 return key.getAlgorithm(); 400 } 401 } 402 403 public String getFormat() { 404 if (modifiedFormat) { 405 return this.format; 406 } else { 407 return key.getFormat(); 408 } 409 410 } 411 412 public byte[] getEncoded() { 413 if (modifiedEncoding) { 414 return this.encoding; 415 } else { 416 return key.getEncoded(); 417 } 418 419 } 420 421 public long getSerVerUID() { 422 return key.serialVersionUID; 423 } 424 425 public void setAlgorithm(String myAlgo) { 426 modifiedAlgo = true; 427 this.algo = myAlgo; 428 } 429 430 public void setFormat(String myFormat) { 431 modifiedFormat = true; 432 format = myFormat; 433 } 434 435 public void setEncoding(byte[] myEncoded) { 436 modifiedEncoding = true; 437 encoding = myEncoded; 438 } 439 } 440 441 private Certificate cert; 442 443 private Provider wrongProvider; 444 445 private Provider useFulProvider; 446 447 public void setUp() throws Exception { 448 super.setUp(); 449 TestUtils.initCertPathSSCertChain(); 450 cert = TestUtils.rootCertificateSS; 451 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 452 wrongProvider = cf.getProvider(); 453 useFulProvider = Security.getProviders("Signature.sha1WithRSAEncryption")[0]; 454 } 455 456 /** 457 * This test just calls <code>verify(PublicKey,String)</code> method<br> 458 * 459 * @throws InvalidKeyException 460 * @throws CertificateException 461 * @throws NoSuchAlgorithmException 462 * @throws NoSuchProviderException 463 * @throws SignatureException 464 */ 465 @TestTargetNew( 466 level = TestLevel.SUFFICIENT, 467 notes = "Test fails: ClassCastException when SignatureException is expected", 468 method = "verify", 469 args = {java.security.PublicKey.class, java.lang.String.class} 470 ) 471 @AndroidOnly("Gets security providers with specific signature algorithm: " + 472 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 473 public final void testVerifyPublicKeyString2() throws InvalidKeyException, 474 CertificateException, NoSuchAlgorithmException, 475 NoSuchProviderException, SignatureException { 476 477 // real test 478 cert.verify(cert.getPublicKey(), useFulProvider.getName()); 479 480 // Exception tests 481 482 try { 483 cert.verify(cert.getPublicKey(), "UnknownProvider"); 484 } catch (NoSuchProviderException e) { 485 // ok 486 } 487 488 // This test has side effects affecting all other tests running later 489 // on in the same vm instance. Maybe a better way would be to first add 490 // a new provider, test if it works, then remove it and test if the 491 // exception is thrown. 492 // 493 // Security.removeProvider(wrongProvider.getName()); 494 // 495 // try { 496 // cert.verify(cert.getPublicKey(), wrongProvider.getName()); 497 // } catch (NoSuchAlgorithmException e) { 498 // // ok 499 // } 500 // 501 // Security.insertProviderAt(wrongProvider, oldPosition); 502 503 /* 504 PublicKey k = cert.getPublicKey(); 505 MyModifiablePublicKey tamperedKey = new MyModifiablePublicKey(k); 506 tamperedKey.setAlgorithm("wrongAlgo"); 507 508 try { 509 cert.verify(tamperedKey, provs[0].getName()); 510 } catch (SignatureException e) { 511 // ok 512 } 513 514 try { 515 cert.verify(c1.getPublicKey(), provs[0].getName()); 516 } catch (InvalidKeyException e) { 517 // ok 518 } 519 */ 520 } 521 522 /** 523 * This test just calls <code>verify(PublicKey)</code> method<br> 524 * 525 * @throws InvalidKeyException 526 * @throws CertificateException 527 * @throws NoSuchAlgorithmException 528 * @throws NoSuchProviderException 529 * @throws SignatureException 530 * @throws IOException 531 * @throws InvalidAlgorithmParameterException 532 */ 533 @TestTargetNew( 534 level = TestLevel.SUFFICIENT, 535 notes = "Can't test exception for cases where the algorithm is unknown", 536 method = "verify", 537 args = {java.security.PublicKey.class} 538 ) 539 @AndroidOnly("Gets security providers with specific signature algorithm: " + 540 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 541 public final void testVerifyPublicKey2() throws InvalidKeyException, 542 CertificateException, NoSuchAlgorithmException, 543 NoSuchProviderException, SignatureException, InvalidAlgorithmParameterException, IOException { 544 545 Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding); 546 c1.verify(null); 547 548 cert.verify(cert.getPublicKey()); 549 550 PublicKey k = cert.getPublicKey(); 551 552 MyModifiablePublicKey changedEncoding = new MyModifiablePublicKey(k); 553 changedEncoding 554 .setEncoding(new byte[cert.getEncoded().length - 1]); 555 556 try { 557 cert.verify(c1.getPublicKey()); 558 fail("expected InvalidKeyException"); 559 } catch (InvalidKeyException e) { 560 // ok 561 } 562 563 try { 564 cert.verify(changedEncoding); 565 fail("Exception expected"); 566 } catch (Exception e) { 567 // ok 568 } 569 } 570 571 /** 572 * This test just calls <code>writeReplace()</code> method<br> 573 */ 574 @TestTargetNew( 575 level = TestLevel.PARTIAL_COMPLETE, 576 notes = "", 577 method = "writeReplace", 578 args = {} 579 ) 580 @AndroidOnly("Gets security providers with specific signature algorithm: " + 581 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 582 public final void testWriteReplace2() { 583 MyCertificate c1 = new MyFailingCertificate("TEST_TYPE", testEncoding); 584 585 try { 586 Object obj = c1.writeReplace(); 587 } catch (ObjectStreamException e) { 588 //ok 589 } 590 } 591 592 /** 593 * @tests serialization/deserialization compatibility. 594 */ 595 @TestTargets({ 596 @TestTargetNew( 597 level = TestLevel.COMPLETE, 598 notes = "Verifies serialization/deserialization compatibility. And tests default constructor", 599 method = "!SerializationSelf", 600 args = {} 601 ), 602 @TestTargetNew( 603 level = TestLevel.PARTIAL_COMPLETE, 604 notes = "", 605 method = "writeReplace", 606 args = {} 607 ), 608 @TestTargetNew( 609 level = TestLevel.PARTIAL_COMPLETE, 610 notes = "", 611 method = "Certificate.CertificateRep.readResolve", 612 args = {} 613 ) 614 }) 615 @AndroidOnly("Gets security providers with specific signature algorithm: " + 616 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 617 public void testSerializationSelf() throws Exception { 618 TestUtils.initCertPathSSCertChain(); 619 620 SerializationTest.verifySelf(TestUtils.rootCertificateSS); 621 } 622 623 /** 624 * @tests serialization/deserialization compatibility with RI. 625 */ 626 @TestTargets({ 627 @TestTargetNew( 628 level = TestLevel.COMPLETE, 629 notes = "Verifies serialization/deserialization compatibility.", 630 method = "!SerializationGolden", 631 args = {} 632 ), 633 @TestTargetNew( 634 level = TestLevel.PARTIAL_COMPLETE, 635 notes = "", 636 method = "writeReplace", 637 args = {} 638 ), 639 @TestTargetNew( 640 level = TestLevel.PARTIAL_COMPLETE, 641 notes = "", 642 method = "Certificate.CertificateRep.readResolve", 643 args = {} 644 ) 645 }) 646 @AndroidOnly("Gets security providers with specific signature algorithm: " + 647 "Security.getProviders(\"Signature.sha1WithRSAEncryption\")") 648 public void testSerializationCompatibility() throws Exception { 649 //create test file (once) 650 // SerializationTest.createGoldenFile("device/dalvik/libcore/security/src/test/resources/serialization", this, TestUtils.rootCertificateSS); 651 TestUtils.initCertPathSSCertChain(); 652 653 SerializationTest.verifyGolden(this, TestUtils.rootCertificateSS); 654 } 655 } 656