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 * @author Alexander Y. Kleymenov 19 */ 20 21 package org.apache.harmony.security.tests.provider.cert; 22 23 import java.io.ByteArrayInputStream; 24 import java.io.IOException; 25 import java.math.BigInteger; 26 import java.security.KeyPair; 27 import java.security.KeyPairGenerator; 28 import java.security.PrivateKey; 29 import java.security.PublicKey; 30 import java.security.Signature; 31 import java.security.cert.CRLException; 32 import java.security.cert.CertificateFactory; 33 import java.util.Arrays; 34 import java.util.Date; 35 import java.util.List; 36 import java.util.Set; 37 38 import javax.security.auth.x500.X500Principal; 39 40 import junit.framework.Test; 41 import junit.framework.TestCase; 42 import junit.framework.TestSuite; 43 44 import org.apache.harmony.security.provider.cert.X509CRLImpl; 45 import org.apache.harmony.security.provider.cert.X509CertImpl; 46 import org.apache.harmony.security.x501.Name; 47 import org.apache.harmony.security.x509.AlgorithmIdentifier; 48 import org.apache.harmony.security.x509.AuthorityKeyIdentifier; 49 import org.apache.harmony.security.x509.CRLNumber; 50 import org.apache.harmony.security.x509.Certificate; 51 import org.apache.harmony.security.x509.CertificateIssuer; 52 import org.apache.harmony.security.x509.CertificateList; 53 import org.apache.harmony.security.x509.DistributionPointName; 54 import org.apache.harmony.security.x509.Extension; 55 import org.apache.harmony.security.x509.Extensions; 56 import org.apache.harmony.security.x509.GeneralName; 57 import org.apache.harmony.security.x509.GeneralNames; 58 import org.apache.harmony.security.x509.InvalidityDate; 59 import org.apache.harmony.security.x509.IssuingDistributionPoint; 60 import org.apache.harmony.security.x509.ReasonCode; 61 import org.apache.harmony.security.x509.ReasonFlags; 62 import org.apache.harmony.security.x509.SubjectPublicKeyInfo; 63 import org.apache.harmony.security.x509.TBSCertList; 64 import org.apache.harmony.security.x509.TBSCertificate; 65 import org.apache.harmony.security.x509.Validity; 66 67 /** 68 * X509CRLImplTest 69 */ 70 public class X509CRLImplTest extends TestCase { 71 72 // Algorithm name and its OID (http://oid.elibel.tm.fr) 73 private static String algOID = "1.2.840.10040.4.3"; 74 private static String algName = "SHA1withDSA"; 75 // DER boolean false encoding (http://asn1.elibel.tm.fr) 76 // Makes no sense. For testing purposes we need just provide 77 // some ASN.1 structure: 78 private static byte[] algParams = {1, 1, 0}; 79 private static AlgorithmIdentifier signature; 80 private static byte[] signatureValue; 81 static { 82 signature = new AlgorithmIdentifier(algOID, algParams); 83 } 84 private static String issuerName = "O=CRL Issuer"; 85 private static String certIssuerName = "O=Certificate Issuer"; 86 87 private static BigInteger certSerialNumber1 = BigInteger.valueOf(555); 88 private static BigInteger certSerialNumber2 = BigInteger.valueOf(567); 89 private static BigInteger certSerialNumber3 = BigInteger.valueOf(777); 90 91 private static Date thisUpdate = new Date(); 92 private static Date nextUpdate; 93 static { 94 nextUpdate = new Date(thisUpdate.getTime()+100000); 95 } 96 private static Extensions crlEntryExtensions = new Extensions(); 97 static { 98 // Reason Code 99 crlEntryExtensions.addExtension( 100 new Extension("2.5.29.21", Extension.NON_CRITICAL, 101 new ReasonCode(ReasonCode.KEY_COMPROMISE))); 102 // Invalidity Date Extension 103 crlEntryExtensions.addExtension( 104 new Extension("2.5.29.24", Extension.NON_CRITICAL, 105 new InvalidityDate(new Date()))); 106 // add the Certificate Issuer Extension to check if implementation 107 // support indirect CRLs. As says rfc 3280 (p.62): 108 // "If used by conforming CRL issuers, this extension MUST always be 109 // critical. If an implementation ignored this extension it could not 110 // correctly attribute CRL entries to certificates. This specification 111 // RECOMMENDS that implementations recognize this extension." 112 try { 113 crlEntryExtensions.addExtension( 114 new Extension("2.5.29.29", true, 115 new CertificateIssuer( 116 new GeneralName(new Name(certIssuerName)) 117 )) 118 ); 119 } catch (Exception e) { 120 e.printStackTrace(); 121 } 122 } 123 private static Date revocationDate = new Date(); 124 private static List revokedCertificates = Arrays.asList( 125 new TBSCertList.RevokedCertificate[] { 126 new TBSCertList.RevokedCertificate(certSerialNumber1, 127 revocationDate, null), 128 // the item for certificate issued by other authority 129 new TBSCertList.RevokedCertificate(certSerialNumber2, 130 revocationDate, crlEntryExtensions), 131 new TBSCertList.RevokedCertificate(certSerialNumber3, 132 revocationDate, null), 133 }); 134 private static Extensions crlExtensions; 135 static { 136 try { 137 crlExtensions = new Extensions( 138 Arrays.asList(new Extension[] { 139 // CRL Number Extension 140 new Extension("2.5.29.20", Extension.NON_CRITICAL, 141 new CRLNumber(BigInteger.valueOf(4444))), 142 // Authority Key Identifier 143 new Extension("2.5.29.35", false, 144 new AuthorityKeyIdentifier( 145 // keyIdentifier (random value) 146 new byte[] {1, 2, 3, 4, 5}, 147 // authorityCertIssuer 148 new GeneralNames( 149 Arrays.asList(new GeneralName[] { 150 new GeneralName(new Name(certIssuerName)) 151 })), 152 // authorityCertSerialNumber 153 certSerialNumber2)), 154 // Issuing Distribution Point 155 new Extension("2.5.29.28", Extension.CRITICAL, 156 new IssuingDistributionPoint( 157 new DistributionPointName(new GeneralNames( 158 Arrays.asList(new GeneralName[] { 159 new GeneralName(1, "rfc (at) 822.Name"), 160 new GeneralName(2, "dNSName"), 161 new GeneralName(4, "O=Organization"), 162 new GeneralName(6, "http://uniform.Resource.Id"), 163 new GeneralName(7, "255.255.255.0"), 164 new GeneralName(8, "1.2.3.4444.55555") 165 }))), 166 new ReasonFlags(new boolean[] {true, true, false, false, true, true}) 167 )), 168 })); 169 } catch (Exception e) { 170 e.printStackTrace(); 171 } 172 } 173 174 // keys are using to make signature and to verify it 175 private static PublicKey publicKey; 176 private static PrivateKey privateKey; 177 private static byte[] signatureValueBytes; 178 static { 179 try { 180 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); 181 keyGen.initialize(1024); 182 KeyPair keyPair = keyGen.genKeyPair(); 183 publicKey = keyPair.getPublic(); 184 privateKey = keyPair.getPrivate(); 185 } catch (Exception e) { 186 e.printStackTrace(); 187 } 188 } 189 190 private static X509CRLImpl crl; 191 private static CertificateList certificateList; 192 private static TBSCertList tbscertlist; 193 private static byte[] encoding; 194 private static byte[] tbsEncoding; 195 static CertificateFactory factory; 196 197 static { 198 try { 199 Name issuer = new Name(issuerName); 200 201 tbscertlist = 202 new TBSCertList(2, signature, issuer, thisUpdate, 203 nextUpdate, revokedCertificates, crlExtensions); 204 205 tbsEncoding = tbscertlist.getEncoded(); 206 207 try { 208 Signature sig= Signature.getInstance("DSA"); 209 sig.initSign(privateKey); 210 sig.update(tbsEncoding, 0, tbsEncoding.length); 211 signatureValueBytes = sig.sign(); 212 } catch (Exception e) { 213 e.printStackTrace(); 214 fail("Unexpected exception was thrown: "+e.getMessage()); 215 } 216 factory = CertificateFactory.getInstance("X.509"); 217 } catch (Exception e) { 218 e.printStackTrace(); 219 fail("Unexpected Exception was thrown: "+e.getMessage()); 220 } 221 } 222 223 ByteArrayInputStream stream; 224 225 protected void setUp() throws java.lang.Exception { 226 if ("testVerify3".equals(getName())) { 227 signatureValue = new byte[signatureValueBytes.length]; 228 // make incorrect signature value: 229 System.arraycopy(signatureValueBytes, 0, 230 signatureValue, 0, signatureValueBytes.length); 231 signatureValue[20]++; 232 } else { 233 signatureValue = signatureValueBytes; 234 } 235 certificateList = 236 new CertificateList(tbscertlist, signature, signatureValue); 237 238 encoding = CertificateList.ASN1.encode(certificateList); 239 stream = new ByteArrayInputStream(encoding); 240 241 crl = new X509CRLImpl(certificateList); 242 } 243 244 private static int XXX = 0, counter = 0; 245 246 public void testCreationCRL() throws Exception { 247 byte[] stamp = new byte[10]; 248 if ((++counter)%10 != 0) { 249 XXX++; 250 } 251 byte tmp[] = BigInteger.valueOf(XXX).toByteArray(); 252 System.arraycopy(tmp, 0, stamp, 0, tmp.length); 253 System.arraycopy(stamp, 0, encoding, 254 encoding.length-stamp.length, stamp.length); 255 256 stream.reset(); 257 java.security.cert.X509CRL c = (java.security.cert.X509CRL) 258 factory.generateCRL(stream); 259 260 if (counter == 1) { 261 System.out.println("\nUSING: "+ c.getClass()); 262 } 263 264 byte[] enc = c.getEncoded(); 265 byte[] stamp_chek = new byte[stamp.length]; 266 267 System.arraycopy(enc, enc.length - stamp.length, 268 stamp_chek, 0, stamp.length); 269 270 if (!Arrays.equals(stamp, stamp_chek)) { 271 fail("Wrong encoding received."); 272 } 273 } 274 275 /** 276 * X509CRLImpl(CertificateList crl) method testing. 277 * Tested during setup. 278 */ 279 public void testX509CRLImpl() { 280 try { 281 new X509CRLImpl((CertificateList) 282 CertificateList.ASN1.decode(encoding)); 283 } catch (IOException e) { 284 fail("Unexpected exception was thrown"); 285 } 286 } 287 288 /** 289 * getEncoded() method testing. 290 */ 291 public void testGetEncoded() { 292 try { 293 if (!Arrays.equals(encoding, crl.getEncoded())) { 294 fail("Incorrect encoding of CRL."); 295 } 296 } catch (CRLException e) { 297 fail("Unexpected CRLException was thrown."); 298 } 299 } 300 301 /** 302 * getVersion() method testing. 303 */ 304 public void testGetVersion() { 305 assertEquals("Incorrect version value", 2, crl.getVersion()); 306 } 307 308 /** 309 * getIssuerDN() method testing. 310 */ 311 public void testGetIssuerDN() { 312 assertEquals("Incorrect issuer value", 313 new X500Principal(issuerName), crl.getIssuerDN()); 314 } 315 316 /** 317 * getIssuerX500Principal() method testing. 318 */ 319 public void testGetIssuerX500Principal() { 320 assertEquals("Incorrect issuer value", 321 new X500Principal(issuerName), crl.getIssuerDN()); 322 } 323 324 /** 325 * getThisUpdate() method testing. 326 */ 327 public void testGetThisUpdate() { 328 assertTrue("Incorrect thisUpdate value", 329 thisUpdate.getTime()/1000 == crl.getThisUpdate().getTime()/1000); 330 } 331 332 /** 333 * getNextUpdate() method testing. 334 */ 335 public void testGetNextUpdate() { 336 assertTrue("Incorrect nextUpdate value", 337 nextUpdate.getTime()/1000 == crl.getNextUpdate().getTime()/1000); 338 } 339 340 /** 341 * getRevokedCertificate(X509Certificate certificate) method testing. 342 */ 343 public void testGetRevokedCertificate1() { 344 try { 345 X509CertImpl cert1 = new X509CertImpl( 346 new Certificate( 347 new TBSCertificate(2, certSerialNumber1, signature, 348 new Name(certIssuerName), 349 new Validity(new Date(), new Date()), 350 new Name(certIssuerName), 351 new SubjectPublicKeyInfo(signature, new byte[10]), 352 null, null, null), 353 signature, new byte[10])); 354 X509CertImpl cert2 = new X509CertImpl( 355 new Certificate( 356 new TBSCertificate(2, certSerialNumber2, signature, 357 new Name(certIssuerName), 358 new Validity(new Date(), new Date()), 359 new Name(certIssuerName), 360 new SubjectPublicKeyInfo(signature, new byte[10]), 361 null, null, null), 362 signature, new byte[10])); 363 X509CertImpl cert3 = new X509CertImpl( 364 new Certificate( 365 new TBSCertificate(2, certSerialNumber3, signature, 366 new Name("O=Another Cert Issuer"), 367 new Validity(new Date(), new Date()), 368 new Name(certIssuerName), 369 new SubjectPublicKeyInfo(signature, new byte[10]), 370 null, null, null), 371 signature, new byte[10])); 372 assertNull("Certificate should not be presented in CRL " 373 + "because issuer is not the same as CRL issuer", 374 crl.getRevokedCertificate(cert1)); 375 assertNotNull("Certificate should be presented in CRL", 376 crl.getRevokedCertificate(cert2)); 377 assertNull("Certificate should not be presented in CRL " 378 + "because issuer is not the same as CRL issuer", 379 crl.getRevokedCertificate(cert3)); 380 } catch (IOException e) { 381 // should never happen; 382 e.printStackTrace(); 383 fail("Unexpected IOException was thrown:"+e.getMessage()); 384 } 385 } 386 387 /** 388 * getRevokedCertificate(BigInteger serialNumber) method testing. 389 */ 390 public void testGetRevokedCertificate2() { 391 assertNotNull("The revoked certificate with the serial number '" 392 + certSerialNumber1 + "' should be presented in CRL.", 393 crl.getRevokedCertificate(certSerialNumber1)); 394 assertNull("The revoked certificate with the serial number '" 395 + certSerialNumber2 + "' should not be presented in CRL.", 396 crl.getRevokedCertificate(certSerialNumber2)); 397 assertNull("The revoked certificate with the serial number '" 398 + certSerialNumber3 + "' should not be presented in CRL.", 399 crl.getRevokedCertificate(certSerialNumber3)); 400 } 401 402 /** 403 * getRevokedCertificates() method testing. 404 */ 405 public void testGetRevokedCertificates() { 406 Set rcerts = crl.getRevokedCertificates(); 407 assertNotNull("The set should not be null", rcerts); 408 assertTrue("The size of returned set is incorrect", 409 rcerts.size() == revokedCertificates.size()); 410 } 411 412 /** 413 * getTBSCertList() method testing. 414 */ 415 public void testGetTBSCertList() { 416 try { 417 assertTrue( 418 "Retrieved tbsCertList encoding does not equal to expected", 419 Arrays.equals(tbscertlist.getEncoded(), 420 crl.getTBSCertList())); 421 } catch(CRLException e) { 422 e.printStackTrace(); 423 fail("Unexpected CRLException was thrown: "+e.getMessage()); 424 } 425 } 426 427 /** 428 * getSignature() method testing. 429 */ 430 public void testGetSignature() { 431 if (!Arrays.equals(signatureValueBytes, crl.getSignature())) { 432 fail("Incorrect Signature value."); 433 } 434 } 435 436 /** 437 * getSigAlgName() method testing. 438 */ 439 public void testGetSigAlgName() { 440 assertEquals("Incorrect value of signature algorithm name", 441 algName, crl.getSigAlgName()); 442 } 443 444 /** 445 * getSigAlgOID() method testing. 446 */ 447 public void testGetSigAlgOID() { 448 assertEquals("Incorrect value of signature algorithm OID", 449 algOID, crl.getSigAlgOID()); 450 } 451 452 /** 453 * getSigAlgParams() method testing. 454 */ 455 public void testGetSigAlgParams() { 456 if (!Arrays.equals(algParams, crl.getSigAlgParams())) { 457 fail("Incorrect SigAlgParams value."); 458 } 459 } 460 461 /** 462 * verify(PublicKey key) method testing. 463 */ 464 public void testVerify1() throws Exception { 465 crl.verify(publicKey); 466 } 467 468 /** 469 * verify(PublicKey key, String sigProvider) method testing. 470 */ 471 public void testVerify2() throws Exception { 472 crl.verify(publicKey, Signature.getInstance("SHA1withDSA") 473 .getProvider().getName()); 474 } 475 476 /** 477 * verify(PublicKey key) method testing. 478 */ 479 public void testVerify3() throws Exception { 480 try { 481 crl.verify(publicKey); 482 fail("Incorrect signature successfully verified."); 483 } catch (Exception e) { 484 } 485 } 486 487 /** 488 * isRevoked(Certificate cert) method testing. 489 */ 490 public void testIsRevoked() { 491 try { 492 X509CertImpl cert1 = new X509CertImpl( 493 new Certificate( 494 new TBSCertificate(2, certSerialNumber1, signature, 495 new Name(certIssuerName), 496 new Validity(new Date(), new Date()), 497 new Name(certIssuerName), 498 new SubjectPublicKeyInfo(signature, new byte[10]), 499 null, null, null), 500 signature, new byte[10])); 501 X509CertImpl cert2 = new X509CertImpl( 502 new Certificate( 503 new TBSCertificate(2, certSerialNumber2, signature, 504 new Name(certIssuerName), 505 new Validity(new Date(), new Date()), 506 new Name(certIssuerName), 507 new SubjectPublicKeyInfo(signature, new byte[10]), 508 null, null, null), 509 signature, new byte[10])); 510 X509CertImpl cert3 = new X509CertImpl( 511 new Certificate( 512 new TBSCertificate(2, certSerialNumber3, signature, 513 new Name("O=Another Cert Issuer"), 514 new Validity(new Date(), new Date()), 515 new Name(certIssuerName), 516 new SubjectPublicKeyInfo(signature, new byte[10]), 517 null, null, null), 518 signature, new byte[10])); 519 assertFalse("Certificate should not be presented in CRL " 520 + "because issuer is not the same as CRL issuer", 521 crl.isRevoked(cert1)); 522 assertTrue("Certificate should be presented in CRL", 523 crl.isRevoked(cert2)); 524 assertFalse("Certificate should not be presented in CRL " 525 + "because issuer is not the same as CRL issuer", 526 crl.isRevoked(cert3)); 527 } catch (IOException e) { 528 // should never happen; 529 e.printStackTrace(); 530 fail("Unexpected IOException was thrown:"+e.getMessage()); 531 } 532 } 533 534 /** 535 * toString() method testing. 536 */ 537 public void testToString() { 538 assertNotNull("The string representation should not be null", 539 crl.toString()); 540 } 541 542 // the following implementations are tested in X509CertImplTest: 543 544 /** 545 * getNonCriticalExtensionOIDs() method testing. 546 */ 547 public void testGetNonCriticalExtensionOIDs() { 548 System.out.println("getNonCriticalExtensionOIDs: " 549 + crl.getNonCriticalExtensionOIDs()); 550 } 551 552 /** 553 * getCriticalExtensionOIDs() method testing. 554 */ 555 public void testGetCriticalExtensionOIDs() { 556 System.out.println("getCriticalExtensionOIDs: " 557 + crl.getCriticalExtensionOIDs()); 558 } 559 560 /** 561 * getExtensionValue(String oid) method testing. 562 */ 563 public void testGetExtensionValue() throws Exception { 564 assertNotNull(crl.getExtensionValue("2.5.29.20")); 565 assertNull("Null value should be returned in the case of " 566 + "nonexisting extension", crl.getExtensionValue("1.1.1.1")); 567 } 568 569 /** 570 * hasUnsupportedCriticalExtension() method testing. 571 */ 572 public void testHasUnsupportedCriticalExtension() { 573 System.out.println("hasUnsupportedCriticalExtension: " 574 + crl.hasUnsupportedCriticalExtension()); 575 } 576 577 public static Test suite() { 578 return new TestSuite(X509CRLImplTest.class); 579 } 580 581 } 582